aboutsummaryrefslogtreecommitdiff
path: root/server/ddns.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/ddns.c')
-rw-r--r--server/ddns.c230
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 */