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.

Reply via email to