From: Florian Obser Subject: remove net.inet6.ip6.soiikey sysctl To: tech Date: Sun, 03 Aug 2025 20:04:40 +0200 RFC 7217 - "A Method for Generating Semantically Opaque Interface Identifiers with IPv6 Stateless Address Autoconfiguration (SLAAC)" applies to global addresses as well as to link-local address. However, shortly after implementing it we found out that there are a bunch of hosting providers that a) hand out IPv6 addresses via slaac b) know which mac-address their rental servers have c) calculate an expect link-local address from the known mac-address d) only route to the expect link-local address. Implementing 7217 makes things not work, so we quickly disabled it for link-local addresses. But that also means we no longer need the soiikey in the kernel. This diff rips it all out and makes slaacd(8) read /etc/soii.key file. I can think of two behavioural changes, both are not important. 1. previously one could set a new key using sysctl, down & up the interface and slaacd would calculate a new IPv6 address and configure it. With the diff slaacd only reads soii.key on startup. A restart of slaacd would get the old behaviour back. I consider this an implementation detail. 2. The installer no longer sees soii.key during upgrade. So slaacd will create an IPv6 address with a soii.key of all zero. It did so before and *additionally* create a 2nd IPv6 address with the soii.key read from /mnt/etc/soii.key. I don't think anyone could have dependent on this, given the complicated IPv6 source address selection, picking the "correct" address would be dumb luck. It's probably best to first commit userland and then a week later or so the kernel bits. I've successfully built a release with the full diff. OK? diff --git distrib/miniroot/install.sub distrib/miniroot/install.sub index c7eea4df0ff..b2a6844b297 100644 --- distrib/miniroot/install.sub +++ distrib/miniroot/install.sub @@ -2653,9 +2653,6 @@ enable_network() { echo "127.0.0.1\tlocalhost" >/tmp/i/hosts echo "::1\t\tlocalhost" >>/tmp/i/hosts - _f=/mnt/etc/soii.key - [[ -f $_f ]] && sysctl "net.inet6.ip6.soiikey=$(<$_f)" - enable_ifs } diff --git distrib/special/sysctl/sysctl.c distrib/special/sysctl/sysctl.c index 41d19856120..074b1d2b5f1 100644 --- distrib/special/sysctl/sysctl.c +++ distrib/special/sysctl/sysctl.c @@ -33,8 +33,6 @@ #include -#define SOIIKEY_LEN 16 - struct var { char *name; int (*print)(struct var *); @@ -103,39 +101,6 @@ pstring(struct var *v) return (1); } -int -parse_hex_char(char ch) -{ - if (ch >= '0' && ch <= '9') - return (ch - '0'); - - ch = tolower((unsigned char)ch); - if (ch >= 'a' && ch <= 'f') - return (ch - 'a' + 10); - - return (-1); -} - -int -set_soii_key(char *src) -{ - uint8_t key[SOIIKEY_LEN]; - int mib[4] = {CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_SOIIKEY}; - int i, c; - - for(i = 0; i < SOIIKEY_LEN; i++) { - if ((c = parse_hex_char(src[2 * i])) == -1) - return (-1); - key[i] = c << 4; - if ((c = parse_hex_char(src[2 * i + 1])) == -1) - return (-1); - key[i] |= c; - } - - return sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, NULL, key, - SOIIKEY_LEN); -} - int main(int argc, char *argv[]) { @@ -163,17 +128,6 @@ main(int argc, char *argv[]) while (argc--) { name = *argv++; - /* - * strlen("net.inet6.ip6.soiikey=" - * "00000000000000000000000000000000") == 54 - * strlen("net.inet6.ip6.soiikey=") == 22 - */ - if (strlen(name) == 54 && strncmp(name, - "net.inet6.ip6.soiikey=", 22) == 0) { - set_soii_key(name + 22); - continue; - } - for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) { if (strcmp(name, vars[i].name) == 0) { (vars[i].print)(&vars[i]); diff --git etc/netstart etc/netstart index af4866f909e..105d5a977cf 100644 --- etc/netstart +++ etc/netstart @@ -360,13 +360,6 @@ if ifconfig lo0 inet6 >/dev/null 2>&1; then IP6KERNEL=true fi -# Load key material for the generation of IPv6 Semantically Opaque Interface -# Identifiers (SOII) used for SLAAC addresses. -if $IP6KERNEL && ! $PRINT_ONLY; then - [[ -f /etc/soii.key ]] && - sysctl -q "net.inet6.ip6.soiikey=$( /etc/soii.key && - chmod 600 /etc/soii.key && sysctl -q \ - "net.inet6.ip6.soiikey=$( /etc/soii.key && chmod 600 /etc/soii.key fi } diff --git lib/libc/sys/sysctl.2 lib/libc/sys/sysctl.2 index 596b603b7b8..2e030bd9a32 100644 --- lib/libc/sys/sysctl.2 +++ lib/libc/sys/sysctl.2 @@ -1859,7 +1859,6 @@ The currently defined protocols and names are: .It ip6 Ta multipath Ta integer Ta yes .It ip6 Ta neighborgcthresh Ta integer Ta yes .It ip6 Ta redirect Ta integer Ta yes -.It ip6 Ta soiikey Ta uint8_t[IP6_SOIIKEY_LEN] Ta yes .It ip6 Ta use_deprecated Ta integer Ta yes .El .Pp @@ -2030,14 +2029,6 @@ Returns 1 when ICMPv6 redirects may be sent by the node. This option is ignored unless the node is routing IP packets, and should normally be enabled on all systems. .Pp -.It Li ip6.soii Pq Va net.inet6.ip6.soiikey -This variable configures the secret key for the RFC 7217 algorithm to -calculate a persistent Semantically Opaque Interface Identifier (SOII) -for IPv6 Stateless Address Autoconfiguration (SLAAC) addresses. -It must be -.Dv IP6_SOIIKEY_LEN -bytes long. -.Pp .It Li ip6.use_deprecated Pq Va net.inet6.ip6.use_deprecated This variable controls the use of deprecated addresses, specified in RFC 4862 5.5.4. diff --git sbin/slaacd/slaacd.c sbin/slaacd/slaacd.c index 9e81a3994d8..e6b65d45876 100644 --- sbin/slaacd/slaacd.c +++ sbin/slaacd/slaacd.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -76,7 +77,9 @@ void configure_gateway(struct imsg_configure_dfr *, uint8_t); void add_gateway(struct imsg_configure_dfr *); void delete_gateway(struct imsg_configure_dfr *); void send_rdns_proposal(struct imsg_propose_rdns *); -int get_soiikey(uint8_t *); +void read_soiikey(void); +int parse_hex_char(char); +ssize_t parse_hex_string(unsigned char *, size_t, const char *); static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); int main_imsg_compose_frontend(int, int, void *, uint16_t); @@ -89,6 +92,7 @@ pid_t frontend_pid; pid_t engine_pid; int routesock, ioctl_sock, rtm_seq = 0; +uint8_t soiikey[SLAACD_SOIIKEY_LEN]; void main_sig_handler(int sig, short event, void *arg) @@ -274,6 +278,8 @@ main(int argc, char *argv[]) #ifndef SMALL if ((control_fd = control_init(csock)) == -1) warnx("control socket setup failed"); + + read_soiikey(); #endif /* SMALL */ if (pledge("stdio inet sendfd wroute", NULL) == -1) @@ -439,11 +445,10 @@ main_dispatch_frontend(int fd, short event, void *bula) sizeof(imsg_ifinfo)) == -1) fatalx("%s: invalid %s", __func__, i2s(type)); - if (get_soiikey(imsg_ifinfo.soiikey) == -1) - log_warn("get_soiikey"); - else - main_imsg_compose_engine(IMSG_UPDATE_IF, 0, - &imsg_ifinfo, sizeof(imsg_ifinfo)); + memcpy(imsg_ifinfo.soiikey, soiikey, + SLAACD_SOIIKEY_LEN); + main_imsg_compose_engine(IMSG_UPDATE_IF, 0, + &imsg_ifinfo, sizeof(imsg_ifinfo)); break; default: log_debug("%s: error handling imsg %d", __func__, type); @@ -874,17 +879,76 @@ sin6_to_str(struct sockaddr_in6 *sin6) } return hbuf; } -#endif /* SMALL */ int -get_soiikey(uint8_t *key) +parse_hex_char(char ch) { - int mib[4] = {CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_SOIIKEY}; - size_t size = SLAACD_SOIIKEY_LEN; + if (ch >= '0' && ch <= '9') + return (ch - '0'); - return sysctl(mib, sizeof(mib) / sizeof(mib[0]), key, &size, NULL, 0); + ch = tolower((unsigned char)ch); + if (ch >= 'a' && ch <= 'f') + return (ch - 'a' + 10); + + return (-1); } +ssize_t +parse_hex_string(unsigned char *dst, size_t dstlen, const char *src) +{ + size_t len = 0; + int digit; + + while (len < dstlen) { + if (*src == '\0') + return (len); + + digit = parse_hex_char(*src++); + if (digit == -1) + return (-1); + dst[len] = digit << 4; + + digit = parse_hex_char(*src++); + if (digit == -1) + return (-1); + + dst[len] |= digit; + len++; + } + + while (*src != '\0') { + if (parse_hex_char(*src++) == -1 || + parse_hex_char(*src++) == -1) + return (-1); + + len++; + } + + return (len); +} + +void +read_soiikey(void) +{ + int fd = -1; + char buf[33]; + + if ((fd = open("/etc/soii.key", O_RDONLY)) == -1) + goto err; + memset(buf, 0, sizeof(buf)); + if (read(fd, buf, sizeof(buf) - 1) == -1) + goto err; + if (parse_hex_string(soiikey, sizeof(soiikey), buf) == -1) + goto err; + return; + err: + memset(soiikey, 0, sizeof(soiikey)); + if (fd != -1) + close(fd); +} + +#endif /* SMALL */ + void open_icmp6sock(int rdomain) { diff --git sbin/sysctl/sysctl.c sbin/sysctl/sysctl.c index b2dd40151e7..70d5bfe5390 100644 --- sbin/sysctl/sysctl.c +++ sbin/sysctl/sysctl.c @@ -693,10 +693,6 @@ parse(char *string, int flags) if (len < 0) return; - if (mib[2] == IPPROTO_IPV6 && - mib[3] == IPV6CTL_SOIIKEY) - special |= HEX; - if ((mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_MRTMFC) || (mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_MRTMIF)) { if (flags == 0) diff --git sys/kern/kern_pledge.c sys/kern/kern_pledge.c index a418aca22b3..375920ad357 100644 --- sys/kern/kern_pledge.c +++ sys/kern/kern_pledge.c @@ -832,13 +832,6 @@ pledge_sysctl(struct proc *p, int miblen, int *mib, void *new) return (0); } - if ((pledge & PLEDGE_WROUTE)) { - if (miblen == 4 && - mib[0] == CTL_NET && mib[1] == PF_INET6 && - mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_SOIIKEY) - return (0); - } - if (pledge & (PLEDGE_PS | PLEDGE_VMINFO)) { if (miblen == 2 && /* kern.fscale */ mib[0] == CTL_KERN && mib[1] == KERN_FSCALE) diff --git sys/netinet6/in6.h sys/netinet6/in6.h index 8a997b563ba..074fde1f792 100644 --- sys/netinet6/in6.h +++ sys/netinet6/in6.h @@ -597,8 +597,7 @@ ifatoia6(struct ifaddr *ifa) #define IPV6CTL_IFQUEUE 51 #define IPV6CTL_MRTMIF 52 #define IPV6CTL_MRTMFC 53 -#define IPV6CTL_SOIIKEY 54 -#define IPV6CTL_MAXID 55 +#define IPV6CTL_MAXID 54 /* New entries should be added here from current IPV6CTL_MAXID value. */ /* to define items, should talk with KAME guys first, for *BSD compatibility */ @@ -658,7 +657,6 @@ ifatoia6(struct ifaddr *ifa) { "ifq", CTLTYPE_NODE }, \ { "mrtmif", CTLTYPE_STRUCT }, \ { "mrtmfc", CTLTYPE_STRUCT }, \ - { "soiikey", CTLTYPE_STRING }, /* binary string */ \ } __BEGIN_DECLS diff --git sys/netinet6/ip6_input.c sys/netinet6/ip6_input.c index e6a5fbc0404..6e042a797ff 100644 --- sys/netinet6/ip6_input.c +++ sys/netinet6/ip6_input.c @@ -109,14 +109,11 @@ 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, struct netstack *); int ip6_check_rh0hdr(struct mbuf *, int *); int ip6_hbhchcheck(struct mbuf **, int *, int *, int); int ip6_hopopts_input(struct mbuf **, int *, u_int32_t *, u_int32_t *); 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; @@ -1481,32 +1478,6 @@ ip6_sysctl_ip6stat(void *oldp, size_t *oldlenp, void *newp) } #endif /* SMALL_KERNEL */ -int -ip6_sysctl_soiikey(void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ - uint8_t soiikey[sizeof(ip6_soiikey)]; - int error; - - error = suser(curproc); - if (error != 0) - return (error); - - rw_enter_read(&sysctl_lock); - memcpy(soiikey, ip6_soiikey, sizeof(ip6_soiikey)); - rw_exit_read(&sysctl_lock); - - error = sysctl_struct(oldp, oldlenp, newp, newlen, soiikey, - sizeof(soiikey)); - - if (error == 0 && newp) { - rw_enter_write(&sysctl_lock); - memcpy(ip6_soiikey, soiikey, sizeof(soiikey)); - rw_exit_write(&sysctl_lock); - } - - return (error); -} - int ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) @@ -1516,8 +1487,6 @@ ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, return (ENOTDIR); switch (name[0]) { - case IPV6CTL_SOIIKEY: - return (ip6_sysctl_soiikey(oldp, oldlenp, newp, newlen)); #ifndef SMALL_KERNEL case IPV6CTL_STATS: return (ip6_sysctl_ip6stat(oldp, oldlenp, newp)); diff --git sys/netinet6/ip6_var.h sys/netinet6/ip6_var.h index e5353caa50c..c9ad11832bb 100644 --- sys/netinet6/ip6_var.h +++ sys/netinet6/ip6_var.h @@ -298,9 +298,6 @@ extern int ip6_dad_pending; /* number of currently running DADs */ extern int ip6_auto_flowlabel; -#define IP6_SOIIKEY_LEN 16 -extern uint8_t ip6_soiikey[IP6_SOIIKEY_LEN]; - extern const struct pr_usrreqs rip6_usrreqs; struct inpcb; -- In my defence, I have been left unsupervised.