summaryrefslogtreecommitdiffstats
path: root/if-bsd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2016-08-05 09:41:51 +0000
committerRoy Marples <roy@marples.name>2016-08-05 09:41:51 +0000
commit19024074413d39af6a7722e4b9892efe4d6aebcd (patch)
treeacac2482e77b2cb66289b0b47760dd2532b305f1 /if-bsd.c
parent6d189cb65f5fbc8898841baf86f5288ae41b70b5 (diff)
downloaddhcpcd-19024074413d39af6a7722e4b9892efe4d6aebcd.tar.xz
Workaround an issue on BSD where the kernel pretends a freshly added address is from a RA and uses it's liftetime for the prefix route.
See comments in the changeset for more details.
Diffstat (limited to 'if-bsd.c')
-rw-r--r--if-bsd.c34
1 files changed, 33 insertions, 1 deletions
diff --git a/if-bsd.c b/if-bsd.c
index f6fb036c..3a91a49d 100644
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -909,6 +909,8 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
struct in6_addr mask;
struct priv *priv;
+ priv = (struct priv *)ia->iface->ctx->priv;
+
memset(&ifa, 0, sizeof(ifa));
strlcpy(ifa.ifra_name, ia->iface->name, sizeof(ifa.ifra_name));
/*
@@ -938,11 +940,41 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
ifa_scope(&ifa.ifra_addr, ia->iface->index);
ipv6_mask(&mask, ia->prefix_len);
ADDADDR(&ifa.ifra_prefixmask, &mask);
+
+ /*
+ * Every BSD kernel wants to add the prefix of the address to it's
+ * list of RA received prefixes.
+ * THIS IS WRONG because there (as the comments in the kernel state)
+ * is no API for managing prefix lifetime and the kernel should not
+ * pretend it's from a RA either.
+ *
+ * The issue is that the very first assigned prefix will inherit the
+ * lifetime of the address, but any subsequent alteration of the
+ * address OR it's lifetime will not affect the prefix lifetime.
+ * As such, we cannot stop the prefix from timing out and then
+ * constantly removing the prefix route dhcpcd is capable of adding
+ * in it's absense.
+ *
+ * What we can do to mitigate the issue is to add the adress with
+ * infinite lifetimes, so the prefix route will never time out.
+ * Once done, we can then set lifetimes on the address and all is good.
+ * The downside of this approach is that we need to manually remove
+ * the kernel route because it has no lifetime, but this is OK as
+ * dhcpcd will handle this too.
+ *
+ * This issue is discussed on the NetBSD mailing lists here:
+ * http://mail-index.netbsd.org/tech-net/2016/08/05/msg006044.html
+ */
+ if (cmd == RTM_NEWADDR && !(ia->flags & IPV6_AF_ADDED)) {
+ ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+ ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+ (void)ioctl(priv->pf_inet6_fd, SIOCAIFADDR_IN6, &ifa);
+ }
+
ifa.ifra_lifetime.ia6t_vltime = ia->prefix_vltime;
ifa.ifra_lifetime.ia6t_pltime = ia->prefix_pltime;
#undef ADDADDR
- priv = (struct priv *)ia->iface->ctx->priv;
return ioctl(priv->pf_inet6_fd,
cmd == RTM_DELADDR ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa);
}