Commit f1208e79 authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

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

    Merges in rt34097.
parent 700e3fca
...@@ -284,6 +284,18 @@ dhcp-users@lists.isc.org. ...@@ -284,6 +284,18 @@ dhcp-users@lists.isc.org.
- Corrected some minor coverity issues: CID 1426059, 1426058, and 1426057. - Corrected some minor coverity issues: CID 1426059, 1426058, and 1426057.
[ISC-Bugs #46836] [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): Changes since 4.3.6 (Bugs):
- Corrected an issue where the server would return a client's previously - 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) ...@@ -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. */ /* 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 " log_error("Impossible memory leak at %s:%d (attempt to free "
"DDNS Control Block before transaction).", MDL); "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); dfree(ddns_cb, file, line);
} }
......
...@@ -1646,6 +1646,7 @@ struct iasubopt { ...@@ -1646,6 +1646,7 @@ struct iasubopt {
/* space for the on * executable statements */ /* space for the on * executable statements */
struct on_star on_star; struct on_star on_star;
int static_lease;
}; };
struct ia_xx { struct ia_xx {
...@@ -1818,6 +1819,7 @@ typedef struct dhcp_ddns_cb { ...@@ -1818,6 +1819,7 @@ typedef struct dhcp_ddns_cb {
dns_rdataclass_t dhcid_class; dns_rdataclass_t dhcid_class;
dns_rdataclass_t other_dhcid_class; dns_rdataclass_t other_dhcid_class;
char *lease_tag; char *lease_tag;
struct ia_xx *fixed6_ia;
} dhcp_ddns_cb_t; } dhcp_ddns_cb_t;
extern struct ipv6_pool **pools; extern struct ipv6_pool **pools;
......
...@@ -57,6 +57,25 @@ static void copy_conflict_flags(u_int16_t *target, u_int16_t source); ...@@ -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); 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 /* DN: No way of checking that there is enough space in a data_string's
buffer. Be certain to allocate enough! buffer. Be certain to allocate enough!
TL: This is why the expression evaluation code allocates a *new* 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, ...@@ -153,6 +172,13 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
scope = &(lease6->scope); scope = &(lease6->scope);
memcpy(ddns_cb->address.iabuf, lease6->addr.s6_addr, 16); memcpy(ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
ddns_cb->address.len = 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)); memset (&d1, 0, sizeof(d1));
...@@ -754,7 +780,7 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, ...@@ -754,7 +780,7 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
* Final cleanup. * Final cleanup.
*/ */
if (ddns_cb != NULL) { if (ddns_cb != NULL) {
ddns_cb_free(ddns_cb, MDL); destroy_ddns_cb(ddns_cb, MDL);
} }
data_string_forget(&d1, MDL); data_string_forget(&d1, MDL);
...@@ -1296,7 +1322,7 @@ ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb, ...@@ -1296,7 +1322,7 @@ ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
} }
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 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 * A single DDNS operation may require several calls depending on
* the current state as the prerequisites for the first message * the current state as the prerequisites for the first message
...@@ -1362,7 +1388,7 @@ ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb, ...@@ -1362,7 +1388,7 @@ ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result); 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; return;
} }
...@@ -1476,7 +1502,7 @@ ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb, ...@@ -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_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 * A single DDNS operation may require several calls depending on
* the current state as the prerequisites for the first message * the current state as the prerequisites for the first message
...@@ -1551,7 +1577,7 @@ ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb, ...@@ -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_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 * A single DDNS operation may require several calls depending on
* the current state as the prerequisites for the first message * the current state as the prerequisites for the first message
...@@ -1636,7 +1662,7 @@ ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb, ...@@ -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_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 * A single DDNS operation may require several calls depending on
* the current state as the prerequisites for the first message * the current state as the prerequisites for the first message
...@@ -1694,7 +1720,7 @@ ddns_fwd_srv_connector(struct lease *lease, ...@@ -1694,7 +1720,7 @@ ddns_fwd_srv_connector(struct lease *lease,
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL); ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
} else { } else {
ddns_cb_free(ddns_cb, MDL); destroy_ddns_cb(ddns_cb, MDL);
} }
return; return;
...@@ -1762,7 +1788,7 @@ ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb, ...@@ -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_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult); 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; return;
} }
...@@ -1866,7 +1892,7 @@ ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb, ...@@ -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_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult); 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, ...@@ -1952,7 +1978,7 @@ ddns_removals(struct lease *lease,
} else { } else {
/* Remvoval, check and remove updates */ /* Remvoval, check and remove updates */
if (ddns_cb->next_op != NULL) { 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; ddns_cb->next_op = NULL;
} }
#if defined (DEBUG_DNS_UPDATES) #if defined (DEBUG_DNS_UPDATES)
...@@ -1980,7 +2006,7 @@ ddns_removals(struct lease *lease, ...@@ -1980,7 +2006,7 @@ ddns_removals(struct lease *lease,
} else { } else {
/* Remvoval, check and remove updates */ /* Remvoval, check and remove updates */
if (ddns_cb->next_op != NULL) { 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; ddns_cb->next_op = NULL;
} }
#if defined (DEBUG_DNS_UPDATES) #if defined (DEBUG_DNS_UPDATES)
...@@ -2191,7 +2217,7 @@ ddns_removals(struct lease *lease, ...@@ -2191,7 +2217,7 @@ ddns_removals(struct lease *lease,
*/ */
ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add); ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
if (ddns_cb != NULL) if (ddns_cb != NULL)
ddns_cb_free(ddns_cb, MDL); destroy_ddns_cb(ddns_cb, MDL);
return (result); return (result);
} }
......
...@@ -3379,13 +3379,15 @@ statement ...@@ -3379,13 +3379,15 @@ statement
.PP .PP
The \fIupdate-static-leases\fR flag, if enabled, causes the DHCP The \fIupdate-static-leases\fR flag, if enabled, causes the DHCP
server to do DNS updates for clients even if those clients are being server to do DNS updates for clients even if those clients are being
assigned their IP address using a \fIfixed-address\fR statement - that assigned their IP address using a \fIfixed-address\fR or
is, the client is being given a static assignment. It is not \fIfixed-address6\fR statement - that is, the client is being given a
recommended because the DHCP server has no way to tell that the update static assignment. It is not recommended because the DHCP server has
has been done, and therefore will not delete the record when it is not no way to tell that the update has been done, and therefore will not
in use. Also, the server must attempt the update each time the delete the record when it is not in use. Also, the server must attempt
client renews its lease, which could have a significant performance the update each time the client renews its lease, which could have a
impact in environments that place heavy demands on the DHCP server. 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 .RE
.PP .PP
The The
......
...@@ -185,6 +185,10 @@ static void shorten_lifetimes(struct reply_state *reply, struct iasubopt *lease, ...@@ -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 void write_to_packet(struct reply_state *reply, unsigned ia_cursor);
static const char *iasubopt_plen_str(struct iasubopt *lease); static const char *iasubopt_plen_str(struct iasubopt *lease);
#ifdef NSUPDATE
static void ddns_update_static6(struct reply_state* reply);
#endif
#ifdef DHCP4o6 #ifdef DHCP4o6
/* /*
* \brief Omapi I/O handler * \brief Omapi I/O handler
...@@ -2227,7 +2231,10 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) { ...@@ -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 the lease out in wire-format to the outbound buffer */
write_to_packet(reply, ia_cursor); 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) && if ((reply->buf.reply.msg_type == DHCPV6_REPLY) &&
(reply->on_star.on_commit != NULL)) { (reply->on_star.on_commit != NULL)) {
execute_statements(NULL, reply->packet, NULL, NULL, execute_statements(NULL, reply->packet, NULL, NULL,
...@@ -8448,4 +8455,66 @@ const char *iasubopt_plen_str(struct iasubopt *lease) { ...@@ -8448,4 +8455,66 @@ const char *iasubopt_plen_str(struct iasubopt *lease) {
return (prefix_buf); 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 */ #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