1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <libsec.h>
5 #include "dat.h"
6 #include "protos.h"
7 
8 /* PPP stuff */
9 enum {
10 	PPP_addr=	0xff,
11 	PPP_ctl=	0x3,
12 	PPP_period=	3*1000,	/* period of retransmit process (in ms) */
13 };
14 
15 /* PPP protocols */
16 enum {
17 	PPP_ip=		0x21,		/* internet */
18 	PPP_vjctcp=	0x2d,		/* compressing van jacobson tcp */
19 	PPP_vjutcp=	0x2f,		/* uncompressing van jacobson tcp */
20 	PPP_ml=		0x3d,		/* multi link */
21 	PPP_comp=	0xfd,		/* compressed packets */
22 	PPP_ipcp=	0x8021,		/* ip control */
23 	PPP_ccp=	0x80fd,		/* compression control */
24 	PPP_passwd=	0xc023,		/* passwd authentication */
25 	PPP_lcp=	0xc021,		/* link control */
26 	PPP_lqm=	0xc025,		/* link quality monitoring */
27 	PPP_chap=	0xc223,		/* challenge/response */
28 };
29 
30 /* LCP protocol (and IPCP) */
31 
32 
33 typedef struct Lcppkt	Lcppkt;
34 struct Lcppkt
35 {
36 	uchar	code;
37 	uchar	id;
38 	uchar	len[2];
39 	uchar	data[1];
40 };
41 
42 typedef struct Lcpopt	Lcpopt;
43 struct Lcpopt
44 {
45 	uchar	type;
46 	uchar	len;
47 	uchar	data[1];
48 };
49 
50 enum
51 {
52 	/* LCP codes */
53 	Lconfreq=	1,
54 	Lconfack=	2,
55 	Lconfnak=	3,
56 	Lconfrej=	4,
57 	Ltermreq=	5,
58 	Ltermack=	6,
59 	Lcoderej=	7,
60 	Lprotorej=	8,
61 	Lechoreq=	9,
62 	Lechoack=	10,
63 	Ldiscard=	11,
64 	Lresetreq=	14,	/* for ccp only */
65 	Lresetack=	15,	/* for ccp only */
66 
67 	/* Lcp configure options */
68 	Omtu=		1,
69 	Octlmap=	2,
70 	Oauth=		3,
71 	Oquality=	4,
72 	Omagic=		5,
73 	Opc=		7,
74 	Oac=		8,
75 
76 	/* authentication protocols */
77 	APmd5=		5,
78 	APmschap=	128,
79 
80 	/* Chap codes */
81 	Cchallenge=	1,
82 	Cresponse=	2,
83 	Csuccess=	3,
84 	Cfailure=	4,
85 
86 	/* ipcp configure options */
87 	Oipaddrs=	1,
88 	Oipcompress=	2,
89 	Oipaddr=	3,
90 	Oipdns=		129,
91 	Oipwins=	130,
92 	Oipdns2=	131,
93 	Oipwins2=	132
94 };
95 
96 char *
97 lcpcode[] = {
98 	0,
99 	"confreq",
100 	"confack",
101 	"confnak",
102 	"confrej",
103 	"termreq",
104 	"termack",
105 	"coderej",
106 	"protorej",
107 	"echoreq",
108 	"echoack",
109 	"discard",
110 	"id",
111 	"timeremain",
112 	"resetreq",
113 	"resetack"
114 };
115 
116 static Mux p_mux[] =
117 {
118 	{"ip",		PPP_ip, },
119 	{"ppp_vjctcp",	PPP_vjctcp, },
120 	{"ppp_vjutcp",	PPP_vjutcp, },
121 	{"ppp_ml",	PPP_ml, },
122 	{"ppp_comp",	PPP_comp, },
123 	{"ppp_ipcp",	PPP_ipcp, },
124 	{"ppp_ccp",	PPP_ccp, },
125 	{"ppp_passwd",	PPP_passwd, },
126 	{"ppp_lcp",	PPP_lcp, },
127 	{"ppp_lqm",	PPP_lqm, },
128 	{"ppp_chap",	PPP_chap, },
129 	{0}
130 };
131 
132 enum
133 {
134 	OOproto
135 };
136 
137 static void
p_compile(Filter * f)138 p_compile(Filter *f)
139 {
140 	Mux *m;
141 
142 	for(m = p_mux; m->name != nil; m++)
143 		if(strcmp(f->s, m->name) == 0){
144 			f->pr = m->pr;
145 			f->ulv = m->val;
146 			f->subop = OOproto;
147 			return;
148 		}
149 
150 	sysfatal("unknown ppp field or protocol: %s", f->s);
151 }
152 
153 static int
p_filter(Filter * f,Msg * m)154 p_filter(Filter *f, Msg *m)
155 {
156 	int proto;
157 	int len;
158 
159 	if(f->subop != OOproto)
160 		return 0;
161 
162 	len = m->pe - m->ps;
163 	if(len < 3)
164 		return -1;
165 
166 	if(m->ps[0] == PPP_addr && m->ps[1] == PPP_ctl)
167 		m->ps += 2;
168 
169 	proto = *m->ps++;
170 	if((proto&1) == 0)
171 		proto = (proto<<8) | *m->ps++;
172 
173 	if(proto == f->ulv)
174 		return 1;
175 
176 	return 0;
177 }
178 
179 static int
p_seprint(Msg * m)180 p_seprint(Msg *m)
181 {
182 	int proto;
183 	int len;
184 
185 	len = m->pe - m->ps;
186 	if(len < 3)
187 		return -1;
188 
189 	if(m->ps[0] == PPP_addr && m->ps[1] == PPP_ctl)
190 		m->ps += 2;
191 
192 	proto = *m->ps++;
193 	if((proto&1) == 0)
194 		proto = (proto<<8) | *m->ps++;
195 
196 	m->p = seprint(m->p, m->e, "pr=%ud len=%d", proto, len);
197 	demux(p_mux, proto, proto, m, &dump);
198 
199 	return 0;
200 }
201 
202 static int
p_seprintchap(Msg * m)203 p_seprintchap(Msg *m)
204 {
205 	Lcppkt *lcp;
206 	char *p, *e;
207 	int len;
208 
209 	if(m->pe-m->ps < 4)
210 		return -1;
211 
212 	p = m->p;
213 	e = m->e;
214 	m->pr = nil;
215 
216 	/* resize packet */
217 	lcp = (Lcppkt*)m->ps;
218 	len = NetS(lcp->len);
219 	if(m->ps+len < m->pe)
220 		m->pe = m->ps+len;
221 	else if(m->ps+len > m->pe)
222 		return -1;
223 
224 	p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
225 	switch(lcp->code) {
226 	default:
227 		p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
228 		break;
229 	case 1:
230 	case 2:
231 		if(lcp->data[0] > len-4){
232 			p = seprint(p, e, "%.*H", len-4, lcp->data);
233 		} else {
234 			p = seprint(p, e, " %s=", lcp->code==1?"challenge ":"response ");
235 			p = seprint(p, e, "%.*H", lcp->data[0], lcp->data+1);
236 			p = seprint(p, e, " name=");
237 			p = seprint(p, e, "%.*H", len-4-lcp->data[0]-1, lcp->data+lcp->data[0]+1);
238 		}
239 		break;
240 	case 3:
241 	case 4:
242 		if(len > 64)
243 			len = 64;
244 		p = seprint(p, e, " %s=%.*H", lcp->code==3?"success ":"failure",
245 				len>64?64:len, lcp->data);
246 		break;
247 	}
248 	m->p = seprint(p, e, " len=%d", len);
249 	return 0;
250 }
251 
252 static char*
seprintlcpopt(char * p,char * e,void * a,int len)253 seprintlcpopt(char *p, char *e, void *a, int len)
254 {
255 	Lcpopt *o;
256 	int proto, x, period;
257 	uchar *cp, *ecp;
258 
259 	cp = a;
260 	ecp = cp+len;
261 
262 	for(; cp < ecp; cp += o->len){
263 		o = (Lcpopt*)cp;
264 		if(cp + o->len > ecp || o->len == 0){
265 			p = seprint(p, e, " bad-opt-len=%d", o->len);
266 			return p;
267 		}
268 
269 		switch(o->type){
270 		default:
271 			p = seprint(p, e, " (type=%d len=%d)", o->type, o->len);
272 			break;
273 		case Omtu:
274 			p = seprint(p, e, " mtu=%d", NetS(o->data));
275 			break;
276 		case Octlmap:
277 			p = seprint(p, e, " ctlmap=%ux", NetL(o->data));
278 			break;
279 		case Oauth:
280 			proto = NetS(o->data);
281 			switch(proto) {
282 			default:
283 				p = seprint(p, e, " auth=%d", proto);
284 				break;
285 			case PPP_passwd:
286 				p = seprint(p, e, " auth=passwd");
287 				break;
288 			case PPP_chap:
289 				p = seprint(p, e, " (auth=chap data=%2.2ux)", o->data[2]);
290 				break;
291 			}
292 			break;
293 		case Oquality:
294 			proto = NetS(o->data);
295 			switch(proto) {
296 			default:
297 				p = seprint(p, e, " qproto=%d", proto);
298 				break;
299 			case PPP_lqm:
300 				x = NetL(o->data+2)*10;
301 				period = (x+(PPP_period-1))/PPP_period;
302 				p = seprint(p, e, " (qproto=lqm period=%d)", period);
303 				break;
304 			}
305 		case Omagic:
306 			p = seprint(p, e, " magic=%ux", NetL(o->data));
307 			break;
308 		case Opc:
309 			p = seprint(p, e, " protocol-compress");
310 			break;
311 		case Oac:
312 			p = seprint(p, e, " addr-compress");
313 			break;
314 		}
315 	}
316 	return p;
317 }
318 
319 
320 static int
p_seprintlcp(Msg * m)321 p_seprintlcp(Msg *m)
322 {
323 	Lcppkt *lcp;
324 	char *p, *e;
325 	int len;
326 
327 	if(m->pe-m->ps < 4)
328 		return -1;
329 
330 	p = m->p;
331 	e = m->e;
332 	m->pr = nil;
333 
334 	lcp = (Lcppkt*)m->ps;
335 	len = NetS(lcp->len);
336 	if(m->ps+len < m->pe)
337 		m->pe = m->ps+len;
338 	else if(m->ps+len > m->pe)
339 		return -1;
340 
341 	p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
342 	switch(lcp->code) {
343 	default:
344 		p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
345 		break;
346 	case Lconfreq:
347 	case Lconfack:
348 	case Lconfnak:
349 	case Lconfrej:
350 		p = seprint(p, e, "=%s", lcpcode[lcp->code]);
351 		p = seprintlcpopt(p, e, lcp->data, len-4);
352 		break;
353 	case Ltermreq:
354 	case Ltermack:
355 	case Lcoderej:
356 	case Lprotorej:
357 	case Lechoreq:
358 	case Lechoack:
359 	case Ldiscard:
360 		p = seprint(p, e, "=%s", lcpcode[lcp->code]);
361 		break;
362 	}
363 	m->p = seprint(p, e, " len=%d", len);
364 	return 0;
365 }
366 
367 static char*
seprintipcpopt(char * p,char * e,void * a,int len)368 seprintipcpopt(char *p, char *e, void *a, int len)
369 {
370 	Lcpopt *o;
371 	uchar *cp, *ecp;
372 
373 	cp = a;
374 	ecp = cp+len;
375 
376 	for(; cp < ecp; cp += o->len){
377 		o = (Lcpopt*)cp;
378 		if(cp + o->len > ecp){
379 			p = seprint(p, e, " bad opt len %ux", o->type);
380 			return p;
381 		}
382 
383 		switch(o->type){
384 		default:
385 			p = seprint(p, e, " (type=%d len=%d)", o->type, o->len);
386 			break;
387 		case Oipaddrs:
388 			p = seprint(p, e, " ipaddrs(deprecated)");
389 			break;
390 		case Oipcompress:
391 			p = seprint(p, e, " ipcompress");
392 			break;
393 		case Oipaddr:
394 			p = seprint(p, e, " ipaddr=%V", o->data);
395 			break;
396 		case Oipdns:
397 			p = seprint(p, e, " dnsaddr=%V", o->data);
398 			break;
399 		case Oipwins:
400 			p = seprint(p, e, " winsaddr=%V", o->data);
401 			break;
402 		case Oipdns2:
403 			p = seprint(p, e, " dns2addr=%V", o->data);
404 			break;
405 		case Oipwins2:
406 			p = seprint(p, e, " wins2addr=%V", o->data);
407 			break;
408 		}
409 	}
410 	return p;
411 }
412 
413 static int
p_seprintipcp(Msg * m)414 p_seprintipcp(Msg *m)
415 {
416 	Lcppkt *lcp;
417 	char *p, *e;
418 	int len;
419 
420 	if(m->pe-m->ps < 4)
421 		return -1;
422 
423 	p = m->p;
424 	e = m->e;
425 	m->pr = nil;
426 
427 	lcp = (Lcppkt*)m->ps;
428 	len = NetS(lcp->len);
429 	if(m->ps+len < m->pe)
430 		m->pe = m->ps+len;
431 	else if(m->ps+len > m->pe)
432 		return -1;
433 
434 	p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
435 	switch(lcp->code) {
436 	default:
437 		p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
438 		break;
439 	case Lconfreq:
440 	case Lconfack:
441 	case Lconfnak:
442 	case Lconfrej:
443 		p = seprint(p, e, "=%s", lcpcode[lcp->code]);
444 		p = seprintipcpopt(p, e, lcp->data, len-4);
445 		break;
446 	case Ltermreq:
447 	case Ltermack:
448 		p = seprint(p, e, "=%s", lcpcode[lcp->code]);
449 		break;
450 	}
451 	m->p = seprint(p, e, " len=%d", len);
452 	return 0;
453 }
454 
455 static char*
seprintccpopt(char * p,char * e,void * a,int len)456 seprintccpopt(char *p, char *e, void *a, int len)
457 {
458 	Lcpopt *o;
459 	uchar *cp, *ecp;
460 
461 	cp = a;
462 	ecp = cp+len;
463 
464 	for(; cp < ecp; cp += o->len){
465 		o = (Lcpopt*)cp;
466 		if(cp + o->len > ecp){
467 			p = seprint(p, e, " bad opt len %ux", o->type);
468 			return p;
469 		}
470 
471 		switch(o->type){
472 		default:
473 			p = seprint(p, e, " type=%d ", o->type);
474 			break;
475 		case 0:
476 			p = seprint(p, e, " OUI=(%d %.2ux%.2ux%.2ux) ", o->type,
477 				o->data[0], o->data[1], o->data[2]);
478 			break;
479 		case 17:
480 			p = seprint(p, e, " Stac-LZS");
481 			break;
482 		case 18:
483 			p = seprint(p, e, " Microsoft-PPC=%ux", NetL(o->data));
484 			break;
485 		}
486 	}
487 	return p;
488 }
489 
490 static int
p_seprintccp(Msg * m)491 p_seprintccp(Msg *m)
492 {
493 	Lcppkt *lcp;
494 	char *p, *e;
495 	int len;
496 
497 	if(m->pe-m->ps < 4)
498 		return -1;
499 
500 	p = m->p;
501 	e = m->e;
502 	m->pr = nil;
503 
504 	lcp = (Lcppkt*)m->ps;
505 	len = NetS(lcp->len);
506 	if(m->ps+len < m->pe)
507 		m->pe = m->ps+len;
508 	else if(m->ps+len > m->pe)
509 		return -1;
510 
511 	p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
512 	switch(lcp->code) {
513 	default:
514 		p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
515 		break;
516 	case Lconfreq:
517 	case Lconfack:
518 	case Lconfnak:
519 	case Lconfrej:
520 		p = seprint(p, e, "=%s", lcpcode[lcp->code]);
521 		p = seprintccpopt(p, e, lcp->data, len-4);
522 		break;
523 	case Ltermreq:
524 	case Ltermack:
525 	case Lresetreq:
526 	case Lresetack:
527 		p = seprint(p, e, "=%s", lcpcode[lcp->code]);
528 		break;
529 	}
530 	m->p = seprint(p, e, " len=%d", len);
531 
532 	return 0;
533 }
534 
535 static int
p_seprintcomp(Msg * m)536 p_seprintcomp(Msg *m)
537 {
538 	char compflag[5];
539 	ushort x;
540 	int i;
541 	int len;
542 
543 	len = m->pe-m->ps;
544 	if(len < 2)
545 		return -1;
546 
547 	x = NetS(m->ps);
548 	m->ps += 2;
549 	i = 0;
550 	if(x & (1<<15))
551 		compflag[i++] = 'r';
552 	if(x & (1<<14))
553 		compflag[i++] = 'f';
554 	if(x & (1<<13))
555 		compflag[i++] = 'c';
556 	if(x & (1<<12))
557 		compflag[i++] = 'e';
558 	compflag[i] = 0;
559 	m->p = seprint(m->p, m->e, "flag=%s count=%.3ux", compflag, x&0xfff);
560 	m->p = seprint(m->p, m->e, " data=%.*H", len>64?64:len, m->ps);
561 	m->pr = nil;
562 	return 0;
563 }
564 
565 Proto ppp =
566 {
567 	"ppp",
568 	p_compile,
569 	p_filter,
570 	p_seprint,
571 	p_mux,
572 	"%#.4lux",
573 	nil,
574 	defaultframer
575 };
576 
577 Proto ppp_ipcp =
578 {
579 	"ppp_ipcp",
580 	p_compile,
581 	p_filter,
582 	p_seprintipcp,
583 	nil,
584 	nil,
585 	nil,
586 	defaultframer
587 };
588 
589 Proto ppp_lcp =
590 {
591 	"ppp_lcp",
592 	p_compile,
593 	p_filter,
594 	p_seprintlcp,
595 	nil,
596 	nil,
597 	nil,
598 	defaultframer
599 };
600 
601 Proto ppp_ccp =
602 {
603 	"ppp_ccp",
604 	p_compile,
605 	p_filter,
606 	p_seprintccp,
607 	nil,
608 	nil,
609 	nil,
610 	defaultframer
611 };
612 
613 Proto ppp_chap =
614 {
615 	"ppp_chap",
616 	p_compile,
617 	p_filter,
618 	p_seprintchap,
619 	nil,
620 	nil,
621 	nil,
622 	defaultframer
623 };
624 
625 Proto ppp_comp =
626 {
627 	"ppp_comp",
628 	p_compile,
629 	p_filter,
630 	p_seprintcomp,
631 	nil,
632 	nil,
633 	nil,
634 	defaultframer
635 };
636