Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial import to github as an open source project. Thanks Yahoo!

  • Loading branch information...
commit 16742dceb66d7a878c391843dde0fdf74ccdc12a 0 parents
@jeagle jeagle authored
Showing with 1,615 additions and 0 deletions.
  1. +18 −0 Makefile
  2. +66 −0 README
  3. +216 −0 checksums.c
  4. +39 −0 checksums.h
  5. +1,276 −0 synfrag.c
18 Makefile
@@ -0,0 +1,18 @@
+OBJS = synfrag.o checksums.o
+SRCS = $(OBJS,.o=.c)
+CFLAGS += -Wall
+
+all: synfrag
+
+synfrag.o: synfrag.c
+ $(CC) $(CFLAGS) -c -o $@ synfrag.c
+
+checksums.o: checksums.c
+ $(CC) $(CFLAGS) -c -o $@ checksums.c
+
+synfrag: $(OBJS)
+ $(CC) $(LDFLAGS) -lpcap -o synfrag $(OBJS)
+
+clean:
+ rm -rf *.o synfrag
+
66 README
@@ -0,0 +1,66 @@
+synfrag - Copyright Yahoo! Inc 2012
+
+Summary
+====================
+
+A network scanning tool for sending fragmented IPv4 and IPv6 packets.
+
+Description
+====================
+
+synfrag is a network scanning and penetration testing tool used to craft and
+send fragmented and unfragmented IPv4 and IPv6 packets. It currently supports
+sending both TCP SYN, ICMP echo (ping), and ICMP6 echo packets. Various
+fragmentation configurations are also available. synfrag tries its best to
+read any replies sent by targeted hosts to determine if they are willing
+or able to respond.
+
+The purpose of synfrag is to test host and network responses to fragmented
+requests. Many current routers implement access control lists (ACLs) in
+a manner that is unable to properly detect traffic inside fragmented IP
+packets, leading to situations where hosts are believed to be isolated from
+internet traffic by these ACLs. In some cases, specially crafted packets can
+bypass these router ACLs by taking advantage of their inability to properly
+process fragmented packets, exposing hosts to the internet unprotected.
+
+Some operating systems implement a security mechanism that ignores fragmented
+TCP SYN packets, preventing connections from being established under
+the assumption that these packets are abnormal and specially designed to
+circumvent network protections. However, many of these operating systems
+do not implement the same protections for all protocols, allowing some
+fragmented traffic through while blocking others.
+
+Notes
+====================
+
+synfrag is currently under development and is missing some useful features.
+Namely, synfrag does not resolve hostnames nor discover the next-hop layer
+2 address, and requires the user to specify these parameters.
+
+Additionally, synfrag does not attempt to prevent the host operating system
+from interpreting any replies received from scanned hosts, meaning that after
+a scan the operating system may send a TCP RST packet to the scanned host,
+misinterpreting its reply as meant for the operating system. This can be
+worked around via firewall rules.
+
+TCP SYN requests sent by synfrag currently all use the source port 44128. The
+same number is used for ICMP/6 echo packet IDs. When writing firewall rules
+to prevent the operating system from misinterpreting replies or to prevent
+synfrag scans, traffic sent to (or from) this port, or with this ICMP echo ID,
+can be discarded.
+
+License
+====================
+
+synfrag is released under the BSD license. synfrag includes BSD licensed code
+from libnet, and links against libpcap, also licensed under the BSD license.
+
+Author
+====================
+John Eaglesham
+Yahoo! Inc
+
+Changes
+====================
+1.0 - 20120209
+
216 checksums.c
@@ -0,0 +1,216 @@
+/*
+ * This file originally appeared as part of libnet. This version has been
+ * modified.
+ *
+ * Copyright (c) 1998 - 2001 Mike D. Schiffman <mike@infonexus.com>
+ * Copyright (c) 1999, 2000 Dug Song <dugsong@monkey.org>
+ * Copyright (c) 2005, 2012 John Eaglesham
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+
+#ifdef __FreeBSD__
+#include <netinet/in_systm.h>
+#endif
+
+#ifdef __linux
+#define __FAVOR_BSD
+#endif
+
+#include <arpa/inet.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include "checksums.h"
+
+int in_cksum(unsigned short *addr, int len)
+{
+ int sum;
+ int nleft;
+ unsigned short ans;
+ unsigned short *w;
+
+ sum = 0;
+ ans = 0;
+ nleft = len;
+ w = addr;
+
+ while (nleft > 1)
+ {
+ sum += *w++;
+ nleft -= 2;
+ }
+ if (nleft == 1)
+ {
+ *(unsigned char *)(&ans) = *(unsigned char *)w;
+ sum += ans;
+ }
+ return (sum);
+}
+
+int do_checksum(char *buf, int protocol, int len)
+{
+ /* Set to NULL to avoid compiler warnings. */
+ struct ip *iph_p = NULL;
+ struct ip6_hdr *ip6h_p = NULL;
+ int ip_hl;
+ int sum = 0;
+ int ip_version = buf[0] >> 4;
+
+ if ( ip_version == 6 ) {
+ int next_header;
+ ip6h_p = (struct ip6_hdr *)buf;
+ next_header = ip6h_p->ip6_ctlun.ip6_un1.ip6_un1_nxt;
+ ip_hl = sizeof( struct ip6_hdr );
+
+ while( next_header != protocol ) {
+ switch ( next_header )
+ {
+ case IPPROTO_FRAGMENT:
+ next_header = ( (struct ip6_frag *) ( buf + ip_hl ) )->ip6f_nxt;
+ ip_hl += sizeof( struct ip6_frag );
+ break;
+ case IPPROTO_DSTOPTS:
+ next_header = ( (struct ip6_dest *) ( buf + ip_hl ) )->ip6d_nxt;
+ ip_hl += ( ( (struct ip6_dest *) ( buf + ip_hl ) )->ip6d_len * 8 ) + 8;
+ break;
+ default:
+ return 0;
+ }
+ }
+ } else if ( ip_version == 4 ) {
+ iph_p = (struct ip *)buf;
+ /*
+ * This should mask off the top 4 bits first, but we know they are
+ * 0100 so shifting left by 2 means the top 2 bits are ignored.
+ */
+ ip_hl = iph_p->ip_hl << 2;
+ } else {
+ return (0);
+ }
+ if ( ip_hl < 0 ) return -2;
+
+ /*
+ * Dug Song came up with this very cool checksuming implementation
+ * eliminating the need for explicit psuedoheader use. Check it out.
+ */
+ switch (protocol)
+ {
+ /*
+ * Style note: normally I don't advocate declaring variables inside
+ * blocks of control, but it makes good sense here. -- MDS
+ */
+ case IPPROTO_UDP:
+ {
+ struct udphdr *udph_p =
+ (struct udphdr *)(buf + ip_hl);
+ //if ( ip_hl + sizeof( struct udphdr ) > len ) return -2;
+
+ udph_p->uh_sum = 0;
+ if (ip_version == 6)
+ {
+ sum = in_cksum((unsigned short *)&ip6h_p->ip6_src, 32);
+ }
+ else /* If not 6 we know it's 4 as we only allow 6 and 4 above. */
+ {
+ sum = in_cksum((unsigned short *)&iph_p->ip_src, 8);
+ }
+ sum += ntohs(IPPROTO_UDP + len);
+ sum += in_cksum((unsigned short *)udph_p, len);
+ udph_p->uh_sum = CKSUM_CARRY(sum);
+ break;
+ }
+ case IPPROTO_TCP:
+ {
+ struct tcphdr *tcph_p =
+ (struct tcphdr *)(buf + ip_hl);
+ //if ( ip_hl + sizeof( struct tcphdr ) > len ) return -2;
+
+ tcph_p->th_sum = 0;
+ if (ip_version == 6)
+ {
+ sum = in_cksum((unsigned short *)&ip6h_p->ip6_src, 32);
+ }
+ else /* If not 6 we know it's 4 as we only allow 6 and 4 above. */
+ {
+ sum = in_cksum((unsigned short *)&iph_p->ip_src, 8);
+ }
+ sum += ntohs(IPPROTO_TCP + len);
+ sum += in_cksum((unsigned short *)tcph_p, len);
+ tcph_p->th_sum = CKSUM_CARRY(sum);
+ break;
+ }
+ case IPPROTO_ICMP:
+ {
+ struct icmp *icmph_p =
+ (struct icmp *)(buf + ip_hl);
+ //if ( ip_hl + sizeof( struct icmphdr ) > len ) return -2;
+
+ icmph_p->icmp_cksum = 0;
+ sum = in_cksum((unsigned short *)icmph_p, len);
+ icmph_p->icmp_cksum = CKSUM_CARRY(sum);
+ break;
+ }
+ case IPPROTO_ICMPV6:
+ {
+ struct icmp6_hdr *icmp6h_p =
+ (struct icmp6_hdr *)(buf + ip_hl);
+ //if ( ip_hl + sizeof( struct icmp6_hdr ) > len ) return -2;
+
+ if (ip_version == 6)
+ {
+ sum = in_cksum((unsigned short *)&ip6h_p->ip6_src, 32);
+ }
+ else
+ {
+ return 0;
+ }
+ sum += ntohs(IPPROTO_ICMPV6 + len);
+ icmp6h_p->icmp6_cksum = 0;
+ sum += in_cksum((unsigned short *)icmp6h_p, len);
+ icmp6h_p->icmp6_cksum = CKSUM_CARRY(sum);
+ break;
+ }
+ case IPPROTO_IP:
+ {
+ iph_p->ip_sum = 0;
+ sum = in_cksum((unsigned short *)iph_p, len);
+ iph_p->ip_sum = CKSUM_CARRY(sum);
+ break;
+ }
+ default:
+ {
+ return (-1);
+ }
+ }
+ return (1);
+}
+
39 checksums.h
@@ -0,0 +1,39 @@
+/*
+ * This file originally appeared as part of libnet. This version has been
+ * modified.
+ *
+ * Copyright (c) 1998 - 2001 Mike D. Schiffman <mike@infonexus.com>
+ * Copyright (c) 1999, 2000 Dug Song <dugsong@monkey.org>
+ * Copyright (c) 2005, 2012, John Eaglesham
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Checksum stuff
+ */
+#define CKSUM_CARRY(x) \
+ (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))
+
+int in_cksum(unsigned short *addr, int len);
+int do_checksum(char *buf, int protocol, int len);
1,276 synfrag.c
@@ -0,0 +1,1276 @@
+/*
+ * Copyright (c) 2012, Yahoo! Inc All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. Redistributions
+ * in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __USE_BSD
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <string.h>
+#include <netdb.h>
+
+#ifdef __FreeBSD__
+#include <netinet/in_systm.h>
+#endif
+
+#ifdef __linux
+#define ETHERTYPE_IPV6 ETH_P_IPV6
+#define __FAVOR_BSD
+#endif
+
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <netinet/tcp.h>
+#include <netinet/if_ether.h>
+#include <net/if.h>
+#include <pcap.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <getopt.h>
+#include "checksums.h"
+
+#define PCAP_TIMEOUT_SECONDS 10
+#define IP_FLAGS_OFFSET 13
+#define SOURCE_PORT 44128
+#define BIG_PACKET_SIZE 1500
+#define PCAP_CAPTURE_LEN BIG_PACKET_SIZE
+#define TCP_WINDOW 65535
+/*
+ * If this is ever big enough to exceed BIG_PACKET_SIZE when added with the
+ * sizes of the other (IPv4/IPv6+destination options+fragmentation+padding)
+ * headers, a buffer will overflow. So don't do that.
+ */
+#define MINIMUM_FRAGMENT_SIZE 8
+#define MINIMUM_PACKET_SIZE 68
+
+/* Save time typing/screen real estate. */
+#define SIZEOF_ICMP6 sizeof( struct icmp6_hdr )
+#define SIZEOF_TCP sizeof( struct tcphdr )
+#define SIZEOF_IPV4 sizeof( struct ip )
+#define SIZEOF_IPV6 sizeof( struct ip6_hdr )
+#define SIZEOF_ETHER sizeof( struct ether_header )
+/* This size is fixed but extends past the standard basic icmp header. */
+#define SIZEOF_PING 8
+
+/*
+ * XXX We don't close the pcap device on failure anywhere. The OS will do it
+ * for us, but it's impolite.
+ */
+
+/*
+ * This might turn out to be stupid, but lets try having TCP tests be odd
+ * numbered and ICMP even numbered. IPv4 tests will be <= 10 and IPv6 > 10.
+ */
+#define IS_TEST_TCP(x) ( x % 2 == 1 )
+#define IS_TEST_ICMP(x) ( x % 2 == 0 )
+#define IS_TEST_IPV4(x) ( x <= 10 )
+#define IS_TEST_IPV6(x) ( x > 10 )
+enum TEST_TYPE {
+ TEST_IPV4_TCP = 1,
+ TEST_FRAG_IPV4_TCP = 3,
+ TEST_FRAG_OPTIONED_IPV4_TCP = 5,
+
+ TEST_FRAG_IPV4_ICMP = 2,
+ TEST_FRAG_OPTIONED_IPV4_ICMP = 4,
+
+ TEST_IPV6_TCP = 11,
+ TEST_FRAG_IPV6_TCP = 13,
+ TEST_FRAG_OPTIONED_IPV6_TCP = 15,
+
+ TEST_FRAG_IPV6_ICMP = 12,
+ TEST_FRAG_OPTIONED_IPV6_ICMP6 = 14,
+
+ TEST_INVALID = 0
+};
+
+/*
+ * Items and their order in test_indexes needs to match test_names (but not
+ * enum TEST_TYPE).
+ */
+enum TEST_TYPE test_indexes[] = {
+ TEST_IPV4_TCP,
+ TEST_FRAG_IPV4_TCP,
+ TEST_FRAG_IPV4_ICMP,
+ TEST_FRAG_OPTIONED_IPV4_TCP,
+ TEST_FRAG_OPTIONED_IPV4_ICMP,
+
+ TEST_IPV6_TCP,
+ TEST_FRAG_IPV6_TCP,
+ TEST_FRAG_IPV6_ICMP,
+ TEST_FRAG_OPTIONED_IPV6_TCP,
+ TEST_FRAG_OPTIONED_IPV6_ICMP6,
+
+ 0
+};
+
+char *test_names[] = {
+ "v4-tcp",
+ "v4-frag-tcp",
+ "v4-frag-icmp",
+ "v4-frag-optioned-tcp",
+ "v4-frag-optioned-icmp",
+
+ "v6-tcp",
+ "v6-frag-tcp",
+ "v6-frag-icmp",
+ "v6-frag-optioned-tcp",
+ "v6-frag-optioned-icmp6",
+
+ NULL
+};
+
+pcap_t *pcap;
+pid_t listener_pid;
+int pfd[2];
+
+#ifdef SIOCGIFHWADDR
+void fill_interface_mac( char *dest, char *interface )
+{
+ int fd;
+ struct ifreq ifr;
+
+ fd = socket( AF_INET, SOCK_DGRAM, 0 );
+ if ( fd == -1 )
+ err( 1, "socket failed" );
+
+ ifr.ifr_addr.sa_family = AF_INET;
+ strncpy( ifr.ifr_name, interface, IFNAMSIZ - 1 );
+
+ if ( ioctl( fd, SIOCGIFHWADDR, &ifr ) == -1 ) {
+ close( fd );
+ err( 1, "ioctl failed" );
+ }
+ close( fd );
+
+ memcpy( dest, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN );
+}
+#elif __FreeBSD__
+#include <ifaddrs.h>
+#include <net/if_dl.h>
+void fill_interface_mac( char *dest, char *interface )
+{
+ struct ifaddrs *ifap;
+
+ if ( getifaddrs( &ifap ) == 0 ) {
+ struct ifaddrs *p;
+ for ( p = ifap; p; p = p->ifa_next ) {
+ if ( ( p->ifa_addr->sa_family == AF_LINK ) && ( strcmp( p->ifa_name, interface ) == 0 ) ) {
+ struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
+ memcpy( dest, sdp->sdl_data + sdp->sdl_nlen, 6 );
+ freeifaddrs( ifap );
+ return;
+ }
+ }
+ freeifaddrs(ifap);
+ }
+ errx( 1, "Failed to get MAC for interface %s", interface );
+}
+#else
+#error Do not know how to get MAC address on this platform.
+#endif
+
+void *malloc_check( int size )
+{
+ void *r = malloc( size );
+ if ( r == NULL ) err( 1, "malloc" );
+ return r;
+}
+
+unsigned short fix_up_destination_options_length( unsigned short optlen )
+{
+ /*
+ * Per RFC 2460, a destination options header must have a payload size
+ * that is: ( multiple of 8 ) - 2. We fix that up here by only ever
+ * increasing the size (though the algorithm would be simpler if we were
+ * willing to decrease it. There's no good reason not to decrease it, I
+ * just made a decision.
+ */
+ if ( optlen % 8 != 6 ) {
+ int x = 6 - ( optlen % 8 );
+ if ( x < 0 ) x += 8;
+ optlen += x;
+ }
+ return optlen;
+}
+
+void print_ethh( struct ether_header *ethh )
+{
+ printf( "Ethernet Frame, ethertype %i\n", ntohs( ethh->ether_type ) );
+
+ printf( " Src MAC %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ethh->ether_shost[0],
+ ethh->ether_shost[1],
+ ethh->ether_shost[2],
+ ethh->ether_shost[3],
+ ethh->ether_shost[4],
+ ethh->ether_shost[5] );
+
+ printf( " Dest MAC %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ethh->ether_dhost[0],
+ ethh->ether_dhost[1],
+ ethh->ether_dhost[2],
+ ethh->ether_dhost[3],
+ ethh->ether_dhost[4],
+ ethh->ether_dhost[5] );
+ printf( "\n" );
+}
+
+void print_iph( struct ip *iph )
+{
+ char srcbuf[INET_ADDRSTRLEN];
+ char dstbuf[INET_ADDRSTRLEN];
+
+ if ( inet_ntop( AF_INET, &iph->ip_src, (char *) &srcbuf, INET_ADDRSTRLEN ) == NULL ) err( 1, "inet_ntop failed" );
+ if ( inet_ntop( AF_INET, &iph->ip_dst, (char *) &dstbuf, INET_ADDRSTRLEN ) == NULL ) err( 1, "inet_ntop failed" );
+
+ printf( "IPv4 Packet:\n\
+ Src IP: %s\n\
+ Dst IP: %s\n\
+ Protocol: %i\n\
+ Frag Offset: %i\n\
+ Flags: %i\n\
+ Iphl: %i\n\
+\n",
+ (char *) &srcbuf,
+ (char *) &dstbuf,
+ iph->ip_p,
+ ntohs( iph->ip_off ) & 0x1FFF,
+ ntohs( iph->ip_off ) >> IP_FLAGS_OFFSET,
+ iph->ip_hl
+ );
+}
+
+void print_ip6h( struct ip6_hdr *ip6h )
+{
+ char srcbuf[INET6_ADDRSTRLEN];
+ char dstbuf[INET6_ADDRSTRLEN];
+
+ if ( inet_ntop( AF_INET6, &ip6h->ip6_src, (char *) &srcbuf, INET6_ADDRSTRLEN ) == NULL ) err( 1, "inet_ntop failed" );
+ if ( inet_ntop( AF_INET6, &ip6h->ip6_dst, (char *) &dstbuf, INET6_ADDRSTRLEN ) == NULL ) err( 1, "inet_ntop failed" );
+
+ printf( "IPv6 Packet:\n\
+ Src IP: %s\n\
+ Dst IP: %s\n\
+ Protocol: %i\n\
+ Payload Len: %i\n\
+\n",
+ (char *) &srcbuf,
+ (char *) &dstbuf,
+ ip6h->ip6_nxt,
+ ntohs( ip6h->ip6_plen )
+ );
+}
+
+void print_icmph( struct icmp *icmph )
+{
+ printf( "ICMP Packet:\n\
+ Type: %i\n\
+ Code: %i\n",
+ icmph->icmp_type,
+ icmph->icmp_code
+ );
+ if ( ( icmph->icmp_type == ICMP_ECHO || icmph->icmp_type == ICMP_ECHOREPLY ) && ( icmph->icmp_code == 0 ) ) {
+ printf( " Echo id: %i\n", htons( icmph->icmp_id ) );
+ }
+ printf( "\n" );
+}
+
+void print_icmp6h( struct icmp6_hdr *icmp6h )
+{
+ printf( "ICMPv6 Packet:\n\
+ Type: %i\n\
+ Code: %i\n\
+\n",
+ icmp6h->icmp6_type,
+ icmp6h->icmp6_code
+ );
+}
+
+void print_tcph( struct tcphdr *tcph )
+{
+ printf( "TCP Packet:\n\
+ Src Port: %u\n\
+ Dst Port: %u\n\
+ Seq Num: %u\n\
+ Ack Num: %u\n\
+ Syn: %i\n\
+ Ack: %i\n\
+ Rst: %i\n\
+\n",
+ ntohs( tcph->th_sport ),
+ ntohs( tcph->th_dport ),
+ ntohl( tcph->th_seq ),
+ ntohl( tcph->th_ack ),
+ tcph->th_flags & TH_SYN ? 1 : 0,
+ tcph->th_flags & TH_ACK ? 1 : 0,
+ tcph->th_flags & TH_RST ? 1 : 0
+ );
+}
+
+void build_ethernet( struct ether_header *ethh, char *interface, char *remote_mac, short int ethertype )
+{
+ fill_interface_mac( (char *) &ethh->ether_shost, interface );
+
+ if ( sscanf( remote_mac, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
+ &ethh->ether_dhost[0],
+ &ethh->ether_dhost[1],
+ &ethh->ether_dhost[2],
+ &ethh->ether_dhost[3],
+ &ethh->ether_dhost[4],
+ &ethh->ether_dhost[5] ) != 6 ) {
+ errx( 1, "Unable to parse remote MAC address" );
+ }
+
+ ethh->ether_type = htons( ethertype );
+ print_ethh( ethh );
+}
+
+void build_tcp_syn( void *iph, struct tcphdr *tcph, unsigned short srcport, unsigned short dstport )
+{
+ tcph->th_sport = htons( srcport );
+ tcph->th_dport = htons( dstport );
+ tcph->th_seq = htonl( rand() );
+ tcph->th_ack = 0;
+ tcph->th_x2 = 0;
+ tcph->th_off = SIZEOF_TCP / 4;
+ tcph->th_flags = TH_SYN;
+ tcph->th_win = TCP_WINDOW;
+ tcph->th_sum = 0;
+ tcph->th_urp = 0;
+ if ( do_checksum( iph, IPPROTO_TCP, SIZEOF_TCP ) != 1 )
+ errx( 1, "Unable to compute checksum (build_tcp_syn)." );
+
+ print_tcph( tcph );
+}
+
+void build_icmp_ping( void *iph, struct icmp *icmph, unsigned short payload_length )
+{
+ icmph->icmp_type = ICMP_ECHO;
+ icmph->icmp_code = 0;
+ icmph->icmp_cksum = 0;
+ icmph->icmp_id = htons( SOURCE_PORT );
+ icmph->icmp_seq = htons( 1 );
+ memset( (char *) icmph + SIZEOF_PING, 0x01, payload_length );
+ if ( do_checksum( iph, IPPROTO_ICMP, SIZEOF_PING + payload_length ) != 1 )
+ errx( 1, "Unable to compute checksum (build_icmp_ping)." );
+
+ print_icmph( icmph );
+}
+
+void build_icmp6_ping( void *iph, struct icmp6_hdr *icmp6h, unsigned short payload_length )
+{
+ icmp6h->icmp6_type = ICMP6_ECHO_REQUEST;
+ icmp6h->icmp6_code = 0;
+ icmp6h->icmp6_cksum = 0;
+ icmp6h->icmp6_id = htons( SOURCE_PORT );
+ icmp6h->icmp6_seq = htons( 1 );
+ memset( (char *) icmp6h + SIZEOF_ICMP6, 0x01, payload_length );
+ if ( do_checksum( iph, IPPROTO_ICMPV6, SIZEOF_ICMP6 + payload_length ) != 1 )
+ errx( 1, "Unable to compute checksum (build_icmp6_ping)." );
+
+ print_icmp6h( icmp6h );
+}
+
+void build_bare_ipv4( struct ip *iph, char *srcip, char *dstip, unsigned char protocol )
+{
+ iph->ip_v = 4;
+ iph->ip_hl = 5;
+ iph->ip_tos = 0;
+ iph->ip_len = htons( SIZEOF_IPV4 + SIZEOF_TCP );
+ iph->ip_id = 0;
+ iph->ip_off = 0;
+ iph->ip_ttl = IPDEFTTL;
+ iph->ip_p = protocol;
+ iph->ip_sum = 0;
+ iph->ip_src.s_addr = inet_addr(srcip);
+ iph->ip_dst.s_addr = inet_addr(dstip);
+}
+
+void build_ipv4( struct ip *iph, char *srcip, char *dstip, unsigned char protocol )
+{
+ build_bare_ipv4( iph, srcip, dstip, protocol );
+ if ( do_checksum( (char *) iph, IPPROTO_IP, iph->ip_hl * 4 ) != 1 )
+ errx( 1, "Unable to compute checksum (build_ipv4)." );
+
+ print_iph( iph );
+}
+
+void build_ipv4_short_frag1( struct ip *iph, char *srcip, char *dstip, unsigned char protocol, unsigned short fragid )
+{
+ build_bare_ipv4( iph, srcip, dstip, protocol );
+ iph->ip_off = htons( 1 << IP_FLAGS_OFFSET ); /* Set More Fragments (MF) bit */
+ iph->ip_id = htons( fragid );
+ iph->ip_len = htons( SIZEOF_IPV4 + MINIMUM_FRAGMENT_SIZE );
+ if ( do_checksum( (char *) iph, IPPROTO_IP, iph->ip_hl * 4 ) != 1 )
+ errx( 1, "Unable to compute checksum (build_ipv4_short_frag1)." );
+
+ print_iph( iph );
+}
+
+void build_ipv4_frag2( struct ip *iph, char *srcip, char *dstip, unsigned char protocol, unsigned short fragid, unsigned short payload_length )
+{
+ build_bare_ipv4( iph, srcip, dstip, protocol );
+ iph->ip_off = htons( 1 );
+ iph->ip_id = htons( fragid );
+ iph->ip_len = htons( SIZEOF_IPV4 + payload_length );
+ if ( do_checksum( (char *) iph, IPPROTO_IP, iph->ip_hl * 4 ) != 1 )
+ errx( 1, "Unable to compute checksum (build_ipv4_frag2)." );
+
+ print_iph( iph );
+}
+
+void build_ipv4_optioned_frag1( struct ip *iph, char *srcip, char *dstip, unsigned char protocol, unsigned short fragid, unsigned short optlen )
+{
+ build_bare_ipv4( iph, srcip, dstip, protocol );
+ iph->ip_off = htons( 1 << IP_FLAGS_OFFSET ); /* Set More Fragments (MF) bit */
+ iph->ip_id = htons( fragid );
+ iph->ip_len = htons( SIZEOF_IPV4 + optlen + MINIMUM_FRAGMENT_SIZE );
+
+ if ( optlen % 4 != 0 ) errx( 1, "optlen must be a multiple of 4" );
+ iph->ip_hl = 5 + optlen;
+
+ /* Pad with NOP's and then end-of-padding option. */
+ memset( (char *) iph + SIZEOF_IPV4, 0x01, optlen );
+ *( (char *) iph + SIZEOF_IPV4 + optlen ) = 0;
+ if ( do_checksum( (char *) iph, IPPROTO_IP, iph->ip_hl * 4 ) != 1 )
+ errx( 1, "Unable to compute checksum (build_ipv4_optioned_frag1)." );
+
+ print_iph( iph );
+}
+
+void build_ipv6( struct ip6_hdr *ip6h, char *srcip, char *dstip, unsigned char protocol, unsigned short payload_length )
+{
+ /* 4 bits version, 8 bits TC, 20 bits flow-ID. We only set the version bits. */
+ ip6h->ip6_flow = htonl( 0x06 << 28 );
+ ip6h->ip6_plen = htons( payload_length );
+ ip6h->ip6_hlim = 64;
+ ip6h->ip6_nxt = protocol;
+ if ( !inet_pton( AF_INET6, srcip, &ip6h->ip6_src ) ) errx( 1, "Invalid source address" );
+ if ( !inet_pton( AF_INET6, dstip, &ip6h->ip6_dst ) ) errx( 1, "Invalid source address" );
+
+ print_ip6h( ip6h );
+}
+
+void build_ipv6_short_frag1( struct ip6_hdr *ip6h, char *srcip, char *dstip, unsigned char protocol, unsigned short fragid )
+{
+ struct ip6_frag *fragh = (struct ip6_frag *) ( (char *)ip6h + SIZEOF_IPV6 );
+
+ /* 4 bits version, 8 bits TC, 20 bits flow-ID. We only set the version bits. */
+ ip6h->ip6_flow = htonl( 0x06 << 28 );
+ ip6h->ip6_plen = htons( sizeof( struct ip6_frag ) + MINIMUM_FRAGMENT_SIZE );
+ ip6h->ip6_hlim = 64;
+ ip6h->ip6_nxt = IPPROTO_FRAGMENT;
+ if ( !inet_pton( AF_INET6, srcip, &ip6h->ip6_src ) ) errx( 1, "Invalid source address" );
+ if ( !inet_pton( AF_INET6, dstip, &ip6h->ip6_dst ) ) errx( 1, "Invalid source address" );
+
+ fragh->ip6f_reserved = 0;
+ fragh->ip6f_nxt = protocol;
+ fragh->ip6f_ident = htons( fragid );
+ fragh->ip6f_offlg = IP6F_MORE_FRAG;
+
+ print_ip6h( ip6h );
+}
+
+void build_ipv6_optioned_frag1( struct ip6_hdr *ip6h, char *srcip, char *dstip, unsigned char protocol, unsigned short fragid, unsigned short optlen )
+{
+ struct ip6_dest *desth = (struct ip6_dest *) ( (char *)ip6h + SIZEOF_IPV6 );
+ struct ip6_frag *fragh = (struct ip6_frag *) ( (char *)ip6h + SIZEOF_IPV6 + sizeof( struct ip6_dest ) + optlen );
+
+ /* 4 bits version, 8 bits TC, 20 bits flow-ID. We only set the version bits. */
+ ip6h->ip6_flow = htonl( 0x06 << 28 );
+ ip6h->ip6_plen = htons( sizeof( struct ip6_dest ) + optlen + sizeof( struct ip6_frag ) + MINIMUM_FRAGMENT_SIZE );
+ ip6h->ip6_hlim = 64;
+ ip6h->ip6_nxt = IPPROTO_DSTOPTS;
+ if ( !inet_pton( AF_INET6, srcip, &ip6h->ip6_src ) ) errx( 1, "Invalid source address" );
+ if ( !inet_pton( AF_INET6, dstip, &ip6h->ip6_dst ) ) errx( 1, "Invalid source address" );
+
+ if ( optlen == 0 || optlen % 8 != 6 ) errx( 1, "optlen value not supported" );
+ desth->ip6d_nxt = IPPROTO_FRAGMENT;
+ desth->ip6d_len = optlen / 8;
+
+ *( (char *) desth + sizeof( struct ip6_dest ) ) = 1;
+ *( (char *) desth + sizeof( struct ip6_dest ) + 1 ) = optlen - 2;
+ memset( (char *) desth + sizeof( struct ip6_dest ) + 2, 0, optlen - 2 );
+
+ fragh->ip6f_reserved = 0;
+ fragh->ip6f_nxt = protocol;
+ fragh->ip6f_ident = htons( fragid );
+ fragh->ip6f_offlg = IP6F_MORE_FRAG;
+
+ print_ip6h( ip6h );
+}
+
+void build_ipv6_frag2( struct ip6_hdr *ip6h, char *srcip, char *dstip, unsigned char protocol, unsigned short fragid, unsigned short payload_length )
+{
+ struct ip6_frag *fragh = (struct ip6_frag *) ( (char *)ip6h + SIZEOF_IPV6 );
+
+ /* 4 bits version, 8 bits TC, 20 bits flow-ID. We only set the version bits. */
+ ip6h->ip6_flow = htonl( 0x06 << 28 );
+ ip6h->ip6_plen = htons( payload_length + sizeof( struct ip6_frag ) );
+ ip6h->ip6_hlim = 64;
+ ip6h->ip6_nxt = IPPROTO_FRAGMENT;
+ if ( !inet_pton( AF_INET6, srcip, &ip6h->ip6_src ) ) errx( 1, "Invalid source address" );
+ if ( !inet_pton( AF_INET6, dstip, &ip6h->ip6_dst ) ) errx( 1, "Invalid source address" );
+
+ fragh->ip6f_reserved = 0;
+ fragh->ip6f_nxt = protocol;
+ fragh->ip6f_ident = htons( fragid );
+ fragh->ip6f_offlg = htons( 1 << 3 );
+
+ print_ip6h( ip6h );
+}
+
+/* Returns the layer 4 header if we found one. */
+char *print_a_packet( int len, char *packet_data, unsigned short wanted_type )
+{
+ struct ip *iph;
+ struct ip6_hdr *ip6h;
+ size_t s;
+ struct ether_header *ethh = (struct ether_header *) packet_data;
+ unsigned short found_type;
+ char *found_header;
+
+ if ( ntohs( ethh->ether_type ) == ETHERTYPE_IP ) {
+ iph = (struct ip *) ( packet_data + SIZEOF_ETHER );
+ s = SIZEOF_ETHER + ( iph->ip_hl * 4 );
+ if ( s > len ) errx( 1, "Reply too short (IPv4)" );
+ print_iph( iph );
+ if ( iph->ip_p == IPPROTO_TCP ) {
+ if ( s + SIZEOF_TCP > len ) errx( 1, "Reply too short" );
+ print_tcph( (struct tcphdr *) ( packet_data + s ) );
+ found_type = IPPROTO_TCP;
+ found_header = packet_data + s;
+ } else if ( iph->ip_p == IPPROTO_ICMP ) {
+ if ( s + SIZEOF_PING > len ) errx( 1, "Reply too short" );
+ print_icmph( (struct icmp *) ( packet_data + s ) );
+ found_type = IPPROTO_ICMP;
+ found_header = packet_data + s;
+ } else {
+ errx( 1, "Unknown reply received (ip protocol %i)", iph->ip_p );
+ }
+
+ } else if ( ntohs( ethh->ether_type ) == ETHERTYPE_IPV6 ) {
+ ip6h = (struct ip6_hdr *) ( packet_data + SIZEOF_ETHER );
+ s = SIZEOF_ETHER + SIZEOF_IPV6;
+ if ( s > len ) errx( 1, "Reply too short (IPv6)" );
+ print_ip6h( ip6h );
+ if ( ip6h->ip6_nxt == IPPROTO_TCP ) {
+ if ( s + SIZEOF_TCP > len ) errx( 1, "Reply too short" );
+ print_tcph( (struct tcphdr *) ( packet_data + s ) );
+ found_type = IPPROTO_TCP;
+ found_header = packet_data + s;
+ } else if ( ip6h->ip6_nxt == IPPROTO_ICMPV6 ) {
+ if ( s + SIZEOF_ICMP6 > len ) errx( 1, "Reply too short" );
+ print_icmp6h( (struct icmp6_hdr *) ( packet_data + s ) );
+ found_type = IPPROTO_ICMPV6;
+ found_header = packet_data + s;
+ } else {
+ errx( 1, "Unknown reply received (ip6 next header %i)", ip6h->ip6_nxt );
+ }
+
+ } else {
+ errx( 1, "Unknown reply received (ethertype %i)", ntohs( ethh->ether_type ) );
+ }
+
+ if ( wanted_type == found_type ) return found_header;
+ return NULL;
+}
+
+int receive_a_packet( char *srcip, char *dstip, unsigned short srcport, unsigned short dstport, enum TEST_TYPE test_type, char **packet_buf )
+{
+ struct pcap_pkthdr *received_packet_pcap;
+ struct bpf_program pcap_filter;
+ char *received_packet_data;
+/*
+ * My back-of-the-napkin for the maximum length for the ipv6 filter string
+ * below + 1 byte for the trailing NULL
+ */
+#define FILTER_STR_LEN 203
+ char filter_str[FILTER_STR_LEN];
+ int r, fd;
+ fd_set select_me;
+ struct timeval ts;
+
+ /*
+ * Something prior to now should have validated srcip and dstip are valid
+ * IP addresses, we hope. Napkin math says we shouldn't even be close to
+ * overflowing our buffer.
+ */
+ if ( IS_TEST_IPV4( test_type ) ) {
+ r = snprintf(
+ (char *) &filter_str,
+ FILTER_STR_LEN,
+ "src %s and dst %s and (icmp or (tcp and src port %i and dst port %i))",
+ srcip,
+ dstip,
+ srcport,
+ dstport
+ );
+ } else {
+ r = snprintf(
+ (char *) &filter_str,
+ FILTER_STR_LEN,
+ /* Attempt to ignore ICMP6 neighbor solicitation/advertisement */
+ "src %s and dst %s and ((icmp6 and ip6[40] != 135 and ip6[40] != 136) or (tcp and src port %i and dst port %i))",
+ srcip,
+ dstip,
+ srcport,
+ dstport
+ );
+ }
+ if ( r < 0 || r >= FILTER_STR_LEN ) errx( 1, "snprintf for pcap filter failed" );
+ if ( pcap_compile( pcap, &pcap_filter, (char *) &filter_str, 1, 0 ) == -1 )
+ errx( 1, "pcap_compile failed: %s", pcap_geterr( pcap ) );
+ if ( pcap_setfilter( pcap, &pcap_filter ) == -1 )
+ errx( 1, "pcap_setfilter failed: %s", pcap_geterr( pcap ) );
+ pcap_freecode( &pcap_filter );
+
+ if ( ( fd = pcap_fileno( pcap ) ) == -1 )
+ errx( 1, "pcap_fileno failed" );
+
+ FD_ZERO( &select_me );
+ FD_SET( fd, &select_me );
+
+ ts.tv_sec = PCAP_TIMEOUT_SECONDS;
+ ts.tv_usec = 0;
+
+ /*
+ * Signal we're ready to go. Still a race condition. I don't see how to
+ * work around this with pcap.
+ */
+ write( pfd[1], ".", 1 );
+ r = select( fd + 1, &select_me, NULL, NULL, &ts );
+ /* Timed out */
+ if ( r == 0 ) return 0;
+
+ r = pcap_next_ex( pcap, &received_packet_pcap, (const unsigned char **) &received_packet_data );
+
+ /* Error or pcap_next_ex timed out (should never happen) */
+ if ( r < 1 ) return 0;
+ if ( received_packet_pcap->len > received_packet_pcap->caplen ) errx( 1, "pcap didn't capture the whole packet." );
+
+ *packet_buf = (char *) received_packet_data;
+ return received_packet_pcap->len;
+}
+
+int check_received_packet( int buf_len, char *packet_buf, enum TEST_TYPE test_type ) {
+ struct ether_header *received_packet_data = (struct ether_header *) packet_buf;
+ struct tcphdr *tcph;
+ struct icmp *icmph;
+ struct icmp6_hdr *icmp6h;
+
+ if ( IS_TEST_IPV4( test_type ) && IS_TEST_ICMP( test_type ) ) {
+ icmph = (struct icmp *) print_a_packet( buf_len, (char *) received_packet_data, IPPROTO_ICMP );
+ if ( !icmph ) return 0;
+ if ( icmph->icmp_type == ICMP_ECHOREPLY && icmph->icmp_id == htons( SOURCE_PORT ) ) return 1;
+ } else if ( IS_TEST_IPV6( test_type ) && IS_TEST_ICMP( test_type ) ) {
+ icmp6h = (struct icmp6_hdr *) print_a_packet( buf_len, (char *) received_packet_data, IPPROTO_ICMPV6 );
+ if ( !icmp6h ) return 0;
+ if ( icmp6h->icmp6_type == ICMP6_ECHO_REPLY && icmp6h->icmp6_id == htons( SOURCE_PORT ) ) return 1;
+ } else { /* Assume pcap picked the right address family for our packet. */
+ tcph = (struct tcphdr *) print_a_packet( buf_len, (char *) received_packet_data, IPPROTO_TCP );
+ if ( !tcph ) return 0;
+ if ( ( tcph->th_flags & ( TH_SYN|TH_ACK ) ) && !( tcph->th_flags & TH_RST ) ) {
+ return 1;
+ }
+ }
+ printf( "Received reply but it wasn't what we were hoping for.\n" );
+ return 0;
+}
+
+/* IPv4 tests. */
+void do_ipv4_syn( char *interface, char *srcip, char *dstip, char *dstmac, unsigned short dstport )
+{
+ struct ip *iph;
+ struct tcphdr *tcph;
+ struct ether_header *ethh;
+ int packet_size;
+
+ packet_size = SIZEOF_ETHER + SIZEOF_TCP + SIZEOF_IPV4;
+
+ ethh = (struct ether_header *) malloc_check( packet_size );
+ iph = (struct ip *) ( (char *) ethh + SIZEOF_ETHER );
+ tcph = (struct tcphdr *) ( (char *) iph + SIZEOF_IPV4 );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IP );
+ build_ipv4( iph, srcip, dstip, IPPROTO_TCP );
+ build_tcp_syn( iph, tcph, SOURCE_PORT, dstport );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+void do_ipv4_short_tcp_frag( char *interface, char *srcip, char *dstip, char *dstmac, unsigned short dstport )
+{
+ struct ip *iph;
+ struct tcphdr *tcph;
+ struct ether_header *ethh;
+ int packet_size;
+ unsigned short fragid = rand();
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV4 + MINIMUM_FRAGMENT_SIZE;
+
+ ethh = (struct ether_header *) malloc_check( BIG_PACKET_SIZE );
+ iph = (struct ip *) ( (char *) ethh + SIZEOF_ETHER );
+ tcph = (struct tcphdr *) ( (char *) iph + SIZEOF_IPV4 );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IP );
+ build_ipv4_short_frag1( iph, srcip, dstip, IPPROTO_TCP, fragid );
+ build_tcp_syn( iph, tcph, SOURCE_PORT, dstport );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV4 + SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE;
+
+ build_ipv4_frag2( iph, srcip, dstip, IPPROTO_TCP, fragid, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+ memmove( tcph, (char *) tcph + MINIMUM_FRAGMENT_SIZE, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+void do_ipv4_short_icmp_frag( char *interface, char *srcip, char *dstip, char *dstmac )
+{
+ struct ip *iph;
+ struct icmp *icmph;
+ struct ether_header *ethh;
+ int packet_size;
+ unsigned short fragid = rand();
+ unsigned short pinglen = 40;
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV4 + MINIMUM_FRAGMENT_SIZE;
+
+ ethh = (struct ether_header *) malloc_check( BIG_PACKET_SIZE );
+ iph = (struct ip *) ( (char *) ethh + SIZEOF_ETHER );
+ icmph = (struct icmp *) ( (char *) iph + SIZEOF_IPV4 );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IP );
+ build_ipv4_short_frag1( iph, srcip, dstip, IPPROTO_ICMP, fragid );
+ build_icmp_ping( iph, icmph, pinglen );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV4 + SIZEOF_PING + pinglen - MINIMUM_FRAGMENT_SIZE;
+
+ build_ipv4_frag2( iph, srcip, dstip, IPPROTO_ICMP, fragid, SIZEOF_PING + pinglen - MINIMUM_FRAGMENT_SIZE );
+ memmove( icmph, (char *) icmph + MINIMUM_FRAGMENT_SIZE, SIZEOF_PING + pinglen - MINIMUM_FRAGMENT_SIZE );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+void do_ipv4_optioned_tcp_frag( char *interface, char *srcip, char *dstip, char *dstmac, unsigned short dstport )
+{
+ struct ip *iph;
+ struct tcphdr *tcph, *tcph_optioned;
+ struct ether_header *ethh;
+ int packet_size;
+ unsigned short fragid = rand();
+ unsigned short optlen = 40; /* Multiple of 4. */
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV4 + optlen + MINIMUM_FRAGMENT_SIZE;
+
+ ethh = (struct ether_header *) malloc_check( BIG_PACKET_SIZE );
+ iph = (struct ip *) ( (char *) ethh + SIZEOF_ETHER );
+ tcph = (struct tcphdr *) ( (char *) iph + SIZEOF_IPV4 );
+ tcph_optioned = (struct tcphdr *) ( (char *) tcph + optlen );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IP );
+ build_ipv4_optioned_frag1( iph, srcip, dstip, IPPROTO_TCP, fragid, optlen );
+ build_tcp_syn( iph, tcph_optioned, SOURCE_PORT, dstport );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV4 + SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE;
+
+ build_ipv4_frag2( iph, srcip, dstip, IPPROTO_TCP, fragid, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+ memmove( tcph, (char *) tcph_optioned + MINIMUM_FRAGMENT_SIZE, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+void do_ipv4_optioned_icmp_frag( char *interface, char *srcip, char *dstip, char *dstmac )
+{
+ struct ip *iph;
+ struct icmp *icmph, *icmph_optioned;
+ struct ether_header *ethh;
+ int packet_size;
+ unsigned short fragid = rand();
+ unsigned short optlen = 40; /* Multiple of 4. */
+ unsigned short pinglen = 40;
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV4 + optlen + MINIMUM_FRAGMENT_SIZE;
+
+ ethh = (struct ether_header *) malloc_check( BIG_PACKET_SIZE );
+ iph = (struct ip *) ( (char *) ethh + SIZEOF_ETHER );
+ icmph = (struct icmp *) ( (char *) iph + SIZEOF_IPV4 );
+ icmph_optioned = (struct icmp *) ( (char *) icmph + optlen );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IP );
+ build_ipv4_optioned_frag1( iph, srcip, dstip, IPPROTO_ICMP, fragid, optlen );
+ build_icmp_ping( iph, icmph_optioned, pinglen );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV4 + SIZEOF_PING + pinglen;
+
+ build_ipv4_frag2( iph, srcip, dstip, IPPROTO_ICMP, fragid, SIZEOF_PING - MINIMUM_FRAGMENT_SIZE + pinglen );
+ memmove( icmph, (char *) icmph_optioned + MINIMUM_FRAGMENT_SIZE, SIZEOF_PING + pinglen - MINIMUM_FRAGMENT_SIZE );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+/* IPv6 tests. */
+void do_ipv6_syn( char *interface, char *srcip, char *dstip, char *dstmac, unsigned short dstport )
+{
+ struct ip6_hdr *ip6h;
+ struct tcphdr *tcph;
+ struct ether_header *ethh;
+ int packet_size;
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + SIZEOF_TCP;
+
+ ethh = (struct ether_header *) malloc_check( packet_size );
+ ip6h = (struct ip6_hdr *) ( (char *) ethh + SIZEOF_ETHER );
+ tcph = (struct tcphdr *) ( (char *) ip6h + SIZEOF_IPV6 );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IPV6 );
+ build_ipv6( ip6h, srcip, dstip, IPPROTO_TCP, SIZEOF_TCP );
+ build_tcp_syn( ip6h, tcph, SOURCE_PORT, dstport );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+void do_ipv6_short_tcp_frag( char *interface, char *srcip, char *dstip, char *dstmac, unsigned short dstport )
+{
+ struct ip6_hdr *ip6h;
+ struct tcphdr *tcph;
+ struct ether_header *ethh;
+ int packet_size;
+ unsigned short fragid = rand();
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + sizeof( struct ip6_frag ) + MINIMUM_FRAGMENT_SIZE;
+
+ ethh = (struct ether_header *) malloc_check( BIG_PACKET_SIZE );
+ ip6h = (struct ip6_hdr *) ( (char *) ethh + SIZEOF_ETHER );
+ tcph = (struct tcphdr *) ( (char *) ip6h + SIZEOF_IPV6 + sizeof( struct ip6_frag ) );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IPV6 );
+ build_ipv6_short_frag1( ip6h, srcip, dstip, IPPROTO_TCP, fragid );
+ build_tcp_syn( ip6h, tcph, SOURCE_PORT, dstport );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + sizeof( struct ip6_frag ) + SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE;
+
+ build_ipv6_frag2( ip6h, srcip, dstip, IPPROTO_TCP, fragid, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+ memmove( tcph, (char *) tcph + MINIMUM_FRAGMENT_SIZE, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+void do_ipv6_short_icmp_frag( char *interface, char *srcip, char *dstip, char *dstmac )
+{
+ struct ip6_hdr *ip6h;
+ struct icmp6_hdr *icmp6h;
+ struct ether_header *ethh;
+ int packet_size;
+ unsigned short fragid = rand();
+ unsigned short pinglen = 40;
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + sizeof( struct ip6_frag ) + MINIMUM_FRAGMENT_SIZE;
+
+ ethh = (struct ether_header *) malloc_check( BIG_PACKET_SIZE );
+ ip6h = (struct ip6_hdr *) ( (char *) ethh + SIZEOF_ETHER );
+ icmp6h = (struct icmp6_hdr *) ( (char *) ip6h + SIZEOF_IPV6 + sizeof( struct ip6_frag ) );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IPV6 );
+ build_ipv6_short_frag1( ip6h, srcip, dstip, IPPROTO_ICMPV6, fragid );
+ build_icmp6_ping( ip6h, icmp6h, pinglen );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + sizeof( struct ip6_frag ) + SIZEOF_PING + pinglen - MINIMUM_FRAGMENT_SIZE;
+
+ build_ipv6_frag2( ip6h, srcip, dstip, IPPROTO_ICMPV6, fragid, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+ memmove( icmp6h, (char *) icmp6h + MINIMUM_FRAGMENT_SIZE, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+void do_ipv6_optioned_icmp_frag( char *interface, char *srcip, char *dstip, char *dstmac )
+{
+ struct ip6_hdr *ip6h;
+ struct icmp6_hdr *icmp6h, *icmp6h_optioned;
+ struct ether_header *ethh;
+ int packet_size;
+ unsigned short fragid = rand();
+ unsigned short optlen = fix_up_destination_options_length(
+ MINIMUM_PACKET_SIZE - SIZEOF_IPV6 - sizeof( struct ip6_dest ) - sizeof( struct ip6_frag ) - MINIMUM_FRAGMENT_SIZE
+ );
+ /*
+ * pinglen must be > 6 or our first packet will be <= MINIMUM_PACKET_SIZE bytes and
+ * our second packet empty.
+ */
+ unsigned short pinglen = 40;
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + sizeof( struct ip6_dest ) + optlen + sizeof( struct ip6_frag ) + MINIMUM_FRAGMENT_SIZE;
+
+ ethh = (struct ether_header *) malloc_check( BIG_PACKET_SIZE );
+ ip6h = (struct ip6_hdr *) ( (char *) ethh + SIZEOF_ETHER );
+ icmp6h = (struct icmp6_hdr *) ( (char *) ip6h + SIZEOF_IPV6 + sizeof( struct ip6_frag ) );
+ icmp6h_optioned = (struct icmp6_hdr *) ( (char *) ip6h + SIZEOF_IPV6 + sizeof( struct ip6_dest ) + optlen + sizeof( struct ip6_frag ) );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IPV6 );
+ build_ipv6_optioned_frag1( ip6h, srcip, dstip, IPPROTO_ICMPV6, fragid, optlen );
+ build_icmp6_ping( ip6h, icmp6h_optioned, pinglen );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + sizeof( struct ip6_frag ) + SIZEOF_PING + pinglen - MINIMUM_FRAGMENT_SIZE;
+
+ build_ipv6_frag2( ip6h, srcip, dstip, IPPROTO_ICMPV6, fragid, SIZEOF_ICMP6 + pinglen - MINIMUM_FRAGMENT_SIZE );
+ memmove( icmp6h, (char *) icmp6h_optioned + MINIMUM_FRAGMENT_SIZE, SIZEOF_ICMP6 + pinglen - MINIMUM_FRAGMENT_SIZE );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+void do_ipv6_optioned_tcp_frag( char *interface, char *srcip, char *dstip, char *dstmac, unsigned short dstport )
+{
+ struct ip6_hdr *ip6h;
+ struct tcphdr *tcph, *tcph_optioned;
+ struct ether_header *ethh;
+ int packet_size;
+ unsigned short fragid = rand();
+ unsigned short optlen = fix_up_destination_options_length(
+ MINIMUM_PACKET_SIZE - SIZEOF_IPV6 - sizeof( struct ip6_dest ) - sizeof( struct ip6_frag ) - MINIMUM_FRAGMENT_SIZE
+ );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + sizeof( struct ip6_dest ) + optlen + sizeof( struct ip6_frag ) + MINIMUM_FRAGMENT_SIZE;
+
+ ethh = (struct ether_header *) malloc_check( BIG_PACKET_SIZE );
+ ip6h = (struct ip6_hdr *) ( (char *) ethh + SIZEOF_ETHER );
+ tcph = (struct tcphdr *) ( (char *) ip6h + SIZEOF_IPV6 + sizeof( struct ip6_frag ) );
+ tcph_optioned = (struct tcphdr *) ( (char *) ip6h + SIZEOF_IPV6 + sizeof( struct ip6_dest ) + optlen + sizeof( struct ip6_frag ) );
+
+ build_ethernet( ethh, interface, dstmac, ETHERTYPE_IPV6 );
+ build_ipv6_optioned_frag1( ip6h, srcip, dstip, IPPROTO_TCP, fragid, optlen );
+ build_tcp_syn( ip6h, tcph_optioned, SOURCE_PORT, dstport );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+
+ packet_size = SIZEOF_ETHER + SIZEOF_IPV6 + sizeof( struct ip6_frag ) + SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE;
+
+ build_ipv6_frag2( ip6h, srcip, dstip, IPPROTO_TCP, fragid, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+ memmove( tcph, (char *) tcph_optioned + MINIMUM_FRAGMENT_SIZE, SIZEOF_TCP - MINIMUM_FRAGMENT_SIZE );
+
+ if ( pcap_inject( pcap, ethh, packet_size ) != packet_size ) errx( 1, "pcap_inject" );
+ free( ethh );
+}
+
+/* Process functions. */
+void fork_pcap_listener( char *dstip, char *srcip, unsigned short dstport, unsigned short srcport, enum TEST_TYPE test_type )
+{
+ char *packet_buf;
+ char buf;
+ int r;
+
+ if ( pipe(pfd) == -1 ) err( 1, "Failed to creatre pipe." );
+
+ listener_pid = fork();
+ if ( listener_pid == -1 ) err( 1, "Failed to fork" );
+ if ( listener_pid ) {
+ close( pfd[1] );
+ read( pfd[0], &buf, 1 );
+ return;
+ }
+ close( pfd[0] );
+ /*
+ * Due to how pcap works there's still a race between we signal that we are
+ * ready and when we actually call select(). Will this even help with our
+ * race condition if write() doesn't block? The documentation seems unclear
+ * as to the advantages of O_NONBLOCK with a 1 byte write.
+ */
+ fcntl( pfd[1], F_SETFL, O_NONBLOCK );
+
+ pcap_setdirection( pcap, PCAP_D_IN );
+
+ r = receive_a_packet( dstip, srcip, dstport, SOURCE_PORT, test_type, &packet_buf );
+ if ( r ) {
+ write( pfd[1], &r, sizeof( int ) );
+ write( pfd[1], packet_buf, r );
+ } else {
+ r = 0;
+ write( pfd[1], &r, sizeof( int ) );
+ }
+ close( pfd[1] );
+ exit( 0 );
+}
+
+int harvest_pcap_listener( char **packet_buf ) {
+ int packet_buf_size;
+
+ if ( read( pfd[0], &packet_buf_size, sizeof( int ) ) < sizeof( int ) )
+ errx( 1, "Error communicating with child process." );
+ /* No packet received. */
+ if ( packet_buf_size == 0 ) return 0;
+ if ( packet_buf_size > PCAP_CAPTURE_LEN || packet_buf_size < 1 )
+ errx( 1, "Bad data received from child process." );
+ *packet_buf = (char *) malloc_check( packet_buf_size );
+ if ( read( pfd[0], *packet_buf, packet_buf_size ) < packet_buf_size )
+ errx( 1, "Error communicating with child process (2)." );
+ wait( NULL );
+ return packet_buf_size;
+}
+
+void exit_with_usage(void)
+{
+ char *test;
+ int x = 0;
+
+ fprintf( stderr, "synfrag usage:\n" );
+ fprintf( stderr, "--help | -h This message.\n" );
+ fprintf( stderr, "--srcip Source IP address (this hosts)\n" );
+ fprintf( stderr, "--dstip Destination IP address (target)\n" );
+ /* Currently not used.
+ fprintf( stderr, "--srcport Source port for TCP tests\n" ); */
+ fprintf( stderr, "--dstport Destination port for TCP tests\n" );
+ fprintf( stderr, "--dstmac Destination MAC address (default gw or target host if on subnet)\n" );
+ fprintf( stderr, "--interface Packet source interface\n" );
+ fprintf( stderr, "--test Type of test to run.\n\n" );
+ fprintf( stderr, "Available test types:\n\n" );
+ while ( ( test = test_names[x++] ) ) {
+ fprintf( stderr, "%s\n", test );
+ }
+ fprintf( stderr, "\nAll TCP tests send syn packets, all ICMP/6 test send ping.\n" );
+ fprintf( stderr, "All \"frag\" tests send fragments that are below the minimum packet size.\n" );
+ fprintf( stderr, "All \"optioned\" tests send fragments that meet the minimum packet size.\n" );
+ exit( 2 );
+}
+
+void copy_arg_string( char **dst, char *opt )
+{
+ *dst = malloc( strlen( opt ) );
+ memcpy( *dst, opt, strlen( opt) );
+}
+
+void ip_test_arg( char *opt )
+{
+ struct in6_addr iptest;
+ if (
+ ( !inet_pton( AF_INET, opt, &iptest ) ) &&
+ ( !inet_pton( AF_INET6, opt, &iptest ) )
+ ) errx( 1, "Invalid IP address: %s", opt );
+}
+
+enum TEST_TYPE parse_args(
+ int argc,
+ char **argv,
+ char **srcip,
+ char **dstip,
+ unsigned short *srcport,
+ unsigned short *dstport,
+ char **dstmac,
+ char **interface,
+ char **test_name
+) {
+ int x = 0;
+ int option_index = 0;
+ int c, tmpport;
+ char *possible_match;
+ enum TEST_TYPE test_type = 0;
+ static struct option long_options[] = {
+ {"srcip", required_argument, 0, 0},
+ {"dstip", required_argument, 0, 0},
+ {"srcport", required_argument, 0, 0},
+ {"dstport", required_argument, 0, 0},
+ {"dstmac", required_argument, 0, 0},
+ {"interface", required_argument, 0, 0},
+ {"test", required_argument, 0, 0},
+ {"help", no_argument, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ if ( argc < 2 ) exit_with_usage();
+
+ *srcip = *dstip = *dstmac = *interface = NULL;
+ *srcport = *dstport = 0;
+
+ while ( 1 ) {
+ c = getopt_long(argc, argv, "h", long_options, &option_index);
+ if ( c != 0 && c != 'h' ) break;
+
+ if ( ( c == 'h' ) || ( strcmp( long_options[option_index].name, "help" ) == 0 ) ) {
+ exit_with_usage();
+
+ } else if ( strcmp( long_options[option_index].name, "srcip" ) == 0 ) {
+ copy_arg_string( srcip, optarg );
+
+ } else if ( strcmp( long_options[option_index].name, "dstip" ) == 0 ) {
+ copy_arg_string( dstip, optarg );
+
+ } else if ( strcmp( long_options[option_index].name, "dstmac" ) == 0 ) {
+ copy_arg_string( dstmac, optarg );
+
+ } else if ( strcmp( long_options[option_index].name, "interface" ) == 0 ) {
+ copy_arg_string( interface, optarg );
+
+ } else if ( strcmp( long_options[option_index].name, "srcport" ) == 0 ) {
+ tmpport = atoi( optarg );
+ if ( tmpport > 65535 || tmpport < 1 ) errx( 1, "Invalid value for srcport" );
+ *srcport = (unsigned short) tmpport;
+
+ } else if ( strcmp( long_options[option_index].name, "dstport" ) == 0 ) {
+ tmpport = atoi( optarg );
+ if ( tmpport > 65535 || tmpport < 1 ) errx( 1, "Invalid value for dstport" );
+ *dstport = (unsigned short) tmpport;
+
+ } else if ( strcmp( long_options[option_index].name, "test" ) == 0 ) {
+ while ( ( possible_match = test_names[x] ) ) {
+ if ( strcmp( optarg, possible_match ) == 0 ) {
+ test_type = test_indexes[x];
+ *test_name = test_names[x];
+ break;
+ }
+ x++;
+ }
+ }
+ }
+
+ if ( optind < argc ) exit_with_usage();
+
+ if ( !*srcip ) errx( 1, "Missing srcip" );
+ if ( !*dstip ) errx( 1, "Missing dstip" );
+ if ( !*dstmac ) errx( 1, "Missing dstmac" );
+ if ( !*interface ) errx( 1, "Missing interface" );
+ if ( !test_type ) errx( 1, "Missing or invalid test type." );
+
+ if ( IS_TEST_TCP( test_type ) ) {
+ /* Currently not used.
+ if ( !*srcport ) errx( 1, "Missing srcport" ); */
+ if ( !*dstport ) errx( 1, "Missing dstport" );
+ }
+
+ return test_type;
+}
+
+int main( int argc, char **argv )
+{
+ char pcaperr[PCAP_ERRBUF_SIZE];
+ int r;
+ enum TEST_TYPE test_type;
+ char *interface;
+ char *srcip;
+ char *dstip;
+ char *dstmac;
+ unsigned short dstport;
+ unsigned short srcport;
+ char *packet_buf;
+ char *test_name;
+
+ test_type = parse_args( argc, argv, &srcip, &dstip, &srcport, &dstport, &dstmac, &interface, &test_name );
+ srand( getpid() );
+
+ printf( "Starting test \"%s\". Opening interface \"%s\".\n\n", test_name, interface );
+ if ( ( pcap = pcap_open_live( interface, PCAP_CAPTURE_LEN, 0, 1, pcaperr ) ) == NULL )
+ errx( 1, "pcap_open_live failed: %s", pcaperr );
+
+ if ( pcap_datalink( pcap ) != DLT_EN10MB )
+ errx( 1, "non-ethernet interface specified." );
+
+ fork_pcap_listener( dstip, srcip, dstport, SOURCE_PORT, test_type );
+
+ switch ( test_type ) {
+ case TEST_IPV4_TCP:
+ do_ipv4_syn( interface, srcip, dstip, dstmac, dstport );
+ break;
+ case TEST_FRAG_IPV4_TCP:
+ do_ipv4_short_tcp_frag( interface, srcip, dstip, dstmac, dstport );
+ break;
+ case TEST_FRAG_IPV4_ICMP:
+ do_ipv4_short_icmp_frag( interface, srcip, dstip, dstmac );
+ break;
+ case TEST_FRAG_OPTIONED_IPV4_TCP:
+ do_ipv4_optioned_tcp_frag( interface, srcip, dstip, dstmac, dstport );
+ break;
+ case TEST_FRAG_OPTIONED_IPV4_ICMP:
+ do_ipv4_optioned_icmp_frag( interface, srcip, dstip, dstmac );
+ break;
+
+ case TEST_IPV6_TCP:
+ do_ipv6_syn( interface, srcip, dstip, dstmac, dstport );
+ break;
+ case TEST_FRAG_IPV6_TCP:
+ do_ipv6_short_tcp_frag( interface, srcip, dstip, dstmac, dstport );
+ break;
+ case TEST_FRAG_IPV6_ICMP:
+ do_ipv6_short_icmp_frag( interface, srcip, dstip, dstmac );
+ break;
+ case TEST_FRAG_OPTIONED_IPV6_TCP:
+ do_ipv6_optioned_tcp_frag( interface, srcip, dstip, dstmac, dstport );
+ break;
+ case TEST_FRAG_OPTIONED_IPV6_ICMP6:
+ do_ipv6_optioned_icmp_frag( interface, srcip, dstip, dstmac );
+ break;
+
+ default:
+ errx( 1, "Unsupported test type!" );
+ }
+
+ printf( "Packet transmission successful, waiting for reply...\n\n" );
+
+ r = harvest_pcap_listener( &packet_buf );
+ if ( !r ) {
+ fprintf( stderr, "Test failed, no response before time out (%i seconds).\n", PCAP_TIMEOUT_SECONDS );
+ free( packet_buf );
+ return 1;
+ }
+ if ( check_received_packet( r, packet_buf, test_type ) ) {
+ printf( "Test was successful.\n" );
+ free( packet_buf );
+ return 0;
+ }
+ fprintf( stderr, "Test failed.\n" );
+ free( packet_buf );
+ return 1;
+}
+
Please sign in to comment.
Something went wrong with that request. Please try again.