X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=slip.c;h=17b3c184899c2c68ab7bd6c7e3a5db4f492c7120;hp=7c138d10fe02306cbe792c11520f7520d537a08d;hb=af0869f572308469d78736416ff3141daf70d844;hpb=04f92904ea6c41517ff7154910c16ef4c3bc646b diff --git a/slip.c b/slip.c index 7c138d1..17b3c18 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,8 +24,9 @@ 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; }; /* Generic SLIP mangling code */ @@ -73,35 +75,67 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) BUF_ASSERT_USED(st->buff); for (i=0; ibuff->size) + buffer_init(st->buff,calculate_max_start_pad()); + if (st->pending_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; + st->buff->size=0; + } + } else { + if (outputchr == OUTPUT_END) { + if (st->buff->size>0) { + st->netlink_to_tunnel(&st->nl,st->buff); + BUF_ALLOC(st->buff,"userv_afterpoll"); + } + st->buff->size=0; + } 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; + } + } + } } } @@ -112,10 +146,9 @@ static void slip_init(struct slip *st, struct cloc loc, dict_t *dict, 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_item_to_ipaddr( - 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 */ @@ -177,6 +210,14 @@ static void userv_deliver_to_kernel(void *sst, struct buffer_if *buf) { struct userv *st=sst; + if (buf->size > st->slip.nl.mtu) { + Message(M_ERR,"%s: packet of size %"PRIu32" exceeds mtu %"PRIu32":" + " cannot be injected into kernel, dropped\n", + st->slip.nl.name, buf->size, st->slip.nl.mtu); + BUF_FREE(buf); + return; + } + slip_stuff(&st->slip,buf,st->txfd); } @@ -197,7 +238,8 @@ static void userv_userv_callback(void *sst, pid_t pid, int status) fatal("%s: userv exited unexpectedly: uncaught signal %d", st->slip.nl.name,WTERMSIG(status)); } else { - fatal("%s: userv stopped unexpectedly"); + fatal("%s: userv stopped unexpectedly", + st->slip.nl.name); } } Message(M_WARNING,"%s: userv subprocess died with status %d\n", @@ -252,16 +294,18 @@ static void userv_invoke_userv(struct userv *st) 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.local_address), ipaddr_to_string(st->slip.nl.secnet_address),st->slip.nl.mtu); allnets=ipset_new(); for (r=st->slip.nl.clients; r; r=r->next) { - struct ipset *nan; - r->kup=True; - nan=ipset_union(allnets,r->networks); - ipset_free(allnets); - allnets=nan; + if (r->link_quality > LINK_QUALITY_UNUSED) { + struct ipset *nan; + r->kup=True; + nan=ipset_union(allnets,r->networks); + ipset_free(allnets); + allnets=nan; + } } snets=ipset_to_subnet_list(allnets); ipset_free(allnets);