From nobody@FreeBSD.org  Thu Nov  4 15:13:38 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 74C761065670
	for <freebsd-gnats-submit@FreeBSD.org>; Thu,  4 Nov 2010 15:13:38 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 63B808FC15
	for <freebsd-gnats-submit@FreeBSD.org>; Thu,  4 Nov 2010 15:13:38 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id oA4FDcVA090912
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 4 Nov 2010 15:13:38 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id oA4FDcMq090911;
	Thu, 4 Nov 2010 15:13:38 GMT
	(envelope-from nobody)
Message-Id: <201011041513.oA4FDcMq090911@www.freebsd.org>
Date: Thu, 4 Nov 2010 15:13:38 GMT
From: kenorb <kenorb@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Implement multiple options in Domain Search Option
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         151940
>Category:       bin
>Synopsis:       dhclient(8): Implement multiple options in Domain Search Option
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    dumbbell
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Nov 04 15:20:09 UTC 2010
>Closed-Date:    Fri Jan 27 18:07:22 UTC 2012
>Last-Modified:  Fri Jan 27 18:07:22 UTC 2012
>Originator:     kenorb
>Release:        FreeBSD 8.1-STABLE
>Organization:
>Environment:
> uname -a
FreeBSD kenorb 8.1-STABLE FreeBSD 8.1-STABLE #3: Wed Nov  3 14:36:47 GMT 2010     root@kenorb:/usr/obj/usr/src/sys/BRO  amd64

>Description:
As reported previously here:
http://forums.freebsd.org/showthread.php?p=108445

I'm reporting feature, which is implementation for option-119, which is described in RFC 3397
Look for: Domain Search Option Format
in http://www.ietf.org/rfc/rfc3397.txt


>How-To-Repeat:
> more /etc/resolv.conf
search core.xxx xxx dbh.xxx
nameserver 192.168.14.2

> sudo dhclient bge0
DHCPREQUEST on bge0 to 255.255.255.255 port 67
DHCPACK from 192.168.14.2
bound to 192.168.14.38 -- renewal in 300 seconds.

> more /etc/resolv.conf
search dbh.xxx
nameserver 192.168.14.2
>Fix:
> less +/option-119 /usr/src/sbin/dhclient/tables.c

