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.

Reply via email to