summaryrefslogtreecommitdiff
path: root/staging/layer4.c
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2013-05-13 13:53:27 +0200
committerDaniel Borkmann <dborkman@redhat.com>2013-05-13 15:10:16 +0200
commitd0009856814c13d13770db5aadd7b2fabf947776 (patch)
tree6d18a94439f27f3c2685f05c57435116673f40cc /staging/layer4.c
parent2b100f7515dbd01032967c2d1b81d2f8d63bf9b5 (diff)
staging: add mausezahn staging directory
After some back and forth, we decided that it is easier to maintain mausezahn in a staging directory until it is fully reworked and cleaned up to be ready to be fully integrated. This way, it is better than having it in a separate branch, and we can also accept patches from outside more easily. Also, while at it, fix up some function mismatches with libcli. Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Diffstat (limited to 'staging/layer4.c')
-rw-r--r--staging/layer4.c884
1 files changed, 884 insertions, 0 deletions
diff --git a/staging/layer4.c b/staging/layer4.c
new file mode 100644
index 0000000..ca4d229
--- /dev/null
+++ b/staging/layer4.c
@@ -0,0 +1,884 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Layer 4 packet types
+//
+// 1. UDP
+// 2. ICMP
+// 3. TCP
+//
+////////////////////////////////////////////////////////////////////
+
+#include "mz.h"
+#include "cli.h"
+
+
+#define MZ_UDP_HELP \
+ "| UDP type: Send raw UDP packets.\n" \
+ "|\n" \
+ "| Parameters: \n" \
+ "|\n" \
+ "| sp 0-65535\n" \
+ "| dp 0-65535\n" \
+ "| len 0-65535\n" \
+ "| udp_sum 0-65535\n" \
+ "| payload|p <hex payload>\n" \
+ "|\n" \
+ "| Optionally the port numbers can be specified as ranges, e. g. \"dp=1023-33700\",\n" \
+ "| in which case one packet per port number is sent.\n" \
+ "|\n" \
+ "| Note that the UDP length must include the header length. If you do NOT specify the len\n" \
+ "| parameter (or specify len=0) then Mausezahn will compute the correct length.\n" \
+ "|\n" \
+ "| Note that all IP parameters can be modified (see IP help, i. e. '-t ip \"help\")\n" \
+ "| except that (to avoid confusion) the IP length is 'iplen' and the IP checksum is 'ipsum'.\n" \
+ "| Of course all Ethernet fields can also be accessed.\n" \
+ "|\n" \
+ "\n"
+
+
+#define MZ_ICMP_HELP \
+ "| ICMP type: Send raw ICMP packets.\n" \
+ "|\n" \
+ "| ARGUMENT SYNTAX: [type] <optional parameters> \n" \
+ "| \n" \
+ "| Per default an echo reply is sent (type=0, code=0)\n" \
+ "|\n" \
+ "| TYPE OPTIONAL PARAMETERS\n" \
+ "| =========== ====================================================================\n" \
+ "| Ping: \"ping\" or \"echoreq\" \n" \
+ "| 'id' (0-65535) is the optional identification number\n" \
+ "| 'seq' (0-65535) is the optional packet sequence number\n" \
+ "|\n" \
+ "| Redirect: \"redir, code=0, gw=192.168.1.10, p=aa:bb:cc\"\n" \
+ "| 'gw' (or 'gateway') is the announced gateway, by default your own\n" \
+ "| IP address.\n" \
+ "| 'code' can be:\n" \
+ "| 0 ... redirect datagram for the network\n" \
+ "| 1 ... redirect datagram for the host\n" \
+ "| 2 ... redirect datagram for ToS and network\n" \
+ "| 3 ... redirect datagram for ToS and host\n" \
+ "| 'p' (or 'payload') is the payload of the ICMP packet, tpyically an IP\n" \
+ "| header. Note that - at the moment - you must prepare this payload by\n" \
+ "| yourself.\n" \
+ "|\n" \
+ "| Unreachable \"unreach, code=2\"\n" \
+ "| 'code' can be:\n" \
+ "| 0 ... network unreachable\n" \
+ "| 1 ... host unreachable\n" \
+ "| 2 ... protocol unreachable\n" \
+ "| 3 ... port unreachable\n" \
+ "| 4 ... fragmentation needed but DF-bit is set\n" \
+ "| 5 ... source route failed\n" \
+ "|\n" \
+ "|\n" \
+ "| (other ICMP types will follow)\n" \
+ "|\n" \
+ "\n"
+
+#define MZ_ICMP6_HELP \
+ "| ICMPv6 type: Send raw ICMPv6 packets.\n" \
+ "|\n" \
+ "| Parameters Values Explanation \n" \
+ "| ---------- ------------------------------------ -------------------\n" \
+ "| type 0-255 ICMPv6 Type\n" \
+ "| code 0-255 ICMPv6 Code\n" \
+ "| id 0-65535 optional identification number\n" \
+ "| seq 0-65535 optional packet sequence number\n" \
+ "| icmpv6_sum 0-65535 optional checksum\n" \
+ "\n"
+
+#define MZ_TCP_HELP \
+ "| TCP type: Send raw TCP packets.\n" \
+ "|\n" \
+ "| Parameters Values Explanation \n" \
+ "| ---------- ------------------------------------ -------------------\n" \
+ "| sp 0-65535 Source Port\n" \
+ "| dp 0-65535 Destination Port\n" \
+ "| flags fin|syn|rst|psh|ack|urg|ecn|cwr\n" \
+ "| s 0-4294967295 Sequence Nr.\n" \
+ "| a 0-4294967295 Acknowledgement Nr.\n" \
+ "| win 0-65535 Window Size\n" \
+ "| urg 0-65535 Urgent Pointer\n" \
+ "| tcp_sum 0-65535 Checksum\n" \
+ "|\n" \
+ "| The port numbers can be specified as ranges, e. g. \"dp=1023-33700\".\n" \
+ "| Multiple flags can be specified such as \"flags=syn|ack|urg\".\n" \
+ "|\n" \
+ "| Also the sequence number can be specified as a range, for example:\n" \
+ "|\n" \
+ "| s=10000-50000 ... send 40000 packets with SQNRs in that range. If the second\n" \
+ "| value is lower than the first then it is assumed that the\n" \
+ "| SQNRs should 'wrap around'.\n" \
+ "| ds=30000 ........ use this increment within a SQNR-range.\n" \
+ "|\n" \
+ "| Note that all IP parameters can be modified (see IP help, i. e. '-t ip \"help\")\n" \
+ "| except that (to avoid confusion) the IP length is 'iplen' and the IP checksum is 'ipsum'.\n" \
+ "| Of course all Ethernet fields can also be accessed.\n"\
+ "|\n"
+
+
+
+// Note: If another function specified tx.udp_payload then it must also
+// set tx.udp_payload_s AND tx.udp_len = tx.udp_payload_s + 8
+libnet_ptag_t create_udp_packet (libnet_t *l)
+{
+ libnet_ptag_t t;
+ char argval[MAX_PAYLOAD_SIZE];
+ int T; // only an abbreviation for tx.packet_mode
+ int i;
+
+ /////////////////////////////
+ // Default UDP header fields
+ // Already reset in init.c
+ /////////////////////////////
+
+ T = tx.packet_mode; // >0 means automatic L2 creation
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==UDP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_UDP_HELP);
+ return -1;
+ }
+ else
+ {
+
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_UDP_HELP);
+
+ exit(0);
+ }
+
+ }
+
+
+ // Evaluate CLI parameters:
+
+ if (getarg(tx.arg_string,"dp", argval)==1)
+ {
+ if (get_port_range (DST_PORT, argval)) // problem
+ {
+ tx.dp = 0;
+ }
+ }
+
+ if (getarg(tx.arg_string,"sp", argval)==1)
+ {
+ if (get_port_range (SRC_PORT, argval)) // problem
+ {
+ tx.sp = 0;
+ }
+ }
+
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.udp_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.udp_payload_s = tx.hex_payload_s;
+ }
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ tx.udp_payload_s = str2hex (argval, tx.udp_payload, MAX_PAYLOAD_SIZE);
+ }
+
+
+
+ if (getarg(tx.arg_string,"sum", argval)==1)
+ {
+ if (T) fprintf(stderr, " IP_Warning: 'sum' cannot be set in this mode.\n");
+ tx.ip_sum = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"udp_sum", argval)==1)
+ {
+ tx.udp_sum = (u_int16_t) str2int(argval);
+ }
+
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.udp_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.udp_payload_s = strlen((char *)tx.ascii_payload);
+ printf("[%s]\n", tx.ascii_payload);
+ }
+
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if (tx.padding)
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.udp_payload[tx.udp_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.udp_payload_s += tx.padding;
+ }
+
+
+
+ ////////
+ // The following is VERY IMPORTANT because the ip_payload_s is also set!
+ if (getarg(tx.arg_string,"len", argval)==1)
+ {
+ tx.udp_len = (u_int16_t) str2int(argval);
+ tx.ip_payload_s = tx.udp_len;
+ }
+ else // len NOT specified by user
+ {
+ if (tx.udp_len == 0) // len also not specified by another function (e. g. create_dns_packet...)
+ {
+ tx.udp_len = 8 + tx.udp_payload_s;
+ tx.ip_payload_s = tx.udp_len;
+ }
+ else // len (and payload and payload_s) has been specified by another function
+ {
+ tx.ip_payload_s = tx.udp_len;
+ }
+
+ }
+
+
+
+ t = libnet_build_udp(tx.sp,
+ tx.dp,
+ tx.udp_len,
+ tx.udp_sum,
+ (tx.udp_payload_s) ? tx.udp_payload : NULL,
+ tx.udp_payload_s,
+ l,
+ 0);
+
+ // Checksum overwrite? Libnet IPv6 checksum calculation can't deal with extension headers, we have to do it ourself...
+ libnet_toggle_checksum(l, t, (tx.udp_sum || ipv6_mode) ? LIBNET_OFF : LIBNET_ON);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_udp_packet: Can't build UDP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+
+
+ return t;
+
+}
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+
+
+
+libnet_ptag_t create_icmp_packet (libnet_t *l)
+{
+
+ libnet_ptag_t t;
+ char argval[MAX_PAYLOAD_SIZE];
+ unsigned char *x;
+
+ int i;
+
+ enum
+ {
+ NONE,
+ ECHO_REQUEST,
+ REDIRECT,
+ UNREACHABLE
+ }
+ icmp; // which ICMP Type?
+
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==ICMP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_ICMP_HELP);
+ return -1;
+ }
+ else
+ {
+
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_ICMP_HELP);
+ exit(0);
+ }
+ }
+
+
+ /////////////////////////////////////////
+ //
+ // Which ICMP Type has been specified?
+ //
+ // Note: to allow invalid type values we need the enum 'icmp' tp specify the sending function
+ // and the 'type' variable seperately.
+
+ if ( (getarg(tx.arg_string,"redirect", NULL)==1) || (getarg(tx.arg_string,"redir", NULL)==1) )
+ {
+ icmp = REDIRECT;
+ tx.icmp_type = ICMP_REDIRECT;
+ tx.icmp_code=ICMP_REDIRECT_HOST;
+ }
+
+
+ if ( (getarg(tx.arg_string,"ping", NULL)==1) || (getarg(tx.arg_string,"echoreq", NULL)==1) )
+ {
+ icmp = ECHO_REQUEST;
+ tx.icmp_type = ICMP_ECHO;
+ tx.icmp_code = 0;
+ }
+
+
+ if (getarg(tx.arg_string,"unreach", NULL)==1)
+ {
+ icmp = UNREACHABLE;
+ tx.icmp_type = ICMP_UNREACH;
+ tx.icmp_code = 0; // network unreachable
+ }
+
+
+ /////////////////////////////////////////
+ //
+ // Which parameters have been specified?
+
+
+ if (getarg(tx.arg_string,"type", argval)==1)
+ {
+ tx.icmp_type = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"code", argval)==1)
+ {
+ tx.icmp_code = (u_int8_t) str2int(argval);
+ }
+ else
+ {
+ // Use appropriate defaults depending on ICMP type
+ }
+
+
+ if (getarg(tx.arg_string,"icmp_sum", argval)==1)
+ {
+ tx.icmp_chksum = (u_int16_t) str2int(argval);
+ }
+
+ if ( (getarg(tx.arg_string,"gateway", argval)==1) || (getarg(tx.arg_string,"gw", argval)==1) )
+ {
+ tx.icmp_gateway = str2ip32 (argval);
+ }
+ else
+ {
+ tx.icmp_gateway = tx.ip_src; // prefer own address
+ }
+
+
+ if (getarg(tx.arg_string,"id", argval)==1)
+ {
+ tx.icmp_ident = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"seq", argval)==1)
+ {
+ tx.icmp_sqnr = (u_int16_t) str2int(argval);
+ }
+
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.icmp_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.icmp_payload_s = tx.hex_payload_s;
+ }
+
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ tx.icmp_payload_s = str2hex (argval, tx.icmp_payload, MAX_PAYLOAD_SIZE);
+ }
+ else
+ {
+ tx.icmp_payload_s = 0;
+ }
+
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.icmp_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.icmp_payload_s = strlen((char *)tx.ascii_payload);
+ }
+
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if (tx.padding)
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.icmp_payload[tx.icmp_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.icmp_payload_s += tx.padding;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Now determine which type of ICMP packet to send.
+ //
+ // NOTE: Every section (icmp-type) must provide
+ //
+ // 1. a build function
+ // 2. tx.ip_payload_s which indicates the whole ICMP packet size
+ // 3. tx.icmp_verbose_string containing details about the ICMP packet (verbose mode)
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+
+ switch (icmp)
+ {
+ case REDIRECT: // +++++++++++++++
+ t = libnet_build_icmpv4_redirect (tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ tx.icmp_gateway,
+ (tx.icmp_payload_s) ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ 0);
+ tx.ip_payload_s = LIBNET_ICMPV4_REDIRECT_H + tx.icmp_payload_s; // for send_ip
+ if (verbose)
+ {
+ x = (unsigned char*) &tx.icmp_gateway;
+ sprintf(tx.icmp_verbose_txt,"ICMP Redirect, GW=%u.%u.%u.%u",
+ *(x),*(x+1),*(x+2),*(x+3));
+ }
+ break; // ++++++++++++++++++++++
+ case NONE:
+ case ECHO_REQUEST:
+ t = libnet_build_icmpv4_echo(tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ tx.icmp_ident,
+ tx.icmp_sqnr,
+ (tx.icmp_payload_s) ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ 0);
+ tx.ip_payload_s = LIBNET_ICMPV4_REDIRECT_H + tx.icmp_payload_s; // for send_ip
+ if (verbose)
+ {
+ if (icmp == NONE)
+ sprintf(tx.icmp_verbose_txt,"ICMP Type %u Code %u\n",tx.icmp_type,tx.icmp_code);
+ else
+ sprintf(tx.icmp_verbose_txt,"ICMP Echo Request (id=%u seq=%u)\n",tx.icmp_ident,tx.icmp_sqnr);
+ }
+ break; // ++++++++++++++++++++++
+ case UNREACHABLE:
+ t = libnet_build_icmpv4_unreach(tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ (tx.icmp_payload_s) ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ 0);
+ if (verbose)
+ {
+ sprintf(tx.icmp_verbose_txt,"ICMP unreachable (code=%u)\n",tx.icmp_code);
+ }
+ break; // ++++++++++++++++++++++
+ default:
+ (void) fprintf(stderr," mz/icmp: unknown mode! Stop.\n");
+ return (1);
+ }
+
+ libnet_toggle_checksum(l, t, tx.icmp_chksum ? LIBNET_OFF : LIBNET_ON);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_icmp_packet: Can't build ICMP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+
+ return t;
+}
+
+libnet_ptag_t create_icmp6_packet (libnet_t *l)
+{
+ libnet_ptag_t t;
+ char argval[MAX_PAYLOAD_SIZE];
+
+ int i;
+ tx.icmp_ident = 0;
+ tx.icmp_sqnr = 0;
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==ICMP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_ICMP6_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_ICMP6_HELP);
+ exit(0);
+ }
+ }
+
+
+ /////////////////////////////////////////
+ //
+ // Which parameters have been specified?
+
+
+ if (getarg(tx.arg_string,"type", argval)==1)
+ {
+ tx.icmp_type = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"code", argval)==1)
+ {
+ tx.icmp_code = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"id", argval)==1)
+ {
+ tx.icmp_ident = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"seq", argval)==1)
+ {
+ tx.icmp_sqnr = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"icmpv6_sum", argval)==1)
+ {
+ tx.icmp_chksum = (u_int16_t) str2int(argval);
+ }
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.icmp_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.icmp_payload_s = tx.hex_payload_s;
+ }
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ tx.icmp_payload_s = str2hex (argval, tx.icmp_payload, MAX_PAYLOAD_SIZE);
+ }
+ else
+ {
+ tx.icmp_payload_s = 0;
+ }
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.icmp_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.icmp_payload_s = strlen((char *)tx.ascii_payload);
+ }
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if (tx.padding)
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.icmp_payload[tx.icmp_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.icmp_payload_s += tx.padding;
+ }
+
+ sprintf(tx.icmp_verbose_txt,"ICMPv6 Type %u Code %u\n",tx.icmp_type,tx.icmp_code);
+
+ t = libnet_build_icmpv4_echo (tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ tx.icmp_ident,
+ tx.icmp_sqnr,
+ tx.icmp_payload_s ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ 0);
+ tx.ip_payload_s = LIBNET_ICMPV6_H + tx.icmp_payload_s; // for send_ip
+
+ // Libnet IPv6 checksum calculation can't deal with extension headers, we have to do it ourself...
+ libnet_toggle_checksum(l, t, (tx.icmp_chksum || ipv6_mode) ? LIBNET_OFF : LIBNET_ON);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_icmp_packet: Can't build ICMPv6 header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+ return t;
+}
+
+
+
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+
+
+// Note: If another function specified tx.tcp_payload then it must also
+// set tx.tcp_payload_s AND tx.tcp_len = tx.tcp_payload_s + 20
+libnet_ptag_t create_tcp_packet (libnet_t *l)
+{
+ libnet_ptag_t t, t2;
+ char argval[MAX_PAYLOAD_SIZE], *dummy1, *dummy2;
+ int T; // only an abbreviation for tx.packet_mode
+ int i;
+
+ u_int8_t tcp_default_options[] =
+ {
+ 0x02, 0x04, 0x05, 0xac, // MSS
+ 0x04, 0x02, // SACK permitted
+ 0x08, 0x0a, 0x19, 0x35, 0x90, 0xc3, 0x00, 0x00, 0x00, 0x00, // Timestamps
+ 0x01, // NOP
+ 0x03, 0x03, 0x05 // Window Scale 5
+ };
+
+
+
+ /////////////////////////////
+ // Default TCP header fields
+ // Already reset in init.c
+ /////////////////////////////
+
+ T = tx.packet_mode; // >0 means automatic L2 creation
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==TCP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_TCP_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_TCP_HELP);
+ exit(0);
+ }
+ }
+
+
+ // Evaluate CLI parameters:
+
+ if (getarg(tx.arg_string,"dp", argval)==1)
+ {
+ if (get_port_range (DST_PORT, argval)) // problem
+ {
+ tx.dp = 0;
+ }
+ }
+
+
+ if (getarg(tx.arg_string,"sp", argval)==1)
+ {
+ if (get_port_range (SRC_PORT, argval)) // problem
+ {
+ tx.sp = 0;
+ }
+ }
+
+
+ if (getarg(tx.arg_string,"s", argval)==1)
+ {
+ //check whether a range has been specified:
+ dummy1 = strtok(argval, "-");
+ tx.tcp_seq = (u_int32_t) str2int (dummy1);
+ if ( (dummy2 = strtok(NULL, "-")) == NULL ) // no additional value
+ {
+ tx.tcp_seq_stop = tx.tcp_seq;
+ }
+ else // range
+ {
+ tx.tcp_seq_stop = (u_int32_t) str2int (dummy2);
+ tx.tcp_seq_start = tx.tcp_seq; // initially tcp_seq = tcp_seq_start
+ tx.tcp_seq_delta = 1; // an initialization only in case 'ds' not specified
+ }
+ }
+
+ if (getarg(tx.arg_string,"ds", argval)==1)
+ {
+ tx.tcp_seq_delta = (u_int32_t) str2int (argval);
+ }
+
+ if (getarg(tx.arg_string,"a", argval)==1)
+ {
+ tx.tcp_ack = (u_int32_t) str2int (argval);
+ }
+
+ if (getarg(tx.arg_string,"win", argval)==1)
+ {
+ tx.tcp_win = (u_int16_t) str2int (argval);
+ }
+
+ if (getarg(tx.arg_string,"urg", argval)==1)
+ {
+ tx.tcp_urg = (u_int16_t) str2int (argval);
+ }
+
+
+ if ( (getarg(tx.arg_string,"flags", argval)==1) ||
+ (getarg(tx.arg_string,"flag", argval)==1) ) // because everybody confuses this
+ {
+ if (get_tcp_flags(argval)) // problem
+ {
+ tx.tcp_control=2; // Assume SYN as default
+ }
+ }
+
+ if (getarg(tx.arg_string,"tcp_sum", argval)==1)
+ {
+ tx.tcp_sum = (u_int16_t) str2int(argval);
+ }
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.tcp_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.tcp_payload_s = tx.hex_payload_s;
+ }
+
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ tx.tcp_payload_s = str2hex (argval, tx.tcp_payload, MAX_PAYLOAD_SIZE);
+ }
+
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.tcp_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.tcp_payload_s = strlen((char *)tx.ascii_payload);
+ tx.tcp_len = 20 + tx.tcp_payload_s; // only needed by libnet to calculate checksum
+ tx.ip_payload_s = tx.tcp_len; // for create_ip_packet
+ }
+
+
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if (tx.padding)
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.tcp_payload[tx.tcp_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.tcp_payload_s += tx.padding;
+
+ }
+
+
+
+ tx.tcp_len = 20 + tx.tcp_payload_s; // only needed by libnet to calculate checksum
+ tx.ip_payload_s = tx.tcp_len; // for create_ip_packet
+
+ if (tx.tcp_control & 0x02) // packets with syn require an MSS option
+ {
+ t2 = libnet_build_tcp_options(tcp_default_options,
+ 20,
+ l,
+ 0);
+
+ if (t2 == -1)
+ {
+ fprintf(stderr, " mz/create_tcp_packet: Can't build TCP options: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+ tx.tcp_len += 20;
+ tx.tcp_offset = 10;
+ tx.ip_payload_s = tx.tcp_len; // for create_ip_packet
+ tx.tcp_sum_part = libnet_in_cksum((u_int16_t *) tcp_default_options, 20);
+ }
+ else
+ {
+ tx.tcp_offset = 5;
+ tx.tcp_sum_part = 0;
+ }
+
+ t = libnet_build_tcp (tx.sp,
+ tx.dp,
+ tx.tcp_seq,
+ tx.tcp_ack,
+ tx.tcp_control,
+ tx.tcp_win,
+ tx.tcp_sum,
+ tx.tcp_urg,
+ tx.tcp_len,
+ (tx.tcp_payload_s) ? tx.tcp_payload : NULL,
+ tx.tcp_payload_s,
+ l,
+ 0);
+
+
+
+ // Libnet IPv6 checksum calculation can't deal with extension headers, we have to do it ourself...
+ libnet_toggle_checksum(l, t, (tx.tcp_sum || ipv6_mode) ? LIBNET_OFF : LIBNET_ON);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_tcp_packet: Can't build TCP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+
+ return t;
+}