>Release-Note:
>Audit-Trail:

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/151940: commit references a PR
Date: Sun,  4 Dec 2011 14:45:29 +0000 (UTC)

 Author: dumbbell
 Date: Sun Dec  4 14:44:31 2011
 New Revision: 228259
 URL: http://svn.freebsd.org/changeset/base/228259
 
 Log:
   Support domain-search in dhclient(8)
   
   The "domain-search" option (option 119) allows a DHCP server to publish
   a list of implicit domain suffixes used during name lookup. This option
   is described in RFC 3397.
   
   For instance, if the domain-search option says:
       ".example.org .example.com"
   and one wants to resolve "foobar", the resolver will try:
       1. "foobar.example.org"
       2. "foobar.example.com"
   
   The file /etc/resolv.conf is updated with a "search" directive if the
   DHCP server provides "domain-search".
   
   A regression test suite is included in this patch under
   tools/regression/sbin/dhclient.
   
   PR:		bin/151940
   Sponsored by	Yakaz (http://www.yakaz.com)
 
 Added:
   head/tools/regression/sbin/dhclient/
   head/tools/regression/sbin/dhclient/Makefile   (contents, props changed)
   head/tools/regression/sbin/dhclient/fake.c   (contents, props changed)
   head/tools/regression/sbin/dhclient/option-domain-search.c   (contents, props changed)
 Modified:
   head/sbin/dhclient/clparse.c
   head/sbin/dhclient/dhclient-script
   head/sbin/dhclient/dhclient.c
   head/sbin/dhclient/dhcp-options.5
   head/sbin/dhclient/dhcp.h
   head/sbin/dhclient/options.c
   head/sbin/dhclient/tables.c
   head/tools/regression/sbin/Makefile
 
 Modified: head/sbin/dhclient/clparse.c
 ==============================================================================
 --- head/sbin/dhclient/clparse.c	Sun Dec  4 12:10:24 2011	(r228258)
 +++ head/sbin/dhclient/clparse.c	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -100,6 +100,8 @@ read_client_conf(void)
  	    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 {
 
 Modified: head/sbin/dhclient/dhclient-script
 ==============================================================================
 --- head/sbin/dhclient/dhclient-script	Sun Dec  4 12:10:24 2011	(r228258)
 +++ head/sbin/dhclient/dhclient-script	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -201,7 +201,9 @@ add_new_resolv_conf() {
  	local tmpres=/var/run/resolv.conf.${interface}
  	rm -f $tmpres
  
 -	if [ -n "$new_domain_name" ]; then
 +	if [ -n "$new_domain_search" ]; then
 +		echo "search $new_domain_search" >>$tmpres
 +	elif [ -n "$new_domain_name" ]; then
  		echo "search $new_domain_name" >>$tmpres
  	fi
  
 
 Modified: head/sbin/dhclient/dhclient.c
 ==============================================================================
 --- head/sbin/dhclient/dhclient.c	Sun Dec  4 12:10:24 2011	(r228258)
 +++ head/sbin/dhclient/dhclient.c	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -2401,6 +2401,7 @@ check_option(struct client_lease *l, int
  		}
  		return (1);
  	case DHO_DOMAIN_NAME:
 +	case DHO_DOMAIN_SEARCH:
  		if (!res_hnok(sbuf)) {
  			if (!check_search(sbuf)) {
  				warning("Bogus domain search list %d: %s (%s)",
 
 Modified: head/sbin/dhclient/dhcp-options.5
 ==============================================================================
 --- head/sbin/dhclient/dhcp-options.5	Sun Dec  4 12:10:24 2011	(r228258)
 +++ head/sbin/dhclient/dhcp-options.5	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -265,6 +265,10 @@ character set.
  .It Ic option domain-name Ar string ;
  This option specifies the domain name that the client should use when
  resolving hostnames via the Domain Name System.
 +.It Ic option domain-search Ar string ;
 +This option specifies a list of domain names that the client should use
 +when resolving hostnames via the Domain Name System. This option is
 +defined in RFC 3397.
  .It Ic option swap-server Ar ip-address ;
  This specifies the IP address of the client's swap server.
  .It Ic option root-path Ar string ;
 
 Modified: head/sbin/dhclient/dhcp.h
 ==============================================================================
 --- head/sbin/dhclient/dhcp.h	Sun Dec  4 12:10:24 2011	(r228258)
 +++ head/sbin/dhclient/dhcp.h	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -169,6 +169,7 @@ struct dhcp_packet {
  #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
  
 
 Modified: head/sbin/dhclient/options.c
 ==============================================================================
 --- head/sbin/dhclient/options.c	Sun Dec  4 12:10:24 2011	(r228258)
 +++ head/sbin/dhclient/options.c	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -55,6 +55,10 @@ void	parse_options(struct packet *);
  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 @@ parse_options(struct packet *packet)
  			    (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 @@ parse_option_buffer(struct packet *packe
  }
  
  /*
 + * 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.
 
 Modified: head/sbin/dhclient/tables.c
 ==============================================================================
 --- head/sbin/dhclient/tables.c	Sun Dec  4 12:10:24 2011	(r228258)
 +++ head/sbin/dhclient/tables.c	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -184,7 +184,7 @@ struct option dhcp_options[256] = {
  	{ "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 @@ unsigned char dhcp_option_default_priori
  	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,
 
 Modified: head/tools/regression/sbin/Makefile
 ==============================================================================
 --- head/tools/regression/sbin/Makefile	Sun Dec  4 12:10:24 2011	(r228258)
 +++ head/tools/regression/sbin/Makefile	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -1,5 +1,5 @@
  # $FreeBSD$
  
 -SUBDIR=	growfs
 +SUBDIR=	dhclient growfs
  
  .include <bsd.subdir.mk>
 
 Added: head/tools/regression/sbin/dhclient/Makefile
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/tools/regression/sbin/dhclient/Makefile	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -0,0 +1,16 @@
 +# $FreeBSD$
 +
 +.PATH:	${.CURDIR}/../../../../sbin/dhclient
 +
 +SRCS=	alloc.c convert.c hash.c options.c tables.c			\
 +	fake.c								\
 +	option-domain-search.c
 +
 +CFLAGS+= -I${.CURDIR}/../../../../sbin/dhclient
 +LDADD=	-lutil
 +
 +PROG=	option-domain-search
 +
 +WARNS?=	2
 +
 +.include <bsd.prog.mk>
 
 Added: head/tools/regression/sbin/dhclient/fake.c
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/tools/regression/sbin/dhclient/fake.c	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -0,0 +1,60 @@
 +/* $FreeBSD$ */
 +
 +#include <setjmp.h>
 +#include <stdarg.h>
 +#include <stdio.h>
 +
 +#include "dhcpd.h"
 +
 +extern jmp_buf env;
 +
 +void
 +error(char *fmt, ...)
 +{
 +	va_list ap;
 +
 +	va_start(ap, fmt);
 +	vfprintf(stderr, fmt, ap);
 +	va_end(ap);
 +	fprintf(stderr, "\n");
 +
 +	longjmp(env, 1);
 +}
 +
 +int
 +warning(char *fmt, ...)
 +{
 +	int ret;
 +	va_list ap;
 +
 +	va_start(ap, fmt);
 +	ret = vfprintf(stderr, fmt, ap);
 +	va_end(ap);
 +	fprintf(stderr, "\n");
 +
 +	return ret;
 +}
 +
 +int
 +note(char *fmt, ...)
 +{
 +	int ret;
 +	va_list ap;
 +
 +	va_start(ap, fmt);
 +	ret = vfprintf(stderr, fmt, ap);
 +	va_end(ap);
 +	fprintf(stderr, "\n");
 +
 +	return ret;
 +}
 +
 +void
 +bootp(struct packet *packet)
 +{
 +}
 +
 +void
 +dhcp(struct packet *packet)
 +{
 +}
 
 Added: head/tools/regression/sbin/dhclient/option-domain-search.c
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/tools/regression/sbin/dhclient/option-domain-search.c	Sun Dec  4 14:44:31 2011	(r228259)
 @@ -0,0 +1,328 @@
 +/* $FreeBSD$ */
 +
 +#include <setjmp.h>
 +#include <stdlib.h>
 +
 +#include "dhcpd.h"
 +
 +jmp_buf env;
 +
 +void	expand_domain_search(struct packet *packet);
 +
 +void
 +no_option_present()
 +{
 +	int ret;
 +	struct option_data option;
 +	struct packet p;
 +
 +	option.data = NULL;
 +	option.len  = 0;
 +	p.options[DHO_DOMAIN_SEARCH] = option;
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (p.options[DHO_DOMAIN_SEARCH].len != 0 ||
 +	    p.options[DHO_DOMAIN_SEARCH].data != NULL)
 +		abort();
 +}
 +
 +void
 +one_domain_valid()
 +{
 +	int ret;
 +	struct packet p;
 +	struct option_data *option;
 +
 +	char *data     = "\007example\003org\0";
 +	char *expected = "example.org.";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 13;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (option->len != strlen(expected) ||
 +	    strcmp(option->data, expected) != 0)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +one_domain_truncated1()
 +{
 +	int ret;
 +	struct option_data *option;
 +	struct packet p;
 +
 +	char *data = "\007example\003org";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 12;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (ret != 1)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +one_domain_truncated2()
 +{
 +	int ret;
 +	struct option_data *option;
 +	struct packet p;
 +
 +	char *data = "\007ex";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 3;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (ret != 1)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +two_domains_valid()
 +{
 +	int ret;
 +	struct packet p;
 +	struct option_data *option;
 +
 +	char *data     = "\007example\003org\0\007example\003com\0";
 +	char *expected = "example.org. example.com.";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 26;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (option->len != strlen(expected) ||
 +	    strcmp(option->data, expected) != 0)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +two_domains_truncated1()
 +{
 +	int ret;
 +	struct option_data *option;
 +	struct packet p;
 +
 +	char *data = "\007example\003org\0\007example\003com";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 25;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (ret != 1)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +two_domains_truncated2()
 +{
 +	int ret;
 +	struct option_data *option;
 +	struct packet p;
 +
 +	char *data = "\007example\003org\0\007ex";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 16;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (ret != 1)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +two_domains_compressed()
 +{
 +	int ret;
 +	struct packet p;
 +	struct option_data *option;
 +
 +	char *data     = "\007example\003org\0\006foobar\xc0\x08";
 +	char *expected = "example.org. foobar.org.";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 22;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (option->len != strlen(expected) ||
 +	    strcmp(option->data, expected) != 0)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +two_domains_infloop()
 +{
 +	int ret;
 +	struct packet p;
 +	struct option_data *option;
 +
 +	char *data = "\007example\003org\0\006foobar\xc0\x0d";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 22;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (ret != 1)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +two_domains_forwardptr()
 +{
 +	int ret;
 +	struct packet p;
 +	struct option_data *option;
 +
 +	char *data = "\007example\003org\xc0\x0d\006foobar\0";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 22;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (ret != 1)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +two_domains_truncatedptr()
 +{
 +	int ret;
 +	struct packet p;
 +	struct option_data *option;
 +
 +	char *data = "\007example\003org\0\006foobar\xc0";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 21;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (ret != 1)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +void
 +multiple_domains_valid()
 +{
 +	int ret;
 +	struct packet p;
 +	struct option_data *option;
 +
 +	char *data =
 +	    "\007example\003org\0\002cl\006foobar\003com\0\002fr\xc0\x10";
 +
 +	char *expected = "example.org. cl.foobar.com. fr.foobar.com.";
 +
 +	option = &p.options[DHO_DOMAIN_SEARCH];
 +	option->len  = 33;
 +	option->data = malloc(option->len);
 +	memcpy(option->data, data, option->len);
 +
 +	ret = setjmp(env);
 +	if (ret == 0)
 +		expand_domain_search(&p);
 +
 +	if (option->len != strlen(expected) ||
 +	    strcmp(option->data, expected) != 0)
 +		abort();
 +
 +	free(option->data);
 +}
 +
 +int
 +main(int argc, char *argv[])
 +{
 +
 +	no_option_present();
 +
 +	one_domain_valid();
 +	one_domain_truncated1();
 +	one_domain_truncated2();
 +
 +	two_domains_valid();
 +	two_domains_truncated1();
 +	two_domains_truncated2();
 +
 +	two_domains_compressed();
 +	two_domains_infloop();
 +	two_domains_forwardptr();
 +	two_domains_truncatedptr();
 +
 +	multiple_domains_valid();
 +
 +	return (0);
 +}
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed 
State-Changed-By: dumbbell 
State-Changed-When: Tue Jan 3 09:06:40 UTC 2012 
State-Changed-Why:  
Support added in r228259 in 10-CURRENT. 


Responsible-Changed-From-To: freebsd-bugs->dumbbell 
Responsible-Changed-By: dumbbell 
Responsible-Changed-When: Tue Jan 3 09:06:40 UTC 2012 
Responsible-Changed-Why:  
Support added in r228259 in 10-CURRENT. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=151940 
State-Changed-From-To: closed->patched 
State-Changed-By: dumbbell 
State-Changed-When: Tue Jan 3 10:45:01 UTC 2012 
State-Changed-Why:  
Re-open this PR because it'll be MFC'd. 

MFC after: 2 weeks 

http://www.freebsd.org/cgi/query-pr.cgi?pr=151940 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/151940: commit references a PR
Date: Thu, 26 Jan 2012 19:46:29 +0000 (UTC)

 Author: dumbbell
 Date: Thu Jan 26 19:46:13 2012
 New Revision: 230597
 URL: http://svn.freebsd.org/changeset/base/230597
 
 Log:
   MFC r228259:
   Support domain-search in dhclient(8)
   
   The "domain-search" option (option 119) allows a DHCP server to publish
   a list of implicit domain suffixes used during name lookup. This option
   is described in RFC 3397.
   
   For instance, if the domain-search option says:
       ".example.org .example.com"
   and one wants to resolve "foobar", the resolver will try:
       1. "foobar.example.org"
       2. "foobar.example.com"
   
   The file /etc/resolv.conf is updated with a "search" directive if the
   DHCP server provides "domain-search".
   
   A regression test suite is included in this patch under
   tools/regression/sbin/dhclient.
   
   PR:		bin/151940
   Sponsored by:	Yakaz (http://www.yakaz.com)
   
   MFC r229000:
   Invalid Domain Search option isn't considered as a fatal error
   
   In the original Domain Search option patch, an invalid option value
   would cause the whole lease to be rejected. However, DHCP servers who
   emit such an invalid value are more common than I thought. With this new
   patch, just the option is rejected, not the entire lease.
   
   PR:		bin/163431
   Submitted by:	Fabian Keil <fk@fabiankeil.de> (earlier version)
   Reviewed by:	Fabian Keil <fk@fabiankeil.de>
   Sponsored by:	Yakaz (http://www.yakaz.com)
   
   MFC r229001:
   Adapt testsuite following change in Domain Search error handling
   
   In this testsuite, warning() and error() have the same behaviour.
   
   PR:		bin/163431
   Sponsored by:	Yakaz (http://www.yakaz.com)
 
 Added:
   stable/9/tools/regression/sbin/dhclient/
      - copied from r228259, head/tools/regression/sbin/dhclient/
 Modified:
   stable/9/sbin/dhclient/clparse.c
   stable/9/sbin/dhclient/dhclient-script
   stable/9/sbin/dhclient/dhclient.c
   stable/9/sbin/dhclient/dhcp-options.5
   stable/9/sbin/dhclient/dhcp.h
   stable/9/sbin/dhclient/options.c
   stable/9/sbin/dhclient/tables.c
   stable/9/tools/regression/sbin/Makefile
   stable/9/tools/regression/sbin/dhclient/fake.c
 Directory Properties:
   stable/9/sbin/dhclient/   (props changed)
   stable/9/tools/   (props changed)
 
 Modified: stable/9/sbin/dhclient/clparse.c
 ==============================================================================
 --- stable/9/sbin/dhclient/clparse.c	Thu Jan 26 19:18:10 2012	(r230596)
 +++ stable/9/sbin/dhclient/clparse.c	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -100,6 +100,8 @@ read_client_conf(void)
  	    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 {
 
 Modified: stable/9/sbin/dhclient/dhclient-script
 ==============================================================================
 --- stable/9/sbin/dhclient/dhclient-script	Thu Jan 26 19:18:10 2012	(r230596)
 +++ stable/9/sbin/dhclient/dhclient-script	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -201,7 +201,9 @@ add_new_resolv_conf() {
  	local tmpres=/var/run/resolv.conf.${interface}
  	rm -f $tmpres
  
 -	if [ -n "$new_domain_name" ]; then
 +	if [ -n "$new_domain_search" ]; then
 +		echo "search $new_domain_search" >>$tmpres
 +	elif [ -n "$new_domain_name" ]; then
  		echo "search $new_domain_name" >>$tmpres
  	fi
  
 
 Modified: stable/9/sbin/dhclient/dhclient.c
 ==============================================================================
 --- stable/9/sbin/dhclient/dhclient.c	Thu Jan 26 19:18:10 2012	(r230596)
 +++ stable/9/sbin/dhclient/dhclient.c	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -2368,6 +2368,7 @@ check_option(struct client_lease *l, int
  		}
  		return (1);
  	case DHO_DOMAIN_NAME:
 +	case DHO_DOMAIN_SEARCH:
  		if (!res_hnok(sbuf)) {
  			if (!check_search(sbuf)) {
  				warning("Bogus domain search list %d: %s (%s)",
 
 Modified: stable/9/sbin/dhclient/dhcp-options.5
 ==============================================================================
 --- stable/9/sbin/dhclient/dhcp-options.5	Thu Jan 26 19:18:10 2012	(r230596)
 +++ stable/9/sbin/dhclient/dhcp-options.5	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -265,6 +265,10 @@ character set.
  .It Ic option domain-name Ar string ;
  This option specifies the domain name that the client should use when
  resolving hostnames via the Domain Name System.
 +.It Ic option domain-search Ar string ;
 +This option specifies a list of domain names that the client should use
 +when resolving hostnames via the Domain Name System. This option is
 +defined in RFC 3397.
  .It Ic option swap-server Ar ip-address ;
  This specifies the IP address of the client's swap server.
  .It Ic option root-path Ar string ;
 
 Modified: stable/9/sbin/dhclient/dhcp.h
 ==============================================================================
 --- stable/9/sbin/dhclient/dhcp.h	Thu Jan 26 19:18:10 2012	(r230596)
 +++ stable/9/sbin/dhclient/dhcp.h	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -169,6 +169,7 @@ struct dhcp_packet {
  #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
  
 
 Modified: stable/9/sbin/dhclient/options.c
 ==============================================================================
 --- stable/9/sbin/dhclient/options.c	Thu Jan 26 19:18:10 2012	(r230596)
 +++ stable/9/sbin/dhclient/options.c	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -55,6 +55,10 @@ void	parse_options(struct packet *);
  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 @@ parse_options(struct packet *packet)
  			    (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,171 @@ parse_option_buffer(struct packet *packe
  }
  
  /*
 + * 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, next_domain_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) {
 +		next_domain_len = find_search_domain_name_len(option, &offset);
 +		if (next_domain_len < 0)
 +			/* The Domain Search option value is invalid. */
 +			return;
 +
 +		/* We add 1 for the space between domain names. */
 +		expanded_len += next_domain_len + 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. */
 +				warning("Truncated pointer in DHCP Domain "
 +				    "Search option.");
 +				return (-1);
 +			}
 +
 +			pointer = ((label_len & ~(0xC0)) << 8) +
 +			    option->data[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 = 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) {
 +			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;
 +
 +		/* Move cursor. */
 +		i += label_len + 1;
 +	}
 +
 +	warning("Truncated DHCP Domain Search option.");
 +
 +	return (-1);
 +}
 +
 +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.
 
 Modified: stable/9/sbin/dhclient/tables.c
 ==============================================================================
 --- stable/9/sbin/dhclient/tables.c	Thu Jan 26 19:18:10 2012	(r230596)
 +++ stable/9/sbin/dhclient/tables.c	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -184,7 +184,7 @@ struct option dhcp_options[256] = {
  	{ "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 @@ unsigned char dhcp_option_default_priori
  	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,
 
 Modified: stable/9/tools/regression/sbin/Makefile
 ==============================================================================
 --- stable/9/tools/regression/sbin/Makefile	Thu Jan 26 19:18:10 2012	(r230596)
 +++ stable/9/tools/regression/sbin/Makefile	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -1,5 +1,5 @@
  # $FreeBSD$
  
 -SUBDIR=	growfs
 +SUBDIR=	dhclient growfs
  
  .include <bsd.subdir.mk>
 
 Modified: stable/9/tools/regression/sbin/dhclient/fake.c
 ==============================================================================
 --- head/tools/regression/sbin/dhclient/fake.c	Sun Dec  4 14:44:31 2011	(r228259)
 +++ stable/9/tools/regression/sbin/dhclient/fake.c	Thu Jan 26 19:46:13 2012	(r230597)
 @@ -32,7 +32,11 @@ warning(char *fmt, ...)
  	va_end(ap);
  	fprintf(stderr, "\n");
  
 -	return ret;
 +	/*
 +	 * The original warning() would return "ret" here. We do this to
 +	 * check warnings explicitely.
 +	 */
 +	longjmp(env, 1);
  }
  
  int
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/151940: commit references a PR
Date: Thu, 26 Jan 2012 22:01:27 +0000 (UTC)

 Author: dumbbell
 Date: Thu Jan 26 22:01:05 2012
 New Revision: 230603
 URL: http://svn.freebsd.org/changeset/base/230603
 
 Log:
   MFC r228259:
   Support domain-search in dhclient(8)
   
   The "domain-search" option (option 119) allows a DHCP server to publish
   a list of implicit domain suffixes used during name lookup. This option
   is described in RFC 3397.
   
   For instance, if the domain-search option says:
       ".example.org .example.com"
   and one wants to resolve "foobar", the resolver will try:
       1. "foobar.example.org"
       2. "foobar.example.com"
   
   The file /etc/resolv.conf is updated with a "search" directive if the
   DHCP server provides "domain-search".
   
   A regression test suite is included in this patch under
   tools/regression/sbin/dhclient.
   
   PR:		bin/151940
   Sponsored by:	Yakaz (http://www.yakaz.com)
   
   MFC r229000:
   Invalid Domain Search option isn't considered as a fatal error
   
   In the original Domain Search option patch, an invalid option value
   would cause the whole lease to be rejected. However, DHCP servers who
   emit such an invalid value are more common than I thought. With this new
   patch, just the option is rejected, not the entire lease.
   
   PR:		bin/163431
   Submitted by:	Fabian Keil <fk@fabiankeil.de> (earlier version)
   Reviewed by:	Fabian Keil <fk@fabiankeil.de>
   Sponsored by:	Yakaz (http://www.yakaz.com)
   
   MFC r229001:
   Adapt testsuite following change in Domain Search error handling
   
   In this testsuite, warning() and error() have the same behaviour.
   
   PR:		bin/163431
   Sponsored by:	Yakaz (http://www.yakaz.com)
 
 Added:
   stable/8/tools/regression/sbin/dhclient/
      - copied from r228259, head/tools/regression/sbin/dhclient/
 Modified:
   stable/8/sbin/dhclient/clparse.c
   stable/8/sbin/dhclient/dhclient-script
   stable/8/sbin/dhclient/dhclient.c
   stable/8/sbin/dhclient/dhcp-options.5
   stable/8/sbin/dhclient/dhcp.h
   stable/8/sbin/dhclient/options.c
   stable/8/sbin/dhclient/tables.c
   stable/8/tools/regression/sbin/Makefile
   stable/8/tools/regression/sbin/dhclient/fake.c
 Directory Properties:
   stable/8/sbin/dhclient/   (props changed)
   stable/8/tools/   (props changed)
 
 Modified: stable/8/sbin/dhclient/clparse.c
 ==============================================================================
 --- stable/8/sbin/dhclient/clparse.c	Thu Jan 26 21:43:11 2012	(r230602)
 +++ stable/8/sbin/dhclient/clparse.c	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -100,6 +100,8 @@ read_client_conf(void)
  	    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 {
 
 Modified: stable/8/sbin/dhclient/dhclient-script
 ==============================================================================
 --- stable/8/sbin/dhclient/dhclient-script	Thu Jan 26 21:43:11 2012	(r230602)
 +++ stable/8/sbin/dhclient/dhclient-script	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -201,7 +201,9 @@ add_new_resolv_conf() {
  	local tmpres=/var/run/resolv.conf.${interface}
  	rm -f $tmpres
  
 -	if [ -n "$new_domain_name" ]; then
 +	if [ -n "$new_domain_search" ]; then
 +		echo "search $new_domain_search" >>$tmpres
 +	elif [ -n "$new_domain_name" ]; then
  		echo "search $new_domain_name" >>$tmpres
  	fi
  
 
 Modified: stable/8/sbin/dhclient/dhclient.c
 ==============================================================================
 --- stable/8/sbin/dhclient/dhclient.c	Thu Jan 26 21:43:11 2012	(r230602)
 +++ stable/8/sbin/dhclient/dhclient.c	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -2368,6 +2368,7 @@ check_option(struct client_lease *l, int
  		}
  		return (1);
  	case DHO_DOMAIN_NAME:
 +	case DHO_DOMAIN_SEARCH:
  		if (!res_hnok(sbuf)) {
  			if (!check_search(sbuf)) {
  				warning("Bogus domain search list %d: %s (%s)",
 
 Modified: stable/8/sbin/dhclient/dhcp-options.5
 ==============================================================================
 --- stable/8/sbin/dhclient/dhcp-options.5	Thu Jan 26 21:43:11 2012	(r230602)
 +++ stable/8/sbin/dhclient/dhcp-options.5	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -265,6 +265,10 @@ character set.
  .It Ic option domain-name Ar string ;
  This option specifies the domain name that the client should use when
  resolving hostnames via the Domain Name System.
 +.It Ic option domain-search Ar string ;
 +This option specifies a list of domain names that the client should use
 +when resolving hostnames via the Domain Name System. This option is
 +defined in RFC 3397.
  .It Ic option swap-server Ar ip-address ;
  This specifies the IP address of the client's swap server.
  .It Ic option root-path Ar string ;
 
 Modified: stable/8/sbin/dhclient/dhcp.h
 ==============================================================================
 --- stable/8/sbin/dhclient/dhcp.h	Thu Jan 26 21:43:11 2012	(r230602)
 +++ stable/8/sbin/dhclient/dhcp.h	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -169,6 +169,7 @@ struct dhcp_packet {
  #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
  
 
 Modified: stable/8/sbin/dhclient/options.c
 ==============================================================================
 --- stable/8/sbin/dhclient/options.c	Thu Jan 26 21:43:11 2012	(r230602)
 +++ stable/8/sbin/dhclient/options.c	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -55,6 +55,10 @@ void	parse_options(struct packet *);
  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 @@ parse_options(struct packet *packet)
  			    (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,171 @@ parse_option_buffer(struct packet *packe
  }
  
  /*
 + * 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, next_domain_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) {
 +		next_domain_len = find_search_domain_name_len(option, &offset);
 +		if (next_domain_len < 0)
 +			/* The Domain Search option value is invalid. */
 +			return;
 +
 +		/* We add 1 for the space between domain names. */
 +		expanded_len += next_domain_len + 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. */
 +				warning("Truncated pointer in DHCP Domain "
 +				    "Search option.");
 +				return (-1);
 +			}
 +
 +			pointer = ((label_len & ~(0xC0)) << 8) +
 +			    option->data[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 = 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) {
 +			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;
 +
 +		/* Move cursor. */
 +		i += label_len + 1;
 +	}
 +
 +	warning("Truncated DHCP Domain Search option.");
 +
 +	return (-1);
 +}
 +
 +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.
 
 Modified: stable/8/sbin/dhclient/tables.c
 ==============================================================================
 --- stable/8/sbin/dhclient/tables.c	Thu Jan 26 21:43:11 2012	(r230602)
 +++ stable/8/sbin/dhclient/tables.c	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -184,7 +184,7 @@ struct option dhcp_options[256] = {
  	{ "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 @@ unsigned char dhcp_option_default_priori
  	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,
 
 Modified: stable/8/tools/regression/sbin/Makefile
 ==============================================================================
 --- stable/8/tools/regression/sbin/Makefile	Thu Jan 26 21:43:11 2012	(r230602)
 +++ stable/8/tools/regression/sbin/Makefile	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -1,5 +1,5 @@
  # $FreeBSD$
  
 -SUBDIR=	growfs
 +SUBDIR=	dhclient growfs
  
  .include <bsd.subdir.mk>
 
 Modified: stable/8/tools/regression/sbin/dhclient/fake.c
 ==============================================================================
 --- head/tools/regression/sbin/dhclient/fake.c	Sun Dec  4 14:44:31 2011	(r228259)
 +++ stable/8/tools/regression/sbin/dhclient/fake.c	Thu Jan 26 22:01:05 2012	(r230603)
 @@ -32,7 +32,11 @@ warning(char *fmt, ...)
  	va_end(ap);
  	fprintf(stderr, "\n");
  
 -	return ret;
 +	/*
 +	 * The original warning() would return "ret" here. We do this to
 +	 * check warnings explicitely.
 +	 */
 +	longjmp(env, 1);
  }
  
  int
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: dumbbell 
State-Changed-When: Fri Jan 27 18:06:05 UTC 2012 
State-Changed-Why:  
Support merged in stable/9 (r230597) and stable/8 (r230603). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=151940 
>Unformatted:
