On Wed, Jul 12, 2017 at 01:45:36PM +1000, David Gwynne wrote: > On Tue, Jul 11, 2017 at 11:48:47AM +0000, Florian Obser wrote: > > On Tue, Jul 11, 2017 at 11:08:23AM +0100, Stuart Henderson wrote: > > > On 2017/07/11 07:45, Florian Obser wrote: > > > > The way I want to move forward with this is: > > > > > > > > 1) generate a random key at boot if it's not present yet (like we do > > > > for ssh host keys and ipsec) > > > > 2) if /etc/netstart brings up an interface set the key there by > > > > enabling the feature per default like we do with privacy addresses. > > > > NOTE that this does NOT enable v6. > > > > If you do not want this you have to put -soiikey into the hostname.if > > > > file (like -autoconfprivacy) > > > > > > It's slightly different to autoconfprivacy as that is enabled by > > > default in the kernel for new interfaces, whereas with this it depends > > > on the key being configured. So there are implications for dynamically > > > created interfaces (USB, vlan etc) which may not always be handled by > > > netstart. > > > > > > I'm wondering if we should have a "system soiikey" (e.g. in a sysctl) > > > that is automatically applied to newly created interfaces? (Does the > > > key even need to be configurable per-interface or would a per-system > > > one be enough by itself?) > > > > I was also considering this. A per system key is probably enough. I > > went with the per-interface key because that made it easier to disable > > the feature on an interface. If we go with per-system we need a > > interface flag to disable the feature (like -autoconfprivacy). > > > > The rfc seems to assume a per system secret. > > > > hmm... are there sysctls that are only readable as root? > > yeah. see below for example code for a net.inet6.ip6.soiikey sysctl. > it looks big cos it teaches sysctl how to handle binary strings > represented by hex.
Awesome, thank you very much, I will adapt my diff to this. I don't think that we need to check securelevel (re: your comment in the diff). I don't really believe in securelevel, also it seems that even at 2 you are still allowed to change ip addresses on interfaces. And this is all this key influences. Additionally I think it is valid to change the key during runtime. > > are we tied to sha512 for this? siphash makes a nice 8 byte output... Nope, the rfc intentionally does not specify the hash function. > > > > > > > > > > 3) if v6 is enabled in hostname.if you get a random but stable link > > > > local address according to RFC 7217. > > > > 4) if autoconf6 is enabled on the interface slaacd will generate a > > > > random but stable global address according to RFC 7217 > > > > > > > > Also note that RFC 8064 is a thing and we are kinda supposed to do this. > > > > Also I think it's a good idea[tm]. > > > > > > > > Comments, OKs? > > > > > > A couple of other comments: > > > > > > - system administrators should know in advance of updating that their > > > IP address may change in case they need to prepare for it (adjust > > > firewalls/nat-pt/proxies). > > > > sure, /me glances at current.html > > > > > > > > - ramdisk upgrades may need to load the key from the installed system > > > (e.g. in presence of restrictive firewall policies). > > > > > > > good point > > > > > - a half-related idea came up while pondering this, > > > "block in inet6 to autoconfprivacy" (similar UI to urpf-failed) > > > (I'm meant to be doing something else and likely to forget so I'd > > > like to at least plant the idea :) > > > > heh, interesting > > > > -- > > I'm not entirely sure you are real. > > > Index: sbin/sysctl/sysctl.c > =================================================================== > RCS file: /cvs/src/sbin/sysctl/sysctl.c,v > retrieving revision 1.226 > diff -u -p -r1.226 sysctl.c > --- sbin/sysctl/sysctl.c 25 Apr 2017 17:33:16 -0000 1.226 > +++ sbin/sysctl/sysctl.c 12 Jul 2017 03:39:33 -0000 > @@ -212,7 +212,7 @@ int sysctl_chipset(char *, char **, int > #endif > void vfsinit(void); > > -char *equ = "="; > +const char *equ = "="; > > int > main(int argc, char *argv[]) > @@ -286,6 +286,52 @@ listall(char *prefix, struct list *lp) > } > } > > +int > +parse_hex_char(char ch) > +{ > + if (ch >= '0' && ch <= '9') > + return (ch - '0'); > + if (ch >= 'a' && ch <= 'f') > + return (ch - 'a'); > + if (ch >= 'A' && ch <= 'F') > + return (ch - 'A'); > + > + return (-1); > +} > + > +ssize_t > +parse_hex_string(unsigned char *dst, size_t dstlen, const char *src) > +{ > + ssize_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); > +} > + > /* > * Parse a name into a MIB entry. > * Lookup and print out the MIB entry if it exists. > @@ -566,6 +612,9 @@ parse(char *string, int flags) > len = sysctl_inet6(string, &bufp, mib, flags, &type); > 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) || > @@ -717,6 +766,29 @@ parse(char *string, int flags) > newval = &quadval; > newsize = sizeof(quadval); > break; > + case CTLTYPE_STRING: > + if (special & HEX) { > + ssize_t len; > + > + len = parse_hex_string(buf, sizeof(buf), > + newval); > + if (len == -1) { > + warnx("%s: hex string %s: invalid", > + string, newval); > + return; > + } > + if (len > sizeof(buf)) { > + warnx("%s: hex string %s: too long", > + string, newval); > + return; > + } > + > + newval = buf; > + newsize = len; > + > + printf("newsize = %zu\n", newsize); > + } > + break; > } > } > size = (special & SMALLBUF) ? 512 : SYSCTL_BUFSIZ; > @@ -936,13 +1008,26 @@ parse(char *string, int flags) > if (newval == NULL) { > if (!nflag) > (void)printf("%s%s", string, equ); > - (void)puts(buf); > - } else { > - if (!qflag) { > - if (!nflag) > - (void)printf("%s: %s -> ", string, buf); > - (void)puts((char *)newval); > + if (special & HEX) { > + size_t i; > + for (i = 0; i < size; i++) > + (void)printf("%02x", buf[i]); > + (void)printf("\n"); > + } else > + (void)puts(buf); > + } else if (!qflag) { > + if (!nflag) { > + (void)printf("%s: ", string); > + if (special & HEX) { > + size_t i; > + for (i = 0; i < size; i++) > + (void)printf("%02x", buf[i]); > + } else > + (void)printf("%s", cp); > + > + (void)printf(" -> "); > } > + (void)puts(cp); > } > return; > > Index: sys/netinet6/in6.h > =================================================================== > RCS file: /cvs/src/sys/netinet6/in6.h,v > retrieving revision 1.96 > diff -u -p -r1.96 in6.h > --- sys/netinet6/in6.h 30 May 2017 09:10:49 -0000 1.96 > +++ sys/netinet6/in6.h 12 Jul 2017 03:39:33 -0000 > @@ -592,7 +592,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 > */ > @@ -652,6 +653,7 @@ ifatoia6(struct ifaddr *ifa) > { "ifq", CTLTYPE_NODE }, \ > { "mrtmif", CTLTYPE_STRUCT }, \ > { "mrtmfc", CTLTYPE_STRUCT }, \ > + { "soiikey", CTLTYPE_STRING }, /* binary string */ \ > } > > #define IPV6CTL_VARS { \ > Index: sys/netinet6/ip6_input.c > =================================================================== > RCS file: /cvs/src/sys/netinet6/ip6_input.c,v > retrieving revision 1.198 > diff -u -p -r1.198 ip6_input.c > --- sys/netinet6/ip6_input.c 5 Jul 2017 11:34:10 -0000 1.198 > +++ sys/netinet6/ip6_input.c 12 Jul 2017 03:39:34 -0000 > @@ -1375,6 +1375,56 @@ ip6_sysctl_ip6stat(void *oldp, size_t *o > return (ret); > } > > +struct ip6_soiikey { > + unsigned int len; > + unsigned char key[32]; > +}; > + > +struct ip6_soiikey ip6_soiikey = { .len = 0 }; > + > +int > +ip6_sysctl_soiikey(void *oldp, size_t *oldlenp, void *newp, size_t newlen) > +{ > + unsigned char key[32]; > + int error; > + > + error = suser(curproc, 0); > + if (error != 0) > + return (error); > + > + if (oldp != NULL) { > + if (newp == NULL && ip6_soiikey.len == 0) > + return (EOPNOTSUPP); > + if (*oldlenp < ip6_soiikey.len) > + return (ENOMEM); > + } > + if (newp != NULL) { > + /* check securelevel? */ > + if (newlen > sizeof(ip6_soiikey.key)) > + return (EINVAL); > + if (newlen > 0) { > + error = copyin(newp, key, newlen); > + if (error != 0) > + return (error); > + } > + } > + if (oldp != NULL) { > + error = copyout(ip6_soiikey.key, oldp, *oldlenp); > + if (error != 0) > + return (error); > + *oldlenp = ip6_soiikey.len; > + } > + > + if (newp != NULL) { > + /* commit */ > + if (newlen > 0) > + memcpy(ip6_soiikey.key, key, newlen); > + ip6_soiikey.len = newlen; > + } > + > + return (0); > +} > + > int > ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, > void *newp, size_t newlen) > @@ -1429,6 +1479,8 @@ ip6_sysctl(int *name, u_int namelen, voi > 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) > return (sysctl_int_arr(ipv6ctl_vars, name, namelen, > -- I'm not entirely sure you are real.