📄 ppp.c
字号:
av[0] = "dns"; av[1] = "wins"; sprint(ip, "%I", ppp->local); t = csipinfo(ppp->net, "ip", ip, av, 2); ndns = nwins = 0; for(nt = t; nt != nil; nt = nt->entry){ if(strcmp(nt->attr, "dns") == 0){ if(ndns < 2) parseip(ppp->dns[ndns++], nt->val); } else if(strcmp(nt->attr, "wins") == 0){ if(nwins < 2) parseip(ppp->wins[nwins++], nt->val); } } if(t != nil) ndbfree(t);}/* * parse configuration request, sends an ack or reject packet * * returns: -1 if request was syntacticly incorrect * 0 if packet was accepted * 1 if packet was rejected */static intgetopts(PPP *ppp, Pstate *p, Block *b){ Lcpmsg *m, *repm; Lcpopt *o; uchar *cp, *ap; ulong rejecting, nacking, flags, proto, chapproto; ulong mtu, ctlmap, period; ulong x; Block *repb; Comptype *ctype; Ipaddr ipaddr; rejecting = 0; nacking = 0; flags = 0; /* defaults */ invalidate(ipaddr); mtu = ppp->mtu; ctlmap = 0xffffffff; period = 0; ctype = nil; chapproto = 0; m = (Lcpmsg*)b->rptr; repb = alloclcp(Lconfack, m->id, BLEN(b), &repm); /* copy options into ack packet */ memmove(repm->data, m->data, b->wptr - m->data); repb->wptr += b->wptr - m->data; /* look for options we don't recognize or like */ for(cp = m->data; cp < b->wptr; cp += o->len){ o = (Lcpopt*)cp; if(cp + o->len > b->wptr || o->len==0){ freeb(repb); netlog("ppp: bad option length %ux\n", o->type); return -1; } switch(p->proto){ case Plcp: switch(o->type){ case Oac: flags |= Fac; continue; case Opc: flags |= Fpc; continue; case Omtu: mtu = nhgets(o->data); continue; case Omagic: if(ppp->magic == nhgetl(o->data)) netlog("ppp: possible loop\n"); continue; case Octlmap: ctlmap = nhgetl(o->data); continue; case Oquality: proto = nhgets(o->data); if(proto != Plqm) break; x = nhgetl(o->data+2)*10; period = (x+Period-1)/Period; continue; case Oauth: proto = nhgets(o->data); if(proto == Ppasswd && !server){ chapproto = APpasswd; continue; } if(proto != Pchap) break; if(o->data[2] != APmd5 && o->data[2] != APmschap) break; chapproto = o->data[2]; continue; } break; case Pccp: if(nocompress) break; switch(o->type){ case Octhwack: break; /* if(o->len == 2){ ctype = &cthwack; continue; } if(!nacking){ nacking = 1; repb->wptr = repm->data; repm->code = Lconfnak; } puto(repb, Octhwack); continue; */ case Ocmppc: x = nhgetl(o->data); // hack for Mac // if(x == 0) // continue; /* stop ppp loops */ if((x&0x41) == 0 || ppp->ctries++ > 5) { /* * turn off requests as well - I don't think this * is needed in the standard */ p->optmask &= ~Fcmppc; break; } if(rejecting) continue; if(x & 1) { ctype = &cmppc; ppp->sendencrypted = (o->data[3]&0x40) == 0x40; continue; } if(!nacking){ nacking = 1; repb->wptr = repm->data; repm->code = Lconfnak; } *repb->wptr++ = Ocmppc; *repb->wptr++ = 6; *repb->wptr++ = 0; *repb->wptr++ = 0; *repb->wptr++ = 0; *repb->wptr++ = 0x41; continue; } break; case Pipcp: switch(o->type){ case Oipaddr: v4tov6(ipaddr, o->data); if(!validv4(ppp->remote)) continue; if(!validv4(ipaddr) && !rejecting){ /* other side requesting an address */ if(!nacking){ nacking = 1; repb->wptr = repm->data; repm->code = Lconfnak; } putv4o(repb, Oipaddr, ppp->remote); } continue; case Oipdns: ap = ppp->dns[0]; goto ipinfo; case Oipdns2: ap = ppp->dns[1]; goto ipinfo; case Oipwins: ap = ppp->wins[0]; goto ipinfo; case Oipwins2: ap = ppp->wins[1]; goto ipinfo; ipinfo: if(!validv4(ap)) getipinfo(ppp); if(!validv4(ap)) break; v4tov6(ipaddr, o->data); if(!validv4(ipaddr) && !rejecting){ /* other side requesting an address */ if(!nacking){ nacking = 1; repb->wptr = repm->data; repm->code = Lconfnak; } putv4o(repb, o->type, ap); } continue; case Oipcompress: /* * don't compress tcp header if we've negotiated data compression. * tcp header compression has very poor performance if there is an error. */ proto = nhgets(o->data); if(noipcompress || proto != Pvjctcp || ppp->ctype != nil) break; if(compress_negotiate(ppp->ctcp, o->data+2) < 0) break; flags |= Fipcompress; continue; } break; } /* come here if option is not recognized */ if(!rejecting){ rejecting = 1; repb->wptr = repm->data; repm->code = Lconfrej; } netlog("ppp: bad %ux option %d\n", p->proto, o->type); memmove(repb->wptr, o, o->len); repb->wptr += o->len; } /* permanent changes only after we know that we liked the packet */ if(!rejecting && !nacking){ switch(p->proto){ case Plcp: ppp->period = period; ppp->xctlmap = ctlmap; if(mtu > Maxmtu) mtu = Maxmtu; if(mtu < Minmtu) mtu = Minmtu; ppp->mtu = mtu; if(chapproto) ppp->chap->proto = chapproto; break; case Pccp: if(ppp->ctype != nil){ (*ppp->ctype->fini)(ppp->cstate); ppp->cstate = nil; } ppp->ctype = ctype; if(ctype) ppp->cstate = (*ctype->init)(ppp); break; case Pipcp: if(validv4(ipaddr) && ppp->remotefrozen == 0) ipmove(ppp->remote, ipaddr); break; } p->flags = flags; } hnputs(repm->len, BLEN(repb)); printopts(p, repb, 1); putframe(ppp, p->proto, repb); freeb(repb); return rejecting || nacking;}static voiddmppkt(char *s, uchar *a, int na){ int i; if (debug < 3) return; fprint(2, "%s", s); for(i = 0; i < na; i++) fprint(2, " %.2ux", a[i]); fprint(2, "\n");}static voiddropoption(Pstate *p, Lcpopt *o){ unsigned n = o->type; switch(n){ case Oipdns: p->optmask &= ~Fipdns; break; case Oipwins: p->optmask &= ~Fipwins; break; case Oipdns2: p->optmask &= ~Fipdns2; break; case Oipwins2: p->optmask &= ~Fipwins2; break; default: if(o->type < 8*sizeof(p->optmask)) p->optmask &= ~(1<<o->type); break; }}/* * parse configuration rejection, just stop sending anything that they * don't like (except for ipcp address nak). */static voidrejopts(PPP *ppp, Pstate *p, Block *b, int code){ Lcpmsg *m; Lcpopt *o; uchar newip[IPaddrlen]; /* just give up trying what the other side doesn't like */ m = (Lcpmsg*)b->rptr; for(b->rptr = m->data; b->rptr < b->wptr; b->rptr += o->len){ o = (Lcpopt*)b->rptr; if(b->rptr + o->len > b->wptr){ netlog("ppp: bad roption length %ux\n", o->type); return; } if(code == Lconfrej){ dropoption(p, o); netlog("ppp: %ux rejecting %d\n", p->proto, o->type); continue; } switch(p->proto){ case Plcp: switch(o->type){ case Octlmap: ppp->rctlmap = nhgetl(o->data); break; case Oauth: /* don't allow client to request no auth */ /* could try different auth protocol here */ fprint(2, "ppp: can not reject CHAP\n"); exits("ppp: CHAP"); break; default: if(o->type < 8*sizeof(p->optmask)) p->optmask &= ~(1<<o->type); break; }; break; case Pccp: switch(o->type){ default: dropoption(p, o); break; } break; case Pipcp: switch(o->type){ case Oipaddr:syslog(0, "ppp", "rejected addr %I with %V", ppp->local, o->data); /* if we're a server, don't let other end change our addr */ if(ppp->localfrozen){ dropoption(p, o); break; } /* accept whatever server tells us */ if(!validv4(ppp->local)){ v4tov6(ppp->local, o->data); dropoption(p, o); break; } /* if he didn't like our addr, ask for a generic one */ v4tov6(newip, o->data); if(!validv4(newip)){ invalidate(ppp->local); break; } /* if he gives us something different, use it anyways */ v4tov6(ppp->local, o->data); dropoption(p, o); break; case Oipdns: if (!validv4(ppp->dns[0])){ v4tov6(ppp->dns[0], o->data); dropoption(p, o); break; } v4tov6(newip, o->data); if(!validv4(newip)){ invalidate(ppp->dns[0]); break; } v4tov6(ppp->dns[0], o->data); dropoption(p, o); break; case Oipwins: if (!validv4(ppp->wins[0])){ v4tov6(ppp->wins[0], o->data); dropoption(p, o); break; } v4tov6(newip, o->data); if(!validv4(newip)){ invalidate(ppp->wins[0]); break; } v4tov6(ppp->wins[0], o->data); dropoption(p, o); break; case Oipdns2: if (!validv4(ppp->dns[1])){ v4tov6(ppp->dns[1], o->data); dropoption(p, o); break; } v4tov6(newip, o->data); if(!validv4(newip)){ invalidate(ppp->dns[1]); break; } v4tov6(ppp->dns[1], o->data); dropoption(p, o); break; case Oipwins2: if (!validv4(ppp->wins[1])){ v4tov6(ppp->wins[1], o->data); dropoption(p, o); break; } v4tov6(newip, o->data); if(!validv4(newip)){ invalidate(ppp->wins[1]); break; } v4tov6(ppp->wins[1], o->data); dropoption(p, o); break; default: dropoption(p, o); break; } break; } }}/* * put a messages through the lcp or ipcp state machine. They are * very similar. */static voidrcv(PPP *ppp, Pstate *p, Block *b){ ulong len; int err; Lcpmsg *m; int proto; if(BLEN(b) < 4){ netlog("ppp: short lcp message\n"); freeb(b); return; } m = (Lcpmsg*)b->rptr; len = nhgets(m->len); if(BLEN(b) < len){ netlog("ppp: short lcp message\n"); freeb(b); return; } netlog("ppp: %ux rcv %d len %ld id %d/%d/%d\n", p->proto, m->code, len, m->id, p->confid, p->id); if(p->proto != Plcp && ppp->lcp->state != Sopened){ netlog("ppp: non-lcp with lcp not open\n"); freeb(b); return; } qlock(ppp); switch(m->code){ case Lconfreq: printopts(p, b, 0); err = getopts(ppp, p, b); if(err < 0) break; if(m->id == p->rcvdconfid) break; /* don't change state for duplicates */ switch(p->state){ case Sackrcvd: if(err) break; newstate(ppp, p, Sopened); break; case Sclosed: case Sopened: config(ppp, p, 1); if(err == 0) newstate(ppp, p, Sacksent); else newstate(ppp, p, Sreqsent); break; case Sreqsent: case Sacksent: if(err == 0) newstate(ppp, p, Sacksent); else newstate(ppp, p, Sreqsent); break; } break; case Lconfack: if(p->confid != m->id){ /* ignore if it isn't the message we're sending */ netlog("ppp: dropping confack\n"); break; } p->confid = -1; /* ignore duplicates */ p->id++; /* avoid sending duplicates */ netlog("ppp: recv confack\n"); switch(p->state){ case Sopened: case Sackrcvd: config(ppp, p, 1); newstate(ppp, p, Sreqsent); break; case Sreqsent: newstate(ppp, p, Sackrcvd); break; case Sacksent: newstate(ppp, p, Sopened); break; } break; case Lconfrej: case Lconfnak: if(p->confid != m->id) { /* ignore if it isn't the message we're sending */ netlog("ppp: dropping confrej or confnak\n"); break; } p->confid = -1; /* ignore duplicates */ p->id++; /* avoid sending duplicates */ switch(p->state){ case Sopened: case Sackrcvd: config(ppp, p, 1); newstate(ppp, p, Sreqsent); break; case Sreqsent: case Sacksent: printopts(p, b, 0); rejopts(ppp, p, b, m->code); config(ppp, p, 1); break; } break; case Ltermreq: m->code = Ltermack; putframe(ppp, p->proto, b); switch(p->state){ case Sackrcvd: case Sacksent: newstate(ppp, p, Sreqsent); break; case Sopened: newstate(ppp, p, Sclosing); break; } break; case Ltermack: if(p->termid != m->id) /* ignore if it isn't the message we're sending */ break; if(p->proto == Plcp) ppp->ipcp->state = Sclosed; switch(p->state){ case Sclosing: newstate(ppp, p, Sclosed); break; case Sackrcvd: newstate(ppp, p, Sreqsent); break; case Sopened: config(ppp, p, 0); newstate(ppp, p, Sreqsent); break; } break; case Lcoderej: //newstate(ppp, p, Sclosed); syslog(0, LOG, "code reject %d\n", m->data[0]); break; case Lprotorej: proto = nhgets(m->data); netlog("ppp: proto reject %ux\n", proto); if(proto == Pccp) newstate(ppp, ppp->ccp, Sclosed); break; case Lechoreq: if(BLEN(b) < 8){ netlog("ppp: short lcp echo request\n"); freeb(b); return; } m->code = Lechoack; hnputl(m->data, ppp->magic); putframe(ppp, p->proto, b); break; case Lechoack: p->echoack = 1; break; case Ldiscard: /* nothing to do */ break; case Lresetreq: if(p->proto != Pccp) break; ppp->stat.compreset++; if(ppp->ctype != nil) b = (*ppp->ctype->resetreq)(ppp->cstate, b); if(b != nil) { m = (Lcpmsg*)b->rptr; m->code = Lresetack; putframe(ppp, p->proto, b); } break; case Lresetack: if(p->proto != Pccp) break; if(ppp->unctype != nil) (*ppp->unctype->resetack)(ppp->uncstate, b); break; } qunlock(ppp); freeb(b);}/* * timer for protocol state machine */static voidptimer(PPP *ppp, Pstate *p){ if(p->state == Sopened || p->state == Sclosed) return; p->timeout--; switch(p->state){ case Sclosing: sendtermreq(ppp, p); break; case Sreqsent: case Sacksent: if(p->timeout <= 0) newstate(ppp, p, Sclosed); else { config(ppp, p, 0); } break; case Sackrcvd: if(p->timeout <= 0) newstate(ppp, p, Sclosed); else { config(ppp, p, 0); newstate(ppp, p, Sreqsent); } break; }}/* paptimer -- pap timer event handler * * If PAP authorization hasn't come through, resend an authreqst. If * the maximum number of requests have been sent (~ 30 seconds), give * up. * */static voidauthtimer(PPP* ppp){ if(ppp->chap->proto != APpasswd) return; if(ppp->chap->id < 21) putpaprequest(ppp); else { terminate(ppp, 0); netlog("ppp: pap timed out--not authorized\n"); }}/* * timer for ppp */static voidppptimer(PPP *ppp){ while(!dying){ sleep(Period); qlock(ppp); netlog("ppp: ppptimer\n"); ptimer(ppp, ppp->lcp); if(ppp->lcp->state == Sopened) { switch(ppp->phase){ case Pnet: ptimer(ppp, ppp->ccp); ptimer(ppp, ppp->ipcp); break; case Pauth: authtimer(ppp); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -