dhcpd domain-search patch

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

dhcpd domain-search patch

William Ahern-2
systemd's dhcp client doesn't accept the hack of putting multiple,
space-separated search domains in the domain-name option. The following
patch parses option domain-search as a list of host names and uses
dn_comp(3) from libc to compress the list for the on-wire option value.

Example dhcpd.conf usage:

  option domain-search openbsd.org, example.com, a.example.com;

Index: confpars.c
===================================================================
RCS file: /cvs/src/usr.sbin/dhcpd/confpars.c,v
retrieving revision 1.33
diff -u -p -r1.33 confpars.c
--- confpars.c 24 Apr 2017 14:58:36 -0000 1.33
+++ confpars.c 27 Feb 2019 07:23:41 -0000
@@ -43,7 +43,9 @@
 
 #include <net/if.h>
 
+#include <limits.h>
 #include <netdb.h>
+#include <resolv.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -1207,6 +1209,12 @@ parse_option_param(FILE *cfile, struct g
  tree = tree_concat(tree, tree_const(
     buf, (cprefix + 7) / 8));
  break;
+ case 'Z':
+ t = parse_domain_and_comp(cfile, uniform);
+ if (!t)
+ return;
+ tree = tree_concat(tree, t);
+ break;
  default:
  log_warnx("Bad format %c in "
     "parse_option_param.", *fmt);
@@ -1467,4 +1475,82 @@ parse_address_range(FILE *cfile, struct
 
  /* Create the new address range. */
  new_address_range(low, high, subnet, dynamic);
+}
+
+static void push_domain_list(char ***domains, size_t *count, char *domain)
+{
+ *domains = reallocarray(*domains, *count + 1, sizeof **domains);
+ if (!*domains)
+ fatalx("Can't allocate domain list");
+
+ (*domains)[*count] = domain;
+ ++*count;
+}
+
+static void
+free_domain_list(char **domains, size_t count)
+{
+ for (size_t i = 0; i < count; i++)
+ free(domains[i]);
+ free(domains);
+}
+
+struct tree *
+parse_domain_and_comp(FILE *cfile, int uniform)
+{
+ char **domains = NULL;
+ size_t count = 0;
+ unsigned char *buf = NULL;
+ size_t bufsiz = 0, bufn = 0;
+ unsigned char **bufptrs = NULL;
+ struct tree *rv = NULL;
+ int token;
+
+ do {
+ char *domain;
+
+ domain = parse_host_name(cfile);
+ if (!domain)
+ goto error;
+ push_domain_list(&domains, &count, domain);
+ /*
+ * openbsd.org normally compresses to [7]openbsd[3]org[0].
+ * +2 to string length provides space for leading and
+ * trailing (root) prefix lengths not already accounted for
+ * by dots, and also provides sufficient space for pointer
+ * compression.
+ */
+ bufsiz = bufsiz + 2 + strlen(domain);
+ token = peek_token(NULL, cfile);
+ if (token == ',')
+ token = next_token(NULL, cfile);
+ } while (uniform && token == ',');
+
+ buf = malloc(bufsiz);
+ if (!buf)
+ fatalx("Can't allocate compressed domain buffer");
+ bufptrs = calloc(count + 1, sizeof *bufptrs);
+ if (!bufptrs)
+ fatalx("Can't allocate compressed pointer list");
+ bufptrs[0] = buf;
+
+ /* dn_comp takes an int for the output buffer size */
+ if (!(bufsiz <= INT_MAX))
+ fatalx("Size of compressed domain buffer too large");
+ for (size_t i = 0; i < count; i++) {
+ int n;
+
+ /* see bufsiz <= INT_MAX assertion, above */
+ n = dn_comp(domains[i], &buf[bufn], bufsiz - bufn, bufptrs, &bufptrs[count + 1]);
+ if (n == -1)
+ fatalx("Can't compress domain");
+ bufn += (size_t)n;
+ }
+
+ rv = tree_const(buf, bufn);
+error:
+ free_domain_list(domains, count);
+ free(buf);
+ free(bufptrs);
+ return rv;
 }
Index: dhcp.h
===================================================================
RCS file: /cvs/src/usr.sbin/dhcpd/dhcp.h,v
retrieving revision 1.10
diff -u -p -r1.10 dhcp.h
--- dhcp.h 21 Jan 2014 03:07:51 -0000 1.10
+++ dhcp.h 27 Feb 2019 07:23:41 -0000
@@ -171,6 +171,7 @@ struct dhcp_packet {
 #define DHO_NDS_SERVERS 85
 #define DHO_NDS_TREE_NAME 86
 #define DHO_NDS_CONTEXT 87
+#define DHO_DOMAIN_SEARCH 119
 #define DHO_CLASSLESS_STATIC_ROUTES 121
 #define DHO_TFTP_CONFIG_FILE 144
 #define DHO_VOIP_CONFIGURATION_SERVER 150
Index: dhcpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/dhcpd/dhcpd.h,v
retrieving revision 1.66
diff -u -p -r1.66 dhcpd.h
--- dhcpd.h 4 Aug 2017 02:01:46 -0000 1.66
+++ dhcpd.h 27 Feb 2019 07:23:41 -0000
@@ -371,6 +371,7 @@ time_t parse_date(FILE *);
 unsigned char *parse_numeric_aggregate(FILE *, unsigned char *,
     int *, int, int, int);
 void convert_num(unsigned char *, char *, int, int);
+struct tree *parse_domain_and_comp(FILE *, int);
 
 /* tree.c */
 pair cons(caddr_t, pair);
Index: tables.c
===================================================================
RCS file: /cvs/src/usr.sbin/dhcpd/tables.c,v
retrieving revision 1.13
diff -u -p -r1.13 tables.c
--- tables.c 13 Feb 2017 19:13:14 -0000 1.13
+++ tables.c 27 Feb 2019 07:23:41 -0000
@@ -193,7 +193,7 @@ struct option dhcp_options[256] = {
  { "option-116", "X", &dhcp_universe, 116 },
  { "option-117", "X", &dhcp_universe, 117 },
  { "option-118", "X", &dhcp_universe, 118 },
- { "option-119", "X", &dhcp_universe, 119 },
+ { "domain-search", "ZA", &dhcp_universe, 119 },
  { "option-120", "X", &dhcp_universe, 120 },
  { "classless-static-routes", "CIA", &dhcp_universe, 121 },
  { "option-122", "X", &dhcp_universe, 122 },
@@ -367,6 +367,7 @@ unsigned char dhcp_option_default_priori
  DHO_BOOT_SIZE,
  DHO_MERIT_DUMP,
  DHO_DOMAIN_NAME,
+ DHO_DOMAIN_SEARCH,
  DHO_SWAP_SERVER,
  DHO_ROOT_PATH,
  DHO_EXTENSIONS_PATH,
@@ -412,7 +413,7 @@ unsigned char dhcp_option_default_priori
  80,  81,       83,  84,  85,  86,  87,  88,  89,
  90,  91,  92,  93,  94,  95,  96,  97,  98,  99,
  100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
- 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118,
  120,      122, 123, 124, 125, 126, 127, 128, 129,
  130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
  140, 141, 142, 143, 144, 145, 146, 147, 148, 149,