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