netsniff-ng: ring: Fix build if tp_vlan_tpid is not available in kernel header
[netsniff-ng.git] / staging / layer3.c
blob0b17db179cb58d40ef511c36d4b7c5b65c9567b6
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
4 *
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.
8 *
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
12 * details.
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
23 //
24 // * IP
25 //
26 // (ahem, yes this is currently all here...)
27 //
28 // ***************************************************************************
30 #include "mz.h"
31 #include "cli.h"
33 #define MZ_IP_HELP \
34 "| IP type: Send raw IP packets.\n" \
35 "|\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" \
40 "|\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" \
44 "|\n" \
45 "| ARGUMENT SYNTAX: [<comma separated parameter list>]\n" \
46 "|\n" \
47 "| Parameters:\n" \
48 "|\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" \
53 "| ttl 0-255\n" \
54 "| proto 0-255\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" \
59 "| id 0-65535\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" \
64 "|\n" \
65 "| Additionally the Ethertype can be specified:\n" \
66 "|\n" \
67 "| ether_type 00:00-ff:ff Only accessible in L2 mode (default = 08:00 = IPv4)\n" \
68 "| \n"
71 #define MZ_IP6_HELP \
72 "| IP type: Send raw IPv6 packets.\n" \
73 "|\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" \
78 "|\n" \
79 "| ARGUMENT SYNTAX: [<comma separated parameter list>]\n" \
80 "|\n" \
81 "| Parameters:\n" \
82 "|\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" \
98 "|\n" \
99 "| Additionally the Ethertype can be specified:\n" \
100 "|\n" \
101 "| ether_type 00:00-ff:ff Only accessible in L2 mode (default = 86:dd = IPv6)\n" \
102 "| \n"
105 // Only used to simplify initialization of libnet
106 // Return pointer to context
107 libnet_t* get_link_context(void)
109 libnet_t * l;
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)
115 return NULL;
119 if (tx.packet_mode)
120 { // Let libnet create an appropriate Ethernet frame
121 if (ipv6_mode)
122 l = libnet_init (LIBNET_RAW6_ADV, tx.device, errbuf);
123 else
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);
131 if (l == NULL)
133 fprintf(stderr, "%s", errbuf);
134 exit(EXIT_FAILURE);
136 return l;
140 //////////////////////////////////////////////////////////////////////////////
141 // Prepare IP packet
142 libnet_ptag_t create_ip_packet (libnet_t *l)
144 libnet_ptag_t t;
145 char argval[MAX_PAYLOAD_SIZE];
146 int i, T; // only an abbreviation for tx.packet_mode
148 if (ipv6_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
153 tx.ip_id = 0;
154 tx.ip_frag = 0; // Flags and Offset !!!
155 tx.ip_sum = 0; // default: automatically calculate checksum
156 tx.ip_tos = 0;
158 // temporary variables
159 unsigned int dummy;
160 size_t len;
161 char *s;
163 T = tx.packet_mode; // >0 means automatic L2 creation
165 if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==IP) )
167 if (mz_port)
169 cli_print(gcli, "%s", MZ_IP_HELP);
170 return -1;
172 else
175 fprintf(stderr,"\n"
176 MAUSEZAHN_VERSION
177 "\n%s", MZ_IP_HELP);
179 exit(0);
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))
195 if (mode==IP)
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'.
204 if (mode==IP)
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);
211 else
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);
229 else
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);
252 if (dummy > 63)
254 fprintf(stderr, " IP_Warning: 'dscp' too big, adjusted to 63\n");
255 dummy = 63;
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)
288 tx.ip_ttl = 255;
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;
304 /////////
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
341 dummy=0;
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
353 else
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
362 tx.ip_option_s = 3;
363 s = strtok(argval, ".+-:;/>");
366 len--;
367 tx.ip_option[tx.ip_option_s] = (u_int8_t) str2int(s);
368 tx.ip_option_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;
378 tx.ip_option_s++;
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"
391 if (tx.ip_option_s)
393 fprintf(stderr, " IP_Error: Another IP option already specified. Please check your arguments.\n");
394 exit(1);
397 tx.ip_option_s = str2hex (argval, tx.ip_option, 1023);
402 if (tx.ip_option_s)
404 t = libnet_build_ipv4_options (tx.ip_option,
405 tx.ip_option_s,
408 tx.ip_len += tx.ip_option_s;
412 ///////
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;
418 tx.ip_payload_s = 1;
422 t = libnet_build_ipv4 (tx.ip_len,
423 tx.ip_tos,
424 tx.ip_id,
425 tx.ip_frag,
426 tx.ip_ttl,
427 tx.ip_proto,
428 tx.ip_sum,
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,
442 if (t == -1)
444 fprintf(stderr, " mz/create_ip_packet: Can't build IP header: %s\n", libnet_geterror(l));
445 exit (0);
449 return t;
453 //////////////////////////////////////////////////////////////////////////////
454 // Prepare IPv6 packet
455 libnet_ptag_t create_ip6_packet (libnet_t *l)
457 libnet_ptag_t t;
458 char argval[MAX_PAYLOAD_SIZE];
459 int i, T; // only an abbreviation for tx.packet_mode
461 // Default IP header fields
462 tx.ip_len = 0;
463 tx.ip_id = 0;
464 tx.ip6_segs = 0;
465 tx.ip6_rtype = 0;
466 tx.ip6_id = 0;
467 tx.ip_frag = 0; // Flags and Offset !!!
468 tx.ip_tos = 0;
469 tx.ip_ttl = 255;
471 // temporary variables
472 unsigned int dummy;
473 size_t len;
474 char *s;
476 T = tx.packet_mode; // >0 means automatic L2 creation
478 if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==IP) )
480 if (mz_port)
482 cli_print(gcli, "%s", MZ_IP6_HELP);
483 return -1;
485 else
487 fprintf(stderr,"\n"
488 MAUSEZAHN_VERSION
489 "\n%s", MZ_IP6_HELP);
491 exit(0);
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))
505 if (mode==IP)
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'.
513 if (mode==IP)
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);
520 else
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);
532 else
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);
549 if (dummy > 1048575)
551 fprintf(stderr, " IP_Warning: 'flow label' too big, adjusted to 0xfffff\n");
552 dummy = 0xfffff;
554 tx.ip_flow = dummy;
557 if (getarg(tx.arg_string,"dscp", argval)==1)
559 dummy = (unsigned int) str2int(argval);
560 if (dummy > 63)
562 fprintf(stderr, " IP_Warning: 'dscp' too big, adjusted to 63\n");
563 dummy = 63;
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);
602 else if (mode==IP)
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;
616 /////////
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;
633 if (tx.ip6_id) {
634 t = libnet_build_ipv6_frag (tx.ip_proto,
636 htons(tx.ip_frag),
637 htonl(tx.ip6_id),
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;
643 tx.ip_payload_s = 0;
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);
652 if (dummy > 255) {
653 fprintf(stderr, " IP_Error: Maximal Routing Segments are 255!\n");
654 exit(1);
656 tx.ip6_segs = dummy;
659 if ( (getarg(tx.arg_string,"rtype", argval)==1) )
661 dummy = (unsigned int) str2int(argval);
662 if (dummy > 255) {
663 fprintf(stderr, " IP_Error: Maximum Routing Type is 255!\n");
664 exit(1);
666 tx.ip6_segs = dummy;
669 if ( (getarg(tx.arg_string,"loose", argval)==1) )
671 // Fill reserved
672 memset(tx.ip_option, 0, 4);
673 tx.ip_option_s=4;
675 len = strlen(argval);
676 s = strtok(argval, ".+-;/>");
679 len--;
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");
686 exit(1);
689 if (mode==IP && tx.ip_payload_s)
690 memmove(tx.ip_payload+tx.ip_option_s, tx.ip_payload, tx.ip_payload_s);
691 else
692 tx.ip_payload_s = 0;
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,
699 tx.ip6_rtype,
700 tx.ip6_segs,
701 tx.ip_payload,
702 tx.ip_payload_s,
705 tx.ip_len += LIBNET_IPV6_ROUTING_H + tx.ip_option_s;
706 tx.ip_payload_s = 0;
707 tx.ip_proto = LIBNET_IPV6_NH_ROUTING;
710 t = libnet_build_ipv6 (tx.ip_tos,
711 tx.ip_flow,
712 tx.ip_len,
713 tx.ip_proto,
714 tx.ip_ttl,
715 tx.ip6_src,
716 tx.ip6_dst,
717 (mode==IP) ? (tx.ip_payload_s) ? tx.ip_payload : NULL : NULL,
718 (mode==IP) ? tx.ip_payload_s : 0,
722 if (t == -1)
724 fprintf(stderr, " mz/create_ip_packet: Can't build IPv6 header: %s\n", libnet_geterror(l));
725 exit (0);
728 return t;