summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hankins <dhankins@isc.org>2006-07-22 02:24:16 +0000
committerDavid Hankins <dhankins@isc.org>2006-07-22 02:24:16 +0000
commitdba5803b955ada381d137b946f96cbb3604421ce (patch)
treefbeedd8ec7cddfa9484d74b7cb6291d66564d59e
parent8f4c32a1012bce633c6292d6d935b50cb093496f (diff)
downloadisc-dhcp-DHCPv6_parsing_base.tar.gz
- Support for compressed 'domain name list' style DHCP option contents, andDHCPv6_parsing_base
in particular the domain search option (#119) was added. [ISC-Bugs #15934]
-rw-r--r--RELNOTES6
-rwxr-xr-xclient/scripts/bsdos16
-rwxr-xr-xclient/scripts/freebsd40
-rwxr-xr-xclient/scripts/linux18
-rwxr-xr-xclient/scripts/netbsd14
-rw-r--r--client/scripts/nextstep16
-rw-r--r--client/scripts/openbsd16
-rwxr-xr-xclient/scripts/solaris16
-rw-r--r--common/conflex.c10
-rw-r--r--common/dhcp-options.518
-rw-r--r--common/options.c241
-rw-r--r--common/parse.c69
-rw-r--r--common/tables.c4
-rw-r--r--includes/dhcp.h1
-rw-r--r--includes/dhcpd.h2
-rw-r--r--includes/dhctoken.h3
-rw-r--r--includes/minires/minires.h9
17 files changed, 431 insertions, 68 deletions
diff --git a/RELNOTES b/RELNOTES
index f44dc64e..dd1a95db 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -143,6 +143,9 @@ and for prodding me into improving it.
for a different name. In essence, this lets the client do as it will,
ignoring this aspect of their request.
+- Support for compressed 'domain name list' style DHCP option contents, and
+ in particular the domain search option (#119) was added.
+
Changes since 3.0.4
- A warning that host statements declared within subnet or shared-network
@@ -208,6 +211,9 @@ and for prodding me into improving it.
- Some manual pages were clarified pursuant to discussion on the dhcp-server
mailing list.
+- Support for compressed 'domain name list' style DHCP option contents, and
+ in particular the domain search option (#119) was added.
+
Changes since 3.0.4b2
- Null-termination sensing for certain clients that unfortunatley require
diff --git a/client/scripts/bsdos b/client/scripts/bsdos
index d076d92d..fb0d43f2 100755
--- a/client/scripts/bsdos
+++ b/client/scripts/bsdos
@@ -1,11 +1,21 @@
#!/bin/sh
make_resolv_conf() {
- if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then
- echo search $new_domain_name >/etc/resolv.conf
+ if [ x"$new_domain_name_servers" != x ]; then
+ cat /dev/null > /etc/resolv.conf.dhclient
+ if [ "x$new_domain_search" != x ]; then
+ echo search $new_domain_search >> /etc/resolv.conf.dhclient
+ elif [ "x$new_domain_name" != x ]; then
+ # Note that the DHCP 'Domain Name Option' is really just a domain
+ # name, and that this practice of using the domain name option as
+ # a search path is both nonstandard and deprecated.
+ echo search $new_domain_name >> /etc/resolv.conf.dhclient
+ fi
for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf
+ echo nameserver $nameserver >> /etc/resolv.conf.dhclient
done
+
+ mv /etc/resolv.conf.dhclient /etc/resolv.conf
fi
}
diff --git a/client/scripts/freebsd b/client/scripts/freebsd
index 2f0623ef..b40316eb 100755
--- a/client/scripts/freebsd
+++ b/client/scripts/freebsd
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# $Id: freebsd,v 1.16 2005/03/17 20:14:56 dhankins Exp $
+# $Id: freebsd,v 1.17 2006/07/22 02:24:16 dhankins Exp $
#
# $FreeBSD$
@@ -12,24 +12,38 @@ fi
make_resolv_conf() {
if [ x"$new_domain_name_servers" != x ]; then
- if [ "x$new_domain_name" != x ]; then
- ( echo search $new_domain_name >/etc/resolv.conf )
- exit_status=$?
+ ( cat /dev/null > /etc/resolv.conf.dhclient )
+ exit_status=$?
+ if [ $exit_status -ne 0 ]; then
+ $LOGGER "Unable to create /etc/resolv.conf.dhclient: Error $exit_status"
else
- if [ -e /etc/resolv.conf ] ; then
- ( rm /etc/resolv.conf )
+ if [ "x$new_domain_search" != x ]; then
+ ( echo search $new_domain_search >> /etc/resolv.conf.dhclient )
exit_status=$?
- else
- ( touch /etc/resolv.conf )
+ elif [ "x$new_domain_name" != x ]; then
+ # Note that the DHCP 'Domain Name Option' is really just a domain
+ # name, and that this practice of using the domain name option as
+ # a search path is both nonstandard and deprecated.
+ ( echo search $new_domain_name >> /etc/resolv.conf.dhclient )
exit_status=$?
fi
- fi
- if [ $exit_status -ne 0 ]; then
- $LOGGER "WARNING: Unable to update resolv.conf: Error $exit_status"
- else
for nameserver in $new_domain_name_servers; do
- ( echo nameserver $nameserver >>/etc/resolv.conf )
+ if [ $exit_status -ne 0 ]; then
+ break
+ fi
+ ( echo nameserver $nameserver >>/etc/resolv.conf.dhclient )
+ exit_status=$?
done
+
+ # If there were no errors, attempt to mv the new file into place.
+ if [ $exit_status -eq 0 ]; then
+ ( mv /etc/resolv.conf.dhclient /etc/resolv.conf )
+ exit_status = $?
+ fi
+
+ if [ $exit_status -ne 0 ]; then
+ $LOGGER "Error while writing new /etc/resolv.conf."
+ fi
fi
fi
}
diff --git a/client/scripts/linux b/client/scripts/linux
index 31ddd2fe..787efff2 100755
--- a/client/scripts/linux
+++ b/client/scripts/linux
@@ -23,12 +23,22 @@
# of the $1 in its args.
make_resolv_conf() {
- if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then
- echo search $new_domain_name >/etc/resolv.conf
- chmod 644 /etc/resolv.conf
+ if [ x"$new_domain_name_servers" != x ]; then
+ cat /dev/null > /etc/resolv.conf.dhclient
+ chmod 644 /etc/resolv.conf.dhclient
+ if [ x"$new_domain_search" != x ]; then
+ echo search $new_domain_search >> /etc/resolv.conf.dhclient
+ elif [ x"$new_domain_name" != x ]; then
+ # Note that the DHCP 'Domain Name Option' is really just a domain
+ # name, and that this practice of using the domain name option as
+ # a search path is both nonstandard and deprecated.
+ echo search $new_domain_name >> /etc/resolv.conf.dhclient
+ fi
for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf
+ echo nameserver $nameserver >>/etc/resolv.conf.dhclient
done
+
+ mv /etc/resolv.conf.dhclient /etc/resolv.conf
fi
}
diff --git a/client/scripts/netbsd b/client/scripts/netbsd
index d226cdff..3de6b555 100755
--- a/client/scripts/netbsd
+++ b/client/scripts/netbsd
@@ -2,10 +2,20 @@
make_resolv_conf() {
if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then
- echo search $new_domain_name >/etc/resolv.conf
+ cat /dev/null > /etc/resolv.conf.dhclient
+ if [ "x$new_domain_search != x ]; then
+ echo search $new_domain_search >> /etc/resolv.conf.dhclient
+ elif [ "x$new_domain_name != x ]; then
+ # Note that the DHCP 'Domain Name Option' is really just a domain
+ # name, and that this practice of using the domain name option as
+ # a search path is both nonstandard and deprecated.
+ echo search $new_domain_name >> /etc/resolv.conf.dhclient
+ fi
for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf
+ echo nameserver $nameserver >>/etc/resolv.conf.dhclient
done
+
+ mv /etc/resolv.conf.dhclient /etc/resolv.conf
fi
}
diff --git a/client/scripts/nextstep b/client/scripts/nextstep
index 7600fb14..b80d175a 100644
--- a/client/scripts/nextstep
+++ b/client/scripts/nextstep
@@ -31,11 +31,21 @@ if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \
route add default $router 1 >/dev/null 2>&1
done
fi
- if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then
- echo search $new_domain_name >/etc/resolv.conf
+ if [ x"$new_domain_name_servers" != x ]; then
+ cat /dev/null > /etc/resolv.conf.dhclient
+ if [ "x$new_domain_search != x ]; then
+ echo search $new_domain_search >> /etc/resolv.conf.dhclient
+ elif [ "x$new_domain_name != x ]; then
+ # Note that the DHCP 'Domain Name Option' is really just a domain
+ # name, and that this practice of using the domain name option as
+ # a search path is both nonstandard and deprecated.
+ echo search $new_domain_name >> /etc/resolv.conf.dhclient
+ fi
for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf
+ echo nameserver $nameserver >>/etc/resolv.conf.dhclient
done
+
+ mv /etc/resolv.conf.dhclient /etc/resolv.conf
fi
exit 0
fi
diff --git a/client/scripts/openbsd b/client/scripts/openbsd
index d076d92d..64fead2e 100644
--- a/client/scripts/openbsd
+++ b/client/scripts/openbsd
@@ -1,11 +1,21 @@
#!/bin/sh
make_resolv_conf() {
- if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then
- echo search $new_domain_name >/etc/resolv.conf
+ if x"$new_domain_name_servers" != x ]; then
+ cat /dev/null > /etc/resolv.conf.dhclient
+ if [ x"$new_domain_search" != x ]; then
+ echo search $new_domain_search >> /etc/resolv.conf.dhclient
+ elif [ x"$new_domain_name" != x ]; then
+ # Note that the DHCP 'Domain Name Option' is really just a domain
+ # name, and that this practice of using the domain name option as
+ # a search path is both nonstandard and deprecated.
+ echo search $new_domain_name >> /etc/resolv.conf.dhclient
+ fi
for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf
+ echo nameserver $nameserver >>/etc/resolv.conf.dhclient
done
+
+ mv /etc/ersolv.conf.dhclient /etc/resolv.conf
fi
}
diff --git a/client/scripts/solaris b/client/scripts/solaris
index e6187c71..c2403dc3 100755
--- a/client/scripts/solaris
+++ b/client/scripts/solaris
@@ -1,11 +1,21 @@
#!/bin/sh
make_resolv_conf() {
- if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then
- echo search $new_domain_name >/etc/resolv.conf
+ if [ x"$new_domain_name_servers" != x ]; then
+ cat /dev/null > /etc/resolv.conf.dhclient
+ if [ x"$new_domain_search" != x ]; then
+ echo search $new_domain_search >> /etc/resolv.conf.dhclient
+ elif [ x"$new_domain_name" != x ]; then
+ # Note that the DHCP 'Domain Name Option' is really just a domain
+ # name, and that this practice of using the domain name option as
+ # a search path is both nonstandard and deprecated.
+ echo search $new_domain_name >> /etc/resolv.conf.dhclient
+ fi
for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf
+ echo nameserver $nameserver >>/etc/resolv.conf.dhclient
done
+
+ mv /etc/resolv.conf.dhclient /etc/resolv.conf
fi
}
diff --git a/common/conflex.c b/common/conflex.c
index 33ffad54..7184a4aa 100644
--- a/common/conflex.c
+++ b/common/conflex.c
@@ -34,7 +34,7 @@
#ifndef lint
static char copyright[] =
-"$Id: conflex.c,v 1.100 2006/06/16 19:26:44 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: conflex.c,v 1.101 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -655,8 +655,12 @@ static enum dhcp_token intern (atom, dfv)
return DNS_DELETE;
if (!strcasecmp (atom + 1, "omain"))
return DOMAIN;
- if (!strcasecmp (atom + 1, "omain-name"))
- return DOMAIN_NAME;
+ if (!strncasecmp (atom + 1, "omain-", 6)) {
+ if (!strcasecmp(atom + 7, "name"))
+ return DOMAIN_NAME;
+ if (!strcasecmp(atom + 7, "list"))
+ return DOMAIN_LIST;
+ }
if (!strcasecmp (atom + 1, "o-forward-update"))
return DO_FORWARD_UPDATE;
if (!strcasecmp (atom + 1, "ebug"))
diff --git a/common/dhcp-options.5 b/common/dhcp-options.5
index ed2eaf05..923d624f 100644
--- a/common/dhcp-options.5
+++ b/common/dhcp-options.5
@@ -1,4 +1,4 @@
-.\" $Id: dhcp-options.5,v 1.29 2006/06/01 20:23:17 dhankins Exp $
+.\" $Id: dhcp-options.5,v 1.30 2006/07/22 02:24:16 dhankins Exp $
.\"
.\" Copyright (c) 2004-2006 by Internet Systems Consortium, Inc. ("ISC")
.\" Copyright (c) 1996-2003 by Internet Software Consortium
@@ -91,6 +91,13 @@ existing DHCP options. The domain name is stored just as if it were
a text option.
.PP
The
+.B domain-list
+data type specifies a list of domain names, a space between each name and
+the entire string enclosed in double quotes. These types of data are used
+for the domain-search option for example, and encodes an RFC1035 compressed
+DNS label list on the wire.
+.PP
+The
.B flag
data type specifies a boolean value. Booleans can be either true or
false (or on or off, if that makes more sense to you).
@@ -389,6 +396,15 @@ The domain-name-servers option specifies a list of Domain Name System
should be listed in order of preference.
.RE
.PP
+.B option \fBdomain-search\fR \fIstring\fR\fB;\fR
+.RS 0.25i
+.PP
+The domain-search option specifies a 'search list' of Domain Names to be
+used by the client to locate not-fully-qualified domain names. The difference
+between this option and historic use of the domain-name option for the same
+ends is that this option is encoded in RFC1035 compressed labels on the wire.
+.RE
+.PP
.B option \fBextensions-path\fR \fItext\fR\fB;\fR
.RS 0.25i
.PP
diff --git a/common/options.c b/common/options.c
index 070cf71c..0e0abfa5 100644
--- a/common/options.c
+++ b/common/options.c
@@ -34,7 +34,7 @@
#ifndef lint
static char copyright[] =
-"$Id: options.c,v 1.91 2006/06/01 20:23:17 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: options.c,v 1.92 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#define DHCP_OPTION_DATA
@@ -46,6 +46,12 @@ struct option *vendor_cfg_option;
static void do_option_set PROTO ((pair *,
struct option_cache *,
enum statement_op));
+static int pretty_escape(char **, char *, const unsigned char **,
+ const unsigned char *);
+static int pretty_text(char **, char *, const unsigned char **,
+ const unsigned char *, int);
+static int pretty_domain(char **, char *, const unsigned char **,
+ const unsigned char *);
/* Parse all available options out of the specified packet. */
@@ -1146,6 +1152,7 @@ format_has_text(format)
case 'a':
case 'X':
case 'x':
+ case 'D':
return 0;
/* 'E' is variable length, but not arbitrary...you
@@ -1264,6 +1271,7 @@ format_min_length(format, oc)
break;
case 'd': /* "Domain name" */
+ case 'D': /* "rfc1035 compressed names" */
case 't': /* "ASCII Text" */
case 'X': /* "ASCII or Hex Conditional */
case 'x': /* "Hex" */
@@ -1293,14 +1301,16 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
int emit_quotes;
{
static char optbuf [32768]; /* XXX */
+ static char *endbuf = &optbuf[sizeof(optbuf)];
int hunksize = 0;
int opthunk = 0;
int hunkinc = 0;
int numhunk = -1;
int numelem = 0;
+ int count;
+ int i, j, k, l;
char fmtbuf [32];
struct enumeration *enumbuf [32];
- int i, j, k, l;
char *op = optbuf;
const unsigned char *dp = data;
struct in_addr foo;
@@ -1439,32 +1449,73 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
for (j = 0; j < numelem; j++) {
switch (fmtbuf [j]) {
case 't':
- if (emit_quotes)
- *op++ = '"';
- for (; dp < data + len; dp++) {
- if (!isascii (*dp) ||
- !isprint (*dp)) {
- /* Skip trailing NUL. */
- if (dp + 1 != data + len ||
- *dp != 0) {
- sprintf (op, "\\%03o",
- *dp);
- op += 4;
- }
- } else if (*dp == '"' ||
- *dp == '\'' ||
- *dp == '$' ||
- *dp == '`' ||
- *dp == '\\') {
- *op++ = '\\';
- *op++ = *dp;
- } else
- *op++ = *dp;
+ /* endbuf-1 leaves room for NULL. */
+ k = pretty_text(&op, endbuf - 1, &dp,
+ data + len, emit_quotes);
+ if (k == -1) {
+ log_error("Error printing text.");
+ break;
}
- if (emit_quotes)
- *op++ = '"';
*op = 0;
break;
+ case 'D': /* RFC1035 format name list */
+ for( ; dp < (data + len) ; dp += k) {
+ unsigned char nbuff[NS_MAXCDNAME];
+ const unsigned char *nbp, *nend;
+
+ nend = &nbuff[sizeof(nbuff)];
+
+ /* If this is for ISC DHCP consumption
+ * (emit_quotes), lay it out as a list
+ * of STRING tokens. Otherwise, it is
+ * a space-separated list of DNS-
+ * escaped names as /etc/resolv.conf
+ * might digest.
+ */
+ if (dp != data) {
+ if (op + 2 > endbuf)
+ break;
+
+ if (emit_quotes)
+ *op++ = ',';
+ *op++ = ' ';
+ }
+
+ k = MRns_name_unpack(data,
+ data + len,
+ dp, nbuff,
+ sizeof(nbuff));
+
+ if (k == -1) {
+ log_error("Invalid domain "
+ "list.");
+ break;
+ }
+
+ /* If emit_quotes, then use ISC DHCP
+ * escapes. Otherwise, rely only on
+ * ns_name_ntop().
+ */
+ if (emit_quotes) {
+ nbp = nbuff;
+ pretty_domain(&op, endbuf-1,
+ &nbp, nend);
+ } else {
+ count = MRns_name_ntop(
+ nbuff, op,
+ (endbuf-op)-1);
+
+ if (count == -1) {
+ log_error("Invalid "
+ "domain name.");
+ break;
+ }
+
+ op += count;
+ }
+ }
+ *op = '\0';
+ break;
/* pretty-printing an array of enums is
going to get ugly. */
case 'N':
@@ -1478,7 +1529,6 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
break;
}
strcpy (op, enumbuf [j] -> values [i].name);
- op += strlen (op);
break;
case 'I':
foo.s_addr = htonl (getULong (dp));
@@ -2642,3 +2692,142 @@ void do_packet (interface, packet, len, from_port, from, hfrom)
dump_rc_history (0);
#endif
}
+
+static int
+pretty_escape(char **dst, char *dend, const unsigned char **src,
+ const unsigned char *send)
+{
+ int count = 0;
+
+ /* If there aren't as many bytes left as there are in the source
+ * buffer, don't even bother entering the loop.
+ */
+ if (dst == NULL || src == NULL || (*dst >= dend) || (*src > send) ||
+ *dst == NULL || *src == NULL ||
+ ((send - *src) > (dend - *dst)))
+ return -1;
+
+ for ( ; *src < send ; *src++) {
+ if (!isascii (**src) || !isprint (**src)) {
+ /* Skip trailing NUL. */
+ if ((*src + 1) != send || **src != '\0') {
+ if (*dst + 4 > dend)
+ return -1;
+
+ sprintf(*dst, "\\%03o",
+ **src);
+ *dst += 4;
+ count += 4;
+ }
+ } else if (**src == '"' || **src == '\'' || **src == '$' ||
+ **src == '`' || **src == '\\') {
+ if (*dst + 2 > dend)
+ return -1;
+
+ **dst = '\\';
+ *dst++;
+ **dst = **src;
+ *dst++;
+ count += 2;
+ } else {
+ if (*dst + 1 > dend)
+ return -1;
+
+ **dst = **src;
+ *dst++;
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static int
+pretty_text(char **dst, char *dend, const unsigned char **src,
+ const unsigned char *send, int emit_quotes)
+{
+ int count;
+
+ if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
+ *dst == NULL || *src == NULL ||
+ ((*dst + (emit_quotes ? 2 : 0)) > dend) || (*src > send))
+ return -1;
+
+ if (emit_quotes) {
+ **dst = '"';
+ *dst++;
+ }
+
+ /* dend-1 leaves 1 byte for the closing quote. */
+ count = pretty_escape(dst, dend - (emit_quotes ? 1 : 0), src, send);
+
+ if (count == -1)
+ return -1;
+
+ if (emit_quotes && (*dst < dend)) {
+ **dst = '"';
+ *dst++;
+
+ /* Includes quote prior to pretty_escape(); */
+ count += 2;
+ }
+
+ return count;
+}
+
+static int
+pretty_domain(char **dst, char *dend, const unsigned char **src,
+ const unsigned char *send)
+{
+ const unsigned char *tend;
+ int count = 2;
+ int tsiz, status;
+
+ if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
+ *dst == NULL || *src == NULL ||
+ ((*dst + 2) > dend) || (*src >= send))
+ return -1;
+
+ **dst = '"';
+ *dst++;
+
+ do {
+ /* Continue loop until end of src buffer. */
+ if (*src >= send)
+ break;
+
+ /* Consume tag size. */
+ tsiz = **src;
+ *src++;
+
+ /* At root, finis. */
+ if (tsiz == 0)
+ break;
+
+ tend = *src + tsiz;
+
+ /* If the tag exceeds the source buffer, it's illegal.
+ * This should also trap compression pointers (which should
+ * not be in these buffers).
+ */
+ if (tend > send)
+ return -1;
+
+ /* dend-2 leaves room for a trailing dot and quote. */
+ status = pretty_escape(dst, dend-2, src, tend);
+
+ if ((status == -1) || ((*dst + 2) > dend))
+ return -1;
+
+ **dst = '.';
+ *dst++;
+ count += status + 1;
+ }
+ while(1);
+
+ **dst = '"';
+ *dst++;
+
+ return count;
+}
+
diff --git a/common/parse.c b/common/parse.c
index e1b6b772..f146d2b1 100644
--- a/common/parse.c
+++ b/common/parse.c
@@ -34,7 +34,7 @@
#ifndef lint
static char copyright[] =
-"$Id: parse.c,v 1.112 2006/06/06 16:35:18 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: parse.c,v 1.113 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -1391,6 +1391,9 @@ int parse_option_code_definition (cfile, option)
case DOMAIN_NAME:
type = 'd';
goto no_arrays;
+ case DOMAIN_LIST:
+ type = 'D';
+ goto no_arrays;
case TEXT:
type = 't';
no_arrays:
@@ -4704,7 +4707,18 @@ int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
}
}
break;
-
+
+ case 'D': /* Domain list... */
+ t = parse_domain_list(cfile);
+
+ if (!t) {
+ if ((*fmt)[1] != 'o')
+ skip_to_semi(cfile);
+ return 0;
+ }
+
+ break;
+
case 'd': /* Domain name... */
val = parse_host_name (cfile);
if (!val) {
@@ -5188,3 +5202,54 @@ int parse_warn (struct parse *cfile, const char *fmt, ...)
return 0;
}
+
+struct expression *
+parse_domain_list (cfile)
+ struct parse *cfile;
+{
+ const char *val;
+ enum dhcp_token token = SEMI;
+ struct expression *t = NULL;
+ unsigned len, clen = 0;
+ int result;
+ unsigned char compbuf[256 * NS_MAXCDNAME];
+ const unsigned char *dnptrs[256], **lastdnptr;
+
+ memset(compbuf, 0, sizeof(compbuf));
+ memset(dnptrs, 0, sizeof(dnptrs));
+ dnptrs[0] = compbuf;
+ lastdnptr = &dnptrs[255];
+
+ do {
+ /* Consume the COMMA token if peeked. */
+ if (token == COMMA)
+ next_token(&val, NULL, cfile);
+
+ /* Get next (or first) value. */
+ token = next_token(&val, &len, cfile);
+
+ if (token != STRING) {
+ parse_warn(cfile, "Expecting a domain string.");
+ return NULL;
+ }
+
+ result = MRns_name_compress(val, compbuf + clen,
+ sizeof(compbuf) - clen,
+ dnptrs, lastdnptr);
+
+ if (result < 0) {
+ parse_warn(cfile, "Error compressing domain list: %m");
+ return NULL;
+ }
+
+ clen += result;
+
+ token = peek_token(&val, NULL, cfile);
+ } while (token == COMMA);
+
+ if (!make_const_data(&t, compbuf, clen, 1, 1, MDL))
+ log_fatal("No memory for domain list object.");
+
+ return t;
+}
+
diff --git a/common/tables.c b/common/tables.c
index caad763d..eefad58f 100644
--- a/common/tables.c
+++ b/common/tables.c
@@ -34,7 +34,7 @@
#ifndef lint
static char copyright[] =
-"$Id: tables.c,v 1.55 2006/06/01 20:23:17 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: tables.c,v 1.56 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -94,6 +94,7 @@ HASH_FUNCTIONS (option_code, const unsigned *, struct option,
followed by a '.'. The width of the data is specified in the
named enumeration. Named enumerations are tracked in parse.c.
d - Domain name (i.e., FOO or FOO.BAR).
+ D - Domain list (i.e., example.com eng.example.com)
*/
struct universe dhcp_universe;
@@ -185,6 +186,7 @@ static struct option dhcp_options[] = {
{ "nds-context", "t", &dhcp_universe, 87, 1 },
{ "uap-servers", "t", &dhcp_universe, 98, 1 },
{ "subnet-selection", "I", &dhcp_universe, 118, 1 },
+ { "domain-search", "D", &dhcp_universe, 119, 1 },
{ "vivco", "Evendor-class.", &dhcp_universe, 124, 1 },
{ "vivso", "Evendor.", &dhcp_universe, 125, 1 },
{ NULL, NULL, NULL, 0, 0 }
diff --git a/includes/dhcp.h b/includes/dhcp.h
index abdb8549..23b76fc1 100644
--- a/includes/dhcp.h
+++ b/includes/dhcp.h
@@ -149,6 +149,7 @@ struct dhcp_packet {
#define DHO_FQDN 81
#define DHO_DHCP_AGENT_OPTIONS 82
#define DHO_SUBNET_SELECTION 118 /* RFC3011! */
+#define DHO_DOMAIN_SEARCH 119 /* RFC3397 */
#define DHO_VIVCO_SUBOPTIONS 124
#define DHO_VIVSO_SUBOPTIONS 125
/* The DHO_AUTHENTICATE option is not a standard yet, so I've
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index a0cc560b..2f66d1c1 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -1384,6 +1384,8 @@ int parse_allow_deny PROTO ((struct option_cache **, struct parse *, int));
int parse_auth_key PROTO ((struct data_string *, struct parse *));
int parse_warn (struct parse *, const char *, ...)
__attribute__((__format__(__printf__,2,3)));
+struct expression *parse_domain_list (struct parse *cfile);
+
/* tree.c */
#if defined (NSUPDATE)
diff --git a/includes/dhctoken.h b/includes/dhctoken.h
index 5de43130..0315c7c9 100644
--- a/includes/dhctoken.h
+++ b/includes/dhctoken.h
@@ -322,7 +322,8 @@ enum dhcp_token {
MAX_LEASE_MISBALANCE = 626,
MAX_LEASE_OWNERSHIP = 627,
MAX_BALANCE = 628,
- MIN_BALANCE = 629
+ MIN_BALANCE = 629,
+ DOMAIN_LIST = 630
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
diff --git a/includes/minires/minires.h b/includes/minires/minires.h
index 19d21318..67c55cc7 100644
--- a/includes/minires/minires.h
+++ b/includes/minires/minires.h
@@ -45,6 +45,12 @@ isc_result_t minires_nupdate (res_state, ns_updrec *);
int minires_ninit (res_state);
ns_rcode isc_rcode_to_ns (isc_result_t);
+int MRns_name_compress(const char *, u_char *, size_t, const unsigned char **,
+ const unsigned char **);
+int MRns_name_unpack(const unsigned char *, const unsigned char *,
+ const unsigned char *, unsigned char *, size_t);
+int MRns_name_ntop(const unsigned char *, char *, size_t);
+
#if defined (MINIRES_LIB)
#define res_update minires_update
#define res_mkupdate minires_mkupdate
@@ -187,10 +193,7 @@ isc_result_t ns_sign_tcp_init (void *, const unsigned char *,
unsigned, ns_tcp_tsig_state *);
isc_result_t ns_sign_tcp (unsigned char *,
unsigned *, unsigned, int, ns_tcp_tsig_state *, int);
-int ns_name_ntop (const unsigned char *, char *, size_t);
int ns_name_pton (const char *, unsigned char *, size_t);
-int ns_name_unpack (const unsigned char *, const unsigned char *,
- const unsigned char *, unsigned char *, size_t);
int ns_name_pack (const unsigned char *, unsigned char *,
unsigned, const unsigned char **, const unsigned char **);
int ns_name_compress (const char *, unsigned char *,