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
;
77 /* allocate the syn packet -- Changed for new IPPacket structure */
78 synPacket
= AllocateIPPacket(0, tcpoptlen
, 0, "ECN (SYN)");
79 opt
= (((u_int8_t
*)synPacket
->tcp
) + sizeof(struct TcpHeader
));
80 opt
[0] = (u_int8_t
)TCPOPT_MAXSEG
;
81 opt
[1] = (u_int8_t
)TCPOLEN_MAXSEG
;
82 *((u_int16_t
*)((u_int8_t
*)opt
+ 2)) = htons(session
.mss
);
84 SendSessionPacket(synPacket
,
85 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + tcpoptlen
,
86 TCPFLAGS_SYN
| syn_flags
, 0, tcpoptlen
, ip_tos
);
87 timeoutTime
= GetTime() + 1;
90 * Wait for SYN/ACK and retransmit SYN if appropriate
91 * not great, but it gets the job done
94 while(!synAckReceived
&& numRetransmits
< 3) {
95 while(GetTime() < timeoutTime
) {
96 /* Have we captured any packets? */
97 if ((read_packet
= (char *)CaptureGetPacket(&pi
)) != NULL
) {
98 p
= (struct IPPacket
*)FindHeaderBoundaries(read_packet
);
99 /* Received a packet from us to them */
100 if (INSESSION(p
, session
.src
, session
.sport
,
101 session
.dst
, session
.dport
)) {
102 /* Is it a SYN/ACK? */
103 if (p
->tcp
->tcp_flags
& TCPFLAGS_SYN
) {
104 if (session
.debug
>= SESSION_DEBUG_LOW
) {
108 session
.totSeenSent
++ ;
115 /* Received a packet from them to us */
116 if (INSESSION(p
, session
.dst
, session
.dport
, session
.src
,
118 /* Is it a SYN/ACK? */
119 if ((p
->tcp
->tcp_flags
& TCPFLAGS_SYN
) &&
120 (p
->tcp
->tcp_flags
& TCPFLAGS_ACK
)) {
121 timeoutTime
= GetTime(); /* force exit */
123 if (session
.debug
>= SESSION_DEBUG_LOW
) {
129 * Save ttl for,admittedly poor,indications of reverse
132 session
.ttl
= p
->ip
->ip_ttl
;
133 session
.snd_wnd
= ntohl(p
->tcp
->tcp_win
);
137 if ((p
->tcp
->tcp_flags
)& (TCPFLAGS_RST
)) {
138 printf ("ERROR: EARLY_RST\n");
139 return(ESTABLISH_FAILURE_EARLY_RST
);
146 if (!synAckReceived
) {
147 if (session
.debug
>= SESSION_DEBUG_LOW
) {
148 printf("SYN timeout. Retransmitting\n");
150 SendSessionPacket(synPacket
,
151 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + tcpoptlen
,
152 TCPFLAGS_SYN
| syn_flags
, 0, tcpoptlen
, ip_tos
);
153 timeoutTime
= GetTime() + 1;
158 if (numRetransmits
>= 3) {
159 printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
161 return(ESTABLISH_FAILURE_NO_REPLY
);
163 if (session
.debug
>= SESSION_DEBUG_LOW
)
164 printf("Received SYN-ACK, try to send the third Ack\n");
165 /* Update session variables */
166 session
.irs
= ntohl(p
->tcp
->tcp_seq
);
167 session
.dataRcvd
[0] = 1 ;
168 session
.rcv_nxt
= session
.irs
+ 1; /* SYN/ACK takes up a byte of seq space */
169 session
.snd_nxt
= session
.iss
+ 1; /* SYN takes up a byte of seq space */
170 session
.snd_una
= session
.iss
+ 1;
171 session
.maxseqseen
= ntohl(p
->tcp
->tcp_seq
);
172 session
.initSession
= 1;
173 if (session
.debug
>= SESSION_DEBUG_LOW
) {
174 printf("src = %s:%d (%u)\n", InetAddress(session
.src
),
175 session
.sport
, session
.iss
);
176 printf("dst = %s:%d (%u)\n",InetAddress(session
.dst
),
177 session
.dport
, session
.irs
);
180 /* allocate the syn packet -- Changed for new IPPacket structure */
181 ackPacket
= AllocateIPPacket(0, 0, 0, "Third ACK");
183 SendSessionPacket(ackPacket
,
184 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
),
185 TCPFLAGS_ACK
, 0, 0, 0);
186 FreeIPPacket(&synPacket
);
187 FreeIPPacket(&ackPacket
);
188 return(ESTABLISH_SUCCESS
);
191 void ECNTest(u_int32_t sourceAddress
, u_int16_t sourcePort
,
192 u_int32_t targetAddress
, u_int16_t targetPort
, int mss
)
194 int rawSocket
, rc
, flag
= 1;
198 session
.src
= sourceAddress
;
199 session
.sport
= sourcePort
;
200 session
.dst
= targetAddress
;
201 session
.dport
= targetPort
;
202 session
.rcv_wnd
= 5*mss
;
203 /* random initial sequence number */
204 session
.snd_nxt
= arc4random();
205 session
.iss
= session
.snd_nxt
;
209 session
.maxseqseen
= 0;
210 session
.epochTime
= GetTime ();
211 session
.maxpkts
= 1000;
212 /* session.debug = SESSION_DEBUG_LOW; */
214 if ((session
.dataRcvd
= (u_int8_t
*)calloc(sizeof(u_int8_t
),
215 mss
* session
.maxpkts
)) == NULL
) {
216 printf("no memmory to store data:\nRETURN CODE: %d",
221 if ((rawSocket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0) {
222 perror("ERROR: couldn't open socket:");
223 Quit(ERR_SOCKET_OPEN
);
226 if (setsockopt(rawSocket
, IPPROTO_IP
, IP_HDRINCL
,
227 (char *)&flag
, sizeof(flag
)) < 0) {
228 perror("ERROR: couldn't set raw socket options:");
232 session
.socket
= rawSocket
;
234 /* Establish a TCP connections with ECN bits */
235 rc
= EstablishTcpConnection(TCPFLAGS_ECN_ECHO
| TCPFLAGS_CWR
, 0);
237 case ESTABLISH_FAILURE_EARLY_RST
:
239 /* Received a RST when ECN bits are used. Try again without ECN */
240 rc
= EstablishTcpConnection(0, 0);
241 if (rc
== ESTABLISH_FAILURE_EARLY_RST
) {
242 printf("Received RST with or without ECN negotiation\n");
243 printf("The server might not be listening on this port\n");
245 } else if (rc
== ESTABLISH_SUCCESS
) {
246 printf("Received RST with ECN.\n");
247 printf("Connection established successfully without ECN\n");
249 } else if (rc
== ESTABLISH_FAILURE_NO_REPLY
) {
250 printf("Received RST with ECN\n");
251 printf("Exceed max SYN retransmits without ECN\n");
256 case ESTABLISH_FAILURE_NO_REPLY
:
258 /* No reply after retring, try again without ECN */
259 rc
= EstablishTcpConnection(0, 0);
260 if (rc
== ESTABLISH_FAILURE_EARLY_RST
) {
261 printf("Exceeded max SYN retransmits with ECN\n");
262 printf("Received RST without ECN\n");
264 } else if (rc
== ESTABLISH_FAILURE_NO_REPLY
) {
265 printf("Exceeded max SYN retransmits with ECN\n");
266 printf("Exceeded max SYN retransmits without ECN\n");
269 printf("Exceeded max SYN retransmits with ECN\n");
270 printf("Connection established successfully without ECN\n");
277 /* Test for propogation of CE correctly */
278 DataPkt(session
.filename
, 3, 0);
284 void DataPkt (char *filename
, u_int8_t iptos
, u_int8_t tcp_flags
)
286 struct IPPacket
*p
, *datapkt
;
287 struct pcap_pkthdr pi
;
291 u_int16_t lastSeqSent
= session
.snd_nxt
;
292 double startTime
= 0;
294 char data
[MAXREQUESTLEN
];
298 datalen
= PrepareRequest (data
, filename
);
300 datapkt
= AllocateIPPacket(0, 0, datalen
+ 1, "ECN (datapkt)");
302 dataptr
= (char *)datapkt
->tcp
+ sizeof(struct TcpHeader
);
303 memcpy((void *)dataptr
,(void *)data
, datalen
);
305 ipsz
= sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) + datalen
+ 1;
307 /* send the data packet
308 * we try to "achieve" reliability by
309 * sending the packet upto 5 times, wating for
310 * 2 seconds between packets
318 SendSessionPacket(datapkt
, ipsz
,
319 TCPFLAGS_PSH
| TCPFLAGS_ACK
| tcp_flags
, 0, 0, iptos
);
321 startTime
= GetTime();
326 /* Check if we have received any packets */
327 if ((read_packet
=(char *)CaptureGetPacket(&pi
)) != NULL
) {
329 p
= (struct IPPacket
*)FindHeaderBoundaries(read_packet
);
332 * packet that we sent?
335 if (INSESSION(p
,session
.src
, session
.sport
,
336 session
.dst
,session
.dport
) &&
337 (p
->tcp
->tcp_flags
== (TCPFLAGS_PSH
| TCPFLAGS_ACK
)) &&
338 SEQ_GT(ntohl(p
->tcp
->tcp_seq
), lastSeqSent
) &&
339 SEQ_LEQ(ntohl(p
->tcp
->tcp_ack
), session
.rcv_nxt
)) {
340 lastSeqSent
= ntohl(p
->tcp
->tcp_seq
);
341 if (session
.debug
>= SESSION_DEBUG_LOW
) {
342 printf("xmit %d\n", i
);
346 session
.snd_nxt
+= datalen
+ 1;
347 session
.totSeenSent
++ ;
354 if (INSESSION(p
, session
.dst
, session
.dport
, session
.src
,
355 session
.sport
) && (p
->tcp
->tcp_flags
& TCPFLAGS_ACK
) &&
356 (ntohl(p
->tcp
->tcp_seq
) == session
.rcv_nxt
) &&
357 SEQ_GT(ntohl(p
->tcp
->tcp_ack
), session
.snd_una
)) {
358 session
.snd_una
= ntohl(p
->tcp
->tcp_ack
);
359 session
.snd_nxt
= session
.snd_una
;
360 if (p
->ip
->ip_ttl
!= session
.ttl
) {
361 session
.ttl
= p
->ip
->ip_ttl
;
363 if (session
.debug
>= SESSION_DEBUG_LOW
) {
364 printf("rcvd %d\n", i
);
372 * otherwise, this is a bad packet
375 //processBadPacket(p);
377 if ((GetTime() - startTime
>= 1) && (sendflag
== 0) && (i
< 3)) {
381 printf ("ERROR: sent request 3 times without response\n");
386 FreeIPPacket(&datapkt
);
388 /* process any response by sending Acks */
389 rcvData (ECNAckData
);
392 void ECNAckData (struct IPPacket
*p
)
395 uint32 seq
= history
[session
.hsz
- 1].seqno
;
396 uint16 datalen
= history
[session
.hsz
- 1].dlen
;
397 int fin
= history
[session
.hsz
- 1].fin
;
398 int rst
= history
[session
.hsz
- 1].rst
;
400 struct IPPacket
*ackpkt
= NULL
;
401 static int ECT_00
= 0;
402 static int ECT_01
= 0;
403 static int ECT_10
= 0;
404 static int ECT_11
= 0;
405 static int ECN_ECHO
= 0;
406 static int send_cwr
= 0;
407 static int send_ece
= 0;
412 * ECN_ECHO: counts packets with TCP header ECN bit set
413 * ECT_XX: counts packets with ECT codepoint XX (IP)
416 if (datalen
> session
.mss
) {
417 printf ("ERROR: mss=%d datalen=%d\nRETURN CODE: %d\n",
418 session
.mss
, datalen
, MSS_ERR
);
423 char *http_code
= (char *)calloc(4, sizeof(char));
424 if (seq
- session
.irs
== 1) {
425 /* Response to request packet --> check HTTP response code */
426 memcpy(http_code
, ((char *)(p
->tcp
) + sizeof(struct TcpHeader
) +
427 history
[session
.hsz
- 1].optlen
+ 9), 3);
428 if (strncmp(http_code
, HTTP_OK
, 3) != 0) {
429 printf("HTTP ERROR - HTTP RESPONSE CODE: %s\nRETURN CODE: %d\n",
430 http_code
, atoi(http_code
));
431 Quit(atoi(http_code
));
435 session
.totDataPktsRcvd
++;
437 if (session
.verbose
) {
438 printf ("r %f %d %d\n",
439 GetTime() - session
.epochTime
,
441 seq
- session
.irs
+ datalen
);
446 /* Check if packet has the ECN_ECHO flag set */
447 if (history
[session
.hsz
- 1].ecn_echo
) {
451 if ((p
->ip
->ip_tos
& 0x17) == 0) {
454 if ((p
->ip
->ip_tos
& 0x17) == 1) {
457 if ((p
->ip
->ip_tos
& 0x17) == 2) {
460 if ((p
->ip
->ip_tos
& 0x17) == 3) {
464 if(session
.maxseqseen
< seq
+ datalen
- 1) {
465 session
.maxseqseen
= seq
+ datalen
- 1;
468 if (reordered(p
) != 1) {
469 session
.num_unwanted_drops
+= 1;
474 /* from TCP/IP vol. 2, p 808 */
475 if (SEQ_LEQ(session
.rcv_nxt
, seq
) &&
476 SEQ_LT(seq
, (session
.rcv_nxt
+ session
.rcv_wnd
)) &&
477 SEQ_LEQ(session
.rcv_nxt
, (seq
+ datalen
)) &&
478 SEQ_LT((seq
+datalen
-1), (session
.rcv_nxt
+ session
.rcv_wnd
))) {
480 start
= seq
- session
.irs
;
481 end
= start
+ datalen
;
483 for (i
= start
; i
< end
; i
++) {
484 session
.dataRcvd
[i
] = 1 ;
487 start
= session
.rcv_nxt
- session
.irs
;
488 end
= session
.mss
* session
.maxpkts
;
490 for (i
= start
; i
< end
; i
++) {
491 if (session
.dataRcvd
[i
] == 0) {
499 if (session
.verbose
) {
500 printf ("a %f %d\n", GetTime() - session
.epochTime
,
501 session
.rcv_nxt
- session
.irs
);
503 ackpkt
= AllocateIPPacket(0, 0, 0, "NewECN (ACK)");
504 if ((p
->ip
->ip_tos
& 0x17) == 3) {
505 tcp_flags
= TCPFLAGS_ACK
| TCPFLAGS_ECN_ECHO
;
507 tcp_flags
= TCPFLAGS_ACK
;
510 if (send_cwr
== 2 && send_ece
< 2) {
511 /* Send ECE as if a CE was received, we have to get CWR back */
513 tcp_flags
|= TCPFLAGS_ECN_ECHO
;
516 SendSessionPacket (ackpkt
,
517 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
),
521 if (send_cwr
== 0 && (p
->tcp
->tcp_flags
& TCPFLAGS_ECN_ECHO
)) {
522 /* Send CWR atleast once if ECN ECHO is set */
524 struct IPPacket
*datapkt
;
526 char data
[MAXREQUESTLEN
];
529 datalen
= PrepareRequest(data
, NULL
);
530 datapkt
= AllocateIPPacket(0, 0, datalen
+ 1, "ECN (datapkt)");
531 dataptr
= (char *)datapkt
->tcp
+ sizeof(struct TcpHeader
);
532 memcpy((void *)dataptr
, (void *)data
, datalen
);
533 ipsz
= sizeof(struct IpHeader
) + sizeof(struct TcpHeader
) +
536 SendSessionPacket(datapkt
, ipsz
,
537 TCPFLAGS_PSH
| TCPFLAGS_ACK
| TCPFLAGS_CWR
, 0, 0, 2);
540 FreeIPPacket(&datapkt
);
543 if (send_cwr
== 1 && !(p
->tcp
->tcp_flags
& TCPFLAGS_ECN_ECHO
)) {
544 /* ECE was reset in response to CWR, move to the next state of probing */
548 if (send_ece
== 1 && (p
->tcp
->tcp_flags
& TCPFLAGS_CWR
)) {
549 /* Received CWR in response to ECE */
553 if (SEQ_GT(ntohl(p
->tcp
->tcp_ack
), session
.snd_una
))
554 session
.snd_una
= ntohl(p
->tcp
->tcp_ack
);
555 if (SEQ_LT(session
.snd_nxt
, session
.snd_una
))
556 session
.snd_nxt
= session
.snd_una
;
559 /* Increment sequence number for FIN rcvd */
561 if (ECT_01
== 0 && ECT_10
== 0) {
562 printf("Never received ECT(0) or ECT(1) in ToS field: FAIL\n");
565 /* If we received more than 3 CE, flag it as an error */
566 printf("Received too many ECT_CE (%d): FAIL\n", ECT_11
);
568 printf ("Totdata = %d ECN_ECHO: %d ECT00: %d ECT01: %d ECT10: %d ECT11: %d drops: %d\n",
569 session
.rcv_nxt
- session
.irs
, ECN_ECHO
, ECT_00
,
570 ECT_01
, ECT_10
, ECT_11
, session
.num_unwanted_drops
);
572 SendSessionPacket (ackpkt
,
573 sizeof(struct IpHeader
) + sizeof(struct TcpHeader
),
584 int sr
= 0; /* sr=1: SYN/ACK rcvd */
585 int se
= 0; /* se=0: no CWR/no ECHO; se=1: no CWR/ECHO; se=2: CWR/ECHO */
586 int ar
= 0; /* ar=0: no ACK rcvd; ar=1: ACK rcvd */
587 int ae
= 0; /* ae=0: ACK/no ECHO; ae=1: ACK/ECHO */
588 int we
= 0; /* we=0: no ECHO; we=1 ECHO/CWR; we=2 ECHO/CWR/ECHO stop */
589 int ee
= 0; /* ee=0 never sent ECE; ee=1 sent ECE; ee=2 ECE / CWR */
591 for (i
= 0 ; i
< session
.hsz
; i
++) {
592 if ((history
[i
].type
== RCVD
) && (history
[i
].syn
== 1) &&
593 (history
[i
].ack
== 1)) {
595 if (history
[i
].ecn_echo
== 1) {
597 if (history
[i
].cwr
== 1) {
604 for (i
= 0 ; i
< session
.hsz
; i
++) {
605 if (history
[i
].type
== RCVD
&& history
[i
].syn
== 0 &&
606 history
[i
].ack
== 1) {
608 if (history
[i
].ecn_echo
== 1) {
614 for (i
= 0; i
< session
.hsz
; i
++) {
615 if (history
[i
].type
== SENT
&& history
[i
].dlen
> 0 &&
616 history
[i
].cwr
== 1) {
620 if (we
== 1 && history
[i
].type
== RCVD
&& history
[i
].ecn_echo
== 0) {
624 if (we
== 2 && history
[i
].type
== RCVD
&& history
[i
].ecn_echo
== 1) {
630 for (i
= 0; i
< session
.hsz
; i
++) {
631 if (history
[i
].type
== SENT
&& history
[i
].ecn_echo
== 1) {
635 if (ee
== 1 && history
[i
].type
== RCVD
&& history
[i
].dlen
> 0 &&
636 history
[i
].cwr
== 1) {
637 /* Received cwr in response to ECE */
643 printf ("sr=%d se=%d ar=%d ae=%d we=%d\n", sr
, se
, ar
, ae
, we
);
646 printf("No SYN/ACK received from server\n");
649 printf("SYN/ACK received: PASS \n");
652 printf("Unknown value for sr: %d\n", sr
);
657 printf("No CWR or ECE on SYN/ACK, server does not support ECN\n");
660 printf("ECE flag set on SYN/ACK, server supports ECN: PASS\n");
663 printf("Both CWR and ECE set on SYN/ACK, incompatible SYN/ACK\n");
666 printf("Unknown value for se: %d\n", se
);
672 printf("No ACK received\n");
675 printf("ACK received: PASS\n");
678 printf("Unknown value for ar: %d\n", ar
);
684 printf("Received ACKS but never ECE\n");
687 printf("Received ACKs with ECE, in response to simulated CE bit: PASS\n");
690 printf("Unknown value for ae: %d\n", ae
);
696 printf("Never received ECE\n");
699 printf("Received ECE and sent CWR\n");
702 printf("Received ECE, sent CWR and stopped receiving ECE afterwards: PASS\n");
705 printf("Unknown value for we: %d\n", we
);
711 printf("Never sent ECE\n");
714 printf("Sent ECE to simulate receiving CE \n");
717 printf("Sent ECE and received CWR in response: PASS\n");
720 printf("Unknown value for ee: %d\n", ee
);