diff options
author | Florian Obser <florian@cvs.openbsd.org> | 2018-07-23 06:14:15 +0000 |
---|---|---|
committer | Florian Obser <florian@cvs.openbsd.org> | 2018-07-23 06:14:15 +0000 |
commit | 7a2a049403bb80e50a5be89d5ff8e2c2345b89b0 (patch) | |
tree | 536f2870a22835df31739331b0dfadbb2667c059 /sbin/slaacd/frontend.c | |
parent | 9ca8cb0a669109357766c425d569d5f96d7f7030 (diff) |
Handle duplicate address detection failures.
We get notified when duplication is detected on the route socket. For
privacy addresses simply generate a new random address. If we have
soii enabled increase the dad counter on the prefix and generate a new
address. For eui64 addresses nothing can be done.
Diffstat (limited to 'sbin/slaacd/frontend.c')
-rw-r--r-- | sbin/slaacd/frontend.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/sbin/slaacd/frontend.c b/sbin/slaacd/frontend.c index 96d69b8b661..cdbe7d11b5b 100644 --- a/sbin/slaacd/frontend.c +++ b/sbin/slaacd/frontend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frontend.c,v 1.20 2018/06/06 14:08:28 florian Exp $ */ +/* $OpenBSD: frontend.c,v 1.21 2018/07/23 06:14:14 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser <florian@openbsd.org> @@ -73,6 +73,7 @@ void get_lladdr(char *, struct ether_addr *, struct sockaddr_in6 *); void send_solicitation(uint32_t); #ifndef SMALL void update_autoconf_addresses(uint32_t, char*); +const char *flags_to_str(int); #endif /* SMALL */ struct imsgev *iev_main; @@ -592,6 +593,31 @@ update_autoconf_addresses(uint32_t if_index, char* if_name) } freeifaddrs(ifap); } + +const char* +flags_to_str(int flags) +{ + static char buf[sizeof(" anycast tentative duplicated detached " + "deprecated autoconf autoconfprivacy")]; + + buf[0] = '\0'; + if (flags & IN6_IFF_ANYCAST) + (void)strlcat(buf, " anycast", sizeof(buf)); + if (flags & IN6_IFF_TENTATIVE) + (void)strlcat(buf, " tentative", sizeof(buf)); + if (flags & IN6_IFF_DUPLICATED) + (void)strlcat(buf, " duplicated", sizeof(buf)); + if (flags & IN6_IFF_DETACHED) + (void)strlcat(buf, " detached", sizeof(buf)); + if (flags & IN6_IFF_DEPRECATED) + (void)strlcat(buf, " deprecated", sizeof(buf)); + if (flags & IN6_IFF_AUTOCONF) + (void)strlcat(buf, " autoconf", sizeof(buf)); + if (flags & IN6_IFF_PRIVACY) + (void)strlcat(buf, " autoconfprivacy", sizeof(buf)); + + return (buf); +} #endif /* SMALL */ void @@ -673,7 +699,10 @@ handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) struct imsg_proposal_ack proposal_ack; struct imsg_del_addr del_addr; struct imsg_del_route del_route; + struct imsg_dup_addr dup_addr; struct sockaddr_rtlabel *rl; + struct sockaddr_in6 *sin6; + struct in6_ifreq ifr6; struct in6_addr *in6; int64_t id, pid; int xflags, if_index; @@ -728,6 +757,42 @@ handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) ifm->ifm_index); } break; + case RTM_CHGADDRATTR: + ifm = (struct if_msghdr *)rtm; + if_name = if_indextoname(ifm->ifm_index, ifnamebuf); + if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family + == AF_INET6) { + sin6 = (struct sockaddr_in6 *) rti_info[RTAX_IFA]; + + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + break; + + memset(&ifr6, 0, sizeof(ifr6)); + (void) strlcpy(ifr6.ifr_name, if_name, + sizeof(ifr6.ifr_name)); + memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); + + if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) + < 0) { + log_warn("SIOCGIFAFLAG_IN6"); + break; + } + +#ifndef SMALL + log_debug("RTM_CHGADDRATTR: %s -%s", + sin6_to_str(sin6), + flags_to_str(ifr6.ifr_ifru.ifru_flags6)); +#endif /* SMALL */ + + if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED) { + dup_addr.if_index = ifm->ifm_index; + dup_addr.addr = *sin6; + frontend_imsg_compose_engine(IMSG_DUP_ADDRESS, + 0, 0, &dup_addr, sizeof(dup_addr)); + } + + } + break; case RTM_DELETE: ifm = (struct if_msghdr *)rtm; if ((rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | RTA_LABEL)) != |