Implement RFC 7217: "A Method for Generating Semantically Opaque
authorflorian <florian@openbsd.org>
Sat, 10 Feb 2018 05:52:08 +0000 (05:52 +0000)
committerflorian <florian@openbsd.org>
Sat, 10 Feb 2018 05:52:08 +0000 (05:52 +0000)
Interface Identifiers with IPv6 Stateless Address Autoconfiguration."

"An IPv6 address configured using this method is stable within each
subnet, but the corresponding Interface Identifier changes when the
host moves from one network to another. This method is meant to be an
alternative to generating Interface Identifiers based on hardware
addresses."

OK naddy, sthen

sys/net/if.c
sys/net/if.h
sys/netinet6/in6.h
sys/netinet6/in6_ifattach.c
sys/netinet6/in6_ifattach.h
sys/netinet6/ip6_input.c
sys/netinet6/ip6_var.h

index e450dec..94df391 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if.c,v 1.542 2018/02/10 05:32:21 claudio Exp $        */
+/*     $OpenBSD: if.c,v 1.543 2018/02/10 05:52:08 florian Exp $        */
 /*     $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $  */
 
 /*
@@ -1922,6 +1922,19 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                                break;
                        }
                }
+
+               if (ISSET(ifr->ifr_flags, IFXF_INET6_NOSOII) &&
+                   !ISSET(ifp->if_xflags, IFXF_INET6_NOSOII)) {
+                       ifp->if_xflags |= IFXF_INET6_NOSOII;
+                       in6_soiiupdate(ifp);
+               }
+
+               if (!ISSET(ifr->ifr_flags, IFXF_INET6_NOSOII) &&
+                   ISSET(ifp->if_xflags, IFXF_INET6_NOSOII)) {
+                       ifp->if_xflags &= ~IFXF_INET6_NOSOII;
+                       in6_soiiupdate(ifp);
+               }
+
 #endif /* INET6 */
 
 #ifdef MPLS
index fbee692..39ccfa3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if.h,v 1.190 2018/01/16 10:33:55 mpi Exp $    */
+/*     $OpenBSD: if.h,v 1.191 2018/02/10 05:52:08 florian Exp $        */
 /*     $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $  */
 
 /*
@@ -221,6 +221,7 @@ struct if_status_description {
 #define        IFXF_MPLS               0x8     /* [N] supports MPLS */
 #define        IFXF_WOL                0x10    /* [N] wake on lan enabled */
 #define        IFXF_AUTOCONF6          0x20    /* [N] v6 autoconf enabled */
+#define IFXF_INET6_NOSOII      0x40    /* [N] don't do RFC 7217 */
 
 #define        IFXF_CANTCHANGE \
        (IFXF_MPSAFE|IFXF_CLONED)
index 6ea62f9..337f487 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in6.h,v 1.100 2017/11/20 10:35:24 mpi Exp $   */
+/*     $OpenBSD: in6.h,v 1.101 2018/02/10 05:52:08 florian Exp $       */
 /*     $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $    */
 
 /*
@@ -590,7 +590,8 @@ ifatoia6(struct ifaddr *ifa)
 #define IPV6CTL_IFQUEUE                51
 #define IPV6CTL_MRTMIF         52
 #define IPV6CTL_MRTMFC         53
-#define IPV6CTL_MAXID          54
+#define IPV6CTL_SOIIKEY                54
+#define IPV6CTL_MAXID          55
 
 /* New entries should be added here from current IPV6CTL_MAXID value. */
 /* to define items, should talk with KAME guys first, for *BSD compatibility */
@@ -650,6 +651,7 @@ ifatoia6(struct ifaddr *ifa)
        { "ifq", CTLTYPE_NODE }, \
        { "mrtmif", CTLTYPE_STRUCT }, \
        { "mrtmfc", CTLTYPE_STRUCT }, \
+       { "soiikey", CTLTYPE_STRING }, /* binary string */ \
 }
 
 #define IPV6CTL_VARS { \
