From 77d5cae4d45d1def8f41d4e89b705d2953858643 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 25 Apr 2016 17:56:51 +0200 Subject: trafgen: proto: Add ICMPv6 header generation Support for generating simple ICMPv6 headers using the 'icmp6()/icmpv6()' trafgen generation function. Fields supported: mtype Message type (default: 0) Supported keywords: echorequest, echoreply code Code (default: 0) csum Message checksum (calculated by default) Examples: { eth(), ipv6(daddr=::1), icmpv6(echorequest), 42, 42, 0, 0 }' If not explicitely specified, the lower header is initialized as Ethernet. Suggested-by: Daniel Borkmann Signed-off-by: Tobias Klauser --- trafgen.8 | 25 +++++++++++++++++++++++++ trafgen_l3.c | 3 +++ trafgen_l4.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ trafgen_l4.h | 6 ++++++ trafgen_lexer.l | 7 +++++++ trafgen_parser.y | 34 ++++++++++++++++++++++++++++++++++ trafgen_proto.h | 1 + 7 files changed, 125 insertions(+) diff --git a/trafgen.8 b/trafgen.8 index c81fecb..3075daa 100644 --- a/trafgen.8 +++ b/trafgen.8 @@ -498,6 +498,31 @@ By default, if the lower level header is Ethernet, its EtherType field is set to By default, if the lower level header is Ethernet, its EtherType field is set to 0x86DD (IPv6). +.I ICMPv6 +: +.B icmp6|icmpv6(mtype=, echorequest, echoreply, code=, +.B csum=) +.sp +.in +4 +.B mtype +- Message type (default: 0) +.sp +.B code +- Code (default: 0) +.sp +.B echorequest +- ICMPv6 echo (ping) request +.sp +.B echoreply +- ICMPv6 echo (ping) reply +.sp +.B csum +- Message checksum (calculated by default) +.in -4 +.sp +By default, if the lower level header is IPv6, its Next Header field is set to +58 (ICMPv6). + .I UDP : .B udp(sp=, dp=, len=, csum=) diff --git a/trafgen_l3.c b/trafgen_l3.c index 94c0755..cbdbe6c 100644 --- a/trafgen_l3.c +++ b/trafgen_l3.c @@ -126,6 +126,9 @@ static void ipv6_set_next_proto(struct proto_hdr *hdr, enum proto_id pid) uint8_t ip_proto; switch(pid) { + case PROTO_ICMP6: + ip_proto = IPPROTO_ICMPV6; + break; case PROTO_UDP: ip_proto = IPPROTO_UDP; break; diff --git a/trafgen_l4.c b/trafgen_l4.c index a5981c4..886e2b2 100644 --- a/trafgen_l4.c +++ b/trafgen_l4.c @@ -138,8 +138,57 @@ static struct proto_hdr tcp_hdr = { .packet_finish = tcp_packet_finish, }; +static struct proto_field icmpv6_fields[] = { + { .id = ICMPV6_TYPE, .len = 1, .offset = 0 }, + { .id = ICMPV6_CODE, .len = 1, .offset = 1 }, + { .id = ICMPV6_CSUM, .len = 2, .offset = 2 } +}; + +static void icmpv6_header_init(struct proto_hdr *hdr) +{ + proto_lower_default_add(hdr, PROTO_IP6); + + proto_header_fields_add(hdr, icmpv6_fields, array_size(icmpv6_fields)); +} + +static void icmpv6_packet_finish(struct proto_hdr *hdr) +{ + struct proto_hdr *lower = proto_lower_header(hdr); + struct packet *pkt = current_packet(); + uint16_t total_len; + uint16_t csum; + + if (proto_field_is_set(hdr, ICMPV6_CSUM)) + return; + + if (!lower) + return; + + total_len = pkt->len - hdr->pkt_offset; + + switch (lower->id) { + case PROTO_IP6: + csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr), + total_len, IPPROTO_ICMPV6); + break; + default: + csum = 0; + break; + } + + proto_field_set_be16(hdr, ICMPV6_CSUM, bswap_16(csum)); +} + +static struct proto_hdr icmpv6_hdr = { + .id = PROTO_ICMP6, + .layer = PROTO_L4, + .header_init = icmpv6_header_init, + .packet_finish = icmpv6_packet_finish, +}; + void protos_l4_init(void) { proto_header_register(&udp_hdr); proto_header_register(&tcp_hdr); + proto_header_register(&icmpv6_hdr); } diff --git a/trafgen_l4.h b/trafgen_l4.h index da73ebc..e94ff23 100644 --- a/trafgen_l4.h +++ b/trafgen_l4.h @@ -27,6 +27,12 @@ enum tcp_field { TCP_URG_PTR, }; +enum icmpv6_field { + ICMPV6_TYPE, + ICMPV6_CODE, + ICMPV6_CSUM, +}; + extern void protos_l4_init(void); #endif /* TRAFGEN_L4_H */ diff --git a/trafgen_lexer.l b/trafgen_lexer.l index a093ac1..eb438a8 100644 --- a/trafgen_lexer.l +++ b/trafgen_lexer.l @@ -161,6 +161,12 @@ ip6_addr (({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?: "nh"|"nexthdr" { return K_NEXT_HDR; } "hl"|"hoplimit" { return K_HOP_LIMIT; } + /* ICMPv6 */ +"mtype" { return K_MTYPE; } +"code" { return K_CODE; } +"echorequest" { return K_ECHO_REQUEST; } +"echoreply" { return K_ECHO_REPLY; } + /* UDP */ "sp"|"sport" { return K_SPORT; } "dp"|"dport" { return K_DPORT; } @@ -186,6 +192,7 @@ ip6_addr (({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?: "arp" { return K_ARP; } "ip4"|"ipv4" { return K_IP4; } "ip6"|"ipv6" { return K_IP6; } +"icmp6"|"icmpv6" { return K_ICMP6; } "udp" { return K_UDP; } "tcp" { return K_TCP; } diff --git a/trafgen_parser.y b/trafgen_parser.y index d6c9e70..bf57f47 100644 --- a/trafgen_parser.y +++ b/trafgen_parser.y @@ -20,6 +20,7 @@ #include #include #include +#include #include "xmalloc.h" #include "trafgen_parser.tab.h" @@ -355,6 +356,7 @@ static void proto_add(enum proto_id pid) %token K_OPER K_SHA K_SPA K_THA K_TPA K_REQUEST K_REPLY K_PTYPE K_HTYPE %token K_PROT K_TTL K_DSCP K_ECN K_TOS K_LEN K_ID K_FLAGS K_FRAG K_IHL K_VER K_CSUM K_DF K_MF %token K_FLOW K_NEXT_HDR K_HOP_LIMIT +%token K_MTYPE K_CODE K_ECHO_REQUEST K_ECHO_REPLY %token K_SPORT K_DPORT %token K_SEQ K_ACK_SEQ K_DOFF K_CWR K_ECE K_URG K_ACK K_PSH K_RST K_SYN K_FIN K_WINDOW K_URG_PTR %token K_TPID K_TCI K_PCP K_DEI K_1Q K_1AD @@ -364,6 +366,7 @@ static void proto_add(enum proto_id pid) %token K_VLAN K_MPLS %token K_ARP %token K_IP4 K_IP6 +%token K_ICMP6 %token K_UDP K_TCP %token ',' '{' '}' '(' ')' '[' ']' ':' '-' '+' '*' '/' '%' '&' '|' '<' '>' '^' @@ -591,6 +594,7 @@ proto | arp_proto { } | ip4_proto { } | ip6_proto { } + | icmpv6_proto { } | udp_proto { } | tcp_proto { } ; @@ -812,6 +816,36 @@ ip6 : K_IP6 { proto_add(PROTO_IP6); } ; +icmpv6_proto + : icmp6 '(' icmp6_param_list ')' { } + +icmp6_param_list + : { } + | icmp6_field { } + | icmp6_field delimiter icmp6_param_list { } + ; + +icmp6_field + : K_MTYPE skip_white '=' skip_white number + { proto_field_set_u8(hdr, ICMPV6_TYPE, $5); } + | K_MTYPE skip_white '=' K_ECHO_REQUEST + { proto_field_set_u8(hdr, ICMPV6_TYPE, ICMPV6_ECHO_REQUEST); } + | K_ECHO_REQUEST + { proto_field_set_u8(hdr, ICMPV6_TYPE, ICMPV6_ECHO_REQUEST); } + | K_MTYPE skip_white '=' K_ECHO_REPLY + { proto_field_set_u8(hdr, ICMPV6_TYPE, ICMPV6_ECHO_REPLY); } + | K_ECHO_REPLY + { proto_field_set_u8(hdr, ICMPV6_TYPE, ICMPV6_ECHO_REPLY); } + | K_CODE skip_white '=' skip_white number + { proto_field_set_u8(hdr, ICMPV6_CODE, $5); } + | K_CSUM skip_white '=' skip_white number + { proto_field_set_be16(hdr, ICMPV6_CSUM, $5); } + ; + +icmp6 + : K_ICMP6 { proto_add(PROTO_ICMP6); } + ; + udp_proto : udp '(' udp_param_list ')' { } ; diff --git a/trafgen_proto.h b/trafgen_proto.h index cdcffdc..5528704 100644 --- a/trafgen_proto.h +++ b/trafgen_proto.h @@ -17,6 +17,7 @@ enum proto_id { PROTO_MPLS, PROTO_IP4, PROTO_IP6, + PROTO_ICMP6, PROTO_UDP, PROTO_TCP, }; -- cgit v1.2.3-54-g00ecf