summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2015-10-26 16:32:34 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2015-10-26 16:32:34 +0000
commit17a200456dbcb6b279efef3e2be92bc24ebd0a77 (patch)
tree8e2e054e9f781480c6a3304ca3b4eb066b258f1d /sbin
parent86f40f24a92f411db61b7b115133b3c0809661c7 (diff)
Give dhclient(8) the ability to use option 119, a.k.a. "Domain
Search" if supplied by the server. Requested by a few. Original diff from Ray Lai via tech@. Tested & ok claudio@
Diffstat (limited to 'sbin')
-rw-r--r--sbin/dhclient/clparse.c4
-rw-r--r--sbin/dhclient/dhclient.c57
-rw-r--r--sbin/dhclient/dhcp.h7
-rw-r--r--sbin/dhclient/dhcpd.h4
-rw-r--r--sbin/dhclient/options.c126
-rw-r--r--sbin/dhclient/tables.c4
6 files changed, 183 insertions, 19 deletions
diff --git a/sbin/dhclient/clparse.c b/sbin/dhclient/clparse.c
index ae33a75970f..99a895d926b 100644
--- a/sbin/dhclient/clparse.c
+++ b/sbin/dhclient/clparse.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clparse.c,v 1.92 2015/05/18 17:51:21 krw Exp $ */
+/* $OpenBSD: clparse.c,v 1.93 2015/10/26 16:32:33 krw Exp $ */
/* Parser for dhclient config and lease files. */
@@ -89,6 +89,8 @@ read_client_conf(void)
config->requested_options
[config->requested_option_count++] = DHO_DOMAIN_NAME;
config->requested_options
+ [config->requested_option_count++] = DHO_DOMAIN_SEARCH;
+ config->requested_options
[config->requested_option_count++] = DHO_DOMAIN_NAME_SERVERS;
config->requested_options
[config->requested_option_count++] = DHO_HOST_NAME;
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index b324e9d81db..8c97f1c859e 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhclient.c,v 1.364 2015/09/08 17:19:20 krw Exp $ */
+/* $OpenBSD: dhclient.c,v 1.365 2015/10/26 16:32:33 krw Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -99,7 +99,7 @@ int res_hnok_list(const char *dn);
void fork_privchld(int, int);
void get_ifname(char *);
char *resolv_conf_contents(struct option_data *,
- struct option_data *);
+ struct option_data *, struct option_data *);
void write_resolv_conf(u_int8_t *, size_t);
void write_option_db(u_int8_t *, size_t);
@@ -905,7 +905,8 @@ bind_lease(void)
}
client->new->resolv_conf = resolv_conf_contents(
- &options[DHO_DOMAIN_NAME], &options[DHO_DOMAIN_NAME_SERVERS]);
+ &options[DHO_DOMAIN_NAME], &options[DHO_DOMAIN_NAME_SERVERS],
+ &options[DHO_DOMAIN_SEARCH]);
/* Replace the old active lease with the new one. */
client->active = client->new;
@@ -1097,8 +1098,8 @@ struct client_lease *
packet_to_lease(struct in_addr client_addr, struct option_data *options)
{
struct client_lease *lease;
- char *pretty;
- int i;
+ char *pretty, *buf;
+ int i, sz;
lease = calloc(1, sizeof(struct client_lease));
if (!lease) {
@@ -1120,6 +1121,21 @@ packet_to_lease(struct in_addr client_addr, struct option_data *options)
if (strlen(pretty) == 0)
continue;
switch (i) {
+ case DHO_DOMAIN_SEARCH:
+ /* Must decode the option into text to check names. */
+ buf = calloc(1, DHCP_DOMAIN_SEARCH_LEN);
+ if (buf == NULL)
+ error("No memory to decode domain search");
+ sz = pretty_print_domain_search(buf,
+ DHCP_DOMAIN_SEARCH_LEN,
+ options[i].data, options[i].len);
+ if (strlen(buf) == 0)
+ continue;
+ if (sz == -1 || !res_hnok_list(buf))
+ warning("Bogus data for option %s",
+ dhcp_options[i].name);
+ free(buf);
+ break;
case DHO_DOMAIN_NAME:
/*
* Allow deviant but historically blessed
@@ -1917,8 +1933,9 @@ res_hnok(const char *name)
}
/*
- * resolv_conf(5) says a max of 6 domains and total length of 1024 bytes are
- * acceptable for the 'search' statement.
+ * resolv_conf(5) says a max of DHCP_DOMAIN_SEARCH_CNT domains and total
+ * length of DHCP_DOMAIN_SEARCH_LEN bytes are acceptable for the 'search'
+ * statement.
*/
int
res_hnok_list(const char *names)
@@ -1926,7 +1943,7 @@ res_hnok_list(const char *names)
char *dupnames, *hn, *inputstring;
int count;
- if (strlen(names) >= 1024)
+ if (strlen(names) >= DHCP_DOMAIN_SEARCH_LEN)
return (0);
dupnames = inputstring = strdup(names);
@@ -1940,7 +1957,7 @@ res_hnok_list(const char *names)
if (res_hnok(hn) == 0)
break;
count++;
- if (count > 6)
+ if (count > DHCP_DOMAIN_SEARCH_CNT)
break;
}
@@ -2095,15 +2112,29 @@ get_ifname(char *arg)
*/
char *
resolv_conf_contents(struct option_data *domainname,
- struct option_data *nameservers)
+ struct option_data *nameservers, struct option_data *domainsearch)
{
- char *dn, *ns, *nss[MAXNS], *contents, *courtesy, *p;
+ char *dn, *ns, *nss[MAXNS], *contents, *courtesy, *p, *buf;
size_t len;
- int i, rslt;
+ int i, rslt, sz;
memset(nss, 0, sizeof(nss));
- if (domainname->len) {
+ if (domainsearch->len) {
+ buf = calloc(1, DHCP_DOMAIN_SEARCH_LEN);
+ if (buf == NULL)
+ error("No memory to decode domain search");
+ sz = pretty_print_domain_search(buf, DHCP_DOMAIN_SEARCH_LEN,
+ domainsearch->data, domainsearch->len);
+ if (sz == -1)
+ dn = strdup("");
+ else {
+ rslt = asprintf(&dn, "search %s\n", buf);
+ if (rslt == -1)
+ dn = NULL;
+ }
+ free(buf);
+ } else if (domainname->len) {
rslt = asprintf(&dn, "search %s\n",
pretty_print_option(DHO_DOMAIN_NAME, domainname, 0));
if (rslt == -1)
diff --git a/sbin/dhclient/dhcp.h b/sbin/dhclient/dhcp.h
index 731f8a97054..c0dc07c1e99 100644
--- a/sbin/dhclient/dhcp.h
+++ b/sbin/dhclient/dhcp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhcp.h,v 1.17 2014/01/21 03:07:50 krw Exp $ */
+/* $OpenBSD: dhcp.h,v 1.18 2015/10/26 16:32:33 krw Exp $ */
/* Protocol structures. */
@@ -50,6 +50,10 @@
#define DHCP_MTU_MAX 1500
#define DHCP_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN)
+/* Respect historical limits on 'search' line in resolv.conf(5) */
+#define DHCP_DOMAIN_SEARCH_LEN 1024
+#define DHCP_DOMAIN_SEARCH_CNT 6
+
#define BOOTP_MIN_LEN 300
struct dhcp_packet {
@@ -171,6 +175,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
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index a23f3f15e42..f2868cbb164 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhcpd.h,v 1.151 2015/08/19 17:52:10 krw Exp $ */
+/* $OpenBSD: dhcpd.h,v 1.152 2015/10/26 16:32:33 krw Exp $ */
/*
* Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
@@ -217,6 +217,8 @@ char *pretty_print_option(unsigned int, struct option_data *, int);
int pretty_print_string(unsigned char *, size_t, unsigned char *, size_t, int);
int pretty_print_classless_routes(unsigned char *, size_t, unsigned char *,
size_t);
+int pretty_print_domain_search(unsigned char *, size_t, unsigned char *,
+ size_t);
void do_packet(unsigned int, struct in_addr, struct ether_addr *);
/* errwarn.c */
diff --git a/sbin/dhclient/options.c b/sbin/dhclient/options.c
index aee0c27566a..389d99feaa7 100644
--- a/sbin/dhclient/options.c
+++ b/sbin/dhclient/options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: options.c,v 1.73 2014/10/27 17:01:28 krw Exp $ */
+/* $OpenBSD: options.c,v 1.74 2015/10/26 16:32:33 krw Exp $ */
/* DHCP options parsing and reassembly. */
@@ -45,6 +45,7 @@
#include <vis.h>
int parse_option_buffer(struct option_data *, unsigned char *, int);
+int expand_search_domain_name(unsigned char *, size_t, int *, unsigned char *);
/*
* Parse options out of the specified buffer, storing addresses of
@@ -289,6 +290,129 @@ pretty_print_classless_routes(unsigned char *dst, size_t dstlen,
return (total);
}
+int
+expand_search_domain_name(unsigned char *src, size_t srclen, int *offset,
+ unsigned char *domain_search)
+{
+ int domain_name_len, i, label_len, pointer, pointed_len;
+ char *cursor;
+
+ cursor = domain_search + strlen(domain_search);
+ domain_name_len = 0;
+
+ i = *offset;
+ while (i <= srclen) {
+ label_len = src[i];
+ if (label_len == 0) {
+ /*
+ * A zero-length label marks the end of this
+ * domain name.
+ */
+ *offset = i + 1;
+ return (domain_name_len);
+ } else if (label_len & 0xC0) {
+ /* This is a pointer to another list of labels. */
+ if (i + 1 >= srclen) {
+ /* The pointer is truncated. */
+ warning("Truncated pointer in DHCP Domain "
+ "Search option.");
+ return (-1);
+ }
+
+ pointer = ((label_len & ~(0xC0)) << 8) + src[i + 1];
+ if (pointer >= *offset) {
+ /*
+ * The pointer must indicates a prior
+ * occurance.
+ */
+ warning("Invalid forward pointer in DHCP "
+ "Domain Search option compression.");
+ return (-1);
+ }
+
+ pointed_len = expand_search_domain_name(src, srclen,
+ &pointer, domain_search);
+ domain_name_len += pointed_len;
+
+ *offset = i + 2;
+ return (domain_name_len);
+ }
+ if (i + label_len + 1 > srclen) {
+ warning("Truncated label in DHCP Domain Search "
+ "option.");
+ return (-1);
+ }
+ /*
+ * Update the domain name length with the length of the
+ * current label, plus a trailing dot ('.').
+ */
+ domain_name_len += label_len + 1;
+
+ if (strlen(domain_search) + domain_name_len >=
+ DHCP_DOMAIN_SEARCH_LEN) {
+ warning("Domain search list too long.");
+ return (-1);
+ }
+
+ /* Copy the label found. */
+ memcpy(cursor, src + i + 1, label_len);
+ cursor[label_len] = '.';
+
+ /* Move cursor. */
+ i += label_len + 1;
+ cursor += label_len + 1;
+ }
+
+ warning("Truncated DHCP Domain Search option.");
+
+ return (-1);
+}
+
+/*
+ * Must special case DHO_DOMAIN_SEARCH because it is encoded as described
+ * in RFC 1035 section 4.1.4.
+ */
+int
+pretty_print_domain_search(unsigned char *dst, size_t dstlen,
+ unsigned char *src, size_t srclen)
+{
+ int offset, len, expanded_len, domains;
+ unsigned char *domain_search, *cursor;
+
+ domain_search = calloc(1, DHCP_DOMAIN_SEARCH_LEN);
+ if (domain_search == NULL)
+ error("Can't allocate storage for expanded domain-search\n");
+
+ /* Compute expanded length. */
+ expanded_len = len = 0;
+ domains = 0;
+ offset = 0;
+ while (offset < srclen) {
+ cursor = domain_search + strlen(domain_search);
+ if (domain_search[0]) {
+ *cursor = ' ';
+ expanded_len++;
+ }
+ len = expand_search_domain_name(src, srclen, &offset,
+ domain_search);
+ if (len == -1) {
+ free(domain_search);
+ return (-1);
+ }
+ domains++;
+ expanded_len += len;
+ if (domains > DHCP_DOMAIN_SEARCH_CNT) {
+ free(domain_search);
+ return (-1);
+ }
+ }
+
+ strlcat(dst, domain_search, dstlen);
+ free(domain_search);
+
+ return (0);
+}
+
/*
* Format the specified option so that a human can easily read it.
*/
diff --git a/sbin/dhclient/tables.c b/sbin/dhclient/tables.c
index 84abdb8fda5..ff6c4dfd847 100644
--- a/sbin/dhclient/tables.c
+++ b/sbin/dhclient/tables.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tables.c,v 1.18 2014/01/21 03:07:50 krw Exp $ */
+/* $OpenBSD: tables.c,v 1.19 2015/10/26 16:32:33 krw Exp $ */
/* Tables of information. */
@@ -179,7 +179,7 @@ const struct option dhcp_options[256] = {
/* 116 */ { "option-116", "X" },
/* 117 */ { "option-117", "X" },
/* 118 */ { "option-118", "X" },
- /* 119 */ { "option-119", "X" },
+ /* 119 */ { "domain-search", "X" },
/* 120 */ { "option-120", "X" },
/* 121 */ { "classless-static-routes", "CIA" },
/* 122 */ { "option-122", "X" },