diff options
author | Francis Dupont <fdupont@isc.org> | 2008-05-23 13:56:07 +0000 |
---|---|---|
committer | Francis Dupont <fdupont@isc.org> | 2008-05-23 13:56:07 +0000 |
commit | 420d8b3f0cecfc774ce9c46747ed5a2fb1ff8b5c (patch) | |
tree | 2a5159203b72007751b52eba9bffabedea38d901 /client | |
parent | 3dbe22465b8d37681dc59e18c0c0d3807e09069d (diff) | |
download | isc-dhcp-420d8b3f0cecfc774ce9c46747ed5a2fb1ff8b5c.tar.gz |
merge 17500
Diffstat (limited to 'client')
-rw-r--r-- | client/dhc6.c | 1396 | ||||
-rw-r--r-- | client/dhclient.8 | 45 | ||||
-rw-r--r-- | client/dhclient.c | 423 | ||||
-rwxr-xr-x | client/scripts/bsdos | 6 | ||||
-rwxr-xr-x | client/scripts/freebsd | 14 | ||||
-rwxr-xr-x | client/scripts/linux | 12 | ||||
-rwxr-xr-x | client/scripts/netbsd | 6 | ||||
-rw-r--r-- | client/scripts/openbsd | 6 |
8 files changed, 1367 insertions, 541 deletions
diff --git a/client/dhc6.c b/client/dhc6.c index 00f30e61..b8dbdd28 100644 --- a/client/dhc6.c +++ b/client/dhc6.c @@ -28,7 +28,8 @@ struct sockaddr_in6 DHCPv6DestAddr; -/* Option definition structures that are used by the software - declared +/* + * Option definition structures that are used by the software - declared * here once and assigned at startup to save lookups. */ struct option *clientid_option = NULL; @@ -43,7 +44,7 @@ struct option *irt_option = NULL; static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line); -static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia, +static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line); static struct dhc6_addr *dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line); @@ -60,12 +61,15 @@ static isc_result_t dhc6_parse_ia_pd(struct dhc6_ia **pia, static isc_result_t dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet, struct option_state *options); -static isc_result_t dhc6_parse_prefs(struct dhc6_addr **ppref, - struct packet *packet, - struct option_state *options); -static struct dhc6_ia *find_ia_na(struct dhc6_ia *head, const char *id); +static isc_result_t dhc6_parse_prefixes(struct dhc6_addr **ppref, + struct packet *packet, + struct option_state *options); +static struct dhc6_ia *find_ia(struct dhc6_ia *head, + u_int16_t type, const char *id); static struct dhc6_addr *find_addr(struct dhc6_addr *head, struct iaddr *address); +static struct dhc6_addr *find_pref(struct dhc6_addr *head, + struct iaddr *prefix, u_int8_t plen); 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); @@ -77,6 +81,14 @@ static isc_result_t dhc6_add_ia_na(struct client_state *client, struct data_string *packet, struct dhc6_lease *lease, u_int8_t message); +static isc_result_t dhc6_add_ia_ta(struct client_state *client, + struct data_string *packet, + struct dhc6_lease *lease, + u_int8_t message); +static isc_result_t dhc6_add_ia_pd(struct client_state *client, + struct data_string *packet, + struct dhc6_lease *lease, + u_int8_t message); static isc_boolean_t stopping_finished(void); static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst); void do_select6(void *input); @@ -93,13 +105,15 @@ void do_expire(void *input); static void make_client6_options(struct client_state *client, struct option_state **op, struct dhc6_lease *lease, u_int8_t message); -static void script_write_params6(struct client_state *client, +static void script_write_params6(struct client_state *client, const char *prefix, struct option_state *options); +static isc_boolean_t active_prefix(struct client_state *client); 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 * integrated into the motherboard or similar), is the "LLT", link local * plus time, DUID. For real stateless "LL" is better. @@ -128,7 +142,8 @@ form_duid(struct data_string *duid, const char *file, int line) (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf))) log_fatal("Impossible hardware address length at %s:%d.", MDL); - /* 2 bytes for the 'duid type' field. + /* + * 2 bytes for the 'duid type' field. * 2 bytes for the 'htype' field. * (not stateless) 4 bytes for the 'current time'. * enough bytes for the hardware address (note that hw_address has @@ -157,7 +172,8 @@ form_duid(struct data_string *duid, const char *file, int line) } } -/* Assign DHCPv6 port numbers as a client. +/* + * Assign DHCPv6 port numbers as a client. */ void dhcpv6_client_assignments(void) @@ -243,7 +259,8 @@ dhcpv6_client_assignments(void) #endif } -/* Instead of implementing RFC3315 RAND (section 14) as a float "between" +/* + * Instead of implementing RFC3315 RAND (section 14) as a float "between" * -0.1 and 0.1 non-inclusive, we implement it as an integer. * * The result is expected to follow this table: @@ -268,13 +285,15 @@ dhc6_rand(TIME base) TIME range; TIME split; - /* A zero or less timeout is a bad thing...we don't want to + /* + * A zero or less timeout is a bad thing...we don't want to * DHCP-flood anyone. */ if (base <= 0) log_fatal("Impossible condition at %s:%d.", MDL); - /* The first thing we do is count how many random integers we want + /* + * The first thing we do is count how many random integers we want * in either direction (best thought of as the maximum negative * integer, as we will subtract this potentially from a random 0). */ @@ -284,7 +303,8 @@ dhc6_rand(TIME base) if (split == 0) return 0; - /* Then we count the total number of integers in this set. This + /* + * Then we count the total number of integers in this set. This * is twice the number of integers in positive and negative * directions, plus zero (-1, 0, 1 is 3, -2..2 adds 2 to 5, so forth). */ @@ -349,24 +369,27 @@ dhc6_retrans_advance(struct client_state *client) elapsed.tv_usec -= 1000000; } - /* RT for each subsequent message transmission is based on the previous - * value of RT: - * - * RT = 2*RTprev + RAND*RTprev - */ - client->RT += client->RT + dhc6_rand(client->RT); - - /* MRT specifies an upper bound on the value of RT (disregarding the - * randomization added by the use of RAND). If MRT has a value of 0, - * there is no upper limit on the value of RT. Otherwise: - * - * if (RT > MRT) - * RT = MRT + RAND*MRT - */ - if ((client->MRT != 0) && (client->RT > client->MRT)) - client->RT = client->MRT + dhc6_rand(client->MRT); - - /* Further, if there's an MRD, we should wake up upon reaching + /* + * RT for each subsequent message transmission is based on the previous + * value of RT: + * + * RT = 2*RTprev + RAND*RTprev + */ + client->RT += client->RT + dhc6_rand(client->RT); + + /* + * MRT specifies an upper bound on the value of RT (disregarding the + * randomization added by the use of RAND). If MRT has a value of 0, + * there is no upper limit on the value of RT. Otherwise: + * + * if (RT > MRT) + * RT = MRT + RAND*MRT + */ + if ((client->MRT != 0) && (client->RT > client->MRT)) + client->RT = client->MRT + dhc6_rand(client->MRT); + + /* + * Further, if there's an MRD, we should wake up upon reaching * the MRD rather than at some point after it. */ if (client->MRD == 0) { @@ -439,7 +462,8 @@ valid_reply(struct packet *packet, struct client_state *client) return rval; } -/* Create a complete copy of a DHCPv6 lease structure. +/* + * Create a complete copy of a DHCPv6 lease structure. */ static struct dhc6_lease * dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line) @@ -476,7 +500,8 @@ dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line) return copy; } -/* Duplicate an IA structure. +/* + * Duplicate an IA structure. */ static struct dhc6_ia * dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line) @@ -512,7 +537,8 @@ dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line) return copy; } -/* Duplicate an IAADDR or IAPREFIX structure. +/* + * Duplicate an IAADDR or IAPREFIX structure. */ static struct dhc6_addr * dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line) @@ -539,7 +565,8 @@ dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line) return copy; } -/* Form a DHCPv6 lease structure based upon packet contents. Creates and +/* + * Form a DHCPv6 lease structure based upon packet contents. Creates and * populates IA's and any IAADDR/IAPREFIX's they contain. * Parsed options are deleted in order to not save them in the lease file. */ @@ -582,7 +609,8 @@ dhc6_leaseify(struct packet *packet) } delete_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE); - /* Dig into recursive DHCPv6 pockets for IA_NA and contained IAADDR + /* + * Dig into recursive DHCPv6 pockets for IA_NA and contained IAADDR * options. */ if (dhc6_parse_ia_na(&lease->bindings, packet, @@ -591,7 +619,8 @@ dhc6_leaseify(struct packet *packet) dhc6_lease_destroy(&lease, MDL); return NULL; } - /* Dig into recursive DHCPv6 pockets for IA_TA and contained IAADDR + /* + * Dig into recursive DHCPv6 pockets for IA_TA and contained IAADDR * options. */ if (dhc6_parse_ia_ta(&lease->bindings, packet, @@ -600,7 +629,8 @@ dhc6_leaseify(struct packet *packet) dhc6_lease_destroy(&lease, MDL); return NULL; } - /* Dig into recursive DHCPv6 pockets for IA_PD and contained IAPREFIX + /* + * Dig into recursive DHCPv6 pockets for IA_PD and contained IAPREFIX * options. */ if (dhc6_parse_ia_pd(&lease->bindings, packet, @@ -610,7 +640,8 @@ dhc6_leaseify(struct packet *packet) return NULL; } - /* This is last because in the future we may want to make a different + /* + * This is last because in the future we may want to make a different * key based upon additional information from the packet (we may need * to allow multiple leases in one client state per server, but we're * not sure based on what additional keys now). @@ -669,7 +700,8 @@ dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet, log_debug("RCV: | X-- t1 - renew +%u", ia->renew); log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind); - /* RFC3315 section 22.4, discard IA_NA's that + /* + * RFC3315 section 22.4, discard IA_NA's that * have t1 greater than t2, and both not zero. * Since RFC3315 defines this behaviour, it is not * an error - just normal operation. @@ -693,7 +725,7 @@ dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet, if (!option_state_allocate(&ia->options, MDL)) { log_error("Out of memory allocating " - "IA option state."); + "IA_NA option state."); dfree(ia, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; @@ -724,6 +756,8 @@ dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet, } } + while (*pia != NULL) + pia = &(*pia)->next; *pia = ia; pia = &ia->next; } else { @@ -776,7 +810,7 @@ dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet, if (!option_state_allocate(&ia->options, MDL)) { log_error("Out of memory allocating " - "IA option state."); + "IA_TA option state."); dfree(ia, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; @@ -807,6 +841,8 @@ dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet, } } + while (*pia != NULL) + pia = &(*pia)->next; *pia = ia; pia = &ia->next; } else { @@ -857,9 +893,10 @@ dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet, log_debug("RCV: | X-- t1 - renew +%u", ia->renew); log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind); - /* RFC3315 section 22.4, discard IA_PD's that + /* + * RFC3633 section 9, discard IA_PD's that * have t1 greater than t2, and both not zero. - * Since RFC3315 defines this behaviour, it is not + * Since RFC3633 defines this behaviour, it is not * an error - just normal operation. */ if ((ia->renew > 0) && (ia->rebind > 0) && @@ -877,7 +914,7 @@ dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet, if (!option_state_allocate(&ia->options, MDL)) { log_error("Out of memory allocating " - "IA option state."); + "IA_PD option state."); dfree(ia, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; @@ -898,8 +935,9 @@ dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet, data_string_forget(&ds, MDL); if (ia->options != NULL) { - result = dhc6_parse_prefs(&ia->addrs, packet, - ia->options); + result = dhc6_parse_prefixes(&ia->addrs, + packet, + ia->options); if (result != ISC_R_SUCCESS) { option_state_dereference(&ia->options, MDL); @@ -908,6 +946,8 @@ dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet, } } + while (*pia != NULL) + pia = &(*pia)->next; *pia = ia; pia = &ia->next; } else { @@ -959,7 +999,8 @@ dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet, log_debug("RCV: | | | X-- Max lifetime %u.", addr->max_life); - /* RFC 3315 section 22.6 says we must discard + /* + * RFC 3315 section 22.6 says we must discard * addresses whose pref is later than valid. */ if ((addr->preferred_life > addr->max_life)) { @@ -971,7 +1012,8 @@ dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet, continue; } - /* Fortunately this is the last recursion in the + /* + * Fortunately this is the last recursion in the * protocol. */ if (ds.len > 24) { @@ -1019,19 +1061,19 @@ dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet, } static isc_result_t -dhc6_parse_prefs(struct dhc6_addr **ppref, struct packet *packet, - struct option_state *options) +dhc6_parse_prefixes(struct dhc6_addr **ppfx, struct packet *packet, + struct option_state *options) { struct data_string ds; struct option_cache *oc; - struct dhc6_addr *pref; + struct dhc6_addr *pfx; memset(&ds, 0, sizeof(ds)); oc = lookup_option(&dhcpv6_universe, options, D6O_IAPREFIX); for ( ; oc != NULL ; oc = oc->next) { - pref = dmalloc(sizeof(*pref), MDL); - if (pref == NULL) { + pfx = dmalloc(sizeof(*pfx), MDL); + if (pfx == NULL) { log_error("Out of memory allocating " "prefix structure."); return ISC_R_NOMEMORY; @@ -1040,78 +1082,80 @@ dhc6_parse_prefs(struct dhc6_addr **ppref, struct packet *packet, oc, MDL) && (ds.len >= 25)) { - pref->preferred_life = getULong(ds.data); - pref->max_life = getULong(ds.data + 4); - pref->plen = getUChar(ds.data + 8); - pref->address.len = 16; - memcpy(pref->address.iabuf, ds.data + 9, 16); - pref->starts = cur_time; + pfx->preferred_life = getULong(ds.data); + pfx->max_life = getULong(ds.data + 4); + pfx->plen = getUChar(ds.data + 8); + pfx->address.len = 16; + memcpy(pfx->address.iabuf, ds.data + 9, 16); + pfx->starts = cur_time; log_debug("RCV: | | X-- IAPREFIX %s/%d", - piaddr(pref->address), (int)pref->plen); + piaddr(pfx->address), (int)pfx->plen); log_debug("RCV: | | | X-- Preferred lifetime %u.", - pref->preferred_life); + pfx->preferred_life); log_debug("RCV: | | | X-- Max lifetime %u.", - pref->max_life); + pfx->max_life); /* Sanity check over the prefix length */ - if ((pref->plen < 4) || (pref->plen > 128)) { + if ((pfx->plen < 4) || (pfx->plen > 128)) { log_debug("RCV: | | | !-- INVALID prefix " "length, IAPREFIX discarded. " "Check your server configuration."); - dfree(pref, MDL); + dfree(pfx, MDL); data_string_forget(&ds, MDL); continue; } - /* RFC 3315 section 22.6 says we must discard + /* + * RFC 3633 section 10 says we must discard * prefixes whose pref is later than valid. */ - if ((pref->preferred_life > pref->max_life)) { + if ((pfx->preferred_life > pfx->max_life)) { log_debug("RCV: | | | !-- INVALID lifetimes, " "IAPREFIX discarded. Check your " "server configuration."); - dfree(pref, MDL); + dfree(pfx, MDL); data_string_forget(&ds, MDL); continue; } - /* Fortunately this is the last recursion in the + /* + * Fortunately this is the last recursion in the * protocol. */ if (ds.len > 25) { - if (!option_state_allocate(&pref->options, + if (!option_state_allocate(&pfx->options, MDL)) { log_error("Out of memory allocating " "IAPREFIX option state."); - dfree(pref, MDL); + dfree(pfx, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; } - if (!parse_option_buffer(pref->options, + if (!parse_option_buffer(pfx->options, ds.data + 25, ds.len - 25, &dhcpv6_universe)) { log_error("Corrupt IAPREFIX options."); - option_state_dereference(&pref->options, + option_state_dereference(&pfx->options, MDL); - dfree(pref, MDL); + dfree(pfx, MDL); data_string_forget(&ds, MDL); return ISC_R_BADPARSE; } } - if (pref->options != NULL) + if (pfx->options != NULL) log_debug("RCV: | | | X-- " "[Options]"); data_string_forget(&ds, MDL); - *ppref = pref; - ppref = &pref->next; + *ppfx = pfx; + ppfx = &pfx->next; } else { log_error("Invalid IAPREFIX option cache."); - dfree(pref, MDL); + dfree(pfx, MDL); if (ds.len != 0) data_string_forget(&ds, MDL); return ISC_R_UNEXPECTED; @@ -1127,12 +1171,12 @@ void dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line) { struct dhc6_ia *ia, *nia; - struct dhc6_lease *lease; + struct dhc6_lease *lease; if (src == NULL || *src == NULL) { - log_error("Attempt to destroy null lease."); + log_error("Attempt to destroy null lease."); return; - } + } lease = *src; if (lease->server_id.len != 0) @@ -1148,7 +1192,7 @@ dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line) option_state_dereference(&lease->options, file, line); dfree(lease, file, line); - *src = NULL; + *src = NULL; } /* @@ -1159,12 +1203,12 @@ static void dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line) { struct dhc6_addr *addr, *naddr; - struct dhc6_ia *ia; + struct dhc6_ia *ia; if (src == NULL || *src == NULL) { - log_error("Attempt to destroy null IA."); + log_error("Attempt to destroy null IA."); return; - } + } ia = *src; for (addr = ia->addrs ; addr != NULL ; addr = naddr) { @@ -1180,10 +1224,11 @@ dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line) option_state_dereference(&ia->options, file, line); dfree(ia, file, line); - *src = NULL; + *src = NULL; } -/* For a given lease, insert it into the tail of the lease list. Upon +/* + * For a given lease, insert it into the tail of the lease list. Upon * finding a duplicate by server id, remove it and take over its position. */ static void @@ -1205,7 +1250,8 @@ insert_lease(struct dhc6_lease **head, struct dhc6_lease *new) return; } -/* Not really clear what to do here yet. +/* + * Not really clear what to do here yet. */ static int dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease) @@ -1233,9 +1279,7 @@ dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease) } } - /* If this lease contains a requested option, improve its - * score. - */ + /* If this lease contains a requested option, improve its score. */ req = client->config->requested_options; if (req != NULL) { for (i = 0 ; req[i] != NULL ; i++) { @@ -1256,7 +1300,8 @@ dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease) return lease->score; } -/* start_init6() kicks off the process, transmitting a packet and +/* + * start_init6() kicks off the process, transmitting a packet and * scheduling a retransmission event. */ void @@ -1276,7 +1321,7 @@ start_init6(struct client_state *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 * by choosing RAND to be strictly greater than 0. */ @@ -1289,7 +1334,8 @@ start_init6(struct client_state *client) client->v6_handler = init_handler; - /* RFC3315 section 17.1.2 says we MUST start the first packet + /* + * RFC3315 section 17.1.2 says we MUST start the first packet * between 0 and SOL_MAX_DELAY seconds. The good news is * SOL_MAX_DELAY is 1. */ @@ -1306,7 +1352,8 @@ start_init6(struct client_state *client) go_daemon(); } -/* start_info_request6() kicks off the process, transmitting an info +/* + * start_info_request6() kicks off the process, transmitting an info * request packet and scheduling a retransmission event. */ void @@ -1327,7 +1374,8 @@ start_info_request6(struct client_state *client) client->v6_handler = info_request_handler; - /* RFC3315 section 18.1.5 says we MUST start the first packet + /* + * 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. */ @@ -1344,7 +1392,8 @@ start_info_request6(struct client_state *client) go_daemon(); } -/* start_confirm6() kicks off an "init-reboot" version of the process, at +/* + * 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. */ @@ -1354,7 +1403,9 @@ start_confirm6(struct client_state *client) struct timeval tv; /* If there is no active lease, there is nothing to check. */ - if ((client->active_lease == NULL) || client->active_lease->released) { + if ((client->active_lease == NULL) || + !active_prefix(client) || + client->active_lease->released) { start_init6(client); return; } @@ -1372,7 +1423,8 @@ start_confirm6(struct client_state *client) client->v6_handler = reply_handler; - /* RFC3315 section 18.1.2 says we MUST start the first packet + /* + * RFC3315 section 18.1.2 says we MUST start the first packet * between 0 and CNF_MAX_DELAY seconds. The good news is * CNF_MAX_DELAY is 1. */ @@ -1383,10 +1435,16 @@ start_confirm6(struct client_state *client) tv.tv_sec += 1; tv.tv_usec -= 1000000; } - add_timeout(&tv, do_confirm6, client, NULL, NULL); + if (wanted_ia_pd != 0) { + client->state = S_REBINDING; + client->refresh_type = DHCPV6_REBIND; + add_timeout(&tv, do_refresh6, client, NULL, NULL); + } else + add_timeout(&tv, do_confirm6, client, NULL, NULL); } -/* do_init6() marshals and transmits a solicit. +/* + * do_init6() marshals and transmits a solicit. */ void do_init6(void *input) @@ -1399,11 +1457,12 @@ do_init6(void *input) struct data_string addr; struct timeval elapsed, tv; u_int32_t t1, t2; - int idx, len, send_ret; + int i, idx, len, send_ret; client = input; - /* In RFC3315 section 17.1.2, the retransmission timer is + /* + * In RFC3315 section 17.1.2, the retransmission timer is * used as the selecting timer. */ if (client->advertised_leases != NULL) { @@ -1468,99 +1527,321 @@ do_init6(void *input) make_client6_options(client, &client->sent_options, NULL, DHCPV6_SOLICIT); - /* Fetch any configured 'sent' options (includes DUID) in wire format. + /* + * 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); - /* Use a specific handler with rapid-commit. - */ + /* Use a specific handler with rapid-commit. */ if (lookup_option(&dhcpv6_universe, client->sent_options, D6O_RAPID_COMMIT) != NULL) { client->v6_handler = rapid_commit_handler; } - /* Append an IA_NA. */ - /* XXX: maybe the IA_NA('s) should be put into the sent_options - * cache. They'd have to be pulled down as they also contain - * different option caches in the same universe... - */ - memset(&ia, 0, sizeof(ia)); - if (!buffer_allocate(&ia.buffer, 12, MDL)) { - log_error("Unable to allocate memory for IA_NA."); - data_string_forget(&ds, MDL); - return; - } - ia.data = ia.buffer->data; - ia.len = 12; + /* Append IA_NA. */ + for (i = 0; i < wanted_ia_na; i++) { + /* + * XXX: maybe the IA_NA('s) should be put into the sent_options + * cache. They'd have to be pulled down as they also contain + * different option caches in the same universe... + */ + memset(&ia, 0, sizeof(ia)); + if (!buffer_allocate(&ia.buffer, 12, MDL)) { + log_error("Unable to allocate memory for IA_NA."); + data_string_forget(&ds, MDL); + return; + } + ia.data = ia.buffer->data; + ia.len = 12; - /* A simple IAID is the last 4 bytes of the hardware address. */ - if (client->interface->hw_address.hlen > 4) { - idx = client->interface->hw_address.hlen - 4; - len = 4; - } else { - idx = 0; - len = client->interface->hw_address.hlen; - } - memcpy(ia.buffer->data, client->interface->hw_address.hbuf + idx, len); - - t1 = client->config->requested_lease / 2; - t2 = t1 + (t1 / 2); - putULong(ia.buffer->data + 4, t1); - putULong(ia.buffer->data + 8, t2); - - log_debug("XMT: X-- IA_NA %s", print_hex_1(4, ia.buffer->data, 55)); - log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1); - log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2); - - if ((client->active_lease != NULL) && - ((old_ia = find_ia_na(client->active_lease->bindings, - (char *)ia.buffer->data)) != NULL)) { - /* For each address in the old IA, request a binding. */ - memset(&addr, 0, sizeof(addr)); - for (old_addr = old_ia->addrs ; old_addr != NULL ; - old_addr = old_addr->next) { - if (old_addr->address.len != 16) { - log_error("Invalid IPv6 address length %d. " - "Ignoring. (%s:%d)", - old_addr->address.len, MDL); - continue; - } + /* + * A simple IAID is the last 4 bytes + * of the hardware address. + */ + if (client->interface->hw_address.hlen > 4) { + idx = client->interface->hw_address.hlen - 4; + len = 4; + } else { + idx = 0; + len = client->interface->hw_address.hlen; + } + memcpy(ia.buffer->data, + client->interface->hw_address.hbuf + idx, + len); + if (i) + ia.buffer->data[3] += i; + + t1 = client->config->requested_lease / 2; + t2 = t1 + (t1 / 2); + putULong(ia.buffer->data + 4, t1); + putULong(ia.buffer->data + 8, t2); + + log_debug("XMT: X-- IA_NA %s", + print_hex_1(4, ia.buffer->data, 55)); + log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1); + log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2); + + if ((client->active_lease != NULL) && + ((old_ia = find_ia(client->active_lease->bindings, + D6O_IA_NA, + (char *)ia.buffer->data)) != NULL)) { + /* + * For each address in the old IA_NA, + * request a binding. + */ + memset(&addr, 0, sizeof(addr)); + for (old_addr = old_ia->addrs ; old_addr != NULL ; + old_addr = old_addr->next) { + if (old_addr->address.len != 16) { + log_error("Invalid IPv6 address " + "length %d. " + "Ignoring. (%s:%d)", + old_addr->address.len, + MDL); + continue; + } - if (!buffer_allocate(&addr.buffer, 24, MDL)) { - log_error("Unable to allocate memory for " - "IAADDR."); - data_string_forget(&ia, MDL); - data_string_forget(&ds, MDL); - return; + if (!buffer_allocate(&addr.buffer, 24, MDL)) { + log_error("Unable to allocate memory " + "for IAADDR."); + data_string_forget(&ia, MDL); + data_string_forget(&ds, MDL); + return; + } + addr.data = addr.buffer->data; + addr.len = 24; + + memcpy(addr.buffer->data, + old_addr->address.iabuf, + 16); + + t1 = client->config->requested_lease; + t2 = t1 + (t1 / 2); + putULong(addr.buffer->data + 16, t1); + putULong(addr.buffer->data + 20, t2); + + log_debug("XMT: | X-- Request address %s.", + piaddr(old_addr->address)); + log_debug("XMT: | | X-- Request " + "preferred in +%u", + (unsigned)t1); + log_debug("XMT: | | X-- Request valid " + "in +%u", + (unsigned)t2); + + append_option(&ia, &dhcpv6_universe, + iaaddr_option, + &addr); + + data_string_forget(&addr, MDL); } - addr.data = addr.buffer->data; - addr.len = 24; - - memcpy(addr.buffer->data, old_addr->address.iabuf, 16); + } - t1 = client->config->requested_lease; - t2 = t1 + (t1 / 2); - putULong(addr.buffer->data + 16, t1); - putULong(addr.buffer->data + 20, t2); + append_option(&ds, &dhcpv6_universe, ia_na_option, &ia); + data_string_forget(&ia, MDL); + } - log_debug("XMT: | X-- Request address %s.", - piaddr(old_addr->address)); - log_debug("XMT: | | X-- Request preferred in +%u", - (unsigned)t1); - log_debug("XMT: | | X-- Request valid in +%u", - (unsigned)t2); + /* Append IA_TA. */ + for (i = 0; i < wanted_ia_ta; i++) { + /* + * XXX: maybe the IA_TA('s) should be put into the sent_options + * cache. They'd have to be pulled down as they also contain + * different option caches in the same universe... + */ + memset(&ia, 0, sizeof(ia)); + if (!buffer_allocate(&ia.buffer, 4, MDL)) { + log_error("Unable to allocate memory for IA_TA."); + data_string_forget(&ds, MDL); + return; + } + ia.data = ia.buffer->data; + ia.len = 4; - append_option(&ia, &dhcpv6_universe, iaaddr_option, - &addr); + /* + * A simple IAID is the last 4 bytes + * of the hardware address. + */ + if (client->interface->hw_address.hlen > 4) { + idx = client->interface->hw_address.hlen - 4; + len = 4; + } else { + idx = 0; + len = client->interface->hw_address.hlen; + } + memcpy(ia.buffer->data, + client->interface->hw_address.hbuf + idx, + len); + if (i) + ia.buffer->data[3] += i; + + log_debug("XMT: X-- IA_TA %s", + print_hex_1(4, ia.buffer->data, 55)); + + if ((client->active_lease != NULL) && + ((old_ia = find_ia(client->active_lease->bindings, + D6O_IA_TA, + (char *)ia.buffer->data)) != NULL)) { + /* + * For each address in the old IA_TA, + * request a binding. + */ + memset(&addr, 0, sizeof(addr)); + for (old_addr = old_ia->addrs ; old_addr != NULL ; + old_addr = old_addr->next) { + if (old_addr->address.len != 16) { + log_error("Invalid IPv6 address " + "length %d. " + "Ignoring. (%s:%d)", + old_addr->address.len, + MDL); + continue; + } - data_string_forget(&addr, MDL); + if (!buffer_allocate(&addr.buffer, 24, MDL)) { + log_error("Unable to allocate memory " + "for IAADDR."); + data_string_forget(&ia, MDL); + data_string_forget(&ds, MDL); + return; + } + addr.data = addr.buffer->data; + addr.len = 24; + + memcpy(addr.buffer->data, + old_addr->address.iabuf, + 16); + + t1 = client->config->requested_lease; + t2 = t1 + (t1 / 2); + putULong(addr.buffer->data + 16, t1); + putULong(addr.buffer->data + 20, t2); + + log_debug("XMT: | X-- Request address %s.", + piaddr(old_addr->address)); + log_debug("XMT: | | X-- Request " + "preferred in +%u", + (unsigned)t1); + log_debug("XMT: | | X-- Request valid " + "in +%u", + (unsigned)t2); + + append_option(&ia, &dhcpv6_universe, + iaaddr_option, + &addr); + + data_string_forget(&addr, MDL); + } } + + append_option(&ds, &dhcpv6_universe, ia_ta_option, &ia); + data_string_forget(&ia, MDL); } - append_option(&ds, &dhcpv6_universe, ia_na_option, &ia); - data_string_forget(&ia, MDL); + /* Append IA_PD. */ + for (i = 0; i < wanted_ia_pd; i++) { + /* + * XXX: maybe the IA_PD('s) should be put into the sent_options + * cache. They'd have to be pulled down as they also contain + * different option caches in the same universe... + */ + memset(&ia, 0, sizeof(ia)); + if (!buffer_allocate(&ia.buffer, 12, MDL)) { + log_error("Unable to allocate memory for IA_PD."); + data_string_forget(&ds, MDL); + return; + } + ia.data = ia.buffer->data; + ia.len = 12; + + /* + * A simple IAID is the last 4 bytes + * of the hardware address. + */ + if (client->interface->hw_address.hlen > 4) { + idx = client->interface->hw_address.hlen - 4; + len = 4; + } else { + idx = 0; + len = client->interface->hw_address.hlen; + } + memcpy(ia.buffer->data, + client->interface->hw_address.hbuf + idx, + len); + if (i) + ia.buffer->data[3] += i; + + t1 = client->config->requested_lease / 2; + t2 = t1 + (t1 / 2); + putULong(ia.buffer->data + 4, t1); + putULong(ia.buffer->data + 8, t2); + + log_debug("XMT: X-- IA_PD %s", + print_hex_1(4, ia.buffer->data, 55)); + log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1); + log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2); + + if ((client->active_lease != NULL) && + ((old_ia = find_ia(client->active_lease->bindings, + D6O_IA_PD, + (char *)ia.buffer->data)) != NULL)) { + /* + * For each prefix in the old IA_PD, + * request a binding. + */ + memset(&addr, 0, sizeof(addr)); + for (old_addr = old_ia->addrs ; old_addr != NULL ; + old_addr = old_addr->next) { + if (old_addr->address.len != 16) { + log_error("Invalid IPv6 prefix, " + "Ignoring. (%s:%d)", + MDL); + continue; + } + + if (!buffer_allocate(&addr.buffer, 25, MDL)) { + log_error("Unable to allocate memory " + "for IAPREFIX."); + data_string_forget(&ia, MDL); + data_string_forget(&ds, MDL); + return; + } + addr.data = addr.buffer->data; + addr.len = 25; + + t1 = client->config->requested_lease; + t2 = t1 + (t1 / 2); + putULong(addr.buffer->data, t1); + putULong(addr.buffer->data + 4, t2); + + putUChar(addr.buffer->data + 8, + old_addr->plen); + memcpy(addr.buffer->data + 9, + old_addr->address.iabuf, + 16); + + log_debug("XMT: | X-- Request prefix %s/%u.", + piaddr(old_addr->address), + (unsigned) old_addr->plen); + log_debug("XMT: | | X-- Request " + "preferred in +%u", + (unsigned)t1); + log_debug("XMT: | | X-- Request valid " + "in +%u", + (unsigned)t2); + + append_option(&ia, &dhcpv6_universe, + iaprefix_option, + &addr); + + data_string_forget(&addr, MDL); + } + } + + append_option(&ds, &dhcpv6_universe, ia_pd_option, &ia); + data_string_forget(&ia, MDL); + } /* Transmit and wait. */ @@ -1786,7 +2067,14 @@ do_confirm6(void *input) &dhcpv6_universe); /* Append IA's. */ - if (dhc6_add_ia_na(client, &ds, client->active_lease, + if (wanted_ia_na && + dhc6_add_ia_na(client, &ds, client->active_lease, + DHCPV6_CONFIRM) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + return; + } + if (wanted_ia_ta && + dhc6_add_ia_ta(client, &ds, client->active_lease, DHCPV6_CONFIRM) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; @@ -1825,19 +2113,19 @@ do_confirm6(void *input) void start_release6(struct client_state *client) { - /* Cancel any pending transmissions */ + /* Cancel any pending transmissions */ cancel_timeout(do_confirm6, client); cancel_timeout(do_select6, client); cancel_timeout(do_refresh6, client); cancel_timeout(do_release6, client); - client->state = S_STOPPED; + client->state = S_STOPPED; - /* - * It is written: "The client MUST NOT use any of the addresses it - * is releasing as the source address in the Release message or in - * any subsequently transmitted message." So unconfigure now. - */ - unconfigure6(client, "RELEASE6"); + /* + * It is written: "The client MUST NOT use any of the addresses it + * is releasing as the source address in the Release message or in + * any subsequently transmitted message." So unconfigure now. + */ + unconfigure6(client, "RELEASE6"); /* Note this in the lease file. */ if (client->active_lease == NULL) @@ -1869,7 +2157,7 @@ do_release6(void *input) client = input; - if (client->active_lease == NULL) + if ((client->active_lease == NULL) || !active_prefix(client)) return; if ((client->MRC != 0) && (client->txcount > client->MRC)) { @@ -1908,8 +2196,15 @@ do_release6(void *input) client->sent_options, &global_scope, &dhcpv6_universe); - /* Append IA's. */ - if (dhc6_add_ia_na(client, &ds, client->active_lease, + /* Append IA's (but don't release temporary addresses). */ + if (wanted_ia_na && + dhc6_add_ia_na(client, &ds, client->active_lease, + DHCPV6_RELEASE) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + goto release_done; + } + if (wanted_ia_pd && + dhc6_add_ia_pd(client, &ds, client->active_lease, DHCPV6_RELEASE) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); goto release_done; @@ -1980,6 +2275,10 @@ status_log(int code, const char *scope, const char *additional, int len) msg = "UseMulticast"; break; + case STATUS_NoPrefixAvail: + msg = "NoPrefixAvail"; + break; + default: msg = "UNKNOWN"; break; @@ -1987,8 +2286,8 @@ status_log(int code, const char *scope, const char *additional, int len) if (len > 0) log_info("%s status code %s: %s", scope, msg, - print_hex_1(len, - (const unsigned char *)additional, 50)); + print_hex_1(len, + (const unsigned char *)additional, 50)); else log_info("%s status code %s.", scope, msg); } @@ -2089,7 +2388,6 @@ dhc6_check_advertise(struct dhc6_lease *lease) for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { switch (ia->ia_type) { case D6O_IA_NA: - default: scope = "IA_NA"; break; case D6O_IA_TA: @@ -2098,6 +2396,9 @@ dhc6_check_advertise(struct dhc6_lease *lease) case D6O_IA_PD: scope = "IA_PD"; break; + default: + log_error("dhc6_check_advertise: no type."); + return ISC_R_FAILURE; } rval = dhc6_check_status(rval, ia->options, scope, &code); @@ -2197,6 +2498,7 @@ dhc6_select_action(struct client_state *client, isc_result_t *rvalp, * servers. */ case STATUS_NoAddrsAvail: + case STATUS_NoPrefixAvail: if (client->state == S_REBOOTING) return ISC_FALSE; @@ -2345,6 +2647,7 @@ dhc6_reply_action(struct client_state *client, isc_result_t *rvalp, * server." */ case STATUS_NoAddrsAvail: + case STATUS_NoPrefixAvail: /* Head back to init, keeping any active bindings (!). */ start_init6(client); break; @@ -2407,6 +2710,7 @@ dhc6_stop_action(struct client_state *client, isc_result_t *rvalp, /* Should not happen */ case STATUS_NoAddrsAvail: + case STATUS_NoPrefixAvail: break; /* Give up on it */ @@ -2483,7 +2787,6 @@ dhc6_check_reply(struct client_state *client, struct dhc6_lease *new) for (ia = new->bindings ; ia != NULL ; ia = ia->next) { switch (ia->ia_type) { case D6O_IA_NA: - default: scope = "IA_NA"; break; case D6O_IA_TA: @@ -2492,6 +2795,9 @@ dhc6_check_reply(struct client_state *client, struct dhc6_lease *new) case D6O_IA_PD: scope = "IA_PD"; break; + default: + log_error("dhc6_check_reply: no type."); + return ISC_R_INVALIDARG; } rval = dhc6_check_status(rval, ia->options, scope, &code); @@ -3032,7 +3338,20 @@ do_select6(void *input) &dhcpv6_universe); /* Now append any IA's, and within them any IAADDR/IAPREFIXs. */ - if (dhc6_add_ia_na(client, &ds, lease, + if (wanted_ia_na && + dhc6_add_ia_na(client, &ds, lease, + DHCPV6_REQUEST) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + return; + } + if (wanted_ia_ta && + dhc6_add_ia_ta(client, &ds, lease, + DHCPV6_REQUEST) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + return; + } + if (wanted_ia_pd && + dhc6_add_ia_pd(client, &ds, lease, DHCPV6_REQUEST) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; @@ -3080,8 +3399,8 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet, memset(&iads, 0, sizeof(iads)); memset(&addrds, 0, sizeof(addrds)); for (ia = lease->bindings; - ia != NULL && rval == ISC_R_SUCCESS; - ia = ia->next) { + ia != NULL && rval == ISC_R_SUCCESS; + ia = ia->next) { if (ia->ia_type != D6O_IA_NA) continue; @@ -3096,43 +3415,43 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet, iads.data = iads.buffer->data; iads.len = 12; - switch (message) { - case DHCPV6_REQUEST: - case DHCPV6_RENEW: - case DHCPV6_REBIND: - - t1 = client->config->requested_lease / 2; - t2 = t1 + (t1 / 2); + switch (message) { + case DHCPV6_REQUEST: + case DHCPV6_RENEW: + case DHCPV6_REBIND: + + t1 = client->config->requested_lease / 2; + t2 = t1 + (t1 / 2); #if MAX_TIME > 0xffffffff - if (t1 > 0xffffffff) - t1 = 0xffffffff; - if (t2 > 0xffffffff) - t2 = 0xffffffff; + if (t1 > 0xffffffff) + t1 = 0xffffffff; + if (t2 > 0xffffffff) + t2 = 0xffffffff; #endif - putULong(iads.buffer->data + 4, t1); - putULong(iads.buffer->data + 8, t2); - - log_debug("XMT: X-- IA_NA %s", - print_hex_1(4, iads.data, 59)); - log_debug("XMT: | X-- Requested renew +%u", - (unsigned) t1); - log_debug("XMT: | X-- Requested rebind +%u", - (unsigned) t2); - break; - - case DHCPV6_CONFIRM: - case DHCPV6_RELEASE: - case DHCPV6_DECLINE: - /* Set t1 and t2 to zero; server will ignore them */ - memset(iads.buffer->data + 4, 0, 8); - log_debug("XMT: X-- IA_NA %s", - print_hex_1(4, iads.buffer->data, 55)); - - break; - - default: - log_fatal("Impossible condition at %s:%d.", MDL); - } + putULong(iads.buffer->data + 4, t1); + putULong(iads.buffer->data + 8, t2); + + log_debug("XMT: X-- IA_NA %s", + print_hex_1(4, iads.data, 59)); + log_debug("XMT: | X-- Requested renew +%u", + (unsigned) t1); + log_debug("XMT: | X-- Requested rebind +%u", + (unsigned) t2); + break; + + case DHCPV6_CONFIRM: + case DHCPV6_RELEASE: + case DHCPV6_DECLINE: + /* Set t1 and t2 to zero; server will ignore them */ + memset(iads.buffer->data + 4, 0, 8); + log_debug("XMT: X-- IA_NA %s", + print_hex_1(4, iads.buffer->data, 55)); + + break; + + default: + log_fatal("Impossible condition at %s:%d.", MDL); + } for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { /* @@ -3163,61 +3482,61 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet, /* Copy the address into the packet buffer. */ memcpy(addrds.buffer->data, addr->address.iabuf, 16); - /* Copy in additional information as appropriate */ - switch (message) { - case DHCPV6_REQUEST: - case DHCPV6_RENEW: - case DHCPV6_REBIND: - t1 = client->config->requested_lease; - t2 = t1 + 300; - putULong(addrds.buffer->data + 16, t1); - putULong(addrds.buffer->data + 20, t2); - - log_debug("XMT: | | X-- IAADDR %s", - piaddr(addr->address)); - log_debug("XMT: | | | X-- Preferred " - "lifetime +%u", (unsigned)t1); - log_debug("XMT: | | | X-- Max lifetime +%u", - (unsigned)t2); - - break; - - case DHCPV6_CONFIRM: - /* - * Set preferred and max life to zero, - * per 17.1.3. - */ - memset(addrds.buffer->data + 16, 0, 8); - log_debug("XMT: | X-- Confirm Address %s", - piaddr(addr->address)); - break; - - case DHCPV6_RELEASE: - /* Preferred and max life are irrelevant */ - memset(addrds.buffer->data + 16, 0, 8); - log_debug("XMT: | X-- Release Address %s", - piaddr(addr->address)); - break; - - case DHCPV6_DECLINE: - /* Preferred and max life are irrelevant */ - memset(addrds.buffer->data + 16, 0, 8); - log_debug("XMT: | X-- Decline Address %s", - piaddr(addr->address)); - break; - - default: - log_fatal("Impossible condition at %s:%d.", - MDL); - } + /* Copy in additional information as appropriate */ + switch (message) { + case DHCPV6_REQUEST: + case DHCPV6_RENEW: + case DHCPV6_REBIND: + t1 = client->config->requested_lease; + t2 = t1 + 300; + putULong(addrds.buffer->data + 16, t1); + putULong(addrds.buffer->data + 20, t2); + + log_debug("XMT: | | X-- IAADDR %s", + piaddr(addr->address)); + log_debug("XMT: | | | X-- Preferred " + "lifetime +%u", (unsigned)t1); + log_debug("XMT: | | | X-- Max lifetime +%u", + (unsigned)t2); + + break; + + case DHCPV6_CONFIRM: + /* + * Set preferred and max life to zero, + * per 17.1.3. + */ + memset(addrds.buffer->data + 16, 0, 8); + log_debug("XMT: | X-- Confirm Address %s", + piaddr(addr->address)); + break; + + case DHCPV6_RELEASE: + /* Preferred and max life are irrelevant */ + memset(addrds.buffer->data + 16, 0, 8); + log_debug("XMT: | X-- Release Address %s", + piaddr(addr->address)); + break; + + case DHCPV6_DECLINE: + /* Preferred and max life are irrelevant */ + memset(addrds.buffer->data + 16, 0, 8); + log_debug("XMT: | X-- Decline Address %s", + piaddr(addr->address)); + break; + + default: + log_fatal("Impossible condition at %s:%d.", + MDL); + } append_option(&iads, &dhcpv6_universe, iaaddr_option, - &addrds); + &addrds); data_string_forget(&addrds, MDL); } /* - * It doesn't make sense to make a request without an + * It doesn't make sense to make a request without an * address. */ if (ia->addrs == NULL) { @@ -3232,7 +3551,301 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet, data_string_forget(&iads, MDL); } - return rval; + return rval; +} + +/* For each IA_TA in the lease, for each address in the IA_TA, + * append that information onto the packet-so-far. + */ +static isc_result_t +dhc6_add_ia_ta(struct client_state *client, struct data_string *packet, + struct dhc6_lease *lease, u_int8_t message) +{ + struct data_string iads; + struct data_string addrds; + struct dhc6_addr *addr; + struct dhc6_ia *ia; + isc_result_t rval = ISC_R_SUCCESS; + TIME t1, t2; + + memset(&iads, 0, sizeof(iads)); + memset(&addrds, 0, sizeof(addrds)); + for (ia = lease->bindings; + ia != NULL && rval == ISC_R_SUCCESS; + ia = ia->next) { + if (ia->ia_type != D6O_IA_TA) + continue; + + if (!buffer_allocate(&iads.buffer, 4, MDL)) { + log_error("Unable to allocate memory for IA_TA."); + rval = ISC_R_NOMEMORY; + break; + } + + /* Copy the IAID into the packet buffer. */ + memcpy(iads.buffer->data, ia->iaid, 4); + iads.data = iads.buffer->data; + iads.len = 4; + + log_debug("XMT: X-- IA_TA %s", + print_hex_1(4, iads.buffer->data, 55)); + + for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { + /* + * Do not confirm expired addresses, do not request + * expired addresses (but we keep them around for + * solicit). + */ + if (addr->flags & DHC6_ADDR_EXPIRED) + continue; + + if (addr->address.len != 16) { + log_error("Illegal IPv6 address length (%d), " + "ignoring. (%s:%d)", + addr->address.len, MDL); + continue; + } + + if (!buffer_allocate(&addrds.buffer, 24, MDL)) { + log_error("Unable to allocate memory for " + "IAADDR."); + rval = ISC_R_NOMEMORY; + break; + } + + addrds.data = addrds.buffer->data; + addrds.len = 24; + + /* Copy the address into the packet buffer. */ + memcpy(addrds.buffer->data, addr->address.iabuf, 16); + + /* Copy in additional information as appropriate */ + switch (message) { + case DHCPV6_REQUEST: + case DHCPV6_RENEW: + case DHCPV6_REBIND: + t1 = client->config->requested_lease; + t2 = t1 + 300; + putULong(addrds.buffer->data + 16, t1); + putULong(addrds.buffer->data + 20, t2); + + log_debug("XMT: | | X-- IAADDR %s", + piaddr(addr->address)); + log_debug("XMT: | | | X-- Preferred " + "lifetime +%u", (unsigned)t1); + log_debug("XMT: | | | X-- Max lifetime +%u", + (unsigned)t2); + + break; + + case DHCPV6_CONFIRM: + /* + * Set preferred and max life to zero, + * per 17.1.3. + */ + memset(addrds.buffer->data + 16, 0, 8); + log_debug("XMT: | X-- Confirm Address %s", + piaddr(addr->address)); + break; + + case DHCPV6_RELEASE: + /* Preferred and max life are irrelevant */ + memset(addrds.buffer->data + 16, 0, 8); + log_debug("XMT: | X-- Release Address %s", + piaddr(addr->address)); + break; + + default: + log_fatal("Impossible condition at %s:%d.", + MDL); + } + + append_option(&iads, &dhcpv6_universe, iaaddr_option, + &addrds); + data_string_forget(&addrds, MDL); + } + + /* + * It doesn't make sense to make a request without an + * address. + */ + if (ia->addrs == NULL) { + log_debug("!!!: V IA_TA has no IAADDRs - removed."); + rval = ISC_R_FAILURE; + } else if (rval == ISC_R_SUCCESS) { + log_debug("XMT: V IA_TA appended."); + append_option(packet, &dhcpv6_universe, ia_ta_option, + &iads); + } + + data_string_forget(&iads, MDL); + } + + return rval; +} + +/* For each IA_PD in the lease, for each prefix in the IA_PD, + * append that information onto the packet-so-far. + */ +static isc_result_t +dhc6_add_ia_pd(struct client_state *client, struct data_string *packet, + struct dhc6_lease *lease, u_int8_t message) +{ + struct data_string iads; + struct data_string prefds; + struct dhc6_addr *pref; + struct dhc6_ia *ia; + isc_result_t rval = ISC_R_SUCCESS; + TIME t1, t2; + + memset(&iads, 0, sizeof(iads)); + memset(&prefds, 0, sizeof(prefds)); + for (ia = lease->bindings; + ia != NULL && rval == ISC_R_SUCCESS; + ia = ia->next) { + if (ia->ia_type != D6O_IA_PD) + continue; + + if (!buffer_allocate(&iads.buffer, 12, MDL)) { + log_error("Unable to allocate memory for IA_PD."); + rval = ISC_R_NOMEMORY; + break; + } + + /* Copy the IAID into the packet buffer. */ + memcpy(iads.buffer->data, ia->iaid, 4); + iads.data = iads.buffer->data; + iads.len = 12; + + switch (message) { + case DHCPV6_REQUEST: + case DHCPV6_RENEW: + case DHCPV6_REBIND: + + t1 = client->config->requested_lease / 2; + t2 = t1 + (t1 / 2); +#if MAX_TIME > 0xffffffff + if (t1 > 0xffffffff) + t1 = 0xffffffff; + if (t2 > 0xffffffff) + t2 = 0xffffffff; +#endif + putULong(iads.buffer->data + 4, t1); + putULong(iads.buffer->data + 8, t2); + + log_debug("XMT: X-- IA_PD %s", + print_hex_1(4, iads.data, 59)); + log_debug("XMT: | X-- Requested renew +%u", + (unsigned) t1); + log_debug("XMT: | X-- Requested rebind +%u", + (unsigned) t2); + break; + + case DHCPV6_RELEASE: + /* Set t1 and t2 to zero; server will ignore them */ + memset(iads.buffer->data + 4, 0, 8); + log_debug("XMT: X-- IA_PD %s", + print_hex_1(4, iads.buffer->data, 55)); + + break; + + default: + log_fatal("Impossible condition at %s:%d.", MDL); + } + + for (pref = ia->addrs ; pref != NULL ; pref = pref->next) { + /* + * Do not confirm expired prefixes, do not request + * expired prefixes (but we keep them around for + * solicit). + */ + if (pref->flags & DHC6_ADDR_EXPIRED) + continue; + + if (pref->address.len != 16) { + log_error("Illegal IPv6 prefix " + "ignoring. (%s:%d)", + MDL); + continue; + } + + if (pref->plen == 0) { + log_info("Null IPv6 prefix, " + "ignoring. (%s:%d)", + MDL); + } + + if (!buffer_allocate(&prefds.buffer, 25, MDL)) { + log_error("Unable to allocate memory for " + "IAPREFIX."); + rval = ISC_R_NOMEMORY; + break; + } + + prefds.data = prefds.buffer->data; + prefds.len = 25; + + /* Copy the prefix into the packet buffer. */ + putUChar(prefds.buffer->data + 8, pref->plen); + memcpy(prefds.buffer->data + 9, + pref->address.iabuf, + 16); + + /* Copy in additional information as appropriate */ + switch (message) { + case DHCPV6_REQUEST: + case DHCPV6_RENEW: + case DHCPV6_REBIND: + t1 = client->config->requested_lease; + t2 = t1 + 300; + putULong(prefds.buffer->data, t1); + putULong(prefds.buffer->data + 4, t2); + + log_debug("XMT: | | X-- IAPREFIX %s/%u", + piaddr(pref->address), + (unsigned) pref->plen); + log_debug("XMT: | | | X-- Preferred " + "lifetime +%u", (unsigned)t1); + log_debug("XMT: | | | X-- Max lifetime +%u", + (unsigned)t2); + + break; + + case DHCPV6_RELEASE: + /* Preferred and max life are irrelevant */ + memset(prefds.buffer->data, 0, 8); + log_debug("XMT: | X-- Release Prefix %s/%u", + piaddr(pref->address), + (unsigned) pref->plen); + break; + + default: + log_fatal("Impossible condition at %s:%d.", + MDL); + } + + append_option(&iads, &dhcpv6_universe, + iaprefix_option, &prefds); + data_string_forget(&prefds, MDL); + } + + /* + * It doesn't make sense to make a request without an + * address. + */ + if (ia->addrs == NULL) { + log_debug("!!!: V IA_PD has no IAPREFIXs - removed."); + rval = ISC_R_FAILURE; + } else if (rval == ISC_R_SUCCESS) { + log_debug("XMT: V IA_PD appended."); + append_option(packet, &dhcpv6_universe, + ia_pd_option, &iads); + } + + data_string_forget(&iads, MDL); + } + + return rval; } /* stopping_finished() checks if there is a remaining work to do. @@ -3299,18 +3912,18 @@ reply_handler(struct packet *packet, struct client_state *client) cancel_timeout(do_refresh6, client); cancel_timeout(do_release6, client); - /* If this is in response to a Release/Decline, clean up and return. */ + /* If this is in response to a Release/Decline, clean up and return. */ if (client->state == S_STOPPED) { if (client->active_lease == NULL) return; - dhc6_lease_destroy(&client->active_lease, MDL); - client->active_lease = NULL; + dhc6_lease_destroy(&client->active_lease, MDL); + client->active_lease = NULL; /* We should never wait for nothing!? */ if (stopping_finished()) exit(0); return; - } + } /* Action was taken, so now that we've torn down our scheduled * retransmissions, return. @@ -3392,12 +4005,24 @@ dhc6_marshall_values(const char *prefix, struct client_state *client, /* addr fields. */ if (addr != NULL) { - /* Current practice is that all subnets are /64's, but - * some suspect this may not be permanent. - */ - client_envadd(client, prefix, "ip6_prefixlen", "%d", 64); - client_envadd(client, prefix, "ip6_address", "%s", - piaddr(addr->address)); + if ((ia != NULL) && (ia->ia_type == D6O_IA_PD)) { + client_envadd(client, prefix, + "ip6_prefix", "%s/%u", + piaddr(addr->address), + (unsigned) addr->plen); + } else { + /* Current practice is that all subnets are /64's, but + * some suspect this may not be permanent. + */ + client_envadd(client, prefix, "ip6_prefixlen", + "%d", 64); + client_envadd(client, prefix, "ip6_address", + "%s", piaddr(addr->address)); + } + if ((ia != NULL) && (ia->ia_type == D6O_IA_TA)) { + client_envadd(client, prefix, + "ip6_type", "temporary"); + } client_envadd(client, prefix, "life_starts", "%d", (int)(addr->starts)); client_envadd(client, prefix, "preferred_life", "%d", @@ -3444,9 +4069,6 @@ dhc6_check_times(struct client_state *client) for(ia = lease->bindings ; ia != NULL ; ia = ia->next) { TIME this_ia_lo_expire, this_ia_hi_expire, use_expire; - if (ia->ia_type != D6O_IA_NA) - continue; - this_ia_lo_expire = MAX_TIME; this_ia_hi_expire = 0; @@ -3496,26 +4118,31 @@ dhc6_check_times(struct client_state *client) else use_expire /= 2; - if (ia->renew == 0) { - tmp = ia->starts + use_expire; - } else if(ia->renew == 0xffffffff) - tmp = MAX_TIME; - else - tmp = ia->starts + ia->renew; + /* Don't renew/rebind temporary addresses. */ + if (ia->ia_type != D6O_IA_TA) { + + if (ia->renew == 0) { + tmp = ia->starts + use_expire; + } else if (ia->renew == 0xffffffff) + tmp = MAX_TIME; + else + tmp = ia->starts + ia->renew; - if (tmp < renew) - renew = tmp; + if (tmp < renew) + renew = tmp; - if (ia->rebind == 0) { - /* Set rebind to 3/4 expiration interval. */ - tmp = ia->starts + use_expire + (use_expire / 2); - } else if (ia->renew == 0xffffffff) - tmp = MAX_TIME; - else - tmp = ia->starts + ia->rebind; + if (ia->rebind == 0) { + /* Set rebind to 3/4 expiration interval. */ + tmp = ia->starts; + tmp += use_expire + (use_expire / 2); + } else if (ia->renew == 0xffffffff) + tmp = MAX_TIME; + else + tmp = ia->starts + ia->rebind; - if (tmp < rebind) - rebind = tmp; + if (tmp < rebind) + rebind = tmp; + } /* * Return expiration ranges to EPOCH relative for event @@ -3616,14 +4243,14 @@ dhc6_check_times(struct client_state *client) } } -/* In a given IA chain, find the IA with the same 'iaid'. */ +/* In a given IA chain, find the IA with the same type and 'iaid'. */ static struct dhc6_ia * -find_ia_na(struct dhc6_ia *head, const char *id) +find_ia(struct dhc6_ia *head, u_int16_t type, const char *id) { struct dhc6_ia *ia; for (ia = head ; ia != NULL ; ia = ia->next) { - if (ia->ia_type != D6O_IA_NA) + if (ia->ia_type != type) continue; if (memcmp(ia->iaid, id, 4) == 0) return ia; @@ -3648,6 +4275,23 @@ find_addr(struct dhc6_addr *head, struct iaddr *address) return NULL; } +/* In a given prefix chain, find a matching prefix. */ +static struct dhc6_addr * +find_pref(struct dhc6_addr *head, struct iaddr *prefix, u_int8_t plen) +{ + struct dhc6_addr *pref; + + for (pref = head ; pref != NULL ; pref = pref->next) { + if ((pref->address.len == prefix->len) && + (pref->plen == plen) && + (memcmp(pref->address.iabuf, prefix->iabuf, + prefix->len) == 0)) + return pref; + } + + return NULL; +} + /* Merge the bindings from the source lease into the destination lease * structure, where they are missing. We have to copy the stateful * objects rather than move them over, because later code needs to be @@ -3664,9 +4308,7 @@ dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst) return; for (sia = src->bindings ; sia != NULL ; sia = sia->next) { - if (sia->ia_type != D6O_IA_NA) - continue; - dia = find_ia_na(dst->bindings, (char *)sia->iaid); + dia = find_ia(dst->bindings, sia->ia_type, (char *)sia->iaid); if (dia == NULL) { tia = dhc6_dup_ia(sia, MDL); @@ -3683,8 +4325,13 @@ dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst) } else { for (saddr = sia->addrs ; saddr != NULL ; saddr = saddr->next) { - daddr = find_addr(dia->addrs, - &saddr->address); + if (sia->ia_type != D6O_IA_PD) + daddr = find_addr(dia->addrs, + &saddr->address); + else + daddr = find_pref(dia->addrs, + &saddr->address, + saddr->plen); if (daddr == NULL) { taddr = dhc6_dup_addr(saddr, MDL); @@ -3765,22 +4412,26 @@ start_bound(struct client_state *client) oldia = NULL; for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { - if (ia->ia_type != D6O_IA_NA) - continue; - if (old != NULL) - oldia = find_ia_na(old->bindings, (char *)ia->iaid); + oldia = find_ia(old->bindings, + ia->ia_type, + (char *)ia->iaid); else oldia = NULL; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { - if (oldia != NULL) - oldaddr = find_addr(oldia->addrs, - &addr->address); - else + if (oldia != NULL) { + if (ia->ia_type != D6O_IA_PD) + oldaddr = find_addr(oldia->addrs, + &addr->address); + else + oldaddr = find_pref(oldia->addrs, + &addr->address, + addr->plen); + } else oldaddr = NULL; - if (oldaddr == NULL) + if ((oldaddr == NULL) && (ia->ia_type == D6O_IA_NA)) dhclient_schedule_updates(client, &addr->address, dns_update_offset++); @@ -3896,6 +4547,7 @@ do_refresh6(void *input) int send_ret; client = (struct client_state *)input; + memset(&ds, 0, sizeof(ds)); lease = client->active_lease; if (lease == NULL) { @@ -3942,7 +4594,7 @@ do_refresh6(void *input) */ oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST); if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL, - lease->options, NULL, &global_scope, + lease->options, NULL, &global_scope, oc, MDL)) { if (ds.len < 16) { log_error("Invalid unicast option length %d.", ds.len); @@ -3999,8 +4651,15 @@ do_refresh6(void *input) client->sent_options, &global_scope, &dhcpv6_universe); - /* Append IA's */ - if (dhc6_add_ia_na(client, &ds, lease, + /* Append IA's */ + if (wanted_ia_na && + dhc6_add_ia_na(client, &ds, lease, + client->refresh_type) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + return; + } + if (wanted_ia_pd && + dhc6_add_ia_pd(client, &ds, lease, client->refresh_type) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; @@ -4086,8 +4745,6 @@ do_depref(void *input) return; for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { - if (ia->ia_type != D6O_IA_NA) - continue; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if (addr->flags & DHC6_ADDR_DEPREFFED) continue; @@ -4098,16 +4755,19 @@ do_depref(void *input) ia, addr); script_go(client); - log_info("PRC: Address %s depreferred.", - print_hex_1(addr->address.len, - addr->address.iabuf, - 50)); - - addr->flags |= DHC6_ADDR_DEPREFFED; + if (ia->ia_type != D6O_IA_PD) + log_info("PRC: Address %s depreferred.", + piaddr(addr->address)); + else + log_info("PRC: Prefix %s/%u depreferred.", + piaddr(addr->address), + (unsigned) addr->plen); + /* Remove DDNS bindings at depref time. */ - if (client->config->do_forward_update) + if ((ia->ia_type == D6O_IA_NA) && + client->config->do_forward_update) client_dns_update(client, 0, 0, &addr->address); } @@ -4136,8 +4796,6 @@ do_expire(void *input) return; for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { - if (ia->ia_type != D6O_IA_NA) - continue; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if (addr->flags & DHC6_ADDR_EXPIRED) continue; @@ -4150,16 +4808,20 @@ do_expire(void *input) addr->flags |= DHC6_ADDR_EXPIRED; - log_info("PRC: Address %s expired.", - print_hex_1(addr->address.len, - addr->address.iabuf, - 50)); + if (ia->ia_type != D6O_IA_PD) + log_info("PRC: Address %s expired.", + piaddr(addr->address)); + else + log_info("PRC: Prefix %s/%u expired.", + piaddr(addr->address), + (unsigned) addr->plen); /* We remove DNS records at depref time, but * it is possible that we might get here * without depreffing. */ - if (client->config->do_forward_update && + if ((ia->ia_type == D6O_IA_NA) && + client->config->do_forward_update && !(addr->flags & DHC6_ADDR_DEPREFFED)) client_dns_update(client, 0, 0, &addr->address); @@ -4212,16 +4874,17 @@ unconfigure6(struct client_state *client, const char *reason) return; for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) { - if (ia->ia_type != D6O_IA_NA) + if (ia->ia_type == D6O_IA_TA) continue; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { script_init(client, reason, NULL); - dhc6_marshall_values("old_", client, + dhc6_marshall_values("old_", client, client->active_lease, ia, addr); script_go(client); - - if (client->config->do_forward_update) + + if ((ia->ia_type == D6O_IA_NA) && + client->config->do_forward_update) client_dns_update(client, 0, 0, &addr->address); } } @@ -4367,7 +5030,7 @@ make_client6_options(struct client_state *client, struct option_state **op, option_cache_dereference(&oc, MDL); } - /* Bring in any configured options to send. */ + /* Bring in any configured options to send. */ if (client->config->on_transmission) execute_statements_in_scope(NULL, NULL, NULL, client, lease ? lease->options : NULL, @@ -4535,4 +5198,33 @@ script_write_params6(struct client_state *client, const char *prefix, } } +/* + * Check if there is something not fully defined in the active lease. + */ +static isc_boolean_t +active_prefix(struct client_state *client) +{ + struct dhc6_lease *lease; + struct dhc6_ia *ia; + struct dhc6_addr *pref; + char zeros[16]; + + lease = client->active_lease; + if (lease == NULL) + return ISC_FALSE; + memset(zeros, 0, 16); + for (ia = lease->bindings; ia != NULL; ia = ia->next) { + if (ia->ia_type != D6O_IA_PD) + continue; + for (pref = ia->addrs; pref != NULL; pref = pref->next) { + if (pref->plen == 0) + return ISC_FALSE; + if (pref->address.len != 16) + return ISC_FALSE; + if (memcmp(pref->address.iabuf, zeros, 16) == 0) + return ISC_FALSE; + } + } + return ISC_TRUE; +} #endif /* DHCPv6 */ diff --git a/client/dhclient.8 b/client/dhclient.8 index fe68f6f4..21f7ed27 100644 --- a/client/dhclient.8 +++ b/client/dhclient.8 @@ -1,4 +1,4 @@ -.\" $Id: dhclient.8,v 1.27 2008/01/24 02:43:04 each Exp $ +.\" $Id: dhclient.8,v 1.28 2008/05/23 13:56:07 fdupont Exp $ .\" .\" Copyright (c) 2004,2007-2008 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium @@ -35,6 +35,27 @@ dhclient - Dynamic Host Configuration Protocol Client .B -6 ] [ +.B -S +] +[ +.B -N +[ +.B -N... +] +] +[ +.B -T +[ +.B -T... +] +] +[ +.B -P +[ +.B -P... +] +] +[ .B -p .I port ] @@ -53,8 +74,7 @@ dhclient - Dynamic Host Configuration Protocol Client ] [ .B -r -] -[ +| .B -x ] [ @@ -123,7 +143,23 @@ DHCPv4 protocol to obtain an IPv4 address and configuration parameters. .PP If given the -6 command line argument, dhclient will use the DHCPv6 protocol to obtain whatever IPv6 addresses are available along with -configuration parameters. Information-request is not yet supported. +configuration parameters. But with +.B -S +it uses Information-request to get only (i.e., without address) +stateless configuration parameters. +.PP +The default DHCPv6 behavior is modified too with +.B -T +which asks for IPv6 temporary addresses, one set per +.B -T +flag. +.B -P +enables the IPv6 prefix delegation. +As temporary addresses or prefix delegation disables the normal +address query, +.B -N +restores it. Note it is not recommended to mix queries of different types +together, or even to share the lease file between them. .PP If given the --version command line argument, dhclient will print its version number and exit. @@ -198,6 +234,7 @@ the server transmit these messages to some other address. This can be specified with the .B -s flag, followed by the IP address or domain name of the destination. +This feature is not supported by DHCPv6. .PP For testing purposes, the giaddr field of all packets that the client sends can be set using the diff --git a/client/dhclient.c b/client/dhclient.c index d4bc2c90..5674a341 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -44,7 +44,7 @@ TIME max_lease_time = 86400; /* 24 hours... */ const char *path_dhclient_conf = _PATH_DHCLIENT_CONF; const char *path_dhclient_db = NULL; const char *path_dhclient_pid = NULL; -static char path_dhclient_script_array [] = _PATH_DHCLIENT_SCRIPT; +static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT; char *path_dhclient_script = path_dhclient_script_array; int dhcp_max_agent_option_packet_length = 0; @@ -67,20 +67,23 @@ static char arr [] = "All rights reserved."; static char message [] = "Internet Systems Consortium DHCP Client"; static char url [] = "For info, please visit http://www.isc.org/sw/dhcp/"; -u_int16_t local_port=0; -u_int16_t remote_port=0; -int no_daemon=0; -struct string_list *client_env=NULL; -int client_env_count=0; -int onetry=0; -int quiet=1; -int nowait=0; -int stateless=0; +u_int16_t local_port = 0; +u_int16_t remote_port = 0; +int no_daemon = 0; +struct string_list *client_env = NULL; +int client_env_count = 0; +int onetry = 0; +int quiet = 1; +int nowait = 0; +int stateless = 0; +int wanted_ia_na = -1; /* the absolute value is the real one. */ +int wanted_ia_ta = 0; +int wanted_ia_pd = 0; char *mockup_relay = NULL; void run_stateless(int exit_mode); -static void usage PROTO ((void)); +static void usage(void); static isc_result_t write_duid(struct data_string *duid); @@ -91,7 +94,7 @@ main(int argc, char **argv) { struct interface_info *ip; struct client_state *client; unsigned seed; - char *server = (char *)0; + char *server = NULL; isc_result_t status; int exit_mode = 0; int release_mode = 0; @@ -124,21 +127,21 @@ main(int argc, char **argv) { else if (fd != -1) close(fd); - openlog ("dhclient", LOG_NDELAY, LOG_DAEMON); + openlog("dhclient", LOG_NDELAY, LOG_DAEMON); -#if !(defined (DEBUG) || defined (__CYGWIN32__)) - setlogmask (LOG_UPTO (LOG_INFO)); +#if !(defined(DEBUG) || defined(__CYGWIN32__)) + setlogmask(LOG_UPTO(LOG_INFO)); #endif /* Set up the OMAPI. */ - status = omapi_init (); + status = omapi_init(); if (status != ISC_R_SUCCESS) - log_fatal ("Can't initialize OMAPI: %s", - isc_result_totext (status)); + log_fatal("Can't initialize OMAPI: %s", + isc_result_totext(status)); /* Set up the OMAPI wrappers for various server database internal objects. */ - dhcp_common_objects_setup (); + dhcp_common_objects_setup(); dhcp_interface_discovery_hook = dhclient_interface_discovery_hook; dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook; @@ -162,117 +165,160 @@ main(int argc, char **argv) { local_family_set = 1; local_family = AF_INET6; #endif /* DHCPv6 */ - } else if (!strcmp (argv [i], "-x")) { /* eXit, no release */ + } else if (!strcmp(argv[i], "-x")) { /* eXit, no release */ release_mode = 0; no_daemon = 0; exit_mode = 1; - } else if (!strcmp (argv [i], "-p")) { + } else if (!strcmp(argv[i], "-p")) { if (++i == argc) - usage (); - local_port = htons (atoi (argv [i])); - log_debug ("binding to user-specified port %d", - ntohs (local_port)); - } else if (!strcmp (argv [i], "-d")) { + usage(); + local_port = htons(atoi(argv[i])); + log_debug("binding to user-specified port %d", + ntohs(local_port)); + } else if (!strcmp(argv[i], "-d")) { no_daemon = 1; quiet = 0; - } else if (!strcmp (argv [i], "-pf")) { + } else if (!strcmp(argv[i], "-pf")) { if (++i == argc) - usage (); - path_dhclient_pid = argv [i]; + usage(); + path_dhclient_pid = argv[i]; no_dhclient_pid = 1; - } else if (!strcmp (argv [i], "-cf")) { + } else if (!strcmp(argv[i], "-cf")) { if (++i == argc) - usage (); - path_dhclient_conf = argv [i]; + usage(); + path_dhclient_conf = argv[i]; no_dhclient_conf = 1; - } else if (!strcmp (argv [i], "-lf")) { + } else if (!strcmp(argv[i], "-lf")) { if (++i == argc) - usage (); - path_dhclient_db = argv [i]; + usage(); + path_dhclient_db = argv[i]; no_dhclient_db = 1; - } else if (!strcmp (argv [i], "-sf")) { + } else if (!strcmp(argv[i], "-sf")) { if (++i == argc) - usage (); - path_dhclient_script = argv [i]; + usage(); + path_dhclient_script = argv[i]; no_dhclient_script = 1; - } else if (!strcmp (argv [i], "-1")) { + } else if (!strcmp(argv[i], "-1")) { onetry = 1; - } else if (!strcmp (argv [i], "-q")) { + } else if (!strcmp(argv[i], "-q")) { quiet = 1; - } else if (!strcmp (argv [i], "-s")) { + } else if (!strcmp(argv[i], "-s")) { if (++i == argc) - usage (); - server = argv [i]; - } else if (!strcmp (argv [i], "-g")) { + usage(); + server = argv[i]; + } else if (!strcmp(argv[i], "-g")) { if (++i == argc) - usage (); - mockup_relay = argv [i]; - } else if (!strcmp (argv [i], "-nw")) { + usage(); + mockup_relay = argv[i]; + } else if (!strcmp(argv[i], "-nw")) { nowait = 1; - } else if (!strcmp (argv [i], "-n")) { + } else if (!strcmp(argv[i], "-n")) { /* do not start up any interfaces */ interfaces_requested = -1; - } else if (!strcmp (argv [i], "-w")) { + } else if (!strcmp(argv[i], "-w")) { /* do not exit if there are no broadcast interfaces. */ persist = 1; - } else if (!strcmp (argv [i], "-e")) { + } else if (!strcmp(argv[i], "-e")) { struct string_list *tmp; if (++i == argc) - usage (); - tmp = dmalloc (strlen (argv [i]) + sizeof *tmp, MDL); + usage(); + tmp = dmalloc(strlen(argv[i]) + sizeof *tmp, MDL); if (!tmp) - log_fatal ("No memory for %s", argv [i]); - strcpy (tmp -> string, argv [i]); - tmp -> next = client_env; + log_fatal("No memory for %s", argv[i]); + strcpy(tmp->string, argv[i]); + tmp->next = client_env; client_env = tmp; client_env_count++; +#ifdef DHCPv6 } else if (!strcmp(argv[i], "-S")) { if (local_family_set && (local_family == AF_INET)) { - usage (); + usage(); } local_family_set = 1; local_family = AF_INET6; + wanted_ia_na = 0; stateless = 1; + } else if (!strcmp(argv[i], "-N")) { + if (local_family_set && (local_family == AF_INET)) { + usage(); + } + local_family_set = 1; + local_family = AF_INET6; + if (wanted_ia_na < 0) { + wanted_ia_na = 0; + } + wanted_ia_na++; + } else if (!strcmp(argv[i], "-T")) { + if (local_family_set && (local_family == AF_INET)) { + usage(); + } + local_family_set = 1; + local_family = AF_INET6; + if (wanted_ia_na < 0) { + wanted_ia_na = 0; + } + wanted_ia_ta++; + } else if (!strcmp(argv[i], "-P")) { + if (local_family_set && (local_family == AF_INET)) { + usage(); + } + local_family_set = 1; + local_family = AF_INET6; + if (wanted_ia_na < 0) { + wanted_ia_na = 0; + } + wanted_ia_pd++; +#endif /* DHCPv6 */ } else if (!strcmp(argv[i], "-v")) { quiet = 0; - } else if (!strcmp (argv [i], "--version")) { - log_info ("isc-dhclient-%s", PACKAGE_VERSION); - exit (0); - } else if (argv [i][0] == '-') { - usage (); + } else if (!strcmp(argv[i], "--version")) { + log_info("isc-dhclient-%s", PACKAGE_VERSION); + exit(0); + } else if (argv[i][0] == '-') { + usage(); } else if (interfaces_requested < 0) { - usage (); + usage(); } else { - struct interface_info *tmp = (struct interface_info *)0; - status = interface_allocate (&tmp, MDL); + struct interface_info *tmp = NULL; + + status = interface_allocate(&tmp, MDL); if (status != ISC_R_SUCCESS) - log_fatal ("Can't record interface %s:%s", - argv [i], isc_result_totext (status)); + log_fatal("Can't record interface %s:%s", + argv[i], isc_result_totext(status)); if (strlen(argv[i]) >= sizeof(tmp->name)) log_fatal("%s: interface name too long (is %ld)", - argv [i], (long)strlen(argv[i])); + argv[i], (long)strlen(argv[i])); strcpy(tmp->name, argv[i]); if (interfaces) { - interface_reference (&tmp -> next, - interfaces, MDL); - interface_dereference (&interfaces, MDL); + interface_reference(&tmp->next, + interfaces, MDL); + interface_dereference(&interfaces, MDL); } - interface_reference (&interfaces, tmp, MDL); - tmp -> flags = INTERFACE_REQUESTED; + interface_reference(&interfaces, tmp, MDL); + tmp->flags = INTERFACE_REQUESTED; interfaces_requested++; } } - if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) { + if (wanted_ia_na < 0) { + wanted_ia_na = 1; + } + + /* Support only one (requested) interface for Prefix Delegation. */ + if (wanted_ia_pd && (interfaces_requested != 1)) { + usage(); + } + + if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) { path_dhclient_conf = s; } - if (!no_dhclient_db && (s = getenv ("PATH_DHCLIENT_DB"))) { + if (!no_dhclient_db && (s = getenv("PATH_DHCLIENT_DB"))) { path_dhclient_db = s; } - if (!no_dhclient_pid && (s = getenv ("PATH_DHCLIENT_PID"))) { + if (!no_dhclient_pid && (s = getenv("PATH_DHCLIENT_PID"))) { path_dhclient_pid = s; } - if (!no_dhclient_script && (s = getenv ("PATH_DHCLIENT_SCRIPT"))) { + if (!no_dhclient_script && (s = getenv("PATH_DHCLIENT_SCRIPT"))) { path_dhclient_script = s; } @@ -297,7 +343,7 @@ main(int argc, char **argv) { char *path = dmalloc(PATH_MAX, MDL); if (path == NULL) log_fatal("No memory for filename\n"); - path_dhclient_db = realpath(path_dhclient_db, path); + path_dhclient_db = realpath(path_dhclient_db, path); if (path_dhclient_db == NULL) log_fatal("%s: %s", path, strerror(errno)); } @@ -306,7 +352,7 @@ main(int argc, char **argv) { char *path = dmalloc(PATH_MAX, MDL); if (path == NULL) log_fatal("No memory for filename\n"); - path_dhclient_script = realpath(path_dhclient_script, path); + path_dhclient_script = realpath(path_dhclient_script, path); if (path_dhclient_script == NULL) log_fatal("%s: %s", path, strerror(errno)); } @@ -332,11 +378,11 @@ main(int argc, char **argv) { } if (!quiet) { - log_info ("%s %s", message, PACKAGE_VERSION); - log_info (copyright); - log_info (arr); - log_info (url); - log_info ("%s", ""); + log_info("%s %s", message, PACKAGE_VERSION); + log_info(copyright); + log_info(arr); + log_info(url); + log_info("%s", ""); } else { log_perror = 0; quiet_interface_discovery = 1; @@ -345,14 +391,14 @@ main(int argc, char **argv) { /* If we're given a relay agent address to insert, for testing purposes, figure out what it is. */ if (mockup_relay) { - if (!inet_aton (mockup_relay, &giaddr)) { + if (!inet_aton(mockup_relay, &giaddr)) { struct hostent *he; - he = gethostbyname (mockup_relay); + he = gethostbyname(mockup_relay); if (he) { - memcpy (&giaddr, he -> h_addr_list [0], - sizeof giaddr); + memcpy(&giaddr, he->h_addr_list[0], + sizeof giaddr); } else { - log_fatal ("%s: no such host", mockup_relay); + log_fatal("%s: no such host", mockup_relay); } } } @@ -363,13 +409,13 @@ main(int argc, char **argv) { sockaddr_broadcast.sin_family = AF_INET; sockaddr_broadcast.sin_port = remote_port; if (server) { - if (!inet_aton (server, &sockaddr_broadcast.sin_addr)) { + if (!inet_aton(server, &sockaddr_broadcast.sin_addr)) { struct hostent *he; - he = gethostbyname (server); + he = gethostbyname(server); if (he) { - memcpy (&sockaddr_broadcast.sin_addr, - he -> h_addr_list [0], - sizeof sockaddr_broadcast.sin_addr); + memcpy(&sockaddr_broadcast.sin_addr, + he->h_addr_list[0], + sizeof sockaddr_broadcast.sin_addr); } else sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; @@ -382,52 +428,61 @@ main(int argc, char **argv) { /* Stateless special case. */ if (stateless) { - if (release_mode || (interfaces_requested != 1)) { - usage (); + if (release_mode || (wanted_ia_na > 0) || + wanted_ia_ta || wanted_ia_pd || + (interfaces_requested != 1)) { + usage(); } - run_stateless (exit_mode); + run_stateless(exit_mode); return 0; } /* Discover all the network interfaces. */ - discover_interfaces (DISCOVER_UNCONFIGURED); + discover_interfaces(DISCOVER_UNCONFIGURED); /* Parse the dhclient.conf file. */ - read_client_conf (); + read_client_conf(); /* Parse the lease database. */ - read_client_leases (); + read_client_leases(); /* Rewrite the lease database... */ - rewrite_client_leases (); + rewrite_client_leases(); /* XXX */ /* config_counter(&snd_counter, &rcv_counter); */ - /* If no broadcast interfaces were discovered, call the script - and tell it so. */ + /* + * If no broadcast interfaces were discovered, call the script + * and tell it so. + */ if (!interfaces) { - /* Call dhclient-script with the NBI flag, in case somebody - cares. */ - script_init ((struct client_state *)0, "NBI", - (struct string_list *)0); - script_go ((struct client_state *)0); - - /* If we haven't been asked to persist, waiting for new - interfaces, then just exit. */ + /* + * Call dhclient-script with the NBI flag, + * in case somebody cares. + */ + script_init(NULL, "NBI", NULL); + script_go(NULL); + + /* + * If we haven't been asked to persist, waiting for new + * interfaces, then just exit. + */ if (!persist) { /* Nothing more to do. */ - log_info ("No broadcast interfaces found - exiting."); - exit (0); + log_info("No broadcast interfaces found - exiting."); + exit(0); } } else if (!release_mode && !exit_mode) { /* Call the script with the list of interfaces. */ - for (ip = interfaces; ip; ip = ip -> next) { - /* If interfaces were specified, don't configure - interfaces that weren't specified! */ + for (ip = interfaces; ip; ip = ip->next) { + /* + * If interfaces were specified, don't configure + * interfaces that weren't specified! + */ if ((interfaces_requested > 0) && - ((ip -> flags & (INTERFACE_REQUESTED | - INTERFACE_AUTOMATIC)) != + ((ip->flags & (INTERFACE_REQUESTED | + INTERFACE_AUTOMATIC)) != INTERFACE_REQUESTED)) continue; @@ -440,7 +495,7 @@ main(int argc, char **argv) { "alias_", ip->client->alias); } - script_go (ip->client); + script_go(ip->client); } } @@ -448,9 +503,9 @@ 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 != 0 - ? DISCOVER_REQUESTED - : DISCOVER_RUNNING); + discover_interfaces(interfaces_requested != 0 + ? DISCOVER_REQUESTED + : DISCOVER_RUNNING); /* Make up a seed for the random number generator from current time plus the sum of the last four bytes of each @@ -458,14 +513,14 @@ main(int argc, char **argv) { Not much entropy, but we're booting, so we're not likely to find anything better. */ seed = 0; - for (ip = interfaces; ip; ip = ip -> next) { + for (ip = interfaces; ip; ip = ip->next) { int junk; - memcpy (&junk, - &ip -> hw_address.hbuf [ip -> hw_address.hlen - - sizeof seed], sizeof seed); + memcpy(&junk, + &ip->hw_address.hbuf[ip->hw_address.hlen - + sizeof seed], sizeof seed); seed += junk; } - srandom (seed + cur_time); + srandom(seed + cur_time); /* Start a configuration state machine for each interface. */ #ifdef DHCPv6 @@ -543,18 +598,18 @@ main(int argc, char **argv) { /* 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); + listener = NULL; + 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); + 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)); + log_fatal("Can't start OMAPI protocol: %s", + isc_result_totext (result)); } /* Set up the bootp packet handler... */ @@ -563,8 +618,8 @@ main(int argc, char **argv) { dhcpv6_packet_handler = do_packet6; #endif /* DHCPv6 */ -#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ - defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +#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; @@ -573,41 +628,42 @@ main(int argc, char **argv) { /* If we're not supposed to wait before getting the address, don't. */ if (nowait) - go_daemon (); + go_daemon(); /* If we're not going to daemonize, write the pid file now. */ if (no_daemon || nowait) - write_client_pid_file (); + write_client_pid_file(); /* Start dispatching packets and timeouts... */ - dispatch (); + dispatch(); /*NOTREACHED*/ return 0; } -static void usage () +static void usage() { - log_info ("%s %s", message, PACKAGE_VERSION); - log_info (copyright); - log_info (arr); - log_info (url); + log_info("%s %s", message, PACKAGE_VERSION); + log_info(copyright); + log_info(arr); + log_info(url); - log_error ("Usage: dhclient %s %s", + log_error("Usage: dhclient %s %s", #ifdef DHCPv6 - "[-4|-6] [-S1dvrx] [-nw] [-p <port>]", + "[-4|-6] [-SNTP1dvrx] [-nw] [-p <port>]", #else /* DHCPv6 */ - "[-1dvrx] [-nw] [-p <port>]", + "[-1dvrx] [-nw] [-p <port>]", #endif /* DHCPv6 */ - "[-s server]"); - log_error (" [-cf config-file] [-lf lease-file]%s", - "[-pf pid-file] [-e VAR=val]"); - log_fatal (" [-sf script-file] [interface]"); + "[-s server]"); + log_error(" [-cf config-file] [-lf lease-file]%s", + "[-pf pid-file] [-e VAR=val]"); + log_fatal(" [-sf script-file] [interface]"); } void run_stateless(int exit_mode) { +#ifdef DHCPv6 struct client_state *client; omapi_object_t *listener; isc_result_t result; @@ -647,7 +703,7 @@ void run_stateless(int exit_mode) /* Start up a listener for the object management API protocol. */ if (top_level_config.omapi_port != -1) { - listener = (omapi_object_t *)0; + listener = NULL; result = omapi_generic_new(&listener, MDL); if (result != ISC_R_SUCCESS) log_fatal("Can't allocate new generic object: %s\n", @@ -664,8 +720,8 @@ void run_stateless(int exit_mode) /* 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) +#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; @@ -685,6 +741,7 @@ void run_stateless(int exit_mode) dispatch(); /*NOTREACHED*/ +#endif /* DHCPv6 */ return; } @@ -766,20 +823,24 @@ void state_reboot (cpp) /* We are in the rebooting state. */ client -> state = S_REBOOTING; - /* make_request doesn't initialize xid because it normally comes - from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, - so pick an xid now. */ + /* + * make_request doesn't initialize xid because it normally comes + * from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, + * so pick an xid now. + */ client -> xid = random (); - /* Make a DHCPREQUEST packet, and set appropriate per-interface - flags. */ + /* + * Make a DHCPREQUEST packet, and set + * appropriate per-interface flags. + */ make_request (client, client -> active); client -> destination = iaddr_broadcast; client -> first_sending = cur_time; client -> interval = client -> config -> initial_interval; /* Zap the medium list... */ - client -> medium = (struct string_list *)0; + client -> medium = NULL; /* Send out the first DHCPREQUEST packet. */ send_request (client); @@ -809,8 +870,10 @@ void state_init (cpp) send_discover (client); } -/* state_selecting is called when one or more DHCPOFFER packets have been - received and a configurable period of time has passed. */ +/* + * state_selecting is called when one or more DHCPOFFER packets have been + * received and a configurable period of time has passed. + */ void state_selecting (cpp) void *cpp; @@ -821,31 +884,39 @@ void state_selecting (cpp) ASSERT_STATE(state, S_SELECTING); - /* Cancel state_selecting and send_discover timeouts, since either - one could have got us here. */ + /* + * Cancel state_selecting and send_discover timeouts, since either + * one could have got us here. + */ cancel_timeout (state_selecting, client); cancel_timeout (send_discover, client); - /* We have received one or more DHCPOFFER packets. Currently, - the only criterion by which we judge leases is whether or - not we get a response when we arp for them. */ - picked = (struct client_lease *)0; + /* + * We have received one or more DHCPOFFER packets. Currently, + * the only criterion by which we judge leases is whether or + * not we get a response when we arp for them. + */ + picked = NULL; for (lp = client -> offered_leases; lp; lp = next) { next = lp -> next; - /* Check to see if we got an ARPREPLY for the address - in this particular lease. */ + /* + * Check to see if we got an ARPREPLY for the address + * in this particular lease. + */ if (!picked) { picked = lp; - picked -> next = (struct client_lease *)0; + picked -> next = NULL; } else { destroy_client_lease (lp); } } - client -> offered_leases = (struct client_lease *)0; + client -> offered_leases = NULL; - /* If we just tossed all the leases we were offered, go back - to square one. */ + /* + * If we just tossed all the leases we were offered, go back + * to square one. + */ if (!picked) { client -> state = S_INIT; state_init (client); diff --git a/client/scripts/bsdos b/client/scripts/bsdos index 12077f0c..7f858502 100755 --- a/client/scripts/bsdos +++ b/client/scripts/bsdos @@ -242,6 +242,12 @@ if [ ${reason} = PREINIT6 ] ; then exit_with_hooks 0 fi +if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then + echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} + + exit_with_hooks 0 +fi + if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; diff --git a/client/scripts/freebsd b/client/scripts/freebsd index 67ff002e..ea8f5bb5 100755 --- a/client/scripts/freebsd +++ b/client/scripts/freebsd @@ -1,6 +1,6 @@ #!/bin/sh # -# $Id: freebsd,v 1.21 2008/01/16 23:02:10 dhankins Exp $ +# $Id: freebsd,v 1.22 2008/05/23 13:56:07 fdupont Exp $ # # $FreeBSD$ @@ -306,6 +306,12 @@ if [ ${reason} = PREINIT6 ] ; then exit_with_hooks 0 fi +if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then + echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} + + exit_with_hooks 0 +fi + if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; @@ -332,13 +338,11 @@ if [ ${reason} = RENEW6 ] || [ ${reason} = REBIND6 ] ; then fi if [ ${reason} = DEPREF6 ] ; then - if [ x${new_ip6_prefixlen} = x ] ; then + if [ x${new_ip6_address} = x ] ; then exit_with_hooks 2; fi - # XXX: - # There doesn't appear to be a way to update an addr to indicate - # preference. + ifconfig ${interface} inet6 ${new_ip6_address} deprecated exit_with_hooks 0 fi diff --git a/client/scripts/linux b/client/scripts/linux index a0fcab55..49f0977d 100755 --- a/client/scripts/linux +++ b/client/scripts/linux @@ -243,6 +243,12 @@ if [ ${reason} = PREINIT6 ] ; then exit_with_hooks 0 fi +if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then + echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} + + exit_with_hooks 0 +fi + if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; @@ -274,10 +280,8 @@ if [ ${reason} = DEPREF6 ] ; then exit_with_hooks 2; fi - # There doesn't appear to be a way to update an addr to indicate - # preference. -# ${ip} -f inet6 addr ??? ${new_ip6_address}/${new_ip6_prefixlen} \ -# dev ${interface} scope global deprecated? + ${ip} -f inet6 addr change ${new_ip6_address}/${new_ip6_prefixlen} \ + dev ${interface} scope global preferred_lft 0 exit_with_hooks 0 fi diff --git a/client/scripts/netbsd b/client/scripts/netbsd index a5394796..7a26d28d 100755 --- a/client/scripts/netbsd +++ b/client/scripts/netbsd @@ -242,6 +242,12 @@ if [ ${reason} = PREINIT6 ] ; then exit_with_hooks 0 fi +if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then + echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} + + exit_with_hooks 0 +fi + if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; diff --git a/client/scripts/openbsd b/client/scripts/openbsd index 1b8d7b02..182c7d6c 100644 --- a/client/scripts/openbsd +++ b/client/scripts/openbsd @@ -242,6 +242,12 @@ if [ ${reason} = PREINIT6 ] ; then exit_with_hooks 0 fi +if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then + echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} + + exit_with_hooks 0 +fi + if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; |