X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/a28d65a5e8624c92be4fc3c4a9d8a0d46d92dcc5..cfd794827e3243c681590845063309fa628cfef4:/netlink.c diff --git a/netlink.c b/netlink.c index bc70757..87b6671 100644 --- a/netlink.c +++ b/netlink.c @@ -193,6 +193,10 @@ struct iphdr { uint16_t tot_len; uint16_t id; uint16_t frag_off; +#define IPHDR_FRAG_OFF ((uint16_t)0x1fff) +#define IPHDR_FRAG_MORE ((uint16_t)0x2000) +#define IPHDR_FRAG_DONT ((uint16_t)0x4000) +/* reserved 0x8000 */ uint8_t ttl; uint8_t protocol; uint16_t check; @@ -206,7 +210,7 @@ struct icmphdr { uint8_t type; uint8_t code; uint16_t check; - union { + union icmpinfofield { uint32_t unused; struct { uint8_t pointer; @@ -220,6 +224,8 @@ struct icmphdr { } echo; } d; }; + +static const union icmpinfofield icmp_noinfo; static void netlink_packet_deliver(struct netlink *st, struct netlink_client *client, @@ -293,6 +299,7 @@ static bool_t netlink_icmp_may_reply(struct buffer_if *buf) struct icmphdr *icmph; uint32_t source; + if (buf->size < (int)sizeof(struct icmphdr)) return False; iph=(struct iphdr *)buf->start; icmph=(struct icmphdr *)buf->start; if (iph->protocol==1) { @@ -304,7 +311,7 @@ static bool_t netlink_icmp_may_reply(struct buffer_if *buf) } } /* How do we spot broadcast destination addresses? */ - if (ntohs(iph->frag_off)&0x1fff) return False; /* Non-initial fragment */ + if (ntohs(iph->frag_off)&IPHDR_FRAG_OFF) return False; source=ntohl(iph->saddr); if (source==0) return False; if ((source&0xff000000)==0x7f000000) return False; @@ -338,6 +345,7 @@ static bool_t netlink_icmp_may_reply(struct buffer_if *buf) */ static uint16_t netlink_icmp_reply_len(struct buffer_if *buf) { + if (buf->size < (int)sizeof(struct iphdr)) return 0; struct iphdr *iph=(struct iphdr *)buf->start; uint16_t hlen,plen; @@ -352,16 +360,17 @@ static uint16_t netlink_icmp_reply_len(struct buffer_if *buf) comes from. NULL indicates the host. */ static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf, struct netlink_client *client, - uint8_t type, uint8_t code) + uint8_t type, uint8_t code, + union icmpinfofield info) { - struct iphdr *iph=(struct iphdr *)buf->start; struct icmphdr *h; uint16_t len; if (netlink_icmp_may_reply(buf)) { + struct iphdr *iph=(struct iphdr *)buf->start; len=netlink_icmp_reply_len(buf); h=netlink_icmp_tmpl(st,ntohl(iph->saddr),len); - h->type=type; h->code=code; + h->type=type; h->code=code; h->d=info; memcpy(buf_append(&st->icmp,len),buf->start,len); netlink_icmp_csum(h); netlink_packet_deliver(st,NULL,&st->icmp); @@ -389,6 +398,7 @@ static bool_t netlink_check(struct netlink *st, struct buffer_if *buf, return False; \ }while(0) + if (buf->size < (int)sizeof(struct iphdr)) BAD("len %"PRIu32"",buf->size); struct iphdr *iph=(struct iphdr *)buf->start; int32_t len; @@ -406,6 +416,28 @@ static bool_t netlink_check(struct netlink *st, struct buffer_if *buf, #undef BAD } +/* Deliver a packet _to_ client; used after we have decided + * what to do with it (and just to check that the client has + * actually registered a delivery function with us). */ +static void netlink_client_deliver(struct netlink *st, + struct netlink_client *client, + uint32_t source, uint32_t dest, + struct buffer_if *buf) +{ + if (!client->deliver) { + string_t s,d; + s=ipaddr_to_string(source); + d=ipaddr_to_string(dest); + Message(M_ERR,"%s: dropping %s->%s, client not registered\n", + st->name,s,d); + free(s); free(d); + BUF_FREE(buf); + return; + } + client->deliver(client->dst, buf); + client->outcount++; +} + /* Deliver a packet. "client" is the _origin_ of the packet, not its destination, and is NULL for packets from the host and packets generated internally in secnet. */ @@ -413,6 +445,13 @@ static void netlink_packet_deliver(struct netlink *st, struct netlink_client *client, struct buffer_if *buf) { + if (buf->size < (int)sizeof(struct iphdr)) { + Message(M_ERR,"%s: trying to deliver a too-short packet" + " from %s!\n",st->name, client?client->name:"(local)"); + BUF_FREE(buf); + return; + } + struct iphdr *iph=(struct iphdr *)buf->start; uint32_t dest=ntohl(iph->daddr); uint32_t source=ntohl(iph->saddr); @@ -489,7 +528,7 @@ static void netlink_packet_deliver(struct netlink *st, "(s=%s, d=%s)\n", st->name, s, d); free(s); free(d); netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE, - ICMP_CODE_NET_UNREACHABLE); + ICMP_CODE_NET_UNREACHABLE, icmp_noinfo); BUF_FREE(buf); } } else { @@ -506,19 +545,20 @@ static void netlink_packet_deliver(struct netlink *st, free(s); free(d); netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE, - ICMP_CODE_NET_PROHIBITED); + ICMP_CODE_NET_PROHIBITED, icmp_noinfo); BUF_FREE(buf); } else { if (best_quality>0) { /* XXX Fragment if required */ - st->routes[best_match]->deliver( - st->routes[best_match]->dst, buf); - st->routes[best_match]->outcount++; + netlink_client_deliver(st,st->routes[best_match], + source,dest,buf); BUF_ASSERT_FREE(buf); } else { /* Generate ICMP destination unreachable */ - netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE, - ICMP_CODE_NET_UNREACHABLE); /* client==NULL */ + netlink_icmp_simple(st,buf,client,/* client==NULL */ + ICMP_TYPE_UNREACHABLE, + ICMP_CODE_NET_UNREACHABLE, + icmp_noinfo); BUF_FREE(buf); } } @@ -530,6 +570,7 @@ static void netlink_packet_forward(struct netlink *st, struct netlink_client *client, struct buffer_if *buf) { + if (buf->size < (int)sizeof(struct iphdr)) return; struct iphdr *iph=(struct iphdr *)buf->start; BUF_ASSERT_USED(buf); @@ -538,7 +579,7 @@ static void netlink_packet_forward(struct netlink *st, if (iph->ttl<=1) { /* Generate ICMP time exceeded */ netlink_icmp_simple(st,buf,client,ICMP_TYPE_TIME_EXCEEDED, - ICMP_CODE_TTL_EXCEEDED); + ICMP_CODE_TTL_EXCEEDED,icmp_noinfo); BUF_FREE(buf); return; } @@ -559,9 +600,15 @@ static void netlink_packet_local(struct netlink *st, st->localcount++; + if (buf->size < (int)sizeof(struct icmphdr)) { + Message(M_WARNING,"%s: short packet addressed to secnet; " + "ignoring it\n",st->name); + BUF_FREE(buf); + return; + } h=(struct icmphdr *)buf->start; - if ((ntohs(h->iph.frag_off)&0xbfff)!=0) { + if ((ntohs(h->iph.frag_off)&(IPHDR_FRAG_OFF|IPHDR_FRAG_MORE))!=0) { Message(M_WARNING,"%s: fragmented packet addressed to secnet; " "ignoring it\n",st->name); BUF_FREE(buf); @@ -587,7 +634,7 @@ static void netlink_packet_local(struct netlink *st, } else { /* Send ICMP protocol unreachable */ netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE, - ICMP_CODE_PROTOCOL_UNREACHABLE); + ICMP_CODE_PROTOCOL_UNREACHABLE,icmp_noinfo); BUF_FREE(buf); return; } @@ -614,6 +661,7 @@ static void netlink_incoming(struct netlink *st, struct netlink_client *client, BUF_FREE(buf); return; } + assert(buf->size >= (int)sizeof(struct icmphdr)); iph=(struct iphdr *)buf->start; source=ntohl(iph->saddr); @@ -660,7 +708,7 @@ static void netlink_incoming(struct netlink *st, struct netlink_client *client, if (client) { st->deliver_to_host(st->dst,buf); } else { - st->clients->deliver(st->clients->dst,buf); + netlink_client_deliver(st,st->clients,source,dest,buf); } BUF_ASSERT_FREE(buf); return; @@ -726,7 +774,7 @@ static void netlink_dump_routes(struct netlink *st, bool_t requested) if (requested) c=M_WARNING; if (st->ptp) { net=ipaddr_to_string(st->secnet_address); - Message(c,"%s: point-to-point (remote end is %s); routes:\n", + Message(c,"%s: point-to-point (remote end is %s); routes: ", st->name, net); free(net); netlink_output_subnets(st,c,st->clients->subnets);