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.