mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-09-04 16:25:21 +00:00
merge 17621
This commit is contained in:
@@ -1439,8 +1439,7 @@ parse_client6_lease_statement(struct parse *cfile)
|
|||||||
|
|
||||||
if (iface == NULL)
|
if (iface == NULL)
|
||||||
parse_warn(cfile, "Lease has no interface designation.");
|
parse_warn(cfile, "Lease has no interface designation.");
|
||||||
|
else if (!has_name && (client == NULL)) {
|
||||||
if (!has_name && (client == NULL)) {
|
|
||||||
for (client = iface->client ; client != NULL ;
|
for (client = iface->client ; client != NULL ;
|
||||||
client = client->next) {
|
client = client->next) {
|
||||||
if (client->name == NULL)
|
if (client->name == NULL)
|
||||||
|
344
client/dhc6.c
344
client/dhc6.c
@@ -39,6 +39,7 @@ struct option *ia_pd_option = NULL;
|
|||||||
struct option *iaaddr_option = NULL;
|
struct option *iaaddr_option = NULL;
|
||||||
struct option *iaprefix_option = NULL;
|
struct option *iaprefix_option = NULL;
|
||||||
struct option *oro_option = NULL;
|
struct option *oro_option = NULL;
|
||||||
|
struct option *irt_option = NULL;
|
||||||
|
|
||||||
static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
|
static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
|
||||||
const char *file, int line);
|
const char *file, int line);
|
||||||
@@ -66,8 +67,10 @@ static struct dhc6_ia *find_ia_na(struct dhc6_ia *head, const char *id);
|
|||||||
static struct dhc6_addr *find_addr(struct dhc6_addr *head,
|
static struct dhc6_addr *find_addr(struct dhc6_addr *head,
|
||||||
struct iaddr *address);
|
struct iaddr *address);
|
||||||
void init_handler(struct packet *packet, struct client_state *client);
|
void init_handler(struct packet *packet, struct client_state *client);
|
||||||
|
void info_request_handler(struct packet *packet, struct client_state *client);
|
||||||
void rapid_commit_handler(struct packet *packet, struct client_state *client);
|
void rapid_commit_handler(struct packet *packet, struct client_state *client);
|
||||||
void do_init6(void *input);
|
void do_init6(void *input);
|
||||||
|
void do_info_request6(void *input);
|
||||||
void do_confirm6(void *input);
|
void do_confirm6(void *input);
|
||||||
void reply_handler(struct packet *packet, struct client_state *client);
|
void reply_handler(struct packet *packet, struct client_state *client);
|
||||||
static isc_result_t dhc6_add_ia_na(struct client_state *client,
|
static isc_result_t dhc6_add_ia_na(struct client_state *client,
|
||||||
@@ -80,6 +83,8 @@ void do_select6(void *input);
|
|||||||
void do_refresh6(void *input);
|
void do_refresh6(void *input);
|
||||||
static void do_release6(void *input);
|
static void do_release6(void *input);
|
||||||
static void start_bound(struct client_state *client);
|
static void start_bound(struct client_state *client);
|
||||||
|
static void start_informed(struct client_state *client);
|
||||||
|
void informed_handler(struct packet *packet, struct client_state *client);
|
||||||
void bound_handler(struct packet *packet, struct client_state *client);
|
void bound_handler(struct packet *packet, struct client_state *client);
|
||||||
void start_renew6(void *input);
|
void start_renew6(void *input);
|
||||||
void start_rebind6(void *input);
|
void start_rebind6(void *input);
|
||||||
@@ -92,10 +97,12 @@ static void script_write_params6(struct client_state *client,
|
|||||||
const char *prefix,
|
const char *prefix,
|
||||||
struct option_state *options);
|
struct option_state *options);
|
||||||
|
|
||||||
|
extern int stateless;
|
||||||
|
|
||||||
/* The "best" default DUID, since we cannot predict any information
|
/* The "best" default DUID, since we cannot predict any information
|
||||||
* about the system (such as whether or not the hardware addresses are
|
* about the system (such as whether or not the hardware addresses are
|
||||||
* integrated into the motherboard or similar), is the "LLT", link local
|
* integrated into the motherboard or similar), is the "LLT", link local
|
||||||
* plus time, DUID.
|
* plus time, DUID. For real stateless "LL" is better.
|
||||||
*
|
*
|
||||||
* Once generated, this duid is stored into the state database, and
|
* Once generated, this duid is stored into the state database, and
|
||||||
* retained across restarts.
|
* retained across restarts.
|
||||||
@@ -123,22 +130,31 @@ form_duid(struct data_string *duid, const char *file, int line)
|
|||||||
|
|
||||||
/* 2 bytes for the 'duid type' field.
|
/* 2 bytes for the 'duid type' field.
|
||||||
* 2 bytes for the 'htype' field.
|
* 2 bytes for the 'htype' field.
|
||||||
* 4 bytes for the 'current time'.
|
* (not stateless) 4 bytes for the 'current time'.
|
||||||
* enough bytes for the hardware address (note that hw_address has
|
* enough bytes for the hardware address (note that hw_address has
|
||||||
* the 'htype' on byte zero).
|
* the 'htype' on byte zero).
|
||||||
*/
|
*/
|
||||||
len = 8 + (ip->hw_address.hlen - 1);
|
len = 4 + (ip->hw_address.hlen - 1);
|
||||||
|
if (!stateless)
|
||||||
|
len += 4;
|
||||||
if (!buffer_allocate(&duid->buffer, len, MDL))
|
if (!buffer_allocate(&duid->buffer, len, MDL))
|
||||||
log_fatal("no memory for default DUID!");
|
log_fatal("no memory for default DUID!");
|
||||||
duid->data = duid->buffer->data;
|
duid->data = duid->buffer->data;
|
||||||
duid->len = len;
|
duid->len = len;
|
||||||
|
|
||||||
/* Basic Link Local Address type of DUID. */
|
/* Basic Link Local Address type of DUID. */
|
||||||
|
if (!stateless) {
|
||||||
putUShort(duid->buffer->data, DUID_LLT);
|
putUShort(duid->buffer->data, DUID_LLT);
|
||||||
putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
|
putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
|
||||||
putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
|
putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
|
||||||
memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
|
memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
|
||||||
ip->hw_address.hlen - 1);
|
ip->hw_address.hlen - 1);
|
||||||
|
} else {
|
||||||
|
putUShort(duid->buffer->data, DUID_LL);
|
||||||
|
putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
|
||||||
|
memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
|
||||||
|
ip->hw_address.hlen - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assign DHCPv6 port numbers as a client.
|
/* Assign DHCPv6 port numbers as a client.
|
||||||
@@ -217,6 +233,11 @@ dhcpv6_client_assignments(void)
|
|||||||
&code, 0, MDL))
|
&code, 0, MDL))
|
||||||
log_fatal("Unable to find the ORO option definition.");
|
log_fatal("Unable to find the ORO option definition.");
|
||||||
|
|
||||||
|
code = D6O_INFORMATION_REFRESH_TIME;
|
||||||
|
if (!option_code_hash_lookup(&irt_option, dhcpv6_universe.code_hash,
|
||||||
|
&code, 0, MDL))
|
||||||
|
log_fatal("Unable to find the IRT option definition.");
|
||||||
|
|
||||||
#ifndef __CYGWIN32__ /* XXX */
|
#ifndef __CYGWIN32__ /* XXX */
|
||||||
endservent();
|
endservent();
|
||||||
#endif
|
#endif
|
||||||
@@ -1253,8 +1274,9 @@ start_init6(struct client_state *client)
|
|||||||
client->MRD = 0;
|
client->MRD = 0;
|
||||||
|
|
||||||
dhc6_retrans_init(client);
|
dhc6_retrans_init(client);
|
||||||
/* RFC3315 section 17.1.2 goes out of its way:
|
|
||||||
*
|
/*
|
||||||
|
* RFC3315 section 17.1.2 goes out of its way:
|
||||||
* Also, the first RT MUST be selected to be strictly greater than IRT
|
* Also, the first RT MUST be selected to be strictly greater than IRT
|
||||||
* by choosing RAND to be strictly greater than 0.
|
* by choosing RAND to be strictly greater than 0.
|
||||||
*/
|
*/
|
||||||
@@ -1284,7 +1306,45 @@ start_init6(struct client_state *client)
|
|||||||
go_daemon();
|
go_daemon();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* start_init6() kicks off an "init-reboot" version of the process, at
|
/* start_info_request6() kicks off the process, transmitting an info
|
||||||
|
* request packet and scheduling a retransmission event.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
start_info_request6(struct client_state *client)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
log_debug("PRC: Requesting information (INIT).");
|
||||||
|
client->state = S_INIT;
|
||||||
|
|
||||||
|
/* Initialize timers, RFC3315 section 18.1.5. */
|
||||||
|
client->IRT = INF_TIMEOUT * 100;
|
||||||
|
client->MRT = INF_MAX_RT * 100;
|
||||||
|
client->MRC = 0;
|
||||||
|
client->MRD = 0;
|
||||||
|
|
||||||
|
dhc6_retrans_init(client);
|
||||||
|
|
||||||
|
client->v6_handler = info_request_handler;
|
||||||
|
|
||||||
|
/* RFC3315 section 18.1.5 says we MUST start the first packet
|
||||||
|
* between 0 and INF_MAX_DELAY seconds. The good news is
|
||||||
|
* INF_MAX_DELAY is 1.
|
||||||
|
*/
|
||||||
|
tv.tv_sec = cur_tv.tv_sec;
|
||||||
|
tv.tv_usec = cur_tv.tv_usec;
|
||||||
|
tv.tv_usec += (random() % (INF_MAX_DELAY * 100)) * 10000;
|
||||||
|
if (tv.tv_usec >= 1000000) {
|
||||||
|
tv.tv_sec += 1;
|
||||||
|
tv.tv_usec -= 1000000;
|
||||||
|
}
|
||||||
|
add_timeout(&tv, do_info_request6, client, NULL, NULL);
|
||||||
|
|
||||||
|
if (nowait)
|
||||||
|
go_daemon();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start_confirm6() kicks off an "init-reboot" version of the process, at
|
||||||
* startup to find out if old bindings are 'fair' and at runtime whenever
|
* startup to find out if old bindings are 'fair' and at runtime whenever
|
||||||
* a link cycles state we'll eventually want to do this.
|
* a link cycles state we'll eventually want to do this.
|
||||||
*/
|
*/
|
||||||
@@ -1529,6 +1589,107 @@ do_init6(void *input)
|
|||||||
dhc6_retrans_advance(client);
|
dhc6_retrans_advance(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* do_info_request6() marshals and transmits an information-request. */
|
||||||
|
void
|
||||||
|
do_info_request6(void *input)
|
||||||
|
{
|
||||||
|
struct client_state *client;
|
||||||
|
struct data_string ds;
|
||||||
|
struct timeval elapsed, tv;
|
||||||
|
int send_ret;
|
||||||
|
|
||||||
|
client = input;
|
||||||
|
|
||||||
|
if ((client->MRC != 0) && (client->txcount > client->MRC)) {
|
||||||
|
log_info("Max retransmission count exceeded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start_time starts at the first transmission.
|
||||||
|
*/
|
||||||
|
if (client->txcount == 0) {
|
||||||
|
client->start_time.tv_sec = cur_tv.tv_sec;
|
||||||
|
client->start_time.tv_usec = cur_tv.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* elapsed = cur - start */
|
||||||
|
elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
|
||||||
|
elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
|
||||||
|
if (elapsed.tv_usec < 0) {
|
||||||
|
elapsed.tv_sec -= 1;
|
||||||
|
elapsed.tv_usec += 1000000;
|
||||||
|
}
|
||||||
|
if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
|
||||||
|
log_info("Max retransmission duration exceeded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ds, 0, sizeof(ds));
|
||||||
|
if (!buffer_allocate(&ds.buffer, 4, MDL)) {
|
||||||
|
log_error("Unable to allocate memory for INFO-REQUEST.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ds.data = ds.buffer->data;
|
||||||
|
ds.len = 4;
|
||||||
|
|
||||||
|
ds.buffer->data[0] = DHCPV6_INFORMATION_REQUEST;
|
||||||
|
memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
|
||||||
|
|
||||||
|
/* Form an elapsed option. */
|
||||||
|
/* Maximum value is 65535 1/100s coded as 0xffff. */
|
||||||
|
if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
|
||||||
|
((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
|
||||||
|
client->elapsed = 0xffff;
|
||||||
|
} else {
|
||||||
|
client->elapsed = elapsed.tv_sec * 100;
|
||||||
|
client->elapsed += elapsed.tv_usec / 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->elapsed == 0)
|
||||||
|
log_debug("XMT: Forming Info-Request, 0 ms elapsed.");
|
||||||
|
else
|
||||||
|
log_debug("XMT: Forming Info-Request, %u0 ms elapsed.",
|
||||||
|
(unsigned)client->elapsed);
|
||||||
|
|
||||||
|
client->elapsed = htons(client->elapsed);
|
||||||
|
|
||||||
|
make_client6_options(client, &client->sent_options, NULL,
|
||||||
|
DHCPV6_INFORMATION_REQUEST);
|
||||||
|
|
||||||
|
/* Fetch any configured 'sent' options (includes DUID) in wire format.
|
||||||
|
*/
|
||||||
|
dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
|
||||||
|
NULL, client->sent_options, &global_scope,
|
||||||
|
&dhcpv6_universe);
|
||||||
|
|
||||||
|
/* Transmit and wait. */
|
||||||
|
|
||||||
|
log_info("XMT: Info-Request on %s, interval %ld0ms.",
|
||||||
|
client->name ? client->name : client->interface->name,
|
||||||
|
(long int)client->RT);
|
||||||
|
|
||||||
|
send_ret = send_packet6(client->interface,
|
||||||
|
ds.data, ds.len, &DHCPv6DestAddr);
|
||||||
|
if (send_ret != ds.len) {
|
||||||
|
log_error("dhc6: send_packet6() sent %d of %d bytes",
|
||||||
|
send_ret, ds.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_string_forget(&ds, MDL);
|
||||||
|
|
||||||
|
/* Wait RT */
|
||||||
|
tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
|
||||||
|
tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
|
||||||
|
if (tv.tv_usec >= 1000000) {
|
||||||
|
tv.tv_sec += 1;
|
||||||
|
tv.tv_usec -= 1000000;
|
||||||
|
}
|
||||||
|
add_timeout(&tv, do_info_request6, client, NULL, NULL);
|
||||||
|
|
||||||
|
dhc6_retrans_advance(client);
|
||||||
|
}
|
||||||
|
|
||||||
/* do_confirm6() creates a Confirm packet and transmits it. This function
|
/* do_confirm6() creates a Confirm packet and transmits it. This function
|
||||||
* is called on every timeout to (re)transmit.
|
* is called on every timeout to (re)transmit.
|
||||||
*/
|
*/
|
||||||
@@ -2467,6 +2628,62 @@ init_handler(struct packet *packet, struct client_state *client)
|
|||||||
log_debug("RCV: Advertisement recorded.");
|
log_debug("RCV: Advertisement recorded.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* info_request_handler() accepts a Reply to an Info-request.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
info_request_handler(struct packet *packet, struct client_state *client)
|
||||||
|
{
|
||||||
|
isc_result_t check_status;
|
||||||
|
unsigned code;
|
||||||
|
|
||||||
|
if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* RFC3315 section 15.10 validation (same as 15.3 since we
|
||||||
|
* always include a client id).
|
||||||
|
*/
|
||||||
|
if (!valid_reply(packet, client)) {
|
||||||
|
log_error("Invalid Reply - rejecting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_status = dhc6_check_status(ISC_R_SUCCESS, packet->options,
|
||||||
|
"message", &code);
|
||||||
|
if (check_status != ISC_R_SUCCESS) {
|
||||||
|
/* If no action was taken, but there is an error, then
|
||||||
|
* we wait for a retransmission.
|
||||||
|
*/
|
||||||
|
if (check_status != ISC_R_CANCELED)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're done retransmitting at this point. */
|
||||||
|
cancel_timeout(do_info_request6, client);
|
||||||
|
|
||||||
|
/* Action was taken, so now that we've torn down our scheduled
|
||||||
|
* retransmissions, return.
|
||||||
|
*/
|
||||||
|
if (check_status == ISC_R_CANCELED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Cleanup if a previous attempt to go bound failed. */
|
||||||
|
if (client->old_lease != NULL) {
|
||||||
|
dhc6_lease_destroy(&client->old_lease, MDL);
|
||||||
|
client->old_lease = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cache options in the active_lease. */
|
||||||
|
if (client->active_lease != NULL)
|
||||||
|
client->old_lease = client->active_lease;
|
||||||
|
client->active_lease = dmalloc(sizeof(struct dhc6_lease), MDL);
|
||||||
|
if (client->active_lease == NULL)
|
||||||
|
log_fatal("Out of memory for v6 lease structure.");
|
||||||
|
option_state_reference(&client->active_lease->options,
|
||||||
|
packet->options, MDL);
|
||||||
|
|
||||||
|
start_informed(client);
|
||||||
|
}
|
||||||
|
|
||||||
/* Specific version of init_handler() for rapid-commit.
|
/* Specific version of init_handler() for rapid-commit.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@@ -3499,7 +3716,7 @@ dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst)
|
|||||||
* to inform it about the new values, and then lay in wait for the next
|
* to inform it about the new values, and then lay in wait for the next
|
||||||
* event.
|
* event.
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
start_bound(struct client_state *client)
|
start_bound(struct client_state *client)
|
||||||
{
|
{
|
||||||
struct dhc6_ia *ia, *oldia;
|
struct dhc6_ia *ia, *oldia;
|
||||||
@@ -3974,6 +4191,7 @@ do_expire(void *input)
|
|||||||
* Run client script to unconfigure interface.
|
* Run client script to unconfigure interface.
|
||||||
* Called with reason STOP6 when dhclient -x is run, or with reason
|
* Called with reason STOP6 when dhclient -x is run, or with reason
|
||||||
* RELEASE6 when server has replied to a Release message.
|
* RELEASE6 when server has replied to a Release message.
|
||||||
|
* Stateless is a special case.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
unconfigure6(struct client_state *client, const char *reason)
|
unconfigure6(struct client_state *client, const char *reason)
|
||||||
@@ -3981,6 +4199,15 @@ unconfigure6(struct client_state *client, const char *reason)
|
|||||||
struct dhc6_ia *ia;
|
struct dhc6_ia *ia;
|
||||||
struct dhc6_addr *addr;
|
struct dhc6_addr *addr;
|
||||||
|
|
||||||
|
if (stateless) {
|
||||||
|
script_init(client, reason, NULL);
|
||||||
|
if (client->active_lease != NULL)
|
||||||
|
script_write_params6(client, "old_",
|
||||||
|
client->active_lease->options);
|
||||||
|
script_go(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->active_lease == NULL)
|
if (client->active_lease == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -4000,6 +4227,109 @@ unconfigure6(struct client_state *client, const char *reason)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
refresh_info_request6(void *input)
|
||||||
|
{
|
||||||
|
struct client_state *client;
|
||||||
|
|
||||||
|
client = (struct client_state *)input;
|
||||||
|
start_info_request6(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeout for Information-Request (using the IRT option).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dhc6_check_irt(struct client_state *client)
|
||||||
|
{
|
||||||
|
struct option **req;
|
||||||
|
struct option_cache *oc;
|
||||||
|
TIME expire = MAX_TIME;
|
||||||
|
struct timeval tv;
|
||||||
|
int i;
|
||||||
|
isc_boolean_t found = ISC_FALSE;
|
||||||
|
|
||||||
|
cancel_timeout(refresh_info_request6, client);
|
||||||
|
|
||||||
|
req = client->config->requested_options;
|
||||||
|
for (i = 0; req[i] != NULL; i++) {
|
||||||
|
if (req[i] == irt_option) {
|
||||||
|
found = ISC_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Simply return gives a endless loop waiting for nothing. */
|
||||||
|
if (!found)
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
oc = lookup_option(&dhcpv6_universe, client->active_lease->options,
|
||||||
|
D6O_INFORMATION_REFRESH_TIME);
|
||||||
|
if (oc != NULL) {
|
||||||
|
struct data_string irt;
|
||||||
|
|
||||||
|
memset(&irt, 0, sizeof(irt));
|
||||||
|
if (!evaluate_option_cache(&irt, NULL, NULL, client,
|
||||||
|
client->active_lease->options,
|
||||||
|
NULL, &global_scope, oc, MDL) ||
|
||||||
|
(irt.len < 4)) {
|
||||||
|
log_error("Can't evaluate IRT.");
|
||||||
|
} else {
|
||||||
|
expire = getULong(irt.data);
|
||||||
|
if (expire < IRT_MINIMUM)
|
||||||
|
expire = IRT_MINIMUM;
|
||||||
|
if (expire == 0xffffffff)
|
||||||
|
expire = MAX_TIME;
|
||||||
|
}
|
||||||
|
data_string_forget(&irt, MDL);
|
||||||
|
} else
|
||||||
|
expire = IRT_DEFAULT;
|
||||||
|
|
||||||
|
if (expire != MAX_TIME) {
|
||||||
|
log_debug("PRC: Refresh event scheduled in %u seconds.",
|
||||||
|
(unsigned) expire);
|
||||||
|
tv.tv_sec = cur_time + expire;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
add_timeout(&tv, refresh_info_request6, client, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We got a Reply. Give dhclient-script a tickle to inform it about
|
||||||
|
* the new values, and then lay in wait for the next event.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
start_informed(struct client_state *client)
|
||||||
|
{
|
||||||
|
client->v6_handler = informed_handler;
|
||||||
|
|
||||||
|
log_debug("PRC: Done.");
|
||||||
|
|
||||||
|
client->state = S_BOUND;
|
||||||
|
|
||||||
|
script_init(client, "RENEW6", NULL);
|
||||||
|
if (client->old_lease != NULL)
|
||||||
|
script_write_params6(client, "old_",
|
||||||
|
client->old_lease->options);
|
||||||
|
script_write_params6(client, "new_", client->active_lease->options);
|
||||||
|
script_go(client);
|
||||||
|
|
||||||
|
go_daemon();
|
||||||
|
|
||||||
|
if (client->old_lease != NULL) {
|
||||||
|
dhc6_lease_destroy(&client->old_lease, MDL);
|
||||||
|
client->old_lease = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Schedule events. */
|
||||||
|
dhc6_check_irt(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* While informed, ignore packets.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
informed_handler(struct packet *packet, struct client_state *client)
|
||||||
|
{
|
||||||
|
log_debug("RCV: Input packets are ignored once bound.");
|
||||||
|
}
|
||||||
|
|
||||||
/* make_client6_options() fetches option caches relevant to the client's
|
/* make_client6_options() fetches option caches relevant to the client's
|
||||||
* scope and places them into the sent_options cache. This cache is later
|
* scope and places them into the sent_options cache. This cache is later
|
||||||
* used to populate DHCPv6 output packets with options.
|
* used to populate DHCPv6 output packets with options.
|
||||||
|
@@ -75,8 +75,11 @@ int client_env_count=0;
|
|||||||
int onetry=0;
|
int onetry=0;
|
||||||
int quiet=1;
|
int quiet=1;
|
||||||
int nowait=0;
|
int nowait=0;
|
||||||
|
int stateless=0;
|
||||||
char *mockup_relay = NULL;
|
char *mockup_relay = NULL;
|
||||||
|
|
||||||
|
void run_stateless(int exit_mode);
|
||||||
|
|
||||||
static void usage PROTO ((void));
|
static void usage PROTO ((void));
|
||||||
|
|
||||||
static isc_result_t write_duid(struct data_string *duid);
|
static isc_result_t write_duid(struct data_string *duid);
|
||||||
@@ -208,7 +211,7 @@ main(int argc, char **argv) {
|
|||||||
nowait = 1;
|
nowait = 1;
|
||||||
} else if (!strcmp (argv [i], "-n")) {
|
} else if (!strcmp (argv [i], "-n")) {
|
||||||
/* do not start up any interfaces */
|
/* do not start up any interfaces */
|
||||||
interfaces_requested = 1;
|
interfaces_requested = -1;
|
||||||
} else if (!strcmp (argv [i], "-w")) {
|
} else if (!strcmp (argv [i], "-w")) {
|
||||||
/* do not exit if there are no broadcast interfaces. */
|
/* do not exit if there are no broadcast interfaces. */
|
||||||
persist = 1;
|
persist = 1;
|
||||||
@@ -223,6 +226,13 @@ main(int argc, char **argv) {
|
|||||||
tmp -> next = client_env;
|
tmp -> next = client_env;
|
||||||
client_env = tmp;
|
client_env = tmp;
|
||||||
client_env_count++;
|
client_env_count++;
|
||||||
|
} else if (!strcmp(argv[i], "-S")) {
|
||||||
|
if (local_family_set && (local_family == AF_INET)) {
|
||||||
|
usage ();
|
||||||
|
}
|
||||||
|
local_family_set = 1;
|
||||||
|
local_family = AF_INET6;
|
||||||
|
stateless = 1;
|
||||||
} else if (!strcmp(argv[i], "-v")) {
|
} else if (!strcmp(argv[i], "-v")) {
|
||||||
quiet = 0;
|
quiet = 0;
|
||||||
} else if (!strcmp (argv [i], "--version")) {
|
} else if (!strcmp (argv [i], "--version")) {
|
||||||
@@ -230,6 +240,8 @@ main(int argc, char **argv) {
|
|||||||
exit (0);
|
exit (0);
|
||||||
} else if (argv [i][0] == '-') {
|
} else if (argv [i][0] == '-') {
|
||||||
usage ();
|
usage ();
|
||||||
|
} else if (interfaces_requested < 0) {
|
||||||
|
usage ();
|
||||||
} else {
|
} else {
|
||||||
struct interface_info *tmp = (struct interface_info *)0;
|
struct interface_info *tmp = (struct interface_info *)0;
|
||||||
status = interface_allocate (&tmp, MDL);
|
status = interface_allocate (&tmp, MDL);
|
||||||
@@ -247,7 +259,7 @@ main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
interface_reference (&interfaces, tmp, MDL);
|
interface_reference (&interfaces, tmp, MDL);
|
||||||
tmp -> flags = INTERFACE_REQUESTED;
|
tmp -> flags = INTERFACE_REQUESTED;
|
||||||
interfaces_requested = 1;
|
interfaces_requested++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,6 +380,15 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
inaddr_any.s_addr = INADDR_ANY;
|
inaddr_any.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
/* Stateless special case. */
|
||||||
|
if (stateless) {
|
||||||
|
if (release_mode || (interfaces_requested != 1)) {
|
||||||
|
usage ();
|
||||||
|
}
|
||||||
|
run_stateless (exit_mode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Discover all the network interfaces. */
|
/* Discover all the network interfaces. */
|
||||||
discover_interfaces (DISCOVER_UNCONFIGURED);
|
discover_interfaces (DISCOVER_UNCONFIGURED);
|
||||||
|
|
||||||
@@ -404,7 +425,7 @@ main(int argc, char **argv) {
|
|||||||
for (ip = interfaces; ip; ip = ip -> next) {
|
for (ip = interfaces; ip; ip = ip -> next) {
|
||||||
/* If interfaces were specified, don't configure
|
/* If interfaces were specified, don't configure
|
||||||
interfaces that weren't specified! */
|
interfaces that weren't specified! */
|
||||||
if (interfaces_requested &&
|
if ((interfaces_requested > 0) &&
|
||||||
((ip -> flags & (INTERFACE_REQUESTED |
|
((ip -> flags & (INTERFACE_REQUESTED |
|
||||||
INTERFACE_AUTOMATIC)) !=
|
INTERFACE_AUTOMATIC)) !=
|
||||||
INTERFACE_REQUESTED))
|
INTERFACE_REQUESTED))
|
||||||
@@ -427,7 +448,7 @@ main(int argc, char **argv) {
|
|||||||
are relevant should be running, so now we once again call
|
are relevant should be running, so now we once again call
|
||||||
discover_interfaces(), and this time ask it to actually set
|
discover_interfaces(), and this time ask it to actually set
|
||||||
up the interfaces. */
|
up the interfaces. */
|
||||||
discover_interfaces (interfaces_requested
|
discover_interfaces (interfaces_requested != 0
|
||||||
? DISCOVER_REQUESTED
|
? DISCOVER_REQUESTED
|
||||||
: DISCOVER_RUNNING);
|
: DISCOVER_RUNNING);
|
||||||
|
|
||||||
@@ -575,7 +596,7 @@ static void usage ()
|
|||||||
|
|
||||||
log_error ("Usage: dhclient %s %s",
|
log_error ("Usage: dhclient %s %s",
|
||||||
#ifdef DHCPv6
|
#ifdef DHCPv6
|
||||||
"[-4|-6] [-1dvrx] [-nw] [-p <port>]",
|
"[-4|-6] [-S1dvrx] [-nw] [-p <port>]",
|
||||||
#else /* DHCPv6 */
|
#else /* DHCPv6 */
|
||||||
"[-1dvrx] [-nw] [-p <port>]",
|
"[-1dvrx] [-nw] [-p <port>]",
|
||||||
#endif /* DHCPv6 */
|
#endif /* DHCPv6 */
|
||||||
@@ -585,6 +606,88 @@ static void usage ()
|
|||||||
log_fatal (" [-sf script-file] [interface]");
|
log_fatal (" [-sf script-file] [interface]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void run_stateless(int exit_mode)
|
||||||
|
{
|
||||||
|
struct client_state *client;
|
||||||
|
omapi_object_t *listener;
|
||||||
|
isc_result_t result;
|
||||||
|
|
||||||
|
/* Discover the network interface. */
|
||||||
|
discover_interfaces(DISCOVER_REQUESTED);
|
||||||
|
|
||||||
|
if (!interfaces)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
/* Parse the dhclient.conf file. */
|
||||||
|
read_client_conf();
|
||||||
|
|
||||||
|
/* Parse the lease database. */
|
||||||
|
read_client_leases();
|
||||||
|
|
||||||
|
/* Establish a default DUID. */
|
||||||
|
if (default_duid.len == 0) {
|
||||||
|
if (default_duid.buffer != NULL)
|
||||||
|
data_string_forget(&default_duid, MDL);
|
||||||
|
|
||||||
|
form_duid(&default_duid, MDL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start a configuration state machine. */
|
||||||
|
for (client = interfaces->client ;
|
||||||
|
client != NULL ;
|
||||||
|
client = client->next) {
|
||||||
|
if (exit_mode) {
|
||||||
|
unconfigure6(client, "STOP6");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
start_info_request6(client);
|
||||||
|
}
|
||||||
|
if (exit_mode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Start up a listener for the object management API protocol. */
|
||||||
|
if (top_level_config.omapi_port != -1) {
|
||||||
|
listener = (omapi_object_t *)0;
|
||||||
|
result = omapi_generic_new(&listener, MDL);
|
||||||
|
if (result != ISC_R_SUCCESS)
|
||||||
|
log_fatal("Can't allocate new generic object: %s\n",
|
||||||
|
isc_result_totext(result));
|
||||||
|
result = omapi_protocol_listen(listener,
|
||||||
|
(unsigned)
|
||||||
|
top_level_config.omapi_port,
|
||||||
|
1);
|
||||||
|
if (result != ISC_R_SUCCESS)
|
||||||
|
log_fatal("Can't start OMAPI protocol: %s",
|
||||||
|
isc_result_totext(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up the packet handler... */
|
||||||
|
dhcpv6_packet_handler = do_packet6;
|
||||||
|
|
||||||
|
#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
|
||||||
|
defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
|
||||||
|
dmalloc_cutoff_generation = dmalloc_generation;
|
||||||
|
dmalloc_longterm = dmalloc_outstanding;
|
||||||
|
dmalloc_outstanding = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we're not supposed to wait before getting the address,
|
||||||
|
don't. */
|
||||||
|
if (nowait)
|
||||||
|
go_daemon();
|
||||||
|
|
||||||
|
/* If we're not going to daemonize, write the pid file
|
||||||
|
now. */
|
||||||
|
if (no_daemon || nowait)
|
||||||
|
write_client_pid_file();
|
||||||
|
|
||||||
|
/* Start dispatching packets and timeouts... */
|
||||||
|
dispatch();
|
||||||
|
|
||||||
|
/*NOTREACHED*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
isc_result_t find_class (struct class **c,
|
isc_result_t find_class (struct class **c,
|
||||||
const char *s, const char *file, int line)
|
const char *s, const char *file, int line)
|
||||||
{
|
{
|
||||||
@@ -1201,8 +1304,11 @@ dhcpv6(struct packet *packet) {
|
|||||||
/* Screen out nonsensical messages. */
|
/* Screen out nonsensical messages. */
|
||||||
switch(packet->dhcpv6_msg_type) {
|
switch(packet->dhcpv6_msg_type) {
|
||||||
case DHCPV6_ADVERTISE:
|
case DHCPV6_ADVERTISE:
|
||||||
case DHCPV6_REPLY:
|
|
||||||
case DHCPV6_RECONFIGURE:
|
case DHCPV6_RECONFIGURE:
|
||||||
|
if (stateless)
|
||||||
|
return;
|
||||||
|
/* Falls through */
|
||||||
|
case DHCPV6_REPLY:
|
||||||
log_info("RCV: %s message on %s from %s.",
|
log_info("RCV: %s message on %s from %s.",
|
||||||
dhcpv6_type_names[packet->dhcpv6_msg_type],
|
dhcpv6_type_names[packet->dhcpv6_msg_type],
|
||||||
packet->interface->name, piaddr(packet->client_addr));
|
packet->interface->name, piaddr(packet->client_addr));
|
||||||
@@ -3319,7 +3425,7 @@ isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
|
|||||||
script_go (ip -> client);
|
script_go (ip -> client);
|
||||||
}
|
}
|
||||||
|
|
||||||
discover_interfaces (interfaces_requested
|
discover_interfaces (interfaces_requested != 0
|
||||||
? DISCOVER_REQUESTED
|
? DISCOVER_REQUESTED
|
||||||
: DISCOVER_RUNNING);
|
: DISCOVER_RUNNING);
|
||||||
|
|
||||||
|
@@ -205,3 +205,9 @@ struct dhcpv6_relay_packet {
|
|||||||
* when the Unix epoch began.
|
* when the Unix epoch began.
|
||||||
*/
|
*/
|
||||||
#define DUID_TIME_EPOCH 946684800
|
#define DUID_TIME_EPOCH 946684800
|
||||||
|
|
||||||
|
/* Information-Request Time option (RFC 4242) */
|
||||||
|
|
||||||
|
#define IRT_DEFAULT 86400
|
||||||
|
#define IRT_MINIMUM 600
|
||||||
|
|
||||||
|
@@ -2525,6 +2525,7 @@ void dhcpv6_client_assignments(void);
|
|||||||
void form_duid(struct data_string *duid, const char *file, int line);
|
void form_duid(struct data_string *duid, const char *file, int line);
|
||||||
void dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line);
|
void dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line);
|
||||||
void start_init6(struct client_state *client);
|
void start_init6(struct client_state *client);
|
||||||
|
void start_info_request6(struct client_state *client);
|
||||||
void start_confirm6(struct client_state *client);
|
void start_confirm6(struct client_state *client);
|
||||||
void start_release6(struct client_state *client);
|
void start_release6(struct client_state *client);
|
||||||
void start_selecting6(struct client_state *client);
|
void start_selecting6(struct client_state *client);
|
||||||
|
Reference in New Issue
Block a user