]>
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 <unistd.h> | |
49 | #include "base.h" | |
50 | #include "inet.h" | |
51 | #include "session.h" | |
52 | #include "capture.h" | |
53 | #include "support.h" | |
54 | #include "history.h" | |
55 | ||
56 | extern struct TcpSession session; | |
57 | extern struct History history[]; | |
58 | ||
59 | /* | |
60 | * Deal with struct in_addr type agreement once and for all | |
61 | */ | |
62 | char *InetAddress(uint32 addr) | |
63 | { | |
64 | ||
65 | struct in_addr s; | |
66 | s.s_addr = addr; | |
67 | ||
68 | //printf("In InetAddress:\n"); | |
69 | //printf("addr = %s (%0x)\n", inet_ntoa(s), addr); | |
70 | ||
71 | return (inet_ntoa(s)); | |
72 | } | |
73 | ||
74 | /* | |
75 | * Really slow implementation of ip checksum | |
76 | * ripped off from rfc1071 | |
77 | */ | |
78 | ||
79 | uint16 InetChecksum(uint16 *ip, uint16 *tcp, uint16 ip_len, uint16 tcp_len) { | |
80 | ||
81 | uint32 sum = 0; | |
82 | ||
83 | uint32 ip_count = ip_len; | |
84 | uint32 tcp_count = tcp_len; | |
85 | uint16 *ip_addr = ip; | |
86 | uint16 *tcp_addr = tcp; | |
87 | ||
88 | if (session.debug == SESSION_DEBUG_HIGH) { | |
89 | printf("In InetChecksum...\n"); | |
90 | printf("iplen: %d, tcplen: %d\n", ip_len, tcp_len); | |
91 | } | |
92 | ||
93 | ||
94 | while(ip_count > 1) { | |
95 | //printf("ip[%d]: %x\n", ip_len - ip_count, htons(*ip_addr)); | |
96 | sum += *ip_addr++; | |
97 | ip_count -= 2; | |
98 | } | |
99 | ||
100 | while(tcp_count > 1) { | |
101 | //printf("tcp[%d]: %x\n", tcp_len - tcp_count, htons(*tcp_addr)); | |
102 | sum += *tcp_addr++; | |
103 | tcp_count -= 2; | |
104 | } | |
105 | ||
106 | if(ip_count > 0) { | |
107 | sum += *(uint8 *)ip_addr; | |
108 | } | |
109 | ||
110 | if(tcp_count > 0) { | |
111 | sum += *(uint8 *)tcp_addr; | |
112 | } | |
113 | ||
114 | while (sum >> 16) { | |
115 | sum = (sum & 0xffff) + (sum >> 16); | |
116 | } | |
117 | ||
118 | if (session.debug == SESSION_DEBUG_HIGH) { | |
119 | printf("Out InetChecksum...\n"); | |
120 | } | |
121 | ||
122 | return(~sum); | |
123 | ||
124 | } | |
125 | ||
126 | ||
127 | void WriteIPPacket(struct IPPacket *p, | |
128 | uint32 src, | |
129 | uint32 dst, | |
130 | uint16 sport, | |
131 | uint16 dport, | |
132 | uint32 seq, | |
133 | uint32 ack, | |
134 | uint8 flags, | |
135 | uint16 win, | |
136 | uint16 urp, | |
137 | uint16 datalen, | |
138 | uint16 ip_optlen, | |
139 | uint16 optlen, | |
140 | uint8 iptos, | |
141 | uint8 u4tf) | |
142 | { | |
143 | ||
144 | struct IpHeader *ip = p->ip; | |
145 | struct TcpHeader *tcp = p->tcp; | |
146 | ||
147 | if (session.debug == SESSION_DEBUG_HIGH) { | |
148 | printf("In WriteIPPacket...\n"); | |
149 | } | |
150 | ||
151 | /* Zero out IpHeader to ensure proper checksum computation */ | |
152 | bzero((char *)(p->ip), sizeof(struct IpHeader)); | |
153 | ||
154 | ip->ip_src = src; | |
155 | ip->ip_dst = dst; | |
156 | ip->ip_p = IPPROTOCOL_TCP; | |
157 | ip->ip_xsum = | |
158 | htons((uint16)(sizeof(struct TcpHeader) + datalen + optlen)); /* pseudo hdr */ | |
159 | ||
160 | tcp->tcp_sport = htons(sport); | |
161 | tcp->tcp_dport = htons(dport); | |
162 | tcp->tcp_seq = htonl(seq); | |
163 | tcp->tcp_ack = htonl(ack); | |
164 | tcp->tcp_hl = (sizeof(struct TcpHeader) + optlen) << 2; | |
165 | tcp->tcp_hl = tcp->tcp_hl | u4tf; | |
166 | tcp->tcp_flags = flags; | |
167 | ||
168 | tcp->tcp_win = htons(win); | |
169 | tcp->tcp_urp = htons(urp); | |
170 | ||
171 | tcp->tcp_xsum = 0; | |
172 | tcp->tcp_xsum = InetChecksum((uint16 *)ip, (uint16 *)tcp, | |
173 | (uint16)sizeof(struct IpHeader), /* IP Options should aren't included */ | |
174 | (uint16)(sizeof(struct TcpHeader) + datalen + optlen)); | |
175 | ||
176 | /* Fill in real ip header */ | |
177 | if (session.curr_ttl != 0) { | |
178 | ip->ip_ttl = session.curr_ttl; | |
179 | }else { | |
180 | ip->ip_ttl = 60; | |
181 | } | |
182 | ||
183 | //printf("TTL: %d\n", ip->ip_ttl); | |
184 | ||
185 | ip->ip_tos = iptos; | |
186 | ||
187 | /* IP Version and Header len field */ | |
188 | ip->ip_vhl = 0x40 + 0x5 + (int)(ip_optlen/4); | |
189 | ip->ip_p = IPPROTOCOL_TCP; | |
190 | ||
191 | ip->ip_off = IP_DF; | |
192 | ip->ip_len = (uint16)(sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen + datalen); | |
193 | ||
194 | if (session.debug == SESSION_DEBUG_HIGH) { | |
195 | printf("Out WriteIPPacket...\n"); | |
196 | } | |
197 | ||
198 | } | |
199 | ||
200 | void ReadIPPacket(struct IPPacket *p, | |
201 | uint32 *src, | |
202 | uint32 *dst, | |
203 | uint16 *sport, | |
204 | uint16 *dport, | |
205 | uint32 *seq, | |
206 | uint32 *ack, | |
207 | uint8 *flags, | |
208 | uint16 *win, | |
209 | uint16 *urp, | |
210 | uint16 *datalen, | |
211 | uint16 *ip_optlen, | |
212 | uint16 *optlen) | |
213 | { | |
214 | ||
215 | /* TODO: Add reading of IP options, if any */ | |
216 | ||
217 | struct IpHeader *ip = p->ip; | |
218 | struct TcpHeader *tcp = p->tcp; | |
219 | ||
220 | uint16 ip_len; | |
221 | uint16 ip_hl; | |
222 | uint16 tcp_hl; | |
223 | ||
224 | /* XXX do checksum check? */ | |
225 | if (ip->ip_p != IPPROTOCOL_TCP) { | |
226 | printf("Error: not a TCP packet\n"); | |
227 | Quit(ERR_CHECKSUM); | |
228 | } | |
229 | ||
230 | *src = ip->ip_src; | |
231 | *dst = ip->ip_dst; | |
232 | *sport = ntohs(tcp->tcp_sport); | |
233 | *dport = ntohs(tcp->tcp_dport); | |
234 | *seq = ntohl(tcp->tcp_seq); | |
235 | *ack = ntohl(tcp->tcp_ack); | |
236 | *flags = tcp->tcp_flags; | |
237 | *win = ntohs(tcp->tcp_win); | |
238 | *urp = ntohs(tcp->tcp_urp); | |
239 | ||
240 | tcp_hl = tcp->tcp_hl >> 2; | |
241 | ip_len = ntohs(ip->ip_len); | |
242 | ip_hl = (ip->ip_vhl & 0x0f) << 2; | |
243 | *datalen = (ip_len - ip_hl) - tcp_hl; | |
244 | *ip_optlen = ip_hl - (unsigned int)sizeof(struct IpHeader); /* added to support IP Options */ | |
245 | *optlen = tcp_hl - (unsigned int)sizeof(struct TcpHeader); | |
246 | ||
247 | } | |
248 | ||
249 | void PrintICMPUnreachableErrorPacket(struct ICMPUnreachableErrorPacket *p) | |
250 | { | |
251 | ||
252 | struct IpHeader *ip = &p->ip; | |
253 | struct IcmpHeader *icmp = &p->icmp; | |
254 | struct IpHeader *off_ip = &p->off_ip; | |
255 | ||
256 | printf("IPHdr: "); | |
257 | printf("%s > ", InetAddress(ip->ip_src)); | |
258 | printf("%s ", InetAddress(ip->ip_dst)); | |
259 | printf(" datalen: %u\n", ip->ip_len); | |
260 | printf("ICMPHdr: "); | |
261 | printf("Type: %u Code: %u MTU next hop: %u xsum: %x\n", | |
262 | icmp->icmp_type, | |
263 | icmp->icmp_code, | |
264 | ntohs(icmp->icmp_mtu), | |
265 | icmp->icmp_xsum); | |
266 | printf("Off IPHdr: "); | |
267 | printf("%s > ", InetAddress(off_ip->ip_src)); | |
268 | printf("%s ", InetAddress(off_ip->ip_dst)); | |
269 | printf(" datalen: %u ", off_ip->ip_len); | |
270 | printf("tcp sport: %u ", ntohs(p->tcp_sport)); | |
271 | printf("tcp dport: %u ", ntohs(p->tcp_dport)); | |
272 | printf("tcp seqno: %u\n", (uint32)ntohl(p->tcp_seqno)); | |
273 | ||
274 | } | |
275 | ||
276 | void PrintTcpPacket(struct IPPacket *p) | |
277 | { | |
278 | ||
279 | struct IpHeader *ip = p->ip; | |
280 | struct TcpHeader *tcp = p->tcp; | |
281 | ||
282 | char *opt; | |
283 | int optlen; | |
284 | char *ip_opt; | |
285 | int ip_optlen; | |
286 | int i; | |
287 | ||
288 | printf("%s.%u > ", InetAddress(ip->ip_src), ntohs(tcp->tcp_sport)); | |
289 | printf("%s.%u ", InetAddress(ip->ip_dst), ntohs(tcp->tcp_dport)); | |
290 | ||
291 | if (tcp->tcp_flags & TCPFLAGS_SYN) { | |
292 | printf("S"); | |
293 | } | |
294 | ||
295 | if (tcp->tcp_flags & TCPFLAGS_ACK) { | |
296 | printf("A"); | |
297 | } | |
298 | ||
299 | if (tcp->tcp_flags & TCPFLAGS_FIN) { | |
300 | printf("F"); | |
301 | } | |
302 | ||
303 | if (tcp->tcp_flags & TCPFLAGS_ECN_ECHO) { | |
304 | printf("E"); | |
305 | } | |
306 | ||
307 | if (tcp->tcp_flags & TCPFLAGS_CWR) { | |
308 | printf("W"); | |
309 | } | |
310 | ||
311 | if (tcp->tcp_flags & TCPFLAGS_RST) { | |
312 | printf("R"); | |
313 | } | |
314 | if (tcp->tcp_flags & TCPFLAGS_PSH) { | |
315 | printf("P"); | |
316 | } | |
317 | ||
318 | if (tcp->tcp_flags & TCPFLAGS_URG) { | |
319 | printf("U"); | |
320 | } | |
321 | ||
322 | if (INSESSION(p,session.src,session.sport,session.dst,session.dport)) { | |
323 | printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.iss, (uint32)ntohl(tcp->tcp_ack) - session.irs); | |
324 | } else { | |
325 | printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.irs, (uint32)ntohl(tcp->tcp_ack) - session.iss); | |
326 | } | |
327 | ||
328 | /* IP Options */ | |
329 | ip_optlen = ((ip->ip_vhl & 0x0f) << 2) - sizeof(struct IpHeader); | |
330 | ip_opt = (char *)ip + sizeof(struct IpHeader); | |
331 | ||
332 | i = 0; | |
333 | while (i < ip_optlen) { | |
334 | ||
335 | switch ((unsigned char)ip_opt[i]) { | |
336 | case IPOPT_NOP: | |
337 | printf(" ipopt%d: %s ", i + 1, "IPOPT_NOP"); | |
338 | i = i + 1; | |
339 | break; | |
340 | ||
341 | case IPOPT_EOL: | |
342 | printf(" ipopt%d: %s ", i + 1, "IPOPT_EOL"); | |
343 | i = ip_optlen + 1; | |
344 | break; | |
345 | ||
346 | case IPOPT_RR: | |
347 | printf(" ipopt%d: %s ", i + 1, "IPOPT_RR"); | |
348 | i = i + IPOLEN_RR; | |
349 | break; | |
350 | ||
351 | default: | |
352 | printf("ip_opt%d: UNKNOWN ", i + 1); | |
353 | i = i + (uint8)ip_opt[i+1] ; | |
354 | } | |
355 | } | |
356 | ||
357 | printf(" win: %u, urg: %u, ttl: %d", ntohs(tcp->tcp_win), ntohs(tcp->tcp_urp), ip->ip_ttl); | |
358 | printf(" datalen: %u, optlen: %u ", | |
359 | ip->ip_len - ((ip->ip_vhl &0x0f) << 2) - (tcp->tcp_hl >> 2), | |
360 | (tcp->tcp_hl >> 2) - (unsigned int)sizeof(struct TcpHeader)); | |
361 | ||
362 | ||
363 | /* TCP Options */ | |
364 | optlen = (tcp->tcp_hl >> 2) - (unsigned int)sizeof (struct TcpHeader) ; | |
365 | opt = (char *)tcp + sizeof(struct TcpHeader); | |
366 | ||
367 | i = 0 ; | |
368 | ||
369 | while (i < optlen) { | |
370 | ||
371 | switch ((unsigned char)opt[i]) { | |
372 | ||
373 | case TCPOPT_EOL: | |
374 | printf (" opt%d: %s ", i + 1, "TCPOPT_EOL"); | |
375 | i = optlen + 1; | |
376 | break ; | |
377 | ||
378 | case TCPOPT_NOP: | |
379 | printf (" opt%d: %s ", i + 1, "TCPOPT_NOP"); | |
380 | i++ ; | |
381 | break ; | |
382 | ||
383 | case TCPOPT_MAXSEG: | |
384 | printf (" opt%d: %s: %d ", i + 1, "TCPOPT_MAXSEG", ntohs(*(uint16 *)((char *)opt+2))); | |
385 | i = i + TCPOLEN_MAXSEG ; | |
386 | break ; | |
387 | ||
388 | case TCPOPT_WINDOW: | |
389 | printf (" opt%d: %s ", i + 1, "TCPOPT_WINDOW"); | |
390 | i = i + TCPOLEN_WINDOW ; | |
391 | break ; | |
392 | ||
393 | case TCPOPT_SACK_PERMITTED: | |
394 | printf (" opt%d: %s ", i + 1, "TCPOPT_SACK_PERMITTED"); | |
395 | i = i + TCPOLEN_SACK_PERMITTED ; | |
396 | break ; | |
397 | ||
398 | case TCPOPT_TIMESTAMP: | |
399 | printf (" opt%d: %s ", i + 1, "TCPOPT_TIMESTAMP"); | |
400 | i = i + TCPOLEN_TIMESTAMP ; | |
401 | break ; | |
402 | ||
403 | default: | |
404 | printf (" opt%d c:%d l:%d: UNKNOWN ", i + 1, (uint8)opt[i], (uint8)opt[i+1]); | |
405 | if ((uint8)opt[i+1] > 0) { | |
406 | i = i + (uint8)opt[i+1] ; | |
407 | } else { | |
408 | Quit(20); | |
409 | } | |
410 | break ; | |
411 | } | |
412 | } | |
413 | printf ("\n"); | |
414 | } | |
415 | ||
416 | ||
417 | struct IPPacket *FindHeaderBoundaries(char *p) { | |
418 | ||
419 | struct IPPacket *packet; | |
420 | uint16 ip_hl; | |
421 | ||
422 | if ((packet = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) == NULL) { | |
423 | printf("FindHeaderBoundaries: Cannot allocate memory for read packet\nRETURN CODE: %d\n", ERR_MEM_ALLOC); | |
424 | Quit(ERR_MEM_ALLOC); | |
425 | } | |
426 | ||
427 | packet->ip = (struct IpHeader *)p; | |
428 | ||
429 | if (packet->ip->ip_p != IPPROTOCOL_TCP) { | |
430 | printf("Error: not a TCP packet\n"); | |
431 | Quit(ERR_CHECKSUM); | |
432 | } | |
433 | ||
434 | ip_hl = (packet->ip->ip_vhl & 0x0f) << 2; | |
435 | ||
436 | packet->tcp = (struct TcpHeader *)((char *)p + ip_hl); | |
437 | ||
438 | return packet; | |
439 | ||
440 | } | |
441 | ||
442 | ||
443 | struct IPPacket * | |
444 | AllocateIPPacket(int ip_optlen, int tcp_optlen, int datalen, char *str) | |
445 | { | |
446 | struct IPPacket *p; | |
447 | ||
448 | if (session.debug == SESSION_DEBUG_HIGH) { | |
449 | printf("In AllocateIPPacket: %s...\n", str); | |
450 | } | |
451 | ||
452 | if ((p = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) | |
453 | == NULL) { | |
454 | printf("%s ERROR: No space for packet\nRETURN CODE: %d", | |
455 | str, ERR_MEM_ALLOC); | |
456 | Quit(ERR_MEM_ALLOC); | |
457 | } | |
458 | ||
459 | if ((p->ip = (struct IpHeader *)calloc(1, | |
460 | sizeof(struct IpHeader) + ip_optlen)) == NULL) { | |
461 | printf("%s ERROR: No IpHeader space for packet\n" | |
462 | "RETURN CODE: %d", str, ERR_MEM_ALLOC); | |
463 | Quit(ERR_MEM_ALLOC); | |
464 | } | |
465 | ||
466 | if ((p->tcp = (struct TcpHeader *)calloc(1, | |
467 | sizeof(struct TcpHeader) + tcp_optlen + datalen)) == NULL) { | |
468 | printf("%s ERROR: No TcpHeader space for packet\n" | |
469 | "RETURN CODE: %d", str, ERR_MEM_ALLOC); | |
470 | Quit(ERR_MEM_ALLOC); | |
471 | } | |
472 | ||
473 | if (session.debug == SESSION_DEBUG_HIGH) { | |
474 | printf("Out of AllocateIPPacket: %s...\n", str); | |
475 | } | |
476 | return(p); | |
477 | } | |
478 | ||
479 | void | |
480 | FreeIPPacket(struct IPPacket **pkt_p) | |
481 | { | |
482 | struct IPPacket *pkt; | |
483 | if (pkt_p == NULL) | |
484 | return; | |
485 | if ((pkt = *pkt_p) == NULL) | |
486 | return; | |
487 | if (pkt->ip != NULL) { | |
488 | free(pkt->ip); | |
489 | pkt->ip = NULL; | |
490 | } | |
491 | if (pkt->tcp != NULL) { | |
492 | free(pkt->tcp); | |
493 | pkt->tcp = NULL; | |
494 | } | |
495 | free(pkt); | |
496 | *pkt_p = NULL; | |
497 | } | |
498 |