xref: /plan9-contrib/sys/src/cmd/ip/ppp/mppc.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <libsec.h>
4 #include <ip.h>
5 #include <auth.h>
6 #include "ppp.h"
7 
8 enum {
9 	HistorySize=	8*1024,
10 	Cminmatch	= 3,		/* sintest match possible */
11 	Chshift		= 4,		/* nice compromise between space & time */
12 	Cnhash		= 1<<(Chshift*Cminmatch),
13 	HMASK		= Cnhash-1,
14 };
15 
16 typedef struct Carena Carena;
17 struct Carena
18 {
19 	uchar	*pos;			/* current place, also amount of history filled */
20 	uchar	buf[HistorySize];
21 };
22 
23 typedef struct Cstate Cstate;
24 struct Cstate
25 {
26 	QLock;
27 	int	count;
28 	int	reset;		/* compressor has been reset */
29 	int	front;		/* move to begining of history */
30 	ulong	sreg;		/* output shift reg */
31 	int	bits;		/* number of bits in sreg */
32 	Block	*b; 		/* output block */
33 
34 	/*
35 	 * state for hashing compressor
36 	 */
37 	Carena	arenas[2];
38 	Carena	*hist;
39 	Carena	*ohist;
40 	ulong	hash[Cnhash];
41 	int	h;
42 	ulong	me;
43 	ulong	split;
44 
45 	int	encrypt;
46 	uchar	startkey[16];
47 	uchar	key[16];
48 	RC4state rc4key;
49 };
50 
51 typedef struct Uncstate Uncstate;
52 struct Uncstate
53 {
54 	int	count;	 	/* packet count - detects missing packets */
55 	int	resetid;	/* id of reset requests */
56 	uchar	his[HistorySize];
57 	int	indx;		/* current indx in history */
58 	int	size;		/* current history size */
59 	uchar	startkey[16];
60 	uchar	key[16];
61 	RC4state rc4key;
62 };
63 
64 /* packet flags */
65 enum {
66 	Preset=		(1<<15),	/* reset history */
67 	Pfront=		(1<<14),	/* move packet to front of history */
68 	Pcompress=	(1<<13),	/* packet is compressed */
69 	Pencrypt=	(1<<12),	/* packet is encrypted */
70 };
71 
72 enum {
73 	Lit7,		/* seven bit literal */
74 	Lit8,		/* eight bit literal */
75 	Off6,		/* six bit offset */
76 	Off8,		/* eight bit offset */
77 	Off13,		/* thirteen bit offset */
78 };
79 
80 /* decode first four bits */
81 int decode[16] = {
82 	Lit7,
83 	Lit7,
84 	Lit7,
85 	Lit7,
86 	Lit7,
87 	Lit7,
88 	Lit7,
89 	Lit7,
90 	Lit8,
91 	Lit8,
92 	Lit8,
93 	Lit8,
94 	Off13,
95 	Off13,
96 	Off8,
97 	Off6,
98 };
99 
100 
101 static	void		*compinit(PPP*);
102 static	Block*		comp(PPP*, ushort, Block*, int*);
103 static	void		comp2(Cstate*, uchar*, int);
104 static	Block		*compresetreq(void*, Block*);
105 static	void		compfini(void*);
106 static	void		complit(Cstate*, int);
107 static	void		compcopy(Cstate*, int, int);
108 static	void		compout(Cstate*, ulong, int);
109 static	void		compfront(Cstate*);
110 static	void		hashcheck(Cstate*);
111 static	void		compreset(Cstate*);
112 static	int		hashit(uchar*);
113 
114 
115 static	void		*uncinit(PPP*);
116 static	Block*		uncomp(PPP*, Block*, int *protop, Block**);
117 static	Block		*uncomp2(Uncstate *s, Block*, ushort);
118 static	void		uncfini(void*);
119 static	void		uncresetack(void*, Block*);
120 static  int		ipcheck(uchar*, int);
121 static  void		hischeck(Uncstate*);
122 
123 static	void		setkey(uchar *key, uchar *startkey);
124 
125 Comptype cmppc = {
126 	compinit,
127 	comp,
128 	compresetreq,
129 	compfini
130 };
131 
132 Uncomptype uncmppc = {
133 	uncinit,
134 	uncomp,
135 	uncresetack,
136 	uncfini
137 };
138 
139 static void *
compinit(PPP * ppp)140 compinit(PPP *ppp)
141 {
142 	Cstate *cs;
143 
144 	cs = mallocz(sizeof(Cstate), 1);
145 	cs->hist = &cs->arenas[0];
146 	cs->ohist = &cs->arenas[1];
147 	compreset(cs);
148 	/*
149 	 * make reset clear the hash table
150 	 */
151 	cs->me = ~0;
152 	compreset(cs);
153 
154 	cs->reset = 0;
155 
156 	if(ppp->sendencrypted) {
157 		cs->encrypt = 1;
158 		memmove(cs->startkey, ppp->key, 16);
159 		memmove(cs->key, ppp->key, 16);
160 		setkey(cs->key, cs->startkey);
161 		setupRC4state(&cs->rc4key, cs->key, 16);
162 	}
163 
164 	return cs;
165 }
166 
167 static void
compfini(void * as)168 compfini(void *as)
169 {
170 	Cstate *cs;
171 
172 	cs = as;
173 	free(cs);
174 }
175 
176 
177 static Block*
comp(PPP * ppp,ushort proto,Block * b,int * protop)178 comp(PPP *ppp, ushort proto, Block *b, int *protop)
179 {
180 	Cstate *s;
181 	int n, n2;
182 	ushort count;
183 
184 	s = ppp->cstate;
185 	*protop = 0;
186 
187 	qlock(s);
188 
189 	/* put protocol into b */
190 	b->rptr -= 2;
191 	if(b->rptr < b->base)
192 		sysfatal("mppc: not enough header in block");
193 	b->rptr[0] = proto>>8;
194 	b->rptr[1] = proto;
195 
196 	n = BLEN(b);
197 	s->bits = 0;
198 	s->b = allocb(n*9/8+20);
199 	s->b->wptr += 2;	/* leave room for mppc header */
200 
201 	comp2(s, b->rptr, n);
202 
203 	/* flush sreg */
204 	if(s->bits)
205 		*s->b->wptr++ = s->sreg<<(8-s->bits);
206 	if(s->b->wptr > s->b->lim)
207 		sysfatal("mppc: comp: output block overflowed");
208 
209 	n2 = BLEN(s->b);
210 
211 	if(n2 > n-2 && !s->encrypt) {
212 		/* expened and not excrypting so send as a regular packet */
213 //netlog("mppc: comp: expanded\n");
214 		compreset(s);
215 		freeb(s->b);
216 		b->rptr += 2;
217 		qunlock(s);
218 		*protop = proto;
219 		return b;
220 	}
221 
222 	count = s->count++;
223 	s->count &= 0xfff;
224 	if(s->front)
225 		count |= Pfront;
226 	if(s->reset)
227 		count |= Preset;
228 	s->reset = 0;
229 	s->front = 0;
230 
231 	if(n2 > n) {
232 //netlog("mppc: comp: expanded\n");
233 		freeb(s->b);
234 		/* make room for count */
235 		compreset(s);
236 		b->rptr -= 2;
237 	} else {
238 		freeb(b);
239 		b = s->b;
240 		count |= Pcompress;
241 	}
242 	s->b = nil;
243 
244 	if(s->encrypt) {
245 		count |= Pencrypt;
246 		if((count&0xff) == 0xff) {
247 //netlog("mppc: comp: changing key\n");
248 			setkey(s->key, s->startkey);
249 			setupRC4state(&s->rc4key, s->key, 16);
250 			rc4(&s->rc4key, s->key, 16);
251 			setupRC4state(&s->rc4key, s->key, 16);
252 		} else if(count&Preset)
253 			setupRC4state(&s->rc4key, s->key, 16);
254 		rc4(&s->rc4key, b->rptr+2, BLEN(b)-2);
255 //netlog("mppc: encrypt %ux\n", count);
256 	}
257 
258 	b->rptr[0] = count>>8;
259 	b->rptr[1] = count;
260 
261 	qunlock(s);
262 
263 	*protop = Pcdata;
264 	return b;
265 }
266 
267 static Block *
compresetreq(void * as,Block * b)268 compresetreq(void *as, Block *b)
269 {
270 	Cstate *cs;
271 
272 	cs = as;
273 netlog("mppc: comp: reset request\n");
274 	qlock(cs);
275 	compreset(cs);
276 	qunlock(cs);
277 
278 	freeb(b);
279 
280 	return nil;
281 }
282 
283 static void
comp2(Cstate * cs,uchar * p,int n)284 comp2(Cstate *cs, uchar *p, int n)
285 {
286 	Carena *hist, *ohist;
287 	ulong *hash, me, split, you, last;
288 	uchar *s, *t, *et, *buf, *obuf, *pos, *opos;
289 	int i, h, m;
290 
291 	/*
292 	 * check for wrap
293 	 */
294 	if(cs->me + n < cs->me)
295 		compreset(cs);
296 
297 	if(cs->hist->pos + n > cs->hist->buf + HistorySize)
298 		compfront(cs);
299 
300 	hist = cs->hist;
301 	ohist = cs->ohist;
302 
303 	hash = cs->hash;
304 	me = cs->me;
305 	split = cs->split;
306 
307 	memmove(hist->pos, p, n);
308 	p = hist->pos;
309 	hist->pos = pos = p + n;
310 
311 	m = Cminmatch;
312 	if(m > n)
313 		m = n;
314 	h = cs->h;
315 	for(i = 0; i < m; i++) {
316 		h = (((h)<<Chshift) ^ p[i]) & HMASK;
317 		last = me + (i - (Cminmatch-1));
318 		if(last >= split && last != me)
319 			hash[h] = last;
320 	}
321 
322 	buf = hist->buf - split;
323 	obuf = ohist->buf + HistorySize - split;
324 	opos = ohist->pos;
325 	while(p < pos) {
326 		you = hash[h];
327 		if(you < split) {
328 			if(me - you >= HistorySize)
329 				t = opos;
330 			else
331 				t = obuf + you;
332 			et = opos;
333 		} else {
334 			t = buf + you;
335 			et = pos;
336 		}
337 		m = pos - p;
338 		if(m < et - t)
339 			et = t + m;
340 		for(s = p; t < et; t++) {
341 			if(*s != *t)
342 				break;
343 			s++;
344 		}
345 		m = s - p;
346 		if(m < Cminmatch) {
347 			complit(cs, *p);
348 			s = p + 1;
349 		} else
350 			compcopy(cs, me - you, m);
351 
352 		for(; p != s; p++) {
353 			if(p + Cminmatch <= pos) {
354 				hash[h] = me;
355 				if(p + Cminmatch < pos)
356 					h = (((h)<<Chshift) ^ p[Cminmatch]) & HMASK;
357 			}
358 			me++;
359 		}
360 	}
361 
362 	cs->h = h;
363 	cs->me = me;
364 }
365 
366 static void
compfront(Cstate * cs)367 compfront(Cstate *cs)
368 {
369 	Carena *th;
370 
371 	cs->front = 1;
372 
373 	th = cs->ohist;
374 	cs->ohist = cs->hist;
375 	cs->hist = th;
376 	cs->hist->pos = cs->hist->buf;
377 	cs->h = 0;
378 	cs->me = cs->split + HistorySize;
379 	cs->split = cs->me;
380 }
381 
382 static void
compreset(Cstate * cs)383 compreset(Cstate *cs)
384 {
385 	ulong me;
386 
387 	cs->reset = 1;
388 
389 	me = cs->me;
390 	if(me + 2 * HistorySize < me){
391 		me = 0;
392 		memset(cs->hash, 0, sizeof(cs->hash));
393 	}
394 	cs->me = me + 2 * HistorySize;
395 	cs->split = cs->me;
396 	cs->hist->pos = cs->hist->buf;
397 	cs->ohist->pos = cs->ohist->buf;
398 }
399 
400 static void
complit(Cstate * s,int c)401 complit(Cstate *s, int c)
402 {
403 	if(c&0x80)
404 		compout(s, 0x100|(c&0x7f), 9);
405 	else
406 		compout(s, c, 8);
407 }
408 
409 static void
compcopy(Cstate * s,int off,int len)410 compcopy(Cstate *s, int off, int len)
411 {
412 	int i;
413 	ulong mask;
414 
415 	if(off<64)
416 		compout(s, 0x3c0|off, 10);
417 	else if(off<320)
418 		compout(s, 0xe00|(off-64), 12);
419 	else
420 		compout(s, 0xc000|(off-320), 16);
421 	if(len < 3)
422 		sysfatal("compcopy: bad len: %d", len);
423 	if(len == 3)
424 		compout(s, 0, 1);
425 	else {
426 		for(i=3; (1<<i) <= len; i++)
427 			;
428 		mask = (1<<(i-1))-1;
429 		compout(s, (((1<<(i-2))-1)<<i) | len&mask, (i-1)<<1);
430 	}
431 }
432 
433 static void
compout(Cstate * s,ulong data,int bits)434 compout(Cstate *s, ulong data, int bits)
435 {
436 	ulong sreg;
437 
438 	sreg = s->sreg;
439 	sreg <<= bits;
440 	sreg |= data;
441 	bits += s->bits;
442 	while(bits >= 8) {
443 		*s->b->wptr++ = sreg>>(bits-8);
444 		bits -= 8;
445 	}
446 	s->sreg = sreg;
447 	s->bits = bits;
448 }
449 
450 void
printkey(uchar * key)451 printkey(uchar *key)
452 {
453 	char buf[200], *p;
454 	int i;
455 
456 	p = buf;
457 	for(i=0; i<16; i++)
458 		p += sprint(p, "%.2ux ", key[i]);
459 //netlog("key = %s\n", buf);
460 }
461 
462 static	void *
uncinit(PPP * ppp)463 uncinit(PPP *ppp)
464 {
465 	Uncstate *s;
466 
467 	s = mallocz(sizeof(Uncstate), 1);
468 
469 	s->count = 0xfff;	/* count of non existant last packet */
470 	memmove(s->startkey, ppp->key, 16);
471 	memmove(s->key, ppp->key, 16);
472 	setkey(s->key, s->startkey);
473 	setupRC4state(&s->rc4key, s->key, 16);
474 
475 	return s;
476 }
477 
478 static	Block*
uncomp(PPP * ppp,Block * b,int * protop,Block ** r)479 uncomp(PPP *ppp, Block *b, int *protop, Block **r)
480 {
481 	Uncstate *s;
482 	ushort proto;
483 	ushort count;
484 	Lcpmsg *m;
485 
486 	*r = nil;
487 	*protop = 0;
488 	s = ppp->uncstate;
489 	if(BLEN(b) < 2){
490 		syslog(0, "ppp", ": mppc: short packet\n");
491 		freeb(b);
492 		return nil;
493 	}
494 	count = nhgets(b->rptr);
495 	b->rptr += 2;
496 
497 	b = uncomp2(s, b, count);
498 
499 	if(b == nil) {
500 //netlog("ppp: mppc: reset request\n");
501 		/* return reset request packet */
502 		*r = alloclcp(Lresetreq, s->resetid++, 4, &m);
503 		hnputs(m->len, 4);
504 		*protop = 0;
505 		return nil;
506 	}
507 
508 	if(BLEN(b) < 2){
509 		syslog(0, "ppp", ": mppc: short packet\n");
510 		freeb(b);
511 		*protop = 0;
512 		return nil;
513 	}
514 	proto = nhgets(b->rptr);
515 	b->rptr += 2;
516 
517 /*
518 	if(proto == 0x21)
519 		if(!ipcheck(b->rptr, BLEN(b)))
520 			hischeck(s);
521 */
522 
523 	*protop = proto;
524 	return b;
525 }
526 
527 #define NEXTBYTE	sreg = (sreg<<8) | *p++; n--; bits += 8
528 int	maxoff;
529 
530 static	Block*
uncomp2(Uncstate * s,Block * b,ushort count)531 uncomp2(Uncstate *s, Block *b, ushort count)
532 {
533 	int ecount, n, bits, off, len, ones;
534 	ulong sreg;
535 	int t;
536 	uchar *p, c, *hp, *hs, *he, *hq;
537 
538 	if(count&Preset) {
539 //netlog("mppc reset\n");
540 		s->indx = 0;
541 		s->size = 0;
542 		setupRC4state(&s->rc4key, s->key, 16);
543 	} else {
544 		ecount = (s->count+1)&0xfff;
545 		if((count&0xfff) != ecount) {
546 netlog("******* bad count - got %ux expected %ux\n", count&0xfff, ecount);
547 			freeb(b);
548 			return nil;
549 		}
550 		if(count&Pfront) {
551 			s->indx = 0;
552 /*			netlog("ppp: mppc: frount flag set\n"); */
553 		}
554 	}
555 
556 	/* update key */
557 	n = (((count+1)>>8)&0xf) - (((s->count+1)>>8)&0xf);
558 	if(n < 0)
559 		n += 16;
560 //netlog("mppc count = %ux oldcount %ux n = %d\n", count, s->count, n);
561 	if(n < 0 || n > 1) {
562 		syslog(0, "ppp", ": mppc bad count %ux, %ux", count, s->count);
563 		freeb(b);
564 		return nil;
565 	}
566 	if(n == 1) {
567 		setkey(s->key, s->startkey);
568 		setupRC4state(&s->rc4key, s->key, 16);
569 		rc4(&s->rc4key, s->key, 16);
570 		setupRC4state(&s->rc4key, s->key, 16);
571 	}
572 
573 	s->count = count;
574 
575 	n = BLEN(b);
576 	p = b->rptr;
577 	if(count & Pencrypt) {
578 //netlog("mppc unencrypt count = %ux\n", count);
579 		rc4(&s->rc4key, p, n);
580 	}
581 
582 	if(!(count & Pcompress)) {
583 //netlog("uncompress blen = %d\n", BLEN(b));
584 		return  b;
585 	}
586 
587 	bits = 0;
588 	sreg = 0;
589 	hs = s->his;		/* history start */
590 	hp = hs+s->indx;	/* write pointer in history */
591 	he = hs+sizeof(s->his);	/* hsitory end */
592 	for(;;) {
593 		if(bits<4) {
594 			if(n==0) goto Done;
595 			NEXTBYTE;
596 		}
597 		t = decode[(sreg>>(bits-4))&0xf];
598 		switch(t) {
599 		default:
600 			sysfatal("mppc: bad decode!");
601 		case Lit7:
602 			bits -= 1;
603 			if(bits<7) {
604 				if(n==0) goto Done;
605 				NEXTBYTE;
606 			}
607 			c = (sreg>>(bits-7))&0x7f;
608 			bits -= 7;
609 			if(hp >= he) goto His;
610 			*hp++ = c;
611 /* netlog("\tlit7 %.2ux\n", c); */
612 			continue;
613 		case Lit8:
614 			bits -= 2;
615 			if(bits<7) {
616 				if(n==0) goto Eof;
617 				NEXTBYTE;
618 			}
619 			c = 0x80 | ((sreg>>(bits-7))&0x7f);
620 			bits -= 7;
621 			if(hp >= he) goto His;
622 			*hp++ = c;
623 /* netlog("\tlit8 %.2ux\n", c); */
624 			continue;
625 		case Off6:
626 			bits -= 4;
627 			if(bits<6) {
628 				if(n==0) goto Eof;
629 				NEXTBYTE;
630 			}
631 			off = (sreg>>(bits-6))&0x3f;
632 			bits -= 6;
633 			break;
634 		case Off8:
635 			bits -= 4;
636 			if(bits<8) {
637 				if(n==0) goto Eof;
638 				NEXTBYTE;
639 			}
640 			off = ((sreg>>(bits-8))&0xff)+64;
641 			bits -= 8;
642 			break;
643 		case Off13:
644 			bits -= 3;
645 			while(bits<13) {
646 				if(n==0) goto Eof;
647 				NEXTBYTE;
648 			}
649 			off = ((sreg>>(bits-13))&0x1fff)+320;
650 			bits -= 13;
651 /* netlog("\toff=%d bits = %d sreg = %ux t = %x\n", off, bits, sreg, t); */
652 			break;
653 		}
654 		for(ones=0;;ones++) {
655 			if(bits == 0) {
656 				if(n==0) goto Eof;
657 				NEXTBYTE;
658 			}
659 			bits--;
660 			if(!(sreg&(1<<bits)))
661 				break;
662 		}
663 		if(ones>11) {
664 netlog("ppp: mppc: bad length %d\n", ones);
665 			freeb(b);
666 			return nil;
667 		}
668 		if(ones == 0) {
669 			len = 3;
670 		} else {
671 			ones++;
672 			while(bits<ones) {
673 				if(n==0) goto Eof;
674 				NEXTBYTE;
675 			}
676 			len = (1<<ones) | ((sreg>>(bits-ones))&((1<<ones)-1));
677 			bits -= ones;
678 		}
679 
680 		hq = hp-off;
681 		if(hq < hs) {
682 			hq += sizeof(s->his);
683 			if(hq-hs+len > s->size)
684 				goto His;
685 		}
686 		if(hp+len > he) goto His;
687 		while(len) {
688 			*hp++ = *hq++;
689 			len--;
690 		}
691 	}
692 Done:
693 	freeb(b);
694 
695 	/* build up return block */
696 	hq = hs+s->indx;
697 	len = hp-hq;
698 	b = allocb(len);
699 	memmove(b->wptr, hq, len);
700 	b->wptr += len;
701 netlog("ppp: mppc: len %d bits = %d n=%d\n", len, bits, n);
702 
703 	s->indx += len;
704 	if(s->indx > s->size)
705 		s->size = s->indx;
706 
707 	return b;
708 Eof:
709 netlog("*****unexpected end of data\n");
710 	freeb(b);
711 	return nil;
712 His:
713 netlog("*****bad history\n");
714 	freeb(b);
715 	return nil;
716 }
717 
718 static	void
uncresetack(void *,Block *)719 uncresetack(void*, Block*)
720 {
721 }
722 
723 static	void
uncfini(void * as)724 uncfini(void *as)
725 {
726 	Uncstate *s;
727 
728 	s = as;
729 	free(s);
730 }
731 
732 static void
setkey(uchar * key,uchar * startkey)733 setkey(uchar *key, uchar *startkey)
734 {
735 	uchar pad[40];
736 	SHAstate *s;
737 	uchar digest[SHA1dlen];
738 
739 	s = sha1(startkey, 16, nil, nil);
740 	memset(pad, 0, 40);
741 	sha1(pad, 40, nil, s);
742 	sha1(key, 16, nil, s);
743 	memset(pad, 0xf2, 40);
744 	sha1(pad, 40, digest, s);
745 	memmove(key, digest, 16);
746 }
747 
748 
749 /* code to check if IP packet looks good */
750 
751 typedef struct Iphdr Iphdr;
752 struct Iphdr
753 {
754 	uchar	vihl;		/* Version and header length */
755 	uchar	tos;		/* Type of service */
756 	uchar	length[2];	/* packet length */
757 	uchar	id[2];		/* Identification */
758 	uchar	frag[2];	/* Fragment information */
759 	uchar	ttl;		/* Time to live */
760 	uchar	proto;		/* Protocol */
761 	uchar	cksum[2];	/* Header checksum */
762 	uchar	src[4];		/* Ip source */
763 	uchar	dst[4];		/* Ip destination */
764 };
765 
766 enum
767 {
768 	QMAX		= 64*1024-1,
769 	IP_TCPPROTO	= 6,
770 	TCP_IPLEN	= 8,
771 	TCP_PHDRSIZE	= 12,
772 	TCP_HDRSIZE	= 20,
773 	TCP_PKT		= TCP_IPLEN+TCP_PHDRSIZE,
774 };
775 
776 enum
777 {
778 	UDP_PHDRSIZE	= 12,
779 	UDP_HDRSIZE	= 20,
780 	UDP_IPHDR	= 8,
781 	IP_UDPPROTO	= 17,
782 	UDP_USEAD	= 12,
783 	UDP_RELSIZE	= 16,
784 
785 	Udprxms		= 200,
786 	Udptickms	= 100,
787 	Udpmaxxmit	= 10,
788 };
789 
790 typedef struct UDPhdr UDPhdr;
791 struct UDPhdr
792 {
793 	/* ip header */
794 	uchar	vihl;		/* Version and header length */
795 	uchar	tos;		/* Type of service */
796 	uchar	length[2];	/* packet length */
797 	uchar	id[2];		/* Identification */
798 	uchar	frag[2];	/* Fragment information */
799 	uchar	Unused;
800 	uchar	udpproto;	/* Protocol */
801 	uchar	udpplen[2];	/* Header plus data length */
802 	uchar	udpsrc[4];	/* Ip source */
803 	uchar	udpdst[4];	/* Ip destination */
804 
805 	/* udp header */
806 	uchar	udpsport[2];	/* Source port */
807 	uchar	udpdport[2];	/* Destination port */
808 	uchar	udplen[2];	/* data length */
809 	uchar	udpcksum[2];	/* Checksum */
810 };
811 
812 typedef struct TCPhdr TCPhdr;
813 struct TCPhdr
814 {
815 	uchar	vihl;		/* Version and header length */
816 	uchar	tos;		/* Type of service */
817 	uchar	length[2];	/* packet length */
818 	uchar	id[2];		/* Identification */
819 	uchar	frag[2];	/* Fragment information */
820 	uchar	Unused;
821 	uchar	proto;
822 	uchar	tcplen[2];
823 	uchar	tcpsrc[4];
824 	uchar	tcpdst[4];
825 	uchar	tcpsport[2];
826 	uchar	tcpdport[2];
827 	uchar	tcpseq[4];
828 	uchar	tcpack[4];
829 	uchar	tcpflag[2];
830 	uchar	tcpwin[2];
831 	uchar	tcpcksum[2];
832 	uchar	tcpurg[2];
833 	/* Options segment */
834 	uchar	tcpopt[2];
835 	uchar	tcpmss[2];
836 };
837 
838 static void
hischeck(Uncstate * s)839 hischeck(Uncstate *s)
840 {
841 	uchar *p;
842 	Iphdr *iph;
843 	int len;
844 
845 	p = s->his;
846 
847 netlog("***** history check\n");
848 	while(p < s->his+s->size) {
849 		if(p[0] != 0 || p[1] != 0x21) {
850 netlog("***** unknown protocol\n");
851 			return;
852 		}
853 		p += 2;
854 netlog("off = %ld ", p-s->his);
855 		iph = (Iphdr*)p;
856 		len = nhgets(iph->length);
857 		ipcheck(p, len);
858 		p += len;
859 	}
860 }
861 
862 
863 static int
ipcheck(uchar * p,int len)864 ipcheck(uchar *p, int len)
865 {
866 	Iphdr *iph;
867 	TCPhdr *tcph;
868 	ushort length;
869 	UDPhdr *uh;
870 	Block *bp;
871 	ushort cksum;
872 	int good;
873 
874 	bp = allocb(len);
875 	memmove(bp->wptr, p, len);
876 	bp->wptr += len;
877 
878 	good = 1;
879 
880 	iph = (Iphdr *)(bp->rptr);
881 /* netlog("ppp: mppc: ipcheck %I %I len %d proto %d\n", iph->src, iph->dst, BLEN(bp), iph->proto); */
882 
883 	if(len != nhgets(iph->length)) {
884 		netlog("***** bad length! %d %d\n", len, nhgets(iph->length));
885 		good = 0;
886 	}
887 
888 	cksum = ipcsum(&iph->vihl);
889 	if(cksum) {
890 		netlog("***** IP proto cksum!!! %I %ux\n", iph->src, cksum);
891 		good = 0;
892 	}
893 
894 	switch(iph->proto) {
895 	default:
896 		break;
897 	case IP_TCPPROTO:
898 
899 		tcph = (TCPhdr*)(bp->rptr);
900 
901 		length = nhgets(tcph->length);
902 
903 		tcph->Unused = 0;
904 		hnputs(tcph->tcplen, length-TCP_PKT);
905 		cksum = ptclcsum(bp, TCP_IPLEN, length-TCP_IPLEN);
906 		if(cksum) {
907 			netlog("***** bad tcp proto cksum %ux!!!\n", cksum);
908 			good = 0;
909 		}
910 		break;
911 	case IP_UDPPROTO:
912 		uh = (UDPhdr*)(bp->rptr);
913 
914 		/* Put back pseudo header for checksum */
915 		uh->Unused = 0;
916 		len = nhgets(uh->udplen);
917 		hnputs(uh->udpplen, len);
918 
919 		if(nhgets(uh->udpcksum)) {
920 			cksum = ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE);
921 			if(cksum) {
922 				netlog("***** udp: proto cksum!!! %I %ux\n", uh->udpsrc, cksum);
923 				good = 0;
924 			}
925 		}
926 		break;
927 	}
928 	freeb(bp);
929 	return good;
930 }
931