]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
- Support for compressed 'domain name list' style DHCP option contents, and DHCPv6_parsing_base
authorDavid Hankins <dhankins@isc.org>
Sat, 22 Jul 2006 02:24:16 +0000 (02:24 +0000)
committerDavid Hankins <dhankins@isc.org>
Sat, 22 Jul 2006 02:24:16 +0000 (02:24 +0000)
  in particular the domain search option (#119) was added. [ISC-Bugs #15934]

17 files changed:
RELNOTES
client/scripts/bsdos
client/scripts/freebsd
client/scripts/linux
client/scripts/netbsd
client/scripts/nextstep
client/scripts/openbsd
client/scripts/solaris
common/conflex.c
common/dhcp-options.5
common/options.c
common/parse.c
common/tables.c
includes/dhcp.h
includes/dhcpd.h
includes/dhctoken.h
includes/minires/minires.h

index f44dc64e4e961534a066c47dc2fb962217906e9e..dd1a95db15f1b5360de31447e857de26f13ea4c4 100644 (file)
--- 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
index d076d92d01f14243ad2b2c360ca0e344f849ddee..fb0d43f22510d322367aa409a13bc1ed516aa56d 100755 (executable)
@@ -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
 }
 
index 2f0623efcc0d67a2c17d4f9dd0ec39a70637882b..b40316eb1a7a0e5bc2811186a0dff659aa57afee 100755 (executable)
@@ -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
 }
index 31ddd2fece0a713b5117e31d71121622754aff50..787efff2550100d041591052e5143424df777edd 100755 (executable)
 # 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
 }
 
index d226cdff23c3277404488792429d56a2a597977c..3de6b555d72e167e838bd0153bea3078b8675b2f 100755 (executable)
@@ -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
 }
 
index 7600fb145c54cdba8b376e3be703da2569525049..b80d175ad4c5ce2390655324fd3e2c664c77f8d3 100644 (file)
@@ -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
index d076d92d01f14243ad2b2c360ca0e344f849ddee..64fead2e2fcc989d3338561d589c1a588f238fab 100644 (file)
@@ -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
 }
 
index e6187c7156d874cde8062c20a7ba61b0c078c807..c2403dc302761642a7a9d34a4f6068af6789680d 100755 (executable)
@@ -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
 }
 
index 33ffad542ae4e13fe89ae11602a98c4ca78ef0a5..7184a4aae13679f40898eb14baa91bf77223111e 100644 (file)
@@ -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"))
index ed2eaf0528368a3952def9b4369210b16c326351..923d624f9e7eff814227c664cf1c9018df89d0f6 100644 (file)
@@ -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
index 070cf71ca2f00a728f24dc02c705902964cf1131..0e0abfa5f72df8553eeb0d1d4bb9e0d981511c8c 100644 (file)
@@ -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;
+}
+
index e1b6b772dc579df1d9b22eecdc9eeff39c14a1f0..f146d2b113f2fc93db11c61aaa9d42e2a1b70065 100644 (file)
@@ -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;
+}
+
index caad763d767a007fb65c32ba60821f1174f6324f..eefad58f357aa82eef619e4b28fcefb11e230b06 100644 (file)
@@ -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 }
index abdb854972974534be82efd8474718f11d46421a..23b76fc18cca0bc8756c4248f5352bba2288be5a 100644 (file)
@@ -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
index a0cc560b29243c05ffb6846517c5a63120dfdf12..2f66d1c121134ebe0b33d26ebc80bd193e53a068 100644 (file)
@@ -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)
index 5de43130758ebe8bc7731dade7024ce600f51d1d..0315c7c9fecbe79ffd1b04f61eec45ec3503f75f 100644 (file)
@@ -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 &&  \
index 19d21318682a36ae3911d26d46771e930ae40ed5..67c55cc726780eb93effd17111402570eeda7273 100644 (file)
@@ -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 *,