add support for binary sysctl payloads by handling them as hex
authorflorian <florian@openbsd.org>
Sat, 10 Feb 2018 05:53:58 +0000 (05:53 +0000)
committerflorian <florian@openbsd.org>
Sat, 10 Feb 2018 05:53:58 +0000 (05:53 +0000)
strings.

this was part of a demo showing how to implement the kernel side of
sysctl(3) for setting Semantically Opaque Interface Identifier key
material (for RFC 7217), but it seems to be the most straightforward
path toward integrating soiikey handling and rc.

Originally written by dlg, who commited it some time ago on my request.
I then backed it out again, now it's time to put it back in.

ok florian@ sthen@ naddy@ tb@

Man page bits tweaked & OK jmc

lib/libc/sys/sysctl.2
sbin/sysctl/sysctl.c

index 6aa84ea..f9db61c 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: sysctl.2,v 1.1 2018/01/12 04:36:12 deraadt Exp $
+.\"    $OpenBSD: sysctl.2,v 1.2 2018/02/10 05:53:58 florian Exp $
 .\"
 .\" Copyright (c) 1993
 .\"    The Regents of the University of California.  All rights reserved.
@@ -27,7 +27,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: January 12 2018 $
+.Dd $Mdocdate: February 10 2018 $
 .Dt SYSCTL 2
 .Os
 .Sh NAME
@@ -1663,6 +1663,7 @@ 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[] Ta yes
 .It ip6 Ta use_deprecated Ta integer Ta yes
 .El
 .Pp
@@ -1843,6 +1844,11 @@ 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 link local and Stateless Address Autoconfiguration (SLAAC) addresses.
+.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.
index 4c78bf1..a0a18b0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sysctl.c,v 1.228 2017/07/19 06:30:54 florian Exp $    */
+/*     $OpenBSD: sysctl.c,v 1.229 2018/02/10 05:53:58 florian Exp $    */
 /*     $NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $       */
 
 /*
@@ -182,6 +182,8 @@ int Aflag, aflag, nflag, qflag;
 /* prototypes */
 void debuginit(void);
 void listall(char *, struct list *);
+int parse_hex_char(char);
+ssize_t parse_hex_string(unsigned char *, size_t, const char *);
 void parse(char *, int);
 void parse_baddynamic(int *, size_t, char *, void **, size_t *, int, int);
 void usage(void);
@@ -286,6 +288,53 @@ listall(char *prefix, struct list *lp)
        }
 }
 
+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);
+}
+
+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.
@@ -302,6 +351,7 @@ parse(char *string, int flags)
        struct list *lp;
        int mib[CTL_MAXNAME];
        char *cp, *bufp, buf[SYSCTL_BUFSIZ];
+       unsigned char hex[SYSCTL_BUFSIZ];
 
        (void)strlcpy(buf, string, sizeof(buf));
        bufp = buf;
@@ -567,6 +617,10 @@ 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) ||
                            (mib[2] == IPPROTO_DIVERT && mib[3] == DIVERT6CTL_STATS)) {
@@ -717,6 +771,27 @@ parse(char *string, int flags)
                        newval = &quadval;
                        newsize = sizeof(quadval);
                        break;
+               case CTLTYPE_STRING:
+                       if (special & HEX) {
+                               ssize_t len;
+
+                               len = parse_hex_string(hex, sizeof(hex),
+                                   newval);
+                               if (len == -1) {
+                                       warnx("%s: hex string %s: invalid",
+                                           string, newval);
+                                       return;
+                               }
+                               if (len > sizeof(hex)) {
+                                       warnx("%s: hex string %s: too long",
+                                           string, newval);
+                                       return;
+                               }
+
+                               newval = hex;
+                               newsize = len;
+                       }
+                       break;
                }
        }
        size = (special & SMALLBUF) ? 512 : SYSCTL_BUFSIZ;
@@ -936,13 +1011,30 @@ 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",
+                                           (unsigned char)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",
+                                                   (unsigned char)buf[i]);
+                                       }
+                               } else
+                                       (void)printf("%s", cp);
+
+                               (void)printf(" -> ");
                        }
+                       (void)puts(cp);
                }
                return;