#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, char *ip_opt, int mss,
int optlen,
char *opt,
int maxwin,
int maxpkts,
uint8 iptos,
uint8 tcp_flags) {
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();
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);
}
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;
synPacket = AllocateIPPacket(ip_optlen, optlen, 0, "EstablishSession (SYN)");
if (ip_optlen > 0) {
memcpy((char *)synPacket->ip + sizeof(struct IpHeader), ip_opt, ip_optlen);
}
if (optlen > 0) {
memcpy((char *)synPacket->tcp + sizeof(struct TcpHeader), opt, optlen);
}
SendSessionPacket(synPacket,
sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
TCPFLAGS_SYN | tcp_flags,
ip_optlen,
optlen,
iptos);
timeoutTime = GetTime() + SYNTIMEOUT;
while(!synAckReceived && numRetransmits < MAXSYNRETRANSMITS) {
while(GetTime() < timeoutTime) {
if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
if (INSESSION(p, session.src, session.sport, session.dst, session.dport)) {
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)) {
if (p->tcp->tcp_flags & (TCPFLAGS_SYN | TCPFLAGS_ACK)) {
timeoutTime = GetTime();
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");
}
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);
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,
optlen,
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);
}
session.irs = ntohl(p->tcp->tcp_seq);
session.dataRcvd[0] = 1 ;
session.rcv_nxt = session.irs + 1;
session.snd_nxt = session.iss + 1;
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: */*";
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;
datapkt = AllocateIPPacket(0, 0, datalen + 1, "SendRequest (Data)");
dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
memcpy((void *)dataptr, (void *)data, datalen);
i = 0 ;
while(1) {
if (sendflag == 1) {
SendSessionPacket(datapkt,
ipsz,
TCPFLAGS_PSH | TCPFLAGS_ACK,
0,
0,
0);
startTime = GetTime();
sendflag = 0 ;
i++;
}
if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
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.totSeenSent++;
continue;
}
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;
(*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);
StorePacket(p);
SendPkt(p,
ip_len,
ip_optlen,
optlen);
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) ;
}
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));
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
icmp_pkt->ip.ip_off = htons(IP_DF);
icmp_pkt->ip.ip_len = htons((uint16)((sizeof (struct ICMPUnreachableErrorPacket) + 8 + 1)));
#endif
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);
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
icmp_pkt->off_ip.ip_off = ip->ip_off;
icmp_pkt->off_ip.ip_len = ip->ip_len;
#endif
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");
}
if ((assembled_pkt = (char *)calloc(1, ip_len)) == NULL) {
printf("SendPkt: Cannot allocate memory for assembled packet\n");
Quit(ERR_MEM_ALLOC);
}
memcpy((char *)assembled_pkt, (char *)(p->ip),
sizeof(struct IpHeader) + ip_optlen);
memcpy((char *)(assembled_pkt + sizeof(struct IpHeader) + ip_optlen),
(char *)(p->tcp),
sizeof(struct TcpHeader) + tcp_optlen);
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);
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;
}
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);
ECNAckData(p);
free(p);
continue ;
} else {
free(p);
}
}
}
}