From: Evan Hunt Date: Wed, 6 Jun 2007 22:57:32 +0000 (+0000) Subject: - Add support for dhcpv6 "Release" messages [rt16905] X-Git-Tag: v4_0_0a2~38 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=af5fa176268f5e74371ebb8fb4a9778d41b8caf2;p=thirdparty%2Fdhcp.git - Add support for dhcpv6 "Release" messages [rt16905] - Add -x option, which causes running dhclient processes to exist gracefully *without* releasing leases [rt16741] (Merging both at once because the first one depended on the second one) --- diff --git a/RELNOTES b/RELNOTES index c088ec207..706489787 100644 --- a/RELNOTES +++ b/RELNOTES @@ -61,6 +61,11 @@ suggested fixes to . - Fixed a bug in which write_lease() might report a failure incorrectly +- Added support for DHCPv6 Release messages + +- Added -x option to dhclient, which triggers dhclient processes + to exit gracefully without releasing leases first + Changes since 4.0.0-20070413 - Old (expired) leases are now cleaned. diff --git a/client/dhc6.c b/client/dhc6.c index 02f87487a..2e63b7357 100644 --- a/client/dhc6.c +++ b/client/dhc6.c @@ -24,7 +24,7 @@ #ifndef lint static char ocopyright[] = -"$Id: dhc6.c,v 1.5 2007/05/19 18:47:13 dhankins Exp $ Copyright (c) 2006-2007 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dhc6.c,v 1.6 2007/06/06 22:57:31 each Exp $ Copyright (c) 2006-2007 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -58,10 +58,12 @@ void do_confirm6(void *input); void reply_handler(struct packet *packet, struct client_state *client); static isc_result_t dhc6_add_ia(struct client_state *client, struct data_string *packet, - struct dhc6_lease *lease); + struct dhc6_lease *lease, + u_int8_t message); static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst); void do_select6(void *input); void do_refresh6(void *input); +static void do_release6(void *input); static void start_bound(struct client_state *client); void bound_handler(struct packet *packet, struct client_state *client); void start_renew6(void *input); @@ -1141,64 +1143,144 @@ do_confirm6(void *input) &dhcpv6_universe); /* Append IA's. */ - memset(&ia_data, 0, sizeof(ia_data)); - memset(&addr_data, 0, sizeof(addr_data)); - for (ia = client->active_lease->bindings ; ia != NULL ; - ia = ia->next) { - if (!buffer_allocate(&ia_data.buffer, 12, MDL)) { - log_error("Unable to allocate memory for IA_NA."); - data_string_forget(&ds, MDL); - return; - } + if (dhc6_add_ia(client, &ds, client->active_lease, + DHCPV6_CONFIRM) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + return; + } - /* Copy the IAID into the packet buffer. */ - memcpy(ia_data.buffer->data, ia->iaid, 4); - /* Set t1 and t2 to zero (RFC3315 section 17.1.3) */ - memset(ia_data.buffer->data + 4, 0, 8); + /* Transmit and wait. */ - log_debug("XMT: X-- IA_NA %s", - print_hex_1(4, ia_data.buffer->data, 55)); + log_info("XMT: Confirm on %s, interval %ld.", + client->name ? client->name : client->interface->name, + client->RT); - for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { - if (addr->address.len != 16) { - log_error("Illegal IPv6 address length (%d), " - "ignoring. (%s:%d)", - addr->address.len, MDL); - continue; - } + send_ret = send_packet6(client->interface, ds.data, ds.len, + &DHCPv6DestAddr); + if (send_ret != ds.len) { + log_error("dhc6: sendpacket6() sent %d of %d bytes", + send_ret, ds.len); + } - if (!buffer_allocate(&addr_data.buffer, 24, MDL)) { - log_error("Unable to allocate memory for " - "IAADDR."); - data_string_forget(&ia_data, MDL); - data_string_forget(&ds, MDL); - return; - } + data_string_forget(&ds, MDL); - /* Copy the address into the packet buffer. */ - memcpy(addr_data.buffer->data, addr->address.iabuf, - 16); + add_timeout(cur_time + client->RT, do_confirm6, client, NULL, NULL); - /* Set preferred and max life to zero, per 17.1.3. */ - memset(addr_data.buffer->data + 16, 0, 8); + dhc6_retrans_advance(client); +} - log_debug("XMT: | X-- Confirm Address %s", - piaddr(addr->address)); +/* + * Release addresses. + */ +void +start_release6(struct client_state *client) +{ + struct data_string packet; - append_option(&ia_data, &dhcpv6_universe, - iaaddr_option, &addr_data); + /* 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; + + /* + * 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"); + + /* Fetch a 24-bit transaction ID. */ + dhc6_new_xid(client); + + /* Set timers per RFC3315 section 18.1.1. */ + client->IRT = REL_TIMEOUT; + client->MRT = 0; + client->MRC = REL_MAX_RC; + client->MRD = 0; - data_string_forget(&addr_data, MDL); + dhc6_retrans_init(client); + client->v6_handler = reply_handler; + + /* ("re")transmit the first packet. */ + do_release6(client); +} +/* + * do_release6() creates a Release packet and transmits it. + */ +static void +do_release6(void *input) +{ + struct sockaddr_in6 unicast, *dest_addr = &DHCPv6DestAddr; + struct client_state *client; + struct dhc6_ia *ia; + struct dhc6_addr *addr; + struct data_string ds; + struct data_string ia_data; + struct data_string addr_data; + struct option_cache *oc; + struct dhc6_lease *lease; + int send_ret; + + client = input; + + if (client->active_lease == NULL) + log_fatal("Impossible condition at %s:%d.", MDL); + + if ((client->MRC != 0) && (client->txcount > client->MRC)) { + log_info("Max retransmission count exceeded."); + return; + } + + /* + * Check whether the server has sent a unicast option; if so, we can + * use the address it specified. + */ + oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST); + if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL, + lease->options, NULL, &global_scope, + oc, MDL)) { + if (ds.len < 16) { + log_error("Invalid unicast option length %d.", ds.len); + } else { + memset(&unicast, 0, sizeof(DHCPv6DestAddr)); + unicast.sin6_family = AF_INET6; + unicast.sin6_port = remote_port; + memcpy(&unicast.sin6_addr, ds.data, 16); + dest_addr = &unicast; } - append_option(&ds, &dhcpv6_universe, ia_na_option, &ia_data); + data_string_forget(&ds, MDL); + } - data_string_forget(&ia_data, MDL); + memset(&ds, 0, sizeof(ds)); + if (!buffer_allocate(&ds.buffer, 4, MDL)) { + log_error("Unable to allocate memory for Release."); + return; } - /* Transmit and wait. */ + ds.data = ds.buffer->data; + ds.len = 4; + ds.buffer->data[0] = DHCPV6_RELEASE; + memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3); - log_info("XMT: Confirm on %s, interval %ld.", + log_debug("XMT: Forming Release."); + make_client6_options(client, &client->sent_options, + client->active_lease, DHCPV6_RELEASE); + dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, + client->sent_options, &global_scope, + &dhcpv6_universe); + + /* Append IA's. */ + if (dhc6_add_ia(client, &ds, client->active_lease, + DHCPV6_RELEASE) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + return; + } + + /* Transmit and wait. */ + log_info("XMT: Release on %s, interval %ld.", client->name ? client->name : client->interface->name, client->RT); @@ -1211,8 +1293,7 @@ do_confirm6(void *input) data_string_forget(&ds, MDL); - add_timeout(cur_time + client->RT, do_confirm6, client, NULL, NULL); - + add_timeout(cur_time + client->RT, do_release6, client, NULL, NULL); dhc6_retrans_advance(client); } @@ -1998,7 +2079,7 @@ do_select6(void *input) &dhcpv6_universe); /* Now append any IA_NA's, and within them any IAADDRs. */ - if (dhc6_add_ia(client, &ds, lease) != ISC_R_SUCCESS) { + if (dhc6_add_ia(client, &ds, lease, DHCPV6_REQUEST) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } @@ -2022,12 +2103,11 @@ do_select6(void *input) } /* For each IA in the lease, for each address in the IA, append that - * information onto the packet-so-far in a "what I would like to have - * please" fashion. + * information onto the packet-so-far. */ static isc_result_t dhc6_add_ia(struct client_state *client, struct data_string *packet, - struct dhc6_lease *lease) + struct dhc6_lease *lease, u_int8_t message) { struct data_string iads; struct data_string addrds; @@ -2035,79 +2115,144 @@ dhc6_add_ia(struct client_state *client, struct data_string *packet, struct dhc6_ia *ia; isc_result_t rval = ISC_R_SUCCESS; TIME t1, t2; - - /* Now appended any IA_NA's, and within them any IAADDRs. */ + memset(&iads, 0, sizeof(iads)); memset(&addrds, 0, sizeof(addrds)); - for (ia = lease->bindings ; ia ; ia = ia->next) { + for (ia = lease->bindings; + ia != NULL && rval == ISC_R_SUCCESS; + ia = ia->next) { if (!buffer_allocate(&iads.buffer, 12, MDL)) { - log_error("Unable to allocate memory for IA."); + log_error("Unable to allocate memory for IA_NA."); + rval = ISC_R_NOMEMORY; break; } - iads.data = iads.buffer->data; - iads.len = 12; + /* Copy the IAID into the packet buffer. */ memcpy(iads.buffer->data, ia->iaid, 4); + iads.data = iads.buffer->data; + iads.len = 12; - 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); + 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: + /* 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); + } - 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); + for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { + if (addr->address.len != 16) { + log_error("Illegal IPv6 address length (%d), " + "ignoring. (%s:%d)", + addr->address.len, MDL); + continue; + } - for (addr = ia->addrs ; addr ; addr = addr->next) { 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); - 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); + /* 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); + &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) { + if (ia->addrs == NULL) { + log_debug("!!!: V IA_NA has no IAADDRs - removed."); + rval = ISC_R_FAILURE; + } else if (rval == ISC_R_SUCCESS) { log_debug("XMT: V IA_NA appended."); append_option(packet, &dhcpv6_universe, ia_na_option, &iads); - } else { - log_debug("!!!: V IA_NA has no IAADDRs - removed."); - rval = ISC_R_FAILURE; } data_string_forget(&iads, MDL); } - return rval; + return rval; } /* reply_handler() accepts a Reply while we're attempting Select or Renew or @@ -2153,6 +2298,7 @@ reply_handler(struct packet *packet, struct client_state *client) cancel_timeout(do_confirm6, client); cancel_timeout(do_select6, client); cancel_timeout(do_refresh6, client); + cancel_timeout(do_release6, client); /* Action was taken, so now that we've torn down our scheduled * retransmissions, return. @@ -2165,6 +2311,16 @@ reply_handler(struct packet *packet, struct client_state *client) client->selected_lease = NULL; } + /* If this is in response to a Release, clean up and return. */ + if (client->state == S_STOPPED) { + if (client->active_lease == NULL) + log_fatal("Impossible condition at %s:%d.", MDL); + + dhc6_lease_destroy(client->active_lease, MDL); + client->active_lease = NULL; + return; + } + /* If this is in response to a confirm, we use the lease we've * already got, not the reply we were sent. */ @@ -2769,7 +2925,9 @@ do_refresh6(void *input) client->sent_options, &global_scope, &dhcpv6_universe); - if (dhc6_add_ia(client, &ds, lease) != ISC_R_SUCCESS) { + /* Append IA's */ + if (dhc6_add_ia(client, &ds, lease, + client->refresh_type) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } @@ -2944,6 +3102,33 @@ do_expire(void *input) dhc6_check_times(client); } +/* + * Run client script to unconfigure interface. + * Called with reason STOP6 when dhclient -x is run, or with reason + * RELEASE6 when server has replied to a Release message. + */ +void +unconfigure6(struct client_state *client, const char *reason) +{ + struct dhc6_lease *lease; + struct dhc6_ia *ia; + struct dhc6_addr *addr; + + if (client->active_lease == NULL) + return; + + for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) { + for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { + script_init(client, reason, NULL); + dhc6_marshall_values("old_", client, lease, ia, addr); + script_go(client); + + if (client->config->do_forward_update) + client_dns_update(client, 0, 0, &addr->address); + } + } +} + /* make_client6_options() fetches option caches relevant to the client's * scope and places them into the sent_options cache. This cache is later * used to populate DHCPv6 output packets with options. diff --git a/client/dhclient.8 b/client/dhclient.8 index e2eb4b807..9844a69aa 100644 --- a/client/dhclient.8 +++ b/client/dhclient.8 @@ -1,4 +1,4 @@ -.\" $Id: dhclient.8,v 1.23 2007/05/19 19:16:23 dhankins Exp $ +.\" $Id: dhclient.8,v 1.24 2007/06/06 22:57:32 each Exp $ .\" .\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium @@ -55,6 +55,9 @@ dhclient - Dynamic Host Configuration Protocol Client .B -r ] [ +.B -x +] +[ .B -lf .I lease-file ] @@ -240,6 +243,17 @@ The flag explicitly releases the current lease, and once the lease has been released, the client exits. .PP +If the client is killed by a signal (for example at shutdown or reboot) +it won't execute the +.B dhclient-script (8) +at exit. However if you shut the client down gracefully with +.B -r +or +.B -x +it will execute +.B dhclient-script (8) +at shutdown with the specific reason for calling the script set. +.PP The .B -1 flag will cause dhclient to try once to get a lease. If it fails, dhclient diff --git a/client/dhclient.c b/client/dhclient.c index ee2a0e14f..5466af928 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -32,7 +32,7 @@ #ifndef lint static char ocopyright[] = -"$Id: dhclient.c,v 1.151 2007/05/21 18:16:54 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dhclient.c,v 1.152 2007/06/06 22:57:32 each Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -82,8 +82,6 @@ char *mockup_relay = NULL; static void usage PROTO ((void)); -void do_release(struct client_state *); - static isc_result_t write_duid(struct data_string *duid); int @@ -95,6 +93,7 @@ main(int argc, char **argv) { unsigned seed; char *server = (char *)0; isc_result_t status; + int exit_mode = 0; int release_mode = 0; omapi_object_t *listener; isc_result_t result; @@ -159,6 +158,10 @@ main(int argc, char **argv) { } else if (!strcmp(argv[i], "-r")) { release_mode = 1; no_daemon = 1; + } else if (!strcmp (argv [i], "-x")) { /* eXit, no release */ + release_mode = 0; + no_daemon = 0; + exit_mode = 1; } else if (!strcmp (argv [i], "-p")) { if (++i == argc) usage (); @@ -274,7 +277,7 @@ main(int argc, char **argv) { log_fatal("Impossible condition at %s:%d.", MDL); /* first kill of any currently running client */ - if (release_mode) { + if (release_mode || exit_mode) { FILE *pidfd; pid_t oldpid; long temp; @@ -375,7 +378,7 @@ main(int argc, char **argv) { log_info ("No broadcast interfaces found - exiting."); exit (0); } - } else if (!release_mode) { + } 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 @@ -441,6 +444,14 @@ main(int argc, char **argv) { for (ip = interfaces ; ip != NULL ; ip = ip->next) { for (client = ip->client ; client != NULL ; client = client->next) { + if (release_mode) { + start_release6(client); + continue; + } else if (exit_mode) { + unconfigure6(client, "STOP6"); + continue; + } + /* If we have a previous binding, Confirm * that we can (or can't) still use it. */ @@ -457,7 +468,9 @@ main(int argc, char **argv) { ip->flags |= INTERFACE_RUNNING; for (client = ip->client ; client ; client = client->next) { - if (release_mode) + if (exit_mode) + state_stop(client); + else if (release_mode) do_release(client); else { client->state = S_INIT; @@ -471,7 +484,7 @@ main(int argc, char **argv) { } } - if (release_mode) + if (release_mode || exit_mode) return 0; /* Start up a listener for the object management API protocol. */ @@ -527,7 +540,7 @@ static void usage () log_info (arr); log_info (url); - log_error ("Usage: dhclient [-1dvr] [-nw] [-p ] %s", + log_error ("Usage: dhclient [-1dvrx] [-nw] [-p ] %s", "[-s server]"); log_error (" [-cf config-file] [-lf lease-file]%s", "[-pf pid-file] [-e VAR=val]"); @@ -1003,22 +1016,20 @@ void state_stop (cpp) void *cpp; { struct client_state *client = cpp; - int i; /* Cancel all timeouts. */ - cancel_timeout (state_selecting, client); - cancel_timeout (send_discover, client); - cancel_timeout (send_request, client); - cancel_timeout (state_bound, client); + cancel_timeout(state_selecting, client); + cancel_timeout(send_discover, client); + cancel_timeout(send_request, client); + cancel_timeout(state_bound, client); /* If we have an address, unconfigure it. */ - if (client -> active) { - script_init (client, "STOP", client -> active -> medium); - script_write_params (client, "old_", client -> active); - if (client -> alias) - script_write_params (client, "alias_", - client -> alias); - script_go (client); + if (client->active) { + script_init(client, "STOP", client->active->medium); + script_write_params(client, "old_", client->active); + if (client->alias) + script_write_params(client, "alias_", client->alias); + script_go(client); } } @@ -3323,6 +3334,7 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate, } } } + if (newstate == server_shutdown) add_timeout (cur_time + 1, shutdown_exit, 0, 0, 0); return ISC_R_SUCCESS; diff --git a/client/scripts/bsdos b/client/scripts/bsdos index de3b18d78..12077f0ce 100755 --- a/client/scripts/bsdos +++ b/client/scripts/bsdos @@ -279,7 +279,7 @@ if [ ${reason} = DEPREF6 ] ; then exit_with_hooks 0 fi -if [ ${reason} = EXPIRE6 ] ; then +if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi diff --git a/client/scripts/freebsd b/client/scripts/freebsd index b4567a50c..05c41a976 100755 --- a/client/scripts/freebsd +++ b/client/scripts/freebsd @@ -1,6 +1,6 @@ #!/bin/sh # -# $Id: freebsd,v 1.18 2007/05/18 17:18:05 dhankins Exp $ +# $Id: freebsd,v 1.19 2007/06/06 22:57:32 each Exp $ # # $FreeBSD$ @@ -334,7 +334,7 @@ if [ ${reason} = DEPREF6 ] ; then exit_with_hooks 0 fi -if [ ${reason} = EXPIRE6 ] ; then +if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi diff --git a/client/scripts/linux b/client/scripts/linux index ee3ef42d6..6ac25dd49 100755 --- a/client/scripts/linux +++ b/client/scripts/linux @@ -276,7 +276,7 @@ if [ ${reason} = DEPREF6 ] ; then exit_with_hooks 0 fi -if [ ${reason} = EXPIRE6 ] ; then +if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi diff --git a/client/scripts/netbsd b/client/scripts/netbsd index 5629ee785..a53947962 100755 --- a/client/scripts/netbsd +++ b/client/scripts/netbsd @@ -279,7 +279,7 @@ if [ ${reason} = DEPREF6 ] ; then exit_with_hooks 0 fi -if [ ${reason} = EXPIRE6 ] ; then +if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi diff --git a/client/scripts/openbsd b/client/scripts/openbsd index a17a0a451..1b8d7b021 100644 --- a/client/scripts/openbsd +++ b/client/scripts/openbsd @@ -279,7 +279,7 @@ if [ ${reason} = DEPREF6 ] ; then exit_with_hooks 0 fi -if [ ${reason} = EXPIRE6 ] ; then +if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi diff --git a/includes/dhcpd.h b/includes/dhcpd.h index dd10416ad..51ff4f714 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -2416,10 +2416,12 @@ void form_duid(struct data_string *duid, char *file, int line); void dhc6_lease_destroy(struct dhc6_lease *lease, char *file, int line); void start_init6(struct client_state *client); void start_confirm6(struct client_state *client); +void start_release6(struct client_state *client); void start_selecting6(struct client_state *client); isc_result_t write_client6_lease(struct client_state *client, struct dhc6_lease *lease, int rewrite, int sync); +void unconfigure6(struct client_state *client, const char *reason); /* db.c */ int write_lease PROTO ((struct lease *));