mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-09-01 06:45:27 +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)
|
||||||
|
354
client/dhc6.c
354
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. */
|
||||||
putUShort(duid->buffer->data, DUID_LLT);
|
if (!stateless) {
|
||||||
putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
|
putUShort(duid->buffer->data, DUID_LLT);
|
||||||
putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
|
putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
|
||||||
memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
|
putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
|
||||||
ip->hw_address.hlen - 1);
|
memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 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,13 +75,16 @@ 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);
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv) {
|
main(int argc, char **argv) {
|
||||||
int fd;
|
int fd;
|
||||||
int i;
|
int i;
|
||||||
@@ -90,8 +93,8 @@ main(int argc, char **argv) {
|
|||||||
unsigned seed;
|
unsigned seed;
|
||||||
char *server = (char *)0;
|
char *server = (char *)0;
|
||||||
isc_result_t status;
|
isc_result_t status;
|
||||||
int exit_mode = 0;
|
int exit_mode = 0;
|
||||||
int release_mode = 0;
|
int release_mode = 0;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
omapi_object_t *listener;
|
omapi_object_t *listener;
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
@@ -108,24 +111,24 @@ main(int argc, char **argv) {
|
|||||||
/* Initialize client globals. */
|
/* Initialize client globals. */
|
||||||
memset(&default_duid, 0, sizeof(default_duid));
|
memset(&default_duid, 0, sizeof(default_duid));
|
||||||
|
|
||||||
/* Make sure that file descriptors 0 (stdin), 1, (stdout), and
|
/* Make sure that file descriptors 0 (stdin), 1, (stdout), and
|
||||||
2 (stderr) are open. To do this, we assume that when we
|
2 (stderr) are open. To do this, we assume that when we
|
||||||
open a file the lowest available file descriptor is used. */
|
open a file the lowest available file descriptor is used. */
|
||||||
fd = open("/dev/null", O_RDWR);
|
fd = open("/dev/null", O_RDWR);
|
||||||
if (fd == 0)
|
if (fd == 0)
|
||||||
fd = open("/dev/null", O_RDWR);
|
fd = open("/dev/null", O_RDWR);
|
||||||
if (fd == 1)
|
if (fd == 1)
|
||||||
fd = open("/dev/null", O_RDWR);
|
fd = open("/dev/null", O_RDWR);
|
||||||
if (fd == 2)
|
if (fd == 2)
|
||||||
log_perror = 0; /* No sense logging to /dev/null. */
|
log_perror = 0; /* No sense logging to /dev/null. */
|
||||||
else if (fd != -1)
|
else if (fd != -1)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
|
openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
|
||||||
|
|
||||||
#if !(defined (DEBUG) || defined (__CYGWIN32__))
|
#if !(defined (DEBUG) || defined (__CYGWIN32__))
|
||||||
setlogmask (LOG_UPTO (LOG_INFO));
|
setlogmask (LOG_UPTO (LOG_INFO));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Set up the OMAPI. */
|
/* Set up the OMAPI. */
|
||||||
status = omapi_init ();
|
status = omapi_init ();
|
||||||
@@ -142,7 +145,7 @@ main(int argc, char **argv) {
|
|||||||
dhcp_interface_startup_hook = dhclient_interface_startup_hook;
|
dhcp_interface_startup_hook = dhclient_interface_startup_hook;
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
if (!strcmp(argv[i], "-r")) {
|
if (!strcmp(argv[i], "-r")) {
|
||||||
release_mode = 1;
|
release_mode = 1;
|
||||||
no_daemon = 1;
|
no_daemon = 1;
|
||||||
#ifdef DHCPv6
|
#ifdef DHCPv6
|
||||||
@@ -159,10 +162,10 @@ main(int argc, char **argv) {
|
|||||||
local_family_set = 1;
|
local_family_set = 1;
|
||||||
local_family = AF_INET6;
|
local_family = AF_INET6;
|
||||||
#endif /* DHCPv6 */
|
#endif /* DHCPv6 */
|
||||||
} else if (!strcmp (argv [i], "-x")) { /* eXit, no release */
|
} else if (!strcmp (argv [i], "-x")) { /* eXit, no release */
|
||||||
release_mode = 0;
|
release_mode = 0;
|
||||||
no_daemon = 0;
|
no_daemon = 0;
|
||||||
exit_mode = 1;
|
exit_mode = 1;
|
||||||
} else if (!strcmp (argv [i], "-p")) {
|
} else if (!strcmp (argv [i], "-p")) {
|
||||||
if (++i == argc)
|
if (++i == argc)
|
||||||
usage ();
|
usage ();
|
||||||
@@ -172,25 +175,25 @@ main(int argc, char **argv) {
|
|||||||
} else if (!strcmp (argv [i], "-d")) {
|
} else if (!strcmp (argv [i], "-d")) {
|
||||||
no_daemon = 1;
|
no_daemon = 1;
|
||||||
quiet = 0;
|
quiet = 0;
|
||||||
} else if (!strcmp (argv [i], "-pf")) {
|
} else if (!strcmp (argv [i], "-pf")) {
|
||||||
if (++i == argc)
|
if (++i == argc)
|
||||||
usage ();
|
usage ();
|
||||||
path_dhclient_pid = argv [i];
|
path_dhclient_pid = argv [i];
|
||||||
no_dhclient_pid = 1;
|
no_dhclient_pid = 1;
|
||||||
} else if (!strcmp (argv [i], "-cf")) {
|
} else if (!strcmp (argv [i], "-cf")) {
|
||||||
if (++i == argc)
|
if (++i == argc)
|
||||||
usage ();
|
usage ();
|
||||||
path_dhclient_conf = argv [i];
|
path_dhclient_conf = argv [i];
|
||||||
no_dhclient_conf = 1;
|
no_dhclient_conf = 1;
|
||||||
} else if (!strcmp (argv [i], "-lf")) {
|
} else if (!strcmp (argv [i], "-lf")) {
|
||||||
if (++i == argc)
|
if (++i == argc)
|
||||||
usage ();
|
usage ();
|
||||||
path_dhclient_db = argv [i];
|
path_dhclient_db = argv [i];
|
||||||
no_dhclient_db = 1;
|
no_dhclient_db = 1;
|
||||||
} else if (!strcmp (argv [i], "-sf")) {
|
} else if (!strcmp (argv [i], "-sf")) {
|
||||||
if (++i == argc)
|
if (++i == argc)
|
||||||
usage ();
|
usage ();
|
||||||
path_dhclient_script = argv [i];
|
path_dhclient_script = argv [i];
|
||||||
no_dhclient_script = 1;
|
no_dhclient_script = 1;
|
||||||
} else if (!strcmp (argv [i], "-1")) {
|
} else if (!strcmp (argv [i], "-1")) {
|
||||||
onetry = 1;
|
onetry = 1;
|
||||||
@@ -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,18 +226,27 @@ 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")) {
|
||||||
log_info ("isc-dhclient-%s", PACKAGE_VERSION);
|
log_info ("isc-dhclient-%s", PACKAGE_VERSION);
|
||||||
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);
|
||||||
if (status != ISC_R_SUCCESS)
|
if (status != ISC_R_SUCCESS)
|
||||||
log_fatal ("Can't record interface %s:%s",
|
log_fatal ("Can't record interface %s:%s",
|
||||||
argv [i], isc_result_totext (status));
|
argv [i], isc_result_totext (status));
|
||||||
if (strlen(argv[i]) >= sizeof(tmp->name))
|
if (strlen(argv[i]) >= sizeof(tmp->name))
|
||||||
log_fatal("%s: interface name too long (is %ld)",
|
log_fatal("%s: interface name too long (is %ld)",
|
||||||
@@ -246,9 +258,9 @@ main(int argc, char **argv) {
|
|||||||
interface_dereference (&interfaces, MDL);
|
interface_dereference (&interfaces, MDL);
|
||||||
}
|
}
|
||||||
interface_reference (&interfaces, tmp, MDL);
|
interface_reference (&interfaces, tmp, MDL);
|
||||||
tmp -> flags = INTERFACE_REQUESTED;
|
tmp -> flags = INTERFACE_REQUESTED;
|
||||||
interfaces_requested = 1;
|
interfaces_requested++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
|
if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
|
||||||
@@ -289,7 +301,7 @@ main(int argc, char **argv) {
|
|||||||
if (path_dhclient_db == NULL)
|
if (path_dhclient_db == NULL)
|
||||||
log_fatal("%s: %s", path, strerror(errno));
|
log_fatal("%s: %s", path, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_dhclient_script[0] != '/') {
|
if (path_dhclient_script[0] != '/') {
|
||||||
char *path = dmalloc(PATH_MAX, MDL);
|
char *path = dmalloc(PATH_MAX, MDL);
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
@@ -298,7 +310,7 @@ main(int argc, char **argv) {
|
|||||||
if (path_dhclient_script == NULL)
|
if (path_dhclient_script == NULL)
|
||||||
log_fatal("%s: %s", path, strerror(errno));
|
log_fatal("%s: %s", path, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* first kill off any currently running client */
|
/* first kill off any currently running client */
|
||||||
if (release_mode || exit_mode) {
|
if (release_mode || exit_mode) {
|
||||||
FILE *pidfd;
|
FILE *pidfd;
|
||||||
@@ -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);
|
||||||
|
|
||||||
@@ -463,13 +484,13 @@ main(int argc, char **argv) {
|
|||||||
for (ip = interfaces ; ip != NULL ; ip = ip->next) {
|
for (ip = interfaces ; ip != NULL ; ip = ip->next) {
|
||||||
for (client = ip->client ; client != NULL ;
|
for (client = ip->client ; client != NULL ;
|
||||||
client = client->next) {
|
client = client->next) {
|
||||||
if (release_mode) {
|
if (release_mode) {
|
||||||
start_release6(client);
|
start_release6(client);
|
||||||
continue;
|
continue;
|
||||||
} else if (exit_mode) {
|
} else if (exit_mode) {
|
||||||
unconfigure6(client, "STOP6");
|
unconfigure6(client, "STOP6");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have a previous binding, Confirm
|
/* If we have a previous binding, Confirm
|
||||||
* that we can (or can't) still use it.
|
* that we can (or can't) still use it.
|
||||||
@@ -481,16 +502,16 @@ main(int argc, char **argv) {
|
|||||||
start_init6(client);
|
start_init6(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif /* DHCPv6 */
|
#endif /* DHCPv6 */
|
||||||
{
|
{
|
||||||
for (ip = interfaces ; ip ; ip = ip->next) {
|
for (ip = interfaces ; ip ; ip = ip->next) {
|
||||||
ip->flags |= INTERFACE_RUNNING;
|
ip->flags |= INTERFACE_RUNNING;
|
||||||
for (client = ip->client ; client ;
|
for (client = ip->client ; client ;
|
||||||
client = client->next) {
|
client = client->next) {
|
||||||
if (exit_mode)
|
if (exit_mode)
|
||||||
state_stop(client);
|
state_stop(client);
|
||||||
else if (release_mode)
|
else if (release_mode)
|
||||||
do_release(client);
|
do_release(client);
|
||||||
else {
|
else {
|
||||||
client->state = S_INIT;
|
client->state = S_INIT;
|
||||||
@@ -575,9 +596,9 @@ 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 */
|
||||||
"[-s server]");
|
"[-s server]");
|
||||||
log_error (" [-cf config-file] [-lf lease-file]%s",
|
log_error (" [-cf config-file] [-lf lease-file]%s",
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -619,7 +722,7 @@ int find_subnet (struct subnet **sp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Individual States:
|
/* Individual States:
|
||||||
*
|
*
|
||||||
* Each routine is called from the dhclient_state_machine() in one of
|
* Each routine is called from the dhclient_state_machine() in one of
|
||||||
* these conditions:
|
* these conditions:
|
||||||
* -> entering INIT state
|
* -> entering INIT state
|
||||||
@@ -781,7 +884,7 @@ void state_selecting (cpp)
|
|||||||
|
|
||||||
/* Add an immediate timeout to send the first DHCPREQUEST packet. */
|
/* Add an immediate timeout to send the first DHCPREQUEST packet. */
|
||||||
send_request (client);
|
send_request (client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* state_requesting is called when we receive a DHCPACK message after
|
/* state_requesting is called when we receive a DHCPACK message after
|
||||||
having sent out one or more DHCPREQUEST packets. */
|
having sent out one or more DHCPREQUEST packets. */
|
||||||
@@ -794,7 +897,7 @@ void dhcpack (packet)
|
|||||||
struct client_lease *lease;
|
struct client_lease *lease;
|
||||||
struct option_cache *oc;
|
struct option_cache *oc;
|
||||||
struct data_string ds;
|
struct data_string ds;
|
||||||
|
|
||||||
/* If we're not receptive to an offer right now, or if the offer
|
/* If we're not receptive to an offer right now, or if the offer
|
||||||
has an unrecognizable transaction id, then just drop it. */
|
has an unrecognizable transaction id, then just drop it. */
|
||||||
for (client = ip -> client; client; client = client -> next) {
|
for (client = ip -> client; client; client = client -> next) {
|
||||||
@@ -854,7 +957,7 @@ void dhcpack (packet)
|
|||||||
if (!client -> new -> expiry) {
|
if (!client -> new -> expiry) {
|
||||||
log_error ("no expiry time on offered lease.");
|
log_error ("no expiry time on offered lease.");
|
||||||
/* XXX this is going to be bad - if this _does_
|
/* XXX this is going to be bad - if this _does_
|
||||||
XXX happen, we should probably dynamically
|
XXX happen, we should probably dynamically
|
||||||
XXX disqualify the DHCP server that gave us the
|
XXX disqualify the DHCP server that gave us the
|
||||||
XXX bad packet from future selections and
|
XXX bad packet from future selections and
|
||||||
XXX then go back into the init state. */
|
XXX then go back into the init state. */
|
||||||
@@ -999,7 +1102,7 @@ void bind_lease (client)
|
|||||||
if (client->config->do_forward_update)
|
if (client->config->do_forward_update)
|
||||||
dhclient_schedule_updates(client, &client->active->address,
|
dhclient_schedule_updates(client, &client->active->address,
|
||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* state_bound is called when we've successfully bound to a particular
|
/* state_bound is called when we've successfully bound to a particular
|
||||||
lease, but the renewal time on that lease has expired. We are
|
lease, but the renewal time on that lease has expired. We are
|
||||||
@@ -1043,7 +1146,7 @@ void state_bound (cpp)
|
|||||||
|
|
||||||
/* Send the first packet immediately. */
|
/* Send the first packet immediately. */
|
||||||
send_request (client);
|
send_request (client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* state_stop is called when we've been told to shut down. We unconfigure
|
/* state_stop is called when we've been told to shut down. We unconfigure
|
||||||
the interfaces, and then stop operating until told otherwise. */
|
the interfaces, and then stop operating until told otherwise. */
|
||||||
@@ -1067,7 +1170,7 @@ void state_stop (cpp)
|
|||||||
script_write_params(client, "alias_", client->alias);
|
script_write_params(client, "alias_", client->alias);
|
||||||
script_go(client);
|
script_go(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int commit_leases ()
|
int commit_leases ()
|
||||||
{
|
{
|
||||||
@@ -1119,7 +1222,7 @@ void bootp (packet)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dhcpoffer (packet);
|
dhcpoffer (packet);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1175,7 +1278,7 @@ void dhcp (packet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DHCPv6
|
#ifdef DHCPv6
|
||||||
void
|
void
|
||||||
dhcpv6(struct packet *packet) {
|
dhcpv6(struct packet *packet) {
|
||||||
struct iaddrmatchlist *ap;
|
struct iaddrmatchlist *ap;
|
||||||
struct client_state *client;
|
struct client_state *client;
|
||||||
@@ -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));
|
||||||
@@ -1239,10 +1345,10 @@ void dhcpoffer (packet)
|
|||||||
const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
|
const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
|
||||||
char obuf [1024];
|
char obuf [1024];
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
#ifdef DEBUG_PACKET
|
#ifdef DEBUG_PACKET
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Find a client state that matches the xid... */
|
/* Find a client state that matches the xid... */
|
||||||
for (client = ip -> client; client; client = client -> next)
|
for (client = ip -> client; client; client = client -> next)
|
||||||
@@ -1482,7 +1588,7 @@ struct client_lease *packet_to_lease (packet, client)
|
|||||||
(struct group *)0);
|
(struct group *)0);
|
||||||
|
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dhcpnak (packet)
|
void dhcpnak (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
@@ -1592,7 +1698,7 @@ void send_discover (cpp)
|
|||||||
if (client -> medium) {
|
if (client -> medium) {
|
||||||
client -> medium = client -> medium -> next;
|
client -> medium = client -> medium -> next;
|
||||||
increase = 0;
|
increase = 0;
|
||||||
}
|
}
|
||||||
if (!client -> medium) {
|
if (!client -> medium) {
|
||||||
if (fail)
|
if (fail)
|
||||||
log_fatal ("No valid media types for %s!",
|
log_fatal ("No valid media types for %s!",
|
||||||
@@ -1601,7 +1707,7 @@ void send_discover (cpp)
|
|||||||
client -> config -> media;
|
client -> config -> media;
|
||||||
increase = 1;
|
increase = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info ("Trying medium \"%s\" %d",
|
log_info ("Trying medium \"%s\" %d",
|
||||||
client -> medium -> string, increase);
|
client -> medium -> string, increase);
|
||||||
script_init (client, "MEDIUM", client -> medium);
|
script_init (client, "MEDIUM", client -> medium);
|
||||||
@@ -1628,7 +1734,7 @@ void send_discover (cpp)
|
|||||||
+ (random() % client->config->backoff_cutoff);
|
+ (random() % client->config->backoff_cutoff);
|
||||||
} else if (!client->interval)
|
} else if (!client->interval)
|
||||||
client->interval = client->config->initial_interval;
|
client->interval = client->config->initial_interval;
|
||||||
|
|
||||||
/* If the backoff would take us to the panic timeout, just use that
|
/* If the backoff would take us to the panic timeout, just use that
|
||||||
as the interval. */
|
as the interval. */
|
||||||
if (cur_time + client -> interval >
|
if (cur_time + client -> interval >
|
||||||
@@ -1853,7 +1959,7 @@ void send_request (cpp)
|
|||||||
client -> interval += ((random () >> 2) %
|
client -> interval += ((random () >> 2) %
|
||||||
(2 * client -> interval));
|
(2 * client -> interval));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't backoff past cutoff. */
|
/* Don't backoff past cutoff. */
|
||||||
if (client -> interval >
|
if (client -> interval >
|
||||||
client -> config -> backoff_cutoff)
|
client -> config -> backoff_cutoff)
|
||||||
@@ -2191,7 +2297,7 @@ void make_request (client, lease)
|
|||||||
(struct lease *)0, client,
|
(struct lease *)0, client,
|
||||||
/* maximum packet size */1500,
|
/* maximum packet size */1500,
|
||||||
(struct option_state *)0,
|
(struct option_state *)0,
|
||||||
client -> sent_options,
|
client -> sent_options,
|
||||||
/* scope */ &global_scope,
|
/* scope */ &global_scope,
|
||||||
/* overload */ 0,
|
/* overload */ 0,
|
||||||
/* terminate */0,
|
/* terminate */0,
|
||||||
@@ -2467,7 +2573,7 @@ write_options(struct client_state *client, struct option_state *options,
|
|||||||
|
|
||||||
for (i = 0; i < options->universe_count; i++) {
|
for (i = 0; i < options->universe_count; i++) {
|
||||||
option_space_foreach(NULL, NULL, client, NULL, options,
|
option_space_foreach(NULL, NULL, client, NULL, options,
|
||||||
&global_scope, universes[i],
|
&global_scope, universes[i],
|
||||||
(char *)preamble, write_lease_option);
|
(char *)preamble, write_lease_option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2794,7 +2900,7 @@ void script_init (client, reason, medium)
|
|||||||
}
|
}
|
||||||
client -> env = (struct string_list *)0;
|
client -> env = (struct string_list *)0;
|
||||||
client -> envc = 0;
|
client -> envc = 0;
|
||||||
|
|
||||||
if (client -> interface) {
|
if (client -> interface) {
|
||||||
client_envadd (client, "", "interface", "%s",
|
client_envadd (client, "", "interface", "%s",
|
||||||
client -> interface -> name);
|
client -> interface -> name);
|
||||||
@@ -3048,7 +3154,7 @@ int dhcp_option_ev_name (buf, buflen, option)
|
|||||||
if (option -> universe != &dhcp_universe) {
|
if (option -> universe != &dhcp_universe) {
|
||||||
s = option -> universe -> name;
|
s = option -> universe -> name;
|
||||||
i = 0;
|
i = 0;
|
||||||
} else {
|
} else {
|
||||||
s = option -> name;
|
s = option -> name;
|
||||||
i = 1;
|
i = 1;
|
||||||
}
|
}
|
||||||
@@ -3104,9 +3210,9 @@ void go_daemon ()
|
|||||||
pid = setsid ();
|
pid = setsid ();
|
||||||
|
|
||||||
/* Close standard I/O descriptors. */
|
/* Close standard I/O descriptors. */
|
||||||
close(0);
|
close(0);
|
||||||
close(1);
|
close(1);
|
||||||
close(2);
|
close(2);
|
||||||
|
|
||||||
/* Reopen them on /dev/null. */
|
/* Reopen them on /dev/null. */
|
||||||
open("/dev/null", O_RDWR);
|
open("/dev/null", O_RDWR);
|
||||||
@@ -3115,7 +3221,7 @@ void go_daemon ()
|
|||||||
|
|
||||||
write_client_pid_file ();
|
write_client_pid_file ();
|
||||||
|
|
||||||
chdir("/");
|
chdir("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_client_pid_file ()
|
void write_client_pid_file ()
|
||||||
@@ -3172,7 +3278,7 @@ void client_location_changed ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_release(client)
|
void do_release(client)
|
||||||
struct client_state *client;
|
struct client_state *client;
|
||||||
{
|
{
|
||||||
struct data_string ds;
|
struct data_string ds;
|
||||||
@@ -3209,10 +3315,10 @@ void do_release(client)
|
|||||||
client -> destination = iaddr_broadcast;
|
client -> destination = iaddr_broadcast;
|
||||||
client -> first_sending = cur_time;
|
client -> first_sending = cur_time;
|
||||||
client -> interval = client -> config -> initial_interval;
|
client -> interval = client -> config -> initial_interval;
|
||||||
|
|
||||||
/* Zap the medium list... */
|
/* Zap the medium list... */
|
||||||
client -> medium = (struct string_list *)0;
|
client -> medium = (struct string_list *)0;
|
||||||
|
|
||||||
/* Send out the first and only DHCPRELEASE packet. */
|
/* Send out the first and only DHCPRELEASE packet. */
|
||||||
send_release (client);
|
send_release (client);
|
||||||
|
|
||||||
@@ -3318,8 +3424,8 @@ isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
|
|||||||
ip -> client -> alias);
|
ip -> client -> alias);
|
||||||
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);
|
||||||
|
|
||||||
@@ -3501,7 +3607,7 @@ isc_result_t client_dns_update (struct client_state *client, int addp,
|
|||||||
(struct option_state *)0,
|
(struct option_state *)0,
|
||||||
&global_scope, oc, MDL))
|
&global_scope, oc, MDL))
|
||||||
return ISC_R_SUCCESS;
|
return ISC_R_SUCCESS;
|
||||||
|
|
||||||
/* If we set the "server, please update" flag, or didn't set it
|
/* If we set the "server, please update" flag, or didn't set it
|
||||||
to false, don't do the update. */
|
to false, don't do the update. */
|
||||||
if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
|
if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
|
||||||
@@ -3512,12 +3618,12 @@ isc_result_t client_dns_update (struct client_state *client, int addp,
|
|||||||
(struct option_state *)0,
|
(struct option_state *)0,
|
||||||
&global_scope, oc, MDL))
|
&global_scope, oc, MDL))
|
||||||
return ISC_R_SUCCESS;
|
return ISC_R_SUCCESS;
|
||||||
|
|
||||||
/* If no FQDN option was supplied, don't do the update. */
|
/* If no FQDN option was supplied, don't do the update. */
|
||||||
memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name);
|
memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name);
|
||||||
if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
|
if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
|
||||||
FQDN_FQDN)) ||
|
FQDN_FQDN)) ||
|
||||||
!evaluate_option_cache (&ddns_fwd_name, (struct packet *)0,
|
!evaluate_option_cache (&ddns_fwd_name, (struct packet *)0,
|
||||||
(struct lease *)0, client,
|
(struct lease *)0, client,
|
||||||
client -> sent_options,
|
client -> sent_options,
|
||||||
(struct option_state *)0,
|
(struct option_state *)0,
|
||||||
@@ -3592,7 +3698,7 @@ isc_result_t client_dns_update (struct client_state *client, int addp,
|
|||||||
&ddns_dhcid);
|
&ddns_dhcid);
|
||||||
} else
|
} else
|
||||||
rcode = ISC_R_FAILURE;
|
rcode = ISC_R_FAILURE;
|
||||||
|
|
||||||
data_string_forget (&ddns_fwd_name, MDL);
|
data_string_forget (&ddns_fwd_name, MDL);
|
||||||
data_string_forget (&ddns_dhcid, MDL);
|
data_string_forget (&ddns_dhcid, MDL);
|
||||||
return rcode;
|
return rcode;
|
||||||
|
@@ -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