]>
Commit | Line | Data |
---|---|---|
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 | ||
58 | extern struct TcpSession session; | |
59 | extern struct History history[]; | |
60 | ||
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) | |
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 | ||
190 | void 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 | ||
283 | void 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 | ||
390 | void 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 | ||
580 | void 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 | |
725 | void 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 | } | |
862 | void 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 | ||
952 | void | |
953 | SynTest(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 | } | |
1117 | done: | |
1118 | FreeIPPacket(&synPacket); | |
1119 | } |