print-tcp.c revision 39297
117680Spst/*
239297Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
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[] =
2439297Sfenner    "@(#) $Header: print-tcp.c,v 1.55 97/06/15 13:20:28 leres 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
3739297Sfenner#ifdef HAVE_MEMORY_H
3839297Sfenner#include <memory.h>
3939297Sfenner#endif
4017680Spst#include <stdio.h>
4117680Spst#include <stdlib.h>
4217680Spst#include <string.h>
4317680Spst#include <unistd.h>
4417680Spst
4517680Spst#include "interface.h"
4617680Spst#include "addrtoname.h"
4717680Spst#include "extract.h"
4817680Spst
4917680Spst/* Compatibility */
5017680Spst#ifndef TCPOPT_WSCALE
5117680Spst#define	TCPOPT_WSCALE		3	/* window scale factor (rfc1072) */
5217680Spst#endif
5317680Spst#ifndef TCPOPT_SACKOK
5417680Spst#define	TCPOPT_SACKOK		4	/* selective ack ok (rfc1072) */
5517680Spst#endif
5617680Spst#ifndef TCPOPT_SACK
5717680Spst#define	TCPOPT_SACK		5	/* selective ack (rfc1072) */
5817680Spst#endif
5917680Spst#ifndef TCPOPT_ECHO
6017680Spst#define	TCPOPT_ECHO		6	/* echo (rfc1072) */
6117680Spst#endif
6217680Spst#ifndef TCPOPT_ECHOREPLY
6317680Spst#define	TCPOPT_ECHOREPLY	7	/* echo (rfc1072) */
6417680Spst#endif
6517680Spst#ifndef TCPOPT_TIMESTAMP
6617680Spst#define TCPOPT_TIMESTAMP	8	/* timestamps (rfc1323) */
6717680Spst#endif
6817680Spst#ifndef TCPOPT_CC
6917680Spst#define TCPOPT_CC		11	/* T/TCP CC options (rfc1644) */
7017680Spst#endif
7117680Spst#ifndef TCPOPT_CCNEW
7217680Spst#define TCPOPT_CCNEW		12	/* T/TCP CC options (rfc1644) */
7317680Spst#endif
7417680Spst#ifndef TCPOPT_CCECHO
7517680Spst#define TCPOPT_CCECHO		13	/* T/TCP CC options (rfc1644) */
7617680Spst#endif
7717680Spst
7817680Spststruct tha {
7917680Spst	struct in_addr src;
8017680Spst	struct in_addr dst;
8117680Spst	u_int port;
8217680Spst};
8317680Spst
8417680Spststruct tcp_seq_hash {
8517680Spst	struct tcp_seq_hash *nxt;
8617680Spst	struct tha addr;
8717680Spst	tcp_seq seq;
8817680Spst	tcp_seq ack;
8917680Spst};
9017680Spst
9117680Spst#define TSEQ_HASHSIZE 919
9217680Spst
9317680Spst/* These tcp optinos do not have the size octet */
9417680Spst#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
9517680Spst
9617680Spststatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
9717680Spst
9817680Spst
9917680Spstvoid
10017680Spsttcp_print(register const u_char *bp, register u_int length,
10117680Spst	  register const u_char *bp2)
10217680Spst{
10317680Spst	register const struct tcphdr *tp;
10417680Spst	register const struct ip *ip;
10517680Spst	register u_char flags;
10626180Sfenner	register int hlen;
10717680Spst	register char ch;
10817680Spst	u_short sport, dport, win, urp;
10917680Spst	u_int32_t seq, ack;
11017680Spst
11117680Spst	tp = (struct tcphdr *)bp;
11217680Spst	ip = (struct ip *)bp2;
11317680Spst	ch = '\0';
11417680Spst	TCHECK(*tp);
11517680Spst	if (length < sizeof(*tp)) {
11617680Spst		(void)printf("truncated-tcp %d", length);
11717680Spst		return;
11817680Spst	}
11917680Spst
12017680Spst	sport = ntohs(tp->th_sport);
12117680Spst	dport = ntohs(tp->th_dport);
12217680Spst	seq = ntohl(tp->th_seq);
12317680Spst	ack = ntohl(tp->th_ack);
12417680Spst	win = ntohs(tp->th_win);
12517680Spst	urp = ntohs(tp->th_urp);
12617680Spst
12717680Spst	(void)printf("%s.%s > %s.%s: ",
12817680Spst		ipaddr_string(&ip->ip_src), tcpport_string(sport),
12917680Spst		ipaddr_string(&ip->ip_dst), tcpport_string(dport));
13017680Spst
13117680Spst	if (qflag) {
13217680Spst		(void)printf("tcp %d", length - tp->th_off * 4);
13317680Spst		return;
13417680Spst	}
13517680Spst	if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
13617680Spst		if (flags & TH_SYN)
13717680Spst			putchar('S');
13817680Spst		if (flags & TH_FIN)
13917680Spst			putchar('F');
14017680Spst		if (flags & TH_RST)
14117680Spst			putchar('R');
14217680Spst		if (flags & TH_PUSH)
14317680Spst			putchar('P');
14417680Spst	} else
14517680Spst		putchar('.');
14617680Spst
14717680Spst	if (!Sflag && (flags & TH_ACK)) {
14817680Spst		register struct tcp_seq_hash *th;
14917680Spst		register int rev;
15017680Spst		struct tha tha;
15117680Spst		/*
15217680Spst		 * Find (or record) the initial sequence numbers for
15317680Spst		 * this conversation.  (we pick an arbitrary
15417680Spst		 * collating order so there's only one entry for
15517680Spst		 * both directions).
15617680Spst		 */
15717680Spst		if (sport < dport ||
15817680Spst		    (sport == dport &&
15917680Spst		     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
16017680Spst			tha.src = ip->ip_src, tha.dst = ip->ip_dst;
16117680Spst			tha.port = sport << 16 | dport;
16217680Spst			rev = 0;
16317680Spst		} else {
16417680Spst			tha.src = ip->ip_dst, tha.dst = ip->ip_src;
16517680Spst			tha.port = dport << 16 | sport;
16617680Spst			rev = 1;
16717680Spst		}
16817680Spst
16917680Spst		for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
17017680Spst		     th->nxt; th = th->nxt)
17117680Spst			if (!memcmp((char *)&tha, (char *)&th->addr,
17217680Spst				  sizeof(th->addr)))
17317680Spst				break;
17417680Spst
17517680Spst		if (!th->nxt || flags & TH_SYN) {
17617680Spst			/* didn't find it or new conversation */
17717680Spst			if (th->nxt == NULL) {
17817680Spst				th->nxt = (struct tcp_seq_hash *)
17917680Spst					calloc(1, sizeof(*th));
18017680Spst				if (th->nxt == NULL)
18117680Spst					error("tcp_print: calloc");
18217680Spst			}
18317680Spst			th->addr = tha;
18417680Spst			if (rev)
18517680Spst				th->ack = seq, th->seq = ack - 1;
18617680Spst			else
18717680Spst				th->seq = seq, th->ack = ack - 1;
18817680Spst		} else {
18917680Spst			if (rev)
19017680Spst				seq -= th->ack, ack -= th->seq;
19117680Spst			else
19217680Spst				seq -= th->seq, ack -= th->ack;
19317680Spst		}
19417680Spst	}
19517680Spst	hlen = tp->th_off * 4;
19626180Sfenner	if (hlen > length) {
19726180Sfenner		(void)printf(" [bad hdr length]");
19826180Sfenner		return;
19926180Sfenner	}
20017680Spst	length -= hlen;
20117680Spst	if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
20217680Spst		(void)printf(" %u:%u(%d)", seq, seq + length, length);
20317680Spst	if (flags & TH_ACK)
20417680Spst		(void)printf(" ack %u", ack);
20517680Spst
20617680Spst	(void)printf(" win %d", win);
20717680Spst
20817680Spst	if (flags & TH_URG)
20917680Spst		(void)printf(" urg %d", urp);
21017680Spst	/*
21117680Spst	 * Handle any options.
21217680Spst	 */
21317680Spst	if ((hlen -= sizeof(*tp)) > 0) {
21417680Spst		register const u_char *cp;
21517680Spst		register int i, opt, len, datalen;
21617680Spst
21717680Spst		cp = (const u_char *)tp + sizeof(*tp);
21817680Spst		putchar(' ');
21917680Spst		ch = '<';
22017680Spst		while (hlen > 0) {
22117680Spst			putchar(ch);
22226180Sfenner			TCHECK(*cp);
22317680Spst			opt = *cp++;
22417680Spst			if (ZEROLENOPT(opt))
22517680Spst				len = 1;
22617680Spst			else {
22726180Sfenner				TCHECK(*cp);
22826180Sfenner				len = *cp++;	/* total including type, len */
22926180Sfenner				if (len < 2 || len > hlen)
23026180Sfenner					goto bad;
23126180Sfenner				--hlen;		/* account for length byte */
23217680Spst			}
23326180Sfenner			--hlen;			/* account for type byte */
23417680Spst			datalen = 0;
23526180Sfenner
23626180Sfenner/* Bail if "l" bytes of data are not left or were not captured  */
23726180Sfenner#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
23826180Sfenner
23917680Spst			switch (opt) {
24017680Spst
24117680Spst			case TCPOPT_MAXSEG:
24217680Spst				(void)printf("mss");
24317680Spst				datalen = 2;
24426180Sfenner				LENCHECK(datalen);
24517680Spst				(void)printf(" %u", EXTRACT_16BITS(cp));
24617680Spst
24717680Spst				break;
24817680Spst
24917680Spst			case TCPOPT_EOL:
25017680Spst				(void)printf("eol");
25117680Spst				break;
25217680Spst
25317680Spst			case TCPOPT_NOP:
25417680Spst				(void)printf("nop");
25517680Spst				break;
25617680Spst
25717680Spst			case TCPOPT_WSCALE:
25817680Spst				(void)printf("wscale");
25917680Spst				datalen = 1;
26026180Sfenner				LENCHECK(datalen);
26117680Spst				(void)printf(" %u", *cp);
26217680Spst				break;
26317680Spst
26417680Spst			case TCPOPT_SACKOK:
26517680Spst				(void)printf("sackOK");
26617680Spst				break;
26717680Spst
26817680Spst			case TCPOPT_SACK:
26917680Spst				(void)printf("sack");
27017680Spst				datalen = len - 2;
27126180Sfenner				for (i = 0; i < datalen; i += 4) {
27226180Sfenner					LENCHECK(i + 4);
27317680Spst					/* block-size@relative-origin */
27417680Spst					(void)printf(" %u@%u",
27526180Sfenner					    EXTRACT_16BITS(cp + i + 2),
27626180Sfenner					    EXTRACT_16BITS(cp + i));
27717680Spst				}
27817680Spst				if (datalen % 4)
27917680Spst					(void)printf("[len %d]", len);
28017680Spst				break;
28117680Spst
28217680Spst			case TCPOPT_ECHO:
28317680Spst				(void)printf("echo");
28417680Spst				datalen = 4;
28526180Sfenner				LENCHECK(datalen);
28617680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
28717680Spst				break;
28817680Spst
28917680Spst			case TCPOPT_ECHOREPLY:
29017680Spst				(void)printf("echoreply");
29117680Spst				datalen = 4;
29226180Sfenner				LENCHECK(datalen);
29317680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
29417680Spst				break;
29517680Spst
29617680Spst			case TCPOPT_TIMESTAMP:
29717680Spst				(void)printf("timestamp");
29826180Sfenner				datalen = 8;
29926180Sfenner				LENCHECK(4);
30017680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
30126180Sfenner				LENCHECK(datalen);
30217680Spst				(void)printf(" %u", EXTRACT_32BITS(cp + 4));
30317680Spst				break;
30417680Spst
30517680Spst			case TCPOPT_CC:
30617680Spst				(void)printf("cc");
30717680Spst				datalen = 4;
30826180Sfenner				LENCHECK(datalen);
30917680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
31017680Spst				break;
31117680Spst
31217680Spst			case TCPOPT_CCNEW:
31317680Spst				(void)printf("ccnew");
31417680Spst				datalen = 4;
31526180Sfenner				LENCHECK(datalen);
31617680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
31717680Spst				break;
31817680Spst
31917680Spst			case TCPOPT_CCECHO:
32017680Spst				(void)printf("ccecho");
32117680Spst				datalen = 4;
32226180Sfenner				LENCHECK(datalen);
32317680Spst				(void)printf(" %u", EXTRACT_32BITS(cp));
32417680Spst				break;
32517680Spst
32617680Spst			default:
32717680Spst				(void)printf("opt-%d:", opt);
32817680Spst				datalen = len - 2;
32917680Spst				for (i = 0; i < datalen; ++i) {
33026180Sfenner					LENCHECK(i);
33117680Spst					(void)printf("%02x", cp[i]);
33217680Spst				}
33317680Spst				break;
33417680Spst			}
33517680Spst
33617680Spst			/* Account for data printed */
33717680Spst			cp += datalen;
33817680Spst			hlen -= datalen;
33917680Spst
34017680Spst			/* Check specification against observed length */
34117680Spst			++datalen;			/* option octet */
34217680Spst			if (!ZEROLENOPT(opt))
34317680Spst				++datalen;		/* size octet */
34417680Spst			if (datalen != len)
34517680Spst				(void)printf("[len %d]", len);
34617680Spst			ch = ',';
34726180Sfenner			if (opt == TCPOPT_EOL)
34826180Sfenner				break;
34917680Spst		}
35017680Spst		putchar('>');
35117680Spst	}
35217680Spst	return;
35326180Sfennerbad:
35426180Sfenner	fputs("[bad opt]", stdout);
35526180Sfenner	if (ch != '\0')
35626180Sfenner		putchar('>');
35726180Sfenner	return;
35817680Spsttrunc:
35917680Spst	fputs("[|tcp]", stdout);
36017680Spst	if (ch != '\0')
36117680Spst		putchar('>');
36217680Spst}
36317680Spst
364