print-tcp.c revision 26180
117680Spst/*
217680Spst * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst */
2117680Spst
2217680Spst#ifndef lint
2326180Sfennerstatic const char rcsid[] =
2426180Sfenner    "@(#) $Header: print-tcp.c,v 1.52 96/12/03 10:59:55 vern Exp $ (LBL)";
2517680Spst#endif
2617680Spst
2717680Spst#include <sys/param.h>
2817680Spst#include <sys/time.h>
2917680Spst
3017680Spst#include <netinet/in.h>
3117680Spst#include <netinet/in_systm.h>
3217680Spst#include <netinet/ip.h>
3317680Spst#include <netinet/ip_var.h>
3417680Spst#include <netinet/tcp.h>
3517680Spst#include <netinet/tcpip.h>
3617680Spst
3717680Spst#include <stdio.h>
3817680Spst#include <stdlib.h>
3917680Spst#include <string.h>
4017680Spst#include <unistd.h>
4117680Spst
4217680Spst#include "interface.h"
4317680Spst#include "addrtoname.h"
4417680Spst#include "extract.h"
4517680Spst
4617680Spst/* Compatibility */
4717680Spst#ifndef TCPOPT_WSCALE
4817680Spst#define	TCPOPT_WSCALE		3	/* window scale factor (rfc1072) */
4917680Spst#endif
5017680Spst#ifndef TCPOPT_SACKOK
5117680Spst#define	TCPOPT_SACKOK		4	/* selective ack ok (rfc1072) */
5217680Spst#endif
5317680Spst#ifndef TCPOPT_SACK
5417680Spst#define	TCPOPT_SACK		5	/* selective ack (rfc1072) */
5517680Spst#endif
5617680Spst#ifndef TCPOPT_ECHO
5717680Spst#define	TCPOPT_ECHO		6	/* echo (rfc1072) */
5817680Spst#endif
5917680Spst#ifndef TCPOPT_ECHOREPLY
6017680Spst#define	TCPOPT_ECHOREPLY	7	/* echo (rfc1072) */
6117680Spst#endif
6217680Spst#ifndef TCPOPT_TIMESTAMP
6317680Spst#define TCPOPT_TIMESTAMP	8	/* timestamps (rfc1323) */
6417680Spst#endif
6517680Spst#ifndef TCPOPT_CC
6617680Spst#define TCPOPT_CC		11	/* T/TCP CC options (rfc1644) */
6717680Spst#endif
6817680Spst#ifndef TCPOPT_CCNEW
6917680Spst#define TCPOPT_CCNEW		12	/* T/TCP CC options (rfc1644) */
7017680Spst#endif
7117680Spst#ifndef TCPOPT_CCECHO
7217680Spst#define TCPOPT_CCECHO		13	/* T/TCP CC options (rfc1644) */
7317680Spst#endif
7417680Spst
7517680Spststruct tha {
7617680Spst	struct in_addr src;
7717680Spst	struct in_addr dst;
7817680Spst	u_int port;
7917680Spst};
8017680Spst
8117680Spststruct tcp_seq_hash {
8217680Spst	struct tcp_seq_hash *nxt;
8317680Spst	struct tha addr;
8417680Spst	tcp_seq seq;
8517680Spst	tcp_seq ack;
8617680Spst};
8717680Spst
8817680Spst#define TSEQ_HASHSIZE 919
8917680Spst
9017680Spst/* These tcp optinos do not have the size octet */
9117680Spst#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
9217680Spst
9317680Spststatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
9417680Spst
9517680Spst
9617680Spstvoid
9717680Spsttcp_print(register const u_char *bp, register u_int length,
9817680Spst	  register const u_char *bp2)
9917680Spst{
10017680Spst	register const struct tcphdr *tp;
10117680Spst	register const struct ip *ip;
10217680Spst	register u_char flags;
10326180Sfenner	register int hlen;
10417680Spst	register char ch;
10517680Spst	u_short sport, dport, win, urp;
10617680Spst	u_int32_t seq, ack;
10717680Spst
10817680Spst	tp = (struct tcphdr *)bp;
10917680Spst	ip = (struct ip *)bp2;
11017680Spst	ch = '\0';
11117680Spst	TCHECK(*tp);
11217680Spst	if (length < sizeof(*tp)) {
11317680Spst		(void)printf("truncated-tcp %d", length);
11417680Spst		return;
11517680Spst	}
11617680Spst
11717680Spst	sport = ntohs(tp->th_sport);
11817680Spst	dport = ntohs(tp->th_dport);
11917680Spst	seq = ntohl(tp->th_seq);
12017680Spst	ack = ntohl(tp->th_ack);
12117680Spst	win = ntohs(tp->th_win);
12217680Spst	urp = ntohs(tp->th_urp);
12317680Spst
12417680Spst	(void)printf("%s.%s > %s.%s: ",
12517680Spst		ipaddr_string(&ip->ip_src), tcpport_string(sport),
12617680Spst		ipaddr_string(&ip->ip_dst), tcpport_string(dport));
12717680Spst
12817680Spst	if (qflag) {
12917680Spst		(void)printf("tcp %d", length - tp->th_off * 4);
13017680Spst		return;
13117680Spst	}
13217680Spst	if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
13317680Spst		if (flags & TH_SYN)
13417680Spst			putchar('S');
13517680Spst		if (flags & TH_FIN)
13617680Spst			putchar('F');
13717680Spst		if (flags & TH_RST)
13817680Spst			putchar('R');
13917680Spst		if (flags & TH_PUSH)
14017680Spst			putchar('P');
14117680Spst	} else
14217680Spst		putchar('.');
14317680Spst
14417680Spst	if (!Sflag && (flags & TH_ACK)) {
14517680Spst		register struct tcp_seq_hash *th;
14617680Spst		register int rev;
14717680Spst		struct tha tha;
14817680Spst		/*
14917680Spst		 * Find (or record) the initial sequence numbers for
15017680Spst		 * this conversation.  (we pick an arbitrary
15117680Spst		 * collating order so there's only one entry for
15217680Spst		 * both directions).
15317680Spst		 */
15417680Spst		if (sport < dport ||
15517680Spst		    (sport == dport &&
15617680Spst		     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
15717680Spst			tha.src = ip->ip_src, tha.dst = ip->ip_dst;
15817680Spst			tha.port = sport << 16 | dport;
15917680Spst			rev = 0;
16017680Spst		} else {
16117680Spst			tha.src = ip->ip_dst, tha.dst = ip->ip_src;
16217680Spst			tha.port = dport << 16 | sport;
16317680Spst			rev = 1;
16417680Spst		}
16517680Spst
16617680Spst		for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
16717680Spst		     th->nxt; th = th->nxt)
16817680Spst			if (!memcmp((char *)&tha, (char *)&th->addr,
16917680Spst				  sizeof(th->addr)))
17017680Spst				break;
17117680Spst
17217680Spst		if (!th->nxt || flags & TH_SYN) {
17317680Spst			/* didn't find it or new conversation */
17417680Spst			if (th->nxt == NULL) {
17517680Spst				th->nxt = (struct tcp_seq_hash *)
17617680Spst					calloc(1, sizeof(*th));
17717680Spst				if (th->nxt == NULL)
17817680Spst					error("tcp_print: calloc");
17917680Spst			}
18017680Spst			th->addr = tha;
18117680Spst			if (rev)
18217680Spst				th->ack = seq, th->seq = ack - 1;
18317680Spst			else
18417680Spst				th->seq = seq, th->ack = ack - 1;
18517680Spst		} else {
18617680Spst			if (rev)
18717680Spst				seq -= th->ack, ack -= th->seq;
18817680Spst			else
18917680Spst				seq -= th->seq, ack -= th->ack;
19017680Spst		}
19117680Spst	}
19217680Spst	hlen = tp->th_off * 4;
19326180Sfenner	if (hlen > length) {
19426180Sfenner		(void)printf(" [bad hdr length]");
19526180Sfenner		return;
19626180Sfenner	}
19717680Spst	length -= hlen;
19817680Spst	if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
19917680Spst		(void)printf(" %u:%u(%d)", seq, seq + length, length);
20017680Spst	if (flags & TH_ACK)
20117680Spst		(void)printf(" ack %u", ack);
20217680Spst
20317680Spst	(void)printf(" win %d", win);
20417680Spst
20517680Spst	if (flags & TH_URG)
20617680Spst		(void)printf(" urg %d", urp);
20717680Spst	/*
20817680Spst	 * Handle any options.
20917680Spst	 */
21017680Spst	if ((hlen -= sizeof(*tp)) > 0) {
21117680Spst		register const u_char *cp;
21217680Spst		register int i, opt, len, datalen;
21317680Spst
21417680Spst		cp = (const u_char *)tp + sizeof(*tp);
21517680Spst		putchar(' ');
21617680Spst		ch = '<';
21717680Spst		while (hlen > 0) {
21817680Spst			putchar(ch);
21926180Sfenner			TCHECK(*cp);
22017680Spst			opt = *cp++;
22117680Spst			if (ZEROLENOPT(opt))
22217680Spst				len = 1;
22317680Spst			else {
22426180Sfenner				TCHECK(*cp);
22526180Sfenner				len = *cp++;	/* total including type, len */
22626180Sfenner				if (len < 2 || len > hlen)
22726180Sfenner					goto bad;
22826180Sfenner				--hlen;		/* account for length byte */
22917680Spst			}
23026180Sfenner			--hlen;			/* account for type byte */
23117680Spst			datalen = 0;
23226180Sfenner
23326180Sfenner/* Bail if "l" bytes of data are not left or were not captured  */
23426180Sfenner#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
23526180Sfenner
23617680Spst			switch (opt) {
23717680Spst
23817680Spst			case TCPOPT_MAXSEG:
23917680Spst				(void)printf("mss");
24017680Spst				datalen = 2;
24126180Sfenner				LENCHECK(datalen);
24217680Spst				(void)printf(" %u", EXTRACT_16BITS(cp));
24317680Spst
24417680Spst				break;
24517680Spst
24617680Spst			case TCPOPT_EOL:
24717680Spst				(void)printf("eol");
24817680Spst				break;
24917680Spst
25017680Spst			case TCPOPT_NOP:
25117680Spst				(void)printf("nop");
25217680Spst				break;
25317680Spst
25417680Spst			case TCPOPT_WSCALE:
25517680Spst				(void)printf("wscale");
25617680Spst				datalen = 1;
25726180Sfenner				LENCHECK(datalen);
25817680Spst				(void)printf(" %u", *cp);
25917680Spst				break;
26017680Spst
26117680Spst			case TCPOPT_SACKOK:
26217680Spst				(void)printf("sackOK");
26317680Spst				break;
26417680Spst
26517680Spst			case TCPOPT_SACK:
26617680Spst				(void)printf("sack");
26717680Spst				datalen = len - 2;
26826180Sfenner				for (i = 0; i < datalen; i += 4) {
26926180Sfenner					LENCHECK(i + 4);
27017680Spst					/* block-size@relative-origin */
27117680Spst					(void)printf(" %u@%u",
27226180Sfenner					    EXTRACT_16BITS(cp + i + 2),
27326180Sfenner					    EXTRACT_16BITS(cp + i));
27417680Spst				}
27517680Spst				if (datalen % 4)
27617680Spst					(void)printf("[len %d]", len);
27717680Spst				break;
27817680Spst
27917680Spst			case TCPOPT_ECHO:
28017680Spst				(void)printf("echo");
28117680Spst				datalen = 4;
28226180Sfenner				LENCHECK(datalen);
28317680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
28417680Spst				break;
28517680Spst
28617680Spst			case TCPOPT_ECHOREPLY:
28717680Spst				(void)printf("echoreply");
28817680Spst				datalen = 4;
28926180Sfenner				LENCHECK(datalen);
29017680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
29117680Spst				break;
29217680Spst
29317680Spst			case TCPOPT_TIMESTAMP:
29417680Spst				(void)printf("timestamp");
29526180Sfenner				datalen = 8;
29626180Sfenner				LENCHECK(4);
29717680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
29826180Sfenner				LENCHECK(datalen);
29917680Spst				(void)printf(" %u", EXTRACT_32BITS(cp + 4));
30017680Spst				break;
30117680Spst
30217680Spst			case TCPOPT_CC:
30317680Spst				(void)printf("cc");
30417680Spst				datalen = 4;
30526180Sfenner				LENCHECK(datalen);
30617680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
30717680Spst				break;
30817680Spst
30917680Spst			case TCPOPT_CCNEW:
31017680Spst				(void)printf("ccnew");
31117680Spst				datalen = 4;
31226180Sfenner				LENCHECK(datalen);
31317680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
31417680Spst				break;
31517680Spst
31617680Spst			case TCPOPT_CCECHO:
31717680Spst				(void)printf("ccecho");
31817680Spst				datalen = 4;
31926180Sfenner				LENCHECK(datalen);
32017680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
32117680Spst				break;
32217680Spst
32317680Spst			default:
32417680Spst				(void)printf("opt-%d:", opt);
32517680Spst				datalen = len - 2;
32617680Spst				for (i = 0; i < datalen; ++i) {
32726180Sfenner					LENCHECK(i);
32817680Spst					(void)printf("%02x", cp[i]);
32917680Spst				}
33017680Spst				break;
33117680Spst			}
33217680Spst
33317680Spst			/* Account for data printed */
33417680Spst			cp += datalen;
33517680Spst			hlen -= datalen;
33617680Spst
33717680Spst			/* Check specification against observed length */
33817680Spst			++datalen;			/* option octet */
33917680Spst			if (!ZEROLENOPT(opt))
34017680Spst				++datalen;		/* size octet */
34117680Spst			if (datalen != len)
34217680Spst				(void)printf("[len %d]", len);
34317680Spst			ch = ',';
34426180Sfenner			if (opt == TCPOPT_EOL)
34526180Sfenner				break;
34617680Spst		}
34717680Spst		putchar('>');
34817680Spst	}
34917680Spst	return;
35026180Sfennerbad:
35126180Sfenner	fputs("[bad opt]", stdout);
35226180Sfenner	if (ch != '\0')
35326180Sfenner		putchar('>');
35426180Sfenner	return;
35517680Spsttrunc:
35617680Spst	fputs("[|tcp]", stdout);
35717680Spst	if (ch != '\0')
35817680Spst		putchar('>');
35917680Spst}
36017680Spst
361