xref: /plan9/sys/src/cmd/ip/snoopy/tcp.c (revision 6b6b9ac8b0b103b1e30e4d019522a78c950fce74)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <ip.h>
49a747e4fSDavid du Colombier #include "dat.h"
59a747e4fSDavid du Colombier #include "protos.h"
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier typedef struct Hdr	Hdr;
89a747e4fSDavid du Colombier struct Hdr
99a747e4fSDavid du Colombier {
109a747e4fSDavid du Colombier 	uchar	sport[2];
119a747e4fSDavid du Colombier 	uchar	dport[2];
129a747e4fSDavid du Colombier 	uchar	seq[4];
139a747e4fSDavid du Colombier 	uchar	ack[4];
149a747e4fSDavid du Colombier 	uchar	flag[2];
159a747e4fSDavid du Colombier 	uchar	win[2];
169a747e4fSDavid du Colombier 	uchar	cksum[2];
179a747e4fSDavid du Colombier 	uchar	urg[2];
18*6b6b9ac8SDavid du Colombier 	uchar	opt[1];
199a747e4fSDavid du Colombier };
209a747e4fSDavid du Colombier 
219a747e4fSDavid du Colombier typedef struct PseudoHdr{
229a747e4fSDavid du Colombier 	uchar	src[4];
239a747e4fSDavid du Colombier 	uchar	dst[4];
249a747e4fSDavid du Colombier 	uchar	zero;
259a747e4fSDavid du Colombier 	uchar	proto;
269a747e4fSDavid du Colombier 	uchar	length[2];
279a747e4fSDavid du Colombier 	uchar	hdrdata[1580];
289a747e4fSDavid du Colombier } PseudoHdr;
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier enum
319a747e4fSDavid du Colombier {
329a747e4fSDavid du Colombier 	TCPLEN= 20,
339a747e4fSDavid du Colombier };
349a747e4fSDavid du Colombier 
359a747e4fSDavid du Colombier enum
369a747e4fSDavid du Colombier {
379a747e4fSDavid du Colombier 	Os,
389a747e4fSDavid du Colombier 	Od,
399a747e4fSDavid du Colombier 	Osd,
409a747e4fSDavid du Colombier };
419a747e4fSDavid du Colombier 
429a747e4fSDavid du Colombier static Field p_fields[] =
439a747e4fSDavid du Colombier {
449a747e4fSDavid du Colombier 	{"s",		Fnum,	Os,	"source port",	} ,
459a747e4fSDavid du Colombier 	{"d",		Fnum,	Od,	"dest port",	} ,
469a747e4fSDavid du Colombier 	{"sd",		Fnum,	Osd,	"source/dest port",	} ,
479a747e4fSDavid du Colombier 	{0}
489a747e4fSDavid du Colombier };
499a747e4fSDavid du Colombier 
509a747e4fSDavid du Colombier static Mux p_mux[] =
519a747e4fSDavid du Colombier {
529a747e4fSDavid du Colombier 	{"ninep",	17007, },	/* exportfs */
539a747e4fSDavid du Colombier 	{"ninep",	564, },		/* 9fs */
549a747e4fSDavid du Colombier 	{"ninep",	17005, },	/* ocpu */
559a747e4fSDavid du Colombier 	{"ninep",	17010, },	/* ncpu */
569a747e4fSDavid du Colombier 	{"ninep",	17013, },	/* cpu */
579a747e4fSDavid du Colombier 	{0},
589a747e4fSDavid du Colombier };
599a747e4fSDavid du Colombier 
60*6b6b9ac8SDavid du Colombier enum
61*6b6b9ac8SDavid du Colombier {
62*6b6b9ac8SDavid du Colombier 	EOLOPT		= 0,
63*6b6b9ac8SDavid du Colombier 	NOOPOPT		= 1,
64*6b6b9ac8SDavid du Colombier 	MSSOPT		= 2,
65*6b6b9ac8SDavid du Colombier 	MSS_LENGTH	= 4,		/* Mean segment size */
66*6b6b9ac8SDavid du Colombier 	WSOPT		= 3,
67*6b6b9ac8SDavid du Colombier 	WS_LENGTH	= 3,		/* Bits to scale window size by */
68*6b6b9ac8SDavid du Colombier };
69*6b6b9ac8SDavid du Colombier 
709a747e4fSDavid du Colombier static void
719a747e4fSDavid du Colombier p_compile(Filter *f)
729a747e4fSDavid du Colombier {
739a747e4fSDavid du Colombier 	Mux *m;
749a747e4fSDavid du Colombier 
759a747e4fSDavid du Colombier 	if(f->op == '='){
769a747e4fSDavid du Colombier 		compile_cmp(udp.name, f, p_fields);
779a747e4fSDavid du Colombier 		return;
789a747e4fSDavid du Colombier 	}
799a747e4fSDavid du Colombier 	for(m = p_mux; m->name != nil; m++)
809a747e4fSDavid du Colombier 		if(strcmp(f->s, m->name) == 0){
819a747e4fSDavid du Colombier 			f->pr = m->pr;
829a747e4fSDavid du Colombier 			f->ulv = m->val;
833ff48bf5SDavid du Colombier 			f->subop = Osd;
849a747e4fSDavid du Colombier 			return;
859a747e4fSDavid du Colombier 		}
869a747e4fSDavid du Colombier 	sysfatal("unknown tcp field or protocol: %s", f->s);
879a747e4fSDavid du Colombier }
889a747e4fSDavid du Colombier 
899a747e4fSDavid du Colombier static int
909a747e4fSDavid du Colombier p_filter(Filter *f, Msg *m)
919a747e4fSDavid du Colombier {
929a747e4fSDavid du Colombier 	Hdr *h;
939a747e4fSDavid du Colombier 
949a747e4fSDavid du Colombier 	if(m->pe - m->ps < TCPLEN)
959a747e4fSDavid du Colombier 		return 0;
969a747e4fSDavid du Colombier 
979a747e4fSDavid du Colombier 	h = (Hdr*)m->ps;
989a747e4fSDavid du Colombier 	m->ps += ((NetS(h->flag)>>10)&0x3f);
999a747e4fSDavid du Colombier 
1009a747e4fSDavid du Colombier 	switch(f->subop){
1019a747e4fSDavid du Colombier 	case Os:
1029a747e4fSDavid du Colombier 		return NetS(h->sport) == f->ulv;
1039a747e4fSDavid du Colombier 	case Od:
1049a747e4fSDavid du Colombier 		return NetS(h->dport) == f->ulv;
1059a747e4fSDavid du Colombier 	case Osd:
1069a747e4fSDavid du Colombier 		return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
1079a747e4fSDavid du Colombier 	}
1089a747e4fSDavid du Colombier 	return 0;
1099a747e4fSDavid du Colombier }
1109a747e4fSDavid du Colombier 
1119a747e4fSDavid du Colombier enum
1129a747e4fSDavid du Colombier {
1139a747e4fSDavid du Colombier 	URG		= 0x20,		/* Data marked urgent */
1149a747e4fSDavid du Colombier 	ACK		= 0x10,		/* Aknowledge is valid */
1159a747e4fSDavid du Colombier 	PSH		= 0x08,		/* Whole data pipe is pushed */
1169a747e4fSDavid du Colombier 	RST		= 0x04,		/* Reset connection */
1179a747e4fSDavid du Colombier 	SYN		= 0x02,		/* Pkt. is synchronise */
1189a747e4fSDavid du Colombier 	FIN		= 0x01,		/* Start close down */
1199a747e4fSDavid du Colombier };
1209a747e4fSDavid du Colombier 
1219a747e4fSDavid du Colombier static char*
1229a747e4fSDavid du Colombier flags(int f)
1239a747e4fSDavid du Colombier {
1249a747e4fSDavid du Colombier 	static char fl[20];
1259a747e4fSDavid du Colombier 	char *p;
1269a747e4fSDavid du Colombier 
1279a747e4fSDavid du Colombier 	p = fl;
1289a747e4fSDavid du Colombier 	if(f & URG)
1299a747e4fSDavid du Colombier 		*p++ = 'U';
1309a747e4fSDavid du Colombier 	if(f & ACK)
1319a747e4fSDavid du Colombier 		*p++ = 'A';
1329a747e4fSDavid du Colombier 	if(f & PSH)
1339a747e4fSDavid du Colombier 		*p++ = 'P';
1349a747e4fSDavid du Colombier 	if(f & RST)
1359a747e4fSDavid du Colombier 		*p++ = 'R';
1369a747e4fSDavid du Colombier 	if(f & SYN)
1379a747e4fSDavid du Colombier 		*p++ = 'S';
1389a747e4fSDavid du Colombier 	if(f & FIN)
1399a747e4fSDavid du Colombier 		*p++ = 'F';
1409a747e4fSDavid du Colombier 	*p = 0;
1419a747e4fSDavid du Colombier 	return fl;
1429a747e4fSDavid du Colombier }
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier 
1459a747e4fSDavid du Colombier static int
1469a747e4fSDavid du Colombier p_seprint(Msg *m)
1479a747e4fSDavid du Colombier {
1489a747e4fSDavid du Colombier 	Hdr *h;
1499a747e4fSDavid du Colombier 	int dport, sport;
150*6b6b9ac8SDavid du Colombier 	int len, flag, optlen;
151*6b6b9ac8SDavid du Colombier 	uchar *optr;
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier 	if(m->pe - m->ps < TCPLEN)
1549a747e4fSDavid du Colombier 		return -1;
1559a747e4fSDavid du Colombier 	h = (Hdr*)m->ps;
1569a747e4fSDavid du Colombier 
1579a747e4fSDavid du Colombier 	/* get tcp header length */
1589a747e4fSDavid du Colombier 	flag = NetS(h->flag);
159*6b6b9ac8SDavid du Colombier 	len = (flag>>10)&~3;
1609a747e4fSDavid du Colombier 	flag &= 0x3ff;
1619a747e4fSDavid du Colombier 	m->ps += len;
1629a747e4fSDavid du Colombier 
1639a747e4fSDavid du Colombier 	/* next protocol */
1649a747e4fSDavid du Colombier 	dport = NetS(h->dport);
1659a747e4fSDavid du Colombier 	sport = NetS(h->sport);
1669a747e4fSDavid du Colombier 	demux(p_mux, sport, dport, m, &dump);
1679a747e4fSDavid du Colombier 
1689a747e4fSDavid du Colombier 	m->p = seprint(m->p, m->e, "s=%d d=%d seq=%lud ack=%lud fl=%s win=%d ck=%4.4ux",
1699a747e4fSDavid du Colombier 			NetS(h->sport), dport,
1709a747e4fSDavid du Colombier 			(ulong)NetL(h->seq), (ulong)NetL(h->ack),
1719a747e4fSDavid du Colombier 			flags(flag), NetS(h->win),
1729a747e4fSDavid du Colombier 			NetS(h->cksum));
1739a747e4fSDavid du Colombier 
174*6b6b9ac8SDavid du Colombier 	/* tcp options */
175*6b6b9ac8SDavid du Colombier 	len -= TCPLEN;
176*6b6b9ac8SDavid du Colombier 	optr = h->opt;
177*6b6b9ac8SDavid du Colombier 	while(len > 0) {
178*6b6b9ac8SDavid du Colombier 		if(*optr == EOLOPT){
179*6b6b9ac8SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt=EOL");
180*6b6b9ac8SDavid du Colombier 			break;
181*6b6b9ac8SDavid du Colombier 		}
182*6b6b9ac8SDavid du Colombier 		if(*optr == NOOPOPT) {
183*6b6b9ac8SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt=NOOP");
184*6b6b9ac8SDavid du Colombier 			len--;
185*6b6b9ac8SDavid du Colombier 			optr++;
186*6b6b9ac8SDavid du Colombier 			continue;
187*6b6b9ac8SDavid du Colombier 		}
188*6b6b9ac8SDavid du Colombier 		optlen = optr[1];
189*6b6b9ac8SDavid du Colombier 		if(optlen < 2 || optlen > len)
190*6b6b9ac8SDavid du Colombier 			break;
191*6b6b9ac8SDavid du Colombier 		switch(*optr) {
192*6b6b9ac8SDavid du Colombier 		case MSSOPT:
193*6b6b9ac8SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt%d=(mss %ud)", optlen, nhgets(optr+2));
194*6b6b9ac8SDavid du Colombier 			break;
195*6b6b9ac8SDavid du Colombier 		case WSOPT:
196*6b6b9ac8SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt%d=(wscale %ud)", optlen, *(optr+2));
197*6b6b9ac8SDavid du Colombier 			break;
198*6b6b9ac8SDavid du Colombier 		default:
199*6b6b9ac8SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt%d=(%ud %.*H)", optlen, *optr, optlen-2,optr+2);
200*6b6b9ac8SDavid du Colombier 		}
201*6b6b9ac8SDavid du Colombier 		len -= optlen;
202*6b6b9ac8SDavid du Colombier 		optr += optlen;
203*6b6b9ac8SDavid du Colombier 	}
204*6b6b9ac8SDavid du Colombier 
2059a747e4fSDavid du Colombier 	if(Cflag){
2069a747e4fSDavid du Colombier 		// editing in progress by ehg
2079a747e4fSDavid du Colombier 	}
2089a747e4fSDavid du Colombier 	return 0;
2099a747e4fSDavid du Colombier }
2109a747e4fSDavid du Colombier 
2119a747e4fSDavid du Colombier Proto tcp =
2129a747e4fSDavid du Colombier {
2139a747e4fSDavid du Colombier 	"tcp",
2149a747e4fSDavid du Colombier 	p_compile,
2159a747e4fSDavid du Colombier 	p_filter,
2169a747e4fSDavid du Colombier 	p_seprint,
2179a747e4fSDavid du Colombier 	p_mux,
2189a747e4fSDavid du Colombier 	p_fields,
2193ff48bf5SDavid du Colombier 	defaultframer,
2209a747e4fSDavid du Colombier };
221