1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /* $NetBSD: print-tcp.c,v 1.9 2007/07/26 18:15:12 plunky Exp $ */ |
---|
4 | |
---|
5 | /* |
---|
6 | * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 |
---|
7 | * The Regents of the University of California. All rights reserved. |
---|
8 | * |
---|
9 | * Copyright (c) 1999-2004 The tcpdump.org project |
---|
10 | * |
---|
11 | * Redistribution and use in source and binary forms, with or without |
---|
12 | * modification, are permitted provided that: (1) source code distributions |
---|
13 | * retain the above copyright notice and this paragraph in its entirety, (2) |
---|
14 | * distributions including binary code include the above copyright notice and |
---|
15 | * this paragraph in its entirety in the documentation or other materials |
---|
16 | * provided with the distribution, and (3) all advertising materials mentioning |
---|
17 | * features or use of this software display the following acknowledgement: |
---|
18 | * ``This product includes software developed by the University of California, |
---|
19 | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
---|
20 | * the University nor the names of its contributors may be used to endorse |
---|
21 | * or promote products derived from this software without specific prior |
---|
22 | * written permission. |
---|
23 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
---|
24 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
---|
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
---|
26 | */ |
---|
27 | |
---|
28 | #ifndef lint |
---|
29 | static const char rcsid[] _U_ = |
---|
30 | "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.135 2008-11-09 23:35:03 mcr Exp $ (LBL)"; |
---|
31 | #else |
---|
32 | __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $"); |
---|
33 | #endif |
---|
34 | |
---|
35 | #ifdef HAVE_CONFIG_H |
---|
36 | #include "config.h" |
---|
37 | #endif |
---|
38 | |
---|
39 | #include <tcpdump-stdinc.h> |
---|
40 | |
---|
41 | #include <stdio.h> |
---|
42 | #include <stdlib.h> |
---|
43 | #include <string.h> |
---|
44 | |
---|
45 | #include "interface.h" |
---|
46 | #include "addrtoname.h" |
---|
47 | #include "extract.h" |
---|
48 | |
---|
49 | #include "tcp.h" |
---|
50 | |
---|
51 | #include "ip.h" |
---|
52 | #ifdef INET6 |
---|
53 | #include "ip6.h" |
---|
54 | #endif |
---|
55 | #include "ipproto.h" |
---|
56 | #include "rpc_auth.h" |
---|
57 | #include "rpc_msg.h" |
---|
58 | |
---|
59 | #include "nameser.h" |
---|
60 | |
---|
61 | #ifdef HAVE_LIBCRYPTO |
---|
62 | #include <openssl/md5.h> |
---|
63 | #include <signature.h> |
---|
64 | |
---|
65 | static int tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, |
---|
66 | const u_char *data, int length, const u_char *rcvsig); |
---|
67 | #endif |
---|
68 | |
---|
69 | static void print_tcp_rst_data(register const u_char *sp, u_int length); |
---|
70 | |
---|
71 | #define MAX_RST_DATA_LEN 30 |
---|
72 | |
---|
73 | |
---|
74 | struct tha { |
---|
75 | #ifndef INET6 |
---|
76 | struct in_addr src; |
---|
77 | struct in_addr dst; |
---|
78 | #else |
---|
79 | struct in6_addr src; |
---|
80 | struct in6_addr dst; |
---|
81 | #endif /*INET6*/ |
---|
82 | u_int port; |
---|
83 | }; |
---|
84 | |
---|
85 | struct tcp_seq_hash { |
---|
86 | struct tcp_seq_hash *nxt; |
---|
87 | struct tha addr; |
---|
88 | tcp_seq seq; |
---|
89 | tcp_seq ack; |
---|
90 | }; |
---|
91 | |
---|
92 | #define TSEQ_HASHSIZE 919 |
---|
93 | |
---|
94 | /* These tcp optinos do not have the size octet */ |
---|
95 | #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) |
---|
96 | |
---|
97 | static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; |
---|
98 | |
---|
99 | struct tok tcp_flag_values[] = { |
---|
100 | { TH_FIN, "F" }, |
---|
101 | { TH_SYN, "S" }, |
---|
102 | { TH_RST, "R" }, |
---|
103 | { TH_PUSH, "P" }, |
---|
104 | { TH_ACK, "." }, |
---|
105 | { TH_URG, "U" }, |
---|
106 | { TH_ECNECHO, "E" }, |
---|
107 | { TH_CWR, "W" }, |
---|
108 | { 0, NULL } |
---|
109 | }; |
---|
110 | |
---|
111 | struct tok tcp_option_values[] = { |
---|
112 | { TCPOPT_EOL, "eol" }, |
---|
113 | { TCPOPT_NOP, "nop" }, |
---|
114 | { TCPOPT_MAXSEG, "mss" }, |
---|
115 | { TCPOPT_WSCALE, "wscale" }, |
---|
116 | { TCPOPT_SACKOK, "sackOK" }, |
---|
117 | { TCPOPT_SACK, "sack" }, |
---|
118 | { TCPOPT_ECHO, "echo" }, |
---|
119 | { TCPOPT_ECHOREPLY, "echoreply" }, |
---|
120 | { TCPOPT_TIMESTAMP, "TS" }, |
---|
121 | { TCPOPT_CC, "cc" }, |
---|
122 | { TCPOPT_CCNEW, "ccnew" }, |
---|
123 | { TCPOPT_CCECHO, "" }, |
---|
124 | { TCPOPT_SIGNATURE, "md5" }, |
---|
125 | { TCPOPT_AUTH, "enhanced auth" }, |
---|
126 | { TCPOPT_UTO, "uto" }, |
---|
127 | { 0, NULL } |
---|
128 | }; |
---|
129 | |
---|
130 | static int tcp_cksum(register const struct ip *ip, |
---|
131 | register const struct tcphdr *tp, |
---|
132 | register u_int len) |
---|
133 | { |
---|
134 | return (nextproto4_cksum(ip, (const u_int8_t *)tp, len, |
---|
135 | IPPROTO_TCP)); |
---|
136 | } |
---|
137 | |
---|
138 | void |
---|
139 | tcp_print(register const u_char *bp, register u_int length, |
---|
140 | register const u_char *bp2, int fragmented) |
---|
141 | { |
---|
142 | register const struct tcphdr *tp; |
---|
143 | register const struct ip *ip; |
---|
144 | register u_char flags; |
---|
145 | register u_int hlen; |
---|
146 | register char ch; |
---|
147 | u_int16_t sport, dport, win, urp; |
---|
148 | u_int32_t seq, ack, thseq, thack; |
---|
149 | u_int utoval; |
---|
150 | int threv; |
---|
151 | #ifdef INET6 |
---|
152 | register const struct ip6_hdr *ip6; |
---|
153 | #endif |
---|
154 | |
---|
155 | tp = (struct tcphdr *)bp; |
---|
156 | ip = (struct ip *)bp2; |
---|
157 | #ifdef INET6 |
---|
158 | if (IP_V(ip) == 6) |
---|
159 | ip6 = (struct ip6_hdr *)bp2; |
---|
160 | else |
---|
161 | ip6 = NULL; |
---|
162 | #endif /*INET6*/ |
---|
163 | ch = '\0'; |
---|
164 | if (!TTEST(tp->th_dport)) { |
---|
165 | (void)printf("%s > %s: [|tcp]", |
---|
166 | ipaddr_string(&ip->ip_src), |
---|
167 | ipaddr_string(&ip->ip_dst)); |
---|
168 | return; |
---|
169 | } |
---|
170 | |
---|
171 | sport = EXTRACT_16BITS(&tp->th_sport); |
---|
172 | dport = EXTRACT_16BITS(&tp->th_dport); |
---|
173 | |
---|
174 | hlen = TH_OFF(tp) * 4; |
---|
175 | |
---|
176 | /* |
---|
177 | * If data present, header length valid, and NFS port used, |
---|
178 | * assume NFS. |
---|
179 | * Pass offset of data plus 4 bytes for RPC TCP msg length |
---|
180 | * to NFS print routines. |
---|
181 | */ |
---|
182 | if (!qflag && hlen >= sizeof(*tp) && hlen <= length && |
---|
183 | (length - hlen) >= 4) { |
---|
184 | u_char *fraglenp; |
---|
185 | u_int32_t fraglen; |
---|
186 | register struct sunrpc_msg *rp; |
---|
187 | enum sunrpc_msg_type direction; |
---|
188 | |
---|
189 | fraglenp = (u_char *)tp + hlen; |
---|
190 | if (TTEST2(*fraglenp, 4)) { |
---|
191 | fraglen = EXTRACT_32BITS(fraglenp) & 0x7FFFFFFF; |
---|
192 | if (fraglen > (length - hlen) - 4) |
---|
193 | fraglen = (length - hlen) - 4; |
---|
194 | rp = (struct sunrpc_msg *)(fraglenp + 4); |
---|
195 | if (TTEST(rp->rm_direction)) { |
---|
196 | direction = (enum sunrpc_msg_type)EXTRACT_32BITS(&rp->rm_direction); |
---|
197 | if (dport == NFS_PORT && |
---|
198 | direction == SUNRPC_CALL) { |
---|
199 | nfsreq_print((u_char *)rp, fraglen, |
---|
200 | (u_char *)ip); |
---|
201 | return; |
---|
202 | } |
---|
203 | if (sport == NFS_PORT && |
---|
204 | direction == SUNRPC_REPLY) { |
---|
205 | nfsreply_print((u_char *)rp, fraglen, |
---|
206 | (u_char *)ip); |
---|
207 | return; |
---|
208 | } |
---|
209 | } |
---|
210 | } |
---|
211 | } |
---|
212 | #ifdef INET6 |
---|
213 | if (ip6) { |
---|
214 | if (ip6->ip6_nxt == IPPROTO_TCP) { |
---|
215 | (void)printf("%s.%s > %s.%s: ", |
---|
216 | ip6addr_string(&ip6->ip6_src), |
---|
217 | tcpport_string(sport), |
---|
218 | ip6addr_string(&ip6->ip6_dst), |
---|
219 | tcpport_string(dport)); |
---|
220 | } else { |
---|
221 | (void)printf("%s > %s: ", |
---|
222 | tcpport_string(sport), tcpport_string(dport)); |
---|
223 | } |
---|
224 | } else |
---|
225 | #endif /*INET6*/ |
---|
226 | { |
---|
227 | if (ip->ip_p == IPPROTO_TCP) { |
---|
228 | (void)printf("%s.%s > %s.%s: ", |
---|
229 | ipaddr_string(&ip->ip_src), |
---|
230 | tcpport_string(sport), |
---|
231 | ipaddr_string(&ip->ip_dst), |
---|
232 | tcpport_string(dport)); |
---|
233 | } else { |
---|
234 | (void)printf("%s > %s: ", |
---|
235 | tcpport_string(sport), tcpport_string(dport)); |
---|
236 | } |
---|
237 | } |
---|
238 | |
---|
239 | if (hlen < sizeof(*tp)) { |
---|
240 | (void)printf(" tcp %d [bad hdr length %u - too short, < %lu]", |
---|
241 | length - hlen, hlen, (unsigned long)sizeof(*tp)); |
---|
242 | return; |
---|
243 | } |
---|
244 | |
---|
245 | TCHECK(*tp); |
---|
246 | |
---|
247 | seq = EXTRACT_32BITS(&tp->th_seq); |
---|
248 | ack = EXTRACT_32BITS(&tp->th_ack); |
---|
249 | win = EXTRACT_16BITS(&tp->th_win); |
---|
250 | urp = EXTRACT_16BITS(&tp->th_urp); |
---|
251 | |
---|
252 | if (qflag) { |
---|
253 | (void)printf("tcp %d", length - hlen); |
---|
254 | if (hlen > length) { |
---|
255 | (void)printf(" [bad hdr length %u - too long, > %u]", |
---|
256 | hlen, length); |
---|
257 | } |
---|
258 | return; |
---|
259 | } |
---|
260 | |
---|
261 | flags = tp->th_flags; |
---|
262 | printf("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags)); |
---|
263 | |
---|
264 | if (!Sflag && (flags & TH_ACK)) { |
---|
265 | register struct tcp_seq_hash *th; |
---|
266 | const void *src, *dst; |
---|
267 | register int rev; |
---|
268 | struct tha tha; |
---|
269 | /* |
---|
270 | * Find (or record) the initial sequence numbers for |
---|
271 | * this conversation. (we pick an arbitrary |
---|
272 | * collating order so there's only one entry for |
---|
273 | * both directions). |
---|
274 | */ |
---|
275 | #ifdef INET6 |
---|
276 | rev = 0; |
---|
277 | if (ip6) { |
---|
278 | src = &ip6->ip6_src; |
---|
279 | dst = &ip6->ip6_dst; |
---|
280 | if (sport > dport) |
---|
281 | rev = 1; |
---|
282 | else if (sport == dport) { |
---|
283 | if (memcmp(src, dst, sizeof ip6->ip6_dst) > 0) |
---|
284 | rev = 1; |
---|
285 | } |
---|
286 | if (rev) { |
---|
287 | memcpy(&tha.src, dst, sizeof ip6->ip6_dst); |
---|
288 | memcpy(&tha.dst, src, sizeof ip6->ip6_src); |
---|
289 | tha.port = dport << 16 | sport; |
---|
290 | } else { |
---|
291 | memcpy(&tha.dst, dst, sizeof ip6->ip6_dst); |
---|
292 | memcpy(&tha.src, src, sizeof ip6->ip6_src); |
---|
293 | tha.port = sport << 16 | dport; |
---|
294 | } |
---|
295 | } else { |
---|
296 | /* |
---|
297 | * Zero out the tha structure; the src and dst |
---|
298 | * fields are big enough to hold an IPv6 |
---|
299 | * address, but we only have IPv4 addresses |
---|
300 | * and thus must clear out the remaining 124 |
---|
301 | * bits. |
---|
302 | * |
---|
303 | * XXX - should we just clear those bytes after |
---|
304 | * copying the IPv4 addresses, rather than |
---|
305 | * zeroing out the entire structure and then |
---|
306 | * overwriting some of the zeroes? |
---|
307 | * |
---|
308 | * XXX - this could fail if we see TCP packets |
---|
309 | * with an IPv6 address with the lower 124 bits |
---|
310 | * all zero and also see TCP packes with an |
---|
311 | * IPv4 address with the same 32 bits as the |
---|
312 | * upper 32 bits of the IPv6 address in question. |
---|
313 | * Can that happen? Is it likely enough to be |
---|
314 | * an issue? |
---|
315 | */ |
---|
316 | memset(&tha, 0, sizeof(tha)); |
---|
317 | src = &ip->ip_src; |
---|
318 | dst = &ip->ip_dst; |
---|
319 | if (sport > dport) |
---|
320 | rev = 1; |
---|
321 | else if (sport == dport) { |
---|
322 | if (memcmp(src, dst, sizeof ip->ip_dst) > 0) |
---|
323 | rev = 1; |
---|
324 | } |
---|
325 | if (rev) { |
---|
326 | memcpy(&tha.src, dst, sizeof ip->ip_dst); |
---|
327 | memcpy(&tha.dst, src, sizeof ip->ip_src); |
---|
328 | tha.port = dport << 16 | sport; |
---|
329 | } else { |
---|
330 | memcpy(&tha.dst, dst, sizeof ip->ip_dst); |
---|
331 | memcpy(&tha.src, src, sizeof ip->ip_src); |
---|
332 | tha.port = sport << 16 | dport; |
---|
333 | } |
---|
334 | } |
---|
335 | #else |
---|
336 | rev = 0; |
---|
337 | src = &ip->ip_src; |
---|
338 | dst = &ip->ip_dst; |
---|
339 | if (sport > dport) |
---|
340 | rev = 1; |
---|
341 | else if (sport == dport) { |
---|
342 | if (memcmp(src, dst, sizeof ip->ip_dst) > 0) |
---|
343 | rev = 1; |
---|
344 | } |
---|
345 | if (rev) { |
---|
346 | memcpy(&tha.src, dst, sizeof ip->ip_dst); |
---|
347 | memcpy(&tha.dst, src, sizeof ip->ip_src); |
---|
348 | tha.port = dport << 16 | sport; |
---|
349 | } else { |
---|
350 | memcpy(&tha.dst, dst, sizeof ip->ip_dst); |
---|
351 | memcpy(&tha.src, src, sizeof ip->ip_src); |
---|
352 | tha.port = sport << 16 | dport; |
---|
353 | } |
---|
354 | #endif |
---|
355 | |
---|
356 | threv = rev; |
---|
357 | for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; |
---|
358 | th->nxt; th = th->nxt) |
---|
359 | if (memcmp((char *)&tha, (char *)&th->addr, |
---|
360 | sizeof(th->addr)) == 0) |
---|
361 | break; |
---|
362 | |
---|
363 | if (!th->nxt || (flags & TH_SYN)) { |
---|
364 | /* didn't find it or new conversation */ |
---|
365 | if (th->nxt == NULL) { |
---|
366 | th->nxt = (struct tcp_seq_hash *) |
---|
367 | calloc(1, sizeof(*th)); |
---|
368 | if (th->nxt == NULL) |
---|
369 | error("tcp_print: calloc"); |
---|
370 | } |
---|
371 | th->addr = tha; |
---|
372 | if (rev) |
---|
373 | th->ack = seq, th->seq = ack - 1; |
---|
374 | else |
---|
375 | th->seq = seq, th->ack = ack - 1; |
---|
376 | } else { |
---|
377 | if (rev) |
---|
378 | seq -= th->ack, ack -= th->seq; |
---|
379 | else |
---|
380 | seq -= th->seq, ack -= th->ack; |
---|
381 | } |
---|
382 | |
---|
383 | thseq = th->seq; |
---|
384 | thack = th->ack; |
---|
385 | } else { |
---|
386 | /*fool gcc*/ |
---|
387 | thseq = thack = threv = 0; |
---|
388 | } |
---|
389 | if (hlen > length) { |
---|
390 | (void)printf(" [bad hdr length %u - too long, > %u]", |
---|
391 | hlen, length); |
---|
392 | return; |
---|
393 | } |
---|
394 | |
---|
395 | if (vflag && !Kflag && !fragmented) { |
---|
396 | /* Check the checksum, if possible. */ |
---|
397 | u_int16_t sum, tcp_sum; |
---|
398 | |
---|
399 | if (IP_V(ip) == 4) { |
---|
400 | if (TTEST2(tp->th_sport, length)) { |
---|
401 | sum = tcp_cksum(ip, tp, length); |
---|
402 | tcp_sum = EXTRACT_16BITS(&tp->th_sum); |
---|
403 | |
---|
404 | (void)printf(", cksum 0x%04x", tcp_sum); |
---|
405 | if (sum != 0) |
---|
406 | (void)printf(" (incorrect -> 0x%04x)", |
---|
407 | in_cksum_shouldbe(tcp_sum, sum)); |
---|
408 | else |
---|
409 | (void)printf(" (correct)"); |
---|
410 | } |
---|
411 | } |
---|
412 | #ifdef INET6 |
---|
413 | else if (IP_V(ip) == 6 && ip6->ip6_plen) { |
---|
414 | if (TTEST2(tp->th_sport, length)) { |
---|
415 | sum = nextproto6_cksum(ip6, (const u_int8_t *)tp, length, IPPROTO_TCP); |
---|
416 | tcp_sum = EXTRACT_16BITS(&tp->th_sum); |
---|
417 | |
---|
418 | (void)printf(", cksum 0x%04x", tcp_sum); |
---|
419 | if (sum != 0) |
---|
420 | (void)printf(" (incorrect -> 0x%04x)", |
---|
421 | in_cksum_shouldbe(tcp_sum, sum)); |
---|
422 | else |
---|
423 | (void)printf(" (correct)"); |
---|
424 | |
---|
425 | } |
---|
426 | } |
---|
427 | #endif |
---|
428 | } |
---|
429 | |
---|
430 | length -= hlen; |
---|
431 | if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) { |
---|
432 | (void)printf(", seq %u", seq); |
---|
433 | |
---|
434 | if (length > 0) { |
---|
435 | (void)printf(":%u", seq + length); |
---|
436 | } |
---|
437 | } |
---|
438 | |
---|
439 | if (flags & TH_ACK) { |
---|
440 | (void)printf(", ack %u", ack); |
---|
441 | } |
---|
442 | |
---|
443 | (void)printf(", win %d", win); |
---|
444 | |
---|
445 | if (flags & TH_URG) |
---|
446 | (void)printf(", urg %d", urp); |
---|
447 | /* |
---|
448 | * Handle any options. |
---|
449 | */ |
---|
450 | if (hlen > sizeof(*tp)) { |
---|
451 | register const u_char *cp; |
---|
452 | register u_int i, opt, datalen; |
---|
453 | register u_int len; |
---|
454 | |
---|
455 | hlen -= sizeof(*tp); |
---|
456 | cp = (const u_char *)tp + sizeof(*tp); |
---|
457 | printf(", options ["); |
---|
458 | while (hlen > 0) { |
---|
459 | if (ch != '\0') |
---|
460 | putchar(ch); |
---|
461 | TCHECK(*cp); |
---|
462 | opt = *cp++; |
---|
463 | if (ZEROLENOPT(opt)) |
---|
464 | len = 1; |
---|
465 | else { |
---|
466 | TCHECK(*cp); |
---|
467 | len = *cp++; /* total including type, len */ |
---|
468 | if (len < 2 || len > hlen) |
---|
469 | goto bad; |
---|
470 | --hlen; /* account for length byte */ |
---|
471 | } |
---|
472 | --hlen; /* account for type byte */ |
---|
473 | datalen = 0; |
---|
474 | |
---|
475 | /* Bail if "l" bytes of data are not left or were not captured */ |
---|
476 | #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } |
---|
477 | |
---|
478 | |
---|
479 | printf("%s", tok2str(tcp_option_values, "Unknown Option %u", opt)); |
---|
480 | |
---|
481 | switch (opt) { |
---|
482 | |
---|
483 | case TCPOPT_MAXSEG: |
---|
484 | datalen = 2; |
---|
485 | LENCHECK(datalen); |
---|
486 | (void)printf(" %u", EXTRACT_16BITS(cp)); |
---|
487 | break; |
---|
488 | |
---|
489 | case TCPOPT_WSCALE: |
---|
490 | datalen = 1; |
---|
491 | LENCHECK(datalen); |
---|
492 | (void)printf(" %u", *cp); |
---|
493 | break; |
---|
494 | |
---|
495 | case TCPOPT_SACK: |
---|
496 | datalen = len - 2; |
---|
497 | if (datalen % 8 != 0) { |
---|
498 | (void)printf("malformed sack"); |
---|
499 | } else { |
---|
500 | u_int32_t s, e; |
---|
501 | |
---|
502 | (void)printf(" %d ", datalen / 8); |
---|
503 | for (i = 0; i < datalen; i += 8) { |
---|
504 | LENCHECK(i + 4); |
---|
505 | s = EXTRACT_32BITS(cp + i); |
---|
506 | LENCHECK(i + 8); |
---|
507 | e = EXTRACT_32BITS(cp + i + 4); |
---|
508 | if (threv) { |
---|
509 | s -= thseq; |
---|
510 | e -= thseq; |
---|
511 | } else { |
---|
512 | s -= thack; |
---|
513 | e -= thack; |
---|
514 | } |
---|
515 | (void)printf("{%u:%u}", s, e); |
---|
516 | } |
---|
517 | } |
---|
518 | break; |
---|
519 | |
---|
520 | case TCPOPT_CC: |
---|
521 | case TCPOPT_CCNEW: |
---|
522 | case TCPOPT_CCECHO: |
---|
523 | case TCPOPT_ECHO: |
---|
524 | case TCPOPT_ECHOREPLY: |
---|
525 | |
---|
526 | /* |
---|
527 | * those options share their semantics. |
---|
528 | * fall through |
---|
529 | */ |
---|
530 | datalen = 4; |
---|
531 | LENCHECK(datalen); |
---|
532 | (void)printf(" %u", EXTRACT_32BITS(cp)); |
---|
533 | break; |
---|
534 | |
---|
535 | case TCPOPT_TIMESTAMP: |
---|
536 | datalen = 8; |
---|
537 | LENCHECK(datalen); |
---|
538 | (void)printf(" val %u ecr %u", |
---|
539 | EXTRACT_32BITS(cp), |
---|
540 | EXTRACT_32BITS(cp + 4)); |
---|
541 | break; |
---|
542 | |
---|
543 | case TCPOPT_SIGNATURE: |
---|
544 | datalen = TCP_SIGLEN; |
---|
545 | LENCHECK(datalen); |
---|
546 | #ifdef HAVE_LIBCRYPTO |
---|
547 | switch (tcp_verify_signature(ip, tp, |
---|
548 | bp + TH_OFF(tp) * 4, length, cp)) { |
---|
549 | |
---|
550 | case SIGNATURE_VALID: |
---|
551 | (void)printf("valid"); |
---|
552 | break; |
---|
553 | |
---|
554 | case SIGNATURE_INVALID: |
---|
555 | (void)printf("invalid"); |
---|
556 | break; |
---|
557 | |
---|
558 | case CANT_CHECK_SIGNATURE: |
---|
559 | (void)printf("can't check - "); |
---|
560 | for (i = 0; i < TCP_SIGLEN; ++i) |
---|
561 | (void)printf("%02x", cp[i]); |
---|
562 | break; |
---|
563 | } |
---|
564 | #else |
---|
565 | for (i = 0; i < TCP_SIGLEN; ++i) |
---|
566 | (void)printf("%02x", cp[i]); |
---|
567 | #endif |
---|
568 | break; |
---|
569 | |
---|
570 | case TCPOPT_AUTH: |
---|
571 | (void)printf("keyid %d", *cp++); |
---|
572 | datalen = len - 3; |
---|
573 | for (i = 0; i < datalen; ++i) { |
---|
574 | LENCHECK(i); |
---|
575 | (void)printf("%02x", cp[i]); |
---|
576 | } |
---|
577 | break; |
---|
578 | |
---|
579 | |
---|
580 | case TCPOPT_EOL: |
---|
581 | case TCPOPT_NOP: |
---|
582 | case TCPOPT_SACKOK: |
---|
583 | /* |
---|
584 | * Nothing interesting. |
---|
585 | * fall through |
---|
586 | */ |
---|
587 | break; |
---|
588 | |
---|
589 | case TCPOPT_UTO: |
---|
590 | datalen = 2; |
---|
591 | LENCHECK(datalen); |
---|
592 | utoval = EXTRACT_16BITS(cp); |
---|
593 | (void)printf("0x%x", utoval); |
---|
594 | if (utoval & 0x0001) |
---|
595 | utoval = (utoval >> 1) * 60; |
---|
596 | else |
---|
597 | utoval >>= 1; |
---|
598 | (void)printf(" %u", utoval); |
---|
599 | break; |
---|
600 | |
---|
601 | default: |
---|
602 | datalen = len - 2; |
---|
603 | for (i = 0; i < datalen; ++i) { |
---|
604 | LENCHECK(i); |
---|
605 | (void)printf("%02x", cp[i]); |
---|
606 | } |
---|
607 | break; |
---|
608 | } |
---|
609 | |
---|
610 | /* Account for data printed */ |
---|
611 | cp += datalen; |
---|
612 | hlen -= datalen; |
---|
613 | |
---|
614 | /* Check specification against observed length */ |
---|
615 | ++datalen; /* option octet */ |
---|
616 | if (!ZEROLENOPT(opt)) |
---|
617 | ++datalen; /* size octet */ |
---|
618 | if (datalen != len) |
---|
619 | (void)printf("[len %d]", len); |
---|
620 | ch = ','; |
---|
621 | if (opt == TCPOPT_EOL) |
---|
622 | break; |
---|
623 | } |
---|
624 | putchar(']'); |
---|
625 | } |
---|
626 | |
---|
627 | /* |
---|
628 | * Print length field before crawling down the stack. |
---|
629 | */ |
---|
630 | printf(", length %u", length); |
---|
631 | |
---|
632 | if (length <= 0) |
---|
633 | return; |
---|
634 | |
---|
635 | /* |
---|
636 | * Decode payload if necessary. |
---|
637 | */ |
---|
638 | bp += TH_OFF(tp) * 4; |
---|
639 | if ((flags & TH_RST) && vflag) { |
---|
640 | print_tcp_rst_data(bp, length); |
---|
641 | return; |
---|
642 | } |
---|
643 | |
---|
644 | if (packettype) { |
---|
645 | switch (packettype) { |
---|
646 | case PT_ZMTP1: |
---|
647 | zmtp1_print(bp, length); |
---|
648 | break; |
---|
649 | } |
---|
650 | return; |
---|
651 | } |
---|
652 | |
---|
653 | if (sport == TELNET_PORT || dport == TELNET_PORT) { |
---|
654 | if (!qflag && vflag) |
---|
655 | telnet_print(bp, length); |
---|
656 | } else if (sport == BGP_PORT || dport == BGP_PORT) |
---|
657 | bgp_print(bp, length); |
---|
658 | else if (sport == PPTP_PORT || dport == PPTP_PORT) |
---|
659 | pptp_print(bp); |
---|
660 | #ifdef TCPDUMP_DO_SMB |
---|
661 | else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT) |
---|
662 | nbt_tcp_print(bp, length); |
---|
663 | else if (sport == SMB_PORT || dport == SMB_PORT) |
---|
664 | smb_tcp_print(bp, length); |
---|
665 | #endif |
---|
666 | else if (sport == BEEP_PORT || dport == BEEP_PORT) |
---|
667 | beep_print(bp, length); |
---|
668 | else if (length > 2 && |
---|
669 | (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT || |
---|
670 | sport == MULTICASTDNS_PORT || dport == MULTICASTDNS_PORT)) { |
---|
671 | /* |
---|
672 | * TCP DNS query has 2byte length at the head. |
---|
673 | * XXX packet could be unaligned, it can go strange |
---|
674 | */ |
---|
675 | ns_print(bp + 2, length - 2, 0); |
---|
676 | } else if (sport == MSDP_PORT || dport == MSDP_PORT) { |
---|
677 | msdp_print(bp, length); |
---|
678 | } else if (sport == RPKI_RTR_PORT || dport == RPKI_RTR_PORT) { |
---|
679 | rpki_rtr_print(bp, length); |
---|
680 | } |
---|
681 | else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) { |
---|
682 | ldp_print(bp, length); |
---|
683 | } |
---|
684 | |
---|
685 | return; |
---|
686 | bad: |
---|
687 | fputs("[bad opt]", stdout); |
---|
688 | if (ch != '\0') |
---|
689 | putchar('>'); |
---|
690 | return; |
---|
691 | trunc: |
---|
692 | fputs("[|tcp]", stdout); |
---|
693 | if (ch != '\0') |
---|
694 | putchar('>'); |
---|
695 | } |
---|
696 | |
---|
697 | /* |
---|
698 | * RFC1122 says the following on data in RST segments: |
---|
699 | * |
---|
700 | * 4.2.2.12 RST Segment: RFC-793 Section 3.4 |
---|
701 | * |
---|
702 | * A TCP SHOULD allow a received RST segment to include data. |
---|
703 | * |
---|
704 | * DISCUSSION |
---|
705 | * It has been suggested that a RST segment could contain |
---|
706 | * ASCII text that encoded and explained the cause of the |
---|
707 | * RST. No standard has yet been established for such |
---|
708 | * data. |
---|
709 | * |
---|
710 | */ |
---|
711 | |
---|
712 | static void |
---|
713 | print_tcp_rst_data(register const u_char *sp, u_int length) |
---|
714 | { |
---|
715 | int c; |
---|
716 | |
---|
717 | if (TTEST2(*sp, length)) |
---|
718 | printf(" [RST"); |
---|
719 | else |
---|
720 | printf(" [!RST"); |
---|
721 | if (length > MAX_RST_DATA_LEN) { |
---|
722 | length = MAX_RST_DATA_LEN; /* can use -X for longer */ |
---|
723 | putchar('+'); /* indicate we truncate */ |
---|
724 | } |
---|
725 | putchar(' '); |
---|
726 | while (length-- && sp <= snapend) { |
---|
727 | c = *sp++; |
---|
728 | safeputchar(c); |
---|
729 | } |
---|
730 | putchar(']'); |
---|
731 | } |
---|
732 | |
---|
733 | #ifdef HAVE_LIBCRYPTO |
---|
734 | static int |
---|
735 | tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, |
---|
736 | const u_char *data, int length, const u_char *rcvsig) |
---|
737 | { |
---|
738 | struct tcphdr tp1; |
---|
739 | u_char sig[TCP_SIGLEN]; |
---|
740 | char zero_proto = 0; |
---|
741 | MD5_CTX ctx; |
---|
742 | u_int16_t savecsum, tlen; |
---|
743 | #ifdef INET6 |
---|
744 | struct ip6_hdr *ip6; |
---|
745 | u_int32_t len32; |
---|
746 | u_int8_t nxt; |
---|
747 | #endif |
---|
748 | |
---|
749 | if (data + length > snapend) { |
---|
750 | printf("snaplen too short, "); |
---|
751 | return (CANT_CHECK_SIGNATURE); |
---|
752 | } |
---|
753 | |
---|
754 | tp1 = *tp; |
---|
755 | |
---|
756 | if (sigsecret == NULL) { |
---|
757 | printf("shared secret not supplied with -M, "); |
---|
758 | return (CANT_CHECK_SIGNATURE); |
---|
759 | } |
---|
760 | |
---|
761 | MD5_Init(&ctx); |
---|
762 | /* |
---|
763 | * Step 1: Update MD5 hash with IP pseudo-header. |
---|
764 | */ |
---|
765 | if (IP_V(ip) == 4) { |
---|
766 | MD5_Update(&ctx, (char *)&ip->ip_src, sizeof(ip->ip_src)); |
---|
767 | MD5_Update(&ctx, (char *)&ip->ip_dst, sizeof(ip->ip_dst)); |
---|
768 | MD5_Update(&ctx, (char *)&zero_proto, sizeof(zero_proto)); |
---|
769 | MD5_Update(&ctx, (char *)&ip->ip_p, sizeof(ip->ip_p)); |
---|
770 | tlen = EXTRACT_16BITS(&ip->ip_len) - IP_HL(ip) * 4; |
---|
771 | tlen = htons(tlen); |
---|
772 | MD5_Update(&ctx, (char *)&tlen, sizeof(tlen)); |
---|
773 | #ifdef INET6 |
---|
774 | } else if (IP_V(ip) == 6) { |
---|
775 | ip6 = (struct ip6_hdr *)ip; |
---|
776 | MD5_Update(&ctx, (char *)&ip6->ip6_src, sizeof(ip6->ip6_src)); |
---|
777 | MD5_Update(&ctx, (char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst)); |
---|
778 | len32 = htonl(EXTRACT_16BITS(&ip6->ip6_plen)); |
---|
779 | MD5_Update(&ctx, (char *)&len32, sizeof(len32)); |
---|
780 | nxt = 0; |
---|
781 | MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); |
---|
782 | MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); |
---|
783 | MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); |
---|
784 | nxt = IPPROTO_TCP; |
---|
785 | MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); |
---|
786 | #endif |
---|
787 | } else { |
---|
788 | #ifdef INET6 |
---|
789 | printf("IP version not 4 or 6, "); |
---|
790 | #else |
---|
791 | printf("IP version not 4, "); |
---|
792 | #endif |
---|
793 | return (CANT_CHECK_SIGNATURE); |
---|
794 | } |
---|
795 | |
---|
796 | /* |
---|
797 | * Step 2: Update MD5 hash with TCP header, excluding options. |
---|
798 | * The TCP checksum must be set to zero. |
---|
799 | */ |
---|
800 | savecsum = tp1.th_sum; |
---|
801 | tp1.th_sum = 0; |
---|
802 | MD5_Update(&ctx, (char *)&tp1, sizeof(struct tcphdr)); |
---|
803 | tp1.th_sum = savecsum; |
---|
804 | /* |
---|
805 | * Step 3: Update MD5 hash with TCP segment data, if present. |
---|
806 | */ |
---|
807 | if (length > 0) |
---|
808 | MD5_Update(&ctx, data, length); |
---|
809 | /* |
---|
810 | * Step 4: Update MD5 hash with shared secret. |
---|
811 | */ |
---|
812 | MD5_Update(&ctx, sigsecret, strlen(sigsecret)); |
---|
813 | MD5_Final(sig, &ctx); |
---|
814 | |
---|
815 | if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0) |
---|
816 | return (SIGNATURE_VALID); |
---|
817 | else |
---|
818 | return (SIGNATURE_INVALID); |
---|
819 | } |
---|
820 | #endif /* HAVE_LIBCRYPTO */ |
---|
821 | |
---|
822 | /* |
---|
823 | * Local Variables: |
---|
824 | * c-style: whitesmith |
---|
825 | * c-basic-offset: 8 |
---|
826 | * End: |
---|
827 | */ |
---|