From 9798906b8a0a6367c5fe89a7af777dc8935fa69f Mon Sep 17 00:00:00 2001 From: florian Date: Sat, 10 Feb 2018 05:52:08 +0000 Subject: [PATCH] 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 --- sys/net/if.c | 15 +++++++- sys/net/if.h | 3 +- sys/netinet6/in6.h | 6 ++-- sys/netinet6/in6_ifattach.c | 69 +++++++++++++++++++++++++++++++++++-- sys/netinet6/in6_ifattach.h | 3 +- sys/netinet6/ip6_input.c | 37 +++++++++++++++++++- sys/netinet6/ip6_var.h | 5 ++- 7 files changed, 129 insertions(+), 9 deletions(-) diff --git a/sys/net/if.c b/sys/net/if.c index e450decf5ed..94df391bd8a 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -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 diff --git a/sys/net/if.h b/sys/net/if.h index fbee692ba32..39ccfa3c18a 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -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) diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 6ea62f9fbd2..337f48738cf 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -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 { \ 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. * @@ -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)); diff --git a/sys/netinet6/in6_ifattach.h b/sys/netinet6/in6_ifattach.h index 6160fb984a6..0f54b457de9 100644 --- a/sys/netinet6/in6_ifattach.h +++ b/sys/netinet6/in6_ifattach.h @@ -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_ */ diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index b7dc6287e5a..60006380e9f 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -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 #include #include +#include #include #include #include @@ -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(); diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 2e62ac01540..c6fcbef957a 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -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; -- 2.20.1