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.