10 Cminmatch = 3, /* sintest match possible */
11 Chshift = 4, /* nice compromise between space & time */
12 Cnhash = 1<<(Chshift*Cminmatch),
16 typedef struct Carena Carena;
19 uchar *pos; /* current place, also amount of history filled */
20 uchar buf[HistorySize];
23 typedef struct Cstate Cstate;
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 */
35 * state for hashing compressor
51 typedef struct Uncstate Uncstate;
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 */
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 */
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 */
80 /* decode first four bits */
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*);
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*);
123 static void setkey(uchar *key, uchar *startkey);
132 Uncomptype uncmppc = {
144 cs = mallocz(sizeof(Cstate), 1);
145 cs->hist = &cs->arenas[0];
146 cs->ohist = &cs->arenas[1];
149 * make reset clear the hash table
156 if(ppp->sendencrypted) {
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);
178 comp(PPP *ppp, ushort proto, Block *b, int *protop)
189 /* put protocol into b */
191 if(b->rptr < b->base)
192 sysfatal("mppc: not enough header in block");
193 b->rptr[0] = proto>>8;
198 s->b = allocb(n*9/8+20);
199 s->b->wptr += 2; /* leave room for mppc header */
201 comp2(s, b->rptr, n);
205 *s->b->wptr++ = s->sreg<<(8-s->bits);
206 if(s->b->wptr > s->b->lim)
207 sysfatal("mppc: comp: output block overflowed");
211 if(n2 > n-2 && !s->encrypt) {
212 /* expened and not excrypting so send as a regular packet */
213 //netlog("mppc: comp: expanded\n");
232 //netlog("mppc: comp: expanded\n");
234 /* make room for count */
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);
258 b->rptr[0] = count>>8;
268 compresetreq(void *as, Block *b)
273 netlog("mppc: comp: reset request\n");
284 comp2(Cstate *cs, uchar *p, int n)
286 Carena *hist, *ohist;
287 ulong *hash, me, split, you, last;
288 uchar *s, *t, *et, *buf, *obuf, *pos, *opos;
294 if(cs->me + n < cs->me)
297 if(cs->hist->pos + n > cs->hist->buf + HistorySize)
307 memmove(hist->pos, p, n);
309 hist->pos = pos = p + n;
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)
322 buf = hist->buf - split;
323 obuf = ohist->buf + HistorySize - split;
328 if(me - you >= HistorySize)
340 for(s = p; t < et; t++) {
350 compcopy(cs, me - you, m);
353 if(p + Cminmatch <= pos) {
355 if(p + Cminmatch < pos)
356 h = (((h)<<Chshift) ^ p[Cminmatch]) & HMASK;
367 compfront(Cstate *cs)
374 cs->ohist = cs->hist;
376 cs->hist->pos = cs->hist->buf;
378 cs->me = cs->split + HistorySize;
383 compreset(Cstate *cs)
390 if(me + 2 * HistorySize < me){
392 memset(cs->hash, 0, sizeof(cs->hash));
394 cs->me = me + 2 * HistorySize;
396 cs->hist->pos = cs->hist->buf;
397 cs->ohist->pos = cs->ohist->buf;
401 complit(Cstate *s, int c)
404 compout(s, 0x100|(c&0x7f), 9);
410 compcopy(Cstate *s, int off, int len)
416 compout(s, 0x3c0|off, 10);
418 compout(s, 0xe00|(off-64), 12);
420 compout(s, 0xc000|(off-320), 16);
422 sysfatal("compcopy: bad len: %d", len);
426 for(i=3; (1<<i) <= len; i++)
429 compout(s, (((1<<(i-2))-1)<<i) | len&mask, (i-1)<<1);
434 compout(Cstate *s, ulong data, int bits)
443 *s->b->wptr++ = sreg>>(bits-8);
458 p += sprint(p, "%.2ux ", key[i]);
459 //netlog("key = %s\n", buf);
467 s = mallocz(sizeof(Uncstate), 1);
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);
479 uncomp(PPP *ppp, Block *b, int *protop, Block **r)
490 syslog(0, "ppp", ": mppc: short packet");
494 count = nhgets(b->rptr);
497 b = uncomp2(s, b, count);
500 //netlog("ppp: mppc: reset request\n");
501 /* return reset request packet */
502 *r = alloclcp(Lresetreq, s->resetid++, 4, &m);
509 syslog(0, "ppp", ": mppc: short packet");
514 proto = nhgets(b->rptr);
519 if(!ipcheck(b->rptr, BLEN(b)))
527 #define NEXTBYTE sreg = (sreg<<8) | *p++; n--; bits += 8
531 uncomp2(Uncstate *s, Block *b, ushort count)
533 int ecount, n, bits, off, len, ones;
536 uchar *p, c, *hp, *hs, *he, *hq;
539 //netlog("mppc reset\n");
542 setupRC4state(&s->rc4key, s->key, 16);
544 ecount = (s->count+1)&0xfff;
545 if((count&0xfff) != ecount) {
546 netlog("******* bad count - got %ux expected %ux\n", count&0xfff, ecount);
552 /* netlog("ppp: mppc: frount flag set\n"); */
557 n = (((count+1)>>8)&0xf) - (((s->count+1)>>8)&0xf);
560 //netlog("mppc count = %ux oldcount %ux n = %d\n", count, s->count, n);
562 syslog(0, "ppp", ": mppc bad count %ux, %ux", count, s->count);
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);
577 if(count & Pencrypt) {
578 //netlog("mppc unencrypt count = %ux\n", count);
579 rc4(&s->rc4key, p, n);
582 if(!(count & Pcompress)) {
583 //netlog("uncompress blen = %d\n", BLEN(b));
589 hs = s->his; /* history start */
590 hp = hs+s->indx; /* write pointer in history */
591 he = hs+sizeof(s->his); /* hsitory end */
597 t = decode[(sreg>>(bits-4))&0xf];
600 sysfatal("mppc: bad decode!");
607 c = (sreg>>(bits-7))&0x7f;
609 if(hp >= he) goto His;
611 /* netlog("\tlit7 %.2ux\n", c); */
619 c = 0x80 | ((sreg>>(bits-7))&0x7f);
621 if(hp >= he) goto His;
623 /* netlog("\tlit8 %.2ux\n", c); */
631 off = (sreg>>(bits-6))&0x3f;
640 off = ((sreg>>(bits-8))&0xff)+64;
649 off = ((sreg>>(bits-13))&0x1fff)+320;
651 /* netlog("\toff=%d bits = %d sreg = %ux t = %x\n", off, bits, sreg, t); */
654 for(ones=0;;ones++) {
660 if(!(sreg&(1<<bits)))
664 netlog("ppp: mppc: bad length %d\n", ones);
676 len = (1<<ones) | ((sreg>>(bits-ones))&((1<<ones)-1));
682 hq += sizeof(s->his);
683 if(hq-hs+len > s->size)
686 if(hp+len > he) goto His;
695 /* build up return block */
699 memmove(b->wptr, hq, len);
701 netlog("ppp: mppc: len %d bits = %d n=%d\n", len, bits, n);
704 if(s->indx > s->size)
709 netlog("*****unexpected end of data\n");
713 netlog("*****bad history\n");
719 uncresetack(void*, Block*)
733 setkey(uchar *key, uchar *startkey)
737 uchar digest[SHA1dlen];
739 s = sha1(startkey, 16, nil, nil);
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);
749 /* code to check if IP packet looks good */
751 typedef struct Iphdr Iphdr;
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 */
773 TCP_PKT = TCP_IPLEN+TCP_PHDRSIZE,
790 typedef struct UDPhdr UDPhdr;
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 */
800 uchar udpproto; /* Protocol */
801 uchar udpplen[2]; /* Header plus data length */
802 uchar udpsrc[4]; /* Ip source */
803 uchar udpdst[4]; /* Ip destination */
806 uchar udpsport[2]; /* Source port */
807 uchar udpdport[2]; /* Destination port */
808 uchar udplen[2]; /* data length */
809 uchar udpcksum[2]; /* Checksum */
812 typedef struct TCPhdr TCPhdr;
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 */
833 /* Options segment */
839 hischeck(Uncstate *s)
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");
854 netlog("off = %zd ", p-s->his);
856 len = nhgets(iph->length);
864 ipcheck(uchar *p, int len)
875 memmove(bp->wptr, p, len);
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); */
883 if(len != nhgets(iph->length)) {
884 netlog("***** bad length! %d %d\n", len, nhgets(iph->length));
888 cksum = ipcsum(&iph->vihl);
890 netlog("***** IP proto cksum!!! %I %ux\n", iph->src, cksum);
899 tcph = (TCPhdr*)(bp->rptr);
901 length = nhgets(tcph->length);
904 hnputs(tcph->tcplen, length-TCP_PKT);
905 cksum = ptclcsum(bp, TCP_IPLEN, length-TCP_IPLEN);
907 netlog("***** bad tcp proto cksum %ux!!!\n", cksum);
912 uh = (UDPhdr*)(bp->rptr);
914 /* Put back pseudo header for checksum */
916 len = nhgets(uh->udplen);
917 hnputs(uh->udpplen, len);
919 if(nhgets(uh->udpcksum)) {
920 cksum = ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE);
922 netlog("***** udp: proto cksum!!! %I %ux\n", uh->udpsrc, cksum);