2
0
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:
Francis Dupont
2008-05-23 13:22:23 +00:00
parent 61220a0091
commit 3dbe22465b
5 changed files with 550 additions and 108 deletions

View File

@@ -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)

View File

@@ -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.

View File

@@ -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;

View File

@@ -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

View File

@@ -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);