mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-09-02 07:15:44 +00:00
merge 17621
This commit is contained in:
@@ -1439,8 +1439,7 @@ parse_client6_lease_statement(struct parse *cfile)
|
||||
|
||||
if (iface == NULL)
|
||||
parse_warn(cfile, "Lease has no interface designation.");
|
||||
|
||||
if (!has_name && (client == NULL)) {
|
||||
else if (!has_name && (client == NULL)) {
|
||||
for (client = iface->client ; client != NULL ;
|
||||
client = client->next) {
|
||||
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 *iaprefix_option = NULL;
|
||||
struct option *oro_option = NULL;
|
||||
struct option *irt_option = NULL;
|
||||
|
||||
static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
|
||||
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,
|
||||
struct iaddr *address);
|
||||
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 do_init6(void *input);
|
||||
void do_info_request6(void *input);
|
||||
void do_confirm6(void *input);
|
||||
void reply_handler(struct packet *packet, 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);
|
||||
static void do_release6(void *input);
|
||||
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 start_renew6(void *input);
|
||||
void start_rebind6(void *input);
|
||||
@@ -92,10 +97,12 @@ static void script_write_params6(struct client_state *client,
|
||||
const char *prefix,
|
||||
struct option_state *options);
|
||||
|
||||
extern int stateless;
|
||||
|
||||
/* The "best" default DUID, since we cannot predict any information
|
||||
* about the system (such as whether or not the hardware addresses are
|
||||
* 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
|
||||
* 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 '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
|
||||
* 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))
|
||||
log_fatal("no memory for default DUID!");
|
||||
duid->data = duid->buffer->data;
|
||||
duid->len = len;
|
||||
|
||||
/* Basic Link Local Address type of DUID. */
|
||||
if (!stateless) {
|
||||
putUShort(duid->buffer->data, DUID_LLT);
|
||||
putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
|
||||
putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
|
||||
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.
|
||||
@@ -217,6 +233,11 @@ dhcpv6_client_assignments(void)
|
||||
&code, 0, MDL))
|
||||
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 */
|
||||
endservent();
|
||||
#endif
|
||||
@@ -1253,8 +1274,9 @@ start_init6(struct client_state *client)
|
||||
client->MRD = 0;
|
||||
|
||||
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
|
||||
* by choosing RAND to be strictly greater than 0.
|
||||
*/
|
||||
@@ -1284,7 +1306,45 @@ start_init6(struct client_state *client)
|
||||
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
|
||||
* a link cycles state we'll eventually want to do this.
|
||||
*/
|
||||
@@ -1529,6 +1589,107 @@ do_init6(void *input)
|
||||
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
|
||||
* 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.");
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
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
|
||||
* event.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
start_bound(struct client_state *client)
|
||||
{
|
||||
struct dhc6_ia *ia, *oldia;
|
||||
@@ -3974,6 +4191,7 @@ do_expire(void *input)
|
||||
* Run client script to unconfigure interface.
|
||||
* Called with reason STOP6 when dhclient -x is run, or with reason
|
||||
* RELEASE6 when server has replied to a Release message.
|
||||
* Stateless is a special case.
|
||||
*/
|
||||
void
|
||||
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_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)
|
||||
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
|
||||
* scope and places them into the sent_options cache. This cache is later
|
||||
* used to populate DHCPv6 output packets with options.
|
||||
|
@@ -75,8 +75,11 @@ int client_env_count=0;
|
||||
int onetry=0;
|
||||
int quiet=1;
|
||||
int nowait=0;
|
||||
int stateless=0;
|
||||
char *mockup_relay = NULL;
|
||||
|
||||
void run_stateless(int exit_mode);
|
||||
|
||||
static void usage PROTO ((void));
|
||||
|
||||
static isc_result_t write_duid(struct data_string *duid);
|
||||
@@ -208,7 +211,7 @@ main(int argc, char **argv) {
|
||||
nowait = 1;
|
||||
} else if (!strcmp (argv [i], "-n")) {
|
||||
/* do not start up any interfaces */
|
||||
interfaces_requested = 1;
|
||||
interfaces_requested = -1;
|
||||
} else if (!strcmp (argv [i], "-w")) {
|
||||
/* do not exit if there are no broadcast interfaces. */
|
||||
persist = 1;
|
||||
@@ -223,6 +226,13 @@ main(int argc, char **argv) {
|
||||
tmp -> next = client_env;
|
||||
client_env = tmp;
|
||||
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")) {
|
||||
quiet = 0;
|
||||
} else if (!strcmp (argv [i], "--version")) {
|
||||
@@ -230,6 +240,8 @@ main(int argc, char **argv) {
|
||||
exit (0);
|
||||
} else if (argv [i][0] == '-') {
|
||||
usage ();
|
||||
} else if (interfaces_requested < 0) {
|
||||
usage ();
|
||||
} else {
|
||||
struct interface_info *tmp = (struct interface_info *)0;
|
||||
status = interface_allocate (&tmp, MDL);
|
||||
@@ -247,7 +259,7 @@ main(int argc, char **argv) {
|
||||
}
|
||||
interface_reference (&interfaces, tmp, MDL);
|
||||
tmp -> flags = INTERFACE_REQUESTED;
|
||||
interfaces_requested = 1;
|
||||
interfaces_requested++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,6 +380,15 @@ main(int argc, char **argv) {
|
||||
|
||||
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_interfaces (DISCOVER_UNCONFIGURED);
|
||||
|
||||
@@ -404,7 +425,7 @@ main(int argc, char **argv) {
|
||||
for (ip = interfaces; ip; ip = ip -> next) {
|
||||
/* If interfaces were specified, don't configure
|
||||
interfaces that weren't specified! */
|
||||
if (interfaces_requested &&
|
||||
if ((interfaces_requested > 0) &&
|
||||
((ip -> flags & (INTERFACE_REQUESTED |
|
||||
INTERFACE_AUTOMATIC)) !=
|
||||
INTERFACE_REQUESTED))
|
||||
@@ -427,7 +448,7 @@ main(int argc, char **argv) {
|
||||
are relevant should be running, so now we once again call
|
||||
discover_interfaces(), and this time ask it to actually set
|
||||
up the interfaces. */
|
||||
discover_interfaces (interfaces_requested
|
||||
discover_interfaces (interfaces_requested != 0
|
||||
? DISCOVER_REQUESTED
|
||||
: DISCOVER_RUNNING);
|
||||
|
||||
@@ -575,7 +596,7 @@ static void usage ()
|
||||
|
||||
log_error ("Usage: dhclient %s %s",
|
||||
#ifdef DHCPv6
|
||||
"[-4|-6] [-1dvrx] [-nw] [-p <port>]",
|
||||
"[-4|-6] [-S1dvrx] [-nw] [-p <port>]",
|
||||
#else /* DHCPv6 */
|
||||
"[-1dvrx] [-nw] [-p <port>]",
|
||||
#endif /* DHCPv6 */
|
||||
@@ -585,6 +606,88 @@ static void usage ()
|
||||
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,
|
||||
const char *s, const char *file, int line)
|
||||
{
|
||||
@@ -1201,8 +1304,11 @@ dhcpv6(struct packet *packet) {
|
||||
/* Screen out nonsensical messages. */
|
||||
switch(packet->dhcpv6_msg_type) {
|
||||
case DHCPV6_ADVERTISE:
|
||||
case DHCPV6_REPLY:
|
||||
case DHCPV6_RECONFIGURE:
|
||||
if (stateless)
|
||||
return;
|
||||
/* Falls through */
|
||||
case DHCPV6_REPLY:
|
||||
log_info("RCV: %s message on %s from %s.",
|
||||
dhcpv6_type_names[packet->dhcpv6_msg_type],
|
||||
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);
|
||||
}
|
||||
|
||||
discover_interfaces (interfaces_requested
|
||||
discover_interfaces (interfaces_requested != 0
|
||||
? DISCOVER_REQUESTED
|
||||
: DISCOVER_RUNNING);
|
||||
|
||||
|
@@ -205,3 +205,9 @@ struct dhcpv6_relay_packet {
|
||||
* when the Unix epoch began.
|
||||
*/
|
||||
#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 dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line);
|
||||
void start_init6(struct client_state *client);
|
||||
void start_info_request6(struct client_state *client);
|
||||
void start_confirm6(struct client_state *client);
|
||||
void start_release6(struct client_state *client);
|
||||
void start_selecting6(struct client_state *client);
|
||||
|
Reference in New Issue
Block a user