xref: /freebsd/contrib/tcpdump/print-tcp.c (revision 4de76e31)
14edb46e9SPaul Traina /*
24edb46e9SPaul Traina  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
34edb46e9SPaul Traina  *	The Regents of the University of California.  All rights reserved.
44edb46e9SPaul Traina  *
54edb46e9SPaul Traina  * Redistribution and use in source and binary forms, with or without
64edb46e9SPaul Traina  * modification, are permitted provided that: (1) source code distributions
74edb46e9SPaul Traina  * retain the above copyright notice and this paragraph in its entirety, (2)
84edb46e9SPaul Traina  * distributions including binary code include the above copyright notice and
94edb46e9SPaul Traina  * this paragraph in its entirety in the documentation or other materials
104edb46e9SPaul Traina  * provided with the distribution, and (3) all advertising materials mentioning
114edb46e9SPaul Traina  * features or use of this software display the following acknowledgement:
124edb46e9SPaul Traina  * ``This product includes software developed by the University of California,
134edb46e9SPaul Traina  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
144edb46e9SPaul Traina  * the University nor the names of its contributors may be used to endorse
154edb46e9SPaul Traina  * or promote products derived from this software without specific prior
164edb46e9SPaul Traina  * written permission.
174edb46e9SPaul Traina  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
184edb46e9SPaul Traina  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
194edb46e9SPaul Traina  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
204edb46e9SPaul Traina  */
214edb46e9SPaul Traina 
224edb46e9SPaul Traina #ifndef lint
234de76e31SBill Fenner static const char rcsid[] =
244de76e31SBill Fenner     "@(#) $Header: print-tcp.c,v 1.52 96/12/03 10:59:55 vern Exp $ (LBL)";
254edb46e9SPaul Traina #endif
264edb46e9SPaul Traina 
274edb46e9SPaul Traina #include <sys/param.h>
284edb46e9SPaul Traina #include <sys/time.h>
294edb46e9SPaul Traina 
304edb46e9SPaul Traina #include <netinet/in.h>
314edb46e9SPaul Traina #include <netinet/in_systm.h>
324edb46e9SPaul Traina #include <netinet/ip.h>
334edb46e9SPaul Traina #include <netinet/ip_var.h>
344edb46e9SPaul Traina #include <netinet/tcp.h>
354edb46e9SPaul Traina #include <netinet/tcpip.h>
364edb46e9SPaul Traina 
374edb46e9SPaul Traina #include <stdio.h>
384edb46e9SPaul Traina #include <stdlib.h>
394edb46e9SPaul Traina #include <string.h>
404edb46e9SPaul Traina #include <unistd.h>
414edb46e9SPaul Traina 
424edb46e9SPaul Traina #include "interface.h"
434edb46e9SPaul Traina #include "addrtoname.h"
444edb46e9SPaul Traina #include "extract.h"
454edb46e9SPaul Traina 
464edb46e9SPaul Traina /* Compatibility */
474edb46e9SPaul Traina #ifndef TCPOPT_WSCALE
484edb46e9SPaul Traina #define	TCPOPT_WSCALE		3	/* window scale factor (rfc1072) */
494edb46e9SPaul Traina #endif
504edb46e9SPaul Traina #ifndef TCPOPT_SACKOK
514edb46e9SPaul Traina #define	TCPOPT_SACKOK		4	/* selective ack ok (rfc1072) */
524edb46e9SPaul Traina #endif
534edb46e9SPaul Traina #ifndef TCPOPT_SACK
544edb46e9SPaul Traina #define	TCPOPT_SACK		5	/* selective ack (rfc1072) */
554edb46e9SPaul Traina #endif
564edb46e9SPaul Traina #ifndef TCPOPT_ECHO
574edb46e9SPaul Traina #define	TCPOPT_ECHO		6	/* echo (rfc1072) */
584edb46e9SPaul Traina #endif
594edb46e9SPaul Traina #ifndef TCPOPT_ECHOREPLY
604edb46e9SPaul Traina #define	TCPOPT_ECHOREPLY	7	/* echo (rfc1072) */
614edb46e9SPaul Traina #endif
624edb46e9SPaul Traina #ifndef TCPOPT_TIMESTAMP
634edb46e9SPaul Traina #define TCPOPT_TIMESTAMP	8	/* timestamps (rfc1323) */
644edb46e9SPaul Traina #endif
654edb46e9SPaul Traina #ifndef TCPOPT_CC
664edb46e9SPaul Traina #define TCPOPT_CC		11	/* T/TCP CC options (rfc1644) */
674edb46e9SPaul Traina #endif
684edb46e9SPaul Traina #ifndef TCPOPT_CCNEW
694edb46e9SPaul Traina #define TCPOPT_CCNEW		12	/* T/TCP CC options (rfc1644) */
704edb46e9SPaul Traina #endif
714edb46e9SPaul Traina #ifndef TCPOPT_CCECHO
724edb46e9SPaul Traina #define TCPOPT_CCECHO		13	/* T/TCP CC options (rfc1644) */
734edb46e9SPaul Traina #endif
744edb46e9SPaul Traina 
754edb46e9SPaul Traina struct tha {
764edb46e9SPaul Traina 	struct in_addr src;
774edb46e9SPaul Traina 	struct in_addr dst;
784edb46e9SPaul Traina 	u_int port;
794edb46e9SPaul Traina };
804edb46e9SPaul Traina 
814edb46e9SPaul Traina struct tcp_seq_hash {
824edb46e9SPaul Traina 	struct tcp_seq_hash *nxt;
834edb46e9SPaul Traina 	struct tha addr;
844edb46e9SPaul Traina 	tcp_seq seq;
854edb46e9SPaul Traina 	tcp_seq ack;
864edb46e9SPaul Traina };
874edb46e9SPaul Traina 
884edb46e9SPaul Traina #define TSEQ_HASHSIZE 919
894edb46e9SPaul Traina 
904edb46e9SPaul Traina /* These tcp optinos do not have the size octet */
914edb46e9SPaul Traina #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
924edb46e9SPaul Traina 
934edb46e9SPaul Traina static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
944edb46e9SPaul Traina 
954edb46e9SPaul Traina 
964edb46e9SPaul Traina void
974edb46e9SPaul Traina tcp_print(register const u_char *bp, register u_int length,
984edb46e9SPaul Traina 	  register const u_char *bp2)
994edb46e9SPaul Traina {
1004edb46e9SPaul Traina 	register const struct tcphdr *tp;
1014edb46e9SPaul Traina 	register const struct ip *ip;
1024edb46e9SPaul Traina 	register u_char flags;
1034de76e31SBill Fenner 	register int hlen;
1044edb46e9SPaul Traina 	register char ch;
1054edb46e9SPaul Traina 	u_short sport, dport, win, urp;
1064edb46e9SPaul Traina 	u_int32_t seq, ack;
1074edb46e9SPaul Traina 
1084edb46e9SPaul Traina 	tp = (struct tcphdr *)bp;
1094edb46e9SPaul Traina 	ip = (struct ip *)bp2;
1104edb46e9SPaul Traina 	ch = '\0';
1114edb46e9SPaul Traina 	TCHECK(*tp);
1124edb46e9SPaul Traina 	if (length < sizeof(*tp)) {
1134edb46e9SPaul Traina 		(void)printf("truncated-tcp %d", length);
1144edb46e9SPaul Traina 		return;
1154edb46e9SPaul Traina 	}
1164edb46e9SPaul Traina 
1174edb46e9SPaul Traina 	sport = ntohs(tp->th_sport);
1184edb46e9SPaul Traina 	dport = ntohs(tp->th_dport);
1194edb46e9SPaul Traina 	seq = ntohl(tp->th_seq);
1204edb46e9SPaul Traina 	ack = ntohl(tp->th_ack);
1214edb46e9SPaul Traina 	win = ntohs(tp->th_win);
1224edb46e9SPaul Traina 	urp = ntohs(tp->th_urp);
1234edb46e9SPaul Traina 
1244edb46e9SPaul Traina 	(void)printf("%s.%s > %s.%s: ",
1254edb46e9SPaul Traina 		ipaddr_string(&ip->ip_src), tcpport_string(sport),
1264edb46e9SPaul Traina 		ipaddr_string(&ip->ip_dst), tcpport_string(dport));
1274edb46e9SPaul Traina 
1284edb46e9SPaul Traina 	if (qflag) {
1294edb46e9SPaul Traina 		(void)printf("tcp %d", length - tp->th_off * 4);
1304edb46e9SPaul Traina 		return;
1314edb46e9SPaul Traina 	}
1324edb46e9SPaul Traina 	if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
1334edb46e9SPaul Traina 		if (flags & TH_SYN)
1344edb46e9SPaul Traina 			putchar('S');
1354edb46e9SPaul Traina 		if (flags & TH_FIN)
1364edb46e9SPaul Traina 			putchar('F');
1374edb46e9SPaul Traina 		if (flags & TH_RST)
1384edb46e9SPaul Traina 			putchar('R');
1394edb46e9SPaul Traina 		if (flags & TH_PUSH)
1404edb46e9SPaul Traina 			putchar('P');
1414edb46e9SPaul Traina 	} else
1424edb46e9SPaul Traina 		putchar('.');
1434edb46e9SPaul Traina 
1444edb46e9SPaul Traina 	if (!Sflag && (flags & TH_ACK)) {
1454edb46e9SPaul Traina 		register struct tcp_seq_hash *th;
1464edb46e9SPaul Traina 		register int rev;
1474edb46e9SPaul Traina 		struct tha tha;
1484edb46e9SPaul Traina 		/*
1494edb46e9SPaul Traina 		 * Find (or record) the initial sequence numbers for
1504edb46e9SPaul Traina 		 * this conversation.  (we pick an arbitrary
1514edb46e9SPaul Traina 		 * collating order so there's only one entry for
1524edb46e9SPaul Traina 		 * both directions).
1534edb46e9SPaul Traina 		 */
1544edb46e9SPaul Traina 		if (sport < dport ||
1554edb46e9SPaul Traina 		    (sport == dport &&
1564edb46e9SPaul Traina 		     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
1574edb46e9SPaul Traina 			tha.src = ip->ip_src, tha.dst = ip->ip_dst;
1584edb46e9SPaul Traina 			tha.port = sport << 16 | dport;
1594edb46e9SPaul Traina 			rev = 0;
1604edb46e9SPaul Traina 		} else {
1614edb46e9SPaul Traina 			tha.src = ip->ip_dst, tha.dst = ip->ip_src;
1624edb46e9SPaul Traina 			tha.port = dport << 16 | sport;
1634edb46e9SPaul Traina 			rev = 1;
1644edb46e9SPaul Traina 		}
1654edb46e9SPaul Traina 
1664edb46e9SPaul Traina 		for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
1674edb46e9SPaul Traina 		     th->nxt; th = th->nxt)
1684edb46e9SPaul Traina 			if (!memcmp((char *)&tha, (char *)&th->addr,
1694edb46e9SPaul Traina 				  sizeof(th->addr)))
1704edb46e9SPaul Traina 				break;
1714edb46e9SPaul Traina 
1724edb46e9SPaul Traina 		if (!th->nxt || flags & TH_SYN) {
1734edb46e9SPaul Traina 			/* didn't find it or new conversation */
1744edb46e9SPaul Traina 			if (th->nxt == NULL) {
1754edb46e9SPaul Traina 				th->nxt = (struct tcp_seq_hash *)
1764edb46e9SPaul Traina 					calloc(1, sizeof(*th));
1774edb46e9SPaul Traina 				if (th->nxt == NULL)
1784edb46e9SPaul Traina 					error("tcp_print: calloc");
1794edb46e9SPaul Traina 			}
1804edb46e9SPaul Traina 			th->addr = tha;
1814edb46e9SPaul Traina 			if (rev)
1824edb46e9SPaul Traina 				th->ack = seq, th->seq = ack - 1;
1834edb46e9SPaul Traina 			else
1844edb46e9SPaul Traina 				th->seq = seq, th->ack = ack - 1;
1854edb46e9SPaul Traina 		} else {
1864edb46e9SPaul Traina 			if (rev)
1874edb46e9SPaul Traina 				seq -= th->ack, ack -= th->seq;
1884edb46e9SPaul Traina 			else
1894edb46e9SPaul Traina 				seq -= th->seq, ack -= th->ack;
1904edb46e9SPaul Traina 		}
1914edb46e9SPaul Traina 	}
1924edb46e9SPaul Traina 	hlen = tp->th_off * 4;
1934de76e31SBill Fenner 	if (hlen > length) {
1944de76e31SBill Fenner 		(void)printf(" [bad hdr length]");
1954de76e31SBill Fenner 		return;
1964de76e31SBill Fenner 	}
1974edb46e9SPaul Traina 	length -= hlen;
1984edb46e9SPaul Traina 	if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
1994edb46e9SPaul Traina 		(void)printf(" %u:%u(%d)", seq, seq + length, length);
2004edb46e9SPaul Traina 	if (flags & TH_ACK)
2014edb46e9SPaul Traina 		(void)printf(" ack %u", ack);
2024edb46e9SPaul Traina 
2034edb46e9SPaul Traina 	(void)printf(" win %d", win);
2044edb46e9SPaul Traina 
2054edb46e9SPaul Traina 	if (flags & TH_URG)
2064edb46e9SPaul Traina 		(void)printf(" urg %d", urp);
2074edb46e9SPaul Traina 	/*
2084edb46e9SPaul Traina 	 * Handle any options.
2094edb46e9SPaul Traina 	 */
2104edb46e9SPaul Traina 	if ((hlen -= sizeof(*tp)) > 0) {
2114edb46e9SPaul Traina 		register const u_char *cp;
2124edb46e9SPaul Traina 		register int i, opt, len, datalen;
2134edb46e9SPaul Traina 
2144edb46e9SPaul Traina 		cp = (const u_char *)tp + sizeof(*tp);
2154edb46e9SPaul Traina 		putchar(' ');
2164edb46e9SPaul Traina 		ch = '<';
2174edb46e9SPaul Traina 		while (hlen > 0) {
2184edb46e9SPaul Traina 			putchar(ch);
2194de76e31SBill Fenner 			TCHECK(*cp);
2204edb46e9SPaul Traina 			opt = *cp++;
2214edb46e9SPaul Traina 			if (ZEROLENOPT(opt))
2224edb46e9SPaul Traina 				len = 1;
2234edb46e9SPaul Traina 			else {
2244de76e31SBill Fenner 				TCHECK(*cp);
2254de76e31SBill Fenner 				len = *cp++;	/* total including type, len */
2264de76e31SBill Fenner 				if (len < 2 || len > hlen)
2274de76e31SBill Fenner 					goto bad;
2284de76e31SBill Fenner 				--hlen;		/* account for length byte */
2294edb46e9SPaul Traina 			}
2304de76e31SBill Fenner 			--hlen;			/* account for type byte */
2314edb46e9SPaul Traina 			datalen = 0;
2324de76e31SBill Fenner 
2334de76e31SBill Fenner /* Bail if "l" bytes of data are not left or were not captured  */
2344de76e31SBill Fenner #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
2354de76e31SBill Fenner 
2364edb46e9SPaul Traina 			switch (opt) {
2374edb46e9SPaul Traina 
2384edb46e9SPaul Traina 			case TCPOPT_MAXSEG:
2394edb46e9SPaul Traina 				(void)printf("mss");
2404edb46e9SPaul Traina 				datalen = 2;
2414de76e31SBill Fenner 				LENCHECK(datalen);
2424edb46e9SPaul Traina 				(void)printf(" %u", EXTRACT_16BITS(cp));
2434edb46e9SPaul Traina 
2444edb46e9SPaul Traina 				break;
2454edb46e9SPaul Traina 
2464edb46e9SPaul Traina 			case TCPOPT_EOL:
2474edb46e9SPaul Traina 				(void)printf("eol");
2484edb46e9SPaul Traina 				break;
2494edb46e9SPaul Traina 
2504edb46e9SPaul Traina 			case TCPOPT_NOP:
2514edb46e9SPaul Traina 				(void)printf("nop");
2524edb46e9SPaul Traina 				break;
2534edb46e9SPaul Traina 
2544edb46e9SPaul Traina 			case TCPOPT_WSCALE:
2554edb46e9SPaul Traina 				(void)printf("wscale");
2564edb46e9SPaul Traina 				datalen = 1;
2574de76e31SBill Fenner 				LENCHECK(datalen);
2584edb46e9SPaul Traina 				(void)printf(" %u", *cp);
2594edb46e9SPaul Traina 				break;
2604edb46e9SPaul Traina 
2614edb46e9SPaul Traina 			case TCPOPT_SACKOK:
2624edb46e9SPaul Traina 				(void)printf("sackOK");
2634edb46e9SPaul Traina 				break;
2644edb46e9SPaul Traina 
2654edb46e9SPaul Traina 			case TCPOPT_SACK:
2664edb46e9SPaul Traina 				(void)printf("sack");
2674edb46e9SPaul Traina 				datalen = len - 2;
2684de76e31SBill Fenner 				for (i = 0; i < datalen; i += 4) {
2694de76e31SBill Fenner 					LENCHECK(i + 4);
2704edb46e9SPaul Traina 					/* block-size@relative-origin */
2714edb46e9SPaul Traina 					(void)printf(" %u@%u",
2724de76e31SBill Fenner 					    EXTRACT_16BITS(cp + i + 2),
2734de76e31SBill Fenner 					    EXTRACT_16BITS(cp + i));
2744edb46e9SPaul Traina 				}
2754edb46e9SPaul Traina 				if (datalen % 4)
2764edb46e9SPaul Traina 					(void)printf("[len %d]", len);
2774edb46e9SPaul Traina 				break;
2784edb46e9SPaul Traina 
2794edb46e9SPaul Traina 			case TCPOPT_ECHO:
2804edb46e9SPaul Traina 				(void)printf("echo");
2814edb46e9SPaul Traina 				datalen = 4;
2824de76e31SBill Fenner 				LENCHECK(datalen);
2834edb46e9SPaul Traina 				(void)printf(" %u", EXTRACT_32BITS(cp));
2844edb46e9SPaul Traina 				break;
2854edb46e9SPaul Traina 
2864edb46e9SPaul Traina 			case TCPOPT_ECHOREPLY:
2874edb46e9SPaul Traina 				(void)printf("echoreply");
2884edb46e9SPaul Traina 				datalen = 4;
2894de76e31SBill Fenner 				LENCHECK(datalen);
2904edb46e9SPaul Traina 				(void)printf(" %u", EXTRACT_32BITS(cp));
2914edb46e9SPaul Traina 				break;
2924edb46e9SPaul Traina 
2934edb46e9SPaul Traina 			case TCPOPT_TIMESTAMP:
2944edb46e9SPaul Traina 				(void)printf("timestamp");
2954de76e31SBill Fenner 				datalen = 8;
2964de76e31SBill Fenner 				LENCHECK(4);
2974edb46e9SPaul Traina 				(void)printf(" %u", EXTRACT_32BITS(cp));
2984de76e31SBill Fenner 				LENCHECK(datalen);
2994edb46e9SPaul Traina 				(void)printf(" %u", EXTRACT_32BITS(cp + 4));
3004edb46e9SPaul Traina 				break;
3014edb46e9SPaul Traina 
3024edb46e9SPaul Traina 			case TCPOPT_CC:
3034edb46e9SPaul Traina 				(void)printf("cc");
3044edb46e9SPaul Traina 				datalen = 4;
3054de76e31SBill Fenner 				LENCHECK(datalen);
3064edb46e9SPaul Traina 				(void)printf(" %u", EXTRACT_32BITS(cp));
3074edb46e9SPaul Traina 				break;
3084edb46e9SPaul Traina 
3094edb46e9SPaul Traina 			case TCPOPT_CCNEW:
3104edb46e9SPaul Traina 				(void)printf("ccnew");
3114edb46e9SPaul Traina 				datalen = 4;
3124de76e31SBill Fenner 				LENCHECK(datalen);
3134edb46e9SPaul Traina 				(void)printf(" %u", EXTRACT_32BITS(cp));
3144edb46e9SPaul Traina 				break;
3154edb46e9SPaul Traina 
3164edb46e9SPaul Traina 			case TCPOPT_CCECHO:
3174edb46e9SPaul Traina 				(void)printf("ccecho");
3184edb46e9SPaul Traina 				datalen = 4;
3194de76e31SBill Fenner 				LENCHECK(datalen);
3204edb46e9SPaul Traina 				(void)printf(" %u", EXTRACT_32BITS(cp));
3214edb46e9SPaul Traina 				break;
3224edb46e9SPaul Traina 
3234edb46e9SPaul Traina 			default:
3244edb46e9SPaul Traina 				(void)printf("opt-%d:", opt);
3254edb46e9SPaul Traina 				datalen = len - 2;
3264edb46e9SPaul Traina 				for (i = 0; i < datalen; ++i) {
3274de76e31SBill Fenner 					LENCHECK(i);
3284edb46e9SPaul Traina 					(void)printf("%02x", cp[i]);
3294edb46e9SPaul Traina 				}
3304edb46e9SPaul Traina 				break;
3314edb46e9SPaul Traina 			}
3324edb46e9SPaul Traina 
3334edb46e9SPaul Traina 			/* Account for data printed */
3344edb46e9SPaul Traina 			cp += datalen;
3354edb46e9SPaul Traina 			hlen -= datalen;
3364edb46e9SPaul Traina 
3374edb46e9SPaul Traina 			/* Check specification against observed length */
3384edb46e9SPaul Traina 			++datalen;			/* option octet */
3394edb46e9SPaul Traina 			if (!ZEROLENOPT(opt))
3404edb46e9SPaul Traina 				++datalen;		/* size octet */
3414edb46e9SPaul Traina 			if (datalen != len)
3424edb46e9SPaul Traina 				(void)printf("[len %d]", len);
3434edb46e9SPaul Traina 			ch = ',';
3444de76e31SBill Fenner 			if (opt == TCPOPT_EOL)
3454de76e31SBill Fenner 				break;
3464edb46e9SPaul Traina 		}
3474edb46e9SPaul Traina 		putchar('>');
3484edb46e9SPaul Traina 	}
3494edb46e9SPaul Traina 	return;
3504de76e31SBill Fenner bad:
3514de76e31SBill Fenner 	fputs("[bad opt]", stdout);
3524de76e31SBill Fenner 	if (ch != '\0')
3534de76e31SBill Fenner 		putchar('>');
3544de76e31SBill Fenner 	return;
3554edb46e9SPaul Traina trunc:
3564edb46e9SPaul Traina 	fputs("[|tcp]", stdout);
3574edb46e9SPaul Traina 	if (ch != '\0')
3584edb46e9SPaul Traina 		putchar('>');
3594edb46e9SPaul Traina }
3604edb46e9SPaul Traina 
361