From 434b33d1b06f39125a2d8fa841b0b7d31d85a687 Mon Sep 17 00:00:00 2001 From: someone Date: Wed, 22 Feb 2012 15:42:48 -0800 Subject: Support building ICMPv6 packets. Support for building base ICMPv6 header (type/code), as well as echo requests, neighbour solicitation, and neighbour advertisement. --- libnet/include/libnet/libnet-functions.h | 69 +++++++++++++ libnet/include/libnet/libnet-headers.h | 63 +++++++----- libnet/include/libnet/libnet-macros.h | 2 +- libnet/include/libnet/libnet-structures.h | 4 + libnet/src/libnet_build_icmp.c | 164 ++++++++++++++++++++++++++++++ 5 files changed, 273 insertions(+), 29 deletions(-) diff --git a/libnet/include/libnet/libnet-functions.h b/libnet/include/libnet/libnet-functions.h index 49a968f..f2d4226 100644 --- a/libnet/include/libnet/libnet-functions.h +++ b/libnet/include/libnet/libnet-functions.h @@ -777,6 +777,22 @@ libnet_build_icmpv4_timestamp(uint8_t type, uint8_t code, uint16_t sum, uint16_t id, uint16_t seq, uint32_t otime, uint32_t rtime, uint32_t ttime, const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); +/* + * Builds an ICMPv6 header + * @param type type of ICMPv6 packet + * @param code code of ICMP packet + * @param sum checksum (0 for libnet to autofill) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * See definitions of types and codes (ICMP6_*) in struct libnet_icmpv6_hdr. + * @return protocol tag value on success, -1 on error + */ +libnet_ptag_t libnet_build_icmpv6(uint8_t type, uint8_t code, uint16_t sum, + uint8_t* payload, uint32_t payload_s, + libnet_t* l, libnet_ptag_t ptag); + /** * Builds an IP version 6 RFC 4443 Internet Control Message Protocol (ICMP) * unreachable header. The IP header that caused the error message should be @@ -794,6 +810,59 @@ libnet_ptag_t libnet_build_icmpv6_unreach(uint8_t type, uint8_t code, uint16_t sum, uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); +/** + * Builds ICMPv6 echo header + * @param id echo id number + * @param seq echo sequence number + * @param data optional payload or NULL + * @param datalen payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success, -1 on error + */ +libnet_ptag_t libnet_build_icmpv6_echo(uint16_t id, uint16_t seq, + uint8_t *data, uint32_t datalen, + libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds ICMPv6 Neighbor Solicitation header + * @param tgt target ipv6 address + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success, -1 on error + */ + + +libnet_ptag_t libnet_build_icmpv6_nsol(struct libnet_in6_addr tgt, + libnet_t* l, libnet_ptag_t ptag); + +/** + * Builds ICMPv6 Neighbor Advertisement header + * @param flags neighbor advertisement flags + * @param tgt target ipv6 address + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success, -1 on error + */ +libnet_ptag_t libnet_build_icmpv6_nadv(uint32_t flags, + struct libnet_in6_addr tgt, + libnet_t* l, libnet_ptag_t ptag); + +/** + * Builds ICMPv6 NDP link-layer address option + * @param type address type (ICMPV6_NDPOPT_SLLA for source, ICMPV6_NDPOPT_TLLA for target) + * @param len addess length in 8-byte chunks FIXME builder should calculate len if it is zero + * @param mac hardware address + * @param maclen hardware address length FIXME builder doesn't pad to 8-byte boundaries, if caller doesn't, option is invalid + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success, -1 on error + + */ +libnet_ptag_t libnet_build_icmpv6_ndp_lla(uint8_t type, uint8_t len, + uint8_t* mac, uint32_t maclen, + libnet_t* l, libnet_ptag_t ptag); + /** * Builds an RFC 1112 Internet Group Memebership Protocol (IGMP) header. * @param type packet type diff --git a/libnet/include/libnet/libnet-headers.h b/libnet/include/libnet/libnet-headers.h index b126e39..2e01541 100644 --- a/libnet/include/libnet/libnet-headers.h +++ b/libnet/include/libnet/libnet-headers.h @@ -63,8 +63,11 @@ #define LIBNET_ICMPV4_TIMXCEED_H 0x08 /**< ICMP_TIMXCEED header: 8 bytes */ #define LIBNET_ICMPV4_REDIRECT_H 0x08 /**< ICMP_REDIRECT header: 8 bytes */ #define LIBNET_ICMPV4_TS_H 0x14 /**< ICMP_TIMESTAMP headr:20 bytes */ -#define LIBNET_ICMPV6_H 0x08 /**< ICMP6 header base: 8 bytes */ +#define LIBNET_ICMPV6_H 0x04 /**< ICMP6 header base: 4 bytes */ #define LIBNET_ICMPV6_UNREACH_H 0x08 /**< ICMP6 unreach base: 8 bytes */ +#define LIBNET_ICMPV6_ECHO_H 0x04 /**< ICMP6 echo header: 4 bytes */ +#define LIBNET_ICMPV6_NDP_NSA_H 0x14 /**< ICMP6 NDP header: 20 bytes */ +#define LIBNET_ICMPV6_NDP_OPT_H 0x02 /**< ICMP6 ndp options: 2 bytes */ #define LIBNET_IGMP_H 0x08 /**< IGMP header: 8 bytes */ #define LIBNET_IPV4_H 0x14 /**< IPv4 header: 20 bytes */ #define LIBNET_IPV6_H 0x28 /**< IPv6 header: 40 bytes */ @@ -502,6 +505,7 @@ struct libnet_ethernet_hdr #ifndef ETHERTYPE_IP #define ETHERTYPE_IP 0x0800 /* IP protocol */ #endif +#define ETHERTYPE_IPV6 0x86dd /* IPv6 protocol */ #ifndef ETHERTYPE_ARP #define ETHERTYPE_ARP 0x0806 /* addr. resolution protocol */ #endif @@ -816,53 +820,56 @@ struct libnet_ipv6_hbhopts_hdr /* * ICMP6 header * Internet Control Message Protocol v6 - * Base header size: 8 bytes + * Base header size: 4 bytes */ -#ifndef IPPROTO_ICMP6 #define IPPROTO_ICMP6 0x3a -#endif struct libnet_icmpv6_hdr { uint8_t icmp_type; /* ICMP type */ -#ifndef ICMP6_ECHO #define ICMP6_ECHO 128 -#endif -#ifndef ICMP6_ECHOREPLY #define ICMP6_ECHOREPLY 129 -#endif -#ifndef ICMP6_UNREACH +#define ICMP6_ROUTERSOL 133 +#define ICMP6_ROUTERADV 134 +#define ICMP6_NEIGHSOL 135 +#define ICMP6_NEIGHADV 136 + #define ICMP6_UNREACH 1 -#endif -#ifndef ICMP6_PKTTOOBIG #define ICMP6_PKTTOOBIG 2 -#endif -#ifndef ICMP6_TIMXCEED #define ICMP6_TIMXCEED 3 -#endif -#ifndef ICMP6_PARAMPROB #define ICMP6_PARAMPROB 4 -#endif uint8_t icmp_code; /* ICMP code */ -#ifndef ICMP6_NOROUTE #define ICMP6_NOROUTE 0 -#endif -#ifndef ICMP6_ADM_PROHIBITED #define ICMP6_ADM_PROHIBITED 1 -#endif -#ifndef ICMP6_NOT_NEIGHBOUR #define ICMP6_NOT_NEIGHBOUR 2 -#endif -#ifndef ICMP6_ADDR_UNREACH #define ICMP6_ADDR_UNREACH 3 -#endif -#ifndef ICMP6_PORT_UNREACH #define ICMP6_PORT_UNREACH 4 -#endif uint16_t icmp_sum; /* ICMP Checksum */ - uint16_t id; /* ICMP id */ - uint16_t seq; /* ICMP sequence number */ }; +/* All of this stuff follows base ICMPv6 header */ + +struct libnet_icmpv6_echo { + uint16_t id; + uint16_t seq; +}; + +struct libnet_icmpv6_ndp_nsa { + uint32_t flags; +#define NDP_FL_ROUTER (1 << 31) +#define NDP_FL_SOLICITED (1 << 30) +#define NDP_FL_OVERRIDE (1 << 29) + struct libnet_in6_addr tgt_addr; +}; + +struct libnet_icmpv6_ndp_opt { + uint8_t type; +#define ICMPV6_NDPOPT_SLLA 1 +#define ICMPV6_NDPOPT_TLLA 2 +#define ICMPV6_NDPOPT_PREFIX 3 +#define ICMPV6_NDPOPT_REDHDR 4 +#define ICMPV6_NDPOPT_MTU 5 + uint8_t len; +}; /* diff --git a/libnet/include/libnet/libnet-macros.h b/libnet/include/libnet/libnet-macros.h index afd9029..817a2b1 100644 --- a/libnet/include/libnet/libnet-macros.h +++ b/libnet/include/libnet/libnet-macros.h @@ -166,7 +166,7 @@ if (payload_s) \ #ifdef IFF_LOOPBACK #define LIBNET_ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK) #else -#define LIBNET_ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo0") == 0) +#define LIBNET_ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo") == 0) #endif /* advanced mode check */ diff --git a/libnet/include/libnet/libnet-structures.h b/libnet/include/libnet/libnet-structures.h index 912c321..831999e 100644 --- a/libnet/include/libnet/libnet-structures.h +++ b/libnet/include/libnet/libnet-structures.h @@ -160,6 +160,10 @@ struct libnet_protocol_block #define LIBNET_PBLOCK_HSRP_H 0x40 /* HSRP header */ #define LIBNET_PBLOCK_ICMPV6_H 0x41 /* ICMPv6 header */ #define LIBNET_PBLOCK_ICMPV6_UNREACH_H 0x42 /* ICMPv6 unreach header */ +#define LIBNET_PBLOCK_ICMPV6_NDNSOL_H 0x43 /* ICMPv6 neighbor solicitation header */ +#define LIBNET_PBLOCK_ICMPV6_NDNADV_H 0x44 /* ICMPv6 neighbor adv header */ +#define LIBNET_PBLOCK_ICMPV6_NDPOPT_H 0x45 /* ICMPv6 NDP option */ +#define LIBNET_PBLOCK_ICMPV6_ECHO_H 0x46 /* ICMPv6 echo header */ uint8_t flags; /* control flags */ #define LIBNET_PBLOCK_DO_CHECKSUM 0x01 /* needs a checksum */ diff --git a/libnet/src/libnet_build_icmp.c b/libnet/src/libnet_build_icmp.c index d46590f..4034ff9 100644 --- a/libnet/src/libnet_build_icmp.c +++ b/libnet/src/libnet_build_icmp.c @@ -404,6 +404,8 @@ uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) libnet_pblock_t *p; struct libnet_icmpv6_hdr icmp_hdr; +#if 0 + if (l == NULL) { return (-1); @@ -434,7 +436,169 @@ uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) LIBNET_PBLOCK_ICMPV6_UNREACH_H)); bad: libnet_pblock_delete(l, p); +#endif return (-1); } +libnet_ptag_t libnet_build_icmpv6(uint8_t type, uint8_t code, uint16_t sum, + uint8_t* payload, uint32_t payload_s, + libnet_t* l, libnet_ptag_t ptag) +{ + struct libnet_icmpv6_hdr icmp_hdr; + libnet_pblock_t* p; + uint32_t n; + + if(l == NULL) + return -1; + + n = payload_s + LIBNET_ICMPV6_H; + + p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_H); + if(p == NULL) + return -1; + + memset(&icmp_hdr, 0, sizeof(icmp_hdr)); + icmp_hdr.icmp_type = type; + icmp_hdr.icmp_code = code; + icmp_hdr.icmp_sum = (sum ? htons(sum) : 0); + + LIBNET_BUILD_ICMP_ERR_FINISH(LIBNET_ICMPV6_H); + + return (ptag ? ptag : libnet_pblock_update(l, p, n, LIBNET_PBLOCK_ICMPV6_H)); + +bad: + libnet_pblock_delete(l, p); + return -1; +} + +libnet_ptag_t libnet_build_icmpv6_echo(uint16_t id, uint16_t seq, + uint8_t *data, uint32_t datalen, + libnet_t *l, libnet_ptag_t ptag) +{ + struct libnet_icmpv6_echo echo; + libnet_pblock_t *p; + uint32_t n; + + if(l == NULL) + return -1; + + n = LIBNET_ICMPV6_ECHO_H; + + p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_ECHO_H); + if(p == NULL) + return -1; + + memset(&echo, 0, sizeof(echo)); + echo.id = id; + echo.seq = seq; + if(libnet_pblock_append(l, p, &echo, n) == -1) + goto bad; + + return ptag ? ptag : libnet_pblock_update(l, p, n, LIBNET_PBLOCK_ICMPV6_ECHO_H); + +bad: + libnet_pblock_delete(l, p); + return -1; +} + + +libnet_ptag_t libnet_build_icmpv6_nsol(struct libnet_in6_addr tgt, + libnet_t* l, libnet_ptag_t ptag) +{ + struct libnet_icmpv6_ndp_nsa na; + uint32_t n; + libnet_pblock_t* p; + + if(l == NULL) + return -1; + + n = LIBNET_ICMPV6_NDP_NSA_H; + + p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_NDNSOL_H); + if(p == NULL) + return -1; + + memset(&na, 0, sizeof(na)); + na.tgt_addr = tgt; + if(libnet_pblock_append(l, p, &na, n) == -1) + goto bad; + + return ptag ? ptag : libnet_pblock_update(l, p, n, LIBNET_PBLOCK_ICMPV6_NDNSOL_H); + +bad: + libnet_pblock_delete(l, p); + return -1; +} + + +libnet_ptag_t libnet_build_icmpv6_nadv(uint32_t flags, + struct libnet_in6_addr tgt, + libnet_t* l, libnet_ptag_t ptag) +{ + struct libnet_icmpv6_ndp_nsa na; + uint32_t n; + libnet_pblock_t* p; + + if(l == NULL) + return -1; + + n = LIBNET_ICMPV6_NDP_NSA_H; + + p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_NDNADV_H); + if(p == NULL) + return -1; + + memset(&na, 0, sizeof(na)); + na.flags = htonl(flags); + na.tgt_addr = tgt; + if(libnet_pblock_append(l, p, &na, n) == -1) + goto bad; + + return ptag ? ptag : libnet_pblock_update(l, p, n, LIBNET_PBLOCK_ICMPV6_NDNADV_H); + +bad: + libnet_pblock_delete(l, p); + return -1; +} + +libnet_ptag_t libnet_build_icmpv6_ndp_lla(uint8_t type, uint8_t len, + uint8_t* mac, uint32_t maclen, + libnet_t* l, libnet_ptag_t ptag) +{ + struct libnet_icmpv6_ndp_opt no; + uint32_t n; + libnet_pblock_t* p; + + if(l == NULL) + return -1; + + if(!mac) + maclen = 0; + + if(len == 0) + len = (LIBNET_PBLOCK_ICMPV6_NDPOPT_H + maclen); + + n = LIBNET_ICMPV6_NDP_OPT_H + maclen; + p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_NDPOPT_H); + if(p == NULL) + return -1; + memset(&no, 0, sizeof(no)); + no.type = type; + no.len = len; + + if(libnet_pblock_append(l, p, &no, LIBNET_ICMPV6_NDP_OPT_H) == -1) + goto bad; + + if(mac != NULL) { + if(libnet_pblock_append(l, p, mac, maclen) == -1) + goto bad; + } + + return ptag ? ptag : libnet_pblock_update(l, p, n, LIBNET_PBLOCK_ICMPV6_NDPOPT_H); + +bad: + libnet_pblock_delete(l, p); + return -1; +} + /* EOF */ -- cgit v1.2.1