Merges in rt34097.
- 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
}
/* 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);
}
/* space for the on * executable statements */
struct on_star on_star;
+ int static_lease;
};
struct ia_xx {
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;
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*
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));
* Final cleanup.
*/
if (ddns_cb != NULL) {
- ddns_cb_free(ddns_cb, MDL);
+ destroy_ddns_cb(ddns_cb, MDL);
}
data_string_forget(&d1, 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
* the current state as the prerequisites for the first message
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;
}
}
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
}
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
}
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
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;
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;
}
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);
}
/*%<
} 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)
} 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)
*/
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);
}
.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
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
/* 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,
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 */