summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Kochan <vadim4j@gmail.com>2016-07-13 01:01:53 +0300
committerTobias Klauser <tklauser@distanz.ch>2016-07-13 09:32:07 +0200
commit423bb070d372341aa178849a9479099b95c7d352 (patch)
treece5a939c07d84d05ea29be0458f51b2ed02af282
parente6fcf1f0f2c58cf38fad98d1d8b00a3b7ebd3070 (diff)
trafgen: proto: Add ICMPv4 header generation
Support for generating ICMPv4 headers using the 'icmp4()/icmpv4()' trafgen generation functions. Fields supported: type Set type field (default 0: Echo reply) Supported keywords: echorequest, echoreply code Set code field (default 0) csum Set checksum field (calculated by default) mtu Set mtu field for destination unreachable (default 0) seq Set sequence field (default 0) id Set identifier field (default 0) addr Set redirect address (default 0.0.0.0) Example (send ping request): { icmpv4(echorequest, seq=1, id=1326) } Signed-off-by: Vadim Kochan <vadim4j@gmail.com> [tk: squash commits, consistency between functionality and docu] Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
-rw-r--r--trafgen.840
-rw-r--r--trafgen_l3.c3
-rw-r--r--trafgen_l4.c42
-rw-r--r--trafgen_l4.h10
-rw-r--r--trafgen_lexer.l6
-rw-r--r--trafgen_parser.y41
-rw-r--r--trafgen_proto.h1
7 files changed, 142 insertions, 1 deletions
diff --git a/trafgen.8 b/trafgen.8
index b011276..c958794 100644
--- a/trafgen.8
+++ b/trafgen.8
@@ -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,