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.
are we tied to sha512 for this? siphash makes a nice 8 byte output...
>
> >
> > > 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,