📄 ppp.c
字号:
} } /* link quality measurement */ if(ppp->period && --(ppp->timeout) <= 0){ ppp->timeout = ppp->period; putlqm(ppp); } qunlock(ppp); }}static voidsetdefroute(char *net, Ipaddr gate){ int fd; char path[128]; snprint(path, sizeof path, "%s/iproute", net); fd = open(path, ORDWR); if(fd < 0) return; fprint(fd, "add 0 0 %I", gate); close(fd);}enum{ Mofd= 32,};struct{ Lock; int fd[Mofd]; int cfd[Mofd]; int n;} old;static char*ipopen(PPP *ppp){ static int ipinprocpid; int n, cfd, fd; char path[128]; char buf[128]; if(ipinprocpid <= 0){ snprint(path, sizeof path, "%s/ipifc/clone", ppp->net); cfd = open(path, ORDWR); if(cfd < 0) return "can't open ip interface"; n = read(cfd, buf, sizeof(buf) - 1); if(n <= 0){ close(cfd); return "can't open ip interface"; } buf[n] = 0; netlog("ppp: setting up IP interface local %I remote %I (valid %d)\n", ppp->local, ppp->remote, validv4(ppp->remote)); if(!validv4(ppp->remote)) ipmove(ppp->remote, ppp->local); snprint(path, sizeof path, "%s/ipifc/%s/data", ppp->net, buf); fd = open(path, ORDWR); if(fd < 0){ close(cfd); return "can't open ip interface"; } if(fprint(cfd, "bind pkt") < 0) return "binding pkt to ip interface"; if(fprint(cfd, "add %I 255.255.255.255 %I %lud proxy", ppp->local, ppp->remote, ppp->mtu-10) < 0){ close(cfd); return "can't set addresses"; } if(primary) setdefroute(ppp->net, ppp->remote); ppp->ipfd = fd; ppp->ipcfd = cfd; /* signal main() that ip is configured */ rendezvous((void*)Rmagic, 0); switch(ipinprocpid = rfork(RFPROC|RFMEM|RFNOWAIT)){ case -1: sysfatal("forking ipinproc"); case 0: ipinproc(ppp); terminate(ppp, 1); _exits(0); } } else { /* we may have changed addresses */ if(ipcmp(ppp->local, ppp->curlocal) != 0 || ipcmp(ppp->remote, ppp->curremote) != 0){ snprint(buf, sizeof buf, "remove %I 255.255.255.255 %I", ppp->curlocal, ppp->curremote); if(fprint(ppp->ipcfd, "%s", buf) < 0) syslog(0, "ppp", "can't %s: %r", buf); snprint(buf, sizeof buf, "add %I 255.255.255.255 %I %lud proxy", ppp->local, ppp->remote, ppp->mtu-10); if(fprint(ppp->ipcfd, "%s", buf) < 0) syslog(0, "ppp", "can't %s: %r", buf); } syslog(0, "ppp", "%I/%I -> %I/%I", ppp->curlocal, ppp->curremote, ppp->local, ppp->remote); } ipmove(ppp->curlocal, ppp->local); ipmove(ppp->curremote, ppp->remote); return nil;}/* return next input IP packet */Block*pppread(PPP *ppp){ Block *b, *reply; int proto, len; Lcpmsg *m; while(!dying){ b = getframe(ppp, &proto); if(b == nil) return nil;Again: switch(proto){ case Plcp: rcv(ppp, ppp->lcp, b); break; case Pccp: rcv(ppp, ppp->ccp, b); break; case Pipcp: rcv(ppp, ppp->ipcp, b); break; case Pip: if(ppp->ipcp->state == Sopened) return b; netlog("ppp: IP recved: link not up\n"); freeb(b); break; case Plqm: getlqm(ppp, b); break; case Pchap: getchap(ppp, b); break; case Ppasswd: getpap(ppp, b); break; case Pvjctcp: case Pvjutcp: if(ppp->ipcp->state != Sopened){ netlog("ppp: VJ tcp recved: link not up\n"); freeb(b); break; } ppp->stat.vjin++; b = tcpuncompress(ppp->ctcp, b, proto); if(b != nil) return b; ppp->stat.vjfail++; break; case Pcdata: ppp->stat.uncomp++; if(ppp->ccp->state != Sopened){ netlog("ppp: compressed data recved: link not up\n"); freeb(b); break; } if(ppp->unctype == nil) { netlog("ppp: compressed data recved: no compression\n"); freeb(b); break; } len = BLEN(b); b = (*ppp->unctype->uncompress)(ppp, b, &proto, &reply); if(reply != nil){ /* send resetreq */ ppp->stat.uncompreset++; putframe(ppp, Pccp, reply); freeb(reply); } if(b == nil) break; ppp->stat.uncompin += len; ppp->stat.uncompout += BLEN(b);/* netlog("ppp: uncompressed frame %ux %d %d (%d uchars)\n", proto, b->rptr[0], b->rptr[1], BLEN(b)); /* */ goto Again; default: syslog(0, LOG, "unknown proto %ux", proto); if(ppp->lcp->state == Sopened){ /* reject the protocol */ b->rptr -= 6; m = (Lcpmsg*)b->rptr; m->code = Lprotorej; m->id = ++ppp->lcp->id; hnputs(m->data, proto); hnputs(m->len, BLEN(b)); putframe(ppp, Plcp, b); } freeb(b); break; } } return nil;}/* transmit an IP packet */intpppwrite(PPP *ppp, Block *b){ int proto; int len; qlock(ppp); /* can't send ip packets till we're established */ if(ppp->ipcp->state != Sopened) { qunlock(ppp); syslog(0, LOG, "IP write: link not up"); len = blen(b); freeb(b); return len; } proto = Pip; ppp->stat.ipsend++; if(ppp->ipcp->flags & Fipcompress){ b = compress(ppp->ctcp, b, &proto); if(b == nil){ qunlock(ppp); return 0; } if(proto != Pip) ppp->stat.vjout++; } if(ppp->ctype != nil) { len = blen(b); b = (*ppp->ctype->compress)(ppp, proto, b, &proto); if(proto == Pcdata) { ppp->stat.comp++; ppp->stat.compin += len; ppp->stat.compout += blen(b); } } if(putframe(ppp, proto, b) < 0) { qunlock(ppp); freeb(b); return -1; } qunlock(ppp); len = blen(b); freeb(b); return len;}static voidterminate(PPP *ppp, int kill){ close(ppp->ipfd); ppp->ipfd = -1; close(ppp->ipcfd); ppp->ipcfd = -1; close(ppp->mediain); close(ppp->mediaout); ppp->mediain = -1; ppp->mediaout = -1; dying = 1; if(kill) postnote(PNGROUP, getpid(), "die");}typedef struct Iphdr Iphdr;struct Iphdr{ uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ uchar id[2]; /* Identification */ uchar frag[2]; /* Fragment information */ uchar ttl; /* Time to live */ uchar proto; /* Protocol */ uchar cksum[2]; /* Header checksum */ uchar src[4]; /* Ip source (uchar ordering unimportant) */ uchar dst[4]; /* Ip destination (uchar ordering unimportant) */};static voidipinproc(PPP *ppp){ Block *b; int m, n; Iphdr *ip; while(!dying){ b = allocb(Buflen); n = read(ppp->ipfd, b->wptr, b->lim-b->wptr); if(n < 0) break; /* trim packet if there's padding (e.g. from ether) */ ip = (Iphdr*)b->rptr; m = nhgets(ip->length); if(m < n && m > 0) n = m; b->wptr += n; if(pppwrite(ppp, b) < 0) break; }}static voidcatchdie(void*, char *msg){ if(strstr(msg, "die") != nil) noted(NCONT); else noted(NDFLT);}static voidhexdump(uchar *a, int na){ int i; char buf[80]; fprint(2, "dump %p %d\n", a, na); buf[0] = '\0'; for(i=0; i<na; i++){ sprint(buf+strlen(buf), " %.2ux", a[i]); if(i%16 == 7) sprint(buf+strlen(buf), " --"); if(i%16==15){ sprint(buf+strlen(buf), "\n"); write(2, buf, strlen(buf)); buf[0] = '\0'; } } if(i%16){ sprint(buf+strlen(buf), "\n"); write(2, buf, strlen(buf)); }}static voidmediainproc(PPP *ppp){ Block *b; Ipaddr remote; notify(catchdie); while(!dying){ b = pppread(ppp); if(b == nil){ syslog(0, LOG, "pppread return nil"); break; } ppp->stat.iprecv++; if(ppp->ipcp->state != Sopened) { ppp->stat.iprecvnotup++; freeb(b); continue; } if(server) { v4tov6(remote, b->rptr+12); if(ipcmp(remote, ppp->remote) != 0) { ppp->stat.iprecvbadsrc++; freeb(b); continue; } } if(debug > 1){ netlog("ip write pkt %p %d\n", b->rptr, blen(b)); hexdump(b->rptr, blen(b)); } if(write(ppp->ipfd, b->rptr, blen(b)) < 0) { syslog(0, LOG, "error writing to pktifc"); freeb(b); break; } freeb(b); } netlog(": remote=%I: ppp shutting down\n", ppp->remote); syslog(0, LOG, ": remote=%I: ppp shutting down", ppp->remote); syslog(0, LOG, "\t\tppp send = %lud/%lud recv= %lud/%lud", ppp->out.packets, ppp->out.uchars, ppp->in.packets, ppp->in.uchars); syslog(0, LOG, "\t\tip send=%lud", ppp->stat.ipsend); syslog(0, LOG, "\t\tip recv=%lud notup=%lud badsrc=%lud", ppp->stat.iprecv, ppp->stat.iprecvnotup, ppp->stat.iprecvbadsrc); syslog(0, LOG, "\t\tcompress=%lud in=%lud out=%lud reset=%lud", ppp->stat.comp, ppp->stat.compin, ppp->stat.compout, ppp->stat.compreset); syslog(0, LOG, "\t\tuncompress=%lud in=%lud out=%lud reset=%lud", ppp->stat.uncomp, ppp->stat.uncompin, ppp->stat.uncompout, ppp->stat.uncompreset); syslog(0, LOG, "\t\tvjin=%lud vjout=%lud vjfail=%lud", ppp->stat.vjin, ppp->stat.vjout, ppp->stat.vjfail);}/* * link quality management */static voidgetlqm(PPP *ppp, Block *b){ Qualpkt *p; p = (Qualpkt*)b->rptr; if(BLEN(b) == sizeof(Qualpkt)){ ppp->in.reports++; ppp->pout.reports = nhgetl(p->peeroutreports); ppp->pout.packets = nhgetl(p->peeroutpackets); ppp->pout.uchars = nhgetl(p->peeroutuchars); ppp->pin.reports = nhgetl(p->peerinreports); ppp->pin.packets = nhgetl(p->peerinpackets); ppp->pin.discards = nhgetl(p->peerindiscards); ppp->pin.errors = nhgetl(p->peerinerrors); ppp->pin.uchars = nhgetl(p->peerinuchars); /* save our numbers at time of reception */ memmove(&ppp->sin, &ppp->in, sizeof(Qualstats)); } freeb(b); if(ppp->period == 0) putlqm(ppp);}static voidputlqm(PPP *ppp){ Qualpkt *p; Block *b; b = allocb(sizeof(Qualpkt)); b->wptr += sizeof(Qualpkt); p = (Qualpkt*)b->rptr; hnputl(p->magic, 0); /* heresay (what he last told us) */ hnputl(p->lastoutreports, ppp->pout.reports); hnputl(p->lastoutpackets, ppp->pout.packets); hnputl(p->lastoutuchars, ppp->pout.uchars); /* our numbers at time of last reception */ hnputl(p->peerinreports, ppp->sin.reports); hnputl(p->peerinpackets, ppp->sin.packets); hnputl(p->peerindiscards, ppp->sin.discards); hnputl(p->peerinerrors, ppp->sin.errors); hnputl(p->peerinuchars, ppp->sin.uchars); /* our numbers now */ hnputl(p->peeroutreports, ppp->out.reports+1); hnputl(p->peeroutpackets, ppp->out.packets+1); hnputl(p->peeroutuchars, ppp->out.uchars+53/*hack*/); putframe(ppp, Plqm, b); freeb(b); ppp->out.reports++;}/* * init challenge response dialog */static voidchapinit(PPP *ppp){ Block *b; Lcpmsg *m; Chap *c; int len; char *aproto; getauth(ppp); c = ppp->chap; c->id++; switch(c->proto){ default: abort(); case APmd5: aproto = "chap"; break; case APmschap: aproto = "mschap"; break; } if((c->cs = auth_challenge("proto=%q role=server", aproto)) == nil) sysfatal("auth_challenge: %r"); syslog(0, LOG, ": remote=%I: sending %d byte challenge", ppp->remote, c->cs->nchal); len = 4 + 1 + c->cs->nchal + strlen(ppp->chapname); b = alloclcp(Cchallenge, c->id, len, &m); *b->wptr++ = c->cs->nchal; memmove(b->wptr, c->cs->chal, c->cs->nchal); b->wptr += c->cs->nchal; memmove(b->wptr, ppp->chapname, strlen(ppp->chapname)); b->wptr += strlen(ppp->chapname); hnputs(m->len, len); putframe(ppp, Pchap, b); freeb(b); c->state = Cchalsent;}/* * BUG factotum should do this */enum { MShashlen = 16, MSresplen = 24, MSchallen = 8,};voiddesencrypt(uchar data[8], uchar key[7]){ ulong ekey[32]; key_setup(key, ekey); block_cipher(ekey, data, 0);}voidnthash(uchar hash[MShashlen], char *passwd){ uchar buf[512]; int i; for(i=0; *passwd && i<sizeof(buf); passwd++) { buf[i++] = *passwd; buf[i++] = 0; } memset(hash, 0, 16); md4(buf, i, hash, 0);}voidmschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]){ int i; uchar buf[21]; memset(buf, 0, sizeof(buf)); memcpy(buf, hash, MShashlen); for(i=0; i<3; i++) { memmove(resp+i*MSchallen, chal, MSchallen); desencrypt(resp+i*MSchallen, buf+i*7); }}/* * challenge response dialog */extern int _asrdresp(int, uchar*, int);static voidgetchap(PPP *ppp, Block *b){ AuthInfo *ai; Lcpmsg *m; int len, vlen, i, id, n, nresp; char md5buf[512], code; Chap *c; Chapreply cr; MSchapreply mscr; char uid[PATH]; uchar digest[16], *p, *resp, sdigest[SHA1dlen]; uchar mshash[MShashlen], mshash2[MShashlen]; DigestState *s; uchar msresp[2*MSresplen+1]; m = (Lcpmsg*)b->rptr; len = nhgets(m->len); if(BLEN(b) < len){ syslog(0, LOG, "short chap message"); freeb(b); return; } qlock(ppp); switch(m->code){ case Cchallenge: getauth(ppp); vlen = m->data[0]; if(vlen > len - 5) { netlog("PPP: chap: bad challenge len\n"); break; } id = m->id; switch(ppp->chap->proto){ default: abort(); case APmd5: md5buf[0] = m->id; strcpy(md5buf+1, ppp->secret); n = strlen(ppp->secret) + 1; memmove(md5buf+n, m->data+1, vlen); n += vlen; md5((uchar*)md5buf, n, digest, nil); resp = digest; nresp = 16; break; case APmschap: nthash(mshash, ppp->secret); memset(msresp, 0, sizeof msresp); mschalresp(msresp+MSresplen, mshash, m->data+1); resp = msresp; nresp = sizeof msresp; nthash(mshash, ppp->secret); md4(mshash, 16, mshash2, 0); s = sha1(mshash2, 16, 0, 0); sha1(mshash2, 16, 0, s); sha1(m->data+1, 8, sdigest, s); memmove(ppp->key, sdigest, 16); break; } len = 4 + 1 + nresp + strlen(ppp->chapname); freeb(b); b = alloclcp(Cresponse, id, len, &m); *b->wptr++ = nresp; memmove(b->wptr, resp, nresp); b->wptr += nresp; memmove(b->wptr, ppp->chapname, strlen(ppp->chapname)); b->wptr += strlen(ppp->chapname); hnputs(m->len, len); netlog("PPP: sending response len %d\n", len); putframe(ppp, Pchap, b); break; case Cresponse: c = ppp->chap; vlen = m->data[0]; if(m->id != c->id) { netlog("PPP: chap: bad response id\n"); break; } switch(c->proto) { default: sysfatal("unknown chap protocol: %d", c->proto); case APmd5: if(vlen > len - 5 || vlen != 16) { netlog("PPP: chap: bad response len\n"); break; } cr.id = m->id; memmove(cr.resp, m->data+1, 16); memset(uid, 0, sizeof(uid)); n = len-5-vlen; if(n >= PATH) n = PATH-1; memmove(uid, m->data+1+vlen, n); c->cs->user = uid; c->cs->resp = &cr; c->cs->nresp = sizeof cr; break; case APmschap: if(vlen > len - 5 || vlen != 49) { netlog("PPP: chap: bad response len\n"); break; } memset(&mscr, 0, sizeof(mscr)); memmove(mscr.LMresp, m->data+1, 24); memmove(mscr.NTresp, m->data+24+1, 24); n = len-5-vlen; p = m->data+1+vlen; /* remove domain name */ for(i=0; i<n; i++) { if(p[i] == '\\') { p += i+1; n -= i+1; break; } } if(n >= PATH) n = PATH-1; memset(uid, 0, sizeof(uid)); memmove(uid, p, n); c->cs->user = uid; c->cs->resp = 𝓂 c->cs->nresp = sizeof mscr; break; } syslog(0, LOG, ": remote=%I vlen %d proto %d response user %s nresp %d", ppp->remote, vlen, c->proto, c->cs->user, c->cs->nresp); if((ai = auth_response(c->cs)) == nil || auth_chuid(ai, nil) < 0){ c->state = Cunauth; code = Cfailure; syslog(0, LOG, ": remote=%I: auth failed: %r, uid=%s", ppp->remote, uid); }else{ c->state = Cauthok; code = Csuccess; syslog(0, LOG, ": remote=%I: auth ok: uid=%s nsecret=%d", ppp->remote, uid, ai->nsecret); if(c->proto == APmschap){ if(ai->nsecret != sizeof(ppp->key)) sysfatal("could not get the encryption key"); memmove(ppp->key, ai->secret, sizeof(ppp->key)); } } auth_freeAI(ai); auth_freechal(c->cs); c->cs = nil; freeb(b); /* send reply */ len = 4; b = alloclcp(code, c->id, len, &m); hnputs(m->len, len); putframe(ppp, Pchap, b);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -