2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
21 // ***************************************************************************
22 // This sections contains functions to send various L3-based PDUs such as
26 // (ahem, yes this is currently all here...)
28 // ***************************************************************************
34 "| IP type: Send raw IP packets.\n" \
36 "| Supports L3 mode (automatic L2 creation) or 'L2-L3' mode (MAC addresses must be provided).\n" \
37 "| In L3 mode the IP checksum and length cannot be manipulated to wrong values (currently).\n" \
38 "| The L2-L3 mode is activated when specifying any MAC addresses on the command line\n" \
39 "| (options -a, -b). \n" \
41 "| The IP addresses can be specified via the -A and -B options, which identify the source\n" \
42 "| and destination addresses, respectively. A dotted decimal notation, an IP range, or a\n" \
43 "| FQDN can be used. The source address can also be random (-A rand).\n" \
45 "| ARGUMENT SYNTAX: [<comma separated parameter list>]\n" \
49 "| len 0-65535 Only accessible in L2 mode\n" \
50 "| sum 0-65535 Only accessible in L2 mode (0 means auto-calculation)\n" \
51 "| tos 00-ff Full 8-bit control via hex input (use this also for ECN bits).\n" \
52 "| dscp 0-63 Allows easier specification of DSCP (PHB and Drop Propability)\n" \
55 "| frag 0-65535 Includes flags (MSB) and offset (LSB)\n" \
56 "| df Sets the \"Don't Fragment\" flag\n" \
57 "| mf Sets the \"More Fragments\" flag\n" \
58 "| rf Sets the reserved flag.\n" \
60 "| loose <addresses> Loose Source Route (LSR) option; specify a sequence of hops\n" \
61 "| using the notation: 1.1.1.1+2.2.2.2+3.3.3.3+...\n" \
62 "| strict <addresses> Strict Source Route (SSR) option; same address notation as above\n" \
63 "| option <hex_string> Specify any IP option using a hexadecimal string (aa:bb:cc:...)\n" \
65 "| Additionally the Ethertype can be specified:\n" \
67 "| ether_type 00:00-ff:ff Only accessible in L2 mode (default = 08:00 = IPv4)\n" \
72 "| IP type: Send raw IPv6 packets.\n" \
74 "| Supports L3 mode (automatic L2 creation) or 'L2-L3' mode (MAC addresses must be provided).\n" \
75 "| In L3 mode the IP checksum and length cannot be manipulated to wrong values (currently).\n" \
76 "| The L2-L3 mode is activated when specifying any MAC addresses on the command line\n" \
77 "| (options -a, -b). \n" \
79 "| ARGUMENT SYNTAX: [<comma separated parameter list>]\n" \
83 "| len 0-65535 Only accessible in L2 mode\n" \
84 "| sum 0-65535 Only accessible in L2 mode (0 means auto-calculation)\n" \
85 "| tos 00-ff Full 8-bit control via hex input (use this also for ECN bits).\n" \
86 "| dscp 0-63 Allows easier specification of DSCP (PHB and Drop Propability)\n" \
87 "| flow 0-1048575 Flow label\n" \
88 "| hop 0-255 Hop limit\n" \
89 "| next 0-255 Next protocol or header type\n" \
90 "| frag 0-65535 Includes flags (MSB) and offset (LSB)\n" \
91 "| mf Sets the \"More Fragments\" flag\n" \
92 "| frag_res1 Sets the reserved flag 1.\n" \
93 "| frag_res2 Sets the reserved flag 2.\n" \
94 "| id 0-65535 Fragment ID\n" \
95 "| loose <addresses> Source Routing Header\n" \
96 "| rtype 0,2 Source Routing Type: 0 (Deprecated in RFC 5095) or 2 for Mobile IP\n" \
97 "| segments 0-255 Number of route segments left, used by RH0\n" \
99 "| Additionally the Ethertype can be specified:\n" \
101 "| ether_type 00:00-ff:ff Only accessible in L2 mode (default = 86:dd = IPv6)\n" \
105 // Only used to simplify initialization of libnet
106 // Return pointer to context
107 libnet_t
* get_link_context(void)
110 char errbuf
[LIBNET_ERRBUF_SIZE
];
112 // Don't open context if only a help text is requested
113 if (getarg(tx
.arg_string
,"help", NULL
)==1)
120 { // Let libnet create an appropriate Ethernet frame
122 l
= libnet_init (LIBNET_RAW6_ADV
, tx
.device
, errbuf
);
124 l
= libnet_init (LIBNET_RAW4_ADV
, tx
.device
, errbuf
);
126 else // User specified Ethernet header details (src or dst)
128 l
= libnet_init (LIBNET_LINK_ADV
, tx
.device
, errbuf
);
133 fprintf(stderr
, "%s", errbuf
);
138 setsockopt (libnet_getfd (l
), SOL_SOCKET
, SO_PRIORITY
, &tx
.prio
,
141 perror("setsockopt SO_PRIORITY");
149 //////////////////////////////////////////////////////////////////////////////
151 libnet_ptag_t
create_ip_packet (libnet_t
*l
)
154 char argval
[MAX_PAYLOAD_SIZE
];
155 int i
, T
; // only an abbreviation for tx.packet_mode
158 return create_ip6_packet(l
);
160 // Default IP header fields
161 tx
.ip_len
= LIBNET_IPV4_H
; // Don't forget to add payload length
163 tx
.ip_frag
= 0; // Flags and Offset !!!
164 tx
.ip_sum
= 0; // default: automatically calculate checksum
167 // temporary variables
172 T
= tx
.packet_mode
; // >0 means automatic L2 creation
174 if ( (getarg(tx
.arg_string
,"help", NULL
)==1) && (mode
==IP
) )
178 cli_print(gcli
, "%s", MZ_IP_HELP
);
192 // Check if hex_payload already specified (externally)
193 if (tx
.hex_payload_s
)
195 memcpy( (void*) tx
.ip_payload
, (void*) tx
.hex_payload
, tx
.hex_payload_s
);
196 tx
.ip_payload_s
= tx
.hex_payload_s
;
200 // Evaluate CLI parameters:
202 if ( (getarg(tx
.arg_string
,"payload", argval
)==1) || (getarg(tx
.arg_string
,"p", argval
)==1))
205 tx
.ip_payload_s
= str2hex (argval
, tx
.ip_payload
, MAX_PAYLOAD_SIZE
);
207 // else payload has been specified as ASCII text via -P option
210 // NOTE: If 'mode' is NOT IP (e. g. UDP or TCP or something else)
211 // then the argument 'len' and 'sum' is NOT meant for the IP header!
212 // Instead the user can use 'iplen' and 'ipsum'.
215 if (getarg(tx
.arg_string
,"len", argval
)==1)
217 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
218 tx
.ip_len
= (u_int16_t
) str2int(argval
);
222 tx
.ip_len
= LIBNET_IPV4_H
+ tx
.ip_payload_s
;
225 if (getarg(tx
.arg_string
,"sum", argval
)==1)
227 if (T
) fprintf(stderr
, " IP_Warning: 'sum' cannot be set in this mode.\n");
228 tx
.ip_sum
= (u_int16_t
) str2int(argval
);
231 else // mode is NOT IP
233 if (getarg(tx
.arg_string
,"iplen", argval
)==1)
235 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
236 tx
.ip_len
= (u_int16_t
) str2int(argval
);
240 tx
.ip_len
= LIBNET_IPV4_H
+ tx
.ip_payload_s
;
243 if (getarg(tx
.arg_string
,"ipsum", argval
)==1)
245 if (T
) fprintf(stderr
, " IP_Warning: 'sum' cannot be set in this mode.\n");
246 tx
.ip_sum
= (u_int16_t
) str2int(argval
);
251 if (getarg(tx
.arg_string
,"tos", argval
)==1)
253 tx
.ip_tos
= (u_int8_t
) strtol(argval
,NULL
,16);
254 dummy
= (unsigned int) strtol(argval
,NULL
,16);
255 if (dummy
> 255) fprintf(stderr
, " IP_Warning: 'tos' too big, adjusted to LSBs\n");
258 if (getarg(tx
.arg_string
,"dscp", argval
)==1)
260 dummy
= (unsigned int) str2int(argval
);
263 fprintf(stderr
, " IP_Warning: 'dscp' too big, adjusted to 63\n");
266 tx
.ip_tos
= (u_int8_t
) dummy
*4;
269 if (getarg(tx
.arg_string
,"id", argval
)==1)
271 tx
.ip_id
= (u_int16_t
) str2int(argval
);
274 if (getarg(tx
.arg_string
,"frag", argval
)==1)
276 tx
.ip_frag
= (u_int16_t
) str2int(argval
);
279 if (getarg(tx
.arg_string
,"df", NULL
)==1)
281 tx
.ip_frag
|= 0x4000;
284 if (getarg(tx
.arg_string
,"mf", NULL
)==1)
286 tx
.ip_frag
|= 0x2000;
289 if (getarg(tx
.arg_string
,"rf", NULL
)==1)
291 tx
.ip_frag
|= 0x8000;
294 if (getarg(tx
.arg_string
, "ttl", argval
) == 1)
295 tx
.ip_ttl
= (u_int8_t
)str2int(argval
);
296 else if (tx
.ip_ttl
== 0)
299 if (getarg(tx
.arg_string
,"proto", argval
)==1)
301 tx
.ip_proto
= (u_int8_t
) str2int(argval
);
305 if ((tx
.ascii
)&&(mode
==IP
)) // ASCII PAYLOAD overrides hex payload
307 strncpy((char *)tx
.ip_payload
, (char *)tx
.ascii_payload
, MAX_PAYLOAD_SIZE
);
308 tx
.ip_payload_s
= strlen((char *)tx
.ascii_payload
);
309 tx
.ip_len
+= tx
.ip_payload_s
;
314 // Want some padding? The specified number of padding bytes are ADDED to the
315 // payload. Note that this is only evaluated if we are in IP mode because
316 // UDP and TCP already might have been padded and set the ip_payload_s.
317 // (Note the difference in send_eth() where you specified the total number
318 // of bytes in the frame)
320 if ((tx
.padding
)&&(mode
==IP
))
322 for (i
=0; i
<tx
.padding
; i
++)
324 tx
.ip_payload
[tx
.ip_payload_s
+i
] = 0x42; // pad with THE ANSWER (why random?)
326 tx
.ip_payload_s
+= tx
.padding
;
327 tx
.ip_len
+= tx
.padding
;
334 // Loose and Strict Source Route
335 // See RFC 791 for most the detailed description
337 if ( (getarg(tx
.arg_string
,"loose", argval
)==1) ||
338 (getarg(tx
.arg_string
,"strict", argval
)==1) )
340 len
= strlen(argval
);
342 if (len
<7) // not even a single dotted decimal IP address given!
344 fprintf(stderr
, " IP_Warning: Source route option requires at least one IP address!\n");
345 // But we allow this :-)
349 // determine how many IP addresses have been specified
351 for (i
=0; i
<len
; i
++)
353 if (ispunct(*(argval
+i
))) dummy
++ ;
355 dummy
= (dummy
+1) / 4; // the number of IP addresses
357 // Specify: type code, length, pointer
358 if (getarg(tx
.arg_string
,"loose", argval
)==1)
360 tx
.ip_option
[0] = 131; // loose source route
364 tx
.ip_option
[0] = 137; // strict source route
366 tx
.ip_option
[1] = 3+(dummy
*4); // length
367 tx
.ip_option
[2] = 4; // Use first IP address as next hop
368 //tx.ip_option[2] = 4+4*dummy; // smallest pointer, points to first address, which is
369 // the 4th byte within this option
372 s
= strtok(argval
, ".+-:;/>");
376 tx
.ip_option
[tx
.ip_option_s
] = (u_int8_t
) str2int(s
);
378 } while ( (s
=strtok(NULL
, ".+-:;/>")) != NULL
);
380 tx
.ip_option_s
++; // EOL
382 // add empty space for record route: //// NONSENSE? /////
384 for (i=0; i<(4*dummy); i++)
386 tx.ip_option[tx.ip_option_s] = 0x00;
394 // Allow any IP option specified as hex string
395 // An option can be a single byte or consist of multiple bytes in which case
396 // a length field is needed, see RFC 791.
397 if (getarg(tx
.arg_string
,"option", argval
)==1)
399 // check if conflicting with argument "loose" or "strict"
402 fprintf(stderr
, " IP_Error: Another IP option already specified. Please check your arguments.\n");
406 tx
.ip_option_s
= str2hex (argval
, tx
.ip_option
, 1023);
413 t
= libnet_build_ipv4_options (tx
.ip_option
,
417 tx
.ip_len
+= tx
.ip_option_s
;
422 // Did the user specify ANY payload? We require at least one byte!
424 if (!tx.ip_payload_s)
426 tx.ip_payload[0] = 0x42;
431 t
= libnet_build_ipv4 (tx
.ip_len
,
438 tx
.ip_src
, // init.c defaults this to own SA
439 tx
.ip_dst
, // init.c defaults this to 255.255.255.255
440 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
, // if e.g. mode=UDP ignore payload argument
441 (mode
==IP
) ? tx
.ip_payload_s
: 0,
444 (mode==IP) ? tx.ip_payload : NULL, // if e.g. mode=UDP ignore payload argument
445 (mode==IP) ? tx.ip_payload_s : 0,
453 fprintf(stderr
, " mz/create_ip_packet: Can't build IP header: %s\n", libnet_geterror(l
));
462 //////////////////////////////////////////////////////////////////////////////
463 // Prepare IPv6 packet
464 libnet_ptag_t
create_ip6_packet (libnet_t
*l
)
467 char argval
[MAX_PAYLOAD_SIZE
];
468 int i
, T
; // only an abbreviation for tx.packet_mode
470 // Default IP header fields
476 tx
.ip_frag
= 0; // Flags and Offset !!!
480 // temporary variables
485 T
= tx
.packet_mode
; // >0 means automatic L2 creation
487 if ( (getarg(tx
.arg_string
,"help", NULL
)==1) && (mode
==IP
) )
491 cli_print(gcli
, "%s", MZ_IP6_HELP
);
498 "\n%s", MZ_IP6_HELP
);
504 // Check if hex_payload already specified (externally)
505 if (tx
.hex_payload_s
)
507 memcpy( (void*) tx
.ip_payload
, (void*) tx
.hex_payload
, tx
.hex_payload_s
);
508 tx
.ip_payload_s
= tx
.hex_payload_s
;
511 // Evaluate CLI parameters:
512 if ( (getarg(tx
.arg_string
,"payload", argval
)==1) || (getarg(tx
.arg_string
,"p", argval
)==1))
515 tx
.ip_payload_s
= str2hex (argval
, tx
.ip_payload
, MAX_PAYLOAD_SIZE
);
517 // else payload has been specified as ASCII text via -P option
519 // NOTE: If 'mode' is NOT IP (e. g. UDP or TCP or something else)
520 // then the argument 'len' and 'sum' is NOT meant for the IP header!
521 // Instead the user can use 'iplen' and 'ipsum'.
524 if (getarg(tx
.arg_string
,"len", argval
)==1)
526 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
527 tx
.ip_len
= (u_int16_t
) str2int(argval
);
531 tx
.ip_len
+= tx
.ip_payload_s
;
534 else // mode is NOT IP
536 if (getarg(tx
.arg_string
,"iplen", argval
)==1)
538 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
539 tx
.ip_len
= (u_int16_t
) str2int(argval
);
543 tx
.ip_len
+= tx
.ip_payload_s
;
548 if (getarg(tx
.arg_string
,"tos", argval
)==1)
550 tx
.ip_tos
= (u_int8_t
) strtol(argval
,NULL
,16);
551 dummy
= (unsigned int) strtol(argval
,NULL
,16);
552 if (dummy
> 255) fprintf(stderr
, " IP_Warning: 'tos' too big, adjusted to LSBs\n");
555 if (getarg(tx
.arg_string
,"flow", argval
)==1)
557 dummy
= (unsigned int) strtol(argval
,NULL
,16);
560 fprintf(stderr
, " IP_Warning: 'flow label' too big, adjusted to 0xfffff\n");
566 if (getarg(tx
.arg_string
,"dscp", argval
)==1)
568 dummy
= (unsigned int) str2int(argval
);
571 fprintf(stderr
, " IP_Warning: 'dscp' too big, adjusted to 63\n");
574 tx
.ip_tos
= (u_int8_t
) dummy
*4;
577 if (getarg(tx
.arg_string
,"id", argval
)==1)
579 tx
.ip6_id
= str2int(argval
);
582 if (getarg(tx
.arg_string
,"frag", argval
)==1)
584 tx
.ip_frag
= ((u_int16_t
) str2int(argval
)) << 3;
587 if (getarg(tx
.arg_string
,"mf", NULL
)==1)
589 tx
.ip_frag
|= 0x0001;
592 if (getarg(tx
.arg_string
,"frag_res1", NULL
)==1)
594 tx
.ip_frag
|= 0x0002;
597 if (getarg(tx
.arg_string
,"frag_res2", NULL
)==1)
599 tx
.ip_frag
|= 0x0004;
602 if (getarg(tx
.arg_string
,"hop", argval
)==1)
604 tx
.ip_ttl
= (u_int8_t
) str2int(argval
);
607 if (getarg(tx
.arg_string
,"next", argval
)==1)
609 tx
.ip_proto
= (u_int8_t
) str2int(argval
);
613 tx
.ip_proto
= 59; // No Next Header for IPv6
617 if ((tx
.ascii
)&&(mode
==IP
)) // ASCII PAYLOAD overrides hex payload
619 strncpy((char *)tx
.ip_payload
, (char *)tx
.ascii_payload
, MAX_PAYLOAD_SIZE
);
620 tx
.ip_payload_s
= strlen((char *)tx
.ascii_payload
);
621 tx
.ip_len
+= tx
.ip_payload_s
;
626 // Want some padding? The specified number of padding bytes are ADDED to the
627 // payload. Note that this is only evaluated if we are in IP mode because
628 // UDP and TCP already might have been padded and set the ip_payload_s.
629 // (Note the difference in send_eth() where you specified the total number
630 // of bytes in the frame)
632 if ((tx
.padding
)&&(mode
==IP
))
634 for (i
=0; i
<tx
.padding
; i
++)
636 tx
.ip_payload
[tx
.ip_payload_s
+i
] = 0x42; // pad with THE ANSWER (why random?)
638 tx
.ip_payload_s
+= tx
.padding
;
639 tx
.ip_len
+= tx
.padding
;
643 t
= libnet_build_ipv6_frag (tx
.ip_proto
,
647 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
648 (mode
==IP
) ? tx
.ip_payload_s
: 0,
651 tx
.ip_len
+= LIBNET_IPV6_FRAG_H
;
653 tx
.ip_proto
= LIBNET_IPV6_NH_FRAGMENT
;
656 // See RFC 2460 Routing Header
658 if ( (getarg(tx
.arg_string
,"segments", argval
)==1) )
660 dummy
= (unsigned int) str2int(argval
);
662 fprintf(stderr
, " IP_Error: Maximal Routing Segments are 255!\n");
668 if ( (getarg(tx
.arg_string
,"rtype", argval
)==1) )
670 dummy
= (unsigned int) str2int(argval
);
672 fprintf(stderr
, " IP_Error: Maximum Routing Type is 255!\n");
678 if ( (getarg(tx
.arg_string
,"loose", argval
)==1) )
681 memset(tx
.ip_option
, 0, 4);
684 len
= strlen(argval
);
685 s
= strtok(argval
, ".+-;/>");
689 *((struct libnet_in6_addr
*) &tx
.ip_option
[tx
.ip_option_s
]) = libnet_name2addr6 (l
, s
, LIBNET_DONT_RESOLVE
);
690 tx
.ip_option_s
+= 16;
691 } while ( (s
=strtok(NULL
, ".+-;/>")) != NULL
);
693 if (!tx
.ip_option_s
) {
694 fprintf(stderr
, " IP_Error: No Routing Hops found!\n");
698 if (mode
==IP
&& tx
.ip_payload_s
)
699 memmove(tx
.ip_payload
+tx
.ip_option_s
, tx
.ip_payload
, tx
.ip_payload_s
);
703 memcpy(tx
.ip_payload
, tx
.ip_option
, tx
.ip_option_s
);
704 tx
.ip_payload_s
+= tx
.ip_option_s
;
706 t
= libnet_build_ipv6_routing(tx
.ip_proto
,
707 (tx
.ip_option_s
-4) / 8,
714 tx
.ip_len
+= LIBNET_IPV6_ROUTING_H
+ tx
.ip_option_s
;
716 tx
.ip_proto
= LIBNET_IPV6_NH_ROUTING
;
719 t
= libnet_build_ipv6 (tx
.ip_tos
,
726 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
727 (mode
==IP
) ? tx
.ip_payload_s
: 0,
733 fprintf(stderr
, " mz/create_ip_packet: Can't build IPv6 header: %s\n", libnet_geterror(l
));