/* This file is in the public domain. */ #if 0 #include #include #endif #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "protocol.h" #include "pollloop.h" typedef struct ipaddr IPADDR; struct ipaddr { int af; union { struct in_addr v4; struct in6_addr v6; } ; } ; static unsigned char *ck; static int cklen; static int ncipaddrs; static IPADDR **cipaddrs; #define Cisspace(c) isspace((unsigned char)(c)) #if 0 typedef struct peer PEER; struct peer { struct sockaddr *sa; int fd; int cfd; int id; } ; static sockaddr *root; static int npeers; static int apeers; static PEER **peers; static int pcfd; static int pcid; static void peer_check_connect(void *pv) { PEER *p; int e; socklen_t el; p = pv; remove_poll_id(p->id); el = sizeof(e); if ( (getsockopt(p->cfd,SOL_SOCKET,SO_ERROR,&e,&el) < 0) || (el != sizeof(e)) || e ) { p->id = PL_NOID; close(p->cfd); p->cfd = -1; return; } peer_start_crypto(p); } static void pcfd_rd(void) { struct timersock_event ev; int i; PEER *p; while (read(pcfd,&ev,sizeof(ev)) > 0) ; for (i=npeers-1;i>=0;i--) { p = peers[i]; if ((p->fd >= 0) || (p->cfd >= 0)) continue; p->cfd = socket(p->sa->sa_family,SOCK_STREAM,0); if (p->cfd < 0) continue; fcntl(p->cfd,F_SETFL,fcntl(p->cfd,F_GETFL,0)|O_NONBLOCK); if (connect(p->cfd,p->sa,p->sa->sa_len) < 0) { if (errno == EINPROGRESS) { p->id = add_poll_fd(p->cfd,&rwtest_never,&rwtest_always,0,&peer_check_connect,p); } else { close(p->cfd); p->cfd = -1; } } else { peer_start_crypto(p); } } } static void startup(void) { struct itimerval itv; npeers = 1; apeers = 1; peers = malloc(sizeof(PEER *)); peers[0] = malloc(sizeof(PEER)); peers[0]->addr = sadup(root); peers[0]->fd = -1; peers[0]->cfd = -1; peers[0]->id = PL_NOID; init_polling(); pcfd = socket(AF_TIMER,SOCK_STREAM,0); itv.it_value.tv_sec = 1; itv.it_value.tv_usec = 0; itv.it_interval.tv_sec = 300; itv.it_interval.tv_usec = 0; write(pcfd,&itv,sizeof(itv)); pcid = add_poll_fd(pcfd,&rwtest_always,&rwtest_never,&pcfd_rd,0,0); } #endif static void config_key(const char *s) { free(ck); cklen = strlen(s); ck = malloc(cklen); bcopy(s,ck,cklen); } static void config_keyfile(const char *s) { int fd; struct stat stb; int r; int l; unsigned char *b; fd = open(s,O_RDONLY,0); if (fd < 0) { fprintf(stderr,"%s: %s: %s\n",__progname,s,strerror(errno)); exit(1); } if (fstat(fd,&stb) < 0) { fprintf(stderr,"%s: fstat %s: %s\n",__progname,s,strerror(errno)); exit(1); } if (stb.st_size < 1) { fprintf(stderr,"%s: %s: empty\n",__progname,s); exit(1); } else if (stb.st_size > 65536) { fprintf(stderr,"%s: %s: too large, using only first 64K\n",__progname,s); l = 65536; } else { l = stb.st_size; } b = malloc(l); r = read(fd,b,l); if (r < 0) { fprintf(stderr,"%s: read from %s: %s\n",__progname,s,strerror(errno)); exit(1); } if (r != l) { fprintf(stderr,"%s: read from %s: wanted %d, got %d\n",__progname,s,l,r); exit(1); } close(fd); free(ck); ck = b; cklen = l; } static void cloud_ip(const char *s) { IPADDR *a; a = malloc(sizeof(IPADDR)); if (inet_pton(AF_INET,s,&a->v4) > 0) { a->af = AF_INET; } else if (inet_pton(AF_INET6,s,&a->v6) > 0) { a->af = AF_INET6; } else { fprintf(stderr,"%s: unparseable IP `%s'\n",__progname,s); free(a); return; } cipaddrs = realloc(cipaddrs,(ncipaddrs+1)*sizeof(IPADDR *)); cipaddrs[ncipaddrs++] = a; } static void readconf(const char *); /* forward */ static int config_line(const char *s) { const char *k0; int kl; static struct { const char *key; void (*handler)(const char *); int keylen; } keys[] = { { "@", &readconf }, { "key", &config_key }, { "keyfile", &config_keyfile }, { "id", &config_id }, { "ip", &config_ip }, { "type", &config_type }, { "listen", &config_listen }, { "uplink", &config_uplink }, { 0 } }; int i; if (keys[0].keylen == 0) for (i=0;keys[i].key;i++) keys[i].keylen = strlen(keys[i].key); while (*s && Cisspace(*s)) s ++; if (! *s) return(0); if (*s == '#') return(0); k0 = s; while (*s && !Cisspace(*s)) s ++; kl = s - k0; while (*s && Cisspace(*s)) s ++; for (i=0;keys[i].key;i++) { if ((kl == keys[i].keylen) && !bcmp(k0,keys[i].key,kl)) { (*keys[i].handler)(s); return(0); } } return(1); } static void readconf(const char *fn) { FILE *f; char *lb; int la; int ln; int c; void savec(char ch) { if (ln >= la) lb = realloc(lb,la=ln+16); lb[ln++] = ch; } void cl(void) { savec('\0'); if (config_line(lb)) { fprintf(stderr,"%s: %s: unrecognized config file line: %s\n",__progname,fn,lb); exit(1); } } f = fopen(fn,"r"); if (f == 0) { fprintf(stderr,"%s: %s: %s\n",__progname,fn,strerror(errno)); exit(1); } lb = 0; la = 0; ln = 0; while <"read"> (1) { c = getc(f); switch (c) { case EOF: if (ln > 0) cl(); break <"read">; break; case '\n': cl(); ln = 0; break; default: savec(c); break; } } free(lb); } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: stray argument `%s'\n",__progname,*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-config")) { WANTARG(); readconf(av[skip]); continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) exit(1); } static void init(void) { ck = 0; ncipaddrs = 0; cipaddrs = 0; } int main(int, char **); int main(int ac, char **av) { init(); handleargs(ac,av); startup(); return(0); }