📄 pptp.c
字号:
/* * Point-to-point Tunneling Protocol (PPTP) * See RFC 2637, pptpd.c */#include <u.h>#include <libc.h>#include <bio.h>#include <ip.h>#include <thread.h>int ack;int alarmed;int ctlechotime;int ctlfd;int ctlrcvtime;int debug;int grefd;uchar localip[IPaddrlen];int localwin;char *keyspec;int now;char *pppnetmntpt;int pid;Channel *pidchan;int pppfd;int primary;int rack;Channel *rdchan;int rdexpect;int remid;uchar remoteip[IPaddrlen];int remwin;int rseq;int seq;char tcpdir[40];Channel *tickchan;int topppfd;int aread(int, int, void*, int);int catchalarm(void*, char*);void dumpctlpkt(uchar*);void getaddrs(void);void *emalloc(long);void ewrite(int, void*, int);void myfatal(char*, ...);#pragma varargck argpos myfatal 1int pptp(char*);void pushppp(int);void recordack(int);int schedack(int, uchar*, int);void waitacks(void);voidusage(void){ fprint(2, "usage: ip/pptp [-Pd] [-s user:secret] [-x pppnetmntpt] [-w window] server\n"); exits("usage");}voidthreadmain(int argc, char **argv){ int fd; ARGBEGIN{ case 'P': primary = 1; break; case 'd': debug++; break; case 'k': keyspec = EARGF(usage()); break; case 'w': localwin = atoi(EARGF(usage())); break; case 'x': pppnetmntpt = EARGF(usage()); break; default: usage(); }ARGEND if(argc != 1) usage(); fmtinstall('E', eipfmt); fmtinstall('I', eipfmt); rfork(RFNOTEG); atnotify(catchalarm, 1); fd = pptp(argv[0]); pushppp(fd); exits(nil);}intcatchalarm(void *a, char *msg){ USED(a); if(strstr(msg, "alarm")){ alarmed = 1; return 1; } if(debug) fprint(2, "note rcved: %s\n", msg); return 0;}enum { Stack = 8192, PptpProto = 0x0100, Magic = 0x1a2b3c4d, Window = 16, /* default window size */ Timeout = 60, /* timeout in seconds for control channel */ Pktsize = 2000, /* maximum packet size */ Tick = 500, /* tick length in milliseconds */ Sendtimeout = 4, /* in ticks */ Servertimeout = 5*60*1000/Tick, Echointerval = 60*1000/Tick,};enum { Syncframe = 0x1, Asyncframe = 0x2, Analog = 0x1, Digital = 0x2, Version = 0x100,};enum { Tstart = 1, Rstart = 2, Tstop = 3, Rstop = 4, Techo = 5, Recho = 6, Tcallout = 7, Rcallout = 8, Tcallreq = 9, Rcallreq = 10, Acallcon = 11, Tcallclear = 12, Acalldis = 13, Awaninfo = 14, Alinkinfo = 15,};voidrecho(uchar *in){ uchar out[20]; if(nhgets(in) < 16) return; memset(out, 0, sizeof out); hnputs(out, sizeof out); hnputs(out+2, 1); hnputl(out+4, Magic); hnputs(out+8, Recho); memmove(out+12, in+12, 4); out[16] = 1; ewrite(ctlfd, out, sizeof out);}voidsendecho(void){ uchar out[16]; ctlechotime = now; memset(out, 0, sizeof out); hnputs(out, sizeof out); hnputs(out+2, 1); hnputl(out+4, Magic); hnputs(out+8, Techo); ewrite(ctlfd, out, sizeof out);}voidpptpctlproc(void*){ uchar pkt[1600], *p; int len; for(;;){ if(readn(ctlfd, pkt, 2) != 2) myfatal("pptpread: %r"); len = nhgets(pkt); if(len < 12) myfatal("pptpread: bad length %d", len); if(readn(ctlfd, pkt+2, len-2) != len-2) myfatal("pptpread: %r"); if(nhgetl(pkt+4) != Magic) myfatal("pptpread bad magic"); if(nhgets(pkt+2) != 1) myfatal("pptpread bad message type"); if(debug) dumpctlpkt(pkt); ctlrcvtime = now; switch(nhgets(pkt+8)){ case Tstart: case Tstop: case Tcallout: case Tcallreq: case Tcallclear: case Acallcon: case Acalldis: case Awaninfo: myfatal("unexpected msg type %d", nhgets(pkt+8)); case Techo: recho(pkt); break; case Recho: break; case Rstart: case Rstop: case Rcallout: case Rcallreq: if(rdexpect != nhgets(pkt+8)) continue; p = emalloc(len); memmove(p, pkt, len); sendp(rdchan, p); break; case Alinkinfo: myfatal("cannot change ppp params on the fly"); } }}enum { Seqnum = 0x1000, Acknum = 0x0080, GrePPP = 0x880B,};voidgrereadproc(void*){ int datoff, flags, len, n, pass; uchar pkt[1600]; uchar src[IPaddrlen], dst[IPaddrlen]; rfork(RFFDG); close(pppfd); sendul(pidchan, getpid()); while((n = read(grefd, pkt, sizeof pkt)) > 0){ if(n == sizeof pkt) myfatal("gre pkt buffer too small"); if(n < 16){ if(debug) fprint(2, "small pkt len %d ignored\n", n); continue; } v4tov6(src, pkt); v4tov6(dst, pkt+4); if(ipcmp(src, remoteip) != 0 || ipcmp(dst, localip) != 0) myfatal("%I: gre read bad address src=%I dst=%I", remoteip, src, dst); if(nhgets(pkt+10) != GrePPP) myfatal("%I: gre read bad protocol 0x%x", remoteip, nhgets(pkt+10)); flags = nhgets(pkt+8); if((flags&0xEF7F) != 0x2001){ if(debug) fprint(2, "bad flags in gre hdr 0x%x\n", flags); continue; } datoff = 8+8; pass = 0; len = nhgets(pkt+8+4); if(len > n-datoff){ fprint(2, "bad payload length %d > %d\n", len, n-datoff); continue; } if(flags&Seqnum) datoff += 4; if(flags&Acknum){ recordack(nhgetl(pkt+datoff)); datoff += 4; } if(flags&Seqnum) pass = schedack(nhgetl(pkt+8+8), pkt+datoff, len); if(debug) fprint(2, "got gre callid %d len %d flag 0x%x pass %d seq %d rseq %d\n", nhgets(pkt+8+6), len, flags, pass, nhgetl(pkt+8+8), rseq); } threadexits(nil);}voidpppreadproc(void*){ int n, myrseq; uchar pkt[1600]; enum { Hdr = 8+16, }; rfork(RFFDG); close(pppfd); sendul(pidchan, getpid()); while((n = read(topppfd, pkt+Hdr, sizeof pkt-Hdr)) > 0){ if(n == sizeof pkt-Hdr) myfatal("ppp pkt buffer too small"); v6tov4(pkt+0, localip); v6tov4(pkt+4, remoteip); hnputs(pkt+8, 0x2001 | Seqnum | Acknum); hnputs(pkt+10, GrePPP); hnputs(pkt+12, n); hnputs(pkt+14, remid); hnputl(pkt+16, ++seq); myrseq = rseq; hnputl(pkt+20, myrseq); rack = myrseq; if(debug) fprint(2, "wrote gre callid %d len %d flag 0x%x seq %d rseq %d\n", nhgets(pkt+8+6), n, nhgets(pkt+8), nhgetl(pkt+16), nhgetl(pkt+20)); if(write(grefd, pkt, n+Hdr) != n+Hdr) myfatal("gre write: %r"); waitacks(); } threadexits(nil);}voidsendack(void){ int myrseq; uchar pkt[20]; v6tov4(pkt+0, localip); v6tov4(pkt+4, remoteip); hnputs(pkt+8, 0x2001 | Acknum); hnputs(pkt+10, GrePPP); hnputs(pkt+12, 0); hnputs(pkt+14, remid); myrseq = rseq; rack = myrseq; hnputs(pkt+16, myrseq); if(write(grefd, pkt, sizeof pkt) != sizeof pkt) myfatal("gre write: %r");}intschedack(int n, uchar *dat, int len){ static uchar sdat[1600]; static int srseq, slen; if(n-rseq <= 0){ fprint(2, "skipping pkt %d len %d, have %d\n", n, len, rseq); return 0; } /* missed one pkt, maybe a swap happened, save pkt */ if(n==rseq+2){ memmove(sdat, dat, len); slen = len; srseq = n; return 0; } if(n-rseq > 1){ if(slen && srseq == n-1){ fprint(2, "reswapped pkts %d and %d\n", srseq, n); write(topppfd, sdat, slen); slen = 0; }else fprint(2, "missed pkts %d-%d, got %d len %d\n", rseq+1, n-1, n, len); } write(topppfd, dat, len); rseq = n; /* send ack if we haven't recently */ if((int)(rseq-rack) > (localwin>>1)) sendack(); return 1;}voidgretimeoutproc(void*){ for(;;){ sleep(Tick); now++; nbsendul(tickchan, now); if(now - ctlrcvtime > Servertimeout) myfatal("server timeout"); if(now - ctlechotime > Echointerval) sendecho(); }}voidrecordack(int n){ ack = n;}voidwaitacks(void){/* int start; start = now; while(seq-ack > remwin && now-start < Sendtimeout){ print("seq %d ack %d remwin %d now %d start %d\n", seq, ack, remwin, now, start); recvul(tickchan); }*/}voidtstart(void){ char *name; uchar pkt[200], *rpkt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -