diff options
Diffstat (limited to 'server/ddns.c')
-rw-r--r-- | server/ddns.c | 230 |
1 files changed, 185 insertions, 45 deletions
diff --git a/server/ddns.c b/server/ddns.c index 2387e04..0c93073 100644 --- a/server/ddns.c +++ b/server/ddns.c @@ -3,7 +3,7 @@ Dynamic DNS updates. */ /* - * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2000-2003 by Internet Software Consortium * @@ -80,7 +80,6 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, struct option_cache *oc; int s1, s2; int result = 0; - isc_result_t rcode1 = ISC_R_SUCCESS; int server_updates_a = 1; //int server_updates_ptr = 1; struct buffer *bp = (struct buffer *)0; @@ -103,12 +102,12 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, if (lease != NULL) { if ((old != NULL) && (old->ddns_cb != NULL)) { - ddns_cancel(old->ddns_cb); + ddns_cancel(old->ddns_cb, MDL); old->ddns_cb = NULL; } } else if (lease6 != NULL) { if ((old6 != NULL) && (old6->ddns_cb != NULL)) { - ddns_cancel(old6->ddns_cb); + ddns_cancel(old6->ddns_cb, MDL); old6->ddns_cb = NULL; } } else { @@ -123,8 +122,12 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, if (ddns_cb == NULL) { return(0); } - /* assume that we shall update both the A and ptr records */ - ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR; + /* + * Assume that we shall update both the A and ptr records and, + * as this is an update, set the active flag + */ + ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR | + DDNS_ACTIVE_LEASE; /* * For v4 we flag static leases so we don't try @@ -329,7 +332,7 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, /* If desired do the removals */ if (do_remove != 0) { - (void) ddns_removals(lease, lease6, NULL); + (void) ddns_removals(lease, lease6, NULL, ISC_TRUE); } goto out; } @@ -531,7 +534,11 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, * the ddns messages. Currently we don't. */ if (do_remove) { - rcode1 = ddns_removals(lease, lease6, ddns_cb); + /* + * We should log a more specific error closer to the actual + * error if we want one. ddns_removal failure not logged here. + */ + (void) ddns_removals(lease, lease6, ddns_cb, ISC_TRUE); } else { ddns_fwd_srv_connector(lease, lease6, scope, ddns_cb, @@ -709,7 +716,7 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, return result; } -/* +/*%< * Utility function to update text strings within a lease. * * The first issue is to find the proper scope. Sometimes we shall be @@ -719,6 +726,19 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, * Lastly, if we needed to find the scope we write it out, if we used a * scope that was passed as an argument we don't write it, assuming that * our caller (or his ...) will do the write. + * + *\li ddns_cb - the control block for the DDNS request + * + *\li inscope - a pointer to the scope to update. This may be NULL + * in which case we use the control block to find the lease and + * then the scope. + * + * Returns + *\li ISC_R_SUCCESS + * + *\li ISC_R_FAILURE - The routine was unable to find an expected scope. + * In some cases (static and inactive leases) we don't expect a scope + * and return success. */ isc_result_t @@ -739,6 +759,14 @@ ddns_update_lease_text(dhcp_ddns_cb_t *ddns_cb, if (ddns_cb->flags & DDNS_STATIC_LEASE) return (ISC_R_SUCCESS); + /* + * If we are processing an expired or released v6 lease + * or some types of v4 leases we don't actually have a + * scope to update + */ + if ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0) + return (ISC_R_SUCCESS); + if (inscope != NULL) { scope = inscope; } else if (ddns_cb->address.len == 4) { @@ -1084,6 +1112,15 @@ ddns_update_lease_ptr(struct lease *lease, return (ISC_R_SUCCESS); } + /* + * If we are processing an expired or released v6 lease + * we don't actually have a lease to update + */ + if ((ddns_cb->address.len == 16) && + ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) { + return (ISC_R_SUCCESS); + } + if (lease != NULL) { safe_lease_update(lease, ddns_cb, ddns_cb_set, file, line); @@ -1131,7 +1168,7 @@ ddns_update_lease_ptr(struct lease *lease, ISC_R_SUCCESS) && (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS)) { - inet_ntop(AF_INET6, &lease6->addr, addrbuf, + inet_ntop(AF_INET6, &addr, addrbuf, MAX_ADDRESS_STRING_LEN); log_error("%s(%d): Pool for lease %s not found.", file, line, addrbuf); @@ -1151,7 +1188,7 @@ ddns_update_lease_ptr(struct lease *lease, find_lease6->ddns_cb = ddns_cb_set; iasubopt_dereference(&find_lease6, MDL); } else { - inet_ntop(AF_INET6, &lease6->addr, addrbuf, + inet_ntop(AF_INET6, &addr, addrbuf, MAX_ADDRESS_STRING_LEN); log_error("%s(%d): Lease %s not found within pool.", file, line, addrbuf); @@ -1240,6 +1277,11 @@ ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb, /* trigger any add operation */ result = ISC_R_SUCCESS; +#if defined (DEBUG_DNS_UPDATES) + log_info("DDNS: removed map or no reverse map to remove %.*s", + (int)ddns_cb->rev_name.len, + (const char *)ddns_cb->rev_name.data); +#endif break; default: @@ -1314,7 +1356,7 @@ ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb, ddns_cb->state = DDNS_STATE_ADD_PTR; ddns_cb->cur_func = ddns_ptr_add; - result = ddns_modify_ptr(ddns_cb); + result = ddns_modify_ptr(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } @@ -1387,12 +1429,11 @@ ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb, ddns_cb->state = DDNS_STATE_ADD_PTR; ddns_cb->cur_func = ddns_ptr_add; - result = ddns_modify_ptr(ddns_cb); + result = ddns_modify_ptr(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } } - break; case DNS_R_YXDOMAIN: @@ -1400,11 +1441,10 @@ ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb, ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID; ddns_cb->cur_func = ddns_fwd_srv_add2; - result = ddns_modify_fwd(ddns_cb); + result = ddns_modify_fwd(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } - break; default: @@ -1455,12 +1495,12 @@ ddns_fwd_srv_connector(struct lease *lease, if (ddns_cb->flags & DDNS_UPDATE_ADDR) { ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN; ddns_cb->cur_func = ddns_fwd_srv_add1; - result = ddns_modify_fwd(ddns_cb); + result = ddns_modify_fwd(ddns_cb, MDL); } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) && (ddns_cb->rev_name.len != 0)) { ddns_cb->state = DDNS_STATE_ADD_PTR; ddns_cb->cur_func = ddns_ptr_add; - result = ddns_modify_ptr(ddns_cb); + result = ddns_modify_ptr(ddns_cb, MDL); } else { ddns_update_lease_text(ddns_cb, inscope); } @@ -1505,7 +1545,7 @@ ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb, ddns_cb->state = DDNS_STATE_REM_PTR; ddns_cb->cur_func = ddns_ptr_remove; - eresult = ddns_modify_ptr(ddns_cb); + eresult = ddns_modify_ptr(ddns_cb, MDL); if (eresult == ISC_R_SUCCESS) { return; } @@ -1545,7 +1585,7 @@ ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb, /* Do the second step of the FWD removal */ ddns_cb->state = DDNS_STATE_REM_FW_NXRR; ddns_cb->cur_func = ddns_fwd_srv_rem2; - result = ddns_modify_fwd(ddns_cb); + result = ddns_modify_fwd(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } @@ -1555,6 +1595,10 @@ ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb, case DNS_R_NXDOMAIN: ddns_update_lease_text(ddns_cb, NULL); +#if defined (DEBUG_DNS_UPDATES) + log_info("DDNS: no forward map to remove. %p", ddns_cb); +#endif + /* Do the next operation */ if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { /* if we have zone information get rid of it */ @@ -1565,7 +1609,7 @@ ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb, ddns_cb->state = DDNS_STATE_REM_PTR; ddns_cb->cur_func = ddns_ptr_remove; - result = ddns_modify_ptr(ddns_cb); + result = ddns_modify_ptr(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } @@ -1585,39 +1629,124 @@ ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb, ddns_cb_free(ddns_cb, MDL); } - -/* +/*%< * Remove relevant entries from DNS. * - * Return values: - * 0 - badness occurred and we weren't able to do what was wanted - * 1 - we were able to do stuff but it's in progress + * \li lease - lease to start with if this is for v4 + * + * \li lease6 - lease to start with if this is for v6 + * + * \li add_ddns_cb - control block for additional DDNS work. This + * is used when the code is going to add a DDNS entry after removing + * the current entry. + * + * \li active - indication about the status of the lease. It is + * ISC_TRUE if the lease is still active, and FALSE if the lease + * is inactive. This is used to indicate if the lease is inactive or going + * to inactive so we can avoid trying to update the lease with cb pointers + * and text information if it isn't useful. + * + * Returns + * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted + * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress + * * in both cases any additional block has been passed on to it's handler */ -int +isc_result_t ddns_removals(struct lease *lease, struct iasubopt *lease6, - dhcp_ddns_cb_t *add_ddns_cb) + dhcp_ddns_cb_t *add_ddns_cb, + isc_boolean_t active) { isc_result_t rcode, execute_add = ISC_R_FAILURE; struct binding_scope **scope = NULL; - int result = 0; + isc_result_t result = ISC_R_FAILURE; dhcp_ddns_cb_t *ddns_cb = NULL; struct data_string leaseid; /* - * Cancel any outstanding requests. When called - * from within the DNS code we probably will have - * already done the cancel but if called from outside - * - for example as part of a lease expiry - we won't. + * See if we need to cancel an outstanding request. Mostly this is + * used to handle the case where this routine is called twice for + * the same release or abandon event. + * + * When called from the dns code as part of an update request + * (add_ddns_cb != NULL) any outstanding requests will have already + * been cancelled. + * + * If the new request is just a removal and we have an outstanding + * request we have several options: + * + * - we are doing an update or we are doing a removal and the active + * flag has changed from TRUE to FALSE. In these cases we need to + * cancel the old request and start the new one. + * + * - other wise we are doing a removal with the active flag unchanged. + * In this case we can let the current removal continue and do not need + * to start a new one. If the old request included an update to be + * done after the removal we need to kill the update part of the + * request. */ - if ((lease != NULL) && (lease->ddns_cb != NULL)) { - ddns_cancel(lease->ddns_cb); - lease->ddns_cb = NULL; - } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) { - ddns_cancel(lease6->ddns_cb); - lease6->ddns_cb = NULL; + + if (add_ddns_cb == NULL) { + if ((lease != NULL) && (lease->ddns_cb != NULL)) { + ddns_cb = lease->ddns_cb; + + /* + * Is the old request an update or did the + * the active flag change? + */ + if (((ddns_cb->state == DDNS_STATE_ADD_PTR) || + (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) || + (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) || + ((active == ISC_FALSE) && + ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) { + /* Cancel the current request */ + ddns_cancel(lease->ddns_cb, MDL); + lease->ddns_cb = NULL; + } else { + /* Remvoval, check and remove updates */ + if (ddns_cb->next_op != NULL) { + ddns_cb_free(ddns_cb->next_op, MDL); + ddns_cb->next_op = NULL; + } +#if defined (DEBUG_DNS_UPDATES) + log_info("DDNS %s(%d): removal already in " + "progress new ddns_cb=%p", + MDL, ddns_cb); +#endif + return (ISC_R_SUCCESS); + } + } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) { + ddns_cb = lease6->ddns_cb; + + /* + * Is the old request an update or did the + * the active flag change? + */ + if (((ddns_cb->state == DDNS_STATE_ADD_PTR) || + (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) || + (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) || + ((active == ISC_FALSE) && + ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) { + /* Cancel the current request */ + ddns_cancel(lease6->ddns_cb, MDL); + lease6->ddns_cb = NULL; + } else { + /* Remvoval, check and remove updates */ + if (ddns_cb->next_op != NULL) { + ddns_cb_free(ddns_cb->next_op, MDL); + ddns_cb->next_op = NULL; + } +#if defined (DEBUG_DNS_UPDATES) + log_info("DDNS %s(%d): removal already in " + "progress new ddns_cb=%p", + MDL, ddns_cb); +#endif + return (ISC_R_SUCCESS); + } + } + ddns_cb = NULL; } /* allocate our control block */ @@ -1643,6 +1772,17 @@ ddns_removals(struct lease *lease, } else goto cleanup; + /* + * Set the flag bit if the lease is active, that is it isn't + * expired or released. This is used to determine if we need + * to update the scope information for both v4 and v6 and + * the lease information for v6 when the response + * from the DNS code is processed. + */ + if (active == ISC_TRUE) { + ddns_cb->flags |= DDNS_ACTIVE_LEASE; + } + /* No scope implies that DDNS has not been performed for this lease. */ if (*scope == NULL) goto cleanup; @@ -1727,11 +1867,11 @@ ddns_removals(struct lease *lease, ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID; ddns_cb->cur_func = ddns_fwd_srv_rem1; - rcode = ddns_modify_fwd(ddns_cb); + rcode = ddns_modify_fwd(ddns_cb, MDL); if (rcode == ISC_R_SUCCESS) { ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL); - return(1); + return (ISC_R_SUCCESS); } /* @@ -1764,14 +1904,14 @@ ddns_removals(struct lease *lease, add_ddns_cb = NULL; } else { - result = 1; + result = ISC_R_SUCCESS; } - rcode = ddns_modify_ptr(ddns_cb); + rcode = ddns_modify_ptr(ddns_cb, MDL); if (rcode == ISC_R_SUCCESS) { ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL); - return(result); + return (result); } /* We weren't able to process the request tag the @@ -1791,7 +1931,7 @@ ddns_removals(struct lease *lease, if (ddns_cb != NULL) ddns_cb_free(ddns_cb, MDL); - return(result); + return (result); } #endif /* NSUPDATE */ |