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
);
140 //////////////////////////////////////////////////////////////////////////////
142 libnet_ptag_t
create_ip_packet (libnet_t
*l
)
145 char argval
[MAX_PAYLOAD_SIZE
];
146 int i
, T
; // only an abbreviation for tx.packet_mode
149 return create_ip6_packet(l
);
151 // Default IP header fields
152 tx
.ip_len
= LIBNET_IPV4_H
; // Don't forget to add payload length
154 tx
.ip_frag
= 0; // Flags and Offset !!!
155 tx
.ip_sum
= 0; // default: automatically calculate checksum
158 // temporary variables
163 T
= tx
.packet_mode
; // >0 means automatic L2 creation
165 if ( (getarg(tx
.arg_string
,"help", NULL
)==1) && (mode
==IP
) )
169 cli_print(gcli
, "%s", MZ_IP_HELP
);
183 // Check if hex_payload already specified (externally)
184 if (tx
.hex_payload_s
)
186 memcpy( (void*) tx
.ip_payload
, (void*) tx
.hex_payload
, tx
.hex_payload_s
);
187 tx
.ip_payload_s
= tx
.hex_payload_s
;
191 // Evaluate CLI parameters:
193 if ( (getarg(tx
.arg_string
,"payload", argval
)==1) || (getarg(tx
.arg_string
,"p", argval
)==1))
196 tx
.ip_payload_s
= str2hex (argval
, tx
.ip_payload
, MAX_PAYLOAD_SIZE
);
198 // else payload has been specified as ASCII text via -P option
201 // NOTE: If 'mode' is NOT IP (e. g. UDP or TCP or something else)
202 // then the argument 'len' and 'sum' is NOT meant for the IP header!
203 // Instead the user can use 'iplen' and 'ipsum'.
206 if (getarg(tx
.arg_string
,"len", argval
)==1)
208 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
209 tx
.ip_len
= (u_int16_t
) str2int(argval
);
213 tx
.ip_len
= LIBNET_IPV4_H
+ tx
.ip_payload_s
;
216 if (getarg(tx
.arg_string
,"sum", argval
)==1)
218 if (T
) fprintf(stderr
, " IP_Warning: 'sum' cannot be set in this mode.\n");
219 tx
.ip_sum
= (u_int16_t
) str2int(argval
);
222 else // mode is NOT IP
224 if (getarg(tx
.arg_string
,"iplen", argval
)==1)
226 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
227 tx
.ip_len
= (u_int16_t
) str2int(argval
);
231 tx
.ip_len
= LIBNET_IPV4_H
+ tx
.ip_payload_s
;
234 if (getarg(tx
.arg_string
,"ipsum", argval
)==1)
236 if (T
) fprintf(stderr
, " IP_Warning: 'sum' cannot be set in this mode.\n");
237 tx
.ip_sum
= (u_int16_t
) str2int(argval
);
242 if (getarg(tx
.arg_string
,"tos", argval
)==1)
244 tx
.ip_tos
= (u_int8_t
) strtol(argval
,NULL
,16);
245 dummy
= (unsigned int) strtol(argval
,NULL
,16);
246 if (dummy
> 255) fprintf(stderr
, " IP_Warning: 'tos' too big, adjusted to LSBs\n");
249 if (getarg(tx
.arg_string
,"dscp", argval
)==1)
251 dummy
= (unsigned int) str2int(argval
);
254 fprintf(stderr
, " IP_Warning: 'dscp' too big, adjusted to 63\n");
257 tx
.ip_tos
= (u_int8_t
) dummy
*4;
260 if (getarg(tx
.arg_string
,"id", argval
)==1)
262 tx
.ip_id
= (u_int16_t
) str2int(argval
);
265 if (getarg(tx
.arg_string
,"frag", argval
)==1)
267 tx
.ip_frag
= (u_int16_t
) str2int(argval
);
270 if (getarg(tx
.arg_string
,"df", NULL
)==1)
272 tx
.ip_frag
|= 0x4000;
275 if (getarg(tx
.arg_string
,"mf", NULL
)==1)
277 tx
.ip_frag
|= 0x2000;
280 if (getarg(tx
.arg_string
,"rf", NULL
)==1)
282 tx
.ip_frag
|= 0x8000;
285 if (getarg(tx
.arg_string
, "ttl", argval
) == 1)
286 tx
.ip_ttl
= (u_int8_t
)str2int(argval
);
287 else if (tx
.ip_ttl
== 0)
290 if (getarg(tx
.arg_string
,"proto", argval
)==1)
292 tx
.ip_proto
= (u_int8_t
) str2int(argval
);
296 if ((tx
.ascii
)&&(mode
==IP
)) // ASCII PAYLOAD overrides hex payload
298 strncpy((char *)tx
.ip_payload
, (char *)tx
.ascii_payload
, MAX_PAYLOAD_SIZE
);
299 tx
.ip_payload_s
= strlen((char *)tx
.ascii_payload
);
300 tx
.ip_len
+= tx
.ip_payload_s
;
305 // Want some padding? The specified number of padding bytes are ADDED to the
306 // payload. Note that this is only evaluated if we are in IP mode because
307 // UDP and TCP already might have been padded and set the ip_payload_s.
308 // (Note the difference in send_eth() where you specified the total number
309 // of bytes in the frame)
311 if ((tx
.padding
)&&(mode
==IP
))
313 for (i
=0; i
<tx
.padding
; i
++)
315 tx
.ip_payload
[tx
.ip_payload_s
+i
] = 0x42; // pad with THE ANSWER (why random?)
317 tx
.ip_payload_s
+= tx
.padding
;
318 tx
.ip_len
+= tx
.padding
;
325 // Loose and Strict Source Route
326 // See RFC 791 for most the detailed description
328 if ( (getarg(tx
.arg_string
,"loose", argval
)==1) ||
329 (getarg(tx
.arg_string
,"strict", argval
)==1) )
331 len
= strlen(argval
);
333 if (len
<7) // not even a single dotted decimal IP address given!
335 fprintf(stderr
, " IP_Warning: Source route option requires at least one IP address!\n");
336 // But we allow this :-)
340 // determine how many IP addresses have been specified
342 for (i
=0; i
<len
; i
++)
344 if (ispunct(*(argval
+i
))) dummy
++ ;
346 dummy
= (dummy
+1) / 4; // the number of IP addresses
348 // Specify: type code, length, pointer
349 if (getarg(tx
.arg_string
,"loose", argval
)==1)
351 tx
.ip_option
[0] = 131; // loose source route
355 tx
.ip_option
[0] = 137; // strict source route
357 tx
.ip_option
[1] = 3+(dummy
*4); // length
358 tx
.ip_option
[2] = 4; // Use first IP address as next hop
359 //tx.ip_option[2] = 4+4*dummy; // smallest pointer, points to first address, which is
360 // the 4th byte within this option
363 s
= strtok(argval
, ".+-:;/>");
367 tx
.ip_option
[tx
.ip_option_s
] = (u_int8_t
) str2int(s
);
369 } while ( (s
=strtok(NULL
, ".+-:;/>")) != NULL
);
371 tx
.ip_option_s
++; // EOL
373 // add empty space for record route: //// NONSENSE? /////
375 for (i=0; i<(4*dummy); i++)
377 tx.ip_option[tx.ip_option_s] = 0x00;
385 // Allow any IP option specified as hex string
386 // An option can be a single byte or consist of multiple bytes in which case
387 // a length field is needed, see RFC 791.
388 if (getarg(tx
.arg_string
,"option", argval
)==1)
390 // check if conflicting with argument "loose" or "strict"
393 fprintf(stderr
, " IP_Error: Another IP option already specified. Please check your arguments.\n");
397 tx
.ip_option_s
= str2hex (argval
, tx
.ip_option
, 1023);
404 t
= libnet_build_ipv4_options (tx
.ip_option
,
408 tx
.ip_len
+= tx
.ip_option_s
;
413 // Did the user specify ANY payload? We require at least one byte!
415 if (!tx.ip_payload_s)
417 tx.ip_payload[0] = 0x42;
422 t
= libnet_build_ipv4 (tx
.ip_len
,
429 tx
.ip_src
, // init.c defaults this to own SA
430 tx
.ip_dst
, // init.c defaults this to 255.255.255.255
431 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
, // if e.g. mode=UDP ignore payload argument
432 (mode
==IP
) ? tx
.ip_payload_s
: 0,
435 (mode==IP) ? tx.ip_payload : NULL, // if e.g. mode=UDP ignore payload argument
436 (mode==IP) ? tx.ip_payload_s : 0,
444 fprintf(stderr
, " mz/create_ip_packet: Can't build IP header: %s\n", libnet_geterror(l
));
453 //////////////////////////////////////////////////////////////////////////////
454 // Prepare IPv6 packet
455 libnet_ptag_t
create_ip6_packet (libnet_t
*l
)
458 char argval
[MAX_PAYLOAD_SIZE
];
459 int i
, T
; // only an abbreviation for tx.packet_mode
461 // Default IP header fields
467 tx
.ip_frag
= 0; // Flags and Offset !!!
471 // temporary variables
476 T
= tx
.packet_mode
; // >0 means automatic L2 creation
478 if ( (getarg(tx
.arg_string
,"help", NULL
)==1) && (mode
==IP
) )
482 cli_print(gcli
, "%s", MZ_IP6_HELP
);
489 "\n%s", MZ_IP6_HELP
);
495 // Check if hex_payload already specified (externally)
496 if (tx
.hex_payload_s
)
498 memcpy( (void*) tx
.ip_payload
, (void*) tx
.hex_payload
, tx
.hex_payload_s
);
499 tx
.ip_payload_s
= tx
.hex_payload_s
;
502 // Evaluate CLI parameters:
503 if ( (getarg(tx
.arg_string
,"payload", argval
)==1) || (getarg(tx
.arg_string
,"p", argval
)==1))
506 tx
.ip_payload_s
= str2hex (argval
, tx
.ip_payload
, MAX_PAYLOAD_SIZE
);
508 // else payload has been specified as ASCII text via -P option
510 // NOTE: If 'mode' is NOT IP (e. g. UDP or TCP or something else)
511 // then the argument 'len' and 'sum' is NOT meant for the IP header!
512 // Instead the user can use 'iplen' and 'ipsum'.
515 if (getarg(tx
.arg_string
,"len", argval
)==1)
517 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
518 tx
.ip_len
= (u_int16_t
) str2int(argval
);
522 tx
.ip_len
+= tx
.ip_payload_s
;
525 else // mode is NOT IP
527 if (getarg(tx
.arg_string
,"iplen", argval
)==1)
529 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
530 tx
.ip_len
= (u_int16_t
) str2int(argval
);
534 tx
.ip_len
+= tx
.ip_payload_s
;
539 if (getarg(tx
.arg_string
,"tos", argval
)==1)
541 tx
.ip_tos
= (u_int8_t
) strtol(argval
,NULL
,16);
542 dummy
= (unsigned int) strtol(argval
,NULL
,16);
543 if (dummy
> 255) fprintf(stderr
, " IP_Warning: 'tos' too big, adjusted to LSBs\n");
546 if (getarg(tx
.arg_string
,"flow", argval
)==1)
548 dummy
= (unsigned int) strtol(argval
,NULL
,16);
551 fprintf(stderr
, " IP_Warning: 'flow label' too big, adjusted to 0xfffff\n");
557 if (getarg(tx
.arg_string
,"dscp", argval
)==1)
559 dummy
= (unsigned int) str2int(argval
);
562 fprintf(stderr
, " IP_Warning: 'dscp' too big, adjusted to 63\n");
565 tx
.ip_tos
= (u_int8_t
) dummy
*4;
568 if (getarg(tx
.arg_string
,"id", argval
)==1)
570 tx
.ip6_id
= str2int(argval
);
573 if (getarg(tx
.arg_string
,"frag", argval
)==1)
575 tx
.ip_frag
= ((u_int16_t
) str2int(argval
)) << 3;
578 if (getarg(tx
.arg_string
,"mf", NULL
)==1)
580 tx
.ip_frag
|= 0x0001;
583 if (getarg(tx
.arg_string
,"frag_res1", NULL
)==1)
585 tx
.ip_frag
|= 0x0002;
588 if (getarg(tx
.arg_string
,"frag_res2", NULL
)==1)
590 tx
.ip_frag
|= 0x0004;
593 if (getarg(tx
.arg_string
,"hop", argval
)==1)
595 tx
.ip_ttl
= (u_int8_t
) str2int(argval
);
598 if (getarg(tx
.arg_string
,"next", argval
)==1)
600 tx
.ip_proto
= (u_int8_t
) str2int(argval
);
604 tx
.ip_proto
= 59; // No Next Header for IPv6
608 if ((tx
.ascii
)&&(mode
==IP
)) // ASCII PAYLOAD overrides hex payload
610 strncpy((char *)tx
.ip_payload
, (char *)tx
.ascii_payload
, MAX_PAYLOAD_SIZE
);
611 tx
.ip_payload_s
= strlen((char *)tx
.ascii_payload
);
612 tx
.ip_len
+= tx
.ip_payload_s
;
617 // Want some padding? The specified number of padding bytes are ADDED to the
618 // payload. Note that this is only evaluated if we are in IP mode because
619 // UDP and TCP already might have been padded and set the ip_payload_s.
620 // (Note the difference in send_eth() where you specified the total number
621 // of bytes in the frame)
623 if ((tx
.padding
)&&(mode
==IP
))
625 for (i
=0; i
<tx
.padding
; i
++)
627 tx
.ip_payload
[tx
.ip_payload_s
+i
] = 0x42; // pad with THE ANSWER (why random?)
629 tx
.ip_payload_s
+= tx
.padding
;
630 tx
.ip_len
+= tx
.padding
;
634 t
= libnet_build_ipv6_frag (tx
.ip_proto
,
638 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
639 (mode
==IP
) ? tx
.ip_payload_s
: 0,
642 tx
.ip_len
+= LIBNET_IPV6_FRAG_H
;
644 tx
.ip_proto
= LIBNET_IPV6_NH_FRAGMENT
;
647 // See RFC 2460 Routing Header
649 if ( (getarg(tx
.arg_string
,"segments", argval
)==1) )
651 dummy
= (unsigned int) str2int(argval
);
653 fprintf(stderr
, " IP_Error: Maximal Routing Segments are 255!\n");
659 if ( (getarg(tx
.arg_string
,"rtype", argval
)==1) )
661 dummy
= (unsigned int) str2int(argval
);
663 fprintf(stderr
, " IP_Error: Maximum Routing Type is 255!\n");
669 if ( (getarg(tx
.arg_string
,"loose", argval
)==1) )
672 memset(tx
.ip_option
, 0, 4);
675 len
= strlen(argval
);
676 s
= strtok(argval
, ".+-;/>");
680 *((struct libnet_in6_addr
*) &tx
.ip_option
[tx
.ip_option_s
]) = libnet_name2addr6 (l
, s
, LIBNET_DONT_RESOLVE
);
681 tx
.ip_option_s
+= 16;
682 } while ( (s
=strtok(NULL
, ".+-;/>")) != NULL
);
684 if (!tx
.ip_option_s
) {
685 fprintf(stderr
, " IP_Error: No Routing Hops found!\n");
689 if (mode
==IP
&& tx
.ip_payload_s
)
690 memmove(tx
.ip_payload
+tx
.ip_option_s
, tx
.ip_payload
, tx
.ip_payload_s
);
694 memcpy(tx
.ip_payload
, tx
.ip_option
, tx
.ip_option_s
);
695 tx
.ip_payload_s
+= tx
.ip_option_s
;
697 t
= libnet_build_ipv6_routing(tx
.ip_proto
,
698 (tx
.ip_option_s
-4) / 8,
705 tx
.ip_len
+= LIBNET_IPV6_ROUTING_H
+ tx
.ip_option_s
;
707 tx
.ip_proto
= LIBNET_IPV6_NH_ROUTING
;
710 t
= libnet_build_ipv6 (tx
.ip_tos
,
717 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
718 (mode
==IP
) ? tx
.ip_payload_s
: 0,
724 fprintf(stderr
, " mz/create_ip_packet: Can't build IPv6 header: %s\n", libnet_geterror(l
));