summaryrefslogtreecommitdiffstats
path: root/network_cmds/ecnprobe
diff options
context:
space:
mode:
Diffstat (limited to 'network_cmds/ecnprobe')
-rw-r--r--network_cmds/ecnprobe/base.h57
-rw-r--r--network_cmds/ecnprobe/capture.c204
-rw-r--r--network_cmds/ecnprobe/capture.h58
-rw-r--r--network_cmds/ecnprobe/ecn.c1119
-rw-r--r--network_cmds/ecnprobe/ecn.h49
-rw-r--r--network_cmds/ecnprobe/ecn_probe.c469
-rw-r--r--network_cmds/ecnprobe/ecnprobe.120
-rw-r--r--network_cmds/ecnprobe/gmt2local.c66
-rw-r--r--network_cmds/ecnprobe/gmt2local.h27
-rw-r--r--network_cmds/ecnprobe/history.c211
-rw-r--r--network_cmds/ecnprobe/history.h75
-rw-r--r--network_cmds/ecnprobe/inet.c503
-rw-r--r--network_cmds/ecnprobe/inet.h206
-rw-r--r--network_cmds/ecnprobe/session.c785
-rw-r--r--network_cmds/ecnprobe/session.h183
-rw-r--r--network_cmds/ecnprobe/support.c246
-rw-r--r--network_cmds/ecnprobe/support.h132
17 files changed, 4410 insertions, 0 deletions
diff --git a/network_cmds/ecnprobe/base.h b/network_cmds/ecnprobe/base.h
new file mode 100644
index 0000000..562b4ef
--- /dev/null
+++ b/network_cmds/ecnprobe/base.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <stdio.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <assert.h>
diff --git a/network_cmds/ecnprobe/capture.c b/network_cmds/ecnprobe/capture.c
new file mode 100644
index 0000000..32a8e0b
--- /dev/null
+++ b/network_cmds/ecnprobe/capture.c
@@ -0,0 +1,204 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmt2local.h"
+#include "pcap.h"
+#include "inet.h"
+#include "capture.h"
+
+/* set snaplen to max etherenet packet size */
+#define DEFAULT_SNAPLEN 1500
+
+pcap_t *pc; /* pcap device */
+int datalinkOffset; /* offset of ip packet from datalink packet */
+int captureDebug = 1;
+unsigned int thisTimeZone;
+
+void CaptureInit(u_int32_t sourceIP, u_int16_t sourcePort,
+ u_int32_t targetIP, u_int16_t targetPort, char *dev)
+{
+
+ char *device = NULL;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ int snaplen = DEFAULT_SNAPLEN;
+ int promisc = 1;
+ int timeout = 10; /* timeout in 1 second (10 ms) */
+ char filtercmds[255];
+ bpf_u_int32 netmask = 0;
+ struct bpf_program filter;
+ char source[18];
+ char target[18];
+ int i;
+
+ /* Get local time zone for interpreting timestamps */
+ /* XXX - does this belong here? */
+ thisTimeZone = gmt2local(0);
+
+ if (dev != NULL) {
+ device = dev;
+ } else {
+ pcap_if_t *devlist;
+ /*
+ * Find the list of interfaces, and pick
+ * the first interface.
+ */
+ if (pcap_findalldevs(&devlist, errbuf) >= 0 &&
+ devlist != NULL) {
+ device = strdup(devlist->name);
+ pcap_freealldevs(devlist);
+ }
+
+ if (device == NULL) {
+ fprintf(stderr, "Can't find capture device: %s\n", errbuf);
+ exit(-1);
+ }
+ }
+
+ if (captureDebug) {
+ printf("Device name is %s\n", device);
+ }
+ pc = pcap_open_live(device, snaplen, promisc, timeout, errbuf);
+ if (pc == NULL) {
+ fprintf(stderr,"Can't open capture device %s: %s\n",device, errbuf);
+ exit(-1);
+ }
+
+ /* XXX why do we need to do this? */
+ i = pcap_snapshot(pc);
+ if (snaplen < i) {
+ fprintf(stderr, "Warning: snaplen raised to %d from %d",
+ snaplen, i);
+ }
+
+ if ((i = pcap_datalink(pc)) < 0) {
+ fprintf(stderr,"Unable to determine datalink type for %s: %s\n",
+ device, errbuf);
+ exit(-1);
+ }
+
+ switch(i) {
+
+ case DLT_EN10MB: datalinkOffset = 14; break;
+ case DLT_IEEE802: datalinkOffset = 22; break;
+ case DLT_NULL: datalinkOffset = 4; break;
+ case DLT_SLIP:
+ case DLT_PPP: datalinkOffset = 24; break;
+ case DLT_RAW: datalinkOffset = 0; break;
+ default:
+ fprintf(stderr,"Unknown datalink type %d\n",i);
+ exit(-1);
+ break;
+
+ }
+
+ if (InetAddress(sourceIP) < 0) {
+ fprintf(stderr, "Invalid source IP address (%d)\n", sourceIP);
+ exit(-1);
+ }
+
+ strlcpy(source, InetAddress(sourceIP), sizeof(source));
+ strlcpy(target, InetAddress(targetIP), sizeof(target));
+
+ /* Setup initial filter */
+ sprintf(filtercmds,
+ "(host %s && host %s && port %d) || icmp\n",
+ source, target, targetPort);
+
+ if (captureDebug) {
+ printf("datalinkOffset = %d\n", datalinkOffset);
+ printf("filter = %s\n", filtercmds);
+ }
+ if (pcap_compile(pc, &filter, filtercmds, 1, netmask) < 0) {
+ printf("Error: %s", pcap_geterr(pc));
+ exit(-1);
+ }
+
+ if (pcap_setfilter(pc, &filter) < 0) {
+ fprintf(stderr, "Can't set filter: %s",pcap_geterr(pc));
+ exit(-1);
+ }
+
+ if (captureDebug) {
+ printf("Listening on %s...\n", device);
+ }
+
+}
+
+char *CaptureGetPacket(struct pcap_pkthdr *pi)
+{
+
+ const u_char *p;
+
+ p = pcap_next(pc, (struct pcap_pkthdr *)pi);
+
+ if (p != NULL) {
+ p += datalinkOffset;
+ }
+
+ pi->ts.tv_sec = (pi->ts.tv_sec + thisTimeZone) % 86400;
+
+ return (char *)p;
+
+}
+
+
+void CaptureEnd()
+{
+ struct pcap_stat stat;
+
+ if (pcap_stats(pc, &stat) < 0) {
+ (void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pc));
+ }
+ else {
+ (void)fprintf(stderr, "%d packets received by filter\n", stat.ps_recv);
+ (void)fprintf(stderr, "%d packets dropped by kernel\n", stat.ps_drop);
+ }
+
+ pcap_close(pc);
+}
+
diff --git a/network_cmds/ecnprobe/capture.h b/network_cmds/ecnprobe/capture.h
new file mode 100644
index 0000000..9bb83be
--- /dev/null
+++ b/network_cmds/ecnprobe/capture.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#ifndef _CAPTURE_H_
+#define _CAPTURE_H_
+#include <pcap/pcap.h>
+
+struct PacketInfo {
+ struct timeval ts;
+ unsigned int caplen;
+ unsigned int len;
+};
+
+void CaptureInit(u_int32_t sourceIP, u_int16_t sourcePort,
+ u_int32_t targetIP, u_int16_t targetPort, char *dev);
+char *CaptureGetPacket(struct pcap_pkthdr *);
+void CaptureEnd();
+
+#endif /* _CAPTURE_H_ */
diff --git a/network_cmds/ecnprobe/ecn.c b/network_cmds/ecnprobe/ecn.c
new file mode 100644
index 0000000..b7dabdf
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn.c
@@ -0,0 +1,1119 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "history.h"
+#include "ecn.h"
+
+extern struct TcpSession session;
+extern struct History history[];
+
+#define ESTABLISH_SUCCESS 0
+#define ESTABLISH_FAILURE_EARLY_RST 1
+#define ESTABLISH_FAILURE_NO_REPLY 2
+int EstablishTcpConnection(u_int8_t syn_flags, u_int8_t ip_tos)
+{
+ struct IPPacket *synPacket = NULL, *ackPacket = NULL;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ int tcpoptlen = 4; /* For negotiating MSS */
+ u_int8_t *opt = NULL;
+ struct IPPacket *p = NULL;
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ synPacket = AllocateIPPacket(0, tcpoptlen, 0, "ECN (SYN)");
+ opt = (((u_int8_t *)synPacket->tcp) + sizeof(struct TcpHeader));
+ opt[0] = (u_int8_t)TCPOPT_MAXSEG;
+ opt[1] = (u_int8_t)TCPOLEN_MAXSEG;
+ *((u_int16_t *)((u_int8_t *)opt + 2)) = htons(session.mss);
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
+ timeoutTime = GetTime() + 1;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < 3) {
+ while(GetTime() < timeoutTime) {
+ /* Have we captured any packets? */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport,
+ session.dst, session.dport)) {
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totSeenSent++ ;
+ } else {
+ processBadPacket(p);
+ }
+ continue;
+ }
+
+ /* Received a packet from them to us */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport)) {
+ /* Is it a SYN/ACK? */
+ if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK)) {
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+
+ /*
+ * Save ttl for,admittedly poor,indications of reverse
+ * route change
+ */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd ++;
+ break;
+ } else {
+ if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
+ printf ("ERROR: EARLY_RST\n");
+ return(ESTABLISH_FAILURE_EARLY_RST);
+ }
+ }
+ }
+ }
+ }
+
+ if (!synAckReceived) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
+ timeoutTime = GetTime() + 1;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= 3) {
+ printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
+ NO_CONNECTION);
+ return(ESTABLISH_FAILURE_NO_REPLY);
+ }
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("Received SYN-ACK, try to send the third Ack\n");
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("src = %s:%d (%u)\n", InetAddress(session.src),
+ session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n",InetAddress(session.dst),
+ session.dport, session.irs);
+ }
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ ackPacket = AllocateIPPacket(0, 0, 0, "Third ACK");
+ /* send an ACK */
+ SendSessionPacket(ackPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ TCPFLAGS_ACK, 0, 0, 0);
+ FreeIPPacket(&synPacket);
+ FreeIPPacket(&ackPacket);
+ return(ESTABLISH_SUCCESS);
+}
+
+void ECNTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss)
+{
+ int rawSocket, rc, flag = 1;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ /* random initial sequence number */
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime ();
+ session.maxpkts = 1000;
+/* session.debug = SESSION_DEBUG_LOW; */
+ session.debug = 0;
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memmory to store data:\nRETURN CODE: %d",
+ ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Establish a TCP connections with ECN bits */
+ rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
+ switch (rc) {
+ case ESTABLISH_FAILURE_EARLY_RST:
+ {
+ /* Received a RST when ECN bits are used. Try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Received RST with or without ECN negotiation\n");
+ printf("The server might not be listening on this port\n");
+ Quit(EARLY_RST);
+ } else if (rc == ESTABLISH_SUCCESS) {
+ printf("Received RST with ECN.\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Received RST with ECN\n");
+ printf("Exceed max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ }
+ break;
+ }
+ case ESTABLISH_FAILURE_NO_REPLY:
+ {
+ /* No reply after retring, try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Received RST without ECN\n");
+ Quit(NO_CONNECTION);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Exceeded max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ } else {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ }
+ break;
+ }
+ }
+
+ /* Test for propogation of CE correctly */
+ DataPkt(session.filename, 3, 0);
+
+ checkECN();
+ return;
+}
+
+void DataPkt (char *filename, u_int8_t iptos, u_int8_t tcp_flags)
+{
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i ;
+ int sendflag = 1 ;
+ u_int16_t lastSeqSent = session.snd_nxt;
+ double startTime = 0;
+ char *dataptr ;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+
+ datalen = PrepareRequest (data, filename);
+
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr,(void *)data, datalen);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+
+ /* send the data packet
+ * we try to "achieve" reliability by
+ * sending the packet upto 5 times, wating for
+ * 2 seconds between packets
+ * BAD busy-wait loop
+ */
+
+ i = 0 ;
+ while(1) {
+
+ if (sendflag == 1) {
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, iptos);
+
+ startTime = GetTime();
+ sendflag = 0 ;
+ i++ ;
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src, session.sport,
+ session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ SEQ_GT(ntohl(p->tcp->tcp_seq), lastSeqSent) &&
+ SEQ_LEQ(ntohl(p->tcp->tcp_ack), session.rcv_nxt)) {
+ lastSeqSent = ntohl(p->tcp->tcp_seq);
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.snd_nxt += datalen + 1;
+ session.totSeenSent ++ ;
+ continue ;
+ }
+
+ /*
+ * from them?
+ */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport) && (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ SEQ_GT(ntohl(p->tcp->tcp_ack), session.snd_una)) {
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ session.snd_nxt = session.snd_una;
+ if (p->ip->ip_ttl != session.ttl) {
+ session.ttl = p->ip->ip_ttl;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totRcvd ++;
+ break ;
+ }
+ /*
+ * otherwise, this is a bad packet
+ * we must quit
+ */
+ //processBadPacket(p);
+ }
+ if ((GetTime() - startTime >= 1) && (sendflag == 0) && (i < 3)) {
+ sendflag = 1 ;
+ }
+ if (i >= 3) {
+ printf ("ERROR: sent request 3 times without response\n");
+ return;
+ }
+ }
+
+ FreeIPPacket(&datapkt);
+
+ /* process any response by sending Acks */
+ rcvData (ECNAckData);
+}
+
+void ECNAckData (struct IPPacket *p)
+{
+
+ uint32 seq = history[session.hsz - 1].seqno;
+ uint16 datalen = history[session.hsz - 1].dlen;
+ int fin = history[session.hsz - 1].fin;
+ int rst = history[session.hsz - 1].rst;
+ int i;
+ struct IPPacket *ackpkt = NULL;
+ static int ECT_00 = 0;
+ static int ECT_01 = 0;
+ static int ECT_10 = 0;
+ static int ECT_11 = 0;
+ static int ECN_ECHO = 0;
+ static int send_cwr = 0;
+ static int send_ece = 0;
+ uint8 tcp_flags = 0;
+
+
+ /* Legend:
+ * ECN_ECHO: counts packets with TCP header ECN bit set
+ * ECT_XX: counts packets with ECT codepoint XX (IP)
+ */
+
+ if (datalen > session.mss) {
+ printf ("ERROR: mss=%d datalen=%d\nRETURN CODE: %d\n",
+ session.mss, datalen, MSS_ERR);
+ Quit(MSS_ERR);
+ }
+
+ if (datalen > 0) {
+ char *http_code = (char *)calloc(4, sizeof(char));
+ if (seq - session.irs == 1) {
+ /* Response to request packet --> check HTTP response code */
+ memcpy(http_code, ((char *)(p->tcp) + sizeof(struct TcpHeader) +
+ history[session.hsz - 1].optlen + 9), 3);
+ if (strncmp(http_code, HTTP_OK, 3) != 0) {
+ printf("HTTP ERROR - HTTP RESPONSE CODE: %s\nRETURN CODE: %d\n",
+ http_code, atoi(http_code));
+ Quit(atoi(http_code));
+ }
+ }
+
+ session.totDataPktsRcvd++;
+
+ if (session.verbose) {
+ printf ("r %f %d %d\n",
+ GetTime() - session.epochTime,
+ seq - session.irs,
+ seq - session.irs + datalen);
+ }
+
+ }
+
+ /* Check if packet has the ECN_ECHO flag set */
+ if (history[session.hsz - 1].ecn_echo) {
+ ECN_ECHO += 1;
+ }
+
+ if ((p->ip->ip_tos & 0x17) == 0) {
+ ECT_00 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 1) {
+ ECT_01 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 2) {
+ ECT_10 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 3) {
+ ECT_11 += 1;
+ }
+
+ if(session.maxseqseen < seq + datalen - 1) {
+ session.maxseqseen = seq + datalen - 1;
+ } else {
+ if (datalen > 0) {
+ if (reordered(p) != 1) {
+ session.num_unwanted_drops += 1;
+ }
+ }
+ }
+
+ /* from TCP/IP vol. 2, p 808 */
+ if (SEQ_LEQ(session.rcv_nxt, seq) &&
+ SEQ_LT(seq, (session.rcv_nxt + session.rcv_wnd)) &&
+ SEQ_LEQ(session.rcv_nxt, (seq + datalen)) &&
+ SEQ_LT((seq+datalen-1), (session.rcv_nxt + session.rcv_wnd))) {
+ int start, end;
+ start = seq - session.irs ;
+ end = start + datalen ;
+
+ for (i = start ; i < end ; i++) {
+ session.dataRcvd[i] = 1 ;
+ }
+
+ start = session.rcv_nxt - session.irs ;
+ end = session.mss * session.maxpkts ;
+
+ for (i = start ; i < end ; i++) {
+ if (session.dataRcvd[i] == 0) {
+ break ;
+ }
+ session.rcv_nxt++ ;
+ }
+ }
+
+ if (datalen > 0) {
+ if (session.verbose) {
+ printf ("a %f %d\n", GetTime() - session.epochTime,
+ session.rcv_nxt - session.irs);
+ }
+ ackpkt = AllocateIPPacket(0, 0, 0, "NewECN (ACK)");
+ if ((p->ip->ip_tos & 0x17) == 3) {
+ tcp_flags = TCPFLAGS_ACK | TCPFLAGS_ECN_ECHO;
+ } else {
+ tcp_flags = TCPFLAGS_ACK;
+ }
+
+ if (send_cwr == 2 && send_ece < 2) {
+ /* Send ECE as if a CE was received, we have to get CWR back */
+ send_ece = 1;
+ tcp_flags |= TCPFLAGS_ECN_ECHO;
+ }
+
+ SendSessionPacket (ackpkt,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ tcp_flags, 0, 0, 0);
+ }
+
+ if (send_cwr == 0 && (p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
+ /* Send CWR atleast once if ECN ECHO is set */
+ int datalen;
+ struct IPPacket *datapkt;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int ipsz;
+
+ datalen = PrepareRequest(data, NULL);
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr, (void *)data, datalen);
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) +
+ datalen + 1;
+
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | TCPFLAGS_CWR, 0, 0, 2);
+
+ session.snd_nxt += (datalen + 1);
+ send_cwr = 1;
+ FreeIPPacket(&datapkt);
+ }
+
+ if (send_cwr == 1 && !(p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
+ /* ECE was reset in response to CWR, move to the next state of probing */
+ send_cwr = 2;
+ }
+
+ if (send_ece == 1 && (p->tcp->tcp_flags & TCPFLAGS_CWR)) {
+ /* Received CWR in response to ECE */
+ send_ece = 2;
+ }
+
+ if (SEQ_GT(ntohl(p->tcp->tcp_ack), session.snd_una))
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ if (SEQ_LT(session.snd_nxt, session.snd_una))
+ session.snd_nxt = session.snd_una;
+
+ if (fin || rst) {
+ /* Increment sequence number for FIN rcvd */
+ session.rcv_nxt++;
+ if (ECT_01 == 0 && ECT_10 == 0) {
+ printf("Never received ECT(0) or ECT(1) in ToS field: FAIL\n");
+ }
+ if (ECT_11 > 3) {
+ /* If we received more than 3 CE, flag it as an error */
+ printf("Received too many ECT_CE (%d): FAIL\n", ECT_11);
+ }
+ printf ("Totdata = %d ECN_ECHO: %d ECT00: %d ECT01: %d ECT10: %d ECT11: %d drops: %d\n",
+ session.rcv_nxt - session.irs, ECN_ECHO, ECT_00,
+ ECT_01, ECT_10, ECT_11, session.num_unwanted_drops);
+ if (fin) {
+ SendSessionPacket (ackpkt,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ tcp_flags, 0, 0, 0);
+ }
+ checkECN();
+ Quit(SUCCESS);
+ }
+}
+
+void checkECN ()
+{
+ int i;
+ int sr = 0; /* sr=1: SYN/ACK rcvd */
+ int se = 0; /* se=0: no CWR/no ECHO; se=1: no CWR/ECHO; se=2: CWR/ECHO */
+ int ar = 0; /* ar=0: no ACK rcvd; ar=1: ACK rcvd */
+ int ae = 0; /* ae=0: ACK/no ECHO; ae=1: ACK/ECHO */
+ int we = 0; /* we=0: no ECHO; we=1 ECHO/CWR; we=2 ECHO/CWR/ECHO stop */
+ int ee = 0; /* ee=0 never sent ECE; ee=1 sent ECE; ee=2 ECE / CWR */
+
+ for (i = 0 ; i < session.hsz; i++) {
+ if ((history[i].type == RCVD) && (history[i].syn == 1) &&
+ (history[i].ack == 1)) {
+ sr = 1;
+ if (history[i].ecn_echo == 1) {
+ se = 1;
+ if (history[i].cwr == 1) {
+ se = 2;
+ }
+ }
+ }
+ }
+
+ for (i = 0 ; i < session.hsz; i++) {
+ if (history[i].type == RCVD && history[i].syn == 0 &&
+ history[i].ack == 1) {
+ ar = 1;
+ if (history[i].ecn_echo == 1) {
+ ae = 1;
+ }
+ }
+ }
+
+ for (i = 0; i < session.hsz; i++) {
+ if (history[i].type == SENT && history[i].dlen > 0 &&
+ history[i].cwr == 1) {
+ we = 1;
+ continue;
+ }
+ if (we == 1 && history[i].type == RCVD && history[i].ecn_echo == 0) {
+ we = 2;
+ break;
+ }
+ if (we == 2 && history[i].type == RCVD && history[i].ecn_echo == 1) {
+ we = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < session.hsz; i++) {
+ if (history[i].type == SENT && history[i].ecn_echo == 1) {
+ ee = 1;
+ continue;
+ }
+ if (ee == 1 && history[i].type == RCVD && history[i].dlen > 0 &&
+ history[i].cwr == 1) {
+ /* Received cwr in response to ECE */
+ ee = 2;
+ break;
+ }
+ }
+
+ printf ("sr=%d se=%d ar=%d ae=%d we=%d\n", sr, se, ar, ae, we);
+ switch (sr) {
+ case 0:
+ printf("No SYN/ACK received from server\n");
+ break;
+ case 1:
+ printf("SYN/ACK received: PASS \n");
+ break;
+ default:
+ printf("Unknown value for sr: %d\n", sr);
+ break;
+ }
+ switch (se) {
+ case 0:
+ printf("No CWR or ECE on SYN/ACK, server does not support ECN\n");
+ break;
+ case 1:
+ printf("ECE flag set on SYN/ACK, server supports ECN: PASS\n");
+ break;
+ case 2:
+ printf("Both CWR and ECE set on SYN/ACK, incompatible SYN/ACK\n");
+ break;
+ default:
+ printf("Unknown value for se: %d\n", se);
+ break;
+ }
+
+ switch (ar) {
+ case 0:
+ printf("No ACK received\n");
+ break;
+ case 1:
+ printf("ACK received: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ar: %d\n", ar);
+ break;
+ }
+
+ switch (ae) {
+ case 0:
+ printf("Received ACKS but never ECE\n");
+ break;
+ case 1:
+ printf("Received ACKs with ECE, in response to simulated CE bit: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ae: %d\n", ae);
+ break;
+ }
+
+ switch (we) {
+ case 0:
+ printf("Never received ECE\n");
+ break;
+ case 1:
+ printf("Received ECE and sent CWR\n");
+ break;
+ case 2:
+ printf("Received ECE, sent CWR and stopped receiving ECE afterwards: PASS\n");
+ break;
+ default:
+ printf("Unknown value for we: %d\n", we);
+ break;
+ }
+
+ switch (ee) {
+ case 0:
+ printf("Never sent ECE\n");
+ break;
+ case 1:
+ printf("Sent ECE to simulate receiving CE \n");
+ break;
+ case 2:
+ printf("Sent ECE and received CWR in response: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ee: %d\n", ee);
+ break;
+ }
+ return;
+}
+
+void DataPktPathCheck(char *filename, u_int8_t iptos, u_int8_t tcp_flags)
+{
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i ;
+ int sendflag = 1 ;
+ u_int16_t lastSeqSent = session.snd_nxt;
+ double startTime = 0;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+ unsigned int init_ttl;
+
+ datalen = PrepareRequest (data, filename);
+
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr,(void *)data, datalen);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+ /* send the data packet
+ * we try to "achieve" reliability by
+ * sending the packet upto 5 times, wating for
+ * 2 seconds between packets
+ * BAD busy-wait loop
+ */
+
+ i = 0 ;
+ init_ttl = 1;
+ while(1) {
+
+ if (sendflag == 1) {
+ session.curr_ttl = ++init_ttl;
+ if (init_ttl > 64) /* reached the max */
+ break;
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, 0x3);
+
+ startTime = GetTime();
+ sendflag = 0;
+ i++ ;
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src, session.sport,
+ session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ SEQ_GT(ntohl(p->tcp->tcp_seq), lastSeqSent) &&
+ SEQ_LEQ(ntohl(p->tcp->tcp_ack), session.rcv_nxt)) {
+ lastSeqSent = ntohl(p->tcp->tcp_seq);
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.snd_nxt += datalen + 1;
+ session.totSeenSent ++ ;
+ continue ;
+ }
+
+ /*
+ * from them?
+ */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport) && (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ ntohl(p->tcp->tcp_ack) == session.snd_nxt) {
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ session.snd_nxt = session.snd_una;
+ if (p->ip->ip_ttl != session.ttl) {
+ session.ttl = p->ip->ip_ttl;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totRcvd ++;
+ break ;
+ }
+ /*
+ * ICMP ttl exceeded
+ */
+ if (p->ip->ip_p == IPPROTOCOL_ICMP) {
+ uint16_t ip_hl;
+ struct IcmpHeader *icmp;
+ ip_hl = (p->ip->ip_vhl & 0x0f) << 2;
+ void *nexthdr;
+
+ icmp = (struct IcmpHeader *)((char *)p->ip + ip_hl);
+ nexthdr = (void *)icmp;
+ if (icmp->icmp_type == ICMP_TIMXCEED) {
+ struct IpHeader off_ip;
+ struct TcpHeader off_tcp;
+
+ bzero(&off_ip, sizeof(struct IpHeader));
+ nexthdr = nexthdr + sizeof(struct IcmpHeader);
+ memcpy((void *)&off_ip, nexthdr,
+ sizeof(struct IpHeader));
+ nexthdr += sizeof(struct IpHeader);
+
+ bzero(&off_tcp, sizeof(struct TcpHeader));
+ memcpy(&off_tcp, nexthdr, 4);
+ if (session.src == off_ip.ip_src &&
+ session.dst == off_ip.ip_dst) {
+ printf("Received ICMP TTL exceeded from %s:"
+ "ttl used %u ip_tos 0x%x sport %u dport %u\n",
+ InetAddress(p->ip->ip_src), init_ttl, off_ip.ip_tos,
+ ntohs(off_tcp.tcp_sport), ntohs(off_tcp.tcp_dport));
+ }
+ }
+ }
+ /*
+ * otherwise, this is a bad packet
+ * we must quit
+ */
+ //processBadPacket(p);
+ }
+ if ((GetTime() - startTime >= 1) && (sendflag == 0)) {
+ sendflag = 1;
+ session.snd_nxt = session.snd_una;
+ }
+ }
+
+ FreeIPPacket(&datapkt);
+}
+void ECNPathCheckTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss)
+{
+ int rawSocket, rc, flag;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime();
+ session.maxpkts = 1000;
+ session.debug = 0;
+
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memory to store data, error: %d \n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ flag = 1;
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Establish a TCP connections with ECN bits */
+ rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
+ switch (rc) {
+ case ESTABLISH_FAILURE_EARLY_RST:
+ {
+ /* Received a RST when ECN bits are used. Try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Received RST with or without ECN negotiation\n");
+ printf("The server might not be listening on this port\n");
+ Quit(EARLY_RST);
+ } else if (rc == ESTABLISH_SUCCESS) {
+ printf("Received RST with ECN.\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Received RST with ECN\n");
+ printf("Exceed max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ }
+ break;
+ }
+ case ESTABLISH_FAILURE_NO_REPLY:
+ {
+ /* No reply after retring, try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Received RST without ECN\n");
+ Quit(NO_CONNECTION);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Exceeded max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ } else {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ }
+ break;
+ }
+ }
+
+ DataPktPathCheck(session.filename, 3, 0);
+ return;
+}
+
+
+void
+SynTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss, int syn_reply)
+{
+ int rawSocket, flag;
+ struct IPPacket *synPacket = NULL, *ackPacket = NULL;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ int tcpoptlen = 4; /* For negotiating MSS */
+ u_int8_t *opt = NULL;
+ struct IPPacket *p = NULL;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime();
+ session.maxpkts = 1000;
+
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memory to store data, error: %d \n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ flag = 1;
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ synPacket = AllocateIPPacket(0, tcpoptlen, 0, "ECN (SYN)");
+ opt = (((u_int8_t *)synPacket->tcp) + sizeof(struct TcpHeader));
+ opt[0] = (u_int8_t)TCPOPT_MAXSEG;
+ opt[1] = (u_int8_t)TCPOLEN_MAXSEG;
+ *((u_int16_t *)((u_int8_t *)opt + 2)) = htons(session.mss);
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN , 0, tcpoptlen, 0);
+ timeoutTime = GetTime() + 1;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < 3) {
+ while(GetTime() < timeoutTime) {
+ /* Have we captured any packets? */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport,
+ session.dst, session.dport)) {
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totSeenSent++ ;
+ } else {
+ processBadPacket(p);
+ }
+ continue;
+ }
+
+ /* Received a packet from them to us */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport)) {
+ /* Is it a SYN/ACK? */
+ if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK)) {
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+
+ /*
+ * Save ttl for,admittedly poor,indications of reverse
+ * route change
+ */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd ++;
+ break;
+ } else {
+ if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
+ printf ("ERROR: EARLY_RST\n");
+ goto done;
+ }
+ }
+ }
+ }
+ }
+
+ if (!synAckReceived) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN , 0, tcpoptlen, 0);
+ timeoutTime = GetTime() + 1;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= 3) {
+ printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
+ NO_CONNECTION);
+ goto done;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("Received SYN-ACK\n");
+ if (syn_reply != 0) {
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("try to send the %s\n", syn_reply == TCPFLAGS_ACK ? "third Ack" : "RST");
+ printf("src = %s:%d (%u)\n", InetAddress(session.src),
+ session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n",InetAddress(session.dst),
+ session.dport, session.irs);
+ }
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ ackPacket = AllocateIPPacket(0, 0, 0, "SYN reply");
+ /* send an ACK */
+ SendSessionPacket(ackPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ syn_reply, 0, 0, 0);
+ FreeIPPacket(&ackPacket);
+ }
+done:
+ FreeIPPacket(&synPacket);
+}
diff --git a/network_cmds/ecnprobe/ecn.h b/network_cmds/ecnprobe/ecn.h
new file mode 100644
index 0000000..5ac582c
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+void ECNTest (u_int32_t sourceIpAddress, u_int16_t sourcePort, u_int32_t targetIpAddress, u_int16_t targetPort, int mss) ;
+void ECNAckData (struct IPPacket *p);
+void DataPkt (char *filename, u_int8_t iptos, u_int8_t tcp_flags);
+void checkECN ();
+void ECNPathCheckTest(u_int32_t sourceIpAddress, u_int16_t surcePort,
+ u_int32_t targetIpAddress, u_int16_t targetPort, int mss);
+void SynTest(u_int32_t sourceIpAddress, u_int16_t surcePort, u_int32_t targetIpAddress, u_int16_t targetPort, int mss, int syn_reply);
diff --git a/network_cmds/ecnprobe/ecn_probe.c b/network_cmds/ecnprobe/ecn_probe.c
new file mode 100644
index 0000000..362ff4f
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn_probe.c
@@ -0,0 +1,469 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <spawn.h>
+#include <ifaddrs.h>
+#include "inet.h"
+#include "capture.h"
+#include "support.h"
+#include "session.h"
+#include "ecn.h"
+#include "history.h"
+
+extern struct TcpSession session;
+
+void usage (char *name);
+int GetCannonicalInfo(char *string, size_t str_size, u_int32_t *address);
+int BindTcpPort(int sockfd) ;
+
+void usage(char *name)
+{
+ printf("%s [options]\n", name);
+ printf("\t-n <target hostname | ipaddress>\n");
+ printf("\t-p <target port>\n");
+ printf("\t-m <mss>\n");
+ printf("\t-M <mtu>\n");
+ printf("\t-w <sourcePort>\n");
+ printf("\t-s <source hostname or ip address>\n");
+ printf("\t-f <file-name to get>\n");
+ printf("\t-d <interface name>\n");
+ printf("\t-C for CE path check\n");
+ printf("\t-S [A|R|X] SYN followed by ACK or RST or nothing\n");
+ printf("\t-F [set|clear|skip] how to handle firewall rules\n");
+ return;
+}
+
+void SetupFirewall(u_int32_t targetIP, u_int16_t port, char *dev)
+{
+ char pfcmd[512];
+ char *pf_file_name = "/tmp/pf.conf";
+ int pf_fd = 0, rc;
+ ssize_t bytes;
+ char *args[4];
+
+ bzero(pfcmd, sizeof(pfcmd));
+
+ bzero(args, sizeof(args));
+ sprintf(pfcmd, "block in quick on %s inet proto tcp from %s port %u\n",
+ dev, InetAddress(targetIP), port);
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("PF rule: %s\n", pfcmd);
+
+ pf_fd = open(pf_file_name, O_RDWR|O_TRUNC|O_CREAT);
+ if (pf_fd < 0) {
+ perror("failed to open pf file");
+ exit(1);
+ }
+ bytes = write(pf_fd, pfcmd, strlen(pfcmd) + 1);
+ close(pf_fd);
+ args[0] = "pfctl";
+ args[1] = "-d";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -d: %d\n", rc);
+ Quit(FAIL);
+ }
+
+ args[1] = "-f";
+ args[2] = pf_file_name;
+ args[3] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -f /tmp/pf.conf: %d\n", rc);
+ Quit(FAIL);
+ }
+
+ args[1] = "-e";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -e: %d\n", rc);
+ Quit(FAIL);
+ }
+}
+
+void CleanupFirewall()
+{
+ char * args[3];
+ int rc;
+
+ args[0] = "pfctl";
+ args[1] = "-d";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -d: %d\n", rc);
+ Quit(FAIL);
+ }
+}
+
+void Cleanup()
+{
+ if (session.initSession > 0) {
+ shutdown(session.socket, 2);
+ }
+ if (session.initCapture > 0) {
+ CaptureEnd();
+ }
+ if (session.initFirewall > 0) {
+ CleanupFirewall();
+ }
+}
+
+void Quit(int how)
+{
+ SendReset();
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(how);
+}
+
+void SigHandle(int signo)
+{
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(-1);
+}
+
+int GetCannonicalInfo(char *string, size_t str_size, u_int32_t *address)
+{
+ struct hostent *hp;
+ /* Is string in dotted decimal format? */
+ if ((*address = inet_addr(string)) == INADDR_NONE) {
+ /* No, then lookup IP address */
+ if ((hp = gethostbyname(string)) == NULL) {
+ /* Can't find IP address */
+ printf("ERROR: Couldn't obtain address for %s\n"
+ "RETURN CODE: %d\n", string, FAIL);
+ return(-1);
+ } else {
+ strlcpy(string, hp->h_name, str_size);
+ memcpy((void *)address, (void *)hp->h_addr,
+ hp->h_length);
+ }
+ } else {
+ if ((hp = gethostbyaddr((char *)address, sizeof(*address),
+ AF_INET)) == NULL) {
+ /*
+ * Can't get cannonical hostname, so just use
+ * input string
+ */
+ if (session.debug) {
+ printf("WARNING: Couldn't obtain cannonical"
+ " name for %s\nRETURN CODE: %d",
+ string, NO_SRC_CANON_INFO);
+ }
+ /* strlcpy(name, string, MAXHOSTNAMELEN);*/
+ } else {
+ /* strlcpy(name, hp->h_name, MAXHOSTNAMELEN);*/
+ }
+ }
+ return(0);
+}
+
+int BindTcpPort(int sockfd)
+{
+ struct sockaddr_in sockName;
+ int port, result;
+ int randomOffset;
+
+#define START_PORT (50*1024)
+#define END_PORT (0xFFFF)
+
+ /*
+ * Choose random offset to reduce likelihood of
+ * collision with last run
+ */
+ randomOffset = (int)(1000.0*drand48());
+
+ /* Try to find a free port in the range START_PORT+1..END_PORT */
+ port = START_PORT+randomOffset;
+ do {
+ ++port;
+ sockName.sin_addr.s_addr = INADDR_ANY;
+ sockName.sin_family = AF_INET;
+ sockName.sin_port = 0; //htons(port);
+ result = bind(sockfd, (struct sockaddr *)&sockName,
+ sizeof(sockName));
+ } while ((result < 0) && (port < END_PORT));
+
+
+ if (result < 0) {
+ /* No free ports */
+ perror("bind");
+ port = 0;
+ } else {
+ socklen_t len = sizeof(sockName);
+ result = getsockname(sockfd, (struct sockaddr *)&sockName, &len);
+ if (result < 0) {
+ perror("getsockname");
+ port = 0;
+ } else {
+ port = ntohs(sockName.sin_port);
+ }
+ }
+ return port;
+
+}
+
+#define FIREWALL_DEFAULT 0
+#define FIREWALL_SET_ONLY 1
+#define FIREWALL_CLEAR_ONLY 2
+#define FIREWALL_SKIP 3
+
+int main(int argc, char **argv)
+{
+ u_int32_t targetIpAddress = 0;
+ u_int16_t targetPort = DEFAULT_TARGETPORT;
+ u_int16_t sourcePort = 0;
+ u_int32_t sourceIpAddress = 0;
+ int mss = DEFAULT_MSS;
+ int mtu = DEFAULT_MTU;
+ int fd, opt, usedev = 0, rc = 0, path_check = 0;
+ int syn_test = 0, syn_reply = 0;
+ struct sockaddr_in saddr;
+ char dev[11]; /* device name for pcap init */
+ struct ifaddrs *ifap, *tmp;
+ int firewall_mode = FIREWALL_DEFAULT;
+
+ bzero(&session, sizeof(session));
+ while ((opt = getopt(argc, argv, "n:p:w:m:M:s:d:f:-CS:vF:")) != -1) {
+ switch (opt) {
+ case 'n':
+ if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
+ printf("Target host name too long, max %u chars\n", MAXHOSTNAMELEN);
+ Quit(FAIL);
+ }
+ strlcpy(session.targetHostName, optarg,
+ sizeof(session.targetHostName));
+ strlcpy(session.targetName, session.targetHostName,
+ sizeof(session.targetName));
+ break;
+ case 'p':
+ targetPort = atoi(optarg);
+ break;
+ case 'm':
+ mss = atoi(optarg);
+ break;
+ case 'M':
+ mtu = atoi(optarg);
+ break;
+ case 'w':
+ sourcePort = atoi(optarg);
+ break;
+ case 's':
+ if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
+ printf("Source host name too long, max %u chars\n", MAXHOSTNAMELEN);
+ Quit(FAIL);
+ }
+ strlcpy(session.sourceHostName, optarg,
+ MAXHOSTNAMELEN);
+ break;
+ case 'd':
+ if (strlen(optarg) > (sizeof(dev) - 1)) {
+ printf("Interface nae is too large, max %lu chars\n", (sizeof(dev) - 1));
+ Quit(FAIL);
+ }
+ bzero(dev, sizeof(dev));
+ strlcpy(dev, optarg, sizeof(dev));
+ usedev = 1;
+ break;
+ case 'f':
+ if (strlen(optarg) > 0) {
+ session.filename = strndup(optarg, strlen(optarg) + 1);
+ } else {
+ printf("Invalid file name \n");
+ }
+ break;
+ case 'F':
+ if (strcasecmp(optarg, "default") == 0)
+ firewall_mode = FIREWALL_DEFAULT;
+ else if (strcasecmp(optarg, "set") == 0)
+ firewall_mode = FIREWALL_SET_ONLY;
+ else if (strcasecmp(optarg, "clear") == 0)
+ firewall_mode = FIREWALL_CLEAR_ONLY;
+ else if (strcasecmp(optarg, "skip") == 0)
+ firewall_mode = FIREWALL_SKIP;
+ else
+ printf("firewall mode\n");
+ break;
+ case 'C':
+ path_check = 1;
+ break;
+ case 'S':
+ syn_test = 1;
+ if (strcasecmp(optarg, "A") == 0)
+ syn_reply = TCPFLAGS_ACK;
+ else if (strcasecmp(optarg, "R") == 0)
+ syn_reply = TCPFLAGS_RST;
+ else if (strcasecmp(optarg, "X") == 0)
+ syn_reply = 0;
+ else
+ printf("Invalid SYN reply \n");
+ break;
+ case 'v':
+ session.debug++;
+ break;
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+ signal(SIGTERM, SigHandle);
+ signal(SIGINT, SigHandle);
+ signal(SIGHUP, SigHandle);
+
+ if (GetCannonicalInfo(session.targetHostName, sizeof(session.targetHostName),
+ &targetIpAddress) < 0)
+ {
+ printf("Failed to convert targetIP address\n");
+ Quit(NO_TARGET_CANON_INFO);
+ }
+ rc = getifaddrs(&ifap);
+ if (rc != 0 || ifap == NULL) {
+ printf("Failed to get source addresswith getifaddrs: %d\n", rc);
+ Quit(FAIL);
+ }
+ tmp = ifap;
+ sourceIpAddress = 0;
+ bzero(session.sourceHostName, MAXHOSTNAMELEN);
+ for (tmp = ifap; tmp != NULL; tmp = tmp->ifa_next) {
+ struct sockaddr_in *sin;
+ if (tmp->ifa_addr == NULL)
+ continue;
+ if (tmp->ifa_addr->sa_family != PF_INET)
+ continue;
+ if (usedev == 1) {
+ /* we know which interface to use */
+ if (strcmp(dev, tmp->ifa_name) == 0) {
+ sin = (struct sockaddr_in *)tmp->ifa_addr;
+ sourceIpAddress = sin->sin_addr.s_addr;
+ strlcpy(session.sourceHostName,
+ inet_ntoa(sin->sin_addr),
+ sizeof(session.sourceHostName));
+ } else {
+ continue;
+ }
+ } else {
+ /* pick the first address */
+ bzero(dev, sizeof(dev));
+ sin = (struct sockaddr_in *)tmp->ifa_addr;
+ sourceIpAddress = sin->sin_addr.s_addr;
+ strlcpy(session.sourceHostName,
+ inet_ntoa(sin->sin_addr),
+ sizeof(session.sourceHostName));
+ strlcpy(dev, tmp->ifa_name, sizeof(dev));
+ }
+ }
+ freeifaddrs(ifap);
+ if (sourceIpAddress == 0) {
+ printf("Failed to get source Ip address\n");
+ Quit(FAIL);
+ }
+
+ if (sourcePort == 0) {
+ bzero(&saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Can't open socket\n");
+ return (-1);
+ }
+ if ((sourcePort = BindTcpPort(fd)) == 0) {
+ printf("Can't bind to port\n");
+ return (-1);
+ }
+ }
+ printf("Source: %s:%d\n", session.sourceHostName, sourcePort);
+ printf("Destination: %s:%d\n", session.targetHostName, targetPort);
+
+ switch (firewall_mode) {
+ case FIREWALL_DEFAULT:
+ SetupFirewall(targetIpAddress, targetPort, dev);
+ session.initFirewall = 1;
+ break;
+ case FIREWALL_SET_ONLY:
+ SetupFirewall(targetIpAddress, targetPort, dev);
+ goto done;
+ case FIREWALL_CLEAR_ONLY:
+ session.initFirewall = 1;
+ goto done;
+ case FIREWALL_SKIP:
+ break;
+ }
+
+ CaptureInit(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, dev);
+ session.initCapture = 1;
+
+
+ printf("Starting ECN test\n");
+ if (syn_test) {
+ session.dont_send_reset = 1;
+ SynTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss, syn_reply);
+ } else if (path_check) {
+ ECNPathCheckTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss);
+ } else {
+ ECNTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss);
+ }
+done:
+ Quit(SUCCESS);
+ close(session.socket);
+ return (0);
+}
diff --git a/network_cmds/ecnprobe/ecnprobe.1 b/network_cmds/ecnprobe/ecnprobe.1
new file mode 100644
index 0000000..76c2173
--- /dev/null
+++ b/network_cmds/ecnprobe/ecnprobe.1
@@ -0,0 +1,20 @@
+.Dd 5/7/2015
+.Dt ecnprobe 1
+.Os Darwin
+.Sh NAME
+.Nm ecnprobe
+.Nd Tool to probe for TCP ECN related incompatibilities in the network
+.Sh SYNOPSIS
+.Nm
+.Op Fl n Ar target hostname or ipaddress
+.Op Fl p Ar target port
+.Op Fl m Ar mss
+.Op Fl M Ar mtu
+.Op Fl w Ar source port
+.Op Fl s Ar source ip address
+.Op Fl f Ar file name to get
+.Op Fl d Ar interface name
+.Sh DESCRIPTION
+The
+.Nm
+utility can be used to test TCP ECN related incompatibilities in the network.
diff --git a/network_cmds/ecnprobe/gmt2local.c b/network_cmds/ecnprobe/gmt2local.c
new file mode 100644
index 0000000..a6114f3
--- /dev/null
+++ b/network_cmds/ecnprobe/gmt2local.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "gmt2local.h"
+
+/*
+ * Returns the difference between gmt and local time in seconds.
+ * Use gmtime() and localtime() to keep things simple.
+ */
+int32_t
+gmt2local(time_t t)
+{
+ register int dt, dir;
+ register struct tm *gmt, *loc;
+ struct tm sgmt;
+
+ if (t == 0)
+ t = time(NULL);
+ gmt = &sgmt;
+ *gmt = *gmtime(&t);
+ loc = localtime(&t);
+ dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
+ (loc->tm_min - gmt->tm_min) * 60;
+
+ /*
+ * If the year or julian day is different, we span 00:00 GMT
+ * and must add or subtract a day. Check the year first to
+ * avoid problems when the julian day wraps.
+ */
+ dir = loc->tm_year - gmt->tm_year;
+ if (dir == 0)
+ dir = loc->tm_yday - gmt->tm_yday;
+ dt += dir * 24 * 60 * 60;
+
+ return (dt);
+}
diff --git a/network_cmds/ecnprobe/gmt2local.h b/network_cmds/ecnprobe/gmt2local.h
new file mode 100644
index 0000000..4933b09
--- /dev/null
+++ b/network_cmds/ecnprobe/gmt2local.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: gmt2local.h,v 1.2 97/01/23 22:31:40 leres Exp $ (LBL)
+ */
+#ifndef gmt2local_h
+#define gmt2local_h
+
+int32_t gmt2local(time_t);
+#endif
diff --git a/network_cmds/ecnprobe/history.c b/network_cmds/ecnprobe/history.c
new file mode 100644
index 0000000..e19b0ba
--- /dev/null
+++ b/network_cmds/ecnprobe/history.c
@@ -0,0 +1,211 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "support.h"
+#include "history.h"
+
+extern struct TcpSession session;
+struct History history[MAXHSZ];
+
+void StorePacket (struct IPPacket *p) {
+
+ uint32 src, dst, seq, ack ;
+ uint16 sport, dport, win, urp, datalen, optlen;
+ uint16 ip_optlen;
+ uint8 flags;
+
+ ReadIPPacket(p,
+ &src, &dst,
+ &sport, &dport,
+ &seq,
+ &ack,
+ &flags,
+ &win,
+ &urp,
+ &datalen,
+ &ip_optlen,
+ &optlen);
+
+ if (src == session.src) {
+ history[session.hsz].type = SENT;
+ } else {
+ history[session.hsz].type = RCVD ;
+ }
+
+ history[session.hsz].timestamp = GetTime () - session.epochTime;
+ history[session.hsz].seqno = seq;
+ history[session.hsz].nextbyte = seq + datalen;
+ history[session.hsz].ackno = ack ;
+ history[session.hsz].fin = (flags & TCPFLAGS_FIN) ? 1 : 0;
+ history[session.hsz].syn = (flags & TCPFLAGS_SYN) ? 1 : 0;
+ history[session.hsz].rst = (flags & TCPFLAGS_RST) ? 1 : 0;
+ history[session.hsz].psh = (flags & TCPFLAGS_PSH) ? 1 : 0;
+ history[session.hsz].ack = (flags & TCPFLAGS_ACK) ? 1 : 0;
+ history[session.hsz].urg = (flags & TCPFLAGS_URG) ? 1 : 0;
+ history[session.hsz].ecn_echo = (flags & TCPFLAGS_ECN_ECHO) ? 1:0;
+ history[session.hsz].cwr = (flags & TCPFLAGS_CWR) ? 1 : 0;
+ history[session.hsz].ip_optlen = ip_optlen;
+ history[session.hsz].optlen = optlen ;
+
+ /* Grab IP Options from Ip Header - New */
+ if (ip_optlen > 0) {
+ if ((history[session.hsz].ip_opt = calloc(sizeof(uint8), ip_optlen)) == NULL) {
+ printf("StorePacket Error: Could not allocate history memory\nRETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit (ERR_MEM_ALLOC);
+ }
+ memcpy(history[session.hsz].ip_opt, (char *)p->ip + sizeof(struct IpHeader), ip_optlen);
+ }
+
+
+ /* Grab TCP options from TCP Header */
+ if (optlen > 0) {
+ if ((history[session.hsz].opt = calloc(sizeof(uint8), optlen)) == NULL) {
+ Quit (ERR_MEM_ALLOC);
+ }
+
+ memcpy(history[session.hsz].opt, (char *)p->tcp + sizeof(struct TcpHeader), optlen);
+ }
+
+ history[session.hsz].dlen = datalen;
+
+ if ((history[session.hsz].data = calloc(sizeof(uint8), datalen)) == NULL) {
+ Quit (ERR_MEM_ALLOC);
+ }
+
+ /* Copy data bytes */
+ memcpy(history[session.hsz].data,
+ (char *)p->tcp + sizeof(struct TcpHeader) + optlen,
+ datalen);
+
+ session.hsz++;
+
+ if (session.hsz >= MAXHSZ) {
+ Quit(TOO_MANY_PKTS);
+ }
+
+}
+
+int reordered(struct IPPacket *p) {
+
+ int i;
+ int count = 0;
+ double ts = -99999;
+
+ /*
+ * This might be either an unwanted packet drop, or just a reordering.
+ * Test:
+ * If we have not sent three acks for this packet
+ * AND the gap between this packet and previous one is "small" (i.e. not a timeout)
+ * then its a reordering, and not a retransmission.
+ */
+
+ /* count the number of (dup) ACKs sent */
+ for (i = 0; i < session.hsz; i++) {
+ if ((history[i].type == SENT) &&
+ (history[i].ack)) {
+ if (history[i].ackno == history[session.hsz - 1].seqno)
+ count += 1;
+ }
+ }
+
+ if (count > 0) {
+
+ session.num_dup_acks += count - 1;
+
+ switch (count) {
+ case 1: /* no dup acks */
+ session.num_pkts_0_dup_acks += 1;
+ break;
+
+ case 2: /* 1 dup acks */
+ session.num_pkts_1_dup_acks += 1;
+ break;
+
+ case 3: /* 2 dup acks */
+ session.num_pkts_2_dup_acks += 1;
+ break;
+
+ case 4: /* 3 dup acks */
+ session.num_pkts_3_dup_acks += 1;
+ break;
+
+ default:
+ session.num_pkts_4_or_more_dup_acks += 1;
+ break;
+ }
+ }
+
+ /* 3 dup acks? => Fast retransmission */
+ if (count > 3) {
+ printf("Fast retransmit...\n");
+ return 3;
+ }
+
+ /* Compute elapsed time between this packet and the previously RCVD packet */
+ for (i = (session.hsz - 2); i >= 0; i--) {
+ if ((history[i].type == RCVD) && (history[i].dlen > 0)) {
+ ts = history[i].timestamp;
+ break;
+ }
+ }
+
+ if ((history[session.hsz - 1].timestamp - ts) > RTT_TO_MULT * (session.rtt + PLOTDIFF)) {
+ printf ("RTO ===> %f %f\n", history[session.hsz - 1].timestamp, ts);
+ return 2;
+ }
+
+ printf ("#### Acks %d\n", count);
+ printf ("#### reordering detected\n");
+ session.num_reordered++;
+
+ return 1;
+
+}
diff --git a/network_cmds/ecnprobe/history.h b/network_cmds/ecnprobe/history.h
new file mode 100644
index 0000000..9e69d44
--- /dev/null
+++ b/network_cmds/ecnprobe/history.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 SENT 1
+#define RCVD 2
+#define MAXHSZ 10000
+
+struct History { /* store history of each packet as it is seen */
+
+ int type ; /* sent or received */
+ double timestamp; /* when */
+ uint32 seqno;
+ uint32 nextbyte; /* seqno + dlen */
+ uint32 ackno;
+ int hlen;
+ int ecn_echo;
+ int cwr;
+ int urg;
+ int ack;
+ int psh;
+ int rst;
+ int syn;
+ int fin;
+ int ip_optlen; /* added to support IP options */
+ uint8 *ip_opt; /* added to support IP options */
+ int optlen;
+ uint8 *opt;
+ uint8 *data;
+ int dlen;
+
+ int pkt_num;
+
+};
+
+void StorePacket (struct IPPacket *p);
+int reordered (struct IPPacket *p);
diff --git a/network_cmds/ecnprobe/inet.c b/network_cmds/ecnprobe/inet.c
new file mode 100644
index 0000000..b145412
--- /dev/null
+++ b/network_cmds/ecnprobe/inet.c
@@ -0,0 +1,503 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "history.h"
+
+extern struct TcpSession session;
+extern struct History history[];
+
+/*
+ * Deal with struct in_addr type agreement once and for all
+ */
+char *InetAddress(uint32 addr)
+{
+
+ struct in_addr s;
+ s.s_addr = addr;
+
+ //printf("In InetAddress:\n");
+ //printf("addr = %s (%0x)\n", inet_ntoa(s), addr);
+
+ return (inet_ntoa(s));
+}
+
+/*
+ * Really slow implementation of ip checksum
+ * ripped off from rfc1071
+ */
+
+uint16 InetChecksum(uint16 *ip, uint16 *tcp, uint16 ip_len, uint16 tcp_len) {
+
+ uint32 sum = 0;
+
+ uint32 ip_count = ip_len;
+ uint32 tcp_count = tcp_len;
+ uint16 *ip_addr = ip;
+ uint16 *tcp_addr = tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In InetChecksum...\n");
+ printf("iplen: %d, tcplen: %d\n", ip_len, tcp_len);
+ }
+
+
+ while(ip_count > 1) {
+ //printf("ip[%d]: %x\n", ip_len - ip_count, htons(*ip_addr));
+ sum += *ip_addr++;
+ ip_count -= 2;
+ }
+
+ while(tcp_count > 1) {
+ //printf("tcp[%d]: %x\n", tcp_len - tcp_count, htons(*tcp_addr));
+ sum += *tcp_addr++;
+ tcp_count -= 2;
+ }
+
+ if(ip_count > 0) {
+ sum += *(uint8 *)ip_addr;
+ }
+
+ if(tcp_count > 0) {
+ sum += *(uint8 *)tcp_addr;
+ }
+
+ while (sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out InetChecksum...\n");
+ }
+
+ return(~sum);
+
+}
+
+
+void WriteIPPacket(struct IPPacket *p,
+ uint32 src,
+ uint32 dst,
+ uint16 sport,
+ uint16 dport,
+ uint32 seq,
+ uint32 ack,
+ uint8 flags,
+ uint16 win,
+ uint16 urp,
+ uint16 datalen,
+ uint16 ip_optlen,
+ uint16 optlen,
+ uint8 iptos,
+ uint8 u4tf)
+{
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In WriteIPPacket...\n");
+ }
+
+ /* Zero out IpHeader to ensure proper checksum computation */
+ bzero((char *)(p->ip), sizeof(struct IpHeader));
+
+ ip->ip_src = src;
+ ip->ip_dst = dst;
+ ip->ip_p = IPPROTOCOL_TCP;
+ ip->ip_xsum =
+ htons((uint16)(sizeof(struct TcpHeader) + datalen + optlen)); /* pseudo hdr */
+
+ tcp->tcp_sport = htons(sport);
+ tcp->tcp_dport = htons(dport);
+ tcp->tcp_seq = htonl(seq);
+ tcp->tcp_ack = htonl(ack);
+ tcp->tcp_hl = (sizeof(struct TcpHeader) + optlen) << 2;
+ tcp->tcp_hl = tcp->tcp_hl | u4tf;
+ tcp->tcp_flags = flags;
+
+ tcp->tcp_win = htons(win);
+ tcp->tcp_urp = htons(urp);
+
+ tcp->tcp_xsum = 0;
+ tcp->tcp_xsum = InetChecksum((uint16 *)ip, (uint16 *)tcp,
+ (uint16)sizeof(struct IpHeader), /* IP Options should aren't included */
+ (uint16)(sizeof(struct TcpHeader) + datalen + optlen));
+
+ /* Fill in real ip header */
+ if (session.curr_ttl != 0) {
+ ip->ip_ttl = session.curr_ttl;
+ }else {
+ ip->ip_ttl = 60;
+ }
+
+ //printf("TTL: %d\n", ip->ip_ttl);
+
+ ip->ip_tos = iptos;
+
+ /* IP Version and Header len field */
+ ip->ip_vhl = 0x40 + 0x5 + (int)(ip_optlen/4);
+ ip->ip_p = IPPROTOCOL_TCP;
+
+ ip->ip_off = IP_DF;
+ ip->ip_len = (uint16)(sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen + datalen);
+
+ ip->ip_xsum = 0;
+ ip->ip_xsum = InetChecksum((uint16 *)ip, NULL,
+ (uint16)sizeof(struct IpHeader) + ip_optlen, /* IP Options should aren't included */
+ 0);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out WriteIPPacket...\n");
+ }
+
+}
+
+void ReadIPPacket(struct IPPacket *p,
+ uint32 *src,
+ uint32 *dst,
+ uint16 *sport,
+ uint16 *dport,
+ uint32 *seq,
+ uint32 *ack,
+ uint8 *flags,
+ uint16 *win,
+ uint16 *urp,
+ uint16 *datalen,
+ uint16 *ip_optlen,
+ uint16 *optlen)
+{
+
+ /* TODO: Add reading of IP options, if any */
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ uint16 ip_len;
+ uint16 ip_hl;
+ uint16 tcp_hl;
+
+ /* XXX do checksum check? */
+ if (ip->ip_p != IPPROTOCOL_TCP && ip->ip_p != IPPROTOCOL_ICMP) {
+ printf("Unexpected protocol packet: %u\n", ip->ip_p);
+ Quit(ERR_CHECKSUM);
+ }
+
+ *src = ip->ip_src;
+ *dst = ip->ip_dst;
+ *sport = ntohs(tcp->tcp_sport);
+ *dport = ntohs(tcp->tcp_dport);
+ *seq = ntohl(tcp->tcp_seq);
+ *ack = ntohl(tcp->tcp_ack);
+ *flags = tcp->tcp_flags;
+ *win = ntohs(tcp->tcp_win);
+ *urp = ntohs(tcp->tcp_urp);
+
+ tcp_hl = tcp->tcp_hl >> 2;
+ ip_len = ntohs(ip->ip_len);
+ ip_hl = (ip->ip_vhl & 0x0f) << 2;
+ *datalen = (ip_len - ip_hl) - tcp_hl;
+ *ip_optlen = ip_hl - (unsigned int)sizeof(struct IpHeader); /* added to support IP Options */
+ *optlen = tcp_hl - (unsigned int)sizeof(struct TcpHeader);
+
+}
+
+void PrintICMPUnreachableErrorPacket(struct ICMPUnreachableErrorPacket *p)
+{
+
+ struct IpHeader *ip = &p->ip;
+ struct IcmpHeader *icmp = &p->icmp;
+ struct IpHeader *off_ip = &p->off_ip;
+
+ printf("IPHdr: ");
+ printf("%s > ", InetAddress(ip->ip_src));
+ printf("%s ", InetAddress(ip->ip_dst));
+ printf(" datalen: %u\n", ip->ip_len);
+ printf("ICMPHdr: ");
+ printf("Type: %u Code: %u MTU next hop: %u xsum: %x\n",
+ icmp->icmp_type,
+ icmp->icmp_code,
+ ntohs(icmp->icmp_mtu),
+ icmp->icmp_xsum);
+ printf("Off IPHdr: ");
+ printf("%s > ", InetAddress(off_ip->ip_src));
+ printf("%s ", InetAddress(off_ip->ip_dst));
+ printf(" datalen: %u ", off_ip->ip_len);
+ printf("tcp sport: %u ", ntohs(p->tcp_sport));
+ printf("tcp dport: %u ", ntohs(p->tcp_dport));
+ printf("tcp seqno: %u\n", (uint32)ntohl(p->tcp_seqno));
+
+}
+
+void PrintTcpPacket(struct IPPacket *p)
+{
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ char *opt;
+ int optlen;
+ char *ip_opt;
+ int ip_optlen;
+ int i;
+
+ printf("%s.%u > ", InetAddress(ip->ip_src), ntohs(tcp->tcp_sport));
+ printf("%s.%u ", InetAddress(ip->ip_dst), ntohs(tcp->tcp_dport));
+
+ if (tcp->tcp_flags & TCPFLAGS_SYN) {
+ printf("S");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_ACK) {
+ printf("A");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_FIN) {
+ printf("F");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_ECN_ECHO) {
+ printf("E");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_CWR) {
+ printf("W");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_RST) {
+ printf("R");
+ }
+ if (tcp->tcp_flags & TCPFLAGS_PSH) {
+ printf("P");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_URG) {
+ printf("U");
+ }
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport)) {
+ printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.iss, (uint32)ntohl(tcp->tcp_ack) - session.irs);
+ } else {
+ printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.irs, (uint32)ntohl(tcp->tcp_ack) - session.iss);
+ }
+
+ /* IP Options */
+ ip_optlen = ((ip->ip_vhl & 0x0f) << 2) - sizeof(struct IpHeader);
+ ip_opt = (char *)ip + sizeof(struct IpHeader);
+
+ i = 0;
+ while (i < ip_optlen) {
+
+ switch ((unsigned char)ip_opt[i]) {
+ case IPOPT_NOP:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_NOP");
+ i = i + 1;
+ break;
+
+ case IPOPT_EOL:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_EOL");
+ i = ip_optlen + 1;
+ break;
+
+ case IPOPT_RR:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_RR");
+ i = i + IPOLEN_RR;
+ break;
+
+ default:
+ printf("ip_opt%d: UNKNOWN ", i + 1);
+ i = i + (uint8)ip_opt[i+1] ;
+ }
+ }
+
+ printf(" win: %u, urg: %u, ttl: %d", ntohs(tcp->tcp_win), ntohs(tcp->tcp_urp), ip->ip_ttl);
+ printf(" datalen: %u, optlen: %u ",
+ ip->ip_len - ((ip->ip_vhl &0x0f) << 2) - (tcp->tcp_hl >> 2),
+ (tcp->tcp_hl >> 2) - (unsigned int)sizeof(struct TcpHeader));
+
+
+ /* TCP Options */
+ optlen = (tcp->tcp_hl >> 2) - (unsigned int)sizeof (struct TcpHeader) ;
+ opt = (char *)tcp + sizeof(struct TcpHeader);
+
+ i = 0 ;
+
+ while (i < optlen) {
+
+ switch ((unsigned char)opt[i]) {
+
+ case TCPOPT_EOL:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_EOL");
+ i = optlen + 1;
+ break ;
+
+ case TCPOPT_NOP:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_NOP");
+ i++ ;
+ break ;
+
+ case TCPOPT_MAXSEG:
+ printf (" opt%d: %s: %d ", i + 1, "TCPOPT_MAXSEG", ntohs(*(uint16 *)((char *)opt+2)));
+ i = i + TCPOLEN_MAXSEG ;
+ break ;
+
+ case TCPOPT_WINDOW:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_WINDOW");
+ i = i + TCPOLEN_WINDOW ;
+ break ;
+
+ case TCPOPT_SACK_PERMITTED:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_SACK_PERMITTED");
+ i = i + TCPOLEN_SACK_PERMITTED ;
+ break ;
+
+ case TCPOPT_TIMESTAMP:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_TIMESTAMP");
+ i = i + TCPOLEN_TIMESTAMP ;
+ break ;
+
+ default:
+ printf (" opt%d c:%d l:%d: UNKNOWN ", i + 1, (uint8)opt[i], (uint8)opt[i+1]);
+ if ((uint8)opt[i+1] > 0) {
+ i = i + (uint8)opt[i+1] ;
+ } else {
+ Quit(20);
+ }
+ break ;
+ }
+ }
+ printf ("\n");
+}
+
+
+struct IPPacket *FindHeaderBoundaries(char *p) {
+
+ struct IPPacket *packet;
+ uint16 ip_hl;
+
+ if ((packet = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) == NULL) {
+ printf("FindHeaderBoundaries: Cannot allocate memory for read packet\nRETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ packet->ip = (struct IpHeader *)p;
+
+ if (packet->ip->ip_p != IPPROTOCOL_TCP &&
+ packet->ip->ip_p != IPPROTOCOL_ICMP) {
+ printf("Error: Unexpected protocol packet: %u \n", packet->ip->ip_p);
+ Quit(ERR_CHECKSUM);
+ }
+
+ ip_hl = (packet->ip->ip_vhl & 0x0f) << 2;
+
+ packet->tcp = (struct TcpHeader *)((char *)p + ip_hl);
+ return packet;
+
+}
+
+
+struct IPPacket *
+AllocateIPPacket(int ip_optlen, int tcp_optlen, int datalen, char *str)
+{
+ struct IPPacket *p;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In AllocateIPPacket: %s...\n", str);
+ }
+
+ if ((p = (struct IPPacket *)calloc(1, sizeof(struct IPPacket)))
+ == NULL) {
+ printf("%s ERROR: No space for packet\nRETURN CODE: %d",
+ str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((p->ip = (struct IpHeader *)calloc(1,
+ sizeof(struct IpHeader) + ip_optlen)) == NULL) {
+ printf("%s ERROR: No IpHeader space for packet\n"
+ "RETURN CODE: %d", str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((p->tcp = (struct TcpHeader *)calloc(1,
+ sizeof(struct TcpHeader) + tcp_optlen + datalen)) == NULL) {
+ printf("%s ERROR: No TcpHeader space for packet\n"
+ "RETURN CODE: %d", str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of AllocateIPPacket: %s...\n", str);
+ }
+ return(p);
+}
+
+void
+FreeIPPacket(struct IPPacket **pkt_p)
+{
+ struct IPPacket *pkt;
+ if (pkt_p == NULL)
+ return;
+ if ((pkt = *pkt_p) == NULL)
+ return;
+ if (pkt->ip != NULL) {
+ free(pkt->ip);
+ pkt->ip = NULL;
+ }
+ if (pkt->tcp != NULL) {
+ free(pkt->tcp);
+ pkt->tcp = NULL;
+ }
+ free(pkt);
+ *pkt_p = NULL;
+}
+
diff --git a/network_cmds/ecnprobe/inet.h b/network_cmds/ecnprobe/inet.h
new file mode 100644
index 0000000..8d1ccff
--- /dev/null
+++ b/network_cmds/ecnprobe/inet.h
@@ -0,0 +1,206 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+
+#ifndef _INET_H_
+#define _INET_H_
+
+/* XXX These are machine/compiler dependent */
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+
+#define IPPROTOCOL_ICMP 1
+#define IPPROTOCOL_IGMP 2
+#define IPPROTOCOL_TCP 6
+#define IPPROTOCOL_UDP 17
+#define IP_DF 0x4000
+
+/* ICMP type */
+#define ICMP_TIMXCEED 11
+
+/* TCP Flags */
+#define TCPFLAGS_FIN 0x01
+#define TCPFLAGS_SYN 0x02
+#define TCPFLAGS_RST 0x04
+#define TCPFLAGS_PSH 0x08
+#define TCPFLAGS_ACK 0x10
+#define TCPFLAGS_URG 0x20
+#define TCPFLAGS_ECN_ECHO 0x40
+#define TCPFLAGS_CWR 0x80
+
+/* IP Options Parameters -- for IP Options te*/
+#define IPOPT_EOL 0x0
+#define IPOLEN_EOL 0x1
+#define IPOPT_NOP 0x1
+#define IPOLEN_NOP 0x1
+#define IPOPT_RR 0x7
+#define IPOLEN_RR 0x27 /* Maximum length; up to 9 IP addresses */
+#define IPOPT_TS 0x44
+#define IPOLEN_TS 0x28
+#define IPOPT_FAKED 0xff
+#define IPOLEN_FAKED 0x4
+
+/* TCP Options Parameters */
+#define TCPOPT_EOL 0
+#define TCPOLEN_EOL 1
+#define TCPOPT_NOP 1
+#define TCPOLEN_NOP 1
+#define TCPOPT_MAXSEG 2
+#define TCPOLEN_MAXSEG 4
+#define TCPOPT_WINDOW 3
+#define TCPOLEN_WINDOW 3
+#define TCPOPT_SACK_PERMITTED 4
+#define TCPOLEN_SACK_PERMITTED 2
+#define TCPOPT_SACK 5
+#define TCPOPT_TIMESTAMP 8
+#define TCPOLEN_TIMESTAMP 10
+#define TCPOPT_FAKED 0x19
+#define TCPOLEN_FAKED 0x4
+
+struct IpHeader {
+ uint8 ip_vhl; /* version (4bits) & header length (4 bits) */
+ uint8 ip_tos; /* type of service */
+ uint16 ip_len; /* length of IP datagram */
+ uint16 ip_id; /* identification (for frags) */
+ uint16 ip_off; /* offset (within a fragment) and flags (3 bits) */
+ uint8 ip_ttl; /* time to live */
+ uint8 ip_p; /* protocol number */
+ uint16 ip_xsum; /* checksum */
+ uint32 ip_src; /* source address */
+ uint32 ip_dst; /* destination address */
+};
+
+/* Pseudo header for doing TCP checksum calculation */
+struct PseudoIpHeader {
+ uint32 filler[2];
+ uint8 zero;
+ uint8 ip_p;
+ uint16 ip_len;
+ uint32 ip_src;
+ uint32 ip_dst;
+};
+
+struct TcpHeader {
+ uint16 tcp_sport; /* source port */
+ uint16 tcp_dport; /* destination port */
+ uint32 tcp_seq; /* sequence number */
+ uint32 tcp_ack; /* acknoledgement number */
+ uint8 tcp_hl; /* header length (4 bits) */
+ uint8 tcp_flags; /* flags */
+ uint16 tcp_win; /* advertized window size */
+ uint16 tcp_xsum; /* checksum */
+ uint16 tcp_urp; /* urgent pointer */
+};
+
+
+
+struct IcmpHeader {
+ uint8 icmp_type; /* ICMP message type */
+ uint8 icmp_code; /* Message code */
+ uint16 icmp_xsum; /* checksum */
+ uint16 icmp_unused; /* unused field */
+ uint16 icmp_mtu; /* MTU of limiting interface */
+};
+
+struct IPPacket {
+ struct IpHeader *ip;
+ struct TcpHeader *tcp;
+};
+
+struct ICMPUnreachableErrorPacket {
+ struct IpHeader ip;
+ struct IcmpHeader icmp;
+ struct IpHeader off_ip;
+ /* 8-first bytes of TCP header */
+ uint16 tcp_sport;
+ uint16 tcp_dport;
+ uint32 tcp_seqno;
+};
+
+struct ICMPTimeExceededErrorPacket {
+ struct IpHeader ip;
+ struct IcmpHeader icmp;
+ struct IpHeader off_ip;
+ /* 8-first bytes of Tcpheader */
+ uint16 tcp_sport;
+ uint16 tcp_dport;
+ uint32 tcp_seqno;
+};
+
+char *InetAddress(uint32 addr);
+
+uint16 InetChecksum(uint16 *ip_addr, uint16 *tcp_addr, uint16 ip_len, uint16 tcp_len);
+
+void PrintTcpPacket(struct IPPacket *p);
+void PrintICMPUnreachableErrorPacket(struct ICMPUnreachableErrorPacket *p);
+
+void WriteIPPacket(struct IPPacket *p,
+ uint32 src,
+ uint32 dst,
+ uint16 sport,
+ uint16 dport,
+ uint32 seq,
+ uint32 ack,
+ uint8 flags,
+ uint16 win,
+ uint16 urp,
+ uint16 datalen,
+ uint16 ip_optlen,
+ uint16 optlen,
+ uint8 iptos,
+ uint8 u4tf);
+
+void ReadIPPacket(struct IPPacket *p, uint32 *src, uint32 *dst,
+ uint16 *sport, uint16 *dport, uint32 *seq, uint32 *ack,
+ uint8 *flags, uint16 *win, uint16 *urp, uint16 *datalen,
+ uint16 *ip_optlen, uint16 *optlen);
+
+void StorePacket (struct IPPacket *p);
+
+struct IPPacket *FindHeaderBoundaries(char *p);
+
+struct IPPacket *AllocateIPPacket(int ip_optlen, int tcp_optlen, int datalen, char *str);
+
+void FreeIPPacket(struct IPPacket **pkt_p);
+
+#endif /* _INET_H_ */
diff --git a/network_cmds/ecnprobe/session.c b/network_cmds/ecnprobe/session.c
new file mode 100644
index 0000000..5ca97d8
--- /dev/null
+++ b/network_cmds/ecnprobe/session.c
@@ -0,0 +1,785 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "ecn.h"
+#include <errno.h>
+
+struct TcpSession session;
+
+int EstablishSession(uint32 sourceAddress,
+ uint16 sourcePort,
+ uint32 targetAddress,
+ uint16 targetPort,
+ int ip_optlen, // AM: add support for IP options
+ char *ip_opt, // AM: add support for IP options
+ int mss,
+ int optlen,
+ char *opt,
+ int maxwin,
+ int maxpkts,
+ uint8 iptos,
+ uint8 tcp_flags) // AM: Add a tcp_flags parameter
+{
+
+ int rawSocket;
+
+ struct IPPacket *p = NULL;
+ struct IPPacket *synPacket;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ double ts1 = 0, ts2;
+ int flag = 1;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In EstablishSession...\n");
+ }
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = maxwin * mss;
+ session.snd_nxt = arc4random(); /* random initial sequence number */
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss ;
+ session.maxseqseen = 0 ;
+ session.epochTime = GetTime();
+ session.maxpkts = maxpkts;
+ session.num_unwanted_drops = 0;
+ session.num_reordered = 0;
+ session.num_rtos = 0;
+ session.num_dup_acks = 0;
+ session.num_pkts_0_dup_acks = 0;
+ session.num_pkts_1_dup_acks = 0;
+ session.num_pkts_2_dup_acks = 0;
+ session.num_pkts_3_dup_acks = 0;
+ session.num_pkts_4_or_more_dup_acks = 0;
+ session.num_dupack_ret = 0;
+ session.num_reord_ret = 0;
+ session.num_reordered = 0;
+ session.num_dup_transmissions = 0;
+ session.ignore_result = 0;
+ session.curr_ttl = 0;
+
+ if ((session.mtu < 1) || (session.mtu > 1460)) {
+ session.mtu = 1500;
+ }
+
+ if (session.verbose) {
+ printf("session.MTU = %d\n", session.mtu);
+ }
+
+ if ((session.dataRcvd = (uint8 *)calloc(sizeof(uint8), mss * session.maxpkts)) == NULL) {
+ perror("ERROR: no memmory to store data:\n");
+ printf("RETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ /* Now open a raw socket for sending our "fake" TCP segments */
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ printf("RETURN CODE: %d\n", ERR_SOCKET_OPEN);
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL, (char *)&flag,sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ printf("RETURN CODE: %d\n", ERR_SOCKOPT);
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Allocate SYN packet */
+ synPacket = AllocateIPPacket(ip_optlen, optlen, 0, "EstablishSession (SYN)");
+
+ /* Copy IP options at the end of IpHeader structure - New */
+ if (ip_optlen > 0) {
+ memcpy((char *)synPacket->ip + sizeof(struct IpHeader), ip_opt, ip_optlen);
+ }
+
+ /* Copy TCP options at the end of TcpHeader structure - New */
+ if (optlen > 0) {
+ memcpy((char *)synPacket->tcp + sizeof(struct TcpHeader), opt, optlen);
+ }
+
+ /* Send SYN Pkt */
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
+ TCPFLAGS_SYN | tcp_flags,
+ ip_optlen, /* IP opt len */
+ optlen, /* TCP opt len */
+ iptos);
+
+ timeoutTime = GetTime() + SYNTIMEOUT;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < MAXSYNRETRANSMITS) {
+
+ while(GetTime() < timeoutTime) {
+
+ /* Have we captured any packets? */
+
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport, session.dst, session.dport)) {
+
+ /* Is it a SYN? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit\n");
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+
+ ts1 = pi.ts.tv_sec + (double)pi.ts.tv_usec/1000000.0;
+ session.totSeenSent ++ ;
+
+ }
+
+ free(p);
+ continue;
+
+
+ }
+
+ if (INSESSION(p, session.dst, session.dport, session.src, session.sport)) {
+
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & (TCPFLAGS_SYN | TCPFLAGS_ACK)) {
+
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ ts2 = pi.ts.tv_sec + (double)pi.ts.tv_usec/1000000.0;
+ session.rtt = ts2 - ts1 ;
+
+ if (numRetransmits > 0) {
+ session.rtt_unreliable = 1;
+ printf("##### Unreliable\n"); /* ACK for which SYN? */
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd:\n");
+ PrintTcpPacket(p);
+ printf("Connection setup took %d ms\n",(int)((ts2 - ts1) * 1000.0));
+ }
+
+ StorePacket(p);
+
+ /* Save ttl for,admittedly poor,indications of reverse route change */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd++;
+
+ free(p);
+ break ;
+
+ }
+
+ }
+
+ free(p->ip);
+ free(p->tcp);
+ free(p);
+
+ }
+
+ }
+
+ if (!synAckReceived) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
+ TCPFLAGS_SYN | tcp_flags,
+ ip_optlen, /* IP opt len */
+ optlen, /* TCP opt len */
+ iptos);
+
+ timeoutTime = GetTime() + SYNTIMEOUT;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= MAXSYNRETRANSMITS) {
+ printf("ERROR: Could not establish contact after %d retries\nRETURN CODE: %d\n",
+ numRetransmits, NO_CONNECTION);
+ Quit(NO_CONNECTION);
+ }
+
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("src = %s:%d (%u)\n", InetAddress(session.src), session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n", InetAddress(session.dst), session.dport, session.irs);
+ }
+
+ free(synPacket->ip);
+ free(synPacket->tcp);
+ free(synPacket);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of EstablishSession...\n");
+ }
+
+ session.start_time = GetTime();
+
+ return 1;
+
+}
+
+int PrepareRequest(char *data, char *filename)
+{
+
+ char h1[] = "GET ";
+ char h2[] = " HTTP/1.1";
+ char h3[] = "Host: ";
+ char h4[] = "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11; DigExt; TBIT)";
+ char h5[] = "Accept: */*";
+
+ /* New */
+ char h7[] = "Pragma: no-cache";
+ char h8[] = "Cache-control: no-chache";
+ char deffile[] = DEFAULT_FILENAME;
+
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In PrepareRequest...\n");
+ }
+
+ if (filename == NULL) {
+ filename = deffile;
+ }
+
+
+ if (strlen(session.targetName) > 0) {
+
+ sprintf(data,
+
+ "%s/%s %s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s%s\r\n\r\n",
+ h1,
+ filename,
+ h2,
+ h4,
+ h7,
+ h8,
+ h5,
+ h3,
+ session.targetName);
+ }else {
+
+ sprintf(data,
+ "%s%s%s\r\n%s\r\n\r\n",
+ h1,
+ filename,
+ h2,
+ h4);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out PrepareRequest...\n");
+ }
+
+ return ((int)strlen(data));
+
+}
+
+
+void SendRequest(char *filename, void (*ackData)(struct IPPacket *p))
+{
+
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i;
+ int sendflag = 1;
+ double startTime = 0;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendRequest...\n");
+ }
+
+ datalen = PrepareRequest(data, filename);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+
+ /* Allocate space for IP data packet */
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "SendRequest (Data)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr, (void *)data, datalen);
+
+ /* Send the data packet. Try to "achieve" reliability by sending the
+ * packet upto 5 times, wating for 2 seconds between packets (BAD
+ * busy-wait loop)
+ */
+
+ i = 0 ;
+ while(1) {
+
+ if (sendflag == 1) {
+
+ SendSessionPacket(datapkt,
+ ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK,
+ 0, /* ip opt len */
+ 0, /* tcp opt len */
+ 0); /* tos */
+
+ startTime = GetTime();
+ sendflag = 0 ;
+ i++;
+
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ (ntohl(p->tcp->tcp_seq) == session.snd_nxt) &&
+ (ntohl(p->tcp->tcp_ack) <= session.rcv_nxt)) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+
+ free(p);
+
+ //session.snd_nxt += datalen + 1;
+ session.totSeenSent++;
+ continue;
+
+ }
+ /*
+ * packet from them?
+ */
+
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ (ntohl(p->tcp->tcp_ack) >= session.snd_una)) {
+
+
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+
+ if (p->ip->ip_ttl != session.ttl) {
+ printf("#### WARNING: route may have changed (ttl was %d, is %d).\n",
+ session.ttl, p->ip->ip_ttl);
+ session.ttl = p->ip->ip_ttl;
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+ session.totRcvd ++;
+ session.snd_nxt += datalen + 1;
+
+ /* if the packet also contains data, receive it and send an ack if needed */
+ (*ackData)(p);
+
+ free(p);
+ break;
+
+ }
+
+ free(p);
+
+ }
+
+ if ((GetTime() - startTime >= REXMITDELAY) &&
+ (sendflag == 0) && (i < MAXDATARETRANSMITS)) {
+ sendflag = 1 ;
+ }
+
+ if (i >= MAXDATARETRANSMITS) {
+ printf ("ERROR: sent request 5 times without response\nRETURN CODE: %d\n",
+ SEND_REQUEST_FAILED);
+ Quit(SEND_REQUEST_FAILED);
+ }
+
+ }
+
+ free(datapkt->ip);
+ free(datapkt->tcp);
+ free(datapkt);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendRequest...\n");
+ }
+}
+
+void SendSessionPacket(struct IPPacket *p,
+ uint16 ip_len, uint8 tcp_flags, uint16 ip_optlen, uint16 optlen,
+ uint8 iptos)
+{
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendSessionPacket...\n");
+ }
+ WriteIPPacket(p,
+ session.src, session.dst, session.sport, session.dport,
+ session.snd_nxt, session.rcv_nxt, tcp_flags,
+ session.rcv_wnd, 0,
+ (ip_len - sizeof(struct IpHeader) - ip_optlen - sizeof(struct TcpHeader) - optlen),
+ ip_optlen, optlen, iptos, 0);
+
+
+ /* Store packet here rather than in rcvData() because otherwise some
+ * ACKs may not be accounted for upon receiving reordered packets */
+
+ StorePacket(p);
+
+ SendPkt(p,
+ ip_len, /* Total IP datagram size */
+ ip_optlen, /* ip options len */
+ optlen); /* tcp options len */
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendSessionPacket...\n");
+ }
+
+}
+
+
+void SendICMPReply(struct IPPacket *p)
+{
+
+ struct ICMPUnreachableErrorPacket *icmp_pkt;
+ int icmpsz;
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendICMPReply...\n");
+ }
+
+ icmpsz = sizeof(struct ICMPUnreachableErrorPacket);
+ if ((icmp_pkt = (struct ICMPUnreachableErrorPacket *)calloc(icmpsz + 1, 1)) == NULL) {
+ perror("ERROR: no space for ICMP packet:");
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ /* Fill IP Header of ICMP packet */
+ bzero((char *)icmp_pkt, sizeof(struct ICMPUnreachableErrorPacket));
+ icmp_pkt->ip.ip_src = ip->ip_dst;
+ icmp_pkt->ip.ip_dst = ip->ip_src;
+ icmp_pkt->ip.ip_p = IPPROTOCOL_ICMP;
+ icmp_pkt->ip.ip_xsum =
+ htons((uint16)(sizeof(struct IcmpHeader) + sizeof(struct IpHeader) + sizeof(struct IpHeader) + 8)); /* pseudo hdr */
+ icmp_pkt->ip.ip_ttl = 60;
+ icmp_pkt->ip.ip_tos = 0x00;
+ icmp_pkt->ip.ip_vhl = 0x45;
+#ifdef __FreeBSD__
+ icmp_pkt->ip.ip_off = IP_DF;
+ icmp_pkt->ip.ip_len = (uint16)(sizeof(struct ICMPUnreachableErrorPacket));
+#else /* __FreeBSD__ */
+ icmp_pkt->ip.ip_off = htons(IP_DF);
+ icmp_pkt->ip.ip_len = htons((uint16)((sizeof (struct ICMPUnreachableErrorPacket) + 8 + 1)));
+#endif /* __FreeBSD__ */
+
+ /* Fill ICMP header */
+ icmp_pkt->icmp.icmp_type = 0x3;
+ icmp_pkt->icmp.icmp_code = 0x4;
+ icmp_pkt->icmp.icmp_xsum = 0;
+ icmp_pkt->icmp.icmp_unused = 0;
+ icmp_pkt->icmp.icmp_mtu = htons(session.mtu);
+
+ /* Fill in ip header of offending packet */
+ icmp_pkt->off_ip.ip_src = ip->ip_src;
+ icmp_pkt->off_ip.ip_dst = ip->ip_dst;
+ icmp_pkt->off_ip.ip_p = ip->ip_p;
+ icmp_pkt->off_ip.ip_xsum = ip->ip_xsum;
+ icmp_pkt->off_ip.ip_ttl = ip->ip_ttl;
+ icmp_pkt->off_ip.ip_tos = ip->ip_tos;
+ icmp_pkt->off_ip.ip_vhl = ip->ip_vhl;
+ icmp_pkt->off_ip.ip_p = ip->ip_p;
+#ifdef __FreeBSD__
+ icmp_pkt->off_ip.ip_off = ntohs(ip->ip_off);
+ icmp_pkt->off_ip.ip_len = ntohs(ip->ip_len);
+#else /* __FreeBSD__ */
+ icmp_pkt->off_ip.ip_off = ip->ip_off;
+ icmp_pkt->off_ip.ip_len = ip->ip_len;
+#endif /* __FreeBSD__ */
+
+ icmp_pkt->tcp_sport = tcp->tcp_sport;
+ icmp_pkt->tcp_dport = tcp->tcp_dport;
+ icmp_pkt->tcp_seqno = (uint32)tcp->tcp_seq;
+
+ icmp_pkt->icmp.icmp_xsum = InetChecksum((uint16 *)(&(icmp_pkt->icmp)), NULL,
+ (uint16)(sizeof(struct IcmpHeader) + sizeof(struct IpHeader) + 8), 0);
+
+ if (session.verbose) {
+ printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ printf("TCP Packet: %lu\n", sizeof(struct IPPacket));
+ PrintTcpPacket(p);
+ printf("ICMP Packet: %lu\n", sizeof(struct ICMPUnreachableErrorPacket));
+ PrintICMPUnreachableErrorPacket(icmp_pkt);
+ printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ }
+
+ SendICMPPkt(icmp_pkt, sizeof(struct ICMPUnreachableErrorPacket));
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendICMPReply...\n");
+ }
+
+}
+
+void SendPkt(struct IPPacket *p, uint16 ip_len, int ip_optlen,
+ int tcp_optlen) {
+ int nbytes, datalen;
+ struct sockaddr_in sockAddr;
+ char *assembled_pkt;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendPkt...\n");
+ }
+ /* Assemble contiguos packet to be sent */
+ if ((assembled_pkt = (char *)calloc(1, ip_len)) == NULL) {
+ printf("SendPkt: Cannot allocate memory for assembled packet\n");
+ Quit(ERR_MEM_ALLOC);
+ }
+ /* Copy IP Header and options, if any */
+ memcpy((char *)assembled_pkt, (char *)(p->ip),
+ sizeof(struct IpHeader) + ip_optlen);
+
+ /* Copy TCP Header and options, if any */
+ memcpy((char *)(assembled_pkt + sizeof(struct IpHeader) + ip_optlen),
+ (char *)(p->tcp),
+ sizeof(struct TcpHeader) + tcp_optlen);
+
+ /* Copy data bytes, if any */
+ datalen = ip_len - ((sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + tcp_optlen));
+
+ if (datalen > 0) {
+ memcpy((char *)assembled_pkt + sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + tcp_optlen,
+ (char *)p->tcp + sizeof(struct TcpHeader) + tcp_optlen, datalen);
+ }
+
+
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = session.dst;
+
+ if ((nbytes = (int)sendto(session.socket,
+ (char *)assembled_pkt,
+ ip_len,
+ 0,
+ (struct sockaddr *)&sockAddr,
+ sizeof(sockAddr))) < ip_len) {
+ printf("#### WARNING: only sent %d of %d bytes\n", nbytes, ip_len);
+ perror("here");
+
+ }
+
+ session.totSent++;
+
+ free(assembled_pkt);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out SendPkt...\n");
+ }
+
+}
+
+
+
+void SendICMPPkt(struct ICMPUnreachableErrorPacket *p, uint16 len) {
+
+ ssize_t nbytes;
+ struct sockaddr_in sockAddr;
+
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = session.dst;
+
+ nbytes = sendto(session.socket, (char *)p, len, 0,
+ (struct sockaddr *)&sockAddr,
+ sizeof(sockAddr));
+
+ if (nbytes < len) {
+ printf("#### WARNING: only sent %zd of %d (errno: %d) bytes\n",
+ nbytes, len, errno);
+ perror("here");
+ }
+
+ session.totSent++ ;
+
+}
+
+void rcvData (void (*ackData)(struct IPPacket *p))
+{
+
+ struct pcap_pkthdr pi;
+ struct IPPacket *p;
+ char *read_packet;
+ double startTime = GetTime () ;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In rcvData...\n");
+ }
+
+ while (1) {
+
+ if ((GetTime() - startTime) > (MAXDATARETRANSMITS * REXMITDELAY)) {
+ printf ("ERROR: no Data received for %f seconds\nRETURN CODE: %d\n",
+ (MAXDATARETRANSMITS*REXMITDELAY), NO_DATA_RCVD);
+ Quit(NO_DATA_RCVD) ;
+ }
+
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * Packet that we sent?
+ */
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport) &&
+ ((p->tcp->tcp_flags & TCPFLAGS_ACK) || (p->tcp->tcp_flags & TCPFLAGS_FIN)) &&
+ (ntohl(p->tcp->tcp_seq) == session.snd_nxt) &&
+ (ntohl(p->tcp->tcp_ack) <= session.rcv_nxt)) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit:\n");
+ PrintTcpPacket(p);
+ }
+
+ session.totSeenSent++ ;
+
+ free(p);
+ continue;
+
+ }
+
+ /*
+ * Data that we were expecting?
+ */
+
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_ack) >= session.snd_una)) {
+
+ if (p->ip->ip_ttl != session.ttl) {
+ printf("#### WARNING: route may have changed (ttl was %d, is %d).\n",
+ session.ttl, p->ip->ip_ttl);
+ session.ttl = p->ip->ip_ttl;
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd: \n");
+ PrintTcpPacket(p);
+ }
+
+ session.totRcvd++ ;
+ startTime = GetTime () ;
+ StorePacket(p);
+
+ /* if the packet also contains data, receive it, and send an ack if needed */
+ ECNAckData(p);
+
+ free(p);
+ continue ;
+
+ } else {
+
+ free(p);
+
+ }
+ }
+ }
+}
+
+
diff --git a/network_cmds/ecnprobe/session.h b/network_cmds/ecnprobe/session.h
new file mode 100644
index 0000000..bff3296
--- /dev/null
+++ b/network_cmds/ecnprobe/session.h
@@ -0,0 +1,183 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 MAXREQUESTLEN 1000
+
+#define SESSION_DEBUG_LOW 1
+#define SESSION_DEBUG_MEDIUM 2
+#define SESSION_DEBUG_HIGH 3
+
+struct TcpSession {
+
+ /* target name, as specified by the user */
+ char targetName[MAXHOSTNAMELEN];
+
+ /* DNS name of hosts */
+ char targetHostName[MAXHOSTNAMELEN];
+ char sourceHostName[MAXHOSTNAMELEN];
+
+ /* raw socket we use to send on */
+ int socket;
+
+ /* connection endpoint identifiers */
+ u_int32_t src;
+ u_int16_t sport;
+ u_int32_t dst;
+ u_int16_t dport;
+
+ /* sender info, from RFC 793 */
+ u_int32_t iss; // initial send sequence
+ u_int32_t snd_una; // sequence numbers of unacknowledged data
+ u_int32_t snd_nxt; // sequence number to be sent next
+ u_int16_t snd_wnd;
+ u_int16_t sndmss;
+
+ /* Receiver info */
+ u_int32_t irs;
+ u_int32_t rcv_wnd;
+ u_int32_t rcv_nxt;
+ u_int32_t maxseqseen;
+ u_int16_t mss;
+
+ /* timing */
+ double rtt;
+ u_int8_t ttl;
+ double start_time;
+
+ /* data buffer */
+ u_int8_t *dataRcvd ;
+
+ /* basic results */
+ int totSent;
+ int totRcvd;
+ int totSeenSent;
+ int totDataPktsRcvd;
+ int totOutofSeq;
+ int hsz;
+
+ /* basic control*/
+ int epochTime;
+ int debug;
+ int verbose;
+ int initSession;
+ int initCapture;
+ int initFirewall;
+ int firewall_rule_number;
+ char *filename;
+ int maxpkts;
+
+ /* New loss-rate parameters */
+ float loss_rate;
+ float prop_delay;
+
+ /* results are suspect for various reasons */
+ int rtt_unreliable;
+ int ignore_result;
+
+ /* Drops and reordering startistics */
+ int num_reordered;
+ int num_unwanted_drops;
+ int num_rtos;
+ int num_reord_ret;
+ int num_dup_transmissions;
+ int num_dup_acks;
+ int num_pkts_0_dup_acks;
+ int num_pkts_1_dup_acks;
+ int num_pkts_2_dup_acks;
+ int num_pkts_3_dup_acks;
+ int num_pkts_4_or_more_dup_acks;
+ int num_dupack_ret;
+
+ /* For PMTUD test */
+ int mtu;
+
+ /* For ByteCounting test */
+ int bytecounting_type;
+ int ack_bytes; /* How many bytes covered per ACK */
+ int ack_rate; /* ACK [every | every other | every third |...] packet */
+
+ /* For WindowScale Option test */
+ u_int8_t receiving_shift_count;
+ u_int8_t sending_shift_count;
+
+ /* For MidBoxTTL test */
+ int curr_ttl;
+
+ int dont_send_reset;
+};
+
+//void SendSessionPacket(struct IPPacket *packet,
+void SendSessionPacket(struct IPPacket *packet,
+ u_int16_t ip_len, /* Total size of IP datagram */
+ u_int8_t tcp_flags,
+ u_int16_t ip_optlen, /* IP options len - New */
+ u_int16_t optlen, /* TCP options len */
+ u_int8_t iptos);
+
+void SendICMPReply(struct IPPacket *p);
+
+void SendPkt(struct IPPacket *p, u_int16_t ip_len, int ip_optlen, int tcp_optlen);
+
+void SendICMPPkt(struct ICMPUnreachableErrorPacket *p, u_int16_t ip_len);
+
+void StorePacket (struct IPPacket *p);
+
+int EstablishSession(u_int32_t sourceAddress, \
+ u_int16_t sourcePort, \
+ u_int32_t targetAddress,
+ u_int16_t targetPort, \
+ int ip_optlen,\
+ char *ip_opt,\
+ int mss,
+ int optlen,
+ char *opt, \
+ int maxwin,
+ int maxpkts,
+ u_int8_t iptos,
+ u_int8_t tcp_flags);
+
+void rcvData (void (*ackData)(struct IPPacket *p));
+
+void SendRequest(char *filename, void (*ackData)(struct IPPacket *p));
+
+int PrepareRequest(char *data, char *filename) ;
diff --git a/network_cmds/ecnprobe/support.c b/network_cmds/ecnprobe/support.c
new file mode 100644
index 0000000..2cdb405
--- /dev/null
+++ b/network_cmds/ecnprobe/support.c
@@ -0,0 +1,246 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+
+extern struct TcpSession session;
+
+void SendReset()
+{
+ struct IPPacket *p;
+ int i;
+
+ if (session.dont_send_reset)
+ return;
+
+ if ((p = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) == NULL) {
+ perror("ERROR: Could not allocate RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ if ((p->ip = (struct IpHeader *)calloc(1, sizeof(struct IpHeader))) == NULL) {
+ perror("ERROR: Could not allocate IP Header for RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ if ((p->tcp = (struct TcpHeader *)calloc(1, sizeof(struct TcpHeader))) == NULL) {
+ perror("ERROR: Could not allocate TCP Header for RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ for (i = 0; i < MAXRESETRETRANSMITS; i++) {
+ SendSessionPacket(p,
+ //sizeof(struct IPPacket),
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ TCPFLAGS_RST,
+ 0,
+ 0,
+ 0);
+ }
+
+/* free(p->ip);
+ free(p->tcp);
+ free(p);
+*/
+
+}
+
+#if 0
+/* make a clean exit on interrupts */
+void SigHandle (int signo)
+{
+ Cleanup () ;
+ fflush(stdout);
+ fflush(stderr);
+ exit(-1);
+}
+
+
+void Cleanup()
+{
+
+ char ipfw_rule[100];
+ int r;
+
+ /* If a firewall rule has been installed then remove it */
+ if (session.initFirewall > 0) {
+
+#ifdef linux
+#define IP_FW_DEL (IP_FW_DELETE)
+#endif /* linux */
+
+ sprintf(ipfw_rule, "ipfw del 00%d", session.firewall_rule_number);
+ r = system(ipfw_rule);
+
+ }
+
+ if (session.initSession > 0) {
+
+ SendReset();
+ shutdown(session.socket,2);
+
+ }
+
+ if (session.initCapture > 0) {
+ CaptureEnd();
+ }
+
+}
+
+void Quit(int how)
+{
+
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(how);
+
+}
+#endif /* 0 */
+
+double GetTime()
+{
+ struct timeval tv;
+ struct timezone tz;
+ double postEpochSecs;
+
+ if (gettimeofday(&tv, &tz) < 0) {
+ perror("GetTime");
+ exit(-1);
+ }
+
+ postEpochSecs = (double)tv.tv_sec + ((double)tv.tv_usec/(double)1000000.0);
+ return postEpochSecs;
+}
+
+double GetTimeMicroSeconds()
+{
+ struct timeval tv;
+ struct timezone tz;
+ double postEpochMicroSecs;
+
+ if (gettimeofday(&tv, &tz) < 0) {
+ perror("GetTimeMicroSeconds");
+ exit(-1);
+ }
+
+ postEpochMicroSecs = (double)tv.tv_sec * 1000000 + (double)tv.tv_usec;
+ return postEpochMicroSecs;
+
+}
+
+void PrintTimeStamp(struct timeval *ts)
+{
+ (void)printf("%02d:%02d:%02d.%06u ",
+ (unsigned int)ts->tv_sec / 3600,
+ ((unsigned int)ts->tv_sec % 3600) / 60,
+ (unsigned int)ts->tv_sec % 60, (unsigned int)ts->tv_usec);
+}
+
+void processBadPacket (struct IPPacket *p)
+{
+
+ if (session.debug == SESSION_DEBUG_HIGH) {
+ printf("In ProcessBadPacket...\n");
+ }
+ /*
+ * reset? the other guy does not like us?
+ */
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) && (p->tcp->tcp_flags & TCPFLAGS_RST)) {
+ printf("ERROR: EARLY_RST.\nRETURN CODE: %d\n", EARLY_RST);
+ Quit(EARLY_RST);
+ }
+ /*
+ * some other packet between us that is none of the above
+ */
+ if (INSESSION(p, session.src, session.sport, session.dst, session.dport) ||
+ INSESSION(p, session.dst, session.dport, session.src, session.sport)) {
+
+ printf("ERROR: Unexpected packet\nRETURN CODE: %d\n", UNEXPECTED_PKT);
+ printf("Expecting:\n");
+ printf("\tsrc = %s:%d (seq=%u, ack=%u)\n",
+ InetAddress(session.src), session.sport,
+ session.snd_nxt-session.iss,
+ session.rcv_nxt-session.irs);
+ printf("\tdst = %s:%d (seq=%u, ack=%u)\n",
+ InetAddress(session.dst),session.dport,
+ session.rcv_nxt-session.irs, session.snd_una-session.iss);
+ printf("Received:\n\t");
+ PrintTcpPacket(p);
+ printf ("session.snd_nxt=%d, session.rcv_nxt=%d, session.snd_una=%d\n",
+ session.snd_nxt-session.iss, session.rcv_nxt-session.irs, session.snd_una-session.iss);
+ Quit(UNEXPECTED_PKT);
+ }
+ /*
+ * none of the above,
+ * so we must be seeing packets
+ * from some other flow!
+ */
+ else {
+ printf("ERRROR: Received packet from different flow\nRETURN CODE: %d\n", DIFF_FLOW);
+ PrintTcpPacket(p);
+ Quit(DIFF_FLOW) ;
+ }
+
+ if (session.debug == SESSION_DEBUG_HIGH) {
+ printf("Out ProcessBadPacket...\n");
+ }
+}
+
+void busy_wait (double wait)
+{
+ double now = GetTime();
+ double x = now ;
+ while ((x - now) < wait) {
+ x = GetTime();
+ }
+}
diff --git a/network_cmds/ecnprobe/support.h b/network_cmds/ecnprobe/support.h
new file mode 100644
index 0000000..94be2e5
--- /dev/null
+++ b/network_cmds/ecnprobe/support.h
@@ -0,0 +1,132 @@
+
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <signal.h>
+
+#define MAXRESETRETRANSMITS (3)
+/*#define INSESSION(p, src, sport, dst, dport) \
+ (((p)->ip.ip_src == (src)) && ((p)->ip.ip_dst == (dst)) && \
+ ((p)->ip.ip_p == IPPROTOCOL_TCP) && \
+ ((p)->tcp.tcp_sport == htons(sport)) && \
+ ((p)->tcp.tcp_dport == htons(dport)))*/
+
+#define INSESSION(p, src, sport, dst, dport) \
+ (((p)->ip->ip_src == (src)) && ((p)->ip->ip_dst == (dst)) && \
+ ((p)->ip->ip_p == IPPROTOCOL_TCP) && \
+ ((p)->tcp->tcp_sport == htons(sport)) && \
+ ((p)->tcp->tcp_dport == htons(dport)))
+
+#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
+#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
+#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
+#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0)
+
+#define DEFAULT_TARGETPORT (80)
+#define DEFAULT_MSS 1360
+#define DEFAULT_MTU 1500
+#define RTT_TO_MULT 5
+#define PLOTDIFF 0.00009
+
+/* Response codes */
+#define FAIL -1
+#define SUCCESS 0
+#define NO_TARGET_CANON_INFO 1
+#define NO_LOCAL_HOSTNAME 2
+#define NO_SRC_CANON_INFO 3
+#define NO_SESSION_ESTABLISH 4
+#define MSS_TOO_SMALL 5
+#define BAD_ARGS 6
+#define FIREWALL_ERR 7
+#define ERR_SOCKET_OPEN 8
+#define ERR_SOCKOPT 9
+#define ERR_MEM_ALLOC 10
+#define NO_CONNECTION 11
+#define MSS_ERR 12
+#define BUFFER_OVERFLOW 13
+#define UNWANTED_PKT_DROP 14
+#define EARLY_RST 15
+#define UNEXPECTED_PKT 16
+#define DIFF_FLOW 17
+#define ERR_CHECKSUM 18
+#define NOT_ENOUGH_PKTS 19
+#define BAD_OPT_LEN 20
+#define TOO_MANY_PKTS 21
+#define NO_DATA_RCVD 22
+#define NO_TRGET_SPECIFIED 23
+#define BAD_OPTIONS 24
+#define TOO_MANY_TIMEOUTS 25
+#define TOO_MANY_RXMTS 26
+#define NO_SACK 27
+#define ERR_IN_SB_CALC 28
+#define TOO_MANY_HOLES 29
+#define TOO_MANY_DROPS 30
+#define UNWANTED_PKT_REORDER 31
+#define NO_PMTUD_ENABLED 32
+#define UNKNOWN_BEHAVIOR 33
+#define NO_SYNACK_RCVD 34
+#define SEND_REQUEST_FAILED 35
+#define PKT_SIZE_CHANGED 36
+#define ECN_SYN_DROP 37
+
+#define DEFAULT_FILENAME "/"
+
+#define RTT_TO_MULT 5
+#define SYNTIMEOUT (2.0)
+#define REXMITDELAY (2.0)
+#define MAXSYNRETRANSMITS (6)
+#define MAXDATARETRANSMITS (6)
+
+/* HTTP Response Codes */
+#define HTTP_OK "200"
+
+
+void SendReset();
+void SigHandle (int signo);
+void Cleanup();
+void Quit(int how);
+double GetTime();
+double GetTimeMicroSeconds();
+void PrintTimeStamp(struct timeval *ts);
+void processBadPacket (struct IPPacket *p);
+void busy_wait (double wait);