summaryrefslogtreecommitdiff
path: root/src/providers/ldap/sdap_dyndns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/ldap/sdap_dyndns.c')
-rw-r--r--src/providers/ldap/sdap_dyndns.c195
1 files changed, 159 insertions, 36 deletions
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index e7fad7ba..ccaec8e0 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -43,6 +43,7 @@ sdap_dyndns_get_addrs_recv(struct tevent_req *req,
struct sdap_dyndns_update_state {
struct tevent_context *ev;
struct be_resolv_ctx *be_res;
+ struct dp_option *opts;
const char *hostname;
const char *dns_zone;
@@ -51,22 +52,29 @@ struct sdap_dyndns_update_state {
int ttl;
struct sss_iface_addr *addresses;
+ struct sss_iface_addr *dns_addrlist;
uint8_t remove_af;
+ bool update_ptr;
bool check_diff;
bool use_server_with_nsupdate;
char *update_msg;
};
static void sdap_dyndns_update_addrs_done(struct tevent_req *subreq);
-static void sdap_dyndns_addrs_check_done(struct tevent_req *subreq);
+static void sdap_dyndns_dns_addrs_done(struct tevent_req *subreq);
+static errno_t sdap_dyndns_addrs_diff(struct sdap_dyndns_update_state *state,
+ bool *_do_update);
static errno_t sdap_dyndns_update_step(struct tevent_req *req);
+static errno_t sdap_dyndns_update_ptr_step(struct tevent_req *req);
static void sdap_dyndns_update_done(struct tevent_req *subreq);
+static void sdap_dyndns_update_ptr_done(struct tevent_req *subreq);
struct tevent_req *
sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_ctx *be_ctx,
+ struct dp_option *opts,
struct sdap_id_ctx *sdap_ctx,
const char *ifname,
const char *hostname,
@@ -86,6 +94,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
return NULL;
}
state->check_diff = check_diff;
+ state->update_ptr = dp_opt_get_bool(opts, DP_OPT_DYNDNS_UPDATE_PTR);
state->hostname = hostname;
state->dns_zone = dns_zone;
state->realm = realm;
@@ -94,6 +103,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
state->ttl = ttl;
state->be_res = be_ctx->be_res;
state->ev = ev;
+ state->opts = opts;
if (ifname) {
/* Unless one family is restricted, just replace all
@@ -155,8 +165,10 @@ sdap_dyndns_update_addrs_done(struct tevent_req *subreq)
return;
}
- if (state->check_diff) {
- /* Check if we need the update at all */
+ if (state->check_diff || state->update_ptr) {
+ /* Check if we need the update at all. In case we are updating the PTR
+ * records as well, we need to know the old addresses to be able to
+ * reliably delete the PTR records */
subreq = nsupdate_get_addrs_send(state, state->ev,
state->be_res, state->hostname);
if (subreq == NULL) {
@@ -164,7 +176,7 @@ sdap_dyndns_update_addrs_done(struct tevent_req *subreq)
tevent_req_error(req, ret);
return;
}
- tevent_req_set_callback(subreq, sdap_dyndns_addrs_check_done, req);
+ tevent_req_set_callback(subreq, sdap_dyndns_dns_addrs_done, req);
return;
}
@@ -178,20 +190,17 @@ sdap_dyndns_update_addrs_done(struct tevent_req *subreq)
}
static void
-sdap_dyndns_addrs_check_done(struct tevent_req *subreq)
+sdap_dyndns_dns_addrs_done(struct tevent_req *subreq)
{
- errno_t ret;
- int i;
struct tevent_req *req;
struct sdap_dyndns_update_state *state;
- char **str_dnslist = NULL, **str_local_list = NULL;
- char **dns_only = NULL, **local_only = NULL;
+ errno_t ret;
bool do_update;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct sdap_dyndns_update_state);
- ret = nsupdate_get_addrs_recv(subreq, state, &str_dnslist);
+ ret = nsupdate_get_addrs_recv(subreq, state, &state->dns_addrlist, NULL);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
@@ -201,14 +210,61 @@ sdap_dyndns_addrs_check_done(struct tevent_req *subreq)
return;
}
+ if (state->check_diff) {
+ ret = sdap_dyndns_addrs_diff(state, &do_update);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not check the diff between DNS "
+ "and current addresses [%d]: %s\n", ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (do_update == false) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("No DNS update needed, addresses did not change\n"));
+ tevent_req_done(req);
+ return;
+ }
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Detected IP addresses change, will perform an update\n"));
+ }
+
+ /* Either we needed the addresses for updating PTR records only or
+ * the addresses have changed (or both) */
+ ret = sdap_dyndns_update_step(req);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not start the update [%d]: %s\n",
+ ret, sss_strerror(ret)));
+ tevent_req_error(req, ret);
+ }
+ return;
+}
+
+static errno_t
+sdap_dyndns_addrs_diff(struct sdap_dyndns_update_state *state, bool *_do_update)
+{
+ errno_t ret;
+ int i;
+ char **str_dnslist = NULL, **str_local_list = NULL;
+ char **dns_only = NULL, **local_only = NULL;
+ bool do_update;
+
+ ret = sss_iface_addr_list_as_str_list(state,
+ state->dns_addrlist, &str_dnslist);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Converting DNS IP addresses to strings failed: [%d]: %s\n",
+ ret, sss_strerror(ret)));
+ return ret;
+ }
+
ret = sss_iface_addr_list_as_str_list(state,
state->addresses, &str_local_list);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
- ("Converting DNS IP addresses to strings failed: [%d]: %s\n",
+ ("Converting local IP addresses to strings failed: [%d]: %s\n",
ret, sss_strerror(ret)));
- tevent_req_error(req, ret);
- return;
+ return ret;
}
/* Compare the lists */
@@ -217,8 +273,7 @@ sdap_dyndns_addrs_check_done(struct tevent_req *subreq)
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("diff_string_lists failed: [%d]: %s\n", ret, sss_strerror(ret)));
- tevent_req_error(req, ret);
- return;
+ return ret;
}
if (dns_only) {
@@ -237,22 +292,8 @@ sdap_dyndns_addrs_check_done(struct tevent_req *subreq)
}
}
- if (do_update) {
- DEBUG(SSSDBG_TRACE_FUNC,
- ("Detected IP addresses change, will perform an update\n"));
- ret = sdap_dyndns_update_step(req);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, ("Could not start the update [%d]: %s\n",
- ret, sss_strerror(ret)));
- tevent_req_error(req, ret);
- }
- return;
- }
-
- DEBUG(SSSDBG_TRACE_FUNC,
- ("No DNS update needed, addresses did not change\n"));
- tevent_req_done(req);
- return;
+ *_do_update = do_update;
+ return EOK;
}
static errno_t
@@ -271,11 +312,11 @@ sdap_dyndns_update_step(struct tevent_req *req)
servername = state->servername;
}
- ret = be_nsupdate_create_msg(state, state->realm, state->dns_zone,
- servername, state->hostname,
- state->ttl, state->remove_af,
- state->addresses,
- &state->update_msg);
+ ret = be_nsupdate_create_fwd_msg(state, state->realm, state->dns_zone,
+ servername, state->hostname,
+ state->ttl, state->remove_af,
+ state->addresses, state->dns_addrlist,
+ &state->update_msg);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Can't get addresses for DNS update\n"));
return ret;
@@ -321,6 +362,88 @@ sdap_dyndns_update_done(struct tevent_req *subreq)
return;
}
+ if (state->update_ptr == false) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("No PTR update requested, done\n"));
+ tevent_req_done(req);
+ return;
+ }
+
+ talloc_free(state->update_msg);
+ ret = sdap_dyndns_update_ptr_step(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ /* Execution will resume in sdap_dyndns_update_ptr_done */
+}
+
+static errno_t
+sdap_dyndns_update_ptr_step(struct tevent_req *req)
+{
+ errno_t ret;
+ struct sdap_dyndns_update_state *state;
+ const char *servername;
+ struct tevent_req *subreq;
+
+ state = tevent_req_data(req, struct sdap_dyndns_update_state);
+
+ servername = NULL;
+ if (state->use_server_with_nsupdate == true &&
+ state->servername) {
+ servername = state->servername;
+ }
+
+ ret = be_nsupdate_create_ptr_msg(state, state->realm,
+ servername, state->hostname,
+ state->ttl, state->remove_af,
+ state->addresses, state->dns_addrlist,
+ &state->update_msg);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Can't get addresses for DNS update\n"));
+ return ret;
+ }
+
+ /* Fork a child process to perform the DNS update */
+ subreq = be_nsupdate_send(state, state->ev,
+ state->update_msg);
+ if (subreq == NULL) {
+ return EIO;
+ }
+
+ tevent_req_set_callback(subreq, sdap_dyndns_update_ptr_done, req);
+ return EOK;
+}
+
+static void
+sdap_dyndns_update_ptr_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ int child_status;
+ struct tevent_req *req;
+ struct sdap_dyndns_update_state *state;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_dyndns_update_state);
+
+ ret = be_nsupdate_recv(subreq, &child_status);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ /* If the update didn't succeed, we can retry using the server name */
+ if (state->use_server_with_nsupdate == false && state->servername &&
+ WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
+ state->use_server_with_nsupdate = true;
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("nsupdate failed, retrying with server name\n"));
+ ret = sdap_dyndns_update_ptr_step(req);
+ if (ret == EOK) {
+ return;
+ }
+ }
+
+ tevent_req_error(req, ret);
+ return;
+ }
+
tevent_req_done(req);
}