#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;
u_int8_t *opt = NULL;
struct IPPacket *p = NULL;
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;
while(!synAckReceived && numRetransmits < 3) {
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) {
PrintTcpPacket(p);
}
StorePacket(p);
session.totSeenSent++ ;
} else {
processBadPacket(p);
}
continue;
}
if (INSESSION(p, session.dst, session.dport, session.src,
session.sport)) {
if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
(p->tcp->tcp_flags & TCPFLAGS_ACK)) {
timeoutTime = GetTime();
synAckReceived++;
if (session.debug >= SESSION_DEBUG_LOW) {
PrintTcpPacket(p);
}
StorePacket(p);
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");
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);
}
ackPacket = AllocateIPPacket(0, 0, 0, "Third 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;
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 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;
rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
switch (rc) {
case ESTABLISH_FAILURE_EARLY_RST:
{
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:
{
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;
}
}
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;
i = 0 ;
while(1) {
if (sendflag == 1) {
SendSessionPacket(datapkt, ipsz,
TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, iptos);
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)) &&
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 ;
}
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 ;
}
}
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);
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;
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) {
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);
}
}
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;
}
}
}
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 = 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)) {
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)) {
send_cwr = 2;
}
if (send_ece == 1 && (p->tcp->tcp_flags & TCPFLAGS_CWR)) {
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) {
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) {
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;
int se = 0;
int ar = 0;
int ae = 0;
int we = 0;
int ee = 0;
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) {
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;
i = 0 ;
init_ttl = 1;
while(1) {
if (sendflag == 1) {
session.curr_ttl = ++init_ttl;
if (init_ttl > 64)
break;
SendSessionPacket(datapkt, ipsz,
TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, 0x3);
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)) &&
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 ;
}
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 ;
}
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));
}
}
}
}
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;
rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
switch (rc) {
case ESTABLISH_FAILURE_EARLY_RST:
{
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:
{
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;
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;
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;
while(!synAckReceived && numRetransmits < 3) {
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) {
PrintTcpPacket(p);
}
StorePacket(p);
session.totSeenSent++ ;
} else {
processBadPacket(p);
}
continue;
}
if (INSESSION(p, session.dst, session.dport, session.src,
session.sport)) {
if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
(p->tcp->tcp_flags & TCPFLAGS_ACK)) {
timeoutTime = GetTime();
synAckReceived++;
if (session.debug >= SESSION_DEBUG_LOW) {
PrintTcpPacket(p);
}
StorePacket(p);
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) {
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("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);
}
ackPacket = AllocateIPPacket(0, 0, 0, "SYN reply");
SendSessionPacket(ackPacket,
sizeof(struct IpHeader) + sizeof(struct TcpHeader),
syn_reply, 0, 0, 0);
FreeIPPacket(&ackPacket);
}
done:
FreeIPPacket(&synPacket);
}