📄 ciped.c
字号:
/* CIPE - encrypted IP over UDP tunneling ciped.c - the user mode driver Copyright 1996 Olaf Titz <olaf@bigred.inka.de> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.*//* $Id: ciped.c,v 1.63 2004/01/18 14:57:51 olaf81825 Exp $ */#ifndef CTLDIR#define CTLDIR "/etc/cipe"#endif#define _GNU_SOURCE#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <netdb.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#include <time.h>#include <unistd.h>#include <arpa/inet.h>#include <net/if_arp.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#include <values.h>#include <linux/if_ether.h>#include "ciped.h"#include "ioctl.h"#include "cipelib.h"#ifndef LOGFAC#define LOGFAC LOG_DAEMON#endifstatic const char daemon_version[]=VERSION;void usage(const char *p){ fprintf(stderr, "usage: %s [ -i | -s fd ] [ -o file ] [option...]\n", p); exit(1);}/* Statistics */struct kstat { int rreq, req, ind, indb, ack, ackb, bogus;} ks = { 0, 0, 0, 0, 0, 0, 0 };char device[16] = "";int devnum = -1;int inetd = 0;int usesock = -1;typedef unsigned long crc;#define CRCFORM "%08lX"/*** Locked memory structure, contains everything to do with keys */#define SECPOOL 256struct lockmem { char pool[SECPOOL]; /* for strings */ int poolptr; struct siocsifcipkey sio; /* setkey ioctl */ unsigned char kxbuf[KEYXCHGBLKMIN+2]; /* KX comm buff */ crc scrc; unsigned char skey[userKeySize]; /* holds current KX key */} *LM;char *secstrdup(const char *p){ char *q=LM->pool+LM->poolptr; int n=strlen(p)+1; if (LM->poolptr+n>SECPOOL) return NULL; strcpy(q, p); LM->poolptr+=n; return q;}#ifdef HAVE_MLOCKvoid xmlock(void *addr, size_t len){ if (mlock(addr, len)<0) Log(LOG_WARNING, "mlock: %m"); /* not fatal */}void xmunlock(void *addr, size_t len){ if (munlock(addr, len)<0) Log(LOG_WARNING, "munlock: %m"); /* not fatal */}#else#define xmlock(a,l)#define xmunlock(a,l)#endif/* Configuration info structure */struct confinfo { char cmd; char fill[3]; char magic[4]; char protocol, crypto, swmaj, swmin; char keyright;};struct confinfo myconfinfo = { CT_CONF, "\0", "CIPE", ProtocolVersion, CRNAMEC, VERSION_MAJ, VERSION_MIN,#ifdef BUG_COMPATIBLE 0#else 1#endif};/*** Option parser ***//* Set an option */int setopt(const char *n, char *v, int r){ struct options *o=opts; static const char * const protos[]={NULL, "udp", "tcp"}; while (o->oname) { if (!strcmp(o->oname, n)) { if ((!v) && (o->otyp!=Tbool)) { fprintf(stderr, "missing value for %s\n", n); return -1; } switch(o->otyp) { case Tbool: o->ov.ovint=1; break; case Tint: o->ov.ovint=atoi(v); break; case Tstr: if (!(o->ov.ovstr=strdup(v))) { fprintf(stderr, "setopt: out of memory\n"); return -1; } break; case Taddr: case Tuaddr: case Ttaddr: if (!(o->ov.ovsaddr=malloc(sizeof(*o->ov.ovsaddr)))) { fprintf(stderr, "setopt: out of memory\n"); return -1; } if (getaddr(v, o->ov.ovsaddr, protos[o->otyp-Taddr])<0) { return -1; } break; case Tsecret: if (r) { fprintf(stderr, "Refused to set key from command line!\n"); return -1; } if (!(o->ov.ovstr=secstrdup(v))) { fprintf(stderr, "setopt: out of secret-pool memory\n"); return -1; } break; default: fprintf(stderr, "internal error: %d\n", __LINE__); return -1; } return 0; } ++o; } fprintf(stderr, "unknown option: %s\n", n); return -1;}/* Set options from command line */void setopt_cmdline(int argc, char *argv[]){ int i; char *q; for (i=0; i<argc; ++i) { if ((q=strchr(argv[i], '='))) *q++='\0'; (void) setopt(argv[i], q, 1); }}/* Set options from file, report file not found if (v) */int setopt_file(const char *n, int v){ FILE *f; char b[128]; char *p, *q; if (secchk(n, 0077, 0022, v)) return -1; if (!(f=fopen(n, "r"))) { if (v) perror("setopt_file: open"); return -1; } xmlock(b, sizeof(b)); /* FIXME: perhaps fgets could allocate unlocked memory */ while (fgets(b, sizeof(b), f)) { for (p=b; isspace(*p); ++p); if ((!*p) || strchr("#;:!", *p)) continue; parseopt(b, &p, &q); (void) setopt(p, q, 0); memset(b, 0, sizeof(b)); } xmunlock(b, sizeof(b)); fclose(f); return 0;}/* Make a "name=value" string of option */char *optstr(struct options *o){ static char buf[1024]; switch(o->otyp) { case Tbool: snprintf(buf, sizeof(buf), "%s=%s", o->oname, o->ov.ovint?"yes":"no"); break; case Tint: snprintf(buf, sizeof(buf), "%s=%d", o->oname, o->ov.ovint); break; case Tstr: snprintf(buf, sizeof(buf), "%s=%s", o->oname, o->ov.ovstr?o->ov.ovstr:"(none)"); break; case Tsecret: snprintf(buf, sizeof(buf), "%s=%s", o->oname, o->ov.ovstr?"(secret)":"(none)"); break; case Taddr: if (o->ov.ovsaddr) snprintf(buf, sizeof(buf), "%s=%s", o->oname, inet_ntoa(o->ov.ovsaddr->sin_addr)); else snprintf(buf, sizeof(buf), "%s=", o->oname); break; case Tuaddr: case Ttaddr: if (o->ov.ovsaddr) snprintf(buf, sizeof(buf), "%s=%s:%d", o->oname, inet_ntoa(o->ov.ovsaddr->sin_addr), ntohs(o->ov.ovsaddr->sin_port)); else snprintf(buf, sizeof(buf), "%s=", o->oname); break; default: fprintf(stderr, "internal error: %d\n", __LINE__); } return buf;}/* Print out all options */void dumpopt(void){ struct options *o; for (o=opts; o->oname; ++o) printf("%s\n", optstr(o));}/*** Logging ***//* missing option */void argmiss(const char *s){ Log(LOG_ERR, "missing argument: %s", s);}/* print if debugging */#define dprintf(f) if(OI(debug)){printf f;}/*** Initialize, open and attach the CIPE device. ***/int opendev(void){ int f, i, iffl;#ifndef NO_DYNDEV struct siocsifcipall d;#endif struct siocsifcippar p; struct siocsifcipatt a; struct ifreq r;#define amiss(s) do{ argmiss(s); goto error; }while(0)#define err(s) do{ Log(LOG_ERR, s); goto error; }while(0) /* Initialize, bind and connect the socket */ if (inetd) { f=0; } else if (usesock>=0) {#if 0 /* this seems to be unnecessary */ struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family=AF_UNSPEC; f=usesock; if (connect(f, (struct sockaddr *)&sa, sizeof(sa))<0) { err("opendev: disconnect: %m"); }#else f=usesock;#endif } else { if ((f=socket(AF_INET, SOCK_DGRAM, 0))<0) { Log(LOG_ERR, "opendev: socket: %m"); return -1; } } i=65536; /* we need much to receive fast */ if (setsockopt(f, SOL_SOCKET, SO_RCVBUF, &i, sizeof(i))) /* not fatal */ Log(LOG_NOTICE, "opendev: setsockopt: %m"); if (!OA(me)) { if (!(OA(me)=malloc(sizeof(*OA(me))))) err("opendev: malloc: %m"); OA(me)->sin_family=AF_INET; OAaddr(me).s_addr=INADDR_ANY; OAport(me)=0; } if (!inetd) { if (usesock<0) { if (bind(f, (struct sockaddr *)OA(me), sizeof(*OA(me)))<0) err("opendev: bind: %m"); } if (OA(peer)) { if (connect(f, (struct sockaddr *)OA(peer), sizeof(*OA(peer)))<0) err("opendev: connect: %m"); } else amiss("peer"); } i=sizeof(*OA(me)); if (getsockname(f, (struct sockaddr *)OA(me), &i)<0) /* not fatal */ Log(LOG_NOTICE, "opendev: getsockname: %m");#ifdef NO_DYNDEV if (!OS(device)) amiss("device"); if (strlen(OS(device)) > 15) err("opendev: device name too long."); strcpy(device, OS(device));#else /* Allocate the device name */ if (OS(device)) { char *x=OS(device)+strlen(OS(device))-1; while (x>=OS(device) && isdigit(*x)) --x; d.num=atoi(++x); } else { d.num=-1; } if (ioctl_alloc(f, DEVNAME "0", &d)<0) err("opendev: alloc: %m"); strcpy(device, d.name); devnum=d.num; dprintf(("Using %s index %d\n", device, devnum));#endif /* Set the CIPE operation parameters */ memset(&p, 0, sizeof(p)); if (OA(socks)) p.socks=*OA(socks); p.tmo_keyxchg=OI(tokxc); p.tmo_keylife=OI(tokey); p.flags=CIPF_MAY_STKEY; if (OI(nokey)) p.flags|=CIPF_MAY_CLEAR; if (OI(dynip)) p.flags|=CIPF_MAY_DYNIP; if (OI(checksum)) p.flags|=CIPF_DO_CSUM; if (OI(ignoredf)) p.flags|=CIPF_IGNORE_DF; if (OI(forcemtu)) p.flags|=CIPF_FORCE_MTU; p.cttl=OI(cttl); if (OS(cipher)) { strncpy(p.cname, OS(cipher), sizeof(p.cname)-5); } else { strcpy(p.cname, "blowfish-internal"); } myconfinfo.crypto=p.cname[0]; if (ioctl_setpar(f, device, &p)<0) err("opendev: setpar: %m"); /* Set the key */ if (OS(key)) { unsigned char *c=OS(key); unsigned char *x=(unsigned char *)&LM->sio.thekey; LM->sio.which=KEY_STATIC;#ifdef BUG_COMPATIBLE /* BROKEN attempt at a primitive hex decoder */ i=0; while(*c) { x[i]=((*c)<<4)&0xF0; *c++='\0'; /* clear after use */ if (!*c) break; x[i++]|=(*c)&0x0F; *c++='\0'; if (i>=userKeySize) break; }#else gethex(c, x, userKeySize); memset(c, 0, strlen(c)); /* clear after use */#endif LM->sio.keylen=userKeySize; if (ioctl_setkey(f, device, &LM->sio)<0) err("opendev: setkey: %m"); } else { if (!OI(nokey)) amiss("key"); } /* Perform attach */ a.fd=f; if (ioctl_attach(f, device, &a)<0) err("opendev: attach: %m"); if (OI(ifconfig)) return f; /* Perform ifconfig */ strcpy(r.ifr_name, device); if (ioctl(f, SIOCGIFFLAGS, &r)<0) err("opendev: SIOCGIFFLAGS: %m"); iffl=r.ifr_flags; if (OA(ipaddr)) { memcpy(&r.ifr_addr, OA(ipaddr), sizeof(*OA(ipaddr))); if (ioctl(f, SIOCSIFADDR, &r)<0) err("opendev: SIOCSIFADDR: %m"); } else amiss("ipaddr"); if (OA(ptpaddr)) { memcpy(&r.ifr_dstaddr, OA(ptpaddr), sizeof(*OA(ptpaddr))); if (ioctl(f, SIOCSIFDSTADDR, &r)<0) err("opendev: SIOCSIFDSTADDR: %m"); iffl|=IFF_POINTOPOINT; } if (OA(mask)) { memcpy(&r.ifr_netmask, OA(mask), sizeof(*OA(mask))); if (ioctl(f, SIOCSIFNETMASK, &r)<0) err("opendev: SIOCSIFNETMASK: %m"); } if (OA(bcast)) { memcpy(&r.ifr_broadaddr, OA(bcast), sizeof(*OA(bcast))); if (ioctl(f, SIOCSIFBRDADDR, &r)<0) err("opendev: SIOCSIFBRDADDR: %m"); } if (OI(mtu)) { r.ifr_mtu=OI(mtu); if (ioctl(f, SIOCSIFMTU, &r)<0) err("opendev: SIOCSIFMTU: %m"); } if (OI(metric)) { r.ifr_metric=OI(metric); if (ioctl(f, SIOCSIFMETRIC, &r)<0) err("opendev: SIOCSIFMETRIC: %m"); } if (OS(hwaddr)) { struct sockaddr sa; sa.sa_family=ARPHRD_ETHER; gethex(OS(hwaddr), (unsigned char *)&sa.sa_data, ETH_ALEN); memcpy(&r.ifr_hwaddr, &sa, sizeof(sa)); if (ioctl(f, SIOCSIFHWADDR, &r)<0) err("opendev: SIOCSIFHWADDR: %m"); } iffl|=IFF_UP|IFF_RUNNING; r.ifr_flags=iffl; if (ioctl(f, SIOCSIFFLAGS, &r)<0) err("opendev: SIOCSIFFLAGS: %m"); return f; error: close(f); return -1;#undef amiss#undef err}/* Close the device. */void closedev(int f){ struct ifreq r; strcpy(r.ifr_name, device); if (ioctl(f, SIOCGIFFLAGS, &r)<0) Log(LOG_ERR, "closedev: SIOCGIFFLAGS: %m"); r.ifr_flags&=~(IFF_UP|IFF_RUNNING); if (ioctl(f, SIOCSIFFLAGS, &r)<0) Log(LOG_ERR, "closedev: SIOCSIFFLAGS: %m"); close(f);#ifndef NO_DYNDEV if (devnum>0) { struct siocsifcipall x; if ((f=socket(AF_INET, SOCK_DGRAM, 0))<0) { Log(LOG_ERR, "closedev: socket: %m"); return; } x.num=devnum; if (ioctl_unalloc(f, device, &x)<0) Log(LOG_ERR, "closedev: unalloc: %m"); close(f); }#endif}/* Fetch the device statistics. */char *getstats(void){ static char b[256]; char *p, *q; FILE *f=fopen("/proc/net/dev", "r"); if (!f) return NULL; while (fgets(b, sizeof(b), f)) { for (p=b; *p==' '; ++p); for (q=p; *q && *q!=':'; ++q); if (!*q) continue; *q++='\0'; if (strcmp(p, device)) continue; fclose(f); return(q); } fclose(f); return NULL;}/*** Open a SOCKS5 connection ***/int opensocks(void) { struct sockaddr_in a; int fd=socks5_open(OA(socks)); if (fd>=0) { /* 3rd par of socks5_cmd is in: my address, out: relayer */ a=*OA(me); fd=socks5_cmd(fd, S5_UDP, &a); /* Swap peer and socks addresses. Use the SOCKS relayer as "peer" and the real peer as "socks"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -