X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=slip.c;h=d8f1a17113f4cd20b8711617f684c07a1f1f159a;hp=369651f459ec5cf3f0915b8eac4c96ee473d76e0;hb=1ce2f8bc69bc1bef98b48f450081d96e2c29cc00;hpb=4f5e39ecfaa49376b0a5c3a4c384e91a828c1105;ds=sidebyside diff --git a/slip.c b/slip.c index 369651f..d8f1a17 100644 --- a/slip.c +++ b/slip.c @@ -7,6 +7,7 @@ #include "util.h" #include "netlink.h" #include "process.h" +#include "unaligned.h" #include #include #include @@ -23,6 +24,8 @@ struct slip { struct buffer_if *buff; /* We unstuff received packets into here and send them to the netlink code. */ bool_t pending_esc; + bool_t ignoring_packet; /* If this packet was corrupt or overlong, + we ignore everything up to the next END */ netlink_deliver_fn *netlink_to_tunnel; uint32_t local_address; }; @@ -33,7 +36,7 @@ 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; + int32_t j=0; BUF_ASSERT_USED(buf); @@ -73,40 +76,69 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) 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; + outputchr=SLIP_END; break; case SLIP_ESCESC: - *(uint8_t *)buf_append(st->buff,1)=SLIP_ESC; + outputchr=SLIP_ESC; break; default: - fatal("userv_afterpoll: bad SLIP escape character"); + if (!st->ignoring_packet) { + Message(M_WARNING, "userv_afterpoll: bad SLIP escape" + " character, dropping packet\n"); + } + st->ignoring_packet=True; + outputchr=OUTPUT_NOTHING; + break; } } else { switch (buf[i]) { case SLIP_END: - if (st->buff->size>0) { - st->netlink_to_tunnel(&st->nl,st->buff); - BUF_ALLOC(st->buff,"userv_afterpoll"); - } - buffer_init(st->buff,st->nl.max_start_pad); + outputchr=OUTPUT_END; break; case SLIP_ESC: st->pending_esc=True; + outputchr=OUTPUT_NOTHING; break; default: - *(uint8_t *)buf_append(st->buff,1)=buf[i]; + outputchr=buf[i]; break; } } + + if (st->ignoring_packet) { + if (outputchr == OUTPUT_END) { + st->ignoring_packet=False; + buffer_init(st->buff,st->nl.max_start_pad); + } + } else { + if (outputchr == OUTPUT_END) { + if (st->buff->size>0) { + st->netlink_to_tunnel(&st->nl,st->buff); + BUF_ALLOC(st->buff,"userv_afterpoll"); + } + buffer_init(st->buff,st->nl.max_start_pad); + } else if (outputchr != OUTPUT_NOTHING) { + if (st->buff->size < st->buff->len) { + buf_append_uint8(st->buff,outputchr); + } else { + Message(M_WARNING, "userv_afterpoll: dropping overlong" + " SLIP packet\n"); + st->ignoring_packet=True; + } + } + } } } static void slip_init(struct slip *st, struct cloc loc, dict_t *dict, - string_t name, netlink_deliver_fn *to_host) + cstring_t name, netlink_deliver_fn *to_host) { st->netlink_to_tunnel= netlink_init(&st->nl,st,loc,dict, @@ -116,6 +148,7 @@ static void slip_init(struct slip *st, struct cloc loc, dict_t *dict, dict_find_item(dict,"local-address", True, name, loc),"netlink"); BUF_ALLOC(st->buff,"slip_init"); st->pending_esc=False; + st->ignoring_packet=False; } /* Connection to the kernel through userv-ipif */ @@ -124,33 +157,31 @@ struct userv { 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; + cstring_t userv_path; + cstring_t service_user; + cstring_t service_name; pid_t pid; bool_t expecting_userv_exit; }; static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io, - int *timeout_io, const struct timeval *tv_now, - uint64_t *now) + int *timeout_io) { struct userv *st=sst; if (st->rxfd!=-1) { *nfds_io=2; fds[0].fd=st->txfd; - fds[0].events=POLLERR; /* Might want to pick up POLLOUT sometime */ + fds[0].events=0; /* Might want to pick up POLLOUT sometime */ fds[1].fd=st->rxfd; - fds[1].events=POLLIN|POLLERR|POLLHUP; + fds[1].events=POLLIN; } else { *nfds_io=0; } return 0; } -static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds, - const struct timeval *tv_now, uint64_t *now) +static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds) { struct userv *st=sst; uint8_t rxbuf[DEFAULT_BUFSIZE]; @@ -208,8 +239,8 @@ static void userv_userv_callback(void *sst, pid_t pid, int status) } struct userv_entry_rec { - string_t path; - char **argv; + cstring_t path; + const char **argv; int in; int out; /* XXX perhaps we should collect and log stderr? */ @@ -224,7 +255,9 @@ static void userv_entry(void *sst) /* XXX close all other fds */ setsid(); - execvp(st->path,st->argv); + /* XXX We really should strdup() all of argv[] but because we'll just + exit anyway if execvp() fails it doesn't seem worth bothering. */ + execvp(st->path,(char *const*)st->argv); perror("userv-entry: execvp()"); exit(1); } @@ -257,7 +290,7 @@ static void userv_invoke_userv(struct userv *st) allnets=ipset_new(); for (r=st->slip.nl.clients; r; r=r->next) { - if (r->up) { + if (r->link_quality > LINK_QUALITY_UNUSED) { struct ipset *nan; r->kup=True; nan=ipset_union(allnets,r->networks); @@ -405,7 +438,6 @@ static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context, return new_closure(&st->slip.nl.cl); } -init_module slip_module; void slip_module(dict_t *dict) { add_closure(dict,"userv-ipif",userv_apply);