xref: /plan9-contrib/sys/src/cmd/ip/snoopy/ip6.c (revision e6dcbf51e935975016093545b6eab69976b6e257)
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	vcf[4];			/* Version and header length */
119a747e4fSDavid du Colombier 	uchar	length[2];		/* packet length */
129a747e4fSDavid du Colombier 	uchar	proto;			/* Protocol */
139a747e4fSDavid du Colombier 	uchar	ttl;			/* Time to live */
149a747e4fSDavid du Colombier 	uchar	src[IPaddrlen];		/* IP source */
159a747e4fSDavid du Colombier 	uchar	dst[IPaddrlen];		/* IP destination */
169a747e4fSDavid du Colombier };
179a747e4fSDavid du Colombier 
189a747e4fSDavid du Colombier enum
199a747e4fSDavid du Colombier {
209a747e4fSDavid du Colombier 	IP6HDR		= 40,		/* sizeof(Iphdr) */
219a747e4fSDavid du Colombier 	IP_VER		= 0x60,		/* Using IP version 4 */
229a747e4fSDavid du Colombier 	HBH_HDR		= 0,
239a747e4fSDavid du Colombier 	ROUT_HDR	= 43,
249a747e4fSDavid du Colombier 	FRAG_HDR	= 44,
259a747e4fSDavid du Colombier 	FRAG_HSZ	= 8, 		/* in bytes */
269a747e4fSDavid du Colombier 	DEST_HDR	= 60,
279a747e4fSDavid du Colombier };
289a747e4fSDavid du Colombier 
299a747e4fSDavid du Colombier static Mux p_mux[] =
309a747e4fSDavid du Colombier {
319a747e4fSDavid du Colombier 	{ "igmp", 2, },
329a747e4fSDavid du Colombier 	{ "ggp", 3, },
339a747e4fSDavid du Colombier 	{ "ip", 4, },
349a747e4fSDavid du Colombier 	{ "st", 5, },
359a747e4fSDavid du Colombier 	{ "tcp", 6, },
369a747e4fSDavid du Colombier 	{ "ucl", 7, },
379a747e4fSDavid du Colombier 	{ "egp", 8, },
389a747e4fSDavid du Colombier 	{ "igp", 9, },
399a747e4fSDavid du Colombier 	{ "bbn-rcc-mon", 10, },
409a747e4fSDavid du Colombier 	{ "nvp-ii", 11, },
419a747e4fSDavid du Colombier 	{ "pup", 12, },
429a747e4fSDavid du Colombier 	{ "argus", 13, },
439a747e4fSDavid du Colombier 	{ "emcon", 14, },
449a747e4fSDavid du Colombier 	{ "xnet", 15, },
459a747e4fSDavid du Colombier 	{ "chaos", 16, },
469a747e4fSDavid du Colombier 	{ "udp", 17, },
479a747e4fSDavid du Colombier 	{ "mux", 18, },
489a747e4fSDavid du Colombier 	{ "dcn-meas", 19, },
499a747e4fSDavid du Colombier 	{ "hmp", 20, },
509a747e4fSDavid du Colombier 	{ "prm", 21, },
519a747e4fSDavid du Colombier 	{ "xns-idp", 22, },
529a747e4fSDavid du Colombier 	{ "trunk-1", 23, },
539a747e4fSDavid du Colombier 	{ "trunk-2", 24, },
549a747e4fSDavid du Colombier 	{ "leaf-1", 25, },
559a747e4fSDavid du Colombier 	{ "leaf-2", 26, },
569a747e4fSDavid du Colombier 	{ "rdp", 27, },
579a747e4fSDavid du Colombier 	{ "irtp", 28, },
589a747e4fSDavid du Colombier 	{ "iso-tp4", 29, },
599a747e4fSDavid du Colombier 	{ "netblt", 30, },
609a747e4fSDavid du Colombier 	{ "mfe-nsp", 31, },
619a747e4fSDavid du Colombier 	{ "merit-inp", 32, },
629a747e4fSDavid du Colombier 	{ "sep", 33, },
639a747e4fSDavid du Colombier 	{ "3pc", 34, },
649a747e4fSDavid du Colombier 	{ "idpr", 35, },
659a747e4fSDavid du Colombier 	{ "xtp", 36, },
669a747e4fSDavid du Colombier 	{ "ddp", 37, },
679a747e4fSDavid du Colombier 	{ "idpr-cmtp", 38, },
689a747e4fSDavid du Colombier 	{ "tp++", 39, },
699a747e4fSDavid du Colombier 	{ "il", 40, },
709a747e4fSDavid du Colombier 	{ "sip", 41, },
719a747e4fSDavid du Colombier 	{ "sdrp", 42, },
729a747e4fSDavid du Colombier 	{ "idrp", 45, },
739a747e4fSDavid du Colombier 	{ "rsvp", 46, },
749a747e4fSDavid du Colombier 	{ "gre", 47, },
759a747e4fSDavid du Colombier 	{ "mhrp", 48, },
769a747e4fSDavid du Colombier 	{ "bna", 49, },
779a747e4fSDavid du Colombier 	{ "sipp-esp", 50, },
789a747e4fSDavid du Colombier 	{ "sipp-ah", 51, },
799a747e4fSDavid du Colombier 	{ "i-nlsp", 52, },
809a747e4fSDavid du Colombier 	{ "swipe", 53, },
819a747e4fSDavid du Colombier 	{ "nhrp", 54, },
829a747e4fSDavid du Colombier 	{ "icmp6", 58, },
839a747e4fSDavid du Colombier 	{ "any", 61, },
849a747e4fSDavid du Colombier 	{ "cftp", 62, },
859a747e4fSDavid du Colombier 	{ "any", 63, },
869a747e4fSDavid du Colombier 	{ "sat-expak", 64, },
879a747e4fSDavid du Colombier 	{ "kryptolan", 65, },
889a747e4fSDavid du Colombier 	{ "rvd", 66, },
899a747e4fSDavid du Colombier 	{ "ippc", 67, },
909a747e4fSDavid du Colombier 	{ "any", 68, },
919a747e4fSDavid du Colombier 	{ "sat-mon", 69, },
929a747e4fSDavid du Colombier 	{ "visa", 70, },
939a747e4fSDavid du Colombier 	{ "ipcv", 71, },
949a747e4fSDavid du Colombier 	{ "cpnx", 72, },
959a747e4fSDavid du Colombier 	{ "cphb", 73, },
969a747e4fSDavid du Colombier 	{ "wsn", 74, },
979a747e4fSDavid du Colombier 	{ "pvp", 75, },
989a747e4fSDavid du Colombier 	{ "br-sat-mon", 76, },
999a747e4fSDavid du Colombier 	{ "sun-nd", 77, },
1009a747e4fSDavid du Colombier 	{ "wb-mon", 78, },
1019a747e4fSDavid du Colombier 	{ "wb-expak", 79, },
1029a747e4fSDavid du Colombier 	{ "iso-ip", 80, },
1039a747e4fSDavid du Colombier 	{ "vmtp", 81, },
1049a747e4fSDavid du Colombier 	{ "secure-vmtp", 82, },
1059a747e4fSDavid du Colombier 	{ "vines", 83, },
1069a747e4fSDavid du Colombier 	{ "ttp", 84, },
1079a747e4fSDavid du Colombier 	{ "nsfnet-igp", 85, },
1089a747e4fSDavid du Colombier 	{ "dgp", 86, },
1099a747e4fSDavid du Colombier 	{ "tcf", 87, },
1109a747e4fSDavid du Colombier 	{ "igrp", 88, },
1119a747e4fSDavid du Colombier 	{ "ospf", 89, },
1129a747e4fSDavid du Colombier 	{ "sprite-rpc", 90, },
1139a747e4fSDavid du Colombier 	{ "larp", 91, },
1149a747e4fSDavid du Colombier 	{ "mtp", 92, },
1159a747e4fSDavid du Colombier 	{ "ax.25", 93, },
1169a747e4fSDavid du Colombier 	{ "ipip", 94, },
1179a747e4fSDavid du Colombier 	{ "micp", 95, },
1189a747e4fSDavid du Colombier 	{ "scc-sp", 96, },
1199a747e4fSDavid du Colombier 	{ "etherip", 97, },
1209a747e4fSDavid du Colombier 	{ "encap", 98, },
1219a747e4fSDavid du Colombier 	{ "any", 99, },
1229a747e4fSDavid du Colombier 	{ "gmtp", 100, },
1239a747e4fSDavid du Colombier 	{ "rudp", 254, },
1249a747e4fSDavid du Colombier 	{ 0 }
1259a747e4fSDavid du Colombier };
1269a747e4fSDavid du Colombier 
1279a747e4fSDavid du Colombier enum
1289a747e4fSDavid du Colombier {
129*e6dcbf51SDavid du Colombier 	Os,	/* source */
130*e6dcbf51SDavid du Colombier 	Od,	/* destination */
131*e6dcbf51SDavid du Colombier 	Osd,	/* source or destination */
132*e6dcbf51SDavid du Colombier 	Ot,	/* type */
1339a747e4fSDavid du Colombier };
1349a747e4fSDavid du Colombier 
1359a747e4fSDavid du Colombier static Field p_fields[] =
1369a747e4fSDavid du Colombier {
1379a747e4fSDavid du Colombier 	{"s",	Fv6ip,	Os,	"source address",	} ,
1389a747e4fSDavid du Colombier 	{"d",	Fv6ip,	Od,	"destination address",	} ,
1399a747e4fSDavid du Colombier 	{"a",	Fv6ip,	Osd,	"source|destination address",} ,
1409a747e4fSDavid du Colombier 	{"t",	Fnum,	Ot,	"sub protocol number",	} ,
1419a747e4fSDavid du Colombier 	{0}
1429a747e4fSDavid du Colombier };
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier static void
p_compile(Filter * f)1459a747e4fSDavid du Colombier p_compile(Filter *f)
1469a747e4fSDavid du Colombier {
1479a747e4fSDavid du Colombier 	Mux *m;
1489a747e4fSDavid du Colombier 
1499a747e4fSDavid du Colombier 	if(f->op == '='){
1509a747e4fSDavid du Colombier 		compile_cmp(ip6.name, f, p_fields);
1519a747e4fSDavid du Colombier 		return;
1529a747e4fSDavid du Colombier 	}
1539a747e4fSDavid du Colombier 	for(m = p_mux; m->name != nil; m++)
1549a747e4fSDavid du Colombier 		if(strcmp(f->s, m->name) == 0){
1559a747e4fSDavid du Colombier 			f->pr = m->pr;
1569a747e4fSDavid du Colombier 			f->ulv = m->val;
1579a747e4fSDavid du Colombier 			f->subop = Ot;
1589a747e4fSDavid du Colombier 			return;
1599a747e4fSDavid du Colombier 		}
1609a747e4fSDavid du Colombier 	sysfatal("unknown ip6 field or protocol: %s", f->s);
1619a747e4fSDavid du Colombier }
1629a747e4fSDavid du Colombier 
1639a747e4fSDavid du Colombier static int
v6hdrlen(Hdr * h)1649a747e4fSDavid du Colombier v6hdrlen(Hdr *h)
1659a747e4fSDavid du Colombier {
1669a747e4fSDavid du Colombier 	int plen, len = IP6HDR;
1679a747e4fSDavid du Colombier 	int pktlen = IP6HDR + NetS(h->length);
1689a747e4fSDavid du Colombier 	uchar nexthdr = h->proto;
1699a747e4fSDavid du Colombier 	uchar *pkt = (uchar*) h;
1709a747e4fSDavid du Colombier 
1719a747e4fSDavid du Colombier 	pkt += len;
1729a747e4fSDavid du Colombier 	plen = len;
1739a747e4fSDavid du Colombier 
174*e6dcbf51SDavid du Colombier 	while (nexthdr == HBH_HDR || nexthdr == ROUT_HDR ||
175*e6dcbf51SDavid du Colombier 	    nexthdr == FRAG_HDR || nexthdr == DEST_HDR) {
1769a747e4fSDavid du Colombier 		if (nexthdr == FRAG_HDR)
1779a747e4fSDavid du Colombier 			len = FRAG_HSZ;
1789a747e4fSDavid du Colombier 		else
179*e6dcbf51SDavid du Colombier 			len = ((int)*(pkt+1) + 1) * 8;
1809a747e4fSDavid du Colombier 
1819a747e4fSDavid du Colombier 		if (plen + len > pktlen)
1829a747e4fSDavid du Colombier 			return -1;
1839a747e4fSDavid du Colombier 
1849a747e4fSDavid du Colombier 		pkt += len;
1859a747e4fSDavid du Colombier 		nexthdr = *pkt;
1869a747e4fSDavid du Colombier 		plen += len;
1879a747e4fSDavid du Colombier 	}
1889a747e4fSDavid du Colombier 	return plen;
1899a747e4fSDavid du Colombier }
1909a747e4fSDavid du Colombier 
1919a747e4fSDavid du Colombier static int
p_filter(Filter * f,Msg * m)1929a747e4fSDavid du Colombier p_filter(Filter *f, Msg *m)
1939a747e4fSDavid du Colombier {
1949a747e4fSDavid du Colombier 	Hdr *h;
1959a747e4fSDavid du Colombier 	int hlen;
1969a747e4fSDavid du Colombier 
1979a747e4fSDavid du Colombier 	if(m->pe - m->ps < IP6HDR)
1989a747e4fSDavid du Colombier 		return 0;
1999a747e4fSDavid du Colombier 
2009a747e4fSDavid du Colombier 	h = (Hdr*)m->ps;
2019a747e4fSDavid du Colombier 
2029a747e4fSDavid du Colombier 	if ((hlen = v6hdrlen(h)) < 0)
2039a747e4fSDavid du Colombier 		return 0;
2049a747e4fSDavid du Colombier 	else
2059a747e4fSDavid du Colombier 		m->ps += hlen;
2069a747e4fSDavid du Colombier 	switch(f->subop){
2079a747e4fSDavid du Colombier 	case Os:
208*e6dcbf51SDavid du Colombier 		return memcmp(h->src, f->a, IPaddrlen) == 0;
2099a747e4fSDavid du Colombier 	case Od:
210*e6dcbf51SDavid du Colombier 		return memcmp(h->dst, f->a, IPaddrlen) == 0;
2119a747e4fSDavid du Colombier 	case Osd:
212*e6dcbf51SDavid du Colombier 		return memcmp(h->src, f->a, IPaddrlen) == 0 ||
213*e6dcbf51SDavid du Colombier 			memcmp(h->dst, f->a, IPaddrlen) == 0;
2149a747e4fSDavid du Colombier 	case Ot:
2159a747e4fSDavid du Colombier 		return h->proto == f->ulv;
2169a747e4fSDavid du Colombier 	}
2179a747e4fSDavid du Colombier 	return 0;
2189a747e4fSDavid du Colombier }
2199a747e4fSDavid du Colombier 
2209a747e4fSDavid du Colombier static int
v6hdr_seprint(Msg * m)2219a747e4fSDavid du Colombier v6hdr_seprint(Msg *m)
2229a747e4fSDavid du Colombier {
223*e6dcbf51SDavid du Colombier 	int plen, len = IP6HDR;
2249a747e4fSDavid du Colombier 	uchar *pkt = m->ps;
2259a747e4fSDavid du Colombier 	Hdr *h = (Hdr *)pkt;
2269a747e4fSDavid du Colombier 	int pktlen = IP6HDR + NetS(h->length);
2279a747e4fSDavid du Colombier 	uchar nexthdr = h->proto;
2289a747e4fSDavid du Colombier 
2299a747e4fSDavid du Colombier 	pkt += len;
2309a747e4fSDavid du Colombier 	plen = len;
2319a747e4fSDavid du Colombier 
232*e6dcbf51SDavid du Colombier 	while (nexthdr == HBH_HDR || nexthdr == ROUT_HDR ||
233*e6dcbf51SDavid du Colombier 	    nexthdr == FRAG_HDR || nexthdr == DEST_HDR) {
2349a747e4fSDavid du Colombier 		switch (nexthdr) {
2359a747e4fSDavid du Colombier 		case FRAG_HDR:
236*e6dcbf51SDavid du Colombier 			m->p = seprint(m->p, m->e, "\n	  xthdr=frag id=%d "
237*e6dcbf51SDavid du Colombier 				"offset=%d pr=%d more=%d res1=%d res2=%d",
238*e6dcbf51SDavid du Colombier 				NetL(pkt+4), NetS(pkt+2) & ~7, (int)*pkt,
239*e6dcbf51SDavid du Colombier 				(int)(*(pkt+3) & 0x1), (int)*(pkt+1),
240*e6dcbf51SDavid du Colombier 				(int)(*(pkt+3) & 0x6));
2419a747e4fSDavid du Colombier 			len = FRAG_HSZ;
2429a747e4fSDavid du Colombier 			break;
2439a747e4fSDavid du Colombier 
2449a747e4fSDavid du Colombier 		case HBH_HDR:
2459a747e4fSDavid du Colombier 		case ROUT_HDR:
2469a747e4fSDavid du Colombier 		case DEST_HDR:
247*e6dcbf51SDavid du Colombier 			len = ((int)*(pkt+1) + 1) * 8;
2489a747e4fSDavid du Colombier 			break;
2499a747e4fSDavid du Colombier 		}
2509a747e4fSDavid du Colombier 
2519a747e4fSDavid du Colombier 		if (plen + len > pktlen) {
2529a747e4fSDavid du Colombier 			m->p = seprint(m->p, m->e, "bad pkt");
2539a747e4fSDavid du Colombier 			m->pr = &dump;
2549a747e4fSDavid du Colombier 			return -1;
2559a747e4fSDavid du Colombier 		}
2569a747e4fSDavid du Colombier 		plen += len;
2579a747e4fSDavid du Colombier 		pkt += len;
2589a747e4fSDavid du Colombier 		nexthdr = *pkt;
2599a747e4fSDavid du Colombier 	}
2609a747e4fSDavid du Colombier 
2619a747e4fSDavid du Colombier 	m->ps = pkt;
2629a747e4fSDavid du Colombier 	return 1;
2639a747e4fSDavid du Colombier }
2649a747e4fSDavid du Colombier 
2659a747e4fSDavid du Colombier static int
p_seprint(Msg * m)2669a747e4fSDavid du Colombier p_seprint(Msg *m)
2679a747e4fSDavid du Colombier {
2689a747e4fSDavid du Colombier 	int len;
269*e6dcbf51SDavid du Colombier 	Hdr *h;
2709a747e4fSDavid du Colombier 
2719a747e4fSDavid du Colombier 	if(m->pe - m->ps < IP6HDR)
2729a747e4fSDavid du Colombier 		return -1;
2739a747e4fSDavid du Colombier 	h = (Hdr*)m->ps;
2749a747e4fSDavid du Colombier 
2759a747e4fSDavid du Colombier 	demux(p_mux, h->proto, h->proto, m, &dump);
2769a747e4fSDavid du Colombier 
2779a747e4fSDavid du Colombier 	/* truncate the message if there's extra */
2789a747e4fSDavid du Colombier 	len = NetS(h->length) + IP6HDR;
2799a747e4fSDavid du Colombier 	if(len < m->pe - m->ps)
2809a747e4fSDavid du Colombier 		m->pe = m->ps + len;
2819a747e4fSDavid du Colombier 
2829a747e4fSDavid du Colombier 	m->p = seprint(m->p, m->e, "s=%I d=%I ttl=%3d pr=%d ln=%d",
283*e6dcbf51SDavid du Colombier 		h->src, h->dst, h->ttl, h->proto, NetS(h->length));
2849a747e4fSDavid du Colombier 	v6hdr_seprint(m);
2859a747e4fSDavid du Colombier 	return 0;
2869a747e4fSDavid du Colombier }
2879a747e4fSDavid du Colombier 
2889a747e4fSDavid du Colombier Proto ip6 =
2899a747e4fSDavid du Colombier {
2909a747e4fSDavid du Colombier 	"ip6",
2919a747e4fSDavid du Colombier 	p_compile,
2929a747e4fSDavid du Colombier 	p_filter,
2939a747e4fSDavid du Colombier 	p_seprint,
2949a747e4fSDavid du Colombier 	p_mux,
295ed397113SDavid du Colombier 	"%lud",
2969a747e4fSDavid du Colombier 	p_fields,
2973ff48bf5SDavid du Colombier 	defaultframer,
2989a747e4fSDavid du Colombier };
299