summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELNOTES4
-rw-r--r--client/clparse.c174
-rw-r--r--client/dhc6.c168
-rw-r--r--client/dhclient.c89
-rw-r--r--client/dhclient.conf.527
-rw-r--r--common/conflex.c2
-rw-r--r--includes/dhcpd.h8
-rw-r--r--includes/dhctoken.h3
8 files changed, 375 insertions, 100 deletions
diff --git a/RELNOTES b/RELNOTES
index c6794127..ef8cf5a2 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -72,6 +72,10 @@ suggested fixes to <dhcp-users@isc.org>.
would segfault if a client attempted to renew a lease that had been
loaded from persistent storage.
+- 'request' and 'also request' syntaxes have been added to accomodate
+ the DHCPv6 client configuration. 'send dhcp6.oro' is no longer
+ necessary.
+
Changes since 4.0.0a1
- Bug in octal parsing fixed. Thanks to Bernd Fuhrmann for the report
diff --git a/client/clparse.c b/client/clparse.c
index ab4839e7..e1c97bd6 100644
--- a/client/clparse.c
+++ b/client/clparse.c
@@ -37,16 +37,8 @@
struct client_config top_level_config;
-u_int32_t default_requested_options [] = {
- DHO_SUBNET_MASK,
- DHO_BROADCAST_ADDRESS,
- DHO_TIME_OFFSET,
- DHO_ROUTERS,
- DHO_DOMAIN_NAME,
- DHO_DOMAIN_NAME_SERVERS,
- DHO_HOST_NAME,
- 0
-};
+#define NUM_DEFAULT_REQUESTED_OPTS 9
+struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
static void parse_client_default_duid(struct parse *cfile);
static void parse_client6_lease_statement(struct parse *cfile);
@@ -65,6 +57,62 @@ isc_result_t read_client_conf ()
struct client_config *config;
struct interface_info *ip;
isc_result_t status;
+ unsigned code;
+
+ /* Initialize the default request list. */
+ memset(default_requested_options, 0, sizeof(default_requested_options));
+
+ /* 1 */
+ code = DHO_SUBNET_MASK;
+ option_code_hash_lookup(&default_requested_options[0],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 2 */
+ code = DHO_BROADCAST_ADDRESS;
+ option_code_hash_lookup(&default_requested_options[1],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 3 */
+ code = DHO_TIME_OFFSET;
+ option_code_hash_lookup(&default_requested_options[2],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 4 */
+ code = DHO_ROUTERS;
+ option_code_hash_lookup(&default_requested_options[3],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 5 */
+ code = DHO_DOMAIN_NAME;
+ option_code_hash_lookup(&default_requested_options[4],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 6 */
+ code = DHO_DOMAIN_NAME_SERVERS;
+ option_code_hash_lookup(&default_requested_options[5],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 7 */
+ code = DHO_HOST_NAME;
+ option_code_hash_lookup(&default_requested_options[6],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 8 */
+ code = D6O_NAME_SERVERS;
+ option_code_hash_lookup(&default_requested_options[7],
+ dhcpv6_universe.code_hash, &code, 0, MDL);
+
+ /* 9 */
+ code = D6O_DOMAIN_SEARCH;
+ option_code_hash_lookup(&default_requested_options[8],
+ dhcpv6_universe.code_hash, &code, 0, MDL);
+
+ for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
+ if (default_requested_options[code] == NULL)
+ log_fatal("Unable to find option definition for "
+ "index %u during default parameter request "
+ "assembly.", code);
+ }
/* Initialize the top level client configuration. */
memset (&top_level_config, 0, sizeof top_level_config);
@@ -231,6 +279,8 @@ void read_client_leases ()
PREPEND option-decl |
APPEND option-decl |
hardware-declaration |
+ ALSO REQUEST option-list |
+ ALSO REQUIRE option-list |
REQUEST option-list |
REQUIRE option-list |
TIMEOUT number |
@@ -259,6 +309,8 @@ void parse_client_statement (cfile, ip, config)
int known;
int tmp, i;
isc_result_t status;
+ int listlen;
+ struct option ***append_list, **new_list, **cat_list;
switch (peek_token (&val, (unsigned *)0, cfile)) {
case INCLUDE:
@@ -297,6 +349,73 @@ void parse_client_statement (cfile, ip, config)
parse_key (cfile);
return;
+ case TOKEN_ALSO:
+ /* consume ALSO */
+ next_token(&val, NULL, cfile);
+
+ /* consume type of ALSO list. */
+ token = next_token(&val, NULL, cfile);
+
+ if (token == REQUEST) {
+ append_list = &config->requested_options;
+ } else if (token == REQUIRE) {
+ append_list = &config->required_options;
+ } else {
+ parse_warn(cfile, "expected REQUEST or REQUIRE list");
+ skip_to_semi(cfile);
+ return;
+ }
+
+ /* If there is no list, cut the concat short. */
+ if (*append_list == NULL) {
+ parse_option_list(cfile, append_list);
+ return;
+ }
+
+ /* Count the length of the existing list. */
+ for (i = 0 ; (*append_list)[i] != NULL ; i++)
+ ; /* This space intentionally left blank. */
+
+ /* If there's no codes on the list, cut the concat short. */
+ if (i == 0) {
+ parse_option_list(cfile, append_list);
+ return;
+ }
+
+ tmp = parse_option_list(cfile, &new_list);
+
+ if (tmp == 0 || new_list == NULL)
+ return;
+
+ /* Allocate 'i + tmp' buckets plus a terminator. */
+ cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1),
+ MDL);
+
+ if (cat_list == NULL) {
+ log_error("Unable to allocate memory for new "
+ "request list.");
+ skip_to_semi(cfile);
+ return;
+ }
+
+ for (i = 0 ; (*append_list)[i] != NULL ; i++)
+ option_reference(&cat_list[i], (*append_list)[i], MDL);
+
+ tmp = i;
+
+ for (i = 0 ; new_list[i] != 0 ; i++)
+ option_reference(&cat_list[tmp++], new_list[i], MDL);
+
+ cat_list[tmp] = 0;
+
+ /* XXX: We cannot free the old list, because it may have been
+ * XXX: assigned from an outer configuration scope (or may be
+ * XXX: the static default setting).
+ */
+ *append_list = cat_list;
+
+ return;
+
/* REQUIRE can either start a policy statement or a
comma-separated list of names of required options. */
case REQUIRE:
@@ -415,7 +534,7 @@ void parse_client_statement (cfile, ip, config)
case REQUEST:
token = next_token (&val, (unsigned *)0, cfile);
if (config -> requested_options == default_requested_options)
- config -> requested_options = (u_int32_t *)0;
+ config -> requested_options = NULL;
parse_option_list (cfile, &config -> requested_options);
return;
@@ -612,9 +731,8 @@ void parse_client_statement (cfile, ip, config)
/* option-list :== option_name |
option_list COMMA option_name */
-void parse_option_list (cfile, list)
- struct parse *cfile;
- u_int32_t **list;
+int
+parse_option_list(struct parse *cfile, struct option ***list)
{
int ix;
int token;
@@ -634,25 +752,18 @@ void parse_option_list (cfile, list)
parse_warn (cfile, "%s: expected option name.", val);
token = next_token (&val, (unsigned *)0, cfile);
skip_to_semi (cfile);
- return;
+ return 0;
}
status = parse_option_name(cfile, 0, NULL, &option);
if (status != ISC_R_SUCCESS || option == NULL) {
parse_warn (cfile, "%s: expected option name.", val);
- return;
- }
- if (option -> universe != &dhcp_universe) {
- parse_warn (cfile,
- "%s.%s: Only global options allowed.",
- option -> universe -> name, option->name );
- skip_to_semi (cfile);
- option_dereference(&option, MDL);
- return;
+ return 0;
}
r = new_pair (MDL);
if (!r)
log_fatal ("can't allocate pair for option code.");
- r -> car = (caddr_t)(long)option -> code;
+ /* XXX: we should probably carry a reference across this */
+ r->car = (caddr_t)option;
option_dereference(&option, MDL);
r -> cdr = (pair)0;
if (p)
@@ -666,20 +777,21 @@ void parse_option_list (cfile, list)
if (token != SEMI) {
parse_warn (cfile, "expecting semicolon.");
skip_to_semi (cfile);
- return;
+ return 0;
}
/* XXX we can't free the list here, because we may have copied
XXX it from an outer config state. */
- *list = (u_int32_t *)0;
+ *list = NULL;
if (ix) {
- *list = dmalloc ((ix + 1) * sizeof **list, MDL);
+ *list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
if (!*list)
log_error ("no memory for option list.");
else {
ix = 0;
for (q = p; q; q = q -> cdr)
- (*list) [ix++] = (u_int32_t)(long)q -> car;
- (*list) [ix] = 0;
+ option_reference(&(*list)[ix++],
+ (struct option *)q->car, MDL);
+ (*list)[ix] = NULL;
}
while (p) {
q = p -> cdr;
@@ -687,6 +799,8 @@ void parse_option_list (cfile, list)
p = q;
}
}
+
+ return ix;
}
/* interface-declaration :==
diff --git a/client/dhc6.c b/client/dhc6.c
index bb5d2000..62455950 100644
--- a/client/dhc6.c
+++ b/client/dhc6.c
@@ -27,10 +27,15 @@
#ifdef DHCPv6
struct sockaddr_in6 DHCPv6DestAddr;
+
+/* Option definition structures that are used by the software - declared
+ * here once and assigned at startup to save lookups.
+ */
struct option *clientid_option = NULL;
+struct option *elapsed_option = NULL;
struct option *ia_na_option = NULL;
struct option *iaaddr_option = NULL;
-struct option *elapsed_option = NULL;
+struct option *oro_option = NULL;
static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
const char *file, int line);
@@ -162,6 +167,11 @@ dhcpv6_client_assignments(void)
dhcpv6_universe.code_hash, &code, 0, MDL))
log_fatal("Unable to find the CLIENTID option definition.");
+ code = D6O_ELAPSED_TIME;
+ if (!option_code_hash_lookup(&elapsed_option,
+ dhcpv6_universe.code_hash, &code, 0, MDL))
+ log_fatal("Unable to find the ELAPSED_TIME option definition.");
+
code = D6O_IA_NA;
if (!option_code_hash_lookup(&ia_na_option, dhcpv6_universe.code_hash,
&code, 0, MDL))
@@ -172,10 +182,10 @@ dhcpv6_client_assignments(void)
&code, 0, MDL))
log_fatal("Unable to find the IAADDR option definition.");
- code = D6O_ELAPSED_TIME;
- if (!option_code_hash_lookup(&elapsed_option,
- dhcpv6_universe.code_hash, &code, 0, MDL))
- log_fatal("Unable to find the ELAPSED_TIME option definition.");
+ code = D6O_ORO;
+ if (!option_code_hash_lookup(&oro_option, dhcpv6_universe.code_hash,
+ &code, 0, MDL))
+ log_fatal("Unable to find the ORO option definition.");
#ifndef __CYGWIN32__ /* XXX */
endservent();
@@ -790,23 +800,42 @@ insert_lease(struct dhc6_lease **head, struct dhc6_lease *new)
/* Not really clear what to do here yet.
*/
static int
-dhc6_score_lease(struct dhc6_lease *lease)
+dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease)
{
struct dhc6_ia *ia;
struct dhc6_addr *addr;
+ struct option **req;
+ int i;
if (lease->score)
return lease->score;
lease->score = 1;
-#if 0 /* XXX: oro is a bit...weird...still */
- for (i = 0 ; i < oro_len ; i++) {
- if (lookup_option(&dhcpv6_universe, lease->options,
- oro[i]) != NULL)
- lease->score++;
+ /* If this lease lacks a required option, dump it. */
+ /* XXX: we should be able to cache the failure... */
+ req = client->config->required_options;
+ if (req != NULL) {
+ for (i = 0 ; req[i] != NULL ; i++) {
+ if (lookup_option(&dhcpv6_universe, lease->options,
+ req[i]->code) == NULL) {
+ lease->score = 0;
+ return lease->score;
+ }
+ }
+ }
+
+ /* If this lease contains a requested option, improve its
+ * score.
+ */
+ req = client->config->requested_options;
+ if (req != NULL) {
+ for (i = 0 ; req[i] != NULL ; i++) {
+ if (lookup_option(&dhcpv6_universe, lease->options,
+ req[i]->code) != NULL)
+ lease->score++;
+ }
}
-#endif
for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
lease->score += 50;
@@ -1708,8 +1737,8 @@ dhc6_check_reply(struct client_state *client, struct dhc6_lease *new)
/* Compare the new lease with the selected lease to make
* sure there is no risky business.
*/
- nscore = dhc6_score_lease(new);
- sscore = dhc6_score_lease(client->selected_lease);
+ nscore = dhc6_score_lease(client, new);
+ sscore = dhc6_score_lease(client, client->selected_lease);
if ((client->advertised_leases != NULL) &&
(nscore < (sscore / 2))) {
/* XXX: An attacker might reply this way to make
@@ -1799,7 +1828,8 @@ init_handler(struct packet *packet, struct client_state *client)
* should not if the advertise contains less than one IA and address.
*/
if ((client->txcount > 1) ||
- ((lease->pref == 255) && (dhc6_score_lease(lease) > 150))) {
+ ((lease->pref == 255) &&
+ (dhc6_score_lease(client, lease) > 150))) {
log_debug("RCV: Advertisement immediately selected.");
cancel_timeout(do_init6, client);
start_selecting6(client);
@@ -1837,7 +1867,7 @@ init_handler(struct packet *packet, struct client_state *client)
* server identifiers and to select the numerically lower one.
*/
static struct dhc6_lease *
-dhc6_best_lease(struct dhc6_lease **head)
+dhc6_best_lease(struct client_state *client, struct dhc6_lease **head)
{
struct dhc6_lease **rpos, *rval, **candp, *cand;
int cscore, rscore;
@@ -1847,7 +1877,7 @@ dhc6_best_lease(struct dhc6_lease **head)
rpos = head;
rval = *rpos;
- rscore = dhc6_score_lease(rval);
+ rscore = dhc6_score_lease(client, rval);
candp = &rval->next;
cand = *candp;
@@ -1858,7 +1888,7 @@ dhc6_best_lease(struct dhc6_lease **head)
rscore, (unsigned)rval->pref);
for (; cand != NULL ; candp = &cand->next, cand = *candp) {
- cscore = dhc6_score_lease(cand);
+ cscore = dhc6_score_lease(client, cand);
log_debug("PRC: X-- Candidate %s (s: %d, p: %u).",
print_hex_1(cand->server_id.len,
@@ -1942,7 +1972,7 @@ start_selecting6(struct client_state *client)
log_debug("PRC: Selecting best advertised lease.");
client->state = S_SELECTING;
- lease = dhc6_best_lease(&client->advertised_leases);
+ lease = dhc6_best_lease(client, &client->advertised_leases);
if (lease == NULL)
log_fatal("Impossible error at %s:%d.", MDL);
@@ -3120,6 +3150,9 @@ make_client6_options(struct client_state *client, struct option_state **op,
struct dhc6_lease *lease, u_int8_t message)
{
struct option_cache *oc;
+ struct option **req;
+ struct data_string oro;
+ int buflen, i;
if ((op == NULL) || (client == NULL))
return;
@@ -3127,8 +3160,10 @@ make_client6_options(struct client_state *client, struct option_state **op,
if (*op)
option_state_dereference(op, MDL);
+ /* Create a cache to carry options to transmission. */
option_state_allocate(op, MDL);
+ /* Create and store an 'elapsed time' option in the cache. */
oc = NULL;
if (option_cache_allocate(&oc, MDL)) {
const unsigned char *cdata;
@@ -3174,6 +3209,98 @@ make_client6_options(struct client_state *client, struct option_state **op,
save_option(&dhcpv6_universe, *op, oc);
}
+ /* 'send dhcp6.oro foo;' syntax we used in 4.0.0a1/a2 has been
+ * deprecated by adjustments to the 'request' syntax also used for
+ * DHCPv4.
+ */
+ if (lookup_option(&dhcpv6_universe, *op, D6O_ORO) == NULL)
+ log_error("'send dhcp6.oro' syntax is deprecated, please "
+ "use the 'request' syntax ("man dhclient.conf").");
+
+ /* Construct and store an ORO (Option Request Option). It is a
+ * fatal error to fail to send an ORO (of at least zero length).
+ *
+ * Discussion: RFC3315 appears to be inconsistent in its statements
+ * of whether or not the ORO is mandatory. In section 18.1.1
+ * ("Creation and Transmission of Request Messages"):
+ *
+ * The client MUST include an Option Request option (see section
+ * 22.7) to indicate the options the client is interested in
+ * receiving. The client MAY include options with data values as
+ * hints to the server about parameter values the client would like
+ * to have returned.
+ *
+ * This MUST is missing from the creation/transmission of other
+ * messages (such as Renew and Rebind), and the section 22.7 ("Option
+ * Request Option" format and definition):
+ *
+ * A client MAY include an Option Request option in a Solicit,
+ * Request, Renew, Rebind, Confirm or Information-request message to
+ * inform the server about options the client wants the server to
+ * send to the client. A server MAY include an Option Request
+ * option in a Reconfigure option to indicate which options the
+ * client should request from the server.
+ *
+ * seems to relax the requirement from MUST to MAY (and still other
+ * language in RFC3315 supports this).
+ *
+ * In lieu of a clarification of RFC3315, we will conform with the
+ * MUST. Instead of an absent ORO, we will if there are no options
+ * to request supply an empty ORO. Theoretically, an absent ORO is
+ * difficult to interpret (does the client want all options or no
+ * options?). A zero-length ORO is intuitively clear: requesting
+ * nothing.
+ */
+ memset(&oro, 0, sizeof(oro));
+ buflen = 32;
+ if (!buffer_allocate(&oro.buffer, buflen, MDL))
+ log_fatal("Out of memory constructing DHCPv6 ORO.");
+ oro.data = oro.buffer->data;
+ req = client->config->requested_options;
+ if (req != NULL) {
+ for (i = 0 ; req[i] != NULL ; i++) {
+ if (buflen == oro.len) {
+ struct buffer *tmpbuf = NULL;
+
+ buflen += 32;
+
+ /* Shell game. */
+ buffer_reference(&tmpbuf, oro.buffer, MDL);
+ buffer_dereference(&oro.buffer, MDL);
+
+ if (!buffer_allocate(&oro.buffer, buflen, MDL))
+ log_fatal("Out of memory resizing "
+ "DHCPv6 ORO buffer.");
+
+ oro.data = oro.buffer->data;
+
+ memcpy(oro.buffer->data, tmpbuf->data,
+ oro.len);
+
+ buffer_dereference(&tmpbuf, MDL);
+ }
+
+ if (req[i]->universe == &dhcpv6_universe) {
+ /* Append the code to the ORO. */
+ putUShort(oro.buffer->data + oro.len,
+ req[i]->code);
+ oro.len += 2;
+ }
+ }
+ }
+
+ oc = NULL;
+ if (option_cache_allocate(&oc, MDL) &&
+ make_const_data(&oc->expression, oro.data, oro.len, 0, 0, MDL)) {
+ option_reference(&oc->option, oro_option, MDL);
+ save_option(&dhcpv6_universe, *op, oc);
+ } else {
+ log_fatal("Unable to create ORO option cache.");
+ }
+
+ data_string_forget(&oro, MDL);
+
+ /* Bring in any configured options to send. */
if (client->config->on_transmission)
execute_statements_in_scope(NULL, NULL, NULL, client,
lease ? lease->options : NULL,
@@ -3186,7 +3313,8 @@ make_client6_options(struct client_state *client, struct option_state **op,
* way (may as well fail early).
*/
if (lookup_option(&dhcpv6_universe, *op, D6O_ORO) == NULL)
- log_fatal("You must configure a dhcp6.oro!");
+ log_fatal("Internal inconsistency: no dhcp6.oro in transmit "
+ "state.");
}
/* A clone of the DHCPv4 script_write_params() minus the DHCPv4-specific
diff --git a/client/dhclient.c b/client/dhclient.c
index 3f6679e2..83484919 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -1207,6 +1207,7 @@ void dhcpoffer (packet)
struct interface_info *ip = packet -> interface;
struct client_state *client;
struct client_lease *lease, *lp;
+ struct option **req;
int i;
int stop_selecting;
const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
@@ -1238,29 +1239,34 @@ void dhcpoffer (packet)
sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr));
- /* If this lease doesn't supply the minimum required parameters,
- blow it off. */
- if (client -> config -> required_options) {
- for (i = 0; client -> config -> required_options [i]; i++) {
- if (!lookup_option
- (&dhcp_universe, packet -> options,
- client -> config -> required_options [i])) {
- struct option *option = NULL;
- unsigned code = client->config->required_options[i];
-
- option_code_hash_lookup(&option, dhcp_universe.code_hash,
- &code, 0, MDL);
-
- if (option)
- log_info("%s: no %s option.", obuf, option->name);
- else
- log_info("%s: no unknown-%u option.", obuf, code);
+ /* If this lease doesn't supply the minimum required DHCPv4 parameters,
+ * ignore it.
+ */
+ req = client->config->required_options;
+ if (req != NULL) {
+ for (i = 0 ; req[i] != NULL ; i++) {
+ if ((req[i]->universe == &dhcp_universe) &&
+ !lookup_option(&dhcp_universe, packet->options,
+ req[i]->code)) {
+ struct option *option = NULL;
+ unsigned code = req[i]->code;
+
+ option_code_hash_lookup(&option,
+ dhcp_universe.code_hash,
+ &code, 0, MDL);
+
+ if (option)
+ log_info("%s: no %s option.", obuf,
+ option->name);
+ else
+ log_info("%s: no unknown-%u option.",
+ obuf, code);
- option_dereference(&option, MDL);
+ option_dereference(&option, MDL);
- return;
+ return;
+ }
}
- }
}
/* If we've already seen this lease, don't record it again. */
@@ -1957,14 +1963,11 @@ void send_release (cpp)
(struct hardware *)0);
}
-void make_client_options (client, lease, type, sid, rip, prl, op)
- struct client_state *client;
- struct client_lease *lease;
- u_int8_t *type;
- struct option_cache *sid;
- struct iaddr *rip;
- u_int32_t *prl;
- struct option_state **op;
+void
+make_client_options(struct client_state *client, struct client_lease *lease,
+ u_int8_t *type, struct option_cache *sid,
+ struct iaddr *rip, struct option **prl,
+ struct option_state **op)
{
unsigned i;
struct option_cache *oc;
@@ -2014,20 +2017,28 @@ void make_client_options (client, lease, type, sid, rip, prl, op)
option_dereference(&option, MDL);
if (prl) {
- /* Figure out how many parameters were requested. */
- for (i = 0; prl [i]; i++)
- ;
- if (!buffer_allocate (&bp, i, MDL))
+ int len;
+
+ /* Probe the length of the list. */
+ len = 0;
+ for (i = 0 ; prl[i] != NULL ; i++)
+ if (prl[i]->universe == &dhcp_universe)
+ len++;
+
+ if (!buffer_allocate (&bp, len, MDL))
log_error ("can't make parameter list buffer.");
else {
unsigned code = DHO_DHCP_PARAMETER_REQUEST_LIST;
- for (i = 0; prl [i]; i++)
- bp -> data [i] = prl [i];
+ len = 0;
+ for (i = 0 ; prl[i] != NULL ; i++)
+ if (prl[i]->universe == &dhcp_universe)
+ bp->data[len++] = prl[i]->code;
+
if (!(option_code_hash_lookup(&option,
dhcp_universe.code_hash,
&code, 0, MDL) &&
- make_const_option_cache(&oc, &bp, NULL, i,
+ make_const_option_cache(&oc, &bp, NULL, len,
option, MDL)))
log_error ("can't make option cache");
else {
@@ -2210,8 +2221,8 @@ void make_decline (client, lease)
oc = lookup_option (&dhcp_universe, lease -> options,
DHO_DHCP_SERVER_IDENTIFIER);
- make_client_options (client, lease, &decline, oc,
- &lease -> address, (u_int32_t *)0, &options);
+ make_client_options(client, lease, &decline, oc, &lease->address,
+ NULL, &options);
/* Set up the option buffer... */
memset (&client -> packet, 0, sizeof (client -> packet));
@@ -2267,9 +2278,7 @@ void make_release (client, lease)
oc = lookup_option (&dhcp_universe, lease -> options,
DHO_DHCP_SERVER_IDENTIFIER);
- make_client_options (client, lease, &request, oc,
- (struct iaddr *)0, (u_int32_t *)0,
- &options);
+ make_client_options(client, lease, &request, oc, NULL, NULL, &options);
/* Set up the option buffer... */
client -> packet_length =
diff --git a/client/dhclient.conf.5 b/client/dhclient.conf.5
index 70d834f9..f3bdaeee 100644
--- a/client/dhclient.conf.5
+++ b/client/dhclient.conf.5
@@ -1,4 +1,4 @@
-.\" $Id: dhclient.conf.5,v 1.20 2007/05/19 19:16:23 dhankins Exp $
+.\" $Id: dhclient.conf.5,v 1.21 2007/08/23 16:06:08 dhankins Exp $
.\"
.\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
.\" Copyright (c) 1996-2003 by Internet Software Consortium
@@ -179,14 +179,16 @@ are called \fIDHCP Options\fR. DHCP Options are defined in
.B request
.I statement
.PP
- \fBrequest [ \fIoption\fR ] [\fB,\fI ... \fIoption\fR ]\fB;\fR
+ \fB[ also ] request [ [ \fIoption-space\fR . ] \fIoption\fR ] [\fB,\fI ... ]\fB;\fR
.PP
The request statement causes the client to request that any server
responding to the client send the client its values for the specified
options. Only the option names should be specified in the request
statement - not option parameters. By default, the DHCP server
requests the subnet-mask, broadcast-address, time-offset, routers,
-domain-name, domain-name-servers and host-name options.
+domain-name, domain-name-servers and host-name options. Note that if
+you enter a 'request' statement, you over-ride this default and these
+options will not be requested.
.PP
In some cases, it may be desirable to send no parameter request list
at all. To do this, simply write the request statement but specify
@@ -196,15 +198,30 @@ no parameters:
request;
.fi
.PP
+In most cases, it is desirable to simply add one option to the request
+list which is of interest to the client in question. In this case, it
+is best to 'also request' the additional options:
+.PP
+.nf
+ also request domain-search, dhcp6.sip-servers-addresses;
+.fi
+.PP
.I The
.B require
.I statement
.PP
- \fBrequire [ \fIoption\fR ] [\fB,\fI ... \fIoption ]\fB;\fR
+ \fB[ also ] require [ [ \fIoption-space\fR . ] \fIoption\fR ] [\fB,\fI ... ]\fB;\fR
.PP
The require statement lists options that must be sent in order for an
offer to be accepted. Offers that do not contain all the listed
-options will be ignored.
+options will be ignored. There is no default require list.
+.PP
+.nf
+ require name-servers;
+
+ interface eth0 {
+ also require domain-search;
+ }
.PP
.I The
.B send
diff --git a/common/conflex.c b/common/conflex.c
index 49747ab8..7f27f111 100644
--- a/common/conflex.c
+++ b/common/conflex.c
@@ -709,6 +709,8 @@ intern(char *atom, enum dhcp_token dfv) {
return ALIAS;
if (!strcasecmp (atom + 1, "lgorithm"))
return ALGORITHM;
+ if (!strcasecmp (atom + 1, "lso"))
+ return TOKEN_ALSO;
if (!strcasecmp (atom + 1, "bandoned"))
return TOKEN_ABANDONED;
if (!strcasecmp (atom + 1, "dd"))
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index c0418816..faedd05e 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -931,8 +931,8 @@ struct client_config {
*/
struct group *on_transmission;
- u_int32_t *required_options; /* Options server must supply. */
- u_int32_t *requested_options; /* Options to request from server. */
+ struct option **required_options; /* Options that MUST be present. */
+ struct option **requested_options; /* Options to request (ORO/PRL). */
TIME timeout; /* Start to panic if we don't get a
lease in this time period when
@@ -2357,7 +2357,7 @@ void bind_lease PROTO ((struct client_state *));
void make_client_options PROTO ((struct client_state *,
struct client_lease *, u_int8_t *,
struct option_cache *, struct iaddr *,
- u_int32_t *, struct option_state **));
+ struct option **, struct option_state **));
void make_discover PROTO ((struct client_state *, struct client_lease *));
void make_request PROTO ((struct client_state *, struct client_lease *));
void make_decline PROTO ((struct client_state *, struct client_lease *));
@@ -2507,7 +2507,7 @@ void read_client_leases PROTO ((void));
void parse_client_statement PROTO ((struct parse *, struct interface_info *,
struct client_config *));
int parse_X PROTO ((struct parse *, u_int8_t *, unsigned));
-void parse_option_list PROTO ((struct parse *, u_int32_t **));
+int parse_option_list PROTO ((struct parse *, struct option ***));
void parse_interface_declaration PROTO ((struct parse *,
struct client_config *, char *));
int interface_or_dummy PROTO ((struct interface_info **, const char *));
diff --git a/includes/dhctoken.h b/includes/dhctoken.h
index 29d0672a..5baea1c4 100644
--- a/includes/dhctoken.h
+++ b/includes/dhctoken.h
@@ -343,7 +343,8 @@ enum dhcp_token {
EN = 646,
LL = 647,
RANGE6 = 648,
- WHITESPACE = 649
+ WHITESPACE = 649,
+ TOKEN_ALSO = 650
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \