first thing that actually changes addresses: link local addresses
- generate new link local address if soiikey changes
- honour NOSOII flag when generating link local address
- regen link local address if NOSOII flag changes
OK?
diff --git sys/net/if.c sys/net/if.c
index 7477fa5606a..b11414c2266 100644
--- sys/net/if.c
+++ sys/net/if.c
@@ -1827,6 +1827,9 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data,
struct proc *p)
char ifdescrbuf[IFDESCRSIZE];
char ifrtlabelbuf[RTLABEL_LEN];
int s, error = 0;
+#ifdef INET6
+ int soii_changed = 0;
+#endif /* INET6 */
size_t bytesdone;
short oif_flags;
const char *label;
@@ -1952,6 +1955,12 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data,
struct proc *p)
if (error != 0)
return (error);
}
+
+ if ((ISSET(ifr->ifr_flags, IFXF_INET6_NOSOII) &&
+ !ISSET(ifp->if_xflags, IFXF_INET6_NOSOII)) ||
+ (!ISSET(ifr->ifr_flags, IFXF_INET6_NOSOII) &&
+ ISSET(ifp->if_xflags, IFXF_INET6_NOSOII)))
+ soii_changed = 1;
#endif /* INET6 */
#ifdef MPLS
@@ -2002,6 +2011,10 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data,
struct proc *p)
ifp->if_xflags = (ifp->if_xflags & IFXF_CANTCHANGE) |
(ifr->ifr_flags & ~IFXF_CANTCHANGE);
rtm_ifchg(ifp);
+#ifdef INET6
+ if (soii_changed)
+ in6_soiiupdate(ifp);
+#endif /* INET6 */
break;
case SIOCSIFMETRIC:
diff --git sys/netinet6/in6_ifattach.c sys/netinet6/in6_ifattach.c
index 89acde9c6a4..dd6085d0b9f 100644
--- sys/netinet6/in6_ifattach.c
+++ sys/netinet6/in6_ifattach.c
@@ -58,6 +58,7 @@
int get_last_resort_ifid(struct ifnet *, struct in6_addr *);
int get_hw_ifid(struct ifnet *, struct in6_addr *);
+int get_soii_ifid(struct ifnet *, struct in6_addr *);
int get_ifid(struct ifnet *, struct in6_addr *);
int in6_ifattach_loopback(struct ifnet *);
@@ -72,6 +73,26 @@ int in6_ifattach_loopback(struct ifnet *);
#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
+void
+in6_soiiupdate(struct ifnet *ifp)
+{
+ struct ifaddr *ifa;
+ int s;
+
+ s = splnet();
+
+ /*
+ * Update the link-local address.
+ */
+ ifa = &in6ifa_ifpforlinklocal(ifp, 0)->ia_ifa;
+ if (ifa) {
+ in6_purgeaddr(ifa);
+ dohooks(ifp->if_addrhooks, 0);
+ in6_ifattach(ifp);
+ }
+ splx(s);
+}
+
/*
* Generate a last-resort interface identifier, when the machine has no
* IEEE802/EUI64 address sources.
@@ -231,6 +252,45 @@ get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
}
/*
+ * Generate a Semantically Opaque Interface Identifier according to RFC 7217
+ *
+ * in6 - upper 64bits are preserved
+ */
+int
+get_soii_ifid(struct ifnet *ifp, struct in6_addr *in6)
+{
+ SHA2_CTX ctx;
+ u_int8_t digest[SHA512_DIGEST_LENGTH];
+ struct in6_addr prefix;
+ struct sockaddr_dl *sdl;
+ int dad_counter = 0; /* XXX not used */
+ char *addr;
+
+ if (ifp->if_xflags & IFXF_INET6_NOSOII)
+ return -1;
+
+ sdl = ifp->if_sadl;
+ if (sdl == NULL || sdl->sdl_alen == 0)
+ return -1;
+
+ memset(&prefix, 0, sizeof(prefix));
+ prefix.s6_addr16[0] = htons(0xfe80);
+ addr = LLADDR(sdl);
+
+ SHA512Init(&ctx);
+
+ SHA512Update(&ctx, &prefix, sizeof(prefix));
+ SHA512Update(&ctx, addr, sdl->sdl_alen);
+ SHA512Update(&ctx, &dad_counter, sizeof(dad_counter));
+ SHA512Update(&ctx, ip6_soiikey, sizeof(ip6_soiikey));
+ SHA512Final(digest, &ctx);
+
+ bcopy(digest, &in6->s6_addr[8], 8);
+
+ return 0;
+}
+
+/*
* Get interface identifier for the specified interface. If it is not
* available on ifp0, borrow interface identifier from other information
* sources.
@@ -240,7 +300,14 @@ get_ifid(struct ifnet *ifp0, struct in6_addr *in6)
{
struct ifnet *ifp;
- /* first, try to get it from the interface itself */
+ /* first, try to generate a Semantically Opaque Interface Identifier */
+ if (get_soii_ifid(ifp0, in6) == 0) {
+ nd6log((LOG_DEBUG, "%s: got Semantically Opaque Interface "
+ "Identifier\n", ifp0->if_xname));
+ goto success;
+ }
+
+ /* next, try to get it from the interface itself */
if (get_hw_ifid(ifp0, in6) == 0) {
nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
ifp0->if_xname));
diff --git sys/netinet6/in6_ifattach.h sys/netinet6/in6_ifattach.h
index 6160fb984a6..00aad7dbc10 100644
--- sys/netinet6/in6_ifattach.h
+++ sys/netinet6/in6_ifattach.h
@@ -38,6 +38,7 @@ int in6_ifattach(struct ifnet *);
void in6_ifdetach(struct ifnet *);
int in6_nigroup(struct ifnet *, const char *, int, struct sockaddr_in6 *);
int in6_ifattach_linklocal(struct ifnet *, struct in6_addr *);
+void in6_soiiupdate(struct ifnet *);
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_IFATTACH_H_ */
diff --git sys/netinet6/ip6_input.c sys/netinet6/ip6_input.c
index 4aaf8cee6d6..758151c5571 100644
--- sys/netinet6/ip6_input.c
+++ sys/netinet6/ip6_input.c
@@ -92,6 +92,7 @@
#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
#include <netinet6/in6_var.h>
+#include <netinet6/in6_ifattach.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet/icmp6.h>
@@ -1380,15 +1381,27 @@ ip6_sysctl_ip6stat(void *oldp, size_t *oldlenp, void
*newp)
int
ip6_sysctl_soiikey(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
{
+ struct ifnet *ifp;
+ uint8_t oldkey[16];
int error;
error = suser(curproc, 0);
if (error != 0)
return (error);
+ memcpy(oldkey, ip6_soiikey, sizeof(oldkey));
+
error = sysctl_struct(oldp, oldlenp, newp, newlen, ip6_soiikey,
sizeof(ip6_soiikey));
+ if (!error && memcmp(ip6_soiikey, oldkey, sizeof(oldkey)) != 0) {
+ TAILQ_FOREACH(ifp, &ifnet, if_list) {
+ if (ifp->if_flags & IFF_LOOPBACK)
+ continue;
+ in6_soiiupdate(ifp);
+ }
+ }
+
return (error);
}
--
2.13.0
--
I'm not entirely sure you are real.