From 4a78c7cf1da74945eaac89675bb548f92d5e06fe Mon Sep 17 00:00:00 2001 From: florian Date: Wed, 11 Jul 2018 17:32:05 +0000 Subject: [PATCH] Send a RA with router lifetime of 0 when an interface is removed from the config. RFC 4861, 6.2.5: [...] the router SHOULD transmit one or more (but not more than MAX_FINAL_RTR_ADVERTISEMENTS) final multicast Router Advertisements on the interface with a Router Lifetime field of zero. --- usr.sbin/rad/engine.c | 46 +++++++++++++++++++++++++++++++++++---- usr.sbin/rad/frontend.c | 48 +++++++++++++++++++++++++++++++++-------- usr.sbin/rad/rad.h | 3 ++- 3 files changed, 83 insertions(+), 14 deletions(-) diff --git a/usr.sbin/rad/engine.c b/usr.sbin/rad/engine.c index 25df94b0ba3..4f568e37ee7 100644 --- a/usr.sbin/rad/engine.c +++ b/usr.sbin/rad/engine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: engine.c,v 1.4 2018/07/11 14:03:13 florian Exp $ */ +/* $OpenBSD: engine.c,v 1.5 2018/07/11 17:32:05 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -43,8 +43,8 @@ #include "rad.h" #include "engine.h" -#define MAX_RTR_ADV_INTERVAL 600 -#define MIN_RTR_ADV_INTERVAL 200 +#define MAX_RTR_ADV_INTERVAL 600 +#define MIN_RTR_ADV_INTERVAL 200 struct engine_iface { TAILQ_ENTRY(engine_iface) entry; @@ -63,6 +63,7 @@ void parse_ra_rs(struct imsg_ra_rs *); void parse_ra(struct imsg_ra_rs *); void parse_rs(struct imsg_ra_rs *); void update_iface(uint32_t); +void remove_iface(uint32_t); struct engine_iface *find_engine_iface_by_id(uint32_t); void iface_timeout(int, short, void *); @@ -147,6 +148,8 @@ engine(int debug, int verbose) if (inet_pton(AF_INET6, "ff02::1", &all_nodes.sin6_addr) != 1) fatal("inet_pton"); + TAILQ_INIT(&engine_interfaces); + event_dispatch(); engine_shutdown(); @@ -224,6 +227,13 @@ engine_dispatch_frontend(int fd, short event, void *bula) memcpy(&if_index, imsg.data, sizeof(if_index)); update_iface(if_index); break; + case IMSG_REMOVE_IF: + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index)) + fatal("%s: IMSG_REMOVE_IF wrong length: %d", + __func__, imsg.hdr.len); + memcpy(&if_index, imsg.data, sizeof(if_index)); + remove_iface(if_index); + break; case IMSG_CTL_LOG_VERBOSE: /* Already checked by frontend. */ memcpy(&verbose, imsg.data, sizeof(verbose)); @@ -487,6 +497,7 @@ update_iface(uint32_t if_index) engine_iface = calloc(1, sizeof(*engine_iface)); engine_iface->if_index = if_index; evtimer_set(&engine_iface->timer, iface_timeout, engine_iface); + TAILQ_INSERT_TAIL(&engine_interfaces, engine_iface, entry); } tv.tv_sec = 0; @@ -494,6 +505,34 @@ update_iface(uint32_t if_index) evtimer_add(&engine_iface->timer, &tv); } +void +remove_iface(uint32_t if_index) +{ + struct engine_iface *engine_iface; + struct imsg_send_ra send_ra; + char if_name[IF_NAMESIZE]; + + if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) { + /* we don't know this interface, frontend can delete it */ + engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, + &if_index, sizeof(if_index)); + return; + } + + send_ra.if_index = engine_iface->if_index; + memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); + + TAILQ_REMOVE(&engine_interfaces, engine_iface, entry); + evtimer_del(&engine_iface->timer); + + if (if_indextoname(if_index, if_name) != NULL) + engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, + sizeof(send_ra)); + engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, + &engine_iface->if_index, sizeof(engine_iface->if_index)); + free(engine_iface); +} + void iface_timeout(int fd, short events, void *arg) { @@ -501,7 +540,6 @@ iface_timeout(int fd, short events, void *arg) struct imsg_send_ra send_ra; struct timeval tv; - tv.tv_sec = MIN_RTR_ADV_INTERVAL + arc4random_uniform(MAX_RTR_ADV_INTERVAL - MIN_RTR_ADV_INTERVAL); tv.tv_usec = arc4random_uniform(1000000); diff --git a/usr.sbin/rad/frontend.c b/usr.sbin/rad/frontend.c index f6a7e7bee43..e3bc5376b7f 100644 --- a/usr.sbin/rad/frontend.c +++ b/usr.sbin/rad/frontend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frontend.c,v 1.3 2018/07/11 14:03:13 florian Exp $ */ +/* $OpenBSD: frontend.c,v 1.4 2018/07/11 17:32:05 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -129,6 +129,7 @@ int in6_mask2prefixlen(struct in6_addr *); void get_interface_prefixes(struct ra_iface *, struct ra_prefix_conf *); void build_package(struct ra_iface *); +void build_leaving_package(struct ra_iface *); void ra_output(struct ra_iface *, struct sockaddr_in6 *); struct rad_conf *frontend_conf; @@ -434,6 +435,7 @@ frontend_dispatch_engine(int fd, short event, void *bula) struct imsg imsg; struct imsg_send_ra send_ra; struct ra_iface *ra_iface; + uint32_t if_index; int n, shut = 0; if (event & EV_READ) { @@ -465,6 +467,17 @@ frontend_dispatch_engine(int fd, short event, void *bula) if (ra_iface) ra_output(ra_iface, &send_ra.to); break; + case IMSG_REMOVE_IF: + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index)) + fatal("%s: IMSG_REMOVE_IF wrong length: %d", + __func__, imsg.hdr.len); + memcpy(&if_index, imsg.data, sizeof(if_index)); + ra_iface = find_ra_iface_by_id(if_index); + if (ra_iface) { + TAILQ_REMOVE(&ra_interfaces, ra_iface, entry); + free_ra_iface(ra_iface); + } + break; default: log_debug("%s: error handling imsg %d", __func__, imsg.hdr.type); @@ -631,7 +644,7 @@ merge_ra_interfaces(void) { struct ra_iface_conf *ra_iface_conf; struct ra_prefix_conf *ra_prefix_conf; - struct ra_iface *ra_iface, *tmp; + struct ra_iface *ra_iface; uint32_t if_index; TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) @@ -660,13 +673,6 @@ merge_ra_interfaces(void) } } - TAILQ_FOREACH_SAFE(ra_iface, &ra_interfaces, entry, tmp) { - if (ra_iface->removed) { - TAILQ_REMOVE(&ra_interfaces, ra_iface, entry); - free_ra_iface(ra_iface); - } - } - TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) { while ((ra_prefix_conf = SIMPLEQ_FIRST(&ra_iface->prefixes)) != NULL) { @@ -676,6 +682,14 @@ merge_ra_interfaces(void) } ra_iface->prefix_count = 0; + if (ra_iface->removed) { + log_debug("iface removed: %s", ra_iface->name); + build_leaving_package(ra_iface); + frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, + &ra_iface->if_index, sizeof(ra_iface->if_index)); + continue; + } + ra_iface_conf = find_ra_iface_conf( &frontend_conf->ra_iface_list, ra_iface->name); @@ -897,6 +911,22 @@ build_package(struct ra_iface *ra_iface) } } +void +build_leaving_package(struct ra_iface *ra_iface) +{ + struct nd_router_advert ra; + size_t len; + + len = sizeof(ra); + + memset(&ra, 0, sizeof(ra)); + + ra.nd_ra_type = ND_ROUTER_ADVERT; + + memcpy(ra_iface->data, &ra, sizeof(ra)); + ra_iface->datalen = sizeof(ra); +} + void ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to) { diff --git a/usr.sbin/rad/rad.h b/usr.sbin/rad/rad.h index 445bf9c6f8b..ee9b32dc86a 100644 --- a/usr.sbin/rad/rad.h +++ b/usr.sbin/rad/rad.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rad.h,v 1.4 2018/07/11 14:03:13 florian Exp $ */ +/* $OpenBSD: rad.h,v 1.5 2018/07/11 17:32:05 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -62,6 +62,7 @@ enum imsg_type { IMSG_RA_RS, IMSG_SEND_RA, IMSG_UPDATE_IF, + IMSG_REMOVE_IF, IMSG_SOCKET_IPC }; -- 2.20.1