3 International Computer Science Institute
6 This file may contain software code originally developed for the
7 Sting project. The Sting software carries the following copyright:
9 Copyright (c) 1998, 1999
10 Stefan Savage and the University of Washington.
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
16 1. Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 2. Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in the
20 documentation and/or other materials provided with the distribution.
21 3. All advertising materials mentioning features or use of this software
22 must display the following acknowledgment:
23 This product includes software developed by ACIRI, the AT&T
24 Center for Internet Research at ICSI (the International Computer
25 Science Institute). This product may also include software developed
26 by Stefan Savage at the University of Washington.
27 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
28 may not be used to endorse or promote products derived from this software
29 without specific prior written permission.
31 THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
32 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ARE DISCLAIMED. IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
35 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 #include <sys/types.h>
44 #include <sys/param.h>
58 extern struct TcpSession session
;
59 extern struct History history
[];
61 #define ESTABLISH_SUCCESS 0
62 #define ESTABLISH_FAILURE_EARLY_RST 1
63 #define ESTABLISH_FAILURE_NO_REPLY 2
64 int EstablishTcpConnection(u_int8_t syn_flags
, u_int8_t ip_tos
)
66 struct IPPacket
*synPacket
= NULL
, *ackPacket
= NULL
;
68 struct pcap_pkthdr pi
;
69 int synAckReceived
= 0;
70 int numRetransmits
= 0;
72 int tcpoptlen
= 4; /* For negotiating MSS */
74 struct IPPacket
*p
= NULL
;
76 /* allocate the syn packet -- Changed for new IPPacket structure */
77 synPacket
= AllocateIPPacket(0, tcpoptlen
, 0, "ECN (SYN)");
78 opt
= (((u_int8_t
*)synPacket
->tcp
) + sizeof(struct TcpHeader
));
79 opt
[0] = (u_int8_t
)TCPOPT_MAXSEG
;
80 opt
[1] = (u_int8_t
)TCPOLEN_MAXSEG
;
81 *((u_int16_t
*)((u_int8_t
*)opt
+ 2)) = htons(session
.mss
);
83 SendSessionPacket(synPacket
,
84 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + tcpoptlen
,
85 TCPFLAGS_SYN
| syn_flags
, 0, tcpoptlen
, ip_tos
);
86 timeoutTime
= GetTime() + 1;
89 * Wait for SYN/ACK and retransmit SYN if appropriate
90 * not great, but it gets the job done
93 while(!synAckReceived
&& numRetransmits
< 3) {
94 while(GetTime() < timeoutTime
) {
95 /* Have we captured any packets? */
96 if ((read_packet
= (char *)CaptureGetPacket(&pi
)) != NULL
) {
97 p
= (struct IPPacket
*)FindHeaderBoundaries(read_packet
);
98 /* Received a packet from us to them */
99 if (INSESSION(p
, session
.src
, session
.sport
,
100 session
.dst
, session
.dport
)) {
101 /* Is it a SYN/ACK? */
102 if (p
->tcp
->tcp_flags
& TCPFLAGS_SYN
) {
103 if (session
.debug
>= SESSION_DEBUG_LOW
) {
107 session
.totSeenSent
++ ;
114 /* Received a packet from them to us */
115 if (INSESSION(p
, session
.dst
, session
.dport
, session
.src
,
117 /* Is it a SYN/ACK? */
118 if ((p
->tcp
->tcp_flags
& TCPFLAGS_SYN
) &&
119 (p
->tcp
->tcp_flags
& TCPFLAGS_ACK
)) {
120 timeoutTime
= GetTime(); /* force exit */
122 if (session
.debug
>= SESSION_DEBUG_LOW
) {
128 * Save ttl for,admittedly poor,indications of reverse
131 session
.ttl
= p
->ip
->ip_ttl
;
132 session
.snd_wnd
= ntohl(p
->tcp
->tcp_win
);
136 if ((p
->tcp
->tcp_flags
)& (TCPFLAGS_RST
)) {
137 printf ("ERROR: EARLY_RST\n");
138 return(ESTABLISH_FAILURE_EARLY_RST
);
145 if (!synAckReceived
) {
146 if (session
.debug
>= SESSION_DEBUG_LOW
) {
147 printf("SYN timeout. Retransmitting\n");
149 SendSessionPacket(synPacket
,
150 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + tcpoptlen
,
151 TCPFLAGS_SYN
| syn_flags
, 0, tcpoptlen
, ip_tos
);
152 timeoutTime
= GetTime() + 1;
157 if (numRetransmits
>= 3) {
158 printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
160 return(ESTABLISH_FAILURE_NO_REPLY
);
162 if (session
.debug
>= SESSION_DEBUG_LOW
)
163 printf("Received SYN-ACK, try to send the third Ack\n");
164 /* Update session variables */
165 session
.irs
= ntohl(p
->tcp
->tcp_seq
);
166 session
.dataRcvd
[0] = 1 ;
167 session
.rcv_nxt
= session
.irs
+ 1; /* SYN/ACK takes up a byte of seq space */
168 session
.snd_nxt
= session
.iss
+ 1; /* SYN takes up a byte of seq space */
169 session
.snd_una
= session
.iss
+ 1;
170 session
.maxseqseen
= ntohl(p
->tcp
->tcp_seq
);
171 session
.initSession
= 1;
172 if (session
.debug
>= SESSION_DEBUG_LOW
) {
173 printf("src = %s:%d (%u)\n", InetAddress(session
.src
),
174 session
.sport
, session
.iss
);
175 printf("dst = %s:%d (%u)\n",InetAddress(session
.dst
),
176 session
.dport
, session
.irs
);
179 /* allocate the syn packet -- Changed for new IPPacket structure */
180 ackPacket
= AllocateIPPacket(0, 0, 0, "Third ACK");
182 SendSessionPacket(ackPacket
,
183 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
),
184 TCPFLAGS_ACK
, 0, 0, 0);
185 FreeIPPacket(&synPacket
);
186 FreeIPPacket(&ackPacket
);
187 return(ESTABLISH_SUCCESS
);
190 void ECNTest(u_int32_t sourceAddress
, u_int16_t sourcePort
,
191 u_int32_t targetAddress
, u_int16_t targetPort
, int mss
)
193 int rawSocket
, rc
, flag
= 1;
197 session
.src
= sourceAddress
;
198 session
.sport
= sourcePort
;
199 session
.dst
= targetAddress
;
200 session
.dport
= targetPort
;
201 session
.rcv_wnd
= 5*mss
;
202 /* random initial sequence number */
203 session
.snd_nxt
= arc4random();
204 session
.iss
= session
.snd_nxt
;
208 session
.maxseqseen
= 0;
209 session
.epochTime
= GetTime ();
210 session
.maxpkts
= 1000;
211 /* session.debug = SESSION_DEBUG_LOW; */
213 if ((session
.dataRcvd
= (u_int8_t
*)calloc(sizeof(u_int8_t
),
214 mss
* session
.maxpkts
)) == NULL
) {
215 printf("no memmory to store data:\nRETURN CODE: %d",
220 if ((rawSocket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0) {
221 perror("ERROR: couldn't open socket:");
222 Quit(ERR_SOCKET_OPEN
);
225 if (setsockopt(rawSocket
, IPPROTO_IP
, IP_HDRINCL
,
226 (char *)&flag
, sizeof(flag
)) < 0) {
227 perror("ERROR: couldn't set raw socket options:");
231 session
.socket
= rawSocket
;
233 /* Establish a TCP connections with ECN bits */
234 rc
= EstablishTcpConnection(TCPFLAGS_ECN_ECHO
| TCPFLAGS_CWR
, 0);
236 case ESTABLISH_FAILURE_EARLY_RST
:
238 /* Received a RST when ECN bits are used. Try again without ECN */
239 rc
= EstablishTcpConnection(0, 0);
240 if (rc
== ESTABLISH_FAILURE_EARLY_RST
) {
241 printf("Received RST with or without ECN negotiation\n");
242 printf("The server might not be listening on this port\n");
244 } else if (rc
== ESTABLISH_SUCCESS
) {
245 printf("Received RST with ECN.\n");
246 printf("Connection established successfully without ECN\n");
248 } else if (rc
== ESTABLISH_FAILURE_NO_REPLY
) {
249 printf("Received RST with ECN\n");
250 printf("Exceed max SYN retransmits without ECN\n");
255 case ESTABLISH_FAILURE_NO_REPLY
:
257 /* No reply after retring, try again without ECN */
258 rc
= EstablishTcpConnection(0, 0);
259 if (rc
== ESTABLISH_FAILURE_EARLY_RST
) {
260 printf("Exceeded max SYN retransmits with ECN\n");
261 printf("Received RST without ECN\n");
263 } else if (rc
== ESTABLISH_FAILURE_NO_REPLY
) {
264 printf("Exceeded max SYN retransmits with ECN\n");
265 printf("Exceeded max SYN retransmits without ECN\n");
268 printf("Exceeded max SYN retransmits with ECN\n");
269 printf("Connection established successfully without ECN\n");
276 /* Test for propogation of CE correctly */
277 DataPkt(session
.filename
, 3, 0);
283 void DataPkt (char *filename
, u_int8_t iptos
, u_int8_t tcp_flags
)
285 struct IPPacket
*p
, *datapkt
;
286 struct pcap_pkthdr pi
;
290 u_int16_t lastSeqSent
= session
.snd_nxt
;
291 double startTime
= 0;
293 char data
[MAXREQUESTLEN
];
297 datalen
= PrepareRequest (data
, filename
);
299 datapkt
= AllocateIPPacket(0, 0, datalen
+ 1, "ECN (datapkt)");
301 dataptr
= (char *)datapkt
->tcp
+ sizeof(struct TcpHeader
);
302 memcpy((void *)dataptr
,(void *)data
, datalen
);
304 ipsz
= sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + datalen
+ 1;
306 /* send the data packet
307 * we try to "achieve" reliability by
308 * sending the packet upto 5 times, wating for
309 * 2 seconds between packets
317 SendSessionPacket(datapkt
, ipsz
,
318 TCPFLAGS_PSH
| TCPFLAGS_ACK
| tcp_flags
, 0, 0, iptos
);
320 startTime
= GetTime();
325 /* Check if we have received any packets */
326 if ((read_packet
=(char *)CaptureGetPacket(&pi
)) != NULL
) {
327 p
= (struct IPPacket
*)FindHeaderBoundaries(read_packet
);
330 * packet that we sent?
333 if (INSESSION(p
,session
.src
, session
.sport
,
334 session
.dst
,session
.dport
) &&
335 (p
->tcp
->tcp_flags
== (TCPFLAGS_PSH
| TCPFLAGS_ACK
)) &&
336 SEQ_GT(ntohl(p
->tcp
->tcp_seq
), lastSeqSent
) &&
337 SEQ_LEQ(ntohl(p
->tcp
->tcp_ack
), session
.rcv_nxt
)) {
338 lastSeqSent
= ntohl(p
->tcp
->tcp_seq
);
339 if (session
.debug
>= SESSION_DEBUG_LOW
) {
340 printf("xmit %d\n", i
);
344 session
.snd_nxt
+= datalen
+ 1;
345 session
.totSeenSent
++ ;
352 if (INSESSION(p
, session
.dst
, session
.dport
, session
.src
,
353 session
.sport
) && (p
->tcp
->tcp_flags
& TCPFLAGS_ACK
) &&
354 (ntohl(p
->tcp
->tcp_seq
) == session
.rcv_nxt
) &&
355 SEQ_GT(ntohl(p
->tcp
->tcp_ack
), session
.snd_una
)) {
356 session
.snd_una
= ntohl(p
->tcp
->tcp_ack
);
357 session
.snd_nxt
= session
.snd_una
;
358 if (p
->ip
->ip_ttl
!= session
.ttl
) {
359 session
.ttl
= p
->ip
->ip_ttl
;
361 if (session
.debug
>= SESSION_DEBUG_LOW
) {
362 printf("rcvd %d\n", i
);
370 * otherwise, this is a bad packet
373 //processBadPacket(p);
375 if ((GetTime() - startTime
>= 1) && (sendflag
== 0) && (i
< 3)) {
379 printf ("ERROR: sent request 3 times without response\n");
384 FreeIPPacket(&datapkt
);
386 /* process any response by sending Acks */
387 rcvData (ECNAckData
);
390 void ECNAckData (struct IPPacket
*p
)
393 uint32 seq
= history
[session
.hsz
- 1].seqno
;
394 uint16 datalen
= history
[session
.hsz
- 1].dlen
;
395 int fin
= history
[session
.hsz
- 1].fin
;
396 int rst
= history
[session
.hsz
- 1].rst
;
398 struct IPPacket
*ackpkt
= NULL
;
399 static int ECT_00
= 0;
400 static int ECT_01
= 0;
401 static int ECT_10
= 0;
402 static int ECT_11
= 0;
403 static int ECN_ECHO
= 0;
404 static int send_cwr
= 0;
405 static int send_ece
= 0;
410 * ECN_ECHO: counts packets with TCP header ECN bit set
411 * ECT_XX: counts packets with ECT codepoint XX (IP)
414 if (datalen
> session
.mss
) {
415 printf ("ERROR: mss=%d datalen=%d\nRETURN CODE: %d\n",
416 session
.mss
, datalen
, MSS_ERR
);
421 char *http_code
= (char *)calloc(4, sizeof(char));
422 if (seq
- session
.irs
== 1) {
423 /* Response to request packet --> check HTTP response code */
424 memcpy(http_code
, ((char *)(p
->tcp
) + sizeof(struct TcpHeader
) +
425 history
[session
.hsz
- 1].optlen
+ 9), 3);
426 if (strncmp(http_code
, HTTP_OK
, 3) != 0) {
427 printf("HTTP ERROR - HTTP RESPONSE CODE: %s\nRETURN CODE: %d\n",
428 http_code
, atoi(http_code
));
429 Quit(atoi(http_code
));
433 session
.totDataPktsRcvd
++;
435 if (session
.verbose
) {
436 printf ("r %f %d %d\n",
437 GetTime() - session
.epochTime
,
439 seq
- session
.irs
+ datalen
);
444 /* Check if packet has the ECN_ECHO flag set */
445 if (history
[session
.hsz
- 1].ecn_echo
) {
449 if ((p
->ip
->ip_tos
& 0x17) == 0) {
452 if ((p
->ip
->ip_tos
& 0x17) == 1) {
455 if ((p
->ip
->ip_tos
& 0x17) == 2) {
458 if ((p
->ip
->ip_tos
& 0x17) == 3) {
462 if(session
.maxseqseen
< seq
+ datalen
- 1) {
463 session
.maxseqseen
= seq
+ datalen
- 1;
466 if (reordered(p
) != 1) {
467 session
.num_unwanted_drops
+= 1;
472 /* from TCP/IP vol. 2, p 808 */
473 if (SEQ_LEQ(session
.rcv_nxt
, seq
) &&
474 SEQ_LT(seq
, (session
.rcv_nxt
+ session
.rcv_wnd
)) &&
475 SEQ_LEQ(session
.rcv_nxt
, (seq
+ datalen
)) &&
476 SEQ_LT((seq
+datalen
-1), (session
.rcv_nxt
+ session
.rcv_wnd
))) {
478 start
= seq
- session
.irs
;
479 end
= start
+ datalen
;
481 for (i
= start
; i
< end
; i
++) {
482 session
.dataRcvd
[i
] = 1 ;
485 start
= session
.rcv_nxt
- session
.irs
;
486 end
= session
.mss
* session
.maxpkts
;
488 for (i
= start
; i
< end
; i
++) {
489 if (session
.dataRcvd
[i
] == 0) {
497 if (session
.verbose
) {
498 printf ("a %f %d\n", GetTime() - session
.epochTime
,
499 session
.rcv_nxt
- session
.irs
);
501 ackpkt
= AllocateIPPacket(0, 0, 0, "NewECN (ACK)");
502 if ((p
->ip
->ip_tos
& 0x17) == 3) {
503 tcp_flags
= TCPFLAGS_ACK
| TCPFLAGS_ECN_ECHO
;
505 tcp_flags
= TCPFLAGS_ACK
;
508 if (send_cwr
== 2 && send_ece
< 2) {
509 /* Send ECE as if a CE was received, we have to get CWR back */
511 tcp_flags
|= TCPFLAGS_ECN_ECHO
;
514 SendSessionPacket (ackpkt
,
515 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
),
519 if (send_cwr
== 0 && (p
->tcp
->tcp_flags
& TCPFLAGS_ECN_ECHO
)) {
520 /* Send CWR atleast once if ECN ECHO is set */
522 struct IPPacket
*datapkt
;
524 char data
[MAXREQUESTLEN
];
527 datalen
= PrepareRequest(data
, NULL
);
528 datapkt
= AllocateIPPacket(0, 0, datalen
+ 1, "ECN (datapkt)");
529 dataptr
= (char *)datapkt
->tcp
+ sizeof(struct TcpHeader
);
530 memcpy((void *)dataptr
, (void *)data
, datalen
);
531 ipsz
= sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) +
534 SendSessionPacket(datapkt
, ipsz
,
535 TCPFLAGS_PSH
| TCPFLAGS_ACK
| TCPFLAGS_CWR
, 0, 0, 2);
537 session
.snd_nxt
+= (datalen
+ 1);
539 FreeIPPacket(&datapkt
);
542 if (send_cwr
== 1 && !(p
->tcp
->tcp_flags
& TCPFLAGS_ECN_ECHO
)) {
543 /* ECE was reset in response to CWR, move to the next state of probing */
547 if (send_ece
== 1 && (p
->tcp
->tcp_flags
& TCPFLAGS_CWR
)) {
548 /* Received CWR in response to ECE */
552 if (SEQ_GT(ntohl(p
->tcp
->tcp_ack
), session
.snd_una
))
553 session
.snd_una
= ntohl(p
->tcp
->tcp_ack
);
554 if (SEQ_LT(session
.snd_nxt
, session
.snd_una
))
555 session
.snd_nxt
= session
.snd_una
;
558 /* Increment sequence number for FIN rcvd */
560 if (ECT_01
== 0 && ECT_10
== 0) {
561 printf("Never received ECT(0) or ECT(1) in ToS field: FAIL\n");
564 /* If we received more than 3 CE, flag it as an error */
565 printf("Received too many ECT_CE (%d): FAIL\n", ECT_11
);
567 printf ("Totdata = %d ECN_ECHO: %d ECT00: %d ECT01: %d ECT10: %d ECT11: %d drops: %d\n",
568 session
.rcv_nxt
- session
.irs
, ECN_ECHO
, ECT_00
,
569 ECT_01
, ECT_10
, ECT_11
, session
.num_unwanted_drops
);
571 SendSessionPacket (ackpkt
,
572 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
),
583 int sr
= 0; /* sr=1: SYN/ACK rcvd */
584 int se
= 0; /* se=0: no CWR/no ECHO; se=1: no CWR/ECHO; se=2: CWR/ECHO */
585 int ar
= 0; /* ar=0: no ACK rcvd; ar=1: ACK rcvd */
586 int ae
= 0; /* ae=0: ACK/no ECHO; ae=1: ACK/ECHO */
587 int we
= 0; /* we=0: no ECHO; we=1 ECHO/CWR; we=2 ECHO/CWR/ECHO stop */
588 int ee
= 0; /* ee=0 never sent ECE; ee=1 sent ECE; ee=2 ECE / CWR */
590 for (i
= 0 ; i
< session
.hsz
; i
++) {
591 if ((history
[i
].type
== RCVD
) && (history
[i
].syn
== 1) &&
592 (history
[i
].ack
== 1)) {
594 if (history
[i
].ecn_echo
== 1) {
596 if (history
[i
].cwr
== 1) {
603 for (i
= 0 ; i
< session
.hsz
; i
++) {
604 if (history
[i
].type
== RCVD
&& history
[i
].syn
== 0 &&
605 history
[i
].ack
== 1) {
607 if (history
[i
].ecn_echo
== 1) {
613 for (i
= 0; i
< session
.hsz
; i
++) {
614 if (history
[i
].type
== SENT
&& history
[i
].dlen
> 0 &&
615 history
[i
].cwr
== 1) {
619 if (we
== 1 && history
[i
].type
== RCVD
&& history
[i
].ecn_echo
== 0) {
623 if (we
== 2 && history
[i
].type
== RCVD
&& history
[i
].ecn_echo
== 1) {
629 for (i
= 0; i
< session
.hsz
; i
++) {
630 if (history
[i
].type
== SENT
&& history
[i
].ecn_echo
== 1) {
634 if (ee
== 1 && history
[i
].type
== RCVD
&& history
[i
].dlen
> 0 &&
635 history
[i
].cwr
== 1) {
636 /* Received cwr in response to ECE */
642 printf ("sr=%d se=%d ar=%d ae=%d we=%d\n", sr
, se
, ar
, ae
, we
);
645 printf("No SYN/ACK received from server\n");
648 printf("SYN/ACK received: PASS \n");
651 printf("Unknown value for sr: %d\n", sr
);
656 printf("No CWR or ECE on SYN/ACK, server does not support ECN\n");
659 printf("ECE flag set on SYN/ACK, server supports ECN: PASS\n");
662 printf("Both CWR and ECE set on SYN/ACK, incompatible SYN/ACK\n");
665 printf("Unknown value for se: %d\n", se
);
671 printf("No ACK received\n");
674 printf("ACK received: PASS\n");
677 printf("Unknown value for ar: %d\n", ar
);
683 printf("Received ACKS but never ECE\n");
686 printf("Received ACKs with ECE, in response to simulated CE bit: PASS\n");
689 printf("Unknown value for ae: %d\n", ae
);
695 printf("Never received ECE\n");
698 printf("Received ECE and sent CWR\n");
701 printf("Received ECE, sent CWR and stopped receiving ECE afterwards: PASS\n");
704 printf("Unknown value for we: %d\n", we
);
710 printf("Never sent ECE\n");
713 printf("Sent ECE to simulate receiving CE \n");
716 printf("Sent ECE and received CWR in response: PASS\n");
719 printf("Unknown value for ee: %d\n", ee
);
725 void DataPktPathCheck(char *filename
, u_int8_t iptos
, u_int8_t tcp_flags
)
727 struct IPPacket
*p
, *datapkt
;
728 struct pcap_pkthdr pi
;
732 u_int16_t lastSeqSent
= session
.snd_nxt
;
733 double startTime
= 0;
735 char data
[MAXREQUESTLEN
];
738 unsigned int init_ttl
;
740 datalen
= PrepareRequest (data
, filename
);
742 datapkt
= AllocateIPPacket(0, 0, datalen
+ 1, "ECN (datapkt)");
744 dataptr
= (char *)datapkt
->tcp
+ sizeof(struct TcpHeader
);
745 memcpy((void *)dataptr
,(void *)data
, datalen
);
747 ipsz
= sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + datalen
+ 1;
748 /* send the data packet
749 * we try to "achieve" reliability by
750 * sending the packet upto 5 times, wating for
751 * 2 seconds between packets
760 session
.curr_ttl
= ++init_ttl
;
761 if (init_ttl
> 64) /* reached the max */
763 SendSessionPacket(datapkt
, ipsz
,
764 TCPFLAGS_PSH
| TCPFLAGS_ACK
| tcp_flags
, 0, 0, 0x3);
766 startTime
= GetTime();
771 /* Check if we have received any packets */
772 if ((read_packet
=(char *)CaptureGetPacket(&pi
)) != NULL
) {
774 p
= (struct IPPacket
*)FindHeaderBoundaries(read_packet
);
777 * packet that we sent?
780 if (INSESSION(p
,session
.src
, session
.sport
,
781 session
.dst
,session
.dport
) &&
782 (p
->tcp
->tcp_flags
== (TCPFLAGS_PSH
| TCPFLAGS_ACK
)) &&
783 SEQ_GT(ntohl(p
->tcp
->tcp_seq
), lastSeqSent
) &&
784 SEQ_LEQ(ntohl(p
->tcp
->tcp_ack
), session
.rcv_nxt
)) {
785 lastSeqSent
= ntohl(p
->tcp
->tcp_seq
);
786 if (session
.debug
>= SESSION_DEBUG_LOW
) {
787 printf("xmit %d\n", i
);
791 session
.snd_nxt
+= datalen
+ 1;
792 session
.totSeenSent
++ ;
799 if (INSESSION(p
, session
.dst
, session
.dport
, session
.src
,
800 session
.sport
) && (p
->tcp
->tcp_flags
& TCPFLAGS_ACK
) &&
801 (ntohl(p
->tcp
->tcp_seq
) == session
.rcv_nxt
) &&
802 ntohl(p
->tcp
->tcp_ack
) == session
.snd_nxt
) {
803 session
.snd_una
= ntohl(p
->tcp
->tcp_ack
);
804 session
.snd_nxt
= session
.snd_una
;
805 if (p
->ip
->ip_ttl
!= session
.ttl
) {
806 session
.ttl
= p
->ip
->ip_ttl
;
808 if (session
.debug
>= SESSION_DEBUG_LOW
) {
809 printf("rcvd %d\n", i
);
819 if (p
->ip
->ip_p
== IPPROTOCOL_ICMP
) {
821 struct IcmpHeader
*icmp
;
822 ip_hl
= (p
->ip
->ip_vhl
& 0x0f) << 2;
825 icmp
= (struct IcmpHeader
*)((char *)p
->ip
+ ip_hl
);
826 nexthdr
= (void *)icmp
;
827 if (icmp
->icmp_type
== ICMP_TIMXCEED
) {
828 struct IpHeader off_ip
;
829 struct TcpHeader off_tcp
;
831 bzero(&off_ip
, sizeof(struct IpHeader
));
832 nexthdr
= nexthdr
+ sizeof(struct IcmpHeader
);
833 memcpy((void *)&off_ip
, nexthdr
,
834 sizeof(struct IpHeader
));
835 nexthdr
+= sizeof(struct IpHeader
);
837 bzero(&off_tcp
, sizeof(struct TcpHeader
));
838 memcpy(&off_tcp
, nexthdr
, 4);
839 if (session
.src
== off_ip
.ip_src
&&
840 session
.dst
== off_ip
.ip_dst
) {
841 printf("Received ICMP TTL exceeded from %s:"
842 "ttl used %u ip_tos 0x%x sport %u dport %u\n",
843 InetAddress(p
->ip
->ip_src
), init_ttl
, off_ip
.ip_tos
,
844 ntohs(off_tcp
.tcp_sport
), ntohs(off_tcp
.tcp_dport
));
849 * otherwise, this is a bad packet
852 //processBadPacket(p);
854 if ((GetTime() - startTime
>= 1) && (sendflag
== 0)) {
856 session
.snd_nxt
= session
.snd_una
;
860 FreeIPPacket(&datapkt
);
862 void ECNPathCheckTest(u_int32_t sourceAddress
, u_int16_t sourcePort
,
863 u_int32_t targetAddress
, u_int16_t targetPort
, int mss
)
865 int rawSocket
, rc
, flag
;
869 session
.src
= sourceAddress
;
870 session
.sport
= sourcePort
;
871 session
.dst
= targetAddress
;
872 session
.dport
= targetPort
;
873 session
.rcv_wnd
= 5*mss
;
874 session
.snd_nxt
= arc4random();
875 session
.iss
= session
.snd_nxt
;
879 session
.maxseqseen
= 0;
880 session
.epochTime
= GetTime();
881 session
.maxpkts
= 1000;
884 if ((session
.dataRcvd
= (u_int8_t
*)calloc(sizeof(u_int8_t
),
885 mss
* session
.maxpkts
)) == NULL
) {
886 printf("no memory to store data, error: %d \n", ERR_MEM_ALLOC
);
890 if ((rawSocket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0) {
891 perror("ERROR: couldn't open socket:");
892 Quit(ERR_SOCKET_OPEN
);
896 if (setsockopt(rawSocket
, IPPROTO_IP
, IP_HDRINCL
,
897 (char *)&flag
, sizeof(flag
)) < 0) {
898 perror("ERROR: couldn't set raw socket options:");
902 session
.socket
= rawSocket
;
904 /* Establish a TCP connections with ECN bits */
905 rc
= EstablishTcpConnection(TCPFLAGS_ECN_ECHO
| TCPFLAGS_CWR
, 0);
907 case ESTABLISH_FAILURE_EARLY_RST
:
909 /* Received a RST when ECN bits are used. Try again without ECN */
910 rc
= EstablishTcpConnection(0, 0);
911 if (rc
== ESTABLISH_FAILURE_EARLY_RST
) {
912 printf("Received RST with or without ECN negotiation\n");
913 printf("The server might not be listening on this port\n");
915 } else if (rc
== ESTABLISH_SUCCESS
) {
916 printf("Received RST with ECN.\n");
917 printf("Connection established successfully without ECN\n");
919 } else if (rc
== ESTABLISH_FAILURE_NO_REPLY
) {
920 printf("Received RST with ECN\n");
921 printf("Exceed max SYN retransmits without ECN\n");
926 case ESTABLISH_FAILURE_NO_REPLY
:
928 /* No reply after retring, try again without ECN */
929 rc
= EstablishTcpConnection(0, 0);
930 if (rc
== ESTABLISH_FAILURE_EARLY_RST
) {
931 printf("Exceeded max SYN retransmits with ECN\n");
932 printf("Received RST without ECN\n");
934 } else if (rc
== ESTABLISH_FAILURE_NO_REPLY
) {
935 printf("Exceeded max SYN retransmits with ECN\n");
936 printf("Exceeded max SYN retransmits without ECN\n");
939 printf("Exceeded max SYN retransmits with ECN\n");
940 printf("Connection established successfully without ECN\n");
947 DataPktPathCheck(session
.filename
, 3, 0);
953 SynTest(u_int32_t sourceAddress
, u_int16_t sourcePort
,
954 u_int32_t targetAddress
, u_int16_t targetPort
, int mss
, int syn_reply
)
957 struct IPPacket
*synPacket
= NULL
, *ackPacket
= NULL
;
959 struct pcap_pkthdr pi
;
960 int synAckReceived
= 0;
961 int numRetransmits
= 0;
963 int tcpoptlen
= 4; /* For negotiating MSS */
964 u_int8_t
*opt
= NULL
;
965 struct IPPacket
*p
= NULL
;
969 session
.src
= sourceAddress
;
970 session
.sport
= sourcePort
;
971 session
.dst
= targetAddress
;
972 session
.dport
= targetPort
;
973 session
.rcv_wnd
= 5*mss
;
974 session
.snd_nxt
= arc4random();
975 session
.iss
= session
.snd_nxt
;
979 session
.maxseqseen
= 0;
980 session
.epochTime
= GetTime();
981 session
.maxpkts
= 1000;
983 if ((session
.dataRcvd
= (u_int8_t
*)calloc(sizeof(u_int8_t
),
984 mss
* session
.maxpkts
)) == NULL
) {
985 printf("no memory to store data, error: %d \n", ERR_MEM_ALLOC
);
989 if ((rawSocket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0) {
990 perror("ERROR: couldn't open socket:");
991 Quit(ERR_SOCKET_OPEN
);
995 if (setsockopt(rawSocket
, IPPROTO_IP
, IP_HDRINCL
,
996 (char *)&flag
, sizeof(flag
)) < 0) {
997 perror("ERROR: couldn't set raw socket options:");
1001 session
.socket
= rawSocket
;
1004 /* allocate the syn packet -- Changed for new IPPacket structure */
1005 synPacket
= AllocateIPPacket(0, tcpoptlen
, 0, "ECN (SYN)");
1006 opt
= (((u_int8_t
*)synPacket
->tcp
) + sizeof(struct TcpHeader
));
1007 opt
[0] = (u_int8_t
)TCPOPT_MAXSEG
;
1008 opt
[1] = (u_int8_t
)TCPOLEN_MAXSEG
;
1009 *((u_int16_t
*)((u_int8_t
*)opt
+ 2)) = htons(session
.mss
);
1011 SendSessionPacket(synPacket
,
1012 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + tcpoptlen
,
1013 TCPFLAGS_SYN
, 0, tcpoptlen
, 0);
1014 timeoutTime
= GetTime() + 1;
1017 * Wait for SYN/ACK and retransmit SYN if appropriate
1018 * not great, but it gets the job done
1021 while(!synAckReceived
&& numRetransmits
< 3) {
1022 while(GetTime() < timeoutTime
) {
1023 /* Have we captured any packets? */
1024 if ((read_packet
= (char *)CaptureGetPacket(&pi
)) != NULL
) {
1025 p
= (struct IPPacket
*)FindHeaderBoundaries(read_packet
);
1026 /* Received a packet from us to them */
1027 if (INSESSION(p
, session
.src
, session
.sport
,
1028 session
.dst
, session
.dport
)) {
1029 /* Is it a SYN/ACK? */
1030 if (p
->tcp
->tcp_flags
& TCPFLAGS_SYN
) {
1031 if (session
.debug
>= SESSION_DEBUG_LOW
) {
1035 session
.totSeenSent
++ ;
1037 processBadPacket(p
);
1042 /* Received a packet from them to us */
1043 if (INSESSION(p
, session
.dst
, session
.dport
, session
.src
,
1045 /* Is it a SYN/ACK? */
1046 if ((p
->tcp
->tcp_flags
& TCPFLAGS_SYN
) &&
1047 (p
->tcp
->tcp_flags
& TCPFLAGS_ACK
)) {
1048 timeoutTime
= GetTime(); /* force exit */
1050 if (session
.debug
>= SESSION_DEBUG_LOW
) {
1056 * Save ttl for,admittedly poor,indications of reverse
1059 session
.ttl
= p
->ip
->ip_ttl
;
1060 session
.snd_wnd
= ntohl(p
->tcp
->tcp_win
);
1064 if ((p
->tcp
->tcp_flags
)& (TCPFLAGS_RST
)) {
1065 printf ("ERROR: EARLY_RST\n");
1073 if (!synAckReceived
) {
1074 if (session
.debug
>= SESSION_DEBUG_LOW
) {
1075 printf("SYN timeout. Retransmitting\n");
1077 SendSessionPacket(synPacket
,
1078 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + tcpoptlen
,
1079 TCPFLAGS_SYN
, 0, tcpoptlen
, 0);
1080 timeoutTime
= GetTime() + 1;
1085 if (numRetransmits
>= 3) {
1086 printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
1090 if (session
.debug
>= SESSION_DEBUG_LOW
)
1091 printf("Received SYN-ACK\n");
1092 if (syn_reply
!= 0) {
1093 /* Update session variables */
1094 session
.irs
= ntohl(p
->tcp
->tcp_seq
);
1095 session
.dataRcvd
[0] = 1 ;
1096 session
.rcv_nxt
= session
.irs
+ 1; /* SYN/ACK takes up a byte of seq space */
1097 session
.snd_nxt
= session
.iss
+ 1; /* SYN takes up a byte of seq space */
1098 session
.snd_una
= session
.iss
+ 1;
1099 session
.maxseqseen
= ntohl(p
->tcp
->tcp_seq
);
1100 session
.initSession
= 1;
1101 if (session
.debug
>= SESSION_DEBUG_LOW
) {
1102 printf("try to send the %s\n", syn_reply
== TCPFLAGS_ACK
? "third Ack" : "RST");
1103 printf("src = %s:%d (%u)\n", InetAddress(session
.src
),
1104 session
.sport
, session
.iss
);
1105 printf("dst = %s:%d (%u)\n",InetAddress(session
.dst
),
1106 session
.dport
, session
.irs
);
1109 /* allocate the syn packet -- Changed for new IPPacket structure */
1110 ackPacket
= AllocateIPPacket(0, 0, 0, "SYN reply");
1112 SendSessionPacket(ackPacket
,
1113 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
),
1114 syn_reply
, 0, 0, 0);
1115 FreeIPPacket(&ackPacket
);
1118 FreeIPPacket(&synPacket
);