summaryrefslogtreecommitdiffstats
path: root/listen/tcpdump.c
blob: 9bc7e160301f136bf151090a14d72994b10b0115 (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
124
125
126
127
128
129
130
131
/* 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");
}