In case this turns out to be useful for unlocking work in the kernel.

It's a minimum diff, if we want to go this way we probably want to move
init_soiikey() to the engine process and stop bouncing through the main
process when an interface changes.

This changes behaviour: in -current we can change the sysctl and down/up
an interface to read the new value, with this diff that no longer
works. slaacd will (and can) only read the file on startup.

This has consequences for the installer: slaacd starts before
/mnt/etc/soii.key is available in the upgrade case. Which in turn means
that we get a different IPv6 address in the installer than in the
running system. I don't know how big of an issue that is.

diff --git distrib/miniroot/install.sub distrib/miniroot/install.sub
index d3d944bf2ca..aa84e4808f2 100644
--- distrib/miniroot/install.sub
+++ distrib/miniroot/install.sub
@@ -2620,9 +2620,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 9156d5f455c..7aedb6dd55b 100644
--- distrib/special/sysctl/sysctl.c
+++ distrib/special/sysctl/sysctl.c
@@ -99,39 +99,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[])
 {
@@ -159,17 +126,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)"
-fi
-
 # If we were invoked with a list of interface names, just reconfigure these
 # interfaces (or bridges), add default routes and return.
 # Create virtual interfaces upfront to make ifconfig commands depending on
diff --git etc/rc etc/rc
index ea30a76aec4..78d82c81cd5 100644
--- etc/rc
+++ etc/rc
@@ -164,11 +164,6 @@ make_keys() {
 
        ssh-keygen -A
 
-       if [[ ! -f /etc/soii.key ]]; then
-               openssl rand -hex 16 > /etc/soii.key &&
-                   chmod 600 /etc/soii.key && sysctl -q \
-                   "net.inet6.ip6.soiikey=$(</etc/soii.key)"
-       fi
 }
 
 # Re-link libraries, placing the objects in a random order.
diff --git sbin/slaacd/slaacd.c sbin/slaacd/slaacd.c
index 4d1786361f7..3187af8740b 100644
--- sbin/slaacd/slaacd.c
+++ sbin/slaacd/slaacd.c
@@ -22,8 +22,8 @@
 #include <sys/ioctl.h>
 #include <sys/queue.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/syslog.h>
-#include <sys/sysctl.h>
 #include <sys/uio.h>
 #include <sys/wait.h>
 
@@ -34,6 +34,7 @@
 #include <netinet6/in6_var.h>
 #include <netinet/icmp6.h>
 
+#include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -76,7 +77,8 @@ 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 *);
+int    parse_hex_char(char);
+void   init_soiikey(void);
 
 static int     main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
 int            main_imsg_compose_frontend(int, int, void *, uint16_t);
@@ -89,6 +91,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)
@@ -189,6 +192,10 @@ main(int argc, char *argv[])
        if (getpwnam(SLAACD_USER) == NULL)
                errx(1, "unknown user %s", SLAACD_USER);
 
+#ifndef SMALL
+       init_soiikey();
+#endif /* SMALL */
+
        log_init(debug, LOG_DAEMON);
        log_setverbose(verbose);
 
@@ -431,11 +438,9 @@ main_dispatch_frontend(int fd, short event, void *bula)
                                fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
                                    __func__, IMSG_DATA_SIZE(imsg));
                        memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
-                       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, sizeof(soiikey));
+                       main_imsg_compose_engine(IMSG_UPDATE_IF, 0,
+                           &imsg_ifinfo, sizeof(imsg_ifinfo));
                        break;
                default:
                        log_debug("%s: error handling imsg %d", __func__,
@@ -856,16 +861,56 @@ 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');
+
+       ch = tolower((unsigned char)ch);
+       if (ch >= 'a' && ch <= 'f')
+               return (ch - 'a' + 10);
+
+       return (-1);
+}
 
-       return sysctl(mib, sizeof(mib) / sizeof(mib[0]), key, &size, NULL, 0);
+void
+init_soiikey(void)
+{
+       int      fd, i;
+       char     buf[SLAACD_SOIIKEY_LEN * 2 + 1];
+
+       memset(buf, 0, sizeof(buf));
+       if ((fd = open(_PATH_SOIIKEY, O_RDONLY)) == -1) {
+               arc4random_buf(soiikey, SLAACD_SOIIKEY_LEN);
+               for (i = 0; i < SLAACD_SOIIKEY_LEN; i++)
+                       snprintf(&buf[2 * i], sizeof(buf) - 2 * i, "%02x",
+                           soiikey[i]);
+               buf[sizeof(buf) - 1] = '\n';
+               if ((fd = open(_PATH_SOIIKEY, O_WRONLY | O_CREAT,
+                   S_IRUSR | S_IWUSR)) != -1) {
+                       write(fd, buf, sizeof(buf));
+                       close(fd);
+               }
+       } else {
+               if (read(fd, buf, sizeof(buf)) == -1)
+                       arc4random_buf(soiikey, SLAACD_SOIIKEY_LEN);
+               else {
+                       for (i = 0; i < SLAACD_SOIIKEY_LEN; i++) {
+                               int c;
+                               if ((c = parse_hex_char(buf[2 * i])) == -1)
+                                       break;
+                               soiikey[i] = c << 4;
+                               if ((c = parse_hex_char(buf[2 * i + 1])) == -1)
+                                       break;
+                               soiikey[i] |= c;
+                       }
+               }
+               close(fd);
+       }
 }
+#endif /* SMALL */
 
 void
 open_icmp6sock(int rdomain)
diff --git sbin/slaacd/slaacd.h sbin/slaacd/slaacd.h
index 2844f4a63b7..9ee028247a8 100644
--- sbin/slaacd/slaacd.h
+++ sbin/slaacd/slaacd.h
@@ -20,6 +20,7 @@
 
 #define        _PATH_LOCKFILE          "/dev/slaacd.lock"
 #define        _PATH_SLAACD_SOCKET     "/dev/slaacd.sock"
+#define        _PATH_SOIIKEY           "/etc/soii.key"
 #define SLAACD_USER            "_slaacd"
 #define SLAACD_RTA_LABEL       "slaacd"
 

-- 
In my defence, I have been left unsupervised.

Reply via email to