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.