summaryrefslogtreecommitdiffstats
path: root/listen/tcpdump.c
blob: 3a9520fd0fd7629ea54ea4ba6700ce552a8f8b81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* @(#) $Header: /home/ax25-cvs/ax25-apps/listen/tcpdump.c,v 1.1 2001/04/10 01:58:56 csmall Exp $ */

/* TCP header tracing routines
 * Copyright 1991 Phil Karn, KA9Q
 */
#include <stdio.h>
#include <string.h>
#include "listen.h"

#define	FIN	0x01
#define	SYN	0x02
#define	RST	0x04
#define	PSH	0x08
#define	ACK	0x10
#define	URG	0x20
#define	CE	0x40

/* TCP options */
#define EOL_KIND	0
#define NOOP_KIND	1
#define MSS_KIND	2
#define MSS_LENGTH	4

#define	TCPLEN	20

#define max(a,b)  ((a) > (b) ? (a) : (b))

/* Dump a TCP segment header. Assumed to be in network byte order */
void tcp_dump(unsigned char *data, int length, int hexdump)
{
	int source, dest;
	int seq;
	int ack;
	int flags;
	int wnd;
	int up;
	int hdrlen;
	int mss = 0;

	source = get16(data + 0);
	dest   = get16(data + 2);
	seq    = get32(data + 4);
	ack    = get32(data + 8);
	hdrlen = (data[12] & 0xF0) >> 2;
	flags  = data[13];
	wnd    = get16(data + 14);
	up     = get16(data + 18);

	lprintf(T_PROTOCOL, "TCP:");
	lprintf(T_TCPHDR, " %s->", servname(source, "tcp"));
	lprintf(T_TCPHDR, "%s Seq x%x", servname(dest, "tcp"), seq);

	if (flags & ACK) lprintf(T_TCPHDR, " Ack x%x", ack);

	if (flags & CE)  lprintf(T_TCPHDR, " CE");

	if (flags & URG) lprintf(T_TCPHDR, " URG");

	if (flags & ACK) lprintf(T_TCPHDR, " ACK");

	if (flags & PSH) lprintf(T_TCPHDR, " PSH");

	if (flags & RST) lprintf(T_TCPHDR, " RST");

	if (flags & SYN) lprintf(T_TCPHDR, " SYN");

	if (flags & FIN) lprintf(T_TCPHDR, " FIN");

	lprintf(T_TCPHDR, " Wnd %d", wnd);

	if (flags & URG) lprintf(T_TCPHDR, " UP x%x", up);

	/* Process options, if any */
	if (hdrlen > TCPLEN && length >= hdrlen) {
		unsigned char *cp = data + TCPLEN;
		int i = hdrlen - TCPLEN;
		int kind, optlen;

		while (i > 0) {
			kind = *cp++;

			/* Process single-byte options */
			switch (kind) {
			case EOL_KIND:
				i--;
				cp++;
				break;
			case NOOP_KIND:
				i--;
				cp++;
				continue;
			}

			/* All other options have a length field */
			optlen = *cp++;

			/* Process valid multi-byte options */
  			switch (kind) {
			case MSS_KIND:
			 	if (optlen == MSS_LENGTH)
					mss = get16(cp);
				break;
			}

			optlen = max(2, optlen); /* Enforce legal minimum */
			i -= optlen;
			cp += optlen - 2;
		}
	}

	if (mss != 0) lprintf(T_TCPHDR," MSS %d", mss);

	length -= hdrlen;
	data   += hdrlen;

	if (length > 0) {
		lprintf(T_TCPHDR, " Data %d\n", length);
		data_dump(data, length, hexdump);
		return;
	}
	
	lprintf(T_TCPHDR, "\n");
}