xref: /plan9/sys/src/cmd/ip/snoopy/dhcp.c (revision b751ae26be1094fda8622607119a26860f1833ab)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6 
7 enum
8 {
9 	Maxoptlen=	312-4,
10 
11 	/* dhcp types */
12 	Discover=	1,
13 	Offer=		2,
14 	Request=	3,
15 	Decline=	4,
16 	Ack=		5,
17 	Nak=		6,
18 	Release=	7,
19 	Inform=		8,
20 
21 	/* bootp option types */
22 	OBend=			255,
23 	OBpad=			0,
24 	OBmask=			1,
25 	OBtimeoff=		2,
26 	OBrouter=		3,
27 	OBtimeserver=		4,
28 	OBnameserver=		5,
29 	OBdnserver=		6,
30 	OBlogserver=		7,
31 	OBcookieserver=		8,
32 	OBlprserver=		9,
33 	OBimpressserver=	10,
34 	OBrlserver=		11,
35 	OBhostname=		12,	/* 0xc0 */
36 	OBbflen=		13,
37 	OBdumpfile=		14,
38 	OBdomainname=		15,
39 	OBswapserver=		16,	/* 0x10 */
40 	OBrootpath=		17,
41 	OBextpath=		18,
42 	OBipforward=		19,
43 	OBnonlocal=		20,
44 	OBpolicyfilter=		21,
45 	OBmaxdatagram=		22,
46 	OBttl=			23,
47 	OBpathtimeout=		24,
48 	OBpathplateau=		25,
49 	OBmtu=			26,
50 	OBsubnetslocal=		27,
51 	OBbaddr=		28,
52 	OBdiscovermask=		29,
53 	OBsupplymask=		30,
54 	OBdiscoverrouter=	31,
55 	OBrsserver=		32,	/* 0x20 */
56 	OBstaticroutes=		33,
57 	OBtrailerencap=		34,
58 	OBarptimeout=		35,
59 	OBetherencap=		36,
60 	OBtcpttl=		37,
61 	OBtcpka=		38,
62 	OBtcpkag=		39,
63 	OBnisdomain=		40,
64 	OBniserver=		41,
65 	OBntpserver=		42,
66 	OBvendorinfo=		43,	/* 0x2b */
67 	OBnetbiosns=		44,
68 	OBnetbiosdds=		45,
69 	OBnetbiostype=		46,
70 	OBnetbiosscope=		47,
71 	OBxfontserver=		48,	/* 0x30 */
72 	OBxdispmanager=		49,
73 	OBnisplusdomain=	64,	/* 0x40 */
74 	OBnisplusserver=	65,
75 	OBhomeagent=		68,
76 	OBsmtpserver=		69,
77 	OBpop3server=		70,
78 	OBnntpserver=		71,
79 	OBwwwserver=		72,
80 	OBfingerserver=		73,
81 	OBircserver=		74,
82 	OBstserver=		75,
83 	OBstdaserver=		76,
84 
85 	/* dhcp options */
86 	ODipaddr=		50,	/* 0x32 */
87 	ODlease=		51,
88 	ODoverload=		52,
89 	ODtype=			53,	/* 0x35 */
90 	ODserverid=		54,	/* 0x36 */
91 	ODparams=		55,	/* 0x37 */
92 	ODmessage=		56,
93 	ODmaxmsg=		57,
94 	ODrenewaltime=		58,
95 	ODrebindingtime=	59,
96 	ODvendorclass=		60,
97 	ODclientid=		61,	/* 0x3d */
98 	ODtftpserver=		66,
99 	ODbootfile=		67,
100 
101 	/* plan9 vendor info options */
102 	OP9fsv4=		128,	/* plan9 file servers */
103 	OP9authv4=		129,	/* plan9 auth servers */
104 };
105 
106 /*
107  *  convert a byte array to hex
108  */
109 static char
hex(int x)110 hex(int x)
111 {
112 	if(x < 10)
113 		return x + '0';
114 	return x - 10 + 'a';
115 }
116 static char*
phex(char * p,char * e,char * tag,uchar * o,int n)117 phex(char *p, char *e, char *tag, uchar *o, int n)
118 {
119 	p = seprint(p, e, "%s=", tag);
120 
121 	for(; p+2 < e && n > 0; n--){
122 		*p++ = hex(*o >> 4);
123 		*p++ = hex(*o & 0xf);
124 		o++;
125 	}
126 	return p;
127 }
128 
129 static char*
pstring(char * p,char * e,char * tag,uchar * o,int n)130 pstring(char *p, char *e, char *tag, uchar *o, int n)
131 {
132 	char msg[256];
133 
134 	if(n > sizeof msg - 1)
135 		n = sizeof msg - 1;
136 	memmove(msg, o, n);
137 	msg[n] = 0;
138 	return seprint(p, e, "%s=%s", tag, msg);
139 }
140 
141 static char*
pint(char * p,char * e,char * tag,uchar * o,int n)142 pint(char *p, char *e, char *tag, uchar *o, int n)
143 {
144 	int x;
145 
146 	x = *(char*)o++;
147 	for(; n > 1; n--)
148 		x = x<<8 | *o++;
149 	return seprint(p, e, "%s=%d", tag, x);
150 }
151 
152 static char*
puint(char * p,char * e,char * tag,uchar * o,int n)153 puint(char *p, char *e, char *tag, uchar *o, int n)
154 {
155 	uint x;
156 
157 	x = *o++;
158 	for(; n > 1; n--)
159 		x = x<<8 | *o++;
160 	return seprint(p, e, "%s=%ud", tag, x);
161 }
162 
163 static char*
pserver(char * p,char * e,char * tag,uchar * o,int n)164 pserver(char *p, char *e, char *tag, uchar *o, int n)
165 {
166 	p = seprint(p, e, "%s=(", tag);
167 	while(n >= 4){
168 		p = seprint(p, e, " %V", o);
169 		n -= 4;
170 		o += 4;
171 	}
172 	p = seprint(p, e, ")");
173 	return p;
174 }
175 
176 static char *dhcptype[256] =
177 {
178 [Discover]	"Discover",
179 [Offer]		"Offer",
180 [Request]	"Request",
181 [Decline]	"Decline",
182 [Ack]		"Ack",
183 [Nak]		"Nak",
184 [Release]	"Release",
185 [Inform]	"Inform",
186 };
187 
188 
189 static char*
ptype(char * p,char * e,uchar val)190 ptype(char *p, char *e, uchar val)
191 {
192 	char *x;
193 
194 	x = dhcptype[val];
195 	if(x != nil)
196 		return seprint(p, e, "t=%s", x);
197 	else
198 		return seprint(p, e, "t=%d", val);
199 }
200 
201 static int
p_seprint(Msg * m)202 p_seprint(Msg *m)
203 {
204 	int i, n, code;
205 	uchar *o, *ps;
206 	char *p, *e;
207 	char msg[64];
208 
209 	/* no next proto */
210 	m->pr = nil;
211 
212 	p = m->p;
213 	e = m->e;
214 	ps = m->ps;
215 
216 	while(ps < m->pe){
217 		code = *ps++;
218 		if(code == 255)
219 			break;
220 		if(code == 0)
221 			continue;
222 
223 		/* ignore anything that's too long */
224 		n = *ps++;
225 		o = ps;
226 		ps += n;
227 		if(ps > m->pe)
228 			break;
229 
230 		switch(code){
231 		case ODipaddr:	/* requested ip address */
232 			p = pserver(p, e, "ipaddr", o, n);
233 			break;
234 		case ODlease:	/* requested lease time */
235 			p = pint(p, e, "lease", o, n);
236 			break;
237 		case ODtype:
238 			p = ptype(p, e, *o);
239 			break;
240 		case ODserverid:
241 			p = pserver(p, e, "serverid", o, n);
242 			break;
243 		case ODmessage:
244 			p = pstring(p, e, "message", o, n);
245 			break;
246 		case ODmaxmsg:
247 			p = puint(p, e, "maxmsg", o, n);
248 			break;
249 		case ODclientid:
250 			p = phex(p, e, "clientid", o, n);
251 			break;
252 		case ODparams:
253 			p = seprint(p, e, " requested=(");
254 			for(i = 0; i < n; i++){
255 				if(i != 0)
256 					p = seprint(p, e, " ");
257 				p = seprint(p, e, "%ud", o[i]);
258 			}
259 			p = seprint(p, e, ")");
260 			break;
261 		case ODvendorclass:
262 			p = pstring(p, e, "vendorclass", o, n);
263 			break;
264 		case OBmask:
265 			p = pserver(p, e, "mask", o, n);
266 			break;
267 		case OBtimeoff:
268 			p = pint(p, e, "timeoff", o, n);
269 			break;
270 		case OBrouter:
271 			p = pserver(p, e, "router", o, n);
272 			break;
273 		case OBtimeserver:
274 			p = pserver(p, e, "timesrv", o, n);
275 			break;
276 		case OBnameserver:
277 			p = pserver(p, e, "namesrv", o, n);
278 			break;
279 		case OBdnserver:
280 			p = pserver(p, e, "dnssrv", o, n);
281 			break;
282 		case OBlogserver:
283 			p = pserver(p, e, "logsrv", o, n);
284 			break;
285 		case OBcookieserver:
286 			p = pserver(p, e, "cookiesrv", o, n);
287 			break;
288 		case OBlprserver:
289 			p = pserver(p, e, "lprsrv", o, n);
290 			break;
291 		case OBimpressserver:
292 			p = pserver(p, e, "impresssrv", o, n);
293 			break;
294 		case OBrlserver:
295 			p = pserver(p, e, "rlsrv", o, n);
296 			break;
297 		case OBhostname:
298 			p = pstring(p, e, "hostname", o, n);
299 			break;
300 		case OBbflen:
301 			break;
302 		case OBdumpfile:
303 			p = pstring(p, e, "dumpfile", o, n);
304 			break;
305 		case OBdomainname:
306 			p = pstring(p, e, "domname", o, n);
307 			break;
308 		case OBswapserver:
309 			p = pserver(p, e, "swapsrv", o, n);
310 			break;
311 		case OBrootpath:
312 			p = pstring(p, e, "rootpath", o, n);
313 			break;
314 		case OBextpath:
315 			p = pstring(p, e, "extpath", o, n);
316 			break;
317 		case OBipforward:
318 			p = phex(p, e, "ipforward", o, n);
319 			break;
320 		case OBnonlocal:
321 			p = phex(p, e, "nonlocal", o, n);
322 			break;
323 		case OBpolicyfilter:
324 			p = phex(p, e, "policyfilter", o, n);
325 			break;
326 		case OBmaxdatagram:
327 			p = phex(p, e, "maxdatagram", o, n);
328 			break;
329 		case OBttl:
330 			p = puint(p, e, "ttl", o, n);
331 			break;
332 		case OBpathtimeout:
333 			p = puint(p, e, "pathtimeout", o, n);
334 			break;
335 		case OBpathplateau:
336 			p = phex(p, e, "pathplateau", o, n);
337 			break;
338 		case OBmtu:
339 			p = puint(p, e, "mtu", o, n);
340 			break;
341 		case OBsubnetslocal:
342 			p = pserver(p, e, "subnet", o, n);
343 			break;
344 		case OBbaddr:
345 			p = pserver(p, e, "baddr", o, n);
346 			break;
347 		case OBdiscovermask:
348 			p = pserver(p, e, "discovermsak", o, n);
349 			break;
350 		case OBsupplymask:
351 			p = pserver(p, e, "rousupplymaskter", o, n);
352 			break;
353 		case OBdiscoverrouter:
354 			p = pserver(p, e, "discoverrouter", o, n);
355 			break;
356 		case OBrsserver:
357 			p = pserver(p, e, "rsrouter", o, n);
358 			break;
359 		case OBstaticroutes:
360 			p = phex(p, e, "staticroutes", o, n);
361 			break;
362 		case OBtrailerencap:
363 			p = phex(p, e, "trailerencap", o, n);
364 			break;
365 		case OBarptimeout:
366 			p = puint(p, e, "arptimeout", o, n);
367 			break;
368 		case OBetherencap:
369 			p = phex(p, e, "etherencap", o, n);
370 			break;
371 		case OBtcpttl:
372 			p = puint(p, e, "tcpttl", o, n);
373 			break;
374 		case OBtcpka:
375 			p = puint(p, e, "tcpka", o, n);
376 			break;
377 		case OBtcpkag:
378 			p = phex(p, e, "tcpkag", o, n);
379 			break;
380 		case OBnisdomain:
381 			p = pstring(p, e, "nisdomain", o, n);
382 			break;
383 		case OBniserver:
384 			p = pserver(p, e, "nisrv", o, n);
385 			break;
386 		case OBntpserver:
387 			p = pserver(p, e, "ntpsrv", o, n);
388 			break;
389 		case OBvendorinfo:
390 			p = phex(p, e, "vendorinfo", o, n);
391 			break;
392 		case OBnetbiosns:
393 			p = pserver(p, e, "biosns", o, n);
394 			break;
395 		case OBnetbiosdds:
396 			p = phex(p, e, "biosdds", o, n);
397 			break;
398 		case OBnetbiostype:
399 			p = phex(p, e, "biostype", o, n);
400 			break;
401 		case OBnetbiosscope:
402 			p = phex(p, e, "biosscope", o, n);
403 			break;
404 		case OBxfontserver:
405 			p = pserver(p, e, "fontsrv", o, n);
406 			break;
407 		case OBxdispmanager:
408 			p = pserver(p, e, "xdispmgr", o, n);
409 			break;
410 		case OBnisplusdomain:
411 			p = pstring(p, e, "nisplusdomain", o, n);
412 			break;
413 		case OBnisplusserver:
414 			p = pserver(p, e, "nisplussrv", o, n);
415 			break;
416 		case OBhomeagent:
417 			p = pserver(p, e, "homeagent", o, n);
418 			break;
419 		case OBsmtpserver:
420 			p = pserver(p, e, "smtpsrv", o, n);
421 			break;
422 		case OBpop3server:
423 			p = pserver(p, e, "pop3srv", o, n);
424 			break;
425 		case OBnntpserver:
426 			p = pserver(p, e, "ntpsrv", o, n);
427 			break;
428 		case OBwwwserver:
429 			p = pserver(p, e, "wwwsrv", o, n);
430 			break;
431 		case OBfingerserver:
432 			p = pserver(p, e, "fingersrv", o, n);
433 			break;
434 		case OBircserver:
435 			p = pserver(p, e, "ircsrv", o, n);
436 			break;
437 		case OBstserver:
438 			p = pserver(p, e, "stsrv", o, n);
439 			break;
440 		case OBstdaserver:
441 			p = pserver(p, e, "stdasrv", o, n);
442 			break;
443 		case OBend:
444 			goto out;
445 		default:
446 			snprint(msg, sizeof msg, " T%ud", code);
447 			p = phex(p, e, msg, o, n);
448 			break;
449 		}
450 		if(*ps != OBend)
451 			p = seprint(p, e, " ");
452 	}
453 out:
454 	m->p = p;
455 	m->ps = ps;
456 	return 0;
457 }
458 
459 Proto dhcp =
460 {
461 	"dhcp",
462 	nil,
463 	nil,
464 	p_seprint,
465 	nil,
466 	nil,
467 	nil,
468 	defaultframer,
469 };
470