xref: /plan9/sys/src/cmd/ip/snoopy/gre.c (revision 0b9a5132554aff81f12a30adb0ffd48684252652)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6 
7 /*
8  GRE version 0 is specified in rfc1701.
9  GRE version 0 has been respecified in rfc2784 as a subset of rfc1701.
10  GRE version 1, as used by pptp, has been specified in rfc2637.
11 */
12 
13 
14 /* GRE flag bits */
15 enum {
16 	GRE_chksum	= (1<<15),
17 	GRE_routing	= (1<<14),
18 	GRE_key		= (1<<13),
19 	GRE_seq		= (1<<12),
20 	GRE_srcrt		= (1<<11),
21 	GRE_recur	= (7<<8),
22 	GRE_ack		= (1<<7),
23 	GRE_version	= 0x7,
24 };
25 
26 
27 typedef struct Hdr	Hdr;
28 struct Hdr
29 {
30 	ushort flags;
31 	ushort proto;
32 	uchar version;
33 	ushort chksum;
34 	ushort offset;
35 	ulong key;
36 	ulong seq;
37 	ulong route;
38 	ulong ack;
39 };
40 
41 enum
42 {
43 	Oproto,
44 };
45 
46 static Field p_fields[] =
47 {
48 	{"proto",		Fnum,	Oproto,	"encapsulated protocol",	} ,
49 	{0}
50 };
51 
52 static Mux p_mux[] =
53 {
54 	{"pup",	0x0200, },
55 	{"xns",	0x0600, },
56 	{"ip",		0x0800, },
57 	{"chaos",	0x0804, },
58 	{"arp",	0x0806, },
59 	{"frarp",	0x0808, },
60 	{"vines",	0x0bad, },
61 	{"vinesecho",	0x0bae, },
62 	{"vinesloop",	0x0baf, },
63 	{"ppp",	0x880b, },
64 	{"llc",	0x007a, },
65 	{"dot1q",	0x8100, },
66 	{"eapol",	0x888e, },
67 	{0},
68 };
69 
70 int
parthdrlen(ushort flags)71 parthdrlen(ushort flags)
72 {
73 	return 4 +
74 		(flags&GRE_chksum || flags&GRE_routing) ? 4 : 0 +
75 		flags&GRE_key ? 4 : 0 +
76 		flags&GRE_seq ? 4 : 0 +
77 		flags&GRE_ack ? 4 : 0;
78 }
79 
80 int
parsehdr(Hdr * h,uchar * s,uchar * e)81 parsehdr(Hdr *h, uchar *s, uchar *e)
82 {
83 	uchar *p;
84 	uchar n;
85 
86 	if(e - s < 4)
87 		return -1;
88 
89 	p = s;
90 
91 	h->flags = NetS(p);
92 	p += 2;
93 	h->proto = NetS(p);
94 	p += 2;
95 	h->version = h->flags&GRE_version;
96 
97 	if(parthdrlen(h->flags) > e - s)
98 		return -1;
99 
100 	if(h->flags&(GRE_chksum|GRE_routing)){
101 		h->chksum = NetS(p);
102 		p += 2;
103 		h->offset = NetS(p);
104 		p += 2;
105 	}
106 	if(h->flags&GRE_key){
107 		h->key = NetL(p);
108 		p += 4;
109 	}
110 	if(h->flags&GRE_seq){
111 		h->seq = NetL(p);
112 		p += 4;
113 	}
114 	if(h->flags&GRE_ack){
115 		h->ack = NetL(p);
116 		p += 4;
117 	}
118 	if(h->flags&GRE_routing){
119 		for(;;){
120 			if(e - p < 4)
121 				return -1;
122 			if((n = p[3]) == 0)
123 				break;
124 			p += n;
125 		}
126 	}
127 
128 	return p - s;
129 }
130 
131 static void
p_compile(Filter * f)132 p_compile(Filter *f)
133 {
134 	Mux *m;
135 
136 	if(f->op == '='){
137 		compile_cmp(gre.name, f, p_fields);
138 		return;
139 	}
140 	for(m = p_mux; m->name != nil; m++)
141 		if(strcmp(f->s, m->name) == 0){
142 			f->pr = m->pr;
143 			f->ulv = m->val;
144 			f->subop = Oproto;
145 			return;
146 		}
147 	sysfatal("unknown gre field or protocol: %s", f->s);
148 }
149 
150 static int
p_filter(Filter * f,Msg * m)151 p_filter(Filter *f, Msg *m)
152 {
153 	Hdr h;
154 	int len;
155 
156 	len = parsehdr(&h, m->ps, m->pe);
157 	if(len < 0)
158 		return -1;
159 	m->ps += len;
160 
161 	switch(f->subop){
162 	case Oproto:
163 		return h.proto == f->ulv;
164 	}
165 	return 0;
166 }
167 
168 static int
p_seprint(Msg * m)169 p_seprint(Msg *m)
170 {
171 	Hdr h;
172 	int len;
173 
174 	len = parsehdr(&h, m->ps, m->pe);
175 	if(len < 0)
176 		return -1;
177 	m->ps += len;
178 
179 	demux(p_mux, h.proto, h.proto, m, &dump);
180 
181 	m->p = seprint(m->p, m->e, "version=%d proto=%#ux flags=%#.4ux", h.version, h.proto, h.flags);
182 	if(h.flags&GRE_chksum)
183 		m->p = seprint(m->p, m->e, " checksum=%#.4ux", h.chksum);
184 	if(h.flags&GRE_key)
185 		m->p = seprint(m->p, m->e, " key=%#.8ulx", h.key);
186 	if(h.flags&GRE_seq)
187 		m->p = seprint(m->p, m->e, " seq=%#.8ulx", h.seq);
188 	if(h.flags&GRE_ack)
189 		m->p = seprint(m->p, m->e, " ack=%#.8ulx", h.ack);
190 	if(h.flags&GRE_routing)
191 		m->p = seprint(m->p, m->e, " offset=%#ux haverouting", h.offset);
192 	if(h.version == 0)
193 		m->p = seprint(m->p, m->e, " recursion=%ud", (h.flags&GRE_recur)>>8);
194 
195 	return 0;
196 }
197 
198 Proto gre =
199 {
200 	"gre",
201 	p_compile,
202 	p_filter,
203 	p_seprint,
204 	p_mux,
205 	"%#.4ux",
206 	p_fields,
207 	defaultframer,
208 };
209