X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=udp.c;h=307a67a9f7d67cdb8dd42758040d3435e054d070;hb=7138d0c54cd2212439434d27cb2d6ea775c3039b;hp=177ce1c23b4481563cf3d2e2895dcb780ae8cc45;hpb=2fe58dfd10216a37f1ece081f926971882de112e;p=secnet.git diff --git a/udp.c b/udp.c index 177ce1c..307a67a 100644 --- a/udp.c +++ b/udp.c @@ -12,16 +12,14 @@ * Packets are offered to registered receivers in turn. Once one * accepts it, it isn't offered to any more. */ +#include "secnet.h" #include #include #include #include #include -#include #include -#include - -#include "secnet.h" +#include #include "util.h" static beforepoll_fn udp_beforepoll; @@ -44,7 +42,9 @@ struct udp { closure_t cl; struct comm_if ops; struct cloc loc; + uint16_t port; int fd; + string_t authbind; struct buffer_if *rbuf; struct notify_list *notify; }; @@ -148,14 +148,69 @@ static bool_t udp_sendmsg(void *commst, struct buffer_if *buf, return True; } +static void udp_phase_hook(void *sst, uint32_t new_phase) +{ + struct udp *st=sst; + struct sockaddr_in addr; + + st->fd=socket(AF_INET, SOCK_DGRAM, 0); + if (st->fd<0) { + fatal_perror("udp (%s:%d): socket",st->loc.file,st->loc.line); + } + if (fcntl(st->fd, F_SETFL, fcntl(st->fd, F_GETFL)|O_NONBLOCK)==-1) { + fatal_perror("udp (%s:%d): fcntl(set O_NONBLOCK)", + st->loc.file,st->loc.line); + } + if (fcntl(st->fd, F_SETFD, FD_CLOEXEC)==-1) { + fatal_perror("udp (%s:%d): fcntl(set FD_CLOEXEC)", + st->loc.file,st->loc.line); + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family=AF_INET; + addr.sin_port=htons(st->port); + if (st->authbind) { + pid_t c; + int status; + + /* XXX this fork() and waitpid() business needs to be hidden + in some system-specific library functions. */ + c=fork(); + if (c==-1) { + fatal_perror("udp_phase_hook: fork() for authbind"); + } + if (c==0) { + char *argv[4]; + argv[0]=st->authbind; + argv[1]="00000000"; + argv[2]=alloca(8); + if (!argv[2]) exit(ENOMEM); + sprintf(argv[2],"%04X",htons(st->port)); + argv[3]=NULL; + dup2(st->fd,0); + execvp(st->authbind,argv); + exit(ENOEXEC); + } + waitpid(c,&status,0); + if (WEXITSTATUS(status)!=0) { + errno=WEXITSTATUS(status); + fatal_perror("udp (%s:%d): authbind",st->loc.file,st->loc.line); + } + } else { + if (bind(st->fd, (struct sockaddr *)&addr, sizeof(addr))!=0) { + fatal_perror("udp (%s:%d): bind",st->loc.file,st->loc.line); + } + } + + register_for_poll(st,udp_beforepoll,udp_afterpoll,1,"udp"); +} + static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, list_t *args) { struct udp *st; item_t *i; dict_t *d; - uint16_t local_port=0; - struct sockaddr_in addr; st=safe_malloc(sizeof(*st),"udp_apply(st)"); st->loc=loc; @@ -167,6 +222,7 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, st->ops.request_notify=request_notify; st->ops.release_notify=release_notify; st->ops.sendmsg=udp_sendmsg; + st->port=0; i=list_elem(args,0); if (!i || i->type!=t_dict) { @@ -174,32 +230,11 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, } d=i->data.dict; - local_port=dict_read_number(d,"port",False,"udp",st->loc,0); + st->port=dict_read_number(d,"port",True,"udp",st->loc,0); st->rbuf=find_cl_if(d,"buffer",CL_BUFFER,True,"udp",st->loc); + st->authbind=dict_read_string(d,"authbind",False,"udp",st->loc); - st->fd=socket(AF_INET, SOCK_DGRAM, 0); - if (st->fd<0) { - fatal_perror("udp_apply (%s:%d): socket",loc.file,loc.line); - } - if (fcntl(st->fd, F_SETFL, fcntl(st->fd, F_GETFL)|O_NONBLOCK)==-1) { - fatal_perror("udp_apply (%s:%d): fcntl(set O_NONBLOCK)", - loc.file,loc.line); - } - if (fcntl(st->fd, F_SETFD, FD_CLOEXEC)==-1) { - fatal_perror("udp_apply (%s:%d): fcntl(set FD_CLOEXEC)", - loc.file,loc.line); - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family=AF_INET; - if (local_port) { - addr.sin_port=htons(local_port); - } - if (bind(st->fd, (struct sockaddr *)&addr, sizeof(addr))!=0) { - fatal_perror("udp_apply (%s:%d): bind",loc.file,loc.line); - } - - register_for_poll(st,udp_beforepoll,udp_afterpoll,1,"udp"); + add_hook(PHASE_GETRESOURCES,udp_phase_hook,st); return new_closure(&st->cl); }