xref: /plan9/sys/src/cmd/ip/snoopy/tcp.c (revision 596f97da1b0ee4a9c44c62489341982fa784c8ed)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6 
7 typedef struct Hdr	Hdr;
8 struct Hdr
9 {
10 	uchar	sport[2];
11 	uchar	dport[2];
12 	uchar	seq[4];
13 	uchar	ack[4];
14 	uchar	flag[2];
15 	uchar	win[2];
16 	uchar	cksum[2];
17 	uchar	urg[2];
18 	uchar	opt[1];
19 };
20 
21 typedef struct PseudoHdr{
22 	uchar	src[4];
23 	uchar	dst[4];
24 	uchar	zero;
25 	uchar	proto;
26 	uchar	length[2];
27 	uchar	hdrdata[1580];
28 } PseudoHdr;
29 
30 enum
31 {
32 	TCPLEN= 20,
33 };
34 
35 enum
36 {
37 	Os,
38 	Od,
39 	Osd,
40 };
41 
42 static Field p_fields[] =
43 {
44 	{"s",		Fnum,	Os,	"source port",	} ,
45 	{"d",		Fnum,	Od,	"dest port",	} ,
46 	{"a",		Fnum,	Osd,	"source/dest port",	} ,
47 	{"sd",		Fnum,	Osd,	"source/dest port",	} ,
48 	{0}
49 };
50 
51 static Mux p_mux[] =
52 {
53 	{"dns",		53, },
54 	{"ninep",	17007, },	/* exportfs */
55 	{"ninep",	564, },		/* 9fs */
56 	{"ninep",	17005, },	/* ocpu */
57 	{"ninep",	17010, },	/* ncpu */
58 	{"ninep",	17013, },	/* cpu */
59 	{0},
60 };
61 
62 enum
63 {
64 	EOLOPT		= 0,
65 	NOOPOPT		= 1,
66 	MSSOPT		= 2,
67 	MSS_LENGTH	= 4,		/* Mean segment size */
68 	WSOPT		= 3,
69 	WS_LENGTH	= 3,		/* Bits to scale window size by */
70 };
71 
72 static void
p_compile(Filter * f)73 p_compile(Filter *f)
74 {
75 	Mux *m;
76 
77 	if(f->op == '='){
78 		compile_cmp(tcp.name, f, p_fields);
79 		return;
80 	}
81 	for(m = p_mux; m->name != nil; m++)
82 		if(strcmp(f->s, m->name) == 0){
83 			f->pr = m->pr;
84 			f->ulv = m->val;
85 			f->subop = Osd;
86 			return;
87 		}
88 	sysfatal("unknown tcp field or protocol: %s", f->s);
89 }
90 
91 static int
p_filter(Filter * f,Msg * m)92 p_filter(Filter *f, Msg *m)
93 {
94 	Hdr *h;
95 
96 	if(m->pe - m->ps < TCPLEN)
97 		return 0;
98 
99 	h = (Hdr*)m->ps;
100 	m->ps += (NetS(h->flag)>>10) & 0x3f;
101 
102 	switch(f->subop){
103 	case Os:
104 		return NetS(h->sport) == f->ulv;
105 	case Od:
106 		return NetS(h->dport) == f->ulv;
107 	case Osd:
108 		return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
109 	}
110 	return 0;
111 }
112 
113 enum
114 {
115 	URG		= 0x20,		/* Data marked urgent */
116 	ACK		= 0x10,		/* Aknowledge is valid */
117 	PSH		= 0x08,		/* Whole data pipe is pushed */
118 	RST		= 0x04,		/* Reset connection */
119 	SYN		= 0x02,		/* Pkt. is synchronise */
120 	FIN		= 0x01,		/* Start close down */
121 };
122 
123 static char*
flags(int f)124 flags(int f)
125 {
126 	static char fl[20];
127 	char *p;
128 
129 	p = fl;
130 	if(f & URG)
131 		*p++ = 'U';
132 	if(f & ACK)
133 		*p++ = 'A';
134 	if(f & PSH)
135 		*p++ = 'P';
136 	if(f & RST)
137 		*p++ = 'R';
138 	if(f & SYN)
139 		*p++ = 'S';
140 	if(f & FIN)
141 		*p++ = 'F';
142 	*p = 0;
143 	return fl;
144 }
145 
146 
147 static int
p_seprint(Msg * m)148 p_seprint(Msg *m)
149 {
150 	int dport, sport, len, flag, optlen;
151 	uchar *optr;
152 	Hdr *h;
153 
154 	if(m->pe - m->ps < TCPLEN)
155 		return -1;
156 	h = (Hdr*)m->ps;
157 
158 	/* get tcp header length */
159 	flag = NetS(h->flag);
160 	len = (flag>>10) & ~3;
161 	flag &= 0x3ff;
162 	m->ps += len;
163 
164 	/* next protocol */
165 	dport = NetS(h->dport);
166 	sport = NetS(h->sport);
167 	demux(p_mux, sport, dport, m, &dump);
168 
169 	m->p = seprint(m->p, m->e, "s=%d d=%d seq=%lud ack=%lud fl=%s win=%d ck=%4.4ux",
170 			NetS(h->sport), dport,
171 			(ulong)NetL(h->seq), (ulong)NetL(h->ack),
172 			flags(flag), NetS(h->win),
173 			NetS(h->cksum));
174 
175 	/* tcp options */
176 	len -= TCPLEN;
177 	optr = h->opt;
178 	while(len > 0) {
179 		if(*optr == EOLOPT){
180 			m->p = seprint(m->p, m->e, " opt=EOL");
181 			break;
182 		}
183 		if(*optr == NOOPOPT) {
184 			m->p = seprint(m->p, m->e, " opt=NOOP");
185 			len--;
186 			optr++;
187 			continue;
188 		}
189 		optlen = optr[1];
190 		if(optlen < 2 || optlen > len)
191 			break;
192 		switch(*optr) {
193 		case MSSOPT:
194 			m->p = seprint(m->p, m->e, " opt%d=(mss %ud)",
195 				optlen, nhgets(optr+2));
196 			break;
197 		case WSOPT:
198 			m->p = seprint(m->p, m->e, " opt%d=(wscale %ud)",
199 				optlen, *(optr+2));
200 			break;
201 		default:
202 			m->p = seprint(m->p, m->e, " opt%d=(%ud %.*H)",
203 				optlen, *optr, optlen-2, optr+2);
204 		}
205 		len -= optlen;
206 		optr += optlen;
207 	}
208 	return 0;
209 }
210 
211 Proto tcp =
212 {
213 	"tcp",
214 	p_compile,
215 	p_filter,
216 	p_seprint,
217 	p_mux,
218 	"%lud",
219 	p_fields,
220 	defaultframer,
221 };
222