xref: /openbsd-src/usr.sbin/tcpdump/print-tcp.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
1 /*	$OpenBSD: print-tcp.c,v 1.19 2004/01/15 12:27:07 markus 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  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23 
24 #ifndef lint
25 static const char rcsid[] =
26     "@(#) $Header: /home/cvs/src/usr.sbin/tcpdump/print-tcp.c,v 1.19 2004/01/15 12:27:07 markus Exp $ (LBL)";
27 #endif
28 
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/socket.h>
32 
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/ip.h>
36 #include <netinet/ip_var.h>
37 #include <netinet/tcp.h>
38 #include <netinet/tcpip.h>
39 #include <net/if.h>
40 #include <net/pfvar.h>
41 
42 #include <rpc/rpc.h>
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 
49 #ifdef INET6
50 #include <netinet/ip6.h>
51 #endif
52 
53 #include "interface.h"
54 #include "addrtoname.h"
55 #include "extract.h"
56 
57 #include "nfs.h"
58 
59 static void print_tcp_rst_data(register const u_char *sp, u_int length);
60 
61 #define MAX_RST_DATA_LEN	30
62 
63 /* Compatibility */
64 #ifndef TCPOPT_WSCALE
65 #define	TCPOPT_WSCALE		3	/* window scale factor (rfc1072) */
66 #endif
67 #ifndef TCPOPT_SACKOK
68 #define	TCPOPT_SACKOK		4	/* selective ack ok (rfc2018) */
69 #endif
70 #ifndef TCPOPT_SACK
71 #define	TCPOPT_SACK		5	/* selective ack (rfc2018) */
72 #endif
73 #ifndef TCPOLEN_SACK
74 #define TCPOLEN_SACK		8	/* length of a SACK block */
75 #endif
76 #ifndef TCPOPT_ECHO
77 #define	TCPOPT_ECHO		6	/* echo (rfc1072) */
78 #endif
79 #ifndef TCPOPT_ECHOREPLY
80 #define	TCPOPT_ECHOREPLY	7	/* echo (rfc1072) */
81 #endif
82 #ifndef TCPOPT_TIMESTAMP
83 #define TCPOPT_TIMESTAMP	8	/* timestamps (rfc1323) */
84 #endif
85 #ifndef TCPOPT_CC
86 #define TCPOPT_CC		11	/* T/TCP CC options (rfc1644) */
87 #endif
88 #ifndef TCPOPT_CCNEW
89 #define TCPOPT_CCNEW		12	/* T/TCP CC options (rfc1644) */
90 #endif
91 #ifndef TCPOPT_CCECHO
92 #define TCPOPT_CCECHO		13	/* T/TCP CC options (rfc1644) */
93 #endif
94 
95 /* Definitions required for ECN
96    for use if the OS running tcpdump does not have ECN */
97 #ifndef TH_ECNECHO
98 #define TH_ECNECHO		0x40	/* ECN Echo in tcp header */
99 #endif
100 #ifndef TH_CWR
101 #define TH_CWR			0x80	/* ECN Cwnd Reduced in tcp header*/
102 #endif
103 
104 struct tha {
105 #ifndef INET6
106 	struct in_addr src;
107 	struct in_addr dst;
108 #else
109 	struct in6_addr src;
110 	struct in6_addr dst;
111 #endif /*INET6*/
112 	u_int port;
113 };
114 
115 struct tcp_seq_hash {
116 	struct tcp_seq_hash *nxt;
117 	struct tha addr;
118 	tcp_seq seq;
119 	tcp_seq ack;
120 };
121 
122 #define TSEQ_HASHSIZE 919
123 
124 /* These tcp optinos do not have the size octet */
125 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
126 
127 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
128 
129 #ifndef BGP_PORT
130 #define BGP_PORT        179
131 #endif
132 #define NETBIOS_SSN_PORT 139
133 
134 static int tcp_cksum(register const struct ip *ip,
135 		     register const struct tcphdr *tp,
136 		     register int len)
137 {
138 	int i, tlen;
139 	union phu {
140 		struct phdr {
141 			u_int32_t src;
142 			u_int32_t dst;
143 			u_char mbz;
144 			u_char proto;
145 			u_int16_t len;
146 		} ph;
147 		u_int16_t pa[6];
148 	} phu;
149 	register const u_int16_t *sp;
150 	u_int32_t sum;
151 	tlen = ntohs(ip->ip_len) - ((const char *)tp-(const char*)ip);
152 
153 	/* pseudo-header.. */
154 	phu.ph.len = htons(tlen);
155 	phu.ph.mbz = 0;
156 	phu.ph.proto = ip->ip_p;
157 	memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
158 	memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
159 
160 	sp = &phu.pa[0];
161 	sum = sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5];
162 
163 	sp = (const u_int16_t *)tp;
164 
165 	for (i=0; i<(tlen&~1); i+= 2)
166 		sum += *sp++;
167 
168 	if (tlen & 1) {
169 		sum += htons( (*(const char *)sp) << 8);
170 	}
171 
172 	while (sum > 0xffff)
173 		sum = (sum & 0xffff) + (sum >> 16);
174 	sum = ~sum & 0xffff;
175 
176 	return (sum);
177 }
178 
179 
180 void
181 tcp_print(register const u_char *bp, register u_int length,
182 	  register const u_char *bp2)
183 {
184 	register const struct tcphdr *tp;
185 	register const struct ip *ip;
186 	register u_char flags;
187 	register int hlen;
188 	register char ch;
189 	register struct tcp_seq_hash *th = NULL;
190 	register int rev = 0;
191 	u_int16_t sport, dport, win, urp;
192 	tcp_seq seq, ack;
193 #ifdef INET6
194 	register const struct ip6_hdr *ip6;
195 #endif
196 
197 	tp = (struct tcphdr *)bp;
198 	ip = (struct ip *)bp2;
199 #ifdef INET6
200 	if (ip->ip_v == 6)
201 		ip6 = (struct ip6_hdr *)bp2;
202 	else
203 		ip6 = NULL;
204 #endif /*INET6*/
205 	ch = '\0';
206 	TCHECK(*tp);
207 	if (length < sizeof(*tp)) {
208 		(void)printf("truncated-tcp %d", length);
209 		return;
210 	}
211 
212 	sport = ntohs(tp->th_sport);
213 	dport = ntohs(tp->th_dport);
214 	seq = ntohl(tp->th_seq);
215 	ack = ntohl(tp->th_ack);
216 	win = ntohs(tp->th_win);
217 	urp = ntohs(tp->th_urp);
218 	hlen = tp->th_off * 4;
219 
220 
221 #ifdef INET6
222 	if (ip6) {
223 		if (ip6->ip6_nxt == IPPROTO_TCP) {
224 			(void)printf("%s.%s > %s.%s: ",
225 				ip6addr_string(&ip6->ip6_src),
226 				tcpport_string(sport),
227 				ip6addr_string(&ip6->ip6_dst),
228 				tcpport_string(dport));
229 		} else {
230 			(void)printf("%s > %s: ",
231 				tcpport_string(sport), tcpport_string(dport));
232 		}
233 	} else
234 #endif /*INET6*/
235 	{
236 		if (ip->ip_p == IPPROTO_TCP) {
237 			(void)printf("%s.%s > %s.%s: ",
238 				ipaddr_string(&ip->ip_src),
239 				tcpport_string(sport),
240 				ipaddr_string(&ip->ip_dst),
241 				tcpport_string(dport));
242 		} else {
243 			(void)printf("%s > %s: ",
244 				tcpport_string(sport), tcpport_string(dport));
245 		}
246 	}
247 
248 	if (qflag) {
249 		(void)printf("tcp %d", length - tp->th_off * 4);
250 		return;
251 	} else {
252 		/*
253 		 * If data present and NFS port used, assume NFS.
254 		 * Pass offset of data plus 4 bytes for RPC TCP msg length
255 		 * to NFS print routines.
256 		 */
257 		u_int len = length - hlen;
258 		if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend &&
259 		    dport == NFS_PORT) {
260 			nfsreq_print((u_char *)tp + hlen + 4, len,
261 				     (u_char *)ip);
262 			return;
263 		} else if ((u_char *)tp + 4 +
264 		    sizeof(struct rpc_msg) <= snapend && sport == NFS_PORT) {
265 			nfsreply_print((u_char *)tp + hlen + 4, len,
266 				       (u_char *)ip);
267 			return;
268 		}
269 	}
270 	if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|
271 				      TH_ECNECHO|TH_CWR)) {
272 		if (flags & TH_SYN)
273 			putchar('S');
274 		if (flags & TH_FIN)
275 			putchar('F');
276 		if (flags & TH_RST)
277 			putchar('R');
278 		if (flags & TH_PUSH)
279 			putchar('P');
280 		if (flags & TH_CWR)
281 			putchar('W');	/* congestion _W_indow reduced (ECN) */
282 		if (flags & TH_ECNECHO)
283 			putchar('E');	/* ecn _E_cho sent (ECN) */
284 	} else
285 		putchar('.');
286 
287 	if (!Sflag && (flags & TH_ACK)) {
288 		struct tha tha;
289 		/*
290 		 * Find (or record) the initial sequence numbers for
291 		 * this conversation.  (we pick an arbitrary
292 		 * collating order so there's only one entry for
293 		 * both directions).
294 		 */
295 #ifdef INET6
296 		bzero(&tha, sizeof(tha));
297 		rev = 0;
298 		if (ip6) {
299 			if (sport > dport) {
300 				rev = 1;
301 			} else if (sport == dport) {
302 			    int i;
303 
304 			    for (i = 0; i < 4; i++) {
305 				if (((u_int32_t *)(&ip6->ip6_src))[i] >
306 				    ((u_int32_t *)(&ip6->ip6_dst))[i]) {
307 					rev = 1;
308 					break;
309 				}
310 			    }
311 			}
312 			if (rev) {
313 				tha.src = ip6->ip6_dst;
314 				tha.dst = ip6->ip6_src;
315 				tha.port = dport << 16 | sport;
316 			} else {
317 				tha.dst = ip6->ip6_dst;
318 				tha.src = ip6->ip6_src;
319 				tha.port = sport << 16 | dport;
320 			}
321 		} else {
322 			if (sport > dport ||
323 			    (sport == dport &&
324 			     ip->ip_src.s_addr > ip->ip_dst.s_addr)) {
325 				rev = 1;
326 			}
327 			if (rev) {
328 				*(struct in_addr *)&tha.src = ip->ip_dst;
329 				*(struct in_addr *)&tha.dst = ip->ip_src;
330 				tha.port = dport << 16 | sport;
331 			} else {
332 				*(struct in_addr *)&tha.dst = ip->ip_dst;
333 				*(struct in_addr *)&tha.src = ip->ip_src;
334 				tha.port = sport << 16 | dport;
335 			}
336 		}
337 #else
338 		if (sport < dport ||
339 		    (sport == dport &&
340 		     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
341 			tha.src = ip->ip_src, tha.dst = ip->ip_dst;
342 			tha.port = sport << 16 | dport;
343 			rev = 0;
344 		} else {
345 			tha.src = ip->ip_dst, tha.dst = ip->ip_src;
346 			tha.port = dport << 16 | sport;
347 			rev = 1;
348 		}
349 #endif
350 
351 		for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
352 		     th->nxt; th = th->nxt)
353 			if (!memcmp((char *)&tha, (char *)&th->addr,
354 				  sizeof(th->addr)))
355 				break;
356 
357 		if (!th->nxt || flags & TH_SYN) {
358 			/* didn't find it or new conversation */
359 			if (th->nxt == NULL) {
360 				th->nxt = (struct tcp_seq_hash *)
361 					calloc(1, sizeof(*th));
362 				if (th->nxt == NULL)
363 					error("tcp_print: calloc");
364 			}
365 			th->addr = tha;
366 			if (rev)
367 				th->ack = seq, th->seq = ack - 1;
368 			else
369 				th->seq = seq, th->ack = ack - 1;
370 		} else {
371 			if (rev)
372 				seq -= th->ack, ack -= th->seq;
373 			else
374 				seq -= th->seq, ack -= th->ack;
375 		}
376 	}
377 	hlen = tp->th_off * 4;
378 	if (hlen > length) {
379 		(void)printf(" [bad hdr length]");
380 		return;
381 	}
382 
383 	if (ip->ip_v == 4 && vflag) {
384 		int sum;
385 		if (TTEST2(tp->th_sport, length)) {
386 			sum = tcp_cksum(ip, tp, length);
387 			if (sum != 0)
388 				(void)printf(" [bad tcp cksum %x!]", sum);
389 			else
390 				(void)printf(" [tcp sum ok]");
391 		}
392 	}
393 
394 	/* OS Fingerprint */
395 	if (oflag &&
396 #ifdef INET6
397 	    ip6 == NULL &&
398 #endif
399 	    (flags & (TH_SYN|TH_ACK)) == TH_SYN) {
400 		struct pf_osfp_enlist *head = NULL;
401 		struct pf_osfp_entry *fp;
402 		unsigned long left;
403 		left = (unsigned long)(snapend - (const u_char *)tp);
404 
405 		if (left >= hlen)
406 			head = pf_osfp_fingerprint_hdr(ip, tp);
407 		if (head) {
408 			int prev = 0;
409 			printf(" (src OS:");
410 			SLIST_FOREACH(fp, head, fp_entry) {
411 				if (fp->fp_enflags & PF_OSFP_EXPANDED)
412 					continue;
413 				if (prev)
414 					printf(",");
415 				printf(" %s", fp->fp_class_nm);
416 				if (fp->fp_version_nm[0])
417 					printf(" %s", fp->fp_version_nm);
418 				if (fp->fp_subtype_nm[0])
419 					printf(" %s", fp->fp_subtype_nm);
420 				prev = 1;
421 			}
422 			printf(")");
423 		} else {
424 			if (left < hlen)
425 				printf(" (src OS: short-pkt)");
426 			else
427 				printf(" (src OS: unknown)");
428 		}
429 	}
430 
431 	length -= hlen;
432 	if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
433 		(void)printf(" %lu:%lu(%d)", (long) seq, (long) (seq + length),
434 		    length);
435 	if (flags & TH_ACK)
436 		(void)printf(" ack %u", ack);
437 
438 	(void)printf(" win %d", win);
439 
440 	if (flags & TH_URG)
441 		(void)printf(" urg %d", urp);
442 	/*
443 	 * Handle any options.
444 	 */
445 	if ((hlen -= sizeof(*tp)) > 0) {
446 		register const u_char *cp;
447 		register int i, opt, len, datalen;
448 
449 		cp = (const u_char *)tp + sizeof(*tp);
450 		putchar(' ');
451 		ch = '<';
452 		while (hlen > 0) {
453 			putchar(ch);
454 			TCHECK(*cp);
455 			opt = *cp++;
456 			if (ZEROLENOPT(opt))
457 				len = 1;
458 			else {
459 				TCHECK(*cp);
460 				len = *cp++;	/* total including type, len */
461 				if (len < 2 || len > hlen)
462 					goto bad;
463 				--hlen;		/* account for length byte */
464 			}
465 			--hlen;			/* account for type byte */
466 			datalen = 0;
467 
468 /* Bail if "l" bytes of data are not left or were not captured  */
469 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
470 
471 			switch (opt) {
472 
473 			case TCPOPT_MAXSEG:
474 				(void)printf("mss");
475 				datalen = 2;
476 				LENCHECK(datalen);
477 				(void)printf(" %u", EXTRACT_16BITS(cp));
478 
479 				break;
480 
481 			case TCPOPT_EOL:
482 				(void)printf("eol");
483 				break;
484 
485 			case TCPOPT_NOP:
486 				(void)printf("nop");
487 				break;
488 
489 			case TCPOPT_WSCALE:
490 				(void)printf("wscale");
491 				datalen = 1;
492 				LENCHECK(datalen);
493 				(void)printf(" %u", *cp);
494 				break;
495 
496 			case TCPOPT_SACKOK:
497 				(void)printf("sackOK");
498 				if (len != 2)
499 					(void)printf("[len %d]", len);
500 				break;
501 
502 			case TCPOPT_SACK:
503 			{
504 				u_long s, e;
505 
506 				datalen = len - 2;
507 				if ((datalen % TCPOLEN_SACK) != 0 ||
508 				    !(flags & TH_ACK)) {
509 				         (void)printf("malformed sack ");
510 					 (void)printf("[len %d] ", datalen);
511 					 break;
512 				}
513 				printf("sack %d ", datalen/TCPOLEN_SACK);
514 				for (i = 0; i < datalen; i += TCPOLEN_SACK) {
515 					LENCHECK (i + TCPOLEN_SACK);
516 					s = EXTRACT_32BITS(cp + i);
517 					e = EXTRACT_32BITS(cp + i + 4);
518 					if (!Sflag) {
519 						if (rev) {
520 							s -= th->seq;
521 							e -= th->seq;
522 						} else {
523 							s -= th->ack;
524 							e -= th->ack;
525 						}
526 					}
527 					(void) printf("{%lu:%lu} ", s, e);
528 				}
529 				break;
530 			}
531 			case TCPOPT_ECHO:
532 				(void)printf("echo");
533 				datalen = 4;
534 				LENCHECK(datalen);
535 				(void)printf(" %u", EXTRACT_32BITS(cp));
536 				break;
537 
538 			case TCPOPT_ECHOREPLY:
539 				(void)printf("echoreply");
540 				datalen = 4;
541 				LENCHECK(datalen);
542 				(void)printf(" %u", EXTRACT_32BITS(cp));
543 				break;
544 
545 			case TCPOPT_TIMESTAMP:
546 				(void)printf("timestamp");
547 				datalen = 8;
548 				LENCHECK(4);
549 				(void)printf(" %u", EXTRACT_32BITS(cp));
550 				LENCHECK(datalen);
551 				(void)printf(" %u", EXTRACT_32BITS(cp + 4));
552 				break;
553 
554 			case TCPOPT_CC:
555 				(void)printf("cc");
556 				datalen = 4;
557 				LENCHECK(datalen);
558 				(void)printf(" %u", EXTRACT_32BITS(cp));
559 				break;
560 
561 			case TCPOPT_CCNEW:
562 				(void)printf("ccnew");
563 				datalen = 4;
564 				LENCHECK(datalen);
565 				(void)printf(" %u", EXTRACT_32BITS(cp));
566 				break;
567 
568 			case TCPOPT_CCECHO:
569 				(void)printf("ccecho");
570 				datalen = 4;
571 				LENCHECK(datalen);
572 				(void)printf(" %u", EXTRACT_32BITS(cp));
573 				break;
574 
575 			case TCPOPT_SIGNATURE:
576 				(void)printf("tcpmd5:");
577 				datalen = len - 2;
578 				for (i = 0; i < datalen; ++i) {
579 					LENCHECK(i);
580 					(void)printf("%02x", cp[i]);
581 				}
582 				break;
583 
584 			default:
585 				(void)printf("opt-%d:", opt);
586 				datalen = len - 2;
587 				for (i = 0; i < datalen; ++i) {
588 					LENCHECK(i);
589 					(void)printf("%02x", cp[i]);
590 				}
591 				break;
592 			}
593 
594 			/* Account for data printed */
595 			cp += datalen;
596 			hlen -= datalen;
597 
598 			/* Check specification against observed length */
599 			++datalen;			/* option octet */
600 			if (!ZEROLENOPT(opt))
601 				++datalen;		/* size octet */
602 			if (datalen != len)
603 				(void)printf("[len %d]", len);
604 			ch = ',';
605 			if (opt == TCPOPT_EOL)
606 				break;
607 		}
608 		putchar('>');
609 	}
610 
611 	if (length <= 0)
612 		return;
613 
614 	/*
615 	 * Decode payload if necessary.
616 	*/
617 	bp += (tp->th_off * 4);
618 	if (flags & TH_RST) {
619 		if (vflag)
620 			print_tcp_rst_data(bp, length);
621 	} else {
622 		if (sport == BGP_PORT || dport == BGP_PORT)
623 			bgp_print(bp, length);
624 #if 0
625 		else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
626 			nbt_tcp_print(bp, length);
627 #endif
628 	}
629 	return;
630 bad:
631 	fputs("[bad opt]", stdout);
632 	if (ch != '\0')
633 		putchar('>');
634 	return;
635 trunc:
636 	fputs("[|tcp]", stdout);
637 	if (ch != '\0')
638 		putchar('>');
639 }
640 
641 
642 /*
643  * RFC1122 says the following on data in RST segments:
644  *
645  *         4.2.2.12  RST Segment: RFC-793 Section 3.4
646  *
647  *            A TCP SHOULD allow a received RST segment to include data.
648  *
649  *            DISCUSSION
650  *                 It has been suggested that a RST segment could contain
651  *                 ASCII text that encoded and explained the cause of the
652  *                 RST.  No standard has yet been established for such
653  *                 data.
654  *
655  */
656 
657 static void
658 print_tcp_rst_data(register const u_char *sp, u_int length)
659 {
660 	int c;
661 
662 	if (TTEST2(*sp, length))
663 		printf(" [RST");
664 	else
665 		printf(" [!RST");
666 	if (length > MAX_RST_DATA_LEN) {
667 		length = MAX_RST_DATA_LEN;	/* can use -X for longer */
668 		putchar('+');			/* indicate we truncate */
669 	}
670 	putchar(' ');
671 	while (length-- && sp <= snapend) {
672 		c = *sp++;
673 		safeputchar(c);
674 	}
675 	putchar(']');
676 }
677