index 8761437..0aa10fa 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in6_ifattach.c,v 1.104 2017/09/01 16:48:27 florian Exp $      */
+/*     $OpenBSD: in6_ifattach.c,v 1.105 2018/02/10 05:52:08 florian Exp $      */
 /*     $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $  */
 
 /*
@@ -58,6 +58,7 @@
 
 void   in6_get_rand_ifid(struct ifnet *, struct in6_addr *);
 int    in6_get_hw_ifid(struct ifnet *, struct in6_addr *);
+int    in6_get_soii_ifid(struct ifnet *, struct in6_addr *);
 void   in6_get_ifid(struct ifnet *, struct in6_addr *);
 int    in6_ifattach_loopback(struct ifnet *);
 
@@ -72,6 +73,24 @@ 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;
+
+       NET_ASSERT_LOCKED();
+
+       /*
+        * 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);
+       }
+}
+
 /*
  * Generate a random interface identifier.
  *
@@ -191,6 +210,45 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
        return 0;
 }
 
+/*
+ * Generate a Semantically Opaque Interface Identifier according to RFC 7217
+ *
+ * in6 - upper 64bits are preserved
+ */
+int
+in6_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
@@ -201,7 +259,14 @@ in6_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 (in6_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 (in6_get_hw_ifid(ifp0, in6) == 0) {
                nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
                    ifp0->if_xname));
index 6160fb9..0f54b45 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in6_ifattach.h,v 1.7 2015/01/27 10:31:19 mpi Exp $    */
+/*     $OpenBSD: in6_ifattach.h,v 1.8 2018/02/10 05:52:08 florian Exp $        */
 /*     $KAME: in6_ifattach.h,v 1.9 2000/04/12 05:35:48 itojun Exp $    */
 
 /*
@@ -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_ */
index b7dc628..6000638 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_input.c,v 1.211 2018/02/01 21:11:33 bluhm Exp $   */
+/*     $OpenBSD: ip6_input.c,v 1.212 2018/02/10 05:52:08 florian Exp $ */
 /*     $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $     */
 
 /*
@@ -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>
@@ -118,12 +119,15 @@ struct niqueue ip6intrq = NIQUEUE_INITIALIZER(IPQ_MAXLEN, NETISR_IPV6);
 
 struct cpumem *ip6counters;
 
+uint8_t ip6_soiikey[IP6_SOIIKEY_LEN];
+
 int ip6_ours(struct mbuf **, int *, int, int);
 int ip6_local(struct mbuf **, int *, int, int);
 int ip6_check_rh0hdr(struct mbuf *, int *);
 int ip6_hbhchcheck(struct mbuf *, int *, int *, int *);
 int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
 struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
+int ip6_sysctl_soiikey(void *, size_t *, void *, size_t);
 
 static struct mbuf_queue       ip6send_mq;
 
@@ -1366,6 +1370,35 @@ ip6_sysctl_ip6stat(void *oldp, size_t *oldlenp, void *newp)
        return (ret);
 }
 
+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;
+                       NET_LOCK();
+                       in6_soiiupdate(ifp);
+                       NET_UNLOCK();
+               }
+       }
+
+       return (error);
+}
+
 int
 ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
     void *newp, size_t newlen)
@@ -1429,6 +1462,8 @@ ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
        case IPV6CTL_IFQUEUE:
                return (sysctl_niq(name + 1, namelen - 1,
                    oldp, oldlenp, newp, newlen, &ip6intrq));
+       case IPV6CTL_SOIIKEY:
+               return (ip6_sysctl_soiikey(oldp, oldlenp, newp, newlen));
        default:
                if (name[0] < IPV6CTL_MAXID) {
                        NET_LOCK();
index 2e62ac0..c6fcbef 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_var.h,v 1.82 2018/02/01 21:11:33 bluhm Exp $      */
+/*     $OpenBSD: ip6_var.h,v 1.83 2018/02/10 05:52:08 florian Exp $    */
 /*     $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $        */
 
 /*
@@ -292,6 +292,9 @@ extern int  ip6_dad_pending;        /* number of currently running DADs */
 extern int ip6_auto_flowlabel;
 extern int ip6_auto_linklocal;
 
+#define        IP6_SOIIKEY_LEN 16
+extern uint8_t ip6_soiikey[IP6_SOIIKEY_LEN];
+
 struct in6pcb;
 struct inpcb;