mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-22 09:57:20 +00:00
- 'request' and 'also request' syntaxes have been added to accomodate
the DHCPv6 client configuration. 'send dhcp6.oro' is no longer necessary. [ISC-Bugs #17023]
This commit is contained in:
parent
c6785bb5e1
commit
0c20eab3c8
4
RELNOTES
4
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
|
||||
|
174
client/clparse.c
174
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 :==
|
||||
|
168
client/dhc6.c
168
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
|
||||
|
@ -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];
|
||||
/* 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);
|
||||
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 (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 =
|
||||
|
@ -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
|
||||
|
@ -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"))
|
||||
|
@ -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 *));
|
||||
|
@ -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 && \
|
||||
|
Loading…
x
Reference in New Issue
Block a user