Commit f1208e79 authored by Thomas Markwalder's avatar Thomas Markwalder

[master] dhcpd (-6) now supports update-static-leases

    Merges in rt34097.
parent 700e3fca
......@@ -284,6 +284,18 @@ dhcp-users@lists.isc.org.
- Corrected some minor coverity issues: CID 1426059, 1426058, and 1426057.
[ISC-Bugs #46836]
- The server (-6) now honors the parameter, update-static-leases, for static
(fixed-address6) DHCPv6 leases. It is worth noting that because stateful
data is not retained by the server for static leases, each time a client
requests or renews a static lease, the server will perform DDNS updates for
it. This may have significant performance implications for environments
with many clients that request or renew static leases often. Similarly,
the DNS entries will not be removed by server when a client issues a RELEASE
nor if the lease is deleted from the configuration. In such cases the DNS
entries must be removed manually. This feature is disabled by default.
[ISC-Bugs #34097]
[ISC-Bugs #41054]
Changes since 4.3.6 (Bugs):
- Corrected an issue where the server would return a client's previously
......
......@@ -594,9 +594,16 @@ ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
}
/* Should be freed by now, check just in case. */
if (ddns_cb->transaction != NULL)
if (ddns_cb->transaction != NULL) {
log_error("Impossible memory leak at %s:%d (attempt to free "
"DDNS Control Block before transaction).", MDL);
}
/* Should be freed by now, check just in case. */
if (ddns_cb->fixed6_ia) {
log_error("Possible memory leak at %s:%d (attempt to free "
"DDNS Control Block before fxed6_ia).", MDL);
}
dfree(ddns_cb, file, line);
}
......
......@@ -1646,6 +1646,7 @@ struct iasubopt {
/* space for the on * executable statements */
struct on_star on_star;
int static_lease;
};
struct ia_xx {
......@@ -1818,6 +1819,7 @@ typedef struct dhcp_ddns_cb {
dns_rdataclass_t dhcid_class;
dns_rdataclass_t other_dhcid_class;
char *lease_tag;
struct ia_xx *fixed6_ia;
} dhcp_ddns_cb_t;
extern struct ipv6_pool **pools;
......
......@@ -57,6 +57,25 @@ static void copy_conflict_flags(u_int16_t *target, u_int16_t source);
static void ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult);
/*
* ddns_cb_free() is part of common lib, while ia_* routines are known
* only in the server. Use this wrapper instead of ddns_cb_free() directly.
*/
static void
destroy_ddns_cb(struct dhcp_ddns_cb *ddns_cb, char* file, int line) {
if (!ddns_cb) {
return;
}
if (ddns_cb->fixed6_ia) {
ia_dereference(&ddns_cb->fixed6_ia, MDL);
}
ddns_cb_free(ddns_cb, file, line);
}
/* DN: No way of checking that there is enough space in a data_string's
buffer. Be certain to allocate enough!
TL: This is why the expression evaluation code allocates a *new*
......@@ -153,6 +172,13 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
scope = &(lease6->scope);
memcpy(ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
ddns_cb->address.len = 16;
if (lease6->static_lease) {
/* We add a reference to keep ia && iasubopt alive
* since static v6s are retained anywhere */
ia_reference(&ddns_cb->fixed6_ia, lease6->ia, MDL);
ddns_cb->flags |= DDNS_STATIC_LEASE;
}
}
memset (&d1, 0, sizeof(d1));
......@@ -754,7 +780,7 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
* Final cleanup.
*/
if (ddns_cb != NULL) {
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
}
data_string_forget(&d1, MDL);
......@@ -1296,7 +1322,7 @@ ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
}
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
/*
* A single DDNS operation may require several calls depending on
* the current state as the prerequisites for the first message
......@@ -1362,7 +1388,7 @@ ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result);
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
return;
}
......@@ -1476,7 +1502,7 @@ ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb,
}
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
/*
* A single DDNS operation may require several calls depending on
* the current state as the prerequisites for the first message
......@@ -1551,7 +1577,7 @@ ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb,
}
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
/*
* A single DDNS operation may require several calls depending on
* the current state as the prerequisites for the first message
......@@ -1636,7 +1662,7 @@ ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb,
}
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
/*
* A single DDNS operation may require several calls depending on
* the current state as the prerequisites for the first message
......@@ -1694,7 +1720,7 @@ ddns_fwd_srv_connector(struct lease *lease,
if (result == ISC_R_SUCCESS) {
ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
} else {
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
}
return;
......@@ -1762,7 +1788,7 @@ ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb,
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
return;
}
......@@ -1866,7 +1892,7 @@ ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb,
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
}
/*%<
......@@ -1952,7 +1978,7 @@ ddns_removals(struct lease *lease,
} else {
/* Remvoval, check and remove updates */
if (ddns_cb->next_op != NULL) {
ddns_cb_free(ddns_cb->next_op, MDL);
destroy_ddns_cb(ddns_cb->next_op, MDL);
ddns_cb->next_op = NULL;
}
#if defined (DEBUG_DNS_UPDATES)
......@@ -1980,7 +2006,7 @@ ddns_removals(struct lease *lease,
} else {
/* Remvoval, check and remove updates */
if (ddns_cb->next_op != NULL) {
ddns_cb_free(ddns_cb->next_op, MDL);
destroy_ddns_cb(ddns_cb->next_op, MDL);
ddns_cb->next_op = NULL;
}
#if defined (DEBUG_DNS_UPDATES)
......@@ -2191,7 +2217,7 @@ ddns_removals(struct lease *lease,
*/
ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
if (ddns_cb != NULL)
ddns_cb_free(ddns_cb, MDL);
destroy_ddns_cb(ddns_cb, MDL);
return (result);
}
......
......@@ -3379,13 +3379,15 @@ statement
.PP
The \fIupdate-static-leases\fR flag, if enabled, causes the DHCP
server to do DNS updates for clients even if those clients are being
assigned their IP address using a \fIfixed-address\fR statement - that
is, the client is being given a static assignment. It is not
recommended because the DHCP server has no way to tell that the update
has been done, and therefore will not delete the record when it is not
in use. Also, the server must attempt the update each time the
client renews its lease, which could have a significant performance
impact in environments that place heavy demands on the DHCP server.
assigned their IP address using a \fIfixed-address\fR or
\fIfixed-address6\fR statement - that is, the client is being given a
static assignment. It is not recommended because the DHCP server has
no way to tell that the update has been done, and therefore will not
delete the record when it is not in use. Also, the server must attempt
the update each time the client renews its lease, which could have a
significant performance impact in environments that place heavy demands
on the DHCP server. This feature is supported for both DHCPv4 and DHCPv6,
and update modes standard or interim. It is disabled by default.
.RE
.PP
The
......
......@@ -185,6 +185,10 @@ static void shorten_lifetimes(struct reply_state *reply, struct iasubopt *lease,
static void write_to_packet(struct reply_state *reply, unsigned ia_cursor);
static const char *iasubopt_plen_str(struct iasubopt *lease);
#ifdef NSUPDATE
static void ddns_update_static6(struct reply_state* reply);
#endif
#ifdef DHCP4o6
/*
* \brief Omapi I/O handler
......@@ -2227,7 +2231,10 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) {
/* Write the lease out in wire-format to the outbound buffer */
write_to_packet(reply, ia_cursor);
#ifdef NSUPDATE
/* Performs DDNS updates if we're configured to do them */
ddns_update_static6(reply);
#endif
if ((reply->buf.reply.msg_type == DHCPV6_REPLY) &&
(reply->on_star.on_commit != NULL)) {
execute_statements(NULL, reply->packet, NULL, NULL,
......@@ -8448,4 +8455,66 @@ const char *iasubopt_plen_str(struct iasubopt *lease) {
return (prefix_buf);
}
#ifdef NSUPDATE
/*
* Initiates DDNS updates for static v6 leases if configured to do so.
*
* The function, which must be called after the IA has been written to the
* packet, adds an iasubopt to the IA for static lease. This is done so we
* have an iasubopt to pass into ddns_updates(). A reference to the IA is
* added to the DDNS control block to ensure it and it's iasubopt remain in
* scope until the update is complete.
*
*/
void ddns_update_static6(struct reply_state* reply) {
struct iasubopt *iasub = NULL;
struct binding_scope *scope = NULL;
struct option_cache *oc = NULL;
oc = lookup_option(&server_universe, reply->opt_state, SV_DDNS_UPDATES);
if ((oc != NULL) &&
(evaluate_boolean_option_cache(NULL, reply->packet, NULL, NULL,
reply->packet->options,
reply->opt_state, NULL,
oc, MDL) == 0)) {
return;
}
oc = lookup_option(&server_universe, reply->opt_state,
SV_UPDATE_STATIC_LEASES);
if ((oc == NULL) ||
(evaluate_boolean_option_cache(NULL, reply->packet,
NULL, NULL,
reply->packet->options,
reply->opt_state, NULL,
oc, MDL) == 0)) {
return;
}
if (iasubopt_allocate(&iasub, MDL) != ISC_R_SUCCESS) {
log_fatal("No memory for iasubopt.");
}
if (ia_add_iasubopt(reply->ia, iasub, MDL) != ISC_R_SUCCESS) {
log_fatal("Could not add iasubopt.");
}
ia_reference(&iasub->ia, reply->ia, MDL);
memcpy(iasub->addr.s6_addr, reply->fixed.data, 16);
iasub->plen = 0;
iasub->prefer = MAX_TIME;
iasub->valid = MAX_TIME;
iasub->static_lease = 1;
if (!binding_scope_allocate(&scope, MDL)) {
log_fatal("Out of memory for binding scope.");
}
binding_scope_reference(&iasub->scope, scope, MDL);
ddns_updates(reply->packet, NULL, NULL, iasub, NULL, reply->opt_state);
}
#endif /* NSUPDATE */
#endif /* DHCPv6 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment