From f1208e796d8e7208055a0afb848f7795f0ea2258 Mon Sep 17 00:00:00 2001 From: Thomas Markwalder Date: Tue, 19 Dec 2017 13:29:32 -0500 Subject: [master] dhcpd (-6) now supports update-static-leases Merges in rt34097. --- server/ddns.c | 50 ++++++++++++++++++++++++++++--------- server/dhcpd.conf.5 | 16 ++++++------ server/dhcpv6.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 20 deletions(-) (limited to 'server') diff --git a/server/ddns.c b/server/ddns.c index 6ac79839..1bd72f6b 100644 --- a/server/ddns.c +++ b/server/ddns.c @@ -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); } diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index cfedf63e..0973f309 100644 --- a/server/dhcpd.conf.5 +++ b/server/dhcpd.conf.5 @@ -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 diff --git a/server/dhcpv6.c b/server/dhcpv6.c index 339766ea..6cdee72c 100644 --- a/server/dhcpv6.c +++ b/server/dhcpv6.c @@ -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 */ -- cgit v1.2.1