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