anyone? On Wed, Jul 18, 2018 at 01:55:37PM +0200, Florian Obser wrote: > > 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. > > OK? > > diff --git engine.c engine.c > index 961e1b115b6..326529caefc 100644 > --- engine.c > +++ engine.c > @@ -106,6 +106,7 @@ enum proposal_state { > PROPOSAL_CONFIGURED, > PROPOSAL_NEARLY_EXPIRED, > PROPOSAL_WITHDRAWN, > + PROPOSAL_DUPLICATED, > }; > > const char* proposal_state_name[] = { > @@ -114,6 +115,7 @@ const char* proposal_state_name[] = { > "CONFIGURED", > "NEARLY_EXPIRED", > "WITHDRAWN", > + "DUPLICATED", > }; > > const char* rpref_name[] = { > @@ -130,6 +132,7 @@ struct radv_prefix { > int autonomous; > uint32_t vltime; > uint32_t pltime; > + int dad_counter; > }; > > struct radv_rdns { > @@ -261,11 +264,10 @@ struct dfr_proposal *find_dfr_proposal_by_id(struct > slaacd_iface *, > int64_t); > struct dfr_proposal *find_dfr_proposal_by_gw(struct slaacd_iface *, > struct sockaddr_in6 *); > -void find_prefix(struct slaacd_iface *, struct > - address_proposal *, struct radv **, struct > - radv_prefix **); > +struct radv_prefix *find_prefix(struct radv *, struct radv_prefix *); > int engine_imsg_compose_main(int, pid_t, void *, uint16_t); > uint32_t real_lifetime(struct timespec *, uint32_t); > +void merge_dad_couters(struct radv *, struct radv *); > > struct imsgev *iev_frontend; > struct imsgev *iev_main; > @@ -392,6 +394,8 @@ engine_dispatch_frontend(int fd, short event, void *bula) > struct dfr_proposal *dfr_proposal = NULL; > struct imsg_del_addr del_addr; > struct imsg_del_route del_route; > + struct imsg_dup_addr dup_addr; > + struct timeval tv; > ssize_t n; > int shut = 0; > #ifndef SMALL > @@ -546,6 +550,31 @@ engine_dispatch_frontend(int fd, short event, void *bula) > start_probe(iface); > } > break; > + case IMSG_DUP_ADDRESS: > + if (imsg.hdr.len != IMSG_HEADER_SIZE + > + sizeof(dup_addr)) > + fatal("%s: IMSG_DUP_ADDRESS wrong length: %d", > + __func__, imsg.hdr.len); > + memcpy(&dup_addr, imsg.data, sizeof(dup_addr)); > + iface = get_slaacd_iface_by_id(dup_addr.if_index); > + if (iface == NULL) { > + log_debug("IMSG_DUP_ADDRESS: unknown interface" > + ", ignoring"); > + break; > + } > + > + addr_proposal = find_address_proposal_by_addr(iface, > + &dup_addr.addr); > + > + if (addr_proposal) { > + /* XXX should we inform netcfgd? */ > + addr_proposal->state = PROPOSAL_DUPLICATED; > + tv.tv_sec = 0; > + tv.tv_usec = arc4random_uniform(1000000); > + addr_proposal->next_timeout = 0; > + evtimer_add(&addr_proposal->timer, &tv); > + } > + break; > default: > log_debug("%s: unexpected imsg %d", __func__, > imsg.hdr.type); > @@ -1261,7 +1290,6 @@ gen_addr(struct slaacd_iface *iface, struct radv_prefix > *prefix, struct > { > SHA2_CTX ctx; > struct in6_addr iid; > - int dad_counter = 0; /* XXX not used */ > int i; > u_int8_t digest[SHA512_DIGEST_LENGTH]; > > @@ -1293,7 +1321,8 @@ gen_addr(struct slaacd_iface *iface, struct radv_prefix > *prefix, struct > sizeof(prefix->prefix)); > SHA512Update(&ctx, &iface->hw_address, > sizeof(iface->hw_address)); > - SHA512Update(&ctx, &dad_counter, sizeof(dad_counter)); > + SHA512Update(&ctx, &prefix->dad_counter, > + sizeof(prefix->dad_counter)); > SHA512Update(&ctx, addr_proposal->soiikey, > sizeof(addr_proposal->soiikey)); > SHA512Final(digest, &ctx); > @@ -1601,13 +1630,16 @@ void update_iface_ra(struct slaacd_iface *iface, > struct radv *ra) > struct address_proposal *addr_proposal; > struct dfr_proposal *dfr_proposal, *tmp; > uint32_t remaining_lifetime; > - int found, found_privacy; > + int found, found_privacy, duplicate_found; > const char *hbuf; > > if ((old_ra = find_ra(iface, &ra->from)) == NULL) > LIST_INSERT_HEAD(&iface->radvs, ra, entries); > else { > LIST_REPLACE(old_ra, ra, entries); > + > + merge_dad_couters(old_ra, ra); > + > free_ra(old_ra); > } > if (ra->router_lifetime == 0) { > @@ -1674,6 +1706,8 @@ void update_iface_ra(struct slaacd_iface *iface, struct > radv *ra) > continue; > found = 0; > found_privacy = 0; > + duplicate_found = 0; > + > LIST_FOREACH(addr_proposal, &iface->addr_proposals, > entries) { > if (prefix->prefix_len == > @@ -1699,7 +1733,9 @@ void update_iface_ra(struct slaacd_iface *iface, struct > radv *ra) > * expires > */ > if (addr_proposal->state != > - PROPOSAL_NEARLY_EXPIRED) > + PROPOSAL_NEARLY_EXPIRED && > + addr_proposal->state != > + PROPOSAL_DUPLICATED) > found_privacy = 1; > > if (!iface->autoconfprivacy) > @@ -1715,6 +1751,12 @@ void update_iface_ra(struct slaacd_iface *iface, > struct radv *ra) > continue; > } > > + if (addr_proposal->state == > + PROPOSAL_DUPLICATED) { > + duplicate_found = 1; > + continue; > + } > + > found = 1; > > remaining_lifetime = > @@ -1751,6 +1793,12 @@ void update_iface_ra(struct slaacd_iface *iface, > struct radv *ra) > } > } > > + if (!found && duplicate_found && iface->soii) { > + prefix->dad_counter++; > + log_debug("%s dad_counter: %d", > + __func__, prefix->dad_counter); > + } > + > if (!found && > (iface->soii || prefix->prefix_len <= 64)) > /* new proposal */ > @@ -2117,6 +2165,13 @@ address_proposal_timeout(int fd, short events, void > *arg) > log_debug("%s: scheduling new timeout in %llds.%06ld", > __func__, tv.tv_sec, tv.tv_usec); > break; > + case PROPOSAL_DUPLICATED: > + engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION, > + 0, &addr_proposal->if_index, > + sizeof(addr_proposal->if_index)); > + log_debug("%s: address duplicated", > + __func__); > + break; > default: > log_debug("%s: unhandled state: %s", __func__, > proposal_state_name[addr_proposal->state]); > @@ -2304,32 +2359,19 @@ find_dfr_proposal_by_gw(struct slaacd_iface *iface, > struct sockaddr_in6 > } > > > -/* XXX currently unused */ > -void > -find_prefix(struct slaacd_iface *iface, struct address_proposal > *addr_proposal, > - struct radv **result_ra, struct radv_prefix **result_prefix) > +struct radv_prefix * > +find_prefix(struct radv *ra, struct radv_prefix *prefix) > { > - struct radv *ra; > - struct radv_prefix *prefix; > - uint32_t lifetime, max_lifetime = 0; > + struct radv_prefix *result; > > - *result_ra = NULL; > - *result_prefix = NULL; > > - LIST_FOREACH(ra, &iface->radvs, entries) { > - LIST_FOREACH(prefix, &ra->prefixes, entries) { > - if (memcmp(&prefix->prefix, &addr_proposal->prefix, > - sizeof(addr_proposal->prefix)) != 0) > - continue; > - lifetime = real_lifetime(&ra->uptime, > - prefix->vltime); > - if (lifetime > max_lifetime) { > - max_lifetime = lifetime; > - *result_ra = ra; > - *result_prefix = prefix; > - } > - } > + LIST_FOREACH(result, &ra->prefixes, entries) { > + if (memcmp(&result->prefix, &prefix->prefix, > + sizeof(prefix->prefix)) == 0 && result->prefix_len == > + prefix->prefix_len) > + return (result); > } > + return (NULL); > } > > uint32_t > @@ -2350,3 +2392,17 @@ real_lifetime(struct timespec *received_uptime, > uint32_t ltime) > > return (remaining); > } > + > +void > +merge_dad_couters(struct radv *old_ra, struct radv *new_ra) > +{ > + > + struct radv_prefix *old_prefix, *new_prefix; > + > + LIST_FOREACH(old_prefix, &old_ra->prefixes, entries) { > + if (!old_prefix->dad_counter) > + continue; > + if ((new_prefix = find_prefix(new_ra, old_prefix)) != NULL) > + new_prefix->dad_counter = old_prefix->dad_counter; > + } > +} > diff --git frontend.c frontend.c > index 96d69b8b661..d959be89b01 100644 > --- frontend.c > +++ frontend.c > @@ -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)) != > diff --git slaacd.c slaacd.c > index 6778659fa10..9ea6649d48b 100644 > --- slaacd.c > +++ slaacd.c > @@ -275,7 +275,7 @@ main(int argc, char *argv[]) > > rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_NEWADDR) | > ROUTE_FILTER(RTM_DELADDR) | ROUTE_FILTER(RTM_PROPOSAL) | > - ROUTE_FILTER(RTM_DELETE); > + ROUTE_FILTER(RTM_DELETE) | ROUTE_FILTER(RTM_CHGADDRATTR); > if (setsockopt(frontend_routesock, PF_ROUTE, ROUTE_MSGFILTER, > &rtfilter, sizeof(rtfilter)) < 0) > fatal("setsockopt(ROUTE_MSGFILTER)"); > diff --git slaacd.h slaacd.h > index 910be91e687..a71ae8380cd 100644 > --- slaacd.h > +++ slaacd.h > @@ -74,6 +74,7 @@ enum imsg_type { > IMSG_FAKE_ACK, > IMSG_CONFIGURE_DFR, > IMSG_WITHDRAW_DFR, > + IMSG_DUP_ADDRESS, > }; > > enum { > @@ -202,6 +203,11 @@ struct imsg_ra { > uint8_t packet[1500]; > }; > > +struct imsg_dup_addr { > + uint32_t if_index; > + struct sockaddr_in6 addr; > +}; > + > /* slaacd.c */ > void imsg_event_add(struct imsgev *); > int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, > > > -- > I'm not entirely sure you are real. >
-- I'm not entirely sure you are real.