xref: /plan9/sys/src/cmd/ip/snoopy/ip.c (revision 853458f38e7eb3a48cfa3a36aefdb799375e398a)
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	vihl;		/* Version and header length */
119a747e4fSDavid du Colombier 	uchar	tos;		/* Type of service */
129a747e4fSDavid du Colombier 	uchar	length[2];	/* packet length */
139a747e4fSDavid du Colombier 	uchar	id[2];		/* ip->identification */
149a747e4fSDavid du Colombier 	uchar	frag[2];	/* Fragment information */
159a747e4fSDavid du Colombier 	uchar	ttl;		/* Time to live */
169a747e4fSDavid du Colombier 	uchar	proto;		/* Protocol */
179a747e4fSDavid du Colombier 	uchar	cksum[2];	/* Header checksum */
189a747e4fSDavid du Colombier 	uchar	src[4];		/* IP source */
199a747e4fSDavid du Colombier 	uchar	dst[4];		/* IP destination */
209a747e4fSDavid du Colombier };
219a747e4fSDavid du Colombier 
229a747e4fSDavid du Colombier enum
239a747e4fSDavid du Colombier {
249a747e4fSDavid du Colombier 	IPHDR		= 20,		/* sizeof(Iphdr) */
259a747e4fSDavid du Colombier 	IP_VER		= 0x40,		/* Using IP version 4 */
269a747e4fSDavid du Colombier 	IP_DF		= 0x4000,	/* Don't fragment */
279a747e4fSDavid du Colombier 	IP_MF		= 0x2000,	/* More fragments */
289a747e4fSDavid du Colombier };
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier static Mux p_mux[] =
319a747e4fSDavid du Colombier {
329a747e4fSDavid du Colombier 	{ "icmp", 1, },
339a747e4fSDavid du Colombier 	{ "igmp", 2, },
349a747e4fSDavid du Colombier 	{ "ggp", 3, },
359a747e4fSDavid du Colombier 	{ "ip", 4, },
369a747e4fSDavid du Colombier 	{ "st", 5, },
379a747e4fSDavid du Colombier 	{ "tcp", 6, },
389a747e4fSDavid du Colombier 	{ "ucl", 7, },
399a747e4fSDavid du Colombier 	{ "egp", 8, },
409a747e4fSDavid du Colombier 	{ "igp", 9, },
419a747e4fSDavid du Colombier 	{ "bbn-rcc-mon", 10, },
429a747e4fSDavid du Colombier 	{ "nvp-ii", 11, },
439a747e4fSDavid du Colombier 	{ "pup", 12, },
449a747e4fSDavid du Colombier 	{ "argus", 13, },
459a747e4fSDavid du Colombier 	{ "emcon", 14, },
469a747e4fSDavid du Colombier 	{ "xnet", 15, },
479a747e4fSDavid du Colombier 	{ "chaos", 16, },
489a747e4fSDavid du Colombier 	{ "udp", 17, },
499a747e4fSDavid du Colombier 	{ "mux", 18, },
509a747e4fSDavid du Colombier 	{ "dcn-meas", 19, },
519a747e4fSDavid du Colombier 	{ "hmp", 20, },
529a747e4fSDavid du Colombier 	{ "prm", 21, },
539a747e4fSDavid du Colombier 	{ "xns-idp", 22, },
549a747e4fSDavid du Colombier 	{ "trunk-1", 23, },
559a747e4fSDavid du Colombier 	{ "trunk-2", 24, },
569a747e4fSDavid du Colombier 	{ "leaf-1", 25, },
579a747e4fSDavid du Colombier 	{ "leaf-2", 26, },
589a747e4fSDavid du Colombier 	{ "rdp", 27, },
599a747e4fSDavid du Colombier 	{ "irtp", 28, },
609a747e4fSDavid du Colombier 	{ "iso-tp4", 29, },
619a747e4fSDavid du Colombier 	{ "netblt", 30, },
629a747e4fSDavid du Colombier 	{ "mfe-nsp", 31, },
639a747e4fSDavid du Colombier 	{ "merit-inp", 32, },
649a747e4fSDavid du Colombier 	{ "sep", 33, },
659a747e4fSDavid du Colombier 	{ "3pc", 34, },
669a747e4fSDavid du Colombier 	{ "idpr", 35, },
679a747e4fSDavid du Colombier 	{ "xtp", 36, },
689a747e4fSDavid du Colombier 	{ "ddp", 37, },
699a747e4fSDavid du Colombier 	{ "idpr-cmtp", 38, },
709a747e4fSDavid du Colombier 	{ "tp++", 39, },
719a747e4fSDavid du Colombier 	{ "il", 40, },
729a747e4fSDavid du Colombier 	{ "sip", 41, },
739a747e4fSDavid du Colombier 	{ "sdrp", 42, },
749a747e4fSDavid du Colombier 	{ "sip-sr", 43, },
759a747e4fSDavid du Colombier 	{ "sip-frag", 44, },
769a747e4fSDavid du Colombier 	{ "idrp", 45, },
779a747e4fSDavid du Colombier 	{ "rsvp", 46, },
789a747e4fSDavid du Colombier 	{ "gre", 47, },
799a747e4fSDavid du Colombier 	{ "mhrp", 48, },
809a747e4fSDavid du Colombier 	{ "bna", 49, },
819a747e4fSDavid du Colombier 	{ "sipp-esp", 50, },
829a747e4fSDavid du Colombier 	{ "sipp-ah", 51, },
839a747e4fSDavid du Colombier 	{ "i-nlsp", 52, },
849a747e4fSDavid du Colombier 	{ "swipe", 53, },
859a747e4fSDavid du Colombier 	{ "nhrp", 54, },
869a747e4fSDavid du Colombier 	{ "any", 61, },
879a747e4fSDavid du Colombier 	{ "cftp", 62, },
889a747e4fSDavid du Colombier 	{ "any", 63, },
899a747e4fSDavid du Colombier 	{ "sat-expak", 64, },
909a747e4fSDavid du Colombier 	{ "kryptolan", 65, },
919a747e4fSDavid du Colombier 	{ "rvd", 66, },
929a747e4fSDavid du Colombier 	{ "ippc", 67, },
939a747e4fSDavid du Colombier 	{ "any", 68, },
949a747e4fSDavid du Colombier 	{ "sat-mon", 69, },
959a747e4fSDavid du Colombier 	{ "visa", 70, },
969a747e4fSDavid du Colombier 	{ "ipcv", 71, },
979a747e4fSDavid du Colombier 	{ "cpnx", 72, },
989a747e4fSDavid du Colombier 	{ "cphb", 73, },
999a747e4fSDavid du Colombier 	{ "wsn", 74, },
1009a747e4fSDavid du Colombier 	{ "pvp", 75, },
1019a747e4fSDavid du Colombier 	{ "br-sat-mon", 76, },
1029a747e4fSDavid du Colombier 	{ "sun-nd", 77, },
1039a747e4fSDavid du Colombier 	{ "wb-mon", 78, },
1049a747e4fSDavid du Colombier 	{ "wb-expak", 79, },
1059a747e4fSDavid du Colombier 	{ "iso-ip", 80, },
1069a747e4fSDavid du Colombier 	{ "vmtp", 81, },
1079a747e4fSDavid du Colombier 	{ "secure-vmtp", 82, },
1089a747e4fSDavid du Colombier 	{ "vines", 83, },
1099a747e4fSDavid du Colombier 	{ "ttp", 84, },
1109a747e4fSDavid du Colombier 	{ "nsfnet-igp", 85, },
1119a747e4fSDavid du Colombier 	{ "dgp", 86, },
1129a747e4fSDavid du Colombier 	{ "tcf", 87, },
1139a747e4fSDavid du Colombier 	{ "igrp", 88, },
1149a747e4fSDavid du Colombier 	{ "ospf", 89, },
1159a747e4fSDavid du Colombier 	{ "sprite-rpc", 90, },
1169a747e4fSDavid du Colombier 	{ "larp", 91, },
1179a747e4fSDavid du Colombier 	{ "mtp", 92, },
1189a747e4fSDavid du Colombier 	{ "ax.25", 93, },
1199a747e4fSDavid du Colombier 	{ "ipip", 94, },
1209a747e4fSDavid du Colombier 	{ "micp", 95, },
1219a747e4fSDavid du Colombier 	{ "scc-sp", 96, },
1229a747e4fSDavid du Colombier 	{ "etherip", 97, },
1239a747e4fSDavid du Colombier 	{ "encap", 98, },
1249a747e4fSDavid du Colombier 	{ "any", 99, },
1259a747e4fSDavid du Colombier 	{ "gmtp", 100, },
1269a747e4fSDavid du Colombier 	{ "rudp", 254, },
1279a747e4fSDavid du Colombier 	{ 0 }
1289a747e4fSDavid du Colombier };
1299a747e4fSDavid du Colombier 
1309a747e4fSDavid du Colombier enum
1319a747e4fSDavid du Colombier {
132e6dcbf51SDavid du Colombier 	Os,	/* source */
133e6dcbf51SDavid du Colombier 	Od,	/* destination */
134e6dcbf51SDavid du Colombier 	Osd,	/* source or destination */
135e6dcbf51SDavid du Colombier 	Ot,	/* type */
1369a747e4fSDavid du Colombier };
1379a747e4fSDavid du Colombier 
1389a747e4fSDavid du Colombier static Field p_fields[] =
1399a747e4fSDavid du Colombier {
1409a747e4fSDavid du Colombier 	{"s",	Fv4ip,	Os,	"source address",	} ,
1419a747e4fSDavid du Colombier 	{"d",	Fv4ip,	Od,	"destination address",	} ,
1429a747e4fSDavid du Colombier 	{"a",	Fv4ip,	Osd,	"source|destination address",} ,
143dc5a79c1SDavid du Colombier 	{"sd",	Fv4ip,	Osd,	"source|destination address",} ,
1449a747e4fSDavid du Colombier 	{"t",	Fnum,	Ot,	"sub protocol number",	} ,
1459a747e4fSDavid du Colombier 	{0}
1469a747e4fSDavid du Colombier };
1479a747e4fSDavid du Colombier 
1489a747e4fSDavid du Colombier static void
p_compile(Filter * f)1499a747e4fSDavid du Colombier p_compile(Filter *f)
1509a747e4fSDavid du Colombier {
1519a747e4fSDavid du Colombier 	Mux *m;
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier 	if(f->op == '='){
1549a747e4fSDavid du Colombier 		compile_cmp(ip.name, f, p_fields);
1559a747e4fSDavid du Colombier 		return;
1569a747e4fSDavid du Colombier 	}
1579a747e4fSDavid du Colombier 	for(m = p_mux; m->name != nil; m++)
1589a747e4fSDavid du Colombier 		if(strcmp(f->s, m->name) == 0){
1599a747e4fSDavid du Colombier 			f->pr = m->pr;
1609a747e4fSDavid du Colombier 			f->ulv = m->val;
1619a747e4fSDavid du Colombier 			f->subop = Ot;
1629a747e4fSDavid du Colombier 			return;
1639a747e4fSDavid du Colombier 		}
1649a747e4fSDavid du Colombier 	sysfatal("unknown ip field or protocol: %s", f->s);
1659a747e4fSDavid du Colombier }
1669a747e4fSDavid du Colombier 
1679a747e4fSDavid du Colombier static int
p_filter(Filter * f,Msg * m)1689a747e4fSDavid du Colombier p_filter(Filter *f, Msg *m)
1699a747e4fSDavid du Colombier {
1709a747e4fSDavid du Colombier 	Hdr *h;
1719a747e4fSDavid du Colombier 
1729a747e4fSDavid du Colombier 	if(m->pe - m->ps < IPHDR)
1739a747e4fSDavid du Colombier 		return 0;
1749a747e4fSDavid du Colombier 
1759a747e4fSDavid du Colombier 	h = (Hdr*)m->ps;
176e6dcbf51SDavid du Colombier 	m->ps += (h->vihl & 0xf) << 2;
1779a747e4fSDavid du Colombier 
1789a747e4fSDavid du Colombier 	switch(f->subop){
1799a747e4fSDavid du Colombier 	case Os:
1809a747e4fSDavid du Colombier 		return NetL(h->src) == f->ulv;
1819a747e4fSDavid du Colombier 	case Od:
1829a747e4fSDavid du Colombier 		return NetL(h->dst) == f->ulv;
1839a747e4fSDavid du Colombier 	case Osd:
1849a747e4fSDavid du Colombier 		return NetL(h->src) == f->ulv || NetL(h->dst) == f->ulv;
1859a747e4fSDavid du Colombier 	case Ot:
1869a747e4fSDavid du Colombier 		return h->proto == f->ulv;
1879a747e4fSDavid du Colombier 	}
1889a747e4fSDavid du Colombier 	return 0;
1899a747e4fSDavid du Colombier }
1909a747e4fSDavid du Colombier 
1919a747e4fSDavid du Colombier static int
p_seprint(Msg * m)1929a747e4fSDavid du Colombier p_seprint(Msg *m)
1939a747e4fSDavid du Colombier {
194*853458f3SDavid du Colombier 	int f, len, hl;
195*853458f3SDavid du Colombier 	uchar *p;
1969a747e4fSDavid du Colombier 	Hdr *h;
1979a747e4fSDavid du Colombier 
1989a747e4fSDavid du Colombier 	if(m->pe - m->ps < IPHDR)
1999a747e4fSDavid du Colombier 		return -1;
2009a747e4fSDavid du Colombier 	h = (Hdr*)m->ps;
2019a747e4fSDavid du Colombier 
2029a747e4fSDavid du Colombier 	/* next protocol, just dump unless this is the first fragment */
2039a747e4fSDavid du Colombier 	m->pr = &dump;
2049a747e4fSDavid du Colombier 	f = NetS(h->frag);
2059a747e4fSDavid du Colombier 	if((f & ~(IP_DF|IP_MF)) == 0)
2069a747e4fSDavid du Colombier 		demux(p_mux, h->proto, h->proto, m, &dump);
2079a747e4fSDavid du Colombier 
2089a747e4fSDavid du Colombier 	/* truncate the message if there's extra */
2099a747e4fSDavid du Colombier 	len = NetS(h->length);
2109a747e4fSDavid du Colombier 	if(len < m->pe - m->ps)
2119a747e4fSDavid du Colombier 		m->pe = m->ps + len;
2129a747e4fSDavid du Colombier 
2139a747e4fSDavid du Colombier 	/* next header */
214*853458f3SDavid du Colombier 	hl = (h->vihl  &0xf) << 2;
2159a747e4fSDavid du Colombier 
216*853458f3SDavid du Colombier 	m->p = seprint(m->p, m->e, "s=%V d=%V id=%4.4ux frag=%4.4ux ttl=%3d pr=%d ln=%d hl=%d",
217e6dcbf51SDavid du Colombier 		h->src, h->dst, NetS(h->id), NetS(h->frag), h->ttl, h->proto,
218*853458f3SDavid du Colombier 		NetS(h->length),
219*853458f3SDavid du Colombier 		(h->vihl & 0xf) << 2);
220*853458f3SDavid du Colombier 
221*853458f3SDavid du Colombier 	m->ps += hl;
222*853458f3SDavid du Colombier 	p = (uchar *)(h + 1);
223*853458f3SDavid du Colombier 	if(p < m->ps){
224*853458f3SDavid du Colombier 		m->p = seprint(m->p, m->e, " opts=(");
225*853458f3SDavid du Colombier 		while(p < m->ps)
226*853458f3SDavid du Colombier 			m->p = seprint(m->p, m->e, "%.2ux", *p++);
227*853458f3SDavid du Colombier 		m->p = seprint(m->p, m->e, ")");
228*853458f3SDavid du Colombier 	}
229*853458f3SDavid du Colombier 
2309a747e4fSDavid du Colombier 	return 0;
2319a747e4fSDavid du Colombier }
2329a747e4fSDavid du Colombier 
2339a747e4fSDavid du Colombier Proto ip =
2349a747e4fSDavid du Colombier {
2359a747e4fSDavid du Colombier 	"ip",
2369a747e4fSDavid du Colombier 	p_compile,
2379a747e4fSDavid du Colombier 	p_filter,
2389a747e4fSDavid du Colombier 	p_seprint,
2399a747e4fSDavid du Colombier 	p_mux,
240ed397113SDavid du Colombier 	"%lud",
2419a747e4fSDavid du Colombier 	p_fields,
2423ff48bf5SDavid du Colombier 	defaultframer,
2439a747e4fSDavid du Colombier };
244