From 96316c8ddaeecefec32be78d215850f29699c19d Mon Sep 17 00:00:00 2001 From: florian Date: Mon, 23 Jul 2018 17:25:52 +0000 Subject: [PATCH] When moving between networks slaacd configures new addresses but leaves old ones behind. The IPv6 RFCs don't seem to offer guidance on what to do in this case. (RFC 5220 discusses related issues, but not exactly this.) It seems a bit harsh to just delete old addresses - a naive implementation can easily lead to flip-flopping between two prefixes. Instead set the preferred lifetime to 0 for all addresses on an interface when the link goes down, thus marking addresses as deprecated but still usable. When the link comes back send a router solicitation. If we are still on the old network and receive a router advertisement the preferred lifetime will increase and the addresses will no longer be deprecated. If we moved to a new network we will get new router advertisements and form new addresses. The old ones will stay deprecated and the address selection algorithm will prefer new addresses. Problem reported by many. testing & OK phessler --- sbin/slaacd/engine.c | 39 ++++++++++++++++++++++++++++++++++++++- sbin/slaacd/frontend.c | 17 ++++++++++++++++- sbin/slaacd/slaacd.c | 13 ++++++++++++- sbin/slaacd/slaacd.h | 8 +++++++- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/sbin/slaacd/engine.c b/sbin/slaacd/engine.c index b2955ea2ff5..58c39fb5c4a 100644 --- a/sbin/slaacd/engine.c +++ b/sbin/slaacd/engine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: engine.c,v 1.28 2018/07/23 06:14:14 florian Exp $ */ +/* $OpenBSD: engine.c,v 1.29 2018/07/23 17:25:52 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser @@ -214,6 +214,7 @@ struct slaacd_iface { struct ether_addr hw_address; struct sockaddr_in6 ll_address; uint8_t soiikey[SLAACD_SOIIKEY_LEN]; + int link_state; LIST_HEAD(, radv) radvs; LIST_HEAD(, address_proposal) addr_proposals; LIST_HEAD(, dfr_proposal) dfr_proposals; @@ -230,6 +231,7 @@ void send_interface_info(struct slaacd_iface *, pid_t); void engine_showinfo_ctl(struct imsg *, uint32_t); void debug_log_ra(struct imsg_ra *); int in6_mask2prefixlen(struct in6_addr *); +void deprecate_all_proposals(struct slaacd_iface *); #endif /* SMALL */ struct slaacd_iface *get_slaacd_iface_by_id(uint32_t); void remove_slaacd_iface(uint32_t); @@ -603,6 +605,7 @@ engine_dispatch_main(int fd, short event, void *bula) int shut = 0; #ifndef SMALL struct imsg_addrinfo imsg_addrinfo; + struct imsg_link_state imsg_link_state; struct address_proposal *addr_proposal = NULL; size_t i; #endif /* SMALL */ @@ -801,6 +804,27 @@ engine_dispatch_main(int fd, short event, void *bula) LIST_INSERT_HEAD(&iface->addr_proposals, addr_proposal, entries); + break; + case IMSG_UPDATE_LINK_STATE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(imsg_link_state)) + fatal("%s: IMSG_UPDATE_LINK_STATE wrong " + "length: %d", __func__, imsg.hdr.len); + + memcpy(&imsg_link_state, imsg.data, + sizeof(imsg_link_state)); + + iface = get_slaacd_iface_by_id( + imsg_link_state.if_index); + if (iface == NULL) + break; + if (iface->link_state != imsg_link_state.link_state) { + iface->link_state = imsg_link_state.link_state; + if (iface->link_state == LINK_STATE_DOWN) + deprecate_all_proposals(iface); + else + start_probe(iface); + } break; #endif /* SMALL */ default: @@ -982,6 +1006,19 @@ engine_showinfo_ctl(struct imsg *imsg, uint32_t if_index) break; } } +void +deprecate_all_proposals(struct slaacd_iface *iface) +{ + struct address_proposal *addr_proposal; + + log_debug("%s: iface: %d", __func__, iface->if_index); + + LIST_FOREACH (addr_proposal, &iface->addr_proposals, entries) { + addr_proposal->pltime = 0; + configure_address(addr_proposal); + addr_proposal->state = PROPOSAL_NEARLY_EXPIRED; + } +} #endif /* SMALL */ struct slaacd_iface* diff --git a/sbin/slaacd/frontend.c b/sbin/slaacd/frontend.c index cdbe7d11b5b..e8bd2a6a9a1 100644 --- a/sbin/slaacd/frontend.c +++ b/sbin/slaacd/frontend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frontend.c,v 1.21 2018/07/23 06:14:14 florian Exp $ */ +/* $OpenBSD: frontend.c,v 1.22 2018/07/23 17:25:52 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser @@ -508,6 +508,7 @@ update_autoconf_addresses(uint32_t if_index, char* if_name) struct ifaddrs *ifap, *ifa; struct in6_addrlifetime *lifetime; struct sockaddr_in6 *sin6; + struct imsg_link_state imsg_link_state; time_t t; int xflags; @@ -521,12 +522,20 @@ update_autoconf_addresses(uint32_t if_index, char* if_name) get_lladdr(if_name, &imsg_addrinfo.hw_address, &imsg_addrinfo.ll_address); + memset(&imsg_link_state, 0, sizeof(imsg_link_state)); + imsg_link_state.if_index = if_index; + if (getifaddrs(&ifap) != 0) fatal("getifaddrs"); for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if (strcmp(if_name, ifa->ifa_name) != 0) continue; + + if (ifa->ifa_addr->sa_family == AF_LINK) + imsg_link_state.link_state = + ((struct if_data *)ifa->ifa_data)->ifi_link_state; + if (ifa->ifa_addr->sa_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; @@ -592,6 +601,12 @@ update_autoconf_addresses(uint32_t if_index, char* if_name) } freeifaddrs(ifap); + + log_debug("%s: %s link state down? %s", __func__, if_name, + imsg_link_state.link_state == LINK_STATE_DOWN ? "yes" : "no"); + + frontend_imsg_compose_main(IMSG_UPDATE_LINK_STATE, 0, + &imsg_link_state, sizeof(imsg_link_state)); } const char* diff --git a/sbin/slaacd/slaacd.c b/sbin/slaacd/slaacd.c index 633864bf566..7afd9dc3ec7 100644 --- a/sbin/slaacd/slaacd.c +++ b/sbin/slaacd/slaacd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: slaacd.c,v 1.26 2018/07/23 06:14:14 florian Exp $ */ +/* $OpenBSD: slaacd.c,v 1.27 2018/07/23 17:25:52 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser @@ -393,6 +393,7 @@ main_dispatch_frontend(int fd, short event, void *bula) int shut = 0; #ifndef SMALL struct imsg_addrinfo imsg_addrinfo; + struct imsg_link_state imsg_link_state; int verbose; #endif /* SMALL */ @@ -438,6 +439,16 @@ main_dispatch_frontend(int fd, short event, void *bula) main_imsg_compose_engine(IMSG_UPDATE_ADDRESS, 0, &imsg_addrinfo, sizeof(imsg_addrinfo)); break; + case IMSG_UPDATE_LINK_STATE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(imsg_link_state)) + fatal("%s: IMSG_UPDATE_LINK_STATE wrong " + "length: %d", __func__, imsg.hdr.len); + memcpy(&imsg_link_state, imsg.data, + sizeof(imsg_link_state)); + main_imsg_compose_engine(IMSG_UPDATE_LINK_STATE, 0, + &imsg_link_state, sizeof(imsg_link_state)); + break; #endif /* SMALL */ case IMSG_UPDATE_IF: if (imsg.hdr.len != IMSG_HEADER_SIZE + diff --git a/sbin/slaacd/slaacd.h b/sbin/slaacd/slaacd.h index 1659c564abf..e2306438fda 100644 --- a/sbin/slaacd/slaacd.h +++ b/sbin/slaacd/slaacd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: slaacd.h,v 1.18 2018/07/23 06:14:14 florian Exp $ */ +/* $OpenBSD: slaacd.h,v 1.19 2018/07/23 17:25:52 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser @@ -55,6 +55,7 @@ enum imsg_type { IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL, IMSG_CTL_END, IMSG_UPDATE_ADDRESS, + IMSG_UPDATE_LINK_STATE, #endif /* SMALL */ IMSG_CTL_SEND_SOLICITATION, IMSG_SOCKET_IPC, @@ -168,6 +169,11 @@ struct imsg_addrinfo { uint32_t vltime; uint32_t pltime; }; + +struct imsg_link_state { + uint32_t if_index; + int link_state; +}; #endif /* SMALL */ struct imsg_ifinfo { -- 2.20.1