📄 ciped.c
字号:
parameter. See output.c why. */ *OA(socks)=*OA(peer); *OA(peer)=a; } return fd;}/* Check whether the SOCKS5 server has closed the connection */const char * const eofsocks_str[] = { "no error", "exception", "read error", "EOF"};int eofsocks(int fd) { fd_set ifd, efd; struct timeval t={0,0}; FD_ZERO(&ifd); FD_ZERO(&efd); FD_SET(fd, &ifd); FD_SET(fd, &efd); if (select(fd+1, &ifd, NULL, &efd, &t)>0) { if (FD_ISSET(fd, &efd)) { return 1; } if (FD_ISSET(fd, &ifd)) { int e; char c; if ((e=read(fd, &c, 1))<=0) { return e<0 ? 2 : 3; } } } return 0;}/*** Signal handler. See also cipelib.h ***/void sighandnot(int s){ /* Dummy */}void sighandexit(int s){ /* exit parent */ exit(0);}/*** Control message handling ***/time_t pingtime=MAXINT, pongtime=MAXINT;void dprintct(const char *h, char c){ switch(c) { case CT_DUMMY: dprintf(("%s CT_DUMMY\n", h)); break; case CT_DEBUG: dprintf(("%s CT_DEBUG\n", h)); break; case CT_PING: dprintf(("%s CT_PING\n", h)); break; case CT_PONG: dprintf(("%s CT_PONG\n", h)); break; case CT_KILL: dprintf(("%s CT_KILL\n",h)); break; case CT_CONFREQ: dprintf(("%s CT_CONFREQ\n",h)); break; case CT_CONF: dprintf(("%s CT_CONF\n",h)); break; default: dprintf(("%s %d\n", h, c)); }}/* send a control */int sendctl(int f, const char *msg, int len, int v, int flags){ int e; dprintct("sending", msg[0]); if (OI(nokey)) return -1; /* unencrypted cant handle controls */ if ((e=send(f, msg, len, flags))<0) { if (v) Log(LOG_ERR, "sendctl: %m"); } return e;}/* handle control message */void ctrl(int f, char *msg, int len){ char buf[64]; struct confinfo *ci; if (OI(nokey)) return; /* unencrypted cant handle controls */ dprintct("received", msg[0]); switch (msg[0]) { case CT_DEBUG: /* Log it */ Log(LOG_NOTICE, "peer: %s", msg+1); /* fall thru */ case CT_DUMMY: break; case CT_PING: msg[0]=CT_PONG; sendctl(f, msg, len, 1, 0); break; case CT_PONG: pongtime=MAXINT; break; case CT_KILL: Log(LOG_NOTICE, "Shutting down at peer request %s", msg+1); gotsig=SIGHUP; break; case CT_CONFREQ:#ifndef DONT_SEND_CONF myconfinfo.cmd=CT_CONF; sendctl(f, (char *)&myconfinfo, sizeof(myconfinfo), 1, MSG_OOB);#endif /* fall thru */ case CT_CONF: ci=(struct confinfo *)msg; if (memcmp(&ci->magic, "CIPE", 4)) break; snprintf(buf, sizeof(buf), "proto=%d, crypto=%c, version=%d.%d, %s key parser", ci->protocol, ci->crypto, ci->swmaj, ci->swmin, ci->keyright?"correct":"broken"); Log(LOG_INFO, "peer configuration info: %s", buf);#define check(v,s) \ if (ci->v!=myconfinfo.v) \ Log(LOG_ERR, s " mismatch to peer, this will not work!\n"); check(protocol, "Protocol version"); check(crypto, "Cipher algorithm"); check(keyright, "Key parser"); break;#undef check default: Log(LOG_NOTICE, "unknown control %d", msg[0]); }}/*** The key exchange procedure ***/#define REM 256 /* How many keys to remember *//* Cache last valid key CRCs. */static int dupcheck(crc c){ static crc ca[REM]; static int caf=0, cal=0; int i; for (i=cal; i<caf; ++i) if (ca[i%REM]==c) return 1; if (caf-cal>=REM) if (++cal>REM) { caf-=REM; cal-=REM; } ca[caf%REM]=c; ++caf; return 0;}#define K_SUCCESS 1#define K_TIMEOUT 0#define K_HARDERR -1#define K_SOFTERR -2int kxchg(int f, int r){ int x=0, e=0; crc c; #define kx_typ (LM->kxbuf[0]) #define kx_nkind_key (LM->kxbuf+1) #define kx_ts ntohl(*(time_t *)(LM->kxbuf+KEYXCHGTSPOS)) #define get_kx_nkind_crc(x) memcpy((x), LM->kxbuf+1+userKeySize, 4) #define put_kx_nkind_crc(x) memcpy(LM->kxbuf+1+userKeySize, (x), 4) #define get_kx_nkack_crc(x) memcpy((x), LM->kxbuf+1, 4) #define put_kx_nkack_crc(x) memcpy(LM->kxbuf+1, (x), 4) if ((x=recv(f, LM->kxbuf, KEYXCHGBLKMIN, 0))<=0) { if (errno==EAGAIN || errno==EINTR) /* This is normal, would be even after select */ return K_TIMEOUT; Log(LOG_INFO, "kxchg: recv: %m"); if (errno==ENXIO) /* Device was closed */ return K_HARDERR; /* allow for some amount of ECONNREFUSED etc. */ return K_SOFTERR; }#if 0 hexdump(LM->kxbuf, x);#endif if (LM->kxbuf[0]>=CT_DUMMY) { LM->kxbuf[55]='\0'; /* max length of message */ ctrl(f, LM->kxbuf, x); return K_SUCCESS; } if (OI(tokxts) && (abs(time(0)-kx_ts)>OI(tokxts))) { Log(LOG_NOTICE, "KX: timestamp error: %02x %lx %x\n", kx_typ, time(0), kx_ts); return K_SUCCESS; } switch(kx_typ) { case NK_RREQ: kx_typ=NK_REQ; dprintf(("KX: [NK_RREQ] sending NK_REQ\n")); x=send(f, &LM->kxbuf, sizeof(LM->kxbuf), 0); e=errno; ++ks.rreq; break; case NK_REQ: kx_typ=NK_IND; if (read(r, &LM->skey, userKeySize)!=userKeySize) { Log(LOG_ERR, "kxchg: read(r): %m"); return K_HARDERR; } memcpy(kx_nkind_key, LM->skey, userKeySize); LM->scrc=htonl(crc32(0, LM->skey, userKeySize)); put_kx_nkind_crc(&LM->scrc); dprintf(("KX: [NK_REQ] sending NK_IND " CRCFORM "\n", LM->scrc)); x=send(f, &LM->kxbuf, sizeof(LM->kxbuf), 0); e=errno; LM->sio.which=KEY_INVAL+KEY_SEND; if (ioctl_setkey(f, device, &LM->sio)<0) Log(LOG_ERR, "setkey: %m"); ++ks.req; break; case NK_IND: get_kx_nkind_crc(&c); if ( crc32(0, kx_nkind_key, userKeySize)==ntohl(c) ) { if (dupcheck(c)) { dprintf(("KX: [NK_IND] duplicate\n")); ++ks.indb; } else { LM->sio.which=KEY_RECV; memcpy(&LM->sio.thekey, kx_nkind_key, userKeySize); LM->sio.keylen=userKeySize; if (ioctl_setkey(f, device, &LM->sio)<0) perror("setkey"); else { kx_typ=NK_ACK; put_kx_nkack_crc(&c); /* XX */ dprintf(("KX: [NK_IND] sending NK_ACK " CRCFORM "\n", c)); x=send(f, &LM->kxbuf, sizeof(LM->kxbuf), 0); e=errno; } ++ks.ind; } } else { dprintf(("KX: [NK_IND] invalid\n")); ++ks.indb; } break; case NK_ACK: get_kx_nkack_crc(&c); if (LM->scrc==c) { if (dupcheck(c)) { dprintf(("KX: [NK_ACK] duplicate\n")); ++ks.ackb; } else { LM->sio.which=KEY_SEND; memcpy(&LM->sio.thekey, &LM->skey, userKeySize); LM->sio.keylen=userKeySize; dprintf(("KX: [NK_ACK] got " CRCFORM "\n", LM->scrc)); if (ioctl_setkey(f, device, &LM->sio)<0) perror("setkey"); ++ks.ack; memset(&LM->skey, 0, sizeof(LM->skey)); } } else { dprintf(("KX: [NK_ACK] unknown " CRCFORM "\n", c)); ++ks.ackb; } break; default: dprintf(("KX: invalid type %02X\n", kx_typ)); ++ks.bogus; } memset(LM->kxbuf, 0, sizeof(LM->kxbuf)); if (x<0) { errno=e; Log(LOG_NOTICE, "kxchg: send: %m"); if (e==ENXIO) return K_HARDERR; return K_SOFTERR; } return K_SUCCESS;}#define M_SUCCESS 1#define M_SOFTERR 0#define M_HARDERR -1int mainloop(int fd, int sd, int ur){ int i, j; time_t t; while (1) { i=kxchg(fd, ur); if (i==K_HARDERR) return M_HARDERR; if (gotsig) { Log(LOG_NOTICE, "%s", strsignal(gotsig)); return M_HARDERR; } if ((sd>=0) && ((j=eofsocks(sd)))) { Log(LOG_NOTICE, "%s on socks connection", eofsocks_str[j]); return M_HARDERR; } t=time(0); if (t>=pongtime) { Log(LOG_NOTICE, "keepalive timeout"); pongtime=MAXINT; return M_SOFTERR; } if (t>=pingtime) { char buf=CT_PING; sendctl(fd, &buf, 1, 1, 0); pingtime=t+OI(ping); pongtime=t+OI(toping); } if (i==K_SUCCESS) { return M_SUCCESS; } if (i==K_SOFTERR) return M_SOFTERR; }}/*** Call the ip-up, ip-down scripts ***/void pspawn(char *s){ int p, c; if (secchk(s, 0022, 0022, 0)) return; p=getpid(); if ((c=fork())<0) { Log(LOG_ERR, "pspawn: fork: %m"); return; } if (c) { (void) wait(NULL); /* exactly one child is active */ } else { /* call <interface> <my-addr> <daemon-pid> <local> <remote> <arg> */ char bufa[32], bufb[32], bufc[32], bufd[32]; char *na[]={s, device, bufa, bufb, bufc, bufd, OS(arg), NULL}; struct options *o = opts; sprintf(bufa, "%s:%d", inet_ntoa(OAaddr(me)), ntohs(OAport(me))); sprintf(bufb, "%d", p); sprintf(bufc, "%s", inet_ntoa(OAaddr(ipaddr))); sprintf(bufd, "%s", inet_ntoa(OAaddr(ptpaddr))); /* put all non-secret options into environment */ for (o=opts+1; o->oname; ++o) if (o->otyp!=Tsecret) putenv(strdup(optstr(o))); /* should closelog(); ? */ close(0); close(1); close(2); (void) open("/dev/null", O_RDWR); (void) dup(0); (void) dup(0); execv(s, na); Log(LOG_WARNING, "pspawn: exec %s: %m", s); exit(1); }}/*** Main program ***/int main(int argc, char *argv[]){ int i=1, ur, fd, sd=-1, isup, errcnt; pid_t pa=0; char pidfile[128]=""; char *st; char *pn=strrchr(argv[0], '/'); if (pn) ++pn; else pn=argv[0]; if (getuid() || geteuid()) { fprintf(stderr, "This program must be run by root.\n"); exit(1); /* This program is not setuid-safe. If run by local users with arbitrary options, it could easily be tricked into executing any code as root. */ } if (!(LM=malloc(sizeof(struct lockmem)))) { perror("malloc"); exit(1); } memset(LM, 0, sizeof(struct lockmem)); xmlock(LM, sizeof(struct lockmem)); openlog(pn, LOG_CONS|LOG_NDELAY|LOG_PID, LOGFAC); /* Snarf options from: standard options file, user-supplied file and finally, command line */ setopt_file(CTLDIR "/options", 0); while ((i=getopt(argc, argv, "is:S:o:"))!=EOF) { switch(i) { case 'i': inetd=1; break; case 's': usesock=atoi(optarg); break; case 'S': sd=atoi(optarg); break; case 'o': if (setopt_file(optarg, 1)<0) exit(1); break; default: usage(pn); } } setopt_cmdline(argc-optind, argv+optind); if (!OI(maxerr)) OI(maxerr)=8; /* compatibility */ for (i=getdtablesize()-1; i>2; --i) if (i!=usesock) (void) close(i); if (OI(debug)) { closelog(); printf("CIPE daemon vers %s (c) Olaf Titz 1996-2003\n", daemon_version); logstderr=1; dumpopt(); } else if (!inetd) { /* daemonize */ gotsig=0; setsig(SIGUSR1, sighandexit); setsig(SIGCHLD, sighand); if ((i=fork())<0) { perror("fork"); exit(1); } if (i) { /* wait until the child is ready - will send SIGUSR1 */ while (1) { int s; if (wait(&s)==i) exit(WIFEXITED(s)?WEXITSTATUS(s):255); } exit(0); } setsig(SIGCHLD, SIG_DFL); /* re-lock after fork */ xmlock(LM, sizeof(struct lockmem)); pa=getppid(); close(0); close(1); close(2); setsid(); syslog(LOG_INFO, "CIPE daemon vers %s (c) Olaf Titz 1996-2003", daemon_version); } setsig(SIGHUP, sighand); setsig(SIGINT, sighand); setsig(SIGTERM, sighand); setsig(SIGPIPE, sighand); setsig(SIGUSR1, sighand); if ((ur=open("/dev/urandom", O_RDONLY))<0) { Log(LOG_ERR, "open(/dev/urandom): %m"); exit(1); } i=MAXINT; if (OA(socks)) { i=30; /* set timeout for control socket check */ if (sd<0) sd=opensocks(); if (sd<0) exit(1); } if ((fd=opendev())<0) exit(1); /* write PID file - contains some PKCIPE compat magic */ if (OS(piddir) && strlen(OS(piddir))) { FILE *f; int j=snprintf(pidfile, sizeof(pidfile), "%s/%s.pid", OS(piddir), OS(arg) ? OS(arg) : device); if (j<0 || j>sizeof(pidfile)) { Log(LOG_ERR, "pidfile path too long"); exit(1); } if (!(f=fopen(pidfile, "w"))) { Log(LOG_ERR, "open(pidfile): %m"); exit(1); } fprintf(f, "%d %s\n", getpid(), device); fclose(f); } pspawn(OS(ipup) ? OS(ipup) : CTLDIR "/ip-up"); /* Set timer for periodic checks: ping, ping-timeout */ if (OI(ping)) { pingtime=time(0); if (OI(ping)<i) i=OI(ping); } if (OI(toping)) { if (OI(toping)<i) i=OI(toping); } if (i<MAXINT) { struct itimerval t; setsig(SIGALRM, sighandnot); t.it_interval.tv_sec = i; t.it_interval.tv_usec = 0; t.it_value.tv_sec = i+10; t.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &t, 0); } if (pa>1) kill(pa, SIGUSR1);#if 0 sendctl(fd, "\x71starting up", 13, 1, 0);#endif#ifndef DONT_SEND_CONF myconfinfo.cmd=CT_CONFREQ; sendctl(fd, (char *)&myconfinfo, sizeof(myconfinfo), 1, MSG_OOB);#endif gotsig=0; isup=1; errcnt=OI(maxerr); if (OI(stayalive)) { while ((i=mainloop(fd, sd, ur))!=M_HARDERR) { if (i==M_SOFTERR && isup && OI(maxerr)>=0 && --errcnt<0) { isup=0; pspawn(OS(ipdown) ? OS(ipdown) : CTLDIR "/ip-down"); } if (i==M_SUCCESS) { errcnt=OI(maxerr); if (!isup) { isup=1; pspawn(OS(ipup) ? OS(ipup) : CTLDIR "/ip-up"); } } } } else { while ((i=mainloop(fd, sd, ur))!=M_HARDERR) { if (i==M_SOFTERR && OI(maxerr)>=0 && --errcnt<0) break; if (i==M_SUCCESS) errcnt=OI(maxerr); } } gotsig=-1;#if 1 sendctl(fd, "\x71going down", 12, 0, 0);#endif if ((st=getstats())) Log(LOG_INFO, "Interface stats %s\n", st); Log(LOG_INFO, "KX stats: rreq=%d, req=%d, ind=%d, indb=%d, ack=%d," " ackb=%d, unknown=%d\n", ks.rreq, ks.req, ks.ind, ks.indb, ks.ack, ks.ackb, ks.bogus); if (isup) pspawn(OS(ipdown) ? OS(ipdown) : CTLDIR "/ip-down"); closedev(fd); if (pidfile[0]) unlink(pidfile); Log(LOG_INFO, "%s: daemon exiting", device); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -