When moving between networks slaacd configures new addresses but
authorflorian <florian@openbsd.org>
Mon, 23 Jul 2018 17:25:52 +0000 (17:25 +0000)
committerflorian <florian@openbsd.org>
Mon, 23 Jul 2018 17:25:52 +0000 (17:25 +0000)
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
sbin/slaacd/frontend.c
sbin/slaacd/slaacd.c
sbin/slaacd/slaacd.h

index b2955ea..58c39fb 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -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*
index cdbe7d1..e8bd2a6 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -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*
index 633864b..7afd9dc 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -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 +
index 1659c56..e230643 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -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 {