From 042a8da9053c205ea74ec1785c93ca4bcf4ea5e0 Mon Sep 17 00:00:00 2001 From: Stephen Early Date: Mon, 15 Oct 2001 01:37:00 +0100 Subject: [PATCH] Import release 0.1.7 --- Makefile.in | 6 +- README | 13 +- TODO | 16 +- debian/changelog | 2 +- netlink.c | 49 ++++-- netlink.h | 1 + process.c | 10 +- process.h | 3 +- secnet.c | 2 +- slip.c | 410 +++++++++++++++++++++++++++++++---------------- 10 files changed, 334 insertions(+), 178 deletions(-) diff --git a/Makefile.in b/Makefile.in index 85a770b..abc8528 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,7 +18,7 @@ .PHONY: all clean realclean dist install PACKAGE:=secnet -VERSION:=0.1.6 +VERSION:=0.1.7 @SET_MAKE@ @@ -96,7 +96,9 @@ config.status: configure # Manual dependencies section - XXX use autodep eventually $(OBJECTS): config.h secnet.h util.h conffile.o conffile.tab.o conffile.yy.o: conffile.h conffile_internal.h -secnet.c: conffile.h +secnet.o: conffile.h process.h +process.o: process.h +log.o: process.h md5.o: md5.h serpent.o transform.o: serpent.h serpent.o: serpentsboxes.h diff --git a/README b/README index 957fe06..a21a2e7 100644 --- a/README +++ b/README @@ -167,12 +167,11 @@ udp: dict argument buffer (buffer closure): buffer for incoming packets authbind (string): optional, path to authbind-helper program -** util +** log Defines: logfile (closure => log closure) syslog (closure => log closure) - sysbuffer (closure => buffer closure) logfile: dict argument filename (string): where to log to @@ -191,6 +190,8 @@ logfile: dict argument { "verbose", M_INFO|M_NOTICE|M_WARNING|M_ERROR|M_SECURITY|M_FATAL }, { "quiet", M_FATAL } +logfile will close and reopen its file upon receipt of SIGHUP. + syslog: dict argument ident (string): include this string in every log message facility (string): facility to log as @@ -213,6 +214,11 @@ syslog: dict argument { "user", LOG_USER }, { "uucp", LOG_UUCP } +** util + +Defines: + sysbuffer (closure => buffer closure) + sysbuffer: integer[,dict] arg1: buffer length arg2: options: @@ -287,6 +293,9 @@ null-netlink: dict argument secnet-address (string): IP address of this netlink device mtu (integer): MTU of host's tunnel interface +Netlink will dump its current routing table to the system/log on +receipt of SIGUSR1. + ** slip Defines: diff --git a/TODO b/TODO index af3a468..d0e8db7 100644 --- a/TODO +++ b/TODO @@ -6,8 +6,8 @@ endianness problems) netlink.c: investigate why 'default' routes don't appear to work (reported by JDA). -slip.c: detect failure of userv-ipif to start. Restart userv-ipif to -cope with soft routes? Restart it if it fails in use? +slip.c: restart userv-ipif to cope with soft routes? Restart it if it +fails in use? tun.c: jdamery reports tun-old code works on Linux-2.2. Unresolved problem with ioctl(TUNSETIFF) sometimes returning EINVAL, seems @@ -24,14 +24,10 @@ cleanly using a table. There's still quite a lot of redundancy in this file. Abandon key exchanges when a bad packet is received. Modify protocol to include version fields, as described in the NOTES file. -transform.c: see below +transform.c: separate the transforms into multiple parts, which can +then be combined in the configuration file. Will allow the user to +plug in different block ciphers, invent an authenticity-only mode, +etc. sha1.c: test -General: separate the transforms in transform.c into multiple parts, -which can then be combined in the configuration file. Will allow the -user to plug in different block ciphers, invent an authenticity-only -mode, etc. - -Signal handling! Really just cope with SIGCHLD and SIGTERM. Possibly -use SIGUSR1/2 for prodding things. Manage child processes properly. diff --git a/debian/changelog b/debian/changelog index 8a69a5e..4c42dd4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -secnet (0.1.5-1) unstable; urgency=low +secnet (0.1.7-1) unstable; urgency=low * New upstream version. diff --git a/netlink.c b/netlink.c index e09eacf..bfdb19b 100644 --- a/netlink.c +++ b/netlink.c @@ -8,10 +8,18 @@ packet to the kernel we check that the tunnel it came over could reasonably have produced it. */ +/* XXX new feature: "point-to-point" mode. Instead of specifying a + secnet-address in the configuration dictionary, the user specifies + the address of the machine at the other end of the (one and only) + tunnel. We bypass all IP packet processing code. This mode is + useful for leafnodes like laptops, which don't require a secnet + router address. */ + #include "secnet.h" #include "util.h" #include "ipaddr.h" #include "netlink.h" +#include "process.h" /* Generic IP checksum routine */ static inline uint16_t ip_csum(uint8_t *iph,uint32_t count) @@ -484,15 +492,18 @@ static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf) } static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c, - bool_t up) + bool_t up, uint32_t quality) { uint32_t i; if (!st->routes) return; /* Table has not yet been created */ for (i=0; in_routes; i++) { - if (!st->routes[i].hard && st->routes[i].c==c) { - st->routes[i].up=up; - st->set_route(st->dst,&st->routes[i]); + if (st->routes[i].c==c) { + st->routes[i].quality=quality; + if (!st->routes[i].hard) { + st->routes[i].up=up; + st->set_route(st->dst,&st->routes[i]); + } } } } @@ -504,9 +515,9 @@ static void netlink_set_quality(void *sst, void *cid, uint32_t quality) c->link_quality=quality; if (c->link_quality==LINK_QUALITY_DOWN) { - netlink_set_softlinks(st,c,False); + netlink_set_softlinks(st,c,False,c->link_quality); } else { - netlink_set_softlinks(st,c,True); + netlink_set_softlinks(st,c,True,c->link_quality); } } @@ -560,26 +571,29 @@ static void *netlink_regnets(void *sst, struct subnet_list *nets, return c; } -static void netlink_dump_routes(struct netlink *st) +static void netlink_dump_routes(struct netlink *st, bool_t requested) { int i; string_t net; + uint32_t c=M_INFO; - Message(M_INFO,"%s: routing table:\n",st->name); + if (requested) c=M_WARNING; + Message(c,"%s: routing table:\n",st->name); for (i=0; in_routes; i++) { net=subnet_to_string(&st->routes[i].net); - Message(M_INFO,"%s -> tunnel %s (%s,%s route,%s)\n",net, + Message(c,"%s -> tunnel %s (%s,%s route,%s,quality %d)\n",net, st->routes[i].c->name, st->routes[i].hard?"hard":"soft", st->routes[i].allow_route?"free":"restricted", - st->routes[i].up?"up":"down"); + st->routes[i].up?"up":"down", + st->routes[i].quality); free(net); } - Message(M_INFO,"%s/32 -> netlink \"%s\"\n", + Message(c,"%s/32 -> netlink \"%s\"\n", ipaddr_to_string(st->secnet_address),st->name); for (i=0; inetworks.entries; i++) { net=subnet_to_string(&st->networks.list[i]); - Message(M_INFO,"%s -> host\n",net); + Message(c,"%s -> host\n",net); free(net); } } @@ -618,6 +632,7 @@ static void netlink_phase_hook(void *sst, uint32_t new_phase) st->routes[i].hard=c->options&NETLINK_OPTION_SOFTROUTE?False:True; st->routes[i].allow_route=c->options&NETLINK_OPTION_ALLOW_ROUTE? True:False; + st->routes[i].quality=c->link_quality; i++; } } @@ -630,7 +645,14 @@ static void netlink_phase_hook(void *sst, uint32_t new_phase) qsort(st->routes,st->n_routes,sizeof(*st->routes), netlink_compare_route_specificity); - netlink_dump_routes(st); + netlink_dump_routes(st,False); +} + +static void netlink_signal_handler(void *sst, int signum) +{ + struct netlink *st=sst; + Message(M_INFO,"%s: route dump requested by SIGUSR1\n",st->name); + netlink_dump_routes(st,True); } netlink_deliver_fn *netlink_init(struct netlink *st, @@ -671,6 +693,7 @@ netlink_deliver_fn *netlink_init(struct netlink *st, st->routes=NULL; add_hook(PHASE_SETUP,netlink_phase_hook,st); + request_signal_notification(SIGUSR1, netlink_signal_handler, st); return netlink_incoming; } diff --git a/netlink.h b/netlink.h index 3f735f2..f3f43d5 100644 --- a/netlink.h +++ b/netlink.h @@ -23,6 +23,7 @@ struct netlink_route { bool_t allow_route; bool_t up; bool_t kup; + uint32_t quality; /* provided by client */ struct netlink_client *c; }; diff --git a/process.c b/process.c index b40801b..d9d01ce 100644 --- a/process.c +++ b/process.c @@ -39,11 +39,10 @@ static void set_default_signals(void); signal processing so that we can catch SIGCHLD for them and report their exit status using the callback function. We block SIGCHLD until signal processing has begun. */ -extern void makesubproc(process_entry_fn *entry, process_callback_fn *cb, - void *est, void *cst, string_t desc) +pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb, + void *est, void *cst, string_t desc) { struct child *c; - sigset_t sigchld; pid_t p; c=safe_malloc(sizeof(*c),"makesubproc"); @@ -52,9 +51,7 @@ extern void makesubproc(process_entry_fn *entry, process_callback_fn *cb, c->cst=cst; if (!signal_handling) { - sigemptyset(&sigchld); - sigaddset(&sigchld,SIGCHLD); - sigprocmask(SIG_BLOCK,&sigchld,NULL); + fatal("makesubproc called before signal handling started\n"); } p=fork(); if (p==0) { @@ -70,6 +67,7 @@ extern void makesubproc(process_entry_fn *entry, process_callback_fn *cb, c->finished=False; c->next=children; children=c; + return p; } static signal_notify_fn sigchld_handler; diff --git a/process.h b/process.h index 986fa38..35f5318 100644 --- a/process.h +++ b/process.h @@ -2,12 +2,13 @@ #define process_h #include +#include typedef void process_callback_fn(void *cst, pid_t pid, int status); typedef void process_entry_fn(void *cst); typedef void signal_notify_fn(void *cst, int signum); -extern void makesubproc(process_entry_fn *entry, process_callback_fn *cb, +extern pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb, void *est, void *cbst, string_t desc); extern void request_signal_notification(int signum, signal_notify_fn *notify, diff --git a/secnet.c b/secnet.c index c7ce2b8..489e0bf 100644 --- a/secnet.c +++ b/secnet.c @@ -388,11 +388,11 @@ int main(int argc, char **argv) enter_phase(PHASE_DROPPRIV); droppriv(); - enter_phase(PHASE_RUN); start_signal_handling(); request_signal_notification(SIGTERM,finish,"SIGTERM"); if (!background) request_signal_notification(SIGINT,finish,"SIGINT"); request_signal_notification(SIGHUP,ignore_hup,NULL); + enter_phase(PHASE_RUN); run(); enter_phase(PHASE_SHUTDOWN); diff --git a/slip.c b/slip.c index afc0528..cff8f63 100644 --- a/slip.c +++ b/slip.c @@ -6,30 +6,132 @@ #include "secnet.h" #include "util.h" #include "netlink.h" +#include "process.h" #include #include #include +#include +#include #define SLIP_END 192 #define SLIP_ESC 219 #define SLIP_ESCEND 220 #define SLIP_ESCESC 221 +struct slip { + struct netlink nl; + struct buffer_if *buff; /* We unstuff received packets into here + and send them to the netlink code. */ + bool_t pending_esc; + netlink_deliver_fn *netlink_to_tunnel; + uint32_t local_address; +}; + +/* Generic SLIP mangling code */ + +static void slip_stuff(struct slip *st, struct buffer_if *buf, int fd) +{ + uint8_t txbuf[DEFAULT_BUFSIZE]; + uint8_t *i; + uint32_t j=0; + + BUF_ASSERT_USED(buf); + + /* XXX crunchy bytestuff code */ + txbuf[j++]=SLIP_END; + for (i=buf->start; i<(buf->start+buf->size); i++) { + switch (*i) { + case SLIP_END: + txbuf[j++]=SLIP_ESC; + txbuf[j++]=SLIP_ESCEND; + break; + case SLIP_ESC: + txbuf[j++]=SLIP_ESC; + txbuf[j++]=SLIP_ESCESC; + break; + default: + txbuf[j++]=*i; + break; + } + if ((j+2)>DEFAULT_BUFSIZE) { + if (write(fd,txbuf,j)<0) { + fatal_perror("slip_stuff: write()"); + } + j=0; + } + } + txbuf[j++]=SLIP_END; + if (write(fd,txbuf,j)<0) { + fatal_perror("slip_stuff: write()"); + } + BUF_FREE(buf); +} + +static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) +{ + uint32_t i; + + /* XXX really crude unstuff code */ + /* XXX check for buffer overflow */ + BUF_ASSERT_USED(st->buff); + for (i=0; ipending_esc) { + st->pending_esc=False; + switch(buf[i]) { + case SLIP_ESCEND: + *(uint8_t *)buf_append(st->buff,1)=SLIP_END; + break; + case SLIP_ESCESC: + *(uint8_t *)buf_append(st->buff,1)=SLIP_ESC; + break; + default: + fatal("userv_afterpoll: bad SLIP escape character\n"); + } + } else { + switch (buf[i]) { + case SLIP_END: + if (st->buff->size>0) { + st->netlink_to_tunnel(&st->nl,NULL, + st->buff); + BUF_ALLOC(st->buff,"userv_afterpoll"); + } + buffer_init(st->buff,st->nl.max_start_pad); + break; + case SLIP_ESC: + st->pending_esc=True; + break; + default: + *(uint8_t *)buf_append(st->buff,1)=buf[i]; + break; + } + } + } +} + +static void slip_init(struct slip *st, struct cloc loc, dict_t *dict, + string_t name, netlink_deliver_fn *to_host) +{ + st->netlink_to_tunnel= + netlink_init(&st->nl,st,loc,dict, + "netlink-userv-ipif",NULL,to_host); + st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"name",loc); + st->local_address=string_to_ipaddr( + dict_find_item(dict,"local-address", True, name, loc),"netlink"); + BUF_ALLOC(st->buff,"slip_init"); + st->pending_esc=False; +} + /* Connection to the kernel through userv-ipif */ struct userv { - struct netlink nl; + struct slip slip; int txfd; /* We transmit to userv */ int rxfd; /* We receive from userv */ string_t userv_path; string_t service_user; string_t service_name; - uint32_t txbuflen; - struct buffer_if *buff; /* We unstuff received packets into here - and send them to the site code. */ - bool_t pending_esc; - netlink_deliver_fn *netlink_to_tunnel; - uint32_t local_address; /* host interface address */ + pid_t pid; + bool_t expecting_userv_exit; }; static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io, @@ -37,11 +139,16 @@ static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io, uint64_t *now) { struct userv *st=sst; - *nfds_io=2; - fds[0].fd=st->txfd; - fds[0].events=POLLERR; /* Might want to pick up POLLOUT sometime */ - fds[1].fd=st->rxfd; - fds[1].events=POLLIN|POLLERR|POLLHUP; + + if (st->rxfd!=-1) { + *nfds_io=2; + fds[0].fd=st->txfd; + fds[0].events=POLLERR; /* Might want to pick up POLLOUT sometime */ + fds[1].fd=st->rxfd; + fds[1].events=POLLIN|POLLERR|POLLHUP; + } else { + *nfds_io=0; + } return 0; } @@ -50,55 +157,23 @@ static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds, { struct userv *st=sst; uint8_t rxbuf[DEFAULT_BUFSIZE]; - int l,i; + int l; + + if (nfds==0) return; if (fds[1].revents&POLLERR) { - Message(M_ERROR,"%s: userv_afterpoll: hup!\n",st->nl.name); + Message(M_ERROR,"%s: userv_afterpoll: POLLERR!\n",st->slip.nl.name); } if (fds[1].revents&POLLIN) { l=read(st->rxfd,rxbuf,DEFAULT_BUFSIZE); if (l<0) { - fatal_perror("%s: userv_afterpoll: read(rxfd)",st->nl.name); - } - if (l==0) { + if (errno!=EINTR) + fatal_perror("%s: userv_afterpoll: read(rxfd)", + st->slip.nl.name); + } else if (l==0) { fatal("%s: userv_afterpoll: read(rxfd)=0; userv gone away?\n", - st->nl.name); - } - /* XXX really crude unstuff code */ - /* XXX check for buffer overflow */ - BUF_ASSERT_USED(st->buff); - for (i=0; ipending_esc) { - st->pending_esc=False; - switch(rxbuf[i]) { - case SLIP_ESCEND: - *(uint8_t *)buf_append(st->buff,1)=SLIP_END; - break; - case SLIP_ESCESC: - *(uint8_t *)buf_append(st->buff,1)=SLIP_ESC; - break; - default: - fatal("userv_afterpoll: bad SLIP escape character\n"); - } - } else { - switch (rxbuf[i]) { - case SLIP_END: - if (st->buff->size>0) { - st->netlink_to_tunnel(&st->nl,NULL, - st->buff); - BUF_ALLOC(st->buff,"userv_afterpoll"); - } - buffer_init(st->buff,st->nl.max_start_pad); - break; - case SLIP_ESC: - st->pending_esc=True; - break; - default: - *(uint8_t *)buf_append(st->buff,1)=rxbuf[i]; - break; - } - } - } + st->slip.nl.name); + } else slip_unstuff(&st->slip,rxbuf,l); } } @@ -107,43 +182,60 @@ static void userv_deliver_to_kernel(void *sst, void *cid, struct buffer_if *buf) { struct userv *st=sst; - uint8_t txbuf[DEFAULT_BUFSIZE]; - uint8_t *i; - uint32_t j; - BUF_ASSERT_USED(buf); + slip_stuff(&st->slip,buf,st->txfd); +} - /* Spit the packet at userv-ipif: SLIP start marker, then - bytestuff the packet, then SLIP end marker */ - /* XXX crunchy bytestuff code */ - j=0; - txbuf[j++]=SLIP_END; - for (i=buf->start; i<(buf->start+buf->size); i++) { - switch (*i) { - case SLIP_END: - txbuf[j++]=SLIP_ESC; - txbuf[j++]=SLIP_ESCEND; - break; - case SLIP_ESC: - txbuf[j++]=SLIP_ESC; - txbuf[j++]=SLIP_ESCESC; - break; - default: - txbuf[j++]=*i; - break; - } +static void userv_userv_callback(void *sst, pid_t pid, int status) +{ + struct userv *st=sst; + + if (pid!=st->pid) { + Message(M_WARNING,"userv_callback called unexpectedly with pid %d " + "(expected %d)\n",pid,st->pid); + return; } - txbuf[j++]=SLIP_END; - if (write(st->txfd,txbuf,j)<0) { - fatal_perror("userv_deliver_to_kernel: write()"); + if (!st->expecting_userv_exit) { + if (WIFEXITED(status)) { + fatal("%s: userv exited unexpectedly with status %d\n", + st->slip.nl.name,WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + fatal("%s: userv exited unexpectedly: uncaught signal %d\n", + st->slip.nl.name,WTERMSIG(status)); + } else { + fatal("%s: userv stopped unexpectedly\n"); + } } - BUF_FREE(buf); + Message(M_WARNING,"%s: userv subprocess died with status %d\n", + st->slip.nl.name,WEXITSTATUS(status)); + st->pid=0; } -static void userv_phase_hook(void *sst, uint32_t newphase) +struct userv_entry_rec { + string_t path; + char **argv; + int stdin; + int stdout; + /* XXX perhaps we should collect and log stderr? */ +}; + +static void userv_entry(void *sst) { - struct userv *st=sst; - pid_t child; + struct userv_entry_rec *st=sst; + + dup2(st->stdin,0); + dup2(st->stdout,1); + + /* XXX close all other fds */ + setsid(); + execvp(st->path,st->argv); + perror("userv-entry: execvp()"); + exit(1); +} + +static void userv_invoke_userv(struct userv *st) +{ + struct userv_entry_rec *er; int c_stdin[2]; int c_stdout[2]; string_t addrs; @@ -151,18 +243,24 @@ static void userv_phase_hook(void *sst, uint32_t newphase) string_t s; struct netlink_route *r; int i; + uint8_t confirm; + + if (st->pid) { + fatal("userv_invoke_userv: already running\n"); + } /* This is where we actually invoke userv - all the networks we'll be using should already have been registered. */ - addrs=safe_malloc(512,"userv_phase_hook:addrs"); - snprintf(addrs,512,"%s,%s,%d,slip",ipaddr_to_string(st->local_address), - ipaddr_to_string(st->nl.secnet_address),st->nl.mtu); + addrs=safe_malloc(512,"userv_invoke_userv:addrs"); + snprintf(addrs,512,"%s,%s,%d,slip", + ipaddr_to_string(st->slip.local_address), + ipaddr_to_string(st->slip.nl.secnet_address),st->slip.nl.mtu); - nets=safe_malloc(1024,"userv_phase_hook:nets"); + nets=safe_malloc(1024,"userv_invoke_userv:nets"); *nets=0; - r=st->nl.routes; - for (i=0; inl.n_routes; i++) { + r=st->slip.nl.routes; + for (i=0; islip.nl.n_routes; i++) { if (r[i].up) { r[i].kup=True; s=subnet_to_string(&r[i].net); @@ -173,61 +271,92 @@ static void userv_phase_hook(void *sst, uint32_t newphase) } nets[strlen(nets)-1]=0; - Message(M_INFO,"%s: about to invoke: %s %s %s %s %s\n",st->nl.name, + Message(M_INFO,"%s: about to invoke: %s %s %s %s %s\n",st->slip.nl.name, st->userv_path,st->service_user,st->service_name,addrs,nets); - /* Allocate buffer, plus space for padding. Make sure we end up - with the start of the packet well-aligned. */ - /* ALIGN(st->max_start_pad,16); */ - /* ALIGN(st->max_end_pad,16); */ - - st->pending_esc=False; + st->slip.pending_esc=False; /* Invoke userv */ if (pipe(c_stdin)!=0) { - fatal_perror("userv_phase_hook: pipe(c_stdin)"); + fatal_perror("userv_invoke_userv: pipe(c_stdin)"); } if (pipe(c_stdout)!=0) { - fatal_perror("userv_phase_hook: pipe(c_stdout)"); + fatal_perror("userv_invoke_userv: pipe(c_stdout)"); } st->txfd=c_stdin[1]; st->rxfd=c_stdout[0]; - child=fork(); - if (child==-1) { - fatal_perror("userv_phase_hook: fork()"); + er=safe_malloc(sizeof(*r),"userv_invoke_userv: er"); + + er->stdin=c_stdin[0]; + er->stdout=c_stdout[1]; + /* The arguments are: + userv + service-user + service-name + local-addr,secnet-addr,mtu,protocol + route1,route2,... */ + er->argv=safe_malloc(sizeof(*er->argv)*6,"userv_invoke_userv:argv"); + er->argv[0]=st->userv_path; + er->argv[1]=st->service_user; + er->argv[2]=st->service_name; + er->argv[3]=addrs; + er->argv[4]=nets; + er->argv[5]=NULL; + er->path=st->userv_path; + + st->pid=makesubproc(userv_entry, userv_userv_callback, + er, st, st->slip.nl.name); + close(er->stdin); + close(er->stdout); + free(er->argv); + free(er); + free(addrs); + free(nets); + Message(M_INFO,"%s: userv-ipif pid is %d\n",st->slip.nl.name,st->pid); + /* Read a single character from the pipe to confirm userv-ipif is + running. If we get a SIGCHLD at this point then we'll get EINTR. */ + if (read(st->rxfd,&confirm,1)!=1) { + if (errno==EINTR) { + Message(M_WARNING,"%s: read of confirmation byte was " + "interrupted\n",st->slip.nl.name); + } else { + fatal_perror("%s: read() of confirmation byte",st->slip.nl.name); + } + } else { + if (confirm!=SLIP_END) { + fatal("%s: bad confirmation byte %d from userv-ipif\n", + st->slip.nl.name,confirm); + } } - if (child==0) { - char **argv; - - /* We are the child. Modify our stdin and stdout, then exec userv */ - dup2(c_stdin[0],0); - dup2(c_stdout[1],1); - close(c_stdin[1]); - close(c_stdout[0]); - - /* The arguments are: - userv - service-user - service-name - local-addr,secnet-addr,mtu,protocol - route1,route2,... */ - argv=malloc(sizeof(*argv)*6); - argv[0]=st->userv_path; - argv[1]=st->service_user; - argv[2]=st->service_name; - argv[3]=addrs; - argv[4]=nets; - argv[5]=NULL; - execvp(st->userv_path,argv); - perror("netlink-userv-ipif: execvp"); - - exit(1); + /* Mark rxfd non-blocking */ + if (fcntl(st->rxfd, F_SETFL, fcntl(st->rxfd, F_GETFL)|O_NONBLOCK)==-1) { + fatal_perror("%s: fcntl(O_NONBLOCK)",st->slip.nl.name); + } +} + +static void userv_kill_userv(struct userv *st) +{ + if (st->pid) { + kill(-st->pid,SIGTERM); + st->expecting_userv_exit=True; + } +} + +static void userv_phase_hook(void *sst, uint32_t newphase) +{ + struct userv *st=sst; + /* We must wait until signal processing has started before forking + userv */ + if (newphase==PHASE_RUN) { + userv_invoke_userv(st); + /* Register for poll() */ + register_for_poll(st, userv_beforepoll, userv_afterpoll, 2, + st->slip.nl.name); + } + if (newphase==PHASE_SHUTDOWN) { + userv_kill_userv(st); } - /* We are the parent... */ - - /* Register for poll() */ - register_for_poll(st, userv_beforepoll, userv_afterpoll, 2, st->nl.name); } static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context, @@ -246,9 +375,8 @@ static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context, dict=item->data.dict; - st->netlink_to_tunnel= - netlink_init(&st->nl,st,loc,dict, - "netlink-userv-ipif",NULL,userv_deliver_to_kernel); + slip_init(&st->slip,loc,dict,"netlink-userv-ipif", + userv_deliver_to_kernel); st->userv_path=dict_read_string(dict,"userv-path",False,"userv-netlink", loc); @@ -259,15 +387,13 @@ static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context, if (!st->userv_path) st->userv_path="userv"; if (!st->service_user) st->service_user="root"; if (!st->service_name) st->service_name="ipif"; - st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"userv-netlink",loc); - st->local_address=string_to_ipaddr( - dict_find_item(dict,"local-address", True, "netlink", loc),"netlink"); - BUF_ALLOC(st->buff,"netlink:userv_apply"); - st->rxfd=-1; st->txfd=-1; - add_hook(PHASE_DROPPRIV,userv_phase_hook,st); + st->pid=0; + st->expecting_userv_exit=False; + add_hook(PHASE_RUN,userv_phase_hook,st); + add_hook(PHASE_SHUTDOWN,userv_phase_hook,st); - return new_closure(&st->nl.cl); + return new_closure(&st->slip.nl.cl); } init_module slip_module; -- 2.30.2