X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/b2a56f7c93d221607864761c590952b9a614dc9f..c6f79b178fe27ee315055dccb371b63ca1a6183a:/netlink.c diff --git a/netlink.c b/netlink.c index 022ddf1..f77d6bd 100644 --- a/netlink.c +++ b/netlink.c @@ -10,7 +10,9 @@ #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) @@ -433,8 +435,8 @@ static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf) /* Check source */ if (client) { - /* Check that the packet source is in 'nets' and its destination is - in st->networks */ + /* Check that the packet source is appropriate for the tunnel + it came down */ if (!subnet_matches_list(client->networks,source)) { string_t s,d; s=ipaddr_to_string(source); @@ -446,6 +448,9 @@ static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf) return; } } else { + /* Check that the packet originates in our configured local + network, and hasn't been forwarded from elsewhere or + generated with the wrong source address */ if (!subnet_matches_list(&st->networks,source)) { string_t s,d; s=ipaddr_to_string(source); @@ -457,6 +462,20 @@ static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf) return; } } + + /* If this is a point-to-point device we don't examine the packet at + all; we blindly send it down our one-and-only registered tunnel, + or to the host, depending on where it came from. */ + if (st->ptp) { + if (client) { + st->deliver_to_host(st->dst,NULL,buf); + } else { + st->clients->deliver(st->clients->dst,NULL,buf); + } + BUF_ASSERT_FREE(buf); + return; + } + /* (st->secnet_address needs checking before matching destination addresses) */ if (dest==st->secnet_address) { @@ -483,15 +502,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]); + } } } } @@ -503,9 +525,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); } } @@ -540,14 +562,20 @@ static void *netlink_regnets(void *sst, struct subnet_list *nets, Message(M_ERROR,"%s: site %s specifies networks that " "intersect with the explicitly excluded remote networks\n", st->name,client_name); - return False; + return NULL; + } + + if (st->clients && st->ptp) { + fatal("%s: only one site may use a point-to-point netlink device\n", + st->name); + return NULL; } c=safe_malloc(sizeof(*c),"netlink_regnets"); c->networks=nets; c->deliver=deliver; c->dst=dst; - c->name=client_name; /* XXX copy it? */ + c->name=client_name; c->options=options; c->link_quality=LINK_QUALITY_DOWN; c->next=st->clients; @@ -559,26 +587,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); } } @@ -599,6 +630,13 @@ static void netlink_phase_hook(void *sst, uint32_t new_phase) struct netlink_client *c; uint32_t i,j; + if (!st->clients && st->ptp) { + /* Point-to-point netlink devices must have precisely one + client. If none has registered by now, complain. */ + fatal("%s: point-to-point netlink devices must have precisely " + "one client. This one doesn't have any.\n",st->name); + } + /* All the networks serviced by the various tunnels should now * have been registered. We build a routing table by sorting the * routes into most-specific-first order. */ @@ -617,6 +655,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++; } } @@ -629,7 +668,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, @@ -638,6 +684,8 @@ netlink_deliver_fn *netlink_init(struct netlink *st, netlink_route_fn *set_route, netlink_deliver_fn *to_host) { + item_t *sa, *ptpa; + st->dst=dst; st->cl.description=description; st->cl.type=CL_NETLINK; @@ -662,14 +710,30 @@ netlink_deliver_fn *netlink_init(struct netlink *st, /* secnet-address does not have to be in local-networks; however, it should be advertised in the 'sites' file for the local site. */ - st->secnet_address=string_to_ipaddr( - dict_find_item(dict,"secnet-address", True, "netlink", loc),"netlink"); + sa=dict_find_item(dict,"secnet-address",False,"netlink",loc); + ptpa=dict_find_item(dict,"ptp-address", False, "netlink", loc); + if (sa && ptpa) { + cfgfatal(loc,st->name,"you may not specify secnet-address and " + "ptp-address in the same netlink device\n"); + } + if (!(sa || ptpa)) { + cfgfatal(loc,st->name,"you must specify secnet-address or " + "ptp-address for this netlink device\n"); + } + if (sa) { + st->secnet_address=string_to_ipaddr(sa,"netlink"); + st->ptp=False; + } else { + st->secnet_address=string_to_ipaddr(ptpa,"netlink"); + st->ptp=True; + } st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU); buffer_new(&st->icmp,ICMP_BUFSIZE); st->n_routes=0; st->routes=NULL; add_hook(PHASE_SETUP,netlink_phase_hook,st); + request_signal_notification(SIGUSR1, netlink_signal_handler, st); return netlink_incoming; }