From owner-freebsd-current@FreeBSD.ORG Sat Nov 12 16:07:07 2011 Return-Path: Delivered-To: freebsd-current@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 756A1106566B for ; Sat, 12 Nov 2011 16:07:07 +0000 (UTC) (envelope-from dumbbell@FreeBSD.org) Received: from mail.made4.biz (unknown [IPv6:2001:41d0:1:7018::1:3]) by mx1.freebsd.org (Postfix) with ESMTP id EEF908FC0A for ; Sat, 12 Nov 2011 16:07:06 +0000 (UTC) Received: from [2a01:e35:2439:2440:290:f5ff:fe9d:b78c] (helo=magellan.dumbbell.fr) by mail.made4.biz with esmtpsa (TLSv1:DHE-RSA-CAMELLIA256-SHA:256) (Exim 4.76 (FreeBSD)) (envelope-from ) id 1RPG6i-000MwT-9u for freebsd-current@FreeBSD.org; Sat, 12 Nov 2011 17:07:06 +0100 Message-ID: <4EBE99A7.90500@FreeBSD.org> Date: Sat, 12 Nov 2011 17:07:03 +0100 From: =?ISO-8859-1?Q?Jean-S=E9bastien_P=E9dron?= User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:7.0.1) Gecko/20111002 Thunderbird/7.0.1 MIME-Version: 1.0 To: freebsd-current@FreeBSD.org X-Enigmail-Version: undefined Content-Type: multipart/mixed; boundary="------------060601050805060900010805" Cc: Subject: [Call for reviews] Support domain-search option in dhclient(8) X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 12 Nov 2011 16:07:07 -0000 This is a multi-part message in MIME format. --------------060601050805060900010805 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit -----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----- --------------060601050805060900010805 Content-Type: text/plain; name="dhclient-domain-search-a.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="dhclient-domain-search-a.patch" 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. --------------060601050805060900010805--