]>
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 | ||
755a8d69 | 88 | if (session.debug >= SESSION_DEBUG_HIGH) { |
89c4ed63 A |
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 | ||
755a8d69 | 118 | if (session.debug >= SESSION_DEBUG_HIGH) { |
89c4ed63 A |
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 | ||
755a8d69 | 147 | if (session.debug >= SESSION_DEBUG_HIGH) { |
89c4ed63 A |
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 | ||
755a8d69 A |
194 | ip->ip_xsum = 0; |
195 | ip->ip_xsum = InetChecksum((uint16 *)ip, NULL, | |
196 | (uint16)sizeof(struct IpHeader) + ip_optlen, /* IP Options should aren't included */ | |
197 | 0); | |
198 | ||
199 | if (session.debug >= SESSION_DEBUG_HIGH) { | |
89c4ed63 A |
200 | printf("Out WriteIPPacket...\n"); |
201 | } | |
202 | ||
203 | } | |
204 | ||
205 | void ReadIPPacket(struct IPPacket *p, | |
206 | uint32 *src, | |
207 | uint32 *dst, | |
208 | uint16 *sport, | |
209 | uint16 *dport, | |
210 | uint32 *seq, | |
211 | uint32 *ack, | |
212 | uint8 *flags, | |
213 | uint16 *win, | |
214 | uint16 *urp, | |
215 | uint16 *datalen, | |
216 | uint16 *ip_optlen, | |
217 | uint16 *optlen) | |
218 | { | |
219 | ||
220 | /* TODO: Add reading of IP options, if any */ | |
221 | ||
222 | struct IpHeader *ip = p->ip; | |
223 | struct TcpHeader *tcp = p->tcp; | |
224 | ||
225 | uint16 ip_len; | |
226 | uint16 ip_hl; | |
227 | uint16 tcp_hl; | |
228 | ||
229 | /* XXX do checksum check? */ | |
fa34b6f5 A |
230 | if (ip->ip_p != IPPROTOCOL_TCP && ip->ip_p != IPPROTOCOL_ICMP) { |
231 | printf("Unexpected protocol packet: %u\n", ip->ip_p); | |
89c4ed63 A |
232 | Quit(ERR_CHECKSUM); |
233 | } | |
234 | ||
235 | *src = ip->ip_src; | |
236 | *dst = ip->ip_dst; | |
237 | *sport = ntohs(tcp->tcp_sport); | |
238 | *dport = ntohs(tcp->tcp_dport); | |
239 | *seq = ntohl(tcp->tcp_seq); | |
240 | *ack = ntohl(tcp->tcp_ack); | |
241 | *flags = tcp->tcp_flags; | |
242 | *win = ntohs(tcp->tcp_win); | |
243 | *urp = ntohs(tcp->tcp_urp); | |
244 | ||
245 | tcp_hl = tcp->tcp_hl >> 2; | |
246 | ip_len = ntohs(ip->ip_len); | |
247 | ip_hl = (ip->ip_vhl & 0x0f) << 2; | |
248 | *datalen = (ip_len - ip_hl) - tcp_hl; | |
249 | *ip_optlen = ip_hl - (unsigned int)sizeof(struct IpHeader); /* added to support IP Options */ | |
250 | *optlen = tcp_hl - (unsigned int)sizeof(struct TcpHeader); | |
251 | ||
252 | } | |
253 | ||
254 | void PrintICMPUnreachableErrorPacket(struct ICMPUnreachableErrorPacket *p) | |
255 | { | |
256 | ||
257 | struct IpHeader *ip = &p->ip; | |
258 | struct IcmpHeader *icmp = &p->icmp; | |
259 | struct IpHeader *off_ip = &p->off_ip; | |
260 | ||
261 | printf("IPHdr: "); | |
262 | printf("%s > ", InetAddress(ip->ip_src)); | |
263 | printf("%s ", InetAddress(ip->ip_dst)); | |
264 | printf(" datalen: %u\n", ip->ip_len); | |
265 | printf("ICMPHdr: "); | |
266 | printf("Type: %u Code: %u MTU next hop: %u xsum: %x\n", | |
267 | icmp->icmp_type, | |
268 | icmp->icmp_code, | |
269 | ntohs(icmp->icmp_mtu), | |
270 | icmp->icmp_xsum); | |
271 | printf("Off IPHdr: "); | |
272 | printf("%s > ", InetAddress(off_ip->ip_src)); | |
273 | printf("%s ", InetAddress(off_ip->ip_dst)); | |
274 | printf(" datalen: %u ", off_ip->ip_len); | |
275 | printf("tcp sport: %u ", ntohs(p->tcp_sport)); | |
276 | printf("tcp dport: %u ", ntohs(p->tcp_dport)); | |
277 | printf("tcp seqno: %u\n", (uint32)ntohl(p->tcp_seqno)); | |
278 | ||
279 | } | |
280 | ||
281 | void PrintTcpPacket(struct IPPacket *p) | |
282 | { | |
283 | ||
284 | struct IpHeader *ip = p->ip; | |
285 | struct TcpHeader *tcp = p->tcp; | |
286 | ||
287 | char *opt; | |
288 | int optlen; | |
289 | char *ip_opt; | |
290 | int ip_optlen; | |
291 | int i; | |
292 | ||
293 | printf("%s.%u > ", InetAddress(ip->ip_src), ntohs(tcp->tcp_sport)); | |
294 | printf("%s.%u ", InetAddress(ip->ip_dst), ntohs(tcp->tcp_dport)); | |
295 | ||
296 | if (tcp->tcp_flags & TCPFLAGS_SYN) { | |
297 | printf("S"); | |
298 | } | |
299 | ||
300 | if (tcp->tcp_flags & TCPFLAGS_ACK) { | |
301 | printf("A"); | |
302 | } | |
303 | ||
304 | if (tcp->tcp_flags & TCPFLAGS_FIN) { | |
305 | printf("F"); | |
306 | } | |
307 | ||
308 | if (tcp->tcp_flags & TCPFLAGS_ECN_ECHO) { | |
309 | printf("E"); | |
310 | } | |
311 | ||
312 | if (tcp->tcp_flags & TCPFLAGS_CWR) { | |
313 | printf("W"); | |
314 | } | |
315 | ||
316 | if (tcp->tcp_flags & TCPFLAGS_RST) { | |
317 | printf("R"); | |
318 | } | |
319 | if (tcp->tcp_flags & TCPFLAGS_PSH) { | |
320 | printf("P"); | |
321 | } | |
322 | ||
323 | if (tcp->tcp_flags & TCPFLAGS_URG) { | |
324 | printf("U"); | |
325 | } | |
326 | ||
327 | if (INSESSION(p,session.src,session.sport,session.dst,session.dport)) { | |
328 | printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.iss, (uint32)ntohl(tcp->tcp_ack) - session.irs); | |
329 | } else { | |
330 | printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.irs, (uint32)ntohl(tcp->tcp_ack) - session.iss); | |
331 | } | |
332 | ||
333 | /* IP Options */ | |
334 | ip_optlen = ((ip->ip_vhl & 0x0f) << 2) - sizeof(struct IpHeader); | |
335 | ip_opt = (char *)ip + sizeof(struct IpHeader); | |
336 | ||
337 | i = 0; | |
338 | while (i < ip_optlen) { | |
339 | ||
340 | switch ((unsigned char)ip_opt[i]) { | |
341 | case IPOPT_NOP: | |
342 | printf(" ipopt%d: %s ", i + 1, "IPOPT_NOP"); | |
343 | i = i + 1; | |
344 | break; | |
345 | ||
346 | case IPOPT_EOL: | |
347 | printf(" ipopt%d: %s ", i + 1, "IPOPT_EOL"); | |
348 | i = ip_optlen + 1; | |
349 | break; | |
350 | ||
351 | case IPOPT_RR: | |
352 | printf(" ipopt%d: %s ", i + 1, "IPOPT_RR"); | |
353 | i = i + IPOLEN_RR; | |
354 | break; | |
355 | ||
356 | default: | |
357 | printf("ip_opt%d: UNKNOWN ", i + 1); | |
358 | i = i + (uint8)ip_opt[i+1] ; | |
359 | } | |
360 | } | |
361 | ||
362 | printf(" win: %u, urg: %u, ttl: %d", ntohs(tcp->tcp_win), ntohs(tcp->tcp_urp), ip->ip_ttl); | |
363 | printf(" datalen: %u, optlen: %u ", | |
364 | ip->ip_len - ((ip->ip_vhl &0x0f) << 2) - (tcp->tcp_hl >> 2), | |
365 | (tcp->tcp_hl >> 2) - (unsigned int)sizeof(struct TcpHeader)); | |
366 | ||
367 | ||
368 | /* TCP Options */ | |
369 | optlen = (tcp->tcp_hl >> 2) - (unsigned int)sizeof (struct TcpHeader) ; | |
370 | opt = (char *)tcp + sizeof(struct TcpHeader); | |
371 | ||
372 | i = 0 ; | |
373 | ||
374 | while (i < optlen) { | |
375 | ||
376 | switch ((unsigned char)opt[i]) { | |
377 | ||
378 | case TCPOPT_EOL: | |
379 | printf (" opt%d: %s ", i + 1, "TCPOPT_EOL"); | |
380 | i = optlen + 1; | |
381 | break ; | |
382 | ||
383 | case TCPOPT_NOP: | |
384 | printf (" opt%d: %s ", i + 1, "TCPOPT_NOP"); | |
385 | i++ ; | |
386 | break ; | |
387 | ||
388 | case TCPOPT_MAXSEG: | |
389 | printf (" opt%d: %s: %d ", i + 1, "TCPOPT_MAXSEG", ntohs(*(uint16 *)((char *)opt+2))); | |
390 | i = i + TCPOLEN_MAXSEG ; | |
391 | break ; | |
392 | ||
393 | case TCPOPT_WINDOW: | |
394 | printf (" opt%d: %s ", i + 1, "TCPOPT_WINDOW"); | |
395 | i = i + TCPOLEN_WINDOW ; | |
396 | break ; | |
397 | ||
398 | case TCPOPT_SACK_PERMITTED: | |
399 | printf (" opt%d: %s ", i + 1, "TCPOPT_SACK_PERMITTED"); | |
400 | i = i + TCPOLEN_SACK_PERMITTED ; | |
401 | break ; | |
402 | ||
403 | case TCPOPT_TIMESTAMP: | |
404 | printf (" opt%d: %s ", i + 1, "TCPOPT_TIMESTAMP"); | |
405 | i = i + TCPOLEN_TIMESTAMP ; | |
406 | break ; | |
407 | ||
408 | default: | |
409 | printf (" opt%d c:%d l:%d: UNKNOWN ", i + 1, (uint8)opt[i], (uint8)opt[i+1]); | |
410 | if ((uint8)opt[i+1] > 0) { | |
411 | i = i + (uint8)opt[i+1] ; | |
412 | } else { | |
413 | Quit(20); | |
414 | } | |
415 | break ; | |
416 | } | |
417 | } | |
418 | printf ("\n"); | |
419 | } | |
420 | ||
421 | ||
422 | struct IPPacket *FindHeaderBoundaries(char *p) { | |
423 | ||
424 | struct IPPacket *packet; | |
425 | uint16 ip_hl; | |
426 | ||
427 | if ((packet = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) == NULL) { | |
428 | printf("FindHeaderBoundaries: Cannot allocate memory for read packet\nRETURN CODE: %d\n", ERR_MEM_ALLOC); | |
429 | Quit(ERR_MEM_ALLOC); | |
430 | } | |
431 | ||
432 | packet->ip = (struct IpHeader *)p; | |
433 | ||
fa34b6f5 A |
434 | if (packet->ip->ip_p != IPPROTOCOL_TCP && |
435 | packet->ip->ip_p != IPPROTOCOL_ICMP) { | |
436 | printf("Error: Unexpected protocol packet: %u \n", packet->ip->ip_p); | |
89c4ed63 A |
437 | Quit(ERR_CHECKSUM); |
438 | } | |
439 | ||
440 | ip_hl = (packet->ip->ip_vhl & 0x0f) << 2; | |
441 | ||
442 | packet->tcp = (struct TcpHeader *)((char *)p + ip_hl); | |
89c4ed63 A |
443 | return packet; |
444 | ||
445 | } | |
446 | ||
447 | ||
448 | struct IPPacket * | |
449 | AllocateIPPacket(int ip_optlen, int tcp_optlen, int datalen, char *str) | |
450 | { | |
451 | struct IPPacket *p; | |
452 | ||
755a8d69 | 453 | if (session.debug >= SESSION_DEBUG_HIGH) { |
89c4ed63 A |
454 | printf("In AllocateIPPacket: %s...\n", str); |
455 | } | |
456 | ||
457 | if ((p = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) | |
458 | == NULL) { | |
459 | printf("%s ERROR: No space for packet\nRETURN CODE: %d", | |
460 | str, ERR_MEM_ALLOC); | |
461 | Quit(ERR_MEM_ALLOC); | |
462 | } | |
463 | ||
464 | if ((p->ip = (struct IpHeader *)calloc(1, | |
465 | sizeof(struct IpHeader) + ip_optlen)) == NULL) { | |
466 | printf("%s ERROR: No IpHeader space for packet\n" | |
467 | "RETURN CODE: %d", str, ERR_MEM_ALLOC); | |
468 | Quit(ERR_MEM_ALLOC); | |
469 | } | |
470 | ||
471 | if ((p->tcp = (struct TcpHeader *)calloc(1, | |
472 | sizeof(struct TcpHeader) + tcp_optlen + datalen)) == NULL) { | |
473 | printf("%s ERROR: No TcpHeader space for packet\n" | |
474 | "RETURN CODE: %d", str, ERR_MEM_ALLOC); | |
475 | Quit(ERR_MEM_ALLOC); | |
476 | } | |
477 | ||
755a8d69 | 478 | if (session.debug >= SESSION_DEBUG_HIGH) { |
89c4ed63 A |
479 | printf("Out of AllocateIPPacket: %s...\n", str); |
480 | } | |
481 | return(p); | |
482 | } | |
483 | ||
484 | void | |
485 | FreeIPPacket(struct IPPacket **pkt_p) | |
486 | { | |
487 | struct IPPacket *pkt; | |
488 | if (pkt_p == NULL) | |
489 | return; | |
490 | if ((pkt = *pkt_p) == NULL) | |
491 | return; | |
492 | if (pkt->ip != NULL) { | |
493 | free(pkt->ip); | |
494 | pkt->ip = NULL; | |
495 | } | |
496 | if (pkt->tcp != NULL) { | |
497 | free(pkt->tcp); | |
498 | pkt->tcp = NULL; | |
499 | } | |
500 | free(pkt); | |
501 | *pkt_p = NULL; | |
502 | } | |
503 |