summaryrefslogtreecommitdiff
path: root/sys/netinet6/in6_ifattach.c
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2018-02-10 05:52:09 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2018-02-10 05:52:09 +0000
commite5ab4005935ce5c8fe35b8486f9547bd9a811db0 (patch)
treed04eeda59a2567e8e28c47fef25ed14d2528d5ab /sys/netinet6/in6_ifattach.c
parent248494399c176361309dd6387ca61e2d5b0c1307 (diff)
Implement RFC 7217: "A Method for Generating Semantically Opaque
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
Diffstat (limited to 'sys/netinet6/in6_ifattach.c')
-rw-r--r--sys/netinet6/in6_ifattach.c69
1 files changed, 67 insertions, 2 deletions
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 87614373686..0aa10fad94b 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -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.
*
@@ -192,6 +211,45 @@ in6_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
+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
* sources.
@@ -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));