summaryrefslogtreecommitdiff
path: root/sbin/slaacd/engine.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/slaacd/engine.c')
-rw-r--r--sbin/slaacd/engine.c116
1 files changed, 86 insertions, 30 deletions
diff --git a/sbin/slaacd/engine.c b/sbin/slaacd/engine.c
index 961e1b115b6..b2955ea2ff5 100644
--- a/sbin/slaacd/engine.c
+++ b/sbin/slaacd/engine.c
@@ -1,4 +1,4 @@
-/* $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>
@@ -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;
+ }
+}