diff options
Diffstat (limited to 'network_cmds/ecnprobe')
-rw-r--r-- | network_cmds/ecnprobe/base.h | 57 | ||||
-rw-r--r-- | network_cmds/ecnprobe/capture.c | 204 | ||||
-rw-r--r-- | network_cmds/ecnprobe/capture.h | 58 | ||||
-rw-r--r-- | network_cmds/ecnprobe/ecn.c | 1119 | ||||
-rw-r--r-- | network_cmds/ecnprobe/ecn.h | 49 | ||||
-rw-r--r-- | network_cmds/ecnprobe/ecn_probe.c | 469 | ||||
-rw-r--r-- | network_cmds/ecnprobe/ecnprobe.1 | 20 | ||||
-rw-r--r-- | network_cmds/ecnprobe/gmt2local.c | 66 | ||||
-rw-r--r-- | network_cmds/ecnprobe/gmt2local.h | 27 | ||||
-rw-r--r-- | network_cmds/ecnprobe/history.c | 211 | ||||
-rw-r--r-- | network_cmds/ecnprobe/history.h | 75 | ||||
-rw-r--r-- | network_cmds/ecnprobe/inet.c | 503 | ||||
-rw-r--r-- | network_cmds/ecnprobe/inet.h | 206 | ||||
-rw-r--r-- | network_cmds/ecnprobe/session.c | 785 | ||||
-rw-r--r-- | network_cmds/ecnprobe/session.h | 183 | ||||
-rw-r--r-- | network_cmds/ecnprobe/support.c | 246 | ||||
-rw-r--r-- | network_cmds/ecnprobe/support.h | 132 |
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); |