-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi!

Attached is a patch that adds support for "domain-search" option
(#119) as defined in RFC 3397[1]. This allows a DHCP server to publish
a list of domain names that should be used to search for non-fully
qualified domain names.

There's already a PR opened about this:
http://www.freebsd.org/cgi/query-pr.cgi?pr=151940

With this patch applied and a DHCP server configured to publish this
option, dhclient(8) will add a line similar to the following one:
  search example.org. foobar.com.

In the example, this indicates that the name "www" should be resolved
first as "www.example.org", then as "www.foobar.com".

I prepared a regression test to be added to tools/regression (not
included). However, I'm not knowledgeable enough to anticipate all
security-related issues. I would appreciate a review especially with
this in mind :)

Thank you!

[1] http://www.faqs.org/rfcs/rfc3397.html

- -- 
Jean-Sébastien Pédron
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (FreeBSD)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk6+macACgkQa+xGJsFYOlMRBACghVQ62JSyt8/yGOsV9jE661W/
PRoAoMsZnSYLfVSzCqZhxbukrbP4bI4q
=qEZg
-----END PGP SIGNATURE-----
Index: sbin/dhclient/dhcp.h
===================================================================
--- sbin/dhclient/dhcp.h        (revision 227467)
+++ sbin/dhclient/dhcp.h        (working copy)
@@ -169,6 +169,7 @@
 #define        DHO_STREETTALK_SERVER           75
 #define        DHO_STREETTALK_DA_SERVER        76
 #define DHO_DHCP_USER_CLASS_ID         77
+#define        DHO_DOMAIN_SEARCH               119
 #define DHO_CLASSLESS_ROUTES           121
 #define DHO_END                                255
 
Index: sbin/dhclient/dhclient.c
===================================================================
--- sbin/dhclient/dhclient.c    (revision 227467)
+++ sbin/dhclient/dhclient.c    (working copy)
@@ -2453,6 +2453,7 @@
        case DHO_DHCP_CLIENT_IDENTIFIER:
        case DHO_BOOTFILE_NAME:
        case DHO_DHCP_USER_CLASS_ID:
+       case DHO_DOMAIN_SEARCH:
        case DHO_END:
                return (1);
        case DHO_CLASSLESS_ROUTES:
Index: sbin/dhclient/tables.c
===================================================================
--- sbin/dhclient/tables.c      (revision 227467)
+++ sbin/dhclient/tables.c      (working copy)
@@ -184,7 +184,7 @@
        { "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", "t",                         &dhcp_universe, 119 },
        { "option-120", "X",                            &dhcp_universe, 120 },
        { "classless-routes", "BA",                     &dhcp_universe, 121 },
        { "option-122", "X",                            &dhcp_universe, 122 },
@@ -400,12 +400,13 @@
        DHO_IRC_SERVER,
        DHO_STREETTALK_SERVER,
        DHO_STREETTALK_DA_SERVER,
+       DHO_DOMAIN_SEARCH,
 
        /* Presently-undefined options... */
        62, 63, 78, 79, 80, 81, 82, 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, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+       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, 150, 151, 152, 153, 154,
        155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
Index: sbin/dhclient/clparse.c
===================================================================
--- sbin/dhclient/clparse.c     (revision 227467)
+++ sbin/dhclient/clparse.c     (working copy)
@@ -100,6 +100,8 @@
            DHO_DOMAIN_NAME_SERVERS;
        top_level_config.requested_options
            [top_level_config.requested_option_count++] = DHO_HOST_NAME;
+       top_level_config.requested_options
+           [top_level_config.requested_option_count++] = DHO_DOMAIN_SEARCH;
 
        if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
                do {
Index: sbin/dhclient/options.c
===================================================================
--- sbin/dhclient/options.c     (revision 227467)
+++ sbin/dhclient/options.c     (working copy)
@@ -55,6 +55,10 @@
 void   parse_option_buffer(struct packet *, unsigned char *, int);
 int    store_options(unsigned char *, int, struct tree_cache **,
            unsigned char *, int, int, int, int);
+void   expand_domain_search(struct packet *packet);
+int    find_search_domain_name_len(struct option_data *option, int *offset);
+void   expand_search_domain_name(struct option_data *option, int *offset,
+           unsigned char **domain_search);
 
 
 /*
@@ -94,6 +98,11 @@
                            (unsigned char *)packet->raw->sname,
                            sizeof(packet->raw->sname));
        }
+
+       /* Expand DHCP Domain Search option. */
+       if (packet->options_valid) {
+               expand_domain_search(packet);
+       }
 }
 
 /*
@@ -194,6 +203,163 @@
 }
 
 /*
+ * Expand DHCP Domain Search option. The value of this option is
+ * encoded like DNS' list of labels. See:
+ *   RFC 3397
+ *   RFC 1035
+ */
+void
+expand_domain_search(struct packet *packet)
+{
+       int offset, expanded_len;
+       struct option_data *option;
+       unsigned char *domain_search, *cursor;
+
+       if (packet->options[DHO_DOMAIN_SEARCH].data == NULL)
+               return;
+
+       option = &packet->options[DHO_DOMAIN_SEARCH];
+
+       /* Compute final expanded length. */
+       expanded_len = 0;
+       offset = 0;
+       while (offset < option->len) {
+               /* We add 1 for the space between domain names. */
+               expanded_len +=
+                   find_search_domain_name_len(option, &offset) + 1;
+       }
+       if (expanded_len > 0)
+               /* Remove 1 for the superfluous trailing space. */
+               --expanded_len;
+
+       domain_search = malloc(expanded_len + 1);
+       if (domain_search == NULL)
+               error("Can't allocate storage for expanded domain-search\n");
+
+       offset = 0;
+       cursor = domain_search;
+       while (offset < option->len) {
+               expand_search_domain_name(option, &offset, &cursor);
+               cursor[0] = ' ';
+               cursor++;
+       }
+       domain_search[expanded_len] = '\0';
+
+       free(option->data);
+       option->len = expanded_len;
+       option->data = domain_search;
+}
+
+int
+find_search_domain_name_len(struct option_data *option, int *offset)
+{
+       int domain_name_len, i, label_len, pointer, pointed_len;
+
+       domain_name_len = 0;
+
+       i = *offset;
+       while (i < option->len) {
+               label_len = option->data[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 >= option->len) {
+                               /* The pointer is truncated. */
+                               error("Truncated pointer in DHCP Domain "
+                                   "Search option.");
+                       }
+
+                       pointer = ((label_len & ~(0xC0)) << 8) +
+                           option->data[i + 1];
+                       if (pointer >= *offset) {
+                               /*
+                                * The pointer must indicates a prior
+                                * occurance.
+                                */
+                               error("Invalid forward pointer in DHCP Domain "
+                                   "Search option compression.");
+                       }
+
+                       pointed_len = find_search_domain_name_len(option,
+                           &pointer);
+                       domain_name_len += pointed_len;
+
+                       *offset = i + 2;
+                       return (domain_name_len);
+               }
+
+               if (i + label_len >= option->len) {
+                       error("Truncated label in DHCP Domain Search option.");
+               }
+
+               /*
+                * Update the domain name length with the length of the
+                * current label, plus a trailing dot ('.').
+                */
+               domain_name_len += label_len + 1;
+
+               /* Move cursor. */
+               i += label_len + 1;
+       }
+
+       error("Truncated DHCP Domain Search option.");
+
+       return (0);
+}
+
+void
+expand_search_domain_name(struct option_data *option, int *offset,
+    unsigned char **domain_search)
+{
+       int i, label_len, pointer;
+       unsigned char *cursor;
+
+       /*
+        * This is the same loop than the function above
+        * (find_search_domain_name_len). Therefore, we remove checks,
+        * they're already done. Here, we just make the copy.
+        */
+       i = *offset;
+       cursor = *domain_search;
+       while (i < option->len) {
+               label_len = option->data[i];
+               if (label_len == 0) {
+                       /*
+                        * A zero-length label marks the end of this
+                        * domain name.
+                        */
+                       *offset = i + 1;
+                       *domain_search = cursor;
+                       return;
+               } else if (label_len & 0xC0) {
+                       /* This is a pointer to another list of labels. */
+                       pointer = ((label_len & ~(0xC0)) << 8) +
+                           option->data[i + 1];
+
+                       expand_search_domain_name(option, &pointer, &cursor);
+
+                       *offset = i + 2;
+                       *domain_search = cursor;
+                       return;
+               }
+
+               /* Copy the label found. */
+               memcpy(cursor, option->data + i + 1, label_len);
+               cursor[label_len] = '.';
+
+               /* Move cursor. */
+               i += label_len + 1;
+               cursor += label_len + 1;
+       }
+}
+
+/*
  * cons options into a big buffer, and then split them out into the
  * three separate buffers if needed.  This allows us to cons up a set of
  * vendor options using the same routine.
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to