xref: /plan9/sys/src/cmd/ip/snoopy/tcp.c (revision 596f97da1b0ee4a9c44c62489341982fa784c8ed)
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];
186b6b9ac8SDavid 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",	} ,
46dc5a79c1SDavid du Colombier 	{"a",		Fnum,	Osd,	"source/dest port",	} ,
479a747e4fSDavid du Colombier 	{"sd",		Fnum,	Osd,	"source/dest port",	} ,
489a747e4fSDavid du Colombier 	{0}
499a747e4fSDavid du Colombier };
509a747e4fSDavid du Colombier 
519a747e4fSDavid du Colombier static Mux p_mux[] =
529a747e4fSDavid du Colombier {
53b4b9fc2fSDavid du Colombier 	{"dns",		53, },
549a747e4fSDavid du Colombier 	{"ninep",	17007, },	/* exportfs */
559a747e4fSDavid du Colombier 	{"ninep",	564, },		/* 9fs */
569a747e4fSDavid du Colombier 	{"ninep",	17005, },	/* ocpu */
579a747e4fSDavid du Colombier 	{"ninep",	17010, },	/* ncpu */
589a747e4fSDavid du Colombier 	{"ninep",	17013, },	/* cpu */
599a747e4fSDavid du Colombier 	{0},
609a747e4fSDavid du Colombier };
619a747e4fSDavid du Colombier 
626b6b9ac8SDavid du Colombier enum
636b6b9ac8SDavid du Colombier {
646b6b9ac8SDavid du Colombier 	EOLOPT		= 0,
656b6b9ac8SDavid du Colombier 	NOOPOPT		= 1,
666b6b9ac8SDavid du Colombier 	MSSOPT		= 2,
676b6b9ac8SDavid du Colombier 	MSS_LENGTH	= 4,		/* Mean segment size */
686b6b9ac8SDavid du Colombier 	WSOPT		= 3,
696b6b9ac8SDavid du Colombier 	WS_LENGTH	= 3,		/* Bits to scale window size by */
706b6b9ac8SDavid du Colombier };
716b6b9ac8SDavid du Colombier 
729a747e4fSDavid du Colombier static void
p_compile(Filter * f)739a747e4fSDavid du Colombier p_compile(Filter *f)
749a747e4fSDavid du Colombier {
759a747e4fSDavid du Colombier 	Mux *m;
769a747e4fSDavid du Colombier 
779a747e4fSDavid du Colombier 	if(f->op == '='){
780b9a5132SDavid du Colombier 		compile_cmp(tcp.name, f, p_fields);
799a747e4fSDavid du Colombier 		return;
809a747e4fSDavid du Colombier 	}
819a747e4fSDavid du Colombier 	for(m = p_mux; m->name != nil; m++)
829a747e4fSDavid du Colombier 		if(strcmp(f->s, m->name) == 0){
839a747e4fSDavid du Colombier 			f->pr = m->pr;
849a747e4fSDavid du Colombier 			f->ulv = m->val;
853ff48bf5SDavid du Colombier 			f->subop = Osd;
869a747e4fSDavid du Colombier 			return;
879a747e4fSDavid du Colombier 		}
889a747e4fSDavid du Colombier 	sysfatal("unknown tcp field or protocol: %s", f->s);
899a747e4fSDavid du Colombier }
909a747e4fSDavid du Colombier 
919a747e4fSDavid du Colombier static int
p_filter(Filter * f,Msg * m)929a747e4fSDavid du Colombier p_filter(Filter *f, Msg *m)
939a747e4fSDavid du Colombier {
949a747e4fSDavid du Colombier 	Hdr *h;
959a747e4fSDavid du Colombier 
969a747e4fSDavid du Colombier 	if(m->pe - m->ps < TCPLEN)
979a747e4fSDavid du Colombier 		return 0;
989a747e4fSDavid du Colombier 
999a747e4fSDavid du Colombier 	h = (Hdr*)m->ps;
100*e6dcbf51SDavid du Colombier 	m->ps += (NetS(h->flag)>>10) & 0x3f;
1019a747e4fSDavid du Colombier 
1029a747e4fSDavid du Colombier 	switch(f->subop){
1039a747e4fSDavid du Colombier 	case Os:
1049a747e4fSDavid du Colombier 		return NetS(h->sport) == f->ulv;
1059a747e4fSDavid du Colombier 	case Od:
1069a747e4fSDavid du Colombier 		return NetS(h->dport) == f->ulv;
1079a747e4fSDavid du Colombier 	case Osd:
1089a747e4fSDavid du Colombier 		return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
1099a747e4fSDavid du Colombier 	}
1109a747e4fSDavid du Colombier 	return 0;
1119a747e4fSDavid du Colombier }
1129a747e4fSDavid du Colombier 
1139a747e4fSDavid du Colombier enum
1149a747e4fSDavid du Colombier {
1159a747e4fSDavid du Colombier 	URG		= 0x20,		/* Data marked urgent */
1169a747e4fSDavid du Colombier 	ACK		= 0x10,		/* Aknowledge is valid */
1179a747e4fSDavid du Colombier 	PSH		= 0x08,		/* Whole data pipe is pushed */
1189a747e4fSDavid du Colombier 	RST		= 0x04,		/* Reset connection */
1199a747e4fSDavid du Colombier 	SYN		= 0x02,		/* Pkt. is synchronise */
1209a747e4fSDavid du Colombier 	FIN		= 0x01,		/* Start close down */
1219a747e4fSDavid du Colombier };
1229a747e4fSDavid du Colombier 
1239a747e4fSDavid du Colombier static char*
flags(int f)1249a747e4fSDavid du Colombier flags(int f)
1259a747e4fSDavid du Colombier {
1269a747e4fSDavid du Colombier 	static char fl[20];
1279a747e4fSDavid du Colombier 	char *p;
1289a747e4fSDavid du Colombier 
1299a747e4fSDavid du Colombier 	p = fl;
1309a747e4fSDavid du Colombier 	if(f & URG)
1319a747e4fSDavid du Colombier 		*p++ = 'U';
1329a747e4fSDavid du Colombier 	if(f & ACK)
1339a747e4fSDavid du Colombier 		*p++ = 'A';
1349a747e4fSDavid du Colombier 	if(f & PSH)
1359a747e4fSDavid du Colombier 		*p++ = 'P';
1369a747e4fSDavid du Colombier 	if(f & RST)
1379a747e4fSDavid du Colombier 		*p++ = 'R';
1389a747e4fSDavid du Colombier 	if(f & SYN)
1399a747e4fSDavid du Colombier 		*p++ = 'S';
1409a747e4fSDavid du Colombier 	if(f & FIN)
1419a747e4fSDavid du Colombier 		*p++ = 'F';
1429a747e4fSDavid du Colombier 	*p = 0;
1439a747e4fSDavid du Colombier 	return fl;
1449a747e4fSDavid du Colombier }
1459a747e4fSDavid du Colombier 
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier static int
p_seprint(Msg * m)1489a747e4fSDavid du Colombier p_seprint(Msg *m)
1499a747e4fSDavid du Colombier {
150*e6dcbf51SDavid du Colombier 	int dport, sport, len, flag, optlen;
1516b6b9ac8SDavid du Colombier 	uchar *optr;
152*e6dcbf51SDavid du Colombier 	Hdr *h;
1539a747e4fSDavid du Colombier 
1549a747e4fSDavid du Colombier 	if(m->pe - m->ps < TCPLEN)
1559a747e4fSDavid du Colombier 		return -1;
1569a747e4fSDavid du Colombier 	h = (Hdr*)m->ps;
1579a747e4fSDavid du Colombier 
1589a747e4fSDavid du Colombier 	/* get tcp header length */
1599a747e4fSDavid du Colombier 	flag = NetS(h->flag);
1606b6b9ac8SDavid du Colombier 	len = (flag>>10) & ~3;
1619a747e4fSDavid du Colombier 	flag &= 0x3ff;
1629a747e4fSDavid du Colombier 	m->ps += len;
1639a747e4fSDavid du Colombier 
1649a747e4fSDavid du Colombier 	/* next protocol */
1659a747e4fSDavid du Colombier 	dport = NetS(h->dport);
1669a747e4fSDavid du Colombier 	sport = NetS(h->sport);
1679a747e4fSDavid du Colombier 	demux(p_mux, sport, dport, m, &dump);
1689a747e4fSDavid du Colombier 
1699a747e4fSDavid du Colombier 	m->p = seprint(m->p, m->e, "s=%d d=%d seq=%lud ack=%lud fl=%s win=%d ck=%4.4ux",
1709a747e4fSDavid du Colombier 			NetS(h->sport), dport,
1719a747e4fSDavid du Colombier 			(ulong)NetL(h->seq), (ulong)NetL(h->ack),
1729a747e4fSDavid du Colombier 			flags(flag), NetS(h->win),
1739a747e4fSDavid du Colombier 			NetS(h->cksum));
1749a747e4fSDavid du Colombier 
1756b6b9ac8SDavid du Colombier 	/* tcp options */
1766b6b9ac8SDavid du Colombier 	len -= TCPLEN;
1776b6b9ac8SDavid du Colombier 	optr = h->opt;
1786b6b9ac8SDavid du Colombier 	while(len > 0) {
1796b6b9ac8SDavid du Colombier 		if(*optr == EOLOPT){
1806b6b9ac8SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt=EOL");
1816b6b9ac8SDavid du Colombier 			break;
1826b6b9ac8SDavid du Colombier 		}
1836b6b9ac8SDavid du Colombier 		if(*optr == NOOPOPT) {
1846b6b9ac8SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt=NOOP");
1856b6b9ac8SDavid du Colombier 			len--;
1866b6b9ac8SDavid du Colombier 			optr++;
1876b6b9ac8SDavid du Colombier 			continue;
1886b6b9ac8SDavid du Colombier 		}
1896b6b9ac8SDavid du Colombier 		optlen = optr[1];
1906b6b9ac8SDavid du Colombier 		if(optlen < 2 || optlen > len)
1916b6b9ac8SDavid du Colombier 			break;
1926b6b9ac8SDavid du Colombier 		switch(*optr) {
1936b6b9ac8SDavid du Colombier 		case MSSOPT:
194*e6dcbf51SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt%d=(mss %ud)",
195*e6dcbf51SDavid du Colombier 				optlen, nhgets(optr+2));
1966b6b9ac8SDavid du Colombier 			break;
1976b6b9ac8SDavid du Colombier 		case WSOPT:
198*e6dcbf51SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt%d=(wscale %ud)",
199*e6dcbf51SDavid du Colombier 				optlen, *(optr+2));
2006b6b9ac8SDavid du Colombier 			break;
2016b6b9ac8SDavid du Colombier 		default:
202*e6dcbf51SDavid du Colombier 			m->p = seprint(m->p, m->e, " opt%d=(%ud %.*H)",
203*e6dcbf51SDavid du Colombier 				optlen, *optr, optlen-2, optr+2);
2046b6b9ac8SDavid du Colombier 		}
2056b6b9ac8SDavid du Colombier 		len -= optlen;
2066b6b9ac8SDavid du Colombier 		optr += optlen;
2076b6b9ac8SDavid 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,
218ed397113SDavid du Colombier 	"%lud",
2199a747e4fSDavid du Colombier 	p_fields,
2203ff48bf5SDavid du Colombier 	defaultframer,
2219a747e4fSDavid du Colombier };
222