diff options
-rw-r--r-- | trafgen.8 | 40 | ||||
-rw-r--r-- | trafgen_l3.c | 3 | ||||
-rw-r--r-- | trafgen_l4.c | 42 | ||||
-rw-r--r-- | trafgen_l4.h | 10 | ||||
-rw-r--r-- | trafgen_lexer.l | 6 | ||||
-rw-r--r-- | trafgen_parser.y | 41 | ||||
-rw-r--r-- | trafgen_proto.h | 1 |
7 files changed, 142 insertions, 1 deletions
@@ -498,6 +498,46 @@ 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 ICMPv4 +: +.B icmp4|icmpv4(type=<number>, code=<number>, echorequest, echoreply, +.B csum=<number>, mtu=<number>, seq=<number>, id=<number>, addr=<ip4_addr>) +.sp +.in +4 +.B type +- Message type (default: 0 - Echo reply) +.sp +.B code +- Message code (default: 0) +.sp +.B echorequest +- ICMPv4 echo (ping) request (type: 8, code: 0) +.sp +.B echoreply +- ICMPv4 echo (ping) reply (type: 0, code: 0) +.sp +.B csum +- Checksum of ICMPv4 header and payload (calculated by default) +.sp +.B mtu +- Next-hop MTU field used in 'Datagram is too big' message type (default; 0) +.sp +.B seq +- Sequence number used in Echo/Timestamp/Address mask messages (default: 0) +.sp +.B id +- Identifier used in Echo/Timestamp/Address mask messages (default: 0) +.sp +.B addr +- IPv4 address used in Redirect messages (default: 0.0.0.0) +.sp +.in -4 +Example ICMP echo request (ping): +.in +4 +.sp +{ icmpv4(echorequest, seq=1, id=1326) } +.in -4 + .I ICMPv6 : .B icmp6|icmpv6(type=<number>, echorequest, echoreply, code=<number>, diff --git a/trafgen_l3.c b/trafgen_l3.c index cbdbe6c..ae3f136 100644 --- a/trafgen_l3.c +++ b/trafgen_l3.c @@ -69,6 +69,9 @@ static void ipv4_set_next_proto(struct proto_hdr *hdr, enum proto_id pid) case PROTO_IP4: ip_proto = IPPROTO_IPIP; break; + case PROTO_ICMP4: + ip_proto = IPPROTO_ICMP; + break; case PROTO_UDP: ip_proto = IPPROTO_UDP; break; diff --git a/trafgen_l4.c b/trafgen_l4.c index 886e2b2..c109675 100644 --- a/trafgen_l4.c +++ b/trafgen_l4.c @@ -138,6 +138,47 @@ static struct proto_hdr tcp_hdr = { .packet_finish = tcp_packet_finish, }; +static struct proto_field icmpv4_fields[] = { + { .id = ICMPV4_TYPE, .len = 1, .offset = 0 }, + { .id = ICMPV4_CODE, .len = 1, .offset = 1 }, + { .id = ICMPV4_CSUM, .len = 2, .offset = 2 }, + /* Echo/Ping fields */ + { .id = ICMPV4_ID, .len = 2, .offset = 4 }, + { .id = ICMPV4_SEQ, .len = 2, .offset = 6 }, + /* Redirect field */ + { .id = ICMPV4_REDIR_ADDR, .len = 4, .offset = 4 }, + /* Next-hop MTU */ + { .id = ICMPV4_MTU, .len = 2, .offset = 6 }, +}; + +static void icmpv4_header_init(struct proto_hdr *hdr) +{ + proto_lower_default_add(hdr, PROTO_IP4); + + proto_header_fields_add(hdr, icmpv4_fields, array_size(icmpv4_fields)); +} + +static void icmpv4_packet_finish(struct proto_hdr *hdr) +{ + struct packet *pkt; + uint16_t csum; + + if (proto_field_is_set(hdr, ICMPV4_CSUM)) + return; + + pkt = current_packet(); + + csum = htons(calc_csum(proto_header_ptr(hdr), pkt->len - hdr->pkt_offset)); + proto_field_set_u16(hdr, ICMPV4_CSUM, bswap_16(csum)); +} + +static struct proto_hdr icmpv4_hdr = { + .id = PROTO_ICMP4, + .layer = PROTO_L4, + .header_init = icmpv4_header_init, + .packet_finish = icmpv4_packet_finish, +}; + static struct proto_field icmpv6_fields[] = { { .id = ICMPV6_TYPE, .len = 1, .offset = 0 }, { .id = ICMPV6_CODE, .len = 1, .offset = 1 }, @@ -190,5 +231,6 @@ void protos_l4_init(void) { proto_header_register(&udp_hdr); proto_header_register(&tcp_hdr); + proto_header_register(&icmpv4_hdr); proto_header_register(&icmpv6_hdr); } diff --git a/trafgen_l4.h b/trafgen_l4.h index e94ff23..9537cbf 100644 --- a/trafgen_l4.h +++ b/trafgen_l4.h @@ -27,6 +27,16 @@ enum tcp_field { TCP_URG_PTR, }; +enum icmpv4_field { + ICMPV4_TYPE, + ICMPV4_CODE, + ICMPV4_CSUM, + ICMPV4_ID, + ICMPV4_SEQ, + ICMPV4_REDIR_ADDR, + ICMPV4_MTU, +}; + enum icmpv6_field { ICMPV6_TYPE, ICMPV6_CODE, diff --git a/trafgen_lexer.l b/trafgen_lexer.l index 87db504..5873eec 100644 --- a/trafgen_lexer.l +++ b/trafgen_lexer.l @@ -162,6 +162,11 @@ 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; } + + /* ICMPv4 */ +"addr" { return K_ADDR; } +"mtu" { return K_MTU; } + /* ICMPv6 */ "code" { return K_CODE; } "echorequest" { return K_ECHO_REQUEST; } @@ -192,6 +197,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; } +"icmp4"|"icmpv4" { return K_ICMP4; } "icmp6"|"icmpv6" { return K_ICMP6; } "udp" { return K_UDP; } "tcp" { return K_TCP; } diff --git a/trafgen_parser.y b/trafgen_parser.y index adb7f5e..0fe8674 100644 --- a/trafgen_parser.y +++ b/trafgen_parser.y @@ -19,6 +19,7 @@ #include <libgen.h> #include <net/if_arp.h> #include <netinet/in.h> +#include <linux/icmp.h> #include <linux/if_ether.h> #include <linux/icmpv6.h> @@ -362,11 +363,13 @@ static void proto_add(enum proto_id pid) %token K_TPID K_TCI K_PCP K_DEI K_1Q K_1AD %token K_LABEL K_TC K_LAST K_EXP +%token K_ADDR K_MTU + %token K_ETH %token K_VLAN K_MPLS %token K_ARP %token K_IP4 K_IP6 -%token K_ICMP6 +%token K_ICMP4 K_ICMP6 %token K_UDP K_TCP %token ',' '{' '}' '(' ')' '[' ']' ':' '-' '+' '*' '/' '%' '&' '|' '<' '>' '^' @@ -594,6 +597,7 @@ proto | arp_proto { } | ip4_proto { } | ip6_proto { } + | icmp4_proto { } | icmpv6_proto { } | udp_proto { } | tcp_proto { } @@ -817,6 +821,41 @@ ip6 : K_IP6 { proto_add(PROTO_IP6); } ; +icmp4_proto + : icmp4 '(' icmp4_param_list ')' { } + ; + +icmp4_param_list + : { } + | icmp4_field { } + | icmp4_field delimiter icmp4_param_list { } + ; + +icmp4_field + : K_TYPE skip_white '=' skip_white number + { proto_field_set_u8(hdr, ICMPV4_TYPE, $5); } + | K_CODE skip_white '=' skip_white number + { proto_field_set_u8(hdr, ICMPV4_CODE, $5); } + | K_ID skip_white '=' skip_white number + { proto_field_set_be16(hdr, ICMPV4_ID, $5); } + | K_SEQ skip_white '=' skip_white number + { proto_field_set_be16(hdr, ICMPV4_SEQ, $5); } + | K_MTU skip_white '=' skip_white number + { proto_field_set_be16(hdr, ICMPV4_MTU, $5); } + | K_ADDR skip_white '=' skip_white ip4_addr + { proto_field_set_u32(hdr, ICMPV4_REDIR_ADDR, $5.s_addr); } + | K_ECHO_REQUEST + { proto_field_set_u8(hdr, ICMPV4_TYPE, ICMP_ECHO); + proto_field_set_u8(hdr, ICMPV4_CODE, 0); } + | K_ECHO_REPLY + { proto_field_set_u8(hdr, ICMPV4_TYPE, ICMP_ECHOREPLY); + proto_field_set_u8(hdr, ICMPV4_CODE, 0); } + ; + +icmp4 + : K_ICMP4 { proto_add(PROTO_ICMP4); } + ; + icmpv6_proto : icmp6 '(' icmp6_param_list ')' { } diff --git a/trafgen_proto.h b/trafgen_proto.h index 5528704..822d841 100644 --- a/trafgen_proto.h +++ b/trafgen_proto.h @@ -16,6 +16,7 @@ enum proto_id { PROTO_ARP, PROTO_MPLS, PROTO_IP4, + PROTO_ICMP4, PROTO_IP6, PROTO_ICMP6, PROTO_UDP, |