-/* $OpenBSD: engine.c,v 1.27 2018/06/20 14:55:29 florian Exp $ */
+/* $OpenBSD: engine.c,v 1.28 2018/07/23 06:14:14 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
PROPOSAL_CONFIGURED,
PROPOSAL_NEARLY_EXPIRED,
PROPOSAL_WITHDRAWN,
+ PROPOSAL_DUPLICATED,
};
const char* proposal_state_name[] = {
"CONFIGURED",
"NEARLY_EXPIRED",
"WITHDRAWN",
+ "DUPLICATED",
};
const char* rpref_name[] = {
int autonomous;
uint32_t vltime;
uint32_t pltime;
+ int dad_counter;
};
struct radv_rdns {
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;
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
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);
{
SHA2_CTX ctx;
struct in6_addr iid;
- int dad_counter = 0; /* XXX not used */
int i;
u_int8_t digest[SHA512_DIGEST_LENGTH];
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);
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) {
continue;
found = 0;
found_privacy = 0;
+ duplicate_found = 0;
+
LIST_FOREACH(addr_proposal, &iface->addr_proposals,
entries) {
if (prefix->prefix_len ==
* expires
*/
if (addr_proposal->state !=
- PROPOSAL_NEARLY_EXPIRED)
+ PROPOSAL_NEARLY_EXPIRED &&
+ addr_proposal->state !=
+ PROPOSAL_DUPLICATED)
found_privacy = 1;
if (!iface->autoconfprivacy)
continue;
}
+ if (addr_proposal->state ==
+ PROPOSAL_DUPLICATED) {
+ duplicate_found = 1;
+ continue;
+ }
+
found = 1;
remaining_lifetime =
}
}
+ 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 */
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]);
}
-/* 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
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;
+ }
+}
-/* $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>
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;
}
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
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;
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)) !=