]> git.saurik.com Git - apple/network_cmds.git/blame - ecnprobe/ecn.c
network_cmds-606.40.2.tar.gz
[apple/network_cmds.git] / ecnprobe / ecn.c
CommitLineData
89c4ed63
A
1/*
2 Copyright (c) 2000
3 International Computer Science Institute
4 All rights reserved.
5
6 This file may contain software code originally developed for the
7 Sting project. The Sting software carries the following copyright:
8
9 Copyright (c) 1998, 1999
10 Stefan Savage and the University of Washington.
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
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.
30
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
41 SUCH DAMAGE.
42*/
43#include <sys/types.h>
44#include <sys/param.h>
45#include <sys/time.h>
46#include <string.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <assert.h>
50#include "base.h"
51#include "inet.h"
52#include "session.h"
53#include "capture.h"
54#include "support.h"
55#include "history.h"
56#include "ecn.h"
57
58extern struct TcpSession session;
59extern struct History history[];
60
61#define ESTABLISH_SUCCESS 0
62#define ESTABLISH_FAILURE_EARLY_RST 1
63#define ESTABLISH_FAILURE_NO_REPLY 2
64int EstablishTcpConnection(u_int8_t syn_flags, u_int8_t ip_tos)
65{
66 struct IPPacket *synPacket = NULL, *ackPacket = NULL;
67 char *read_packet;
68 struct pcap_pkthdr pi;
69 int synAckReceived = 0;
70 int numRetransmits = 0;
71 double timeoutTime;
72 int tcpoptlen = 4; /* For negotiating MSS */
73 u_int8_t *opt = NULL;
74 struct IPPacket *p = NULL;
89c4ed63
A
75
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);
82
83 SendSessionPacket(synPacket,
84 sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
85 TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
86 timeoutTime = GetTime() + 1;
87
88 /*
89 * Wait for SYN/ACK and retransmit SYN if appropriate
90 * not great, but it gets the job done
91 */
92
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) {
104 PrintTcpPacket(p);
105 }
106 StorePacket(p);
107 session.totSeenSent++ ;
108 } else {
109 processBadPacket(p);
110 }
111 continue;
112 }
113
114 /* Received a packet from them to us */
115 if (INSESSION(p, session.dst, session.dport, session.src,
116 session.sport)) {
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 */
121 synAckReceived++;
122 if (session.debug >= SESSION_DEBUG_LOW) {
123 PrintTcpPacket(p);
124 }
125 StorePacket(p);
126
127 /*
128 * Save ttl for,admittedly poor,indications of reverse
129 * route change
130 */
131 session.ttl = p->ip->ip_ttl;
132 session.snd_wnd = ntohl(p->tcp->tcp_win);
133 session.totRcvd ++;
134 break;
135 } else {
136 if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
137 printf ("ERROR: EARLY_RST\n");
138 return(ESTABLISH_FAILURE_EARLY_RST);
139 }
140 }
141 }
142 }
143 }
144
145 if (!synAckReceived) {
146 if (session.debug >= SESSION_DEBUG_LOW) {
147 printf("SYN timeout. Retransmitting\n");
148 }
149 SendSessionPacket(synPacket,
150 sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
151 TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
152 timeoutTime = GetTime() + 1;
153 numRetransmits++;
154 }
155 }
156
157 if (numRetransmits >= 3) {
158 printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
159 NO_CONNECTION);
160 return(ESTABLISH_FAILURE_NO_REPLY);
161 }
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);
177 }
178
179 /* allocate the syn packet -- Changed for new IPPacket structure */
180 ackPacket = AllocateIPPacket(0, 0, 0, "Third ACK");
181 /* send an 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);
188}
189
190void ECNTest(u_int32_t sourceAddress, u_int16_t sourcePort,
191 u_int32_t targetAddress, u_int16_t targetPort, int mss)
192{
193 int rawSocket, rc, flag = 1;
194
195 arc4random_stir();
196
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;
205 session.rcv_nxt = 0;
206 session.irs = 0;
207 session.mss = mss;
208 session.maxseqseen = 0;
209 session.epochTime = GetTime ();
210 session.maxpkts = 1000;
211/* session.debug = SESSION_DEBUG_LOW; */
212 session.debug = 0;
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",
216 ERR_MEM_ALLOC);
217 Quit(ERR_MEM_ALLOC);
218 }
219
220 if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
221 perror("ERROR: couldn't open socket:");
222 Quit(ERR_SOCKET_OPEN);
223 }
224
225 if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
226 (char *)&flag, sizeof(flag)) < 0) {
227 perror("ERROR: couldn't set raw socket options:");
228 Quit(ERR_SOCKOPT);
229 }
230
231 session.socket = rawSocket;
232
233 /* Establish a TCP connections with ECN bits */
234 rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
235 switch (rc) {
236 case ESTABLISH_FAILURE_EARLY_RST:
237 {
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");
243 Quit(EARLY_RST);
244 } else if (rc == ESTABLISH_SUCCESS) {
245 printf("Received RST with ECN.\n");
246 printf("Connection established successfully without ECN\n");
247 Quit(ECN_SYN_DROP);
248 } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
249 printf("Received RST with ECN\n");
250 printf("Exceed max SYN retransmits without ECN\n");
251 Quit(NO_CONNECTION);
252 }
253 break;
254 }
255 case ESTABLISH_FAILURE_NO_REPLY:
256 {
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");
262 Quit(NO_CONNECTION);
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");
266 Quit(NO_CONNECTION);
267 } else {
268 printf("Exceeded max SYN retransmits with ECN\n");
269 printf("Connection established successfully without ECN\n");
270 Quit(ECN_SYN_DROP);
271 }
272 break;
273 }
274 }
275
276 /* Test for propogation of CE correctly */
277 DataPkt(session.filename, 3, 0);
278
279 checkECN();
280 return;
281}
282
283void DataPkt (char *filename, u_int8_t iptos, u_int8_t tcp_flags)
284{
285 struct IPPacket *p, *datapkt;
286 struct pcap_pkthdr pi;
287 char *read_packet;
288 int i ;
289 int sendflag = 1 ;
290 u_int16_t lastSeqSent = session.snd_nxt;
291 double startTime = 0;
292 char *dataptr ;
293 char data[MAXREQUESTLEN];
294 int datalen;
295 int ipsz;
296
297 datalen = PrepareRequest (data, filename);
298
299 datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
300
301 dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
302 memcpy((void *)dataptr,(void *)data, datalen);
303
304 ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
305
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
310 * BAD busy-wait loop
311 */
312
313 i = 0 ;
314 while(1) {
315
316 if (sendflag == 1) {
317 SendSessionPacket(datapkt, ipsz,
318 TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, iptos);
319
320 startTime = GetTime();
321 sendflag = 0 ;
322 i++ ;
323 }
324
325 /* Check if we have received any packets */
326 if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
89c4ed63
A
327 p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
328
329 /*
330 * packet that we sent?
331 */
332
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);
341 PrintTcpPacket(p);
342 }
343 StorePacket(p);
344 session.snd_nxt += datalen + 1;
345 session.totSeenSent ++ ;
346 continue ;
347 }
348
349 /*
350 * from them?
351 */
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;
360 }
361 if (session.debug >= SESSION_DEBUG_LOW) {
362 printf("rcvd %d\n", i);
363 PrintTcpPacket(p);
364 }
365 StorePacket(p);
366 session.totRcvd ++;
367 break ;
368 }
369 /*
370 * otherwise, this is a bad packet
371 * we must quit
372 */
373 //processBadPacket(p);
374 }
375 if ((GetTime() - startTime >= 1) && (sendflag == 0) && (i < 3)) {
376 sendflag = 1 ;
377 }
378 if (i >= 3) {
379 printf ("ERROR: sent request 3 times without response\n");
380 return;
381 }
382 }
383
384 FreeIPPacket(&datapkt);
385
386 /* process any response by sending Acks */
387 rcvData (ECNAckData);
388}
389
390void ECNAckData (struct IPPacket *p)
391{
392
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;
397 int i;
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;
406 uint8 tcp_flags = 0;
407
408
409 /* Legend:
410 * ECN_ECHO: counts packets with TCP header ECN bit set
411 * ECT_XX: counts packets with ECT codepoint XX (IP)
412 */
413
414 if (datalen > session.mss) {
415 printf ("ERROR: mss=%d datalen=%d\nRETURN CODE: %d\n",
416 session.mss, datalen, MSS_ERR);
417 Quit(MSS_ERR);
418 }
419
420 if (datalen > 0) {
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));
430 }
431 }
432
433 session.totDataPktsRcvd++;
434
435 if (session.verbose) {
436 printf ("r %f %d %d\n",
437 GetTime() - session.epochTime,
438 seq - session.irs,
439 seq - session.irs + datalen);
440 }
441
442 }
443
444 /* Check if packet has the ECN_ECHO flag set */
445 if (history[session.hsz - 1].ecn_echo) {
446 ECN_ECHO += 1;
447 }
448
449 if ((p->ip->ip_tos & 0x17) == 0) {
450 ECT_00 += 1;
451 }
452 if ((p->ip->ip_tos & 0x17) == 1) {
453 ECT_01 += 1;
454 }
455 if ((p->ip->ip_tos & 0x17) == 2) {
456 ECT_10 += 1;
457 }
458 if ((p->ip->ip_tos & 0x17) == 3) {
459 ECT_11 += 1;
460 }
461
462 if(session.maxseqseen < seq + datalen - 1) {
463 session.maxseqseen = seq + datalen - 1;
464 } else {
465 if (datalen > 0) {
466 if (reordered(p) != 1) {
467 session.num_unwanted_drops += 1;
468 }
469 }
470 }
471
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))) {
477 int start, end;
478 start = seq - session.irs ;
479 end = start + datalen ;
480
481 for (i = start ; i < end ; i++) {
482 session.dataRcvd[i] = 1 ;
483 }
484
485 start = session.rcv_nxt - session.irs ;
486 end = session.mss * session.maxpkts ;
487
488 for (i = start ; i < end ; i++) {
489 if (session.dataRcvd[i] == 0) {
490 break ;
491 }
492 session.rcv_nxt++ ;
493 }
494 }
495
496 if (datalen > 0) {
497 if (session.verbose) {
498 printf ("a %f %d\n", GetTime() - session.epochTime,
499 session.rcv_nxt - session.irs);
500 }
501 ackpkt = AllocateIPPacket(0, 0, 0, "NewECN (ACK)");
502 if ((p->ip->ip_tos & 0x17) == 3) {
503 tcp_flags = TCPFLAGS_ACK | TCPFLAGS_ECN_ECHO;
504 } else {
505 tcp_flags = TCPFLAGS_ACK;
506 }
507
508 if (send_cwr == 2 && send_ece < 2) {
509 /* Send ECE as if a CE was received, we have to get CWR back */
510 send_ece = 1;
511 tcp_flags |= TCPFLAGS_ECN_ECHO;
512 }
513
514 SendSessionPacket (ackpkt,
515 sizeof(struct IpHeader) + sizeof(struct TcpHeader),
516 tcp_flags, 0, 0, 0);
517 }
518
519 if (send_cwr == 0 && (p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
520 /* Send CWR atleast once if ECN ECHO is set */
521 int datalen;
522 struct IPPacket *datapkt;
523 char *dataptr;
524 char data[MAXREQUESTLEN];
525 int ipsz;
526
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) +
532 datalen + 1;
533
534 SendSessionPacket(datapkt, ipsz,
535 TCPFLAGS_PSH | TCPFLAGS_ACK | TCPFLAGS_CWR, 0, 0, 2);
fa34b6f5
A
536
537 session.snd_nxt += (datalen + 1);
89c4ed63
A
538 send_cwr = 1;
539 FreeIPPacket(&datapkt);
540 }
541
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 */
544 send_cwr = 2;
545 }
546
547 if (send_ece == 1 && (p->tcp->tcp_flags & TCPFLAGS_CWR)) {
548 /* Received CWR in response to ECE */
549 send_ece = 2;
550 }
551
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;
556
557 if (fin || rst) {
558 /* Increment sequence number for FIN rcvd */
559 session.rcv_nxt++;
560 if (ECT_01 == 0 && ECT_10 == 0) {
561 printf("Never received ECT(0) or ECT(1) in ToS field: FAIL\n");
562 }
563 if (ECT_11 > 3) {
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);
566 }
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);
570 if (fin) {
571 SendSessionPacket (ackpkt,
572 sizeof(struct IpHeader) + sizeof(struct TcpHeader),
573 tcp_flags, 0, 0, 0);
574 }
575 checkECN();
576 Quit(SUCCESS);
577 }
578}
579
580void checkECN ()
581{
582 int i;
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 */
589
590 for (i = 0 ; i < session.hsz; i++) {
591 if ((history[i].type == RCVD) && (history[i].syn == 1) &&
592 (history[i].ack == 1)) {
593 sr = 1;
594 if (history[i].ecn_echo == 1) {
595 se = 1;
596 if (history[i].cwr == 1) {
597 se = 2;
598 }
599 }
600 }
601 }
602
603 for (i = 0 ; i < session.hsz; i++) {
604 if (history[i].type == RCVD && history[i].syn == 0 &&
605 history[i].ack == 1) {
606 ar = 1;
607 if (history[i].ecn_echo == 1) {
608 ae = 1;
609 }
610 }
611 }
612
613 for (i = 0; i < session.hsz; i++) {
614 if (history[i].type == SENT && history[i].dlen > 0 &&
615 history[i].cwr == 1) {
616 we = 1;
617 continue;
618 }
619 if (we == 1 && history[i].type == RCVD && history[i].ecn_echo == 0) {
620 we = 2;
621 break;
622 }
623 if (we == 2 && history[i].type == RCVD && history[i].ecn_echo == 1) {
624 we = 1;
625 break;
626 }
627 }
628
629 for (i = 0; i < session.hsz; i++) {
630 if (history[i].type == SENT && history[i].ecn_echo == 1) {
631 ee = 1;
632 continue;
633 }
634 if (ee == 1 && history[i].type == RCVD && history[i].dlen > 0 &&
635 history[i].cwr == 1) {
636 /* Received cwr in response to ECE */
637 ee = 2;
638 break;
639 }
640 }
641
642 printf ("sr=%d se=%d ar=%d ae=%d we=%d\n", sr, se, ar, ae, we);
643 switch (sr) {
644 case 0:
645 printf("No SYN/ACK received from server\n");
646 break;
647 case 1:
648 printf("SYN/ACK received: PASS \n");
649 break;
650 default:
651 printf("Unknown value for sr: %d\n", sr);
652 break;
653 }
654 switch (se) {
655 case 0:
656 printf("No CWR or ECE on SYN/ACK, server does not support ECN\n");
657 break;
658 case 1:
659 printf("ECE flag set on SYN/ACK, server supports ECN: PASS\n");
660 break;
661 case 2:
662 printf("Both CWR and ECE set on SYN/ACK, incompatible SYN/ACK\n");
663 break;
664 default:
665 printf("Unknown value for se: %d\n", se);
666 break;
667 }
668
669 switch (ar) {
670 case 0:
671 printf("No ACK received\n");
672 break;
673 case 1:
674 printf("ACK received: PASS\n");
675 break;
676 default:
677 printf("Unknown value for ar: %d\n", ar);
678 break;
679 }
680
681 switch (ae) {
682 case 0:
683 printf("Received ACKS but never ECE\n");
684 break;
685 case 1:
686 printf("Received ACKs with ECE, in response to simulated CE bit: PASS\n");
687 break;
688 default:
689 printf("Unknown value for ae: %d\n", ae);
690 break;
691 }
692
693 switch (we) {
694 case 0:
695 printf("Never received ECE\n");
696 break;
697 case 1:
698 printf("Received ECE and sent CWR\n");
699 break;
700 case 2:
701 printf("Received ECE, sent CWR and stopped receiving ECE afterwards: PASS\n");
702 break;
703 default:
704 printf("Unknown value for we: %d\n", we);
705 break;
706 }
707
708 switch (ee) {
709 case 0:
710 printf("Never sent ECE\n");
711 break;
712 case 1:
713 printf("Sent ECE to simulate receiving CE \n");
714 break;
715 case 2:
716 printf("Sent ECE and received CWR in response: PASS\n");
717 break;
718 default:
719 printf("Unknown value for ee: %d\n", ee);
720 break;
721 }
722 return;
723}
fa34b6f5
A
724
725void DataPktPathCheck(char *filename, u_int8_t iptos, u_int8_t tcp_flags)
726{
727 struct IPPacket *p, *datapkt;
728 struct pcap_pkthdr pi;
729 char *read_packet;
730 int i ;
731 int sendflag = 1 ;
732 u_int16_t lastSeqSent = session.snd_nxt;
733 double startTime = 0;
734 char *dataptr;
735 char data[MAXREQUESTLEN];
736 int datalen;
737 int ipsz;
738 unsigned int init_ttl;
739
740 datalen = PrepareRequest (data, filename);
741
742 datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
743
744 dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
745 memcpy((void *)dataptr,(void *)data, datalen);
746
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
752 * BAD busy-wait loop
753 */
754
755 i = 0 ;
756 init_ttl = 1;
757 while(1) {
758
759 if (sendflag == 1) {
760 session.curr_ttl = ++init_ttl;
761 if (init_ttl > 64) /* reached the max */
762 break;
763 SendSessionPacket(datapkt, ipsz,
764 TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, 0x3);
765
766 startTime = GetTime();
767 sendflag = 0;
768 i++ ;
769 }
770
771 /* Check if we have received any packets */
772 if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
773
774 p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
775
776 /*
777 * packet that we sent?
778 */
779
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);
788 PrintTcpPacket(p);
789 }
790 StorePacket(p);
791 session.snd_nxt += datalen + 1;
792 session.totSeenSent ++ ;
793 continue ;
794 }
795
796 /*
797 * from them?
798 */
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;
807 }
808 if (session.debug >= SESSION_DEBUG_LOW) {
809 printf("rcvd %d\n", i);
810 PrintTcpPacket(p);
811 }
812 StorePacket(p);
813 session.totRcvd ++;
814 break ;
815 }
816 /*
817 * ICMP ttl exceeded
818 */
819 if (p->ip->ip_p == IPPROTOCOL_ICMP) {
820 uint16_t ip_hl;
821 struct IcmpHeader *icmp;
822 ip_hl = (p->ip->ip_vhl & 0x0f) << 2;
823 void *nexthdr;
824
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;
830
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);
836
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));
845 }
846 }
847 }
848 /*
849 * otherwise, this is a bad packet
850 * we must quit
851 */
852 //processBadPacket(p);
853 }
854 if ((GetTime() - startTime >= 1) && (sendflag == 0)) {
855 sendflag = 1;
856 session.snd_nxt = session.snd_una;
857 }
858 }
859
860 FreeIPPacket(&datapkt);
861}
862void ECNPathCheckTest(u_int32_t sourceAddress, u_int16_t sourcePort,
863 u_int32_t targetAddress, u_int16_t targetPort, int mss)
864{
865 int rawSocket, rc, flag;
866
867 arc4random_stir();
868
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;
876 session.rcv_nxt = 0;
877 session.irs = 0;
878 session.mss = mss;
879 session.maxseqseen = 0;
880 session.epochTime = GetTime();
881 session.maxpkts = 1000;
882 session.debug = 0;
883
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);
887 Quit(ERR_MEM_ALLOC);
888 }
889
890 if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
891 perror("ERROR: couldn't open socket:");
892 Quit(ERR_SOCKET_OPEN);
893 }
894
895 flag = 1;
896 if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
897 (char *)&flag, sizeof(flag)) < 0) {
898 perror("ERROR: couldn't set raw socket options:");
899 Quit(ERR_SOCKOPT);
900 }
901
902 session.socket = rawSocket;
903
904 /* Establish a TCP connections with ECN bits */
905 rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
906 switch (rc) {
907 case ESTABLISH_FAILURE_EARLY_RST:
908 {
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");
914 Quit(EARLY_RST);
915 } else if (rc == ESTABLISH_SUCCESS) {
916 printf("Received RST with ECN.\n");
917 printf("Connection established successfully without ECN\n");
918 Quit(ECN_SYN_DROP);
919 } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
920 printf("Received RST with ECN\n");
921 printf("Exceed max SYN retransmits without ECN\n");
922 Quit(NO_CONNECTION);
923 }
924 break;
925 }
926 case ESTABLISH_FAILURE_NO_REPLY:
927 {
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");
933 Quit(NO_CONNECTION);
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");
937 Quit(NO_CONNECTION);
938 } else {
939 printf("Exceeded max SYN retransmits with ECN\n");
940 printf("Connection established successfully without ECN\n");
941 Quit(ECN_SYN_DROP);
942 }
943 break;
944 }
945 }
946
947 DataPktPathCheck(session.filename, 3, 0);
948 return;
949}
755a8d69
A
950
951
952void
953SynTest(u_int32_t sourceAddress, u_int16_t sourcePort,
954 u_int32_t targetAddress, u_int16_t targetPort, int mss, int syn_reply)
955{
956 int rawSocket, flag;
957 struct IPPacket *synPacket = NULL, *ackPacket = NULL;
958 char *read_packet;
959 struct pcap_pkthdr pi;
960 int synAckReceived = 0;
961 int numRetransmits = 0;
962 double timeoutTime;
963 int tcpoptlen = 4; /* For negotiating MSS */
964 u_int8_t *opt = NULL;
965 struct IPPacket *p = NULL;
966
967 arc4random_stir();
968
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;
976 session.rcv_nxt = 0;
977 session.irs = 0;
978 session.mss = mss;
979 session.maxseqseen = 0;
980 session.epochTime = GetTime();
981 session.maxpkts = 1000;
982
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);
986 Quit(ERR_MEM_ALLOC);
987 }
988
989 if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
990 perror("ERROR: couldn't open socket:");
991 Quit(ERR_SOCKET_OPEN);
992 }
993
994 flag = 1;
995 if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
996 (char *)&flag, sizeof(flag)) < 0) {
997 perror("ERROR: couldn't set raw socket options:");
998 Quit(ERR_SOCKOPT);
999 }
1000
1001 session.socket = rawSocket;
1002
1003
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);
1010
1011 SendSessionPacket(synPacket,
1012 sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
1013 TCPFLAGS_SYN , 0, tcpoptlen, 0);
1014 timeoutTime = GetTime() + 1;
1015
1016 /*
1017 * Wait for SYN/ACK and retransmit SYN if appropriate
1018 * not great, but it gets the job done
1019 */
1020
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) {
1032 PrintTcpPacket(p);
1033 }
1034 StorePacket(p);
1035 session.totSeenSent++ ;
1036 } else {
1037 processBadPacket(p);
1038 }
1039 continue;
1040 }
1041
1042 /* Received a packet from them to us */
1043 if (INSESSION(p, session.dst, session.dport, session.src,
1044 session.sport)) {
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 */
1049 synAckReceived++;
1050 if (session.debug >= SESSION_DEBUG_LOW) {
1051 PrintTcpPacket(p);
1052 }
1053 StorePacket(p);
1054
1055 /*
1056 * Save ttl for,admittedly poor,indications of reverse
1057 * route change
1058 */
1059 session.ttl = p->ip->ip_ttl;
1060 session.snd_wnd = ntohl(p->tcp->tcp_win);
1061 session.totRcvd ++;
1062 break;
1063 } else {
1064 if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
1065 printf ("ERROR: EARLY_RST\n");
1066 goto done;
1067 }
1068 }
1069 }
1070 }
1071 }
1072
1073 if (!synAckReceived) {
1074 if (session.debug >= SESSION_DEBUG_LOW) {
1075 printf("SYN timeout. Retransmitting\n");
1076 }
1077 SendSessionPacket(synPacket,
1078 sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
1079 TCPFLAGS_SYN , 0, tcpoptlen, 0);
1080 timeoutTime = GetTime() + 1;
1081 numRetransmits++;
1082 }
1083 }
1084
1085 if (numRetransmits >= 3) {
1086 printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
1087 NO_CONNECTION);
1088 goto done;
1089 }
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);
1107 }
1108
1109 /* allocate the syn packet -- Changed for new IPPacket structure */
1110 ackPacket = AllocateIPPacket(0, 0, 0, "SYN reply");
1111 /* send an ACK */
1112 SendSessionPacket(ackPacket,
1113 sizeof(struct IpHeader) + sizeof(struct TcpHeader),
1114 syn_reply, 0, 0, 0);
1115 FreeIPPacket(&ackPacket);
1116 }
1117done:
1118 FreeIPPacket(&synPacket);
1119}