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()
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
160 // temporary variables
166 T
= tx
.packet_mode
; // >0 means automatic L2 creation
168 if ( (getarg(tx
.arg_string
,"help", NULL
)==1) && (mode
==IP
) )
172 cli_print(gcli
, "%s", MZ_IP_HELP
);
186 // Check if hex_payload already specified (externally)
187 if (tx
.hex_payload_s
)
189 memcpy( (void*) tx
.ip_payload
, (void*) tx
.hex_payload
, tx
.hex_payload_s
);
190 tx
.ip_payload_s
= tx
.hex_payload_s
;
194 // Evaluate CLI parameters:
196 if ( (getarg(tx
.arg_string
,"payload", argval
)==1) || (getarg(tx
.arg_string
,"p", argval
)==1))
199 tx
.ip_payload_s
= str2hex (argval
, tx
.ip_payload
, MAX_PAYLOAD_SIZE
);
201 // else payload has been specified as ASCII text via -P option
204 // NOTE: If 'mode' is NOT IP (e. g. UDP or TCP or something else)
205 // then the argument 'len' and 'sum' is NOT meant for the IP header!
206 // Instead the user can use 'iplen' and 'ipsum'.
209 if (getarg(tx
.arg_string
,"len", argval
)==1)
211 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
212 tx
.ip_len
= (u_int16_t
) str2int(argval
);
216 tx
.ip_len
= LIBNET_IPV4_H
+ tx
.ip_payload_s
;
219 if (getarg(tx
.arg_string
,"sum", argval
)==1)
221 if (T
) fprintf(stderr
, " IP_Warning: 'sum' cannot be set in this mode.\n");
222 tx
.ip_sum
= (u_int16_t
) str2int(argval
);
225 else // mode is NOT IP
227 if (getarg(tx
.arg_string
,"iplen", argval
)==1)
229 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
230 tx
.ip_len
= (u_int16_t
) str2int(argval
);
234 tx
.ip_len
= LIBNET_IPV4_H
+ tx
.ip_payload_s
;
237 if (getarg(tx
.arg_string
,"ipsum", argval
)==1)
239 if (T
) fprintf(stderr
, " IP_Warning: 'sum' cannot be set in this mode.\n");
240 tx
.ip_sum
= (u_int16_t
) str2int(argval
);
245 if (getarg(tx
.arg_string
,"tos", argval
)==1)
247 tx
.ip_tos
= (u_int8_t
) strtol(argval
,NULL
,16);
248 dummy
= (unsigned int) strtol(argval
,NULL
,16);
249 if (dummy
> 255) fprintf(stderr
, " IP_Warning: 'tos' too big, adjusted to LSBs\n");
252 if (getarg(tx
.arg_string
,"dscp", argval
)==1)
254 dummy
= (unsigned int) str2int(argval
);
257 fprintf(stderr
, " IP_Warning: 'dscp' too big, adjusted to 63\n");
260 tx
.ip_tos
= (u_int8_t
) dummy
*4;
263 if (getarg(tx
.arg_string
,"id", argval
)==1)
265 tx
.ip_id
= (u_int16_t
) str2int(argval
);
268 if (getarg(tx
.arg_string
,"frag", argval
)==1)
270 tx
.ip_frag
= (u_int16_t
) str2int(argval
);
273 if (getarg(tx
.arg_string
,"df", NULL
)==1)
275 tx
.ip_frag
|= 0x4000;
278 if (getarg(tx
.arg_string
,"mf", NULL
)==1)
280 tx
.ip_frag
|= 0x2000;
283 if (getarg(tx
.arg_string
,"rf", NULL
)==1)
285 tx
.ip_frag
|= 0x8000;
289 if (getarg(tx
.arg_string
,"ttl", argval
)==1)
291 tx
.ip_ttl
= (u_int8_t
) str2int(argval
);
294 if (getarg(tx
.arg_string
,"proto", argval
)==1)
296 tx
.ip_proto
= (u_int8_t
) str2int(argval
);
300 if ((tx
.ascii
)&&(mode
==IP
)) // ASCII PAYLOAD overrides hex payload
302 strncpy((char *)tx
.ip_payload
, (char *)tx
.ascii_payload
, MAX_PAYLOAD_SIZE
);
303 tx
.ip_payload_s
= strlen((char *)tx
.ascii_payload
);
304 tx
.ip_len
+= tx
.ip_payload_s
;
309 // Want some padding? The specified number of padding bytes are ADDED to the
310 // payload. Note that this is only evaluated if we are in IP mode because
311 // UDP and TCP already might have been padded and set the ip_payload_s.
312 // (Note the difference in send_eth() where you specified the total number
313 // of bytes in the frame)
315 if ((tx
.padding
)&&(mode
==IP
))
317 for (i
=0; i
<tx
.padding
; i
++)
319 tx
.ip_payload
[tx
.ip_payload_s
+i
] = 0x42; // pad with THE ANSWER (why random?)
321 tx
.ip_payload_s
+= tx
.padding
;
322 tx
.ip_len
+= tx
.padding
;
329 // Loose and Strict Source Route
330 // See RFC 791 for most the detailed description
332 if ( (getarg(tx
.arg_string
,"loose", argval
)==1) ||
333 (getarg(tx
.arg_string
,"strict", argval
)==1) )
335 len
= strlen(argval
);
337 if (len
<7) // not even a single dotted decimal IP address given!
339 fprintf(stderr
, " IP_Warning: Source route option requires at least one IP address!\n");
340 // But we allow this :-)
344 // determine how many IP addresses have been specified
346 for (i
=0; i
<len
; i
++)
348 if (ispunct(*(argval
+i
))) dummy
++ ;
350 dummy
= (dummy
+1) / 4; // the number of IP addresses
352 // Specify: type code, length, pointer
353 if (getarg(tx
.arg_string
,"loose", argval
)==1)
355 tx
.ip_option
[0] = 131; // loose source route
359 tx
.ip_option
[0] = 137; // strict source route
361 tx
.ip_option
[1] = 3+(dummy
*4); // length
362 tx
.ip_option
[2] = 4; // Use first IP address as next hop
363 //tx.ip_option[2] = 4+4*dummy; // smallest pointer, points to first address, which is
364 // the 4th byte within this option
367 s
= strtok(argval
, ".+-:;/>");
371 tx
.ip_option
[tx
.ip_option_s
] = (u_int8_t
) str2int(s
);
373 } while ( (s
=strtok(NULL
, ".+-:;/>")) != NULL
);
375 tx
.ip_option_s
++; // EOL
377 // add empty space for record route: //// NONSENSE? /////
379 for (i=0; i<(4*dummy); i++)
381 tx.ip_option[tx.ip_option_s] = 0x00;
389 // Allow any IP option specified as hex string
390 // An option can be a single byte or consist of multiple bytes in which case
391 // a length field is needed, see RFC 791.
392 if (getarg(tx
.arg_string
,"option", argval
)==1)
394 // check if conflicting with argument "loose" or "strict"
397 fprintf(stderr
, " IP_Error: Another IP option already specified. Please check your arguments.\n");
401 tx
.ip_option_s
= str2hex (argval
, tx
.ip_option
, 1023);
408 t
= libnet_build_ipv4_options (tx
.ip_option
,
412 tx
.ip_len
+= tx
.ip_option_s
;
417 // Did the user specify ANY payload? We require at least one byte!
419 if (!tx.ip_payload_s)
421 tx.ip_payload[0] = 0x42;
426 t
= libnet_build_ipv4 (tx
.ip_len
,
433 tx
.ip_src
, // init.c defaults this to own SA
434 tx
.ip_dst
, // init.c defaults this to 255.255.255.255
435 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
, // if e.g. mode=UDP ignore payload argument
436 (mode
==IP
) ? tx
.ip_payload_s
: 0,
439 (mode==IP) ? tx.ip_payload : NULL, // if e.g. mode=UDP ignore payload argument
440 (mode==IP) ? tx.ip_payload_s : 0,
448 fprintf(stderr
, " mz/create_ip_packet: Can't build IP header: %s\n", libnet_geterror(l
));
457 //////////////////////////////////////////////////////////////////////////////
458 // Prepare IPv6 packet
459 libnet_ptag_t
create_ip6_packet (libnet_t
*l
)
462 char argval
[MAX_PAYLOAD_SIZE
];
463 int i
, T
; // only an abbreviation for tx.packet_mode
465 // Default IP header fields
471 tx
.ip_frag
= 0; // Flags and Offset !!!
475 // temporary variables
480 T
= tx
.packet_mode
; // >0 means automatic L2 creation
482 if ( (getarg(tx
.arg_string
,"help", NULL
)==1) && (mode
==IP
) )
486 cli_print(gcli
, "%s", MZ_IP6_HELP
);
493 "\n%s", MZ_IP6_HELP
);
499 // Check if hex_payload already specified (externally)
500 if (tx
.hex_payload_s
)
502 memcpy( (void*) tx
.ip_payload
, (void*) tx
.hex_payload
, tx
.hex_payload_s
);
503 tx
.ip_payload_s
= tx
.hex_payload_s
;
506 // Evaluate CLI parameters:
507 if ( (getarg(tx
.arg_string
,"payload", argval
)==1) || (getarg(tx
.arg_string
,"p", argval
)==1))
510 tx
.ip_payload_s
= str2hex (argval
, tx
.ip_payload
, MAX_PAYLOAD_SIZE
);
512 // else payload has been specified as ASCII text via -P option
514 // NOTE: If 'mode' is NOT IP (e. g. UDP or TCP or something else)
515 // then the argument 'len' and 'sum' is NOT meant for the IP header!
516 // Instead the user can use 'iplen' and 'ipsum'.
519 if (getarg(tx
.arg_string
,"len", argval
)==1)
521 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
522 tx
.ip_len
= (u_int16_t
) str2int(argval
);
526 tx
.ip_len
+= tx
.ip_payload_s
;
529 else // mode is NOT IP
531 if (getarg(tx
.arg_string
,"iplen", argval
)==1)
533 if (T
) fprintf(stderr
, " IP_Warning: 'len' cannot be set in this mode.\n");
534 tx
.ip_len
= (u_int16_t
) str2int(argval
);
538 tx
.ip_len
+= tx
.ip_payload_s
;
543 if (getarg(tx
.arg_string
,"tos", argval
)==1)
545 tx
.ip_tos
= (u_int8_t
) strtol(argval
,NULL
,16);
546 dummy
= (unsigned int) strtol(argval
,NULL
,16);
547 if (dummy
> 255) fprintf(stderr
, " IP_Warning: 'tos' too big, adjusted to LSBs\n");
550 if (getarg(tx
.arg_string
,"flow", argval
)==1)
552 dummy
= (unsigned int) strtol(argval
,NULL
,16);
555 fprintf(stderr
, " IP_Warning: 'flow label' too big, adjusted to 0xfffff\n");
561 if (getarg(tx
.arg_string
,"dscp", argval
)==1)
563 dummy
= (unsigned int) str2int(argval
);
566 fprintf(stderr
, " IP_Warning: 'dscp' too big, adjusted to 63\n");
569 tx
.ip_tos
= (u_int8_t
) dummy
*4;
572 if (getarg(tx
.arg_string
,"id", argval
)==1)
574 tx
.ip6_id
= str2int(argval
);
577 if (getarg(tx
.arg_string
,"frag", argval
)==1)
579 tx
.ip_frag
= ((u_int16_t
) str2int(argval
)) << 3;
582 if (getarg(tx
.arg_string
,"mf", NULL
)==1)
584 tx
.ip_frag
|= 0x0001;
587 if (getarg(tx
.arg_string
,"frag_res1", NULL
)==1)
589 tx
.ip_frag
|= 0x0002;
592 if (getarg(tx
.arg_string
,"frag_res2", NULL
)==1)
594 tx
.ip_frag
|= 0x0004;
597 if (getarg(tx
.arg_string
,"hop", argval
)==1)
599 tx
.ip_ttl
= (u_int8_t
) str2int(argval
);
602 if (getarg(tx
.arg_string
,"next", argval
)==1)
604 tx
.ip_proto
= (u_int8_t
) str2int(argval
);
608 tx
.ip_proto
= 59; // No Next Header for IPv6
612 if ((tx
.ascii
)&&(mode
==IP
)) // ASCII PAYLOAD overrides hex payload
614 strncpy((char *)tx
.ip_payload
, (char *)tx
.ascii_payload
, MAX_PAYLOAD_SIZE
);
615 tx
.ip_payload_s
= strlen((char *)tx
.ascii_payload
);
616 tx
.ip_len
+= tx
.ip_payload_s
;
621 // Want some padding? The specified number of padding bytes are ADDED to the
622 // payload. Note that this is only evaluated if we are in IP mode because
623 // UDP and TCP already might have been padded and set the ip_payload_s.
624 // (Note the difference in send_eth() where you specified the total number
625 // of bytes in the frame)
627 if ((tx
.padding
)&&(mode
==IP
))
629 for (i
=0; i
<tx
.padding
; i
++)
631 tx
.ip_payload
[tx
.ip_payload_s
+i
] = 0x42; // pad with THE ANSWER (why random?)
633 tx
.ip_payload_s
+= tx
.padding
;
634 tx
.ip_len
+= tx
.padding
;
638 t
= libnet_build_ipv6_frag (tx
.ip_proto
,
642 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
643 (mode
==IP
) ? tx
.ip_payload_s
: 0,
646 tx
.ip_len
+= LIBNET_IPV6_FRAG_H
;
648 tx
.ip_proto
= LIBNET_IPV6_NH_FRAGMENT
;
651 // See RFC 2460 Routing Header
653 if ( (getarg(tx
.arg_string
,"segments", argval
)==1) )
655 dummy
= (unsigned int) str2int(argval
);
657 fprintf(stderr
, " IP_Error: Maximal Routing Segments are 255!\n");
663 if ( (getarg(tx
.arg_string
,"rtype", argval
)==1) )
665 dummy
= (unsigned int) str2int(argval
);
667 fprintf(stderr
, " IP_Error: Maximum Routing Type is 255!\n");
673 if ( (getarg(tx
.arg_string
,"loose", argval
)==1) )
676 memset(tx
.ip_option
, 0, 4);
679 len
= strlen(argval
);
680 s
= strtok(argval
, ".+-;/>");
684 *((struct libnet_in6_addr
*) &tx
.ip_option
[tx
.ip_option_s
]) = libnet_name2addr6 (l
, s
, LIBNET_DONT_RESOLVE
);
685 tx
.ip_option_s
+= 16;
686 } while ( (s
=strtok(NULL
, ".+-;/>")) != NULL
);
688 if (!tx
.ip_option_s
) {
689 fprintf(stderr
, " IP_Error: No Routing Hops found!\n");
693 if (mode
==IP
&& tx
.ip_payload_s
)
694 memmove(tx
.ip_payload
+tx
.ip_option_s
, tx
.ip_payload
, tx
.ip_payload_s
);
698 memcpy(tx
.ip_payload
, tx
.ip_option
, tx
.ip_option_s
);
699 tx
.ip_payload_s
+= tx
.ip_option_s
;
701 t
= libnet_build_ipv6_routing(tx
.ip_proto
,
702 (tx
.ip_option_s
-4) / 8,
709 tx
.ip_len
+= LIBNET_IPV6_ROUTING_H
+ tx
.ip_option_s
;
711 tx
.ip_proto
= LIBNET_IPV6_NH_ROUTING
;
714 t
= libnet_build_ipv6 (tx
.ip_tos
,
721 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
722 (mode
==IP
) ? tx
.ip_payload_s
: 0,
728 fprintf(stderr
, " mz/create_ip_packet: Can't build IPv6 header: %s\n", libnet_geterror(l
));