summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/config/SSSDConfig/__init__.py.in1
-rwxr-xr-xsrc/config/SSSDConfigTest.py2
-rw-r--r--src/config/etc/sssd.api.conf1
-rw-r--r--src/man/sssd-ipa.5.xml20
-rw-r--r--src/providers/dp_dyndns.c327
-rw-r--r--src/providers/dp_dyndns.h28
-rw-r--r--src/providers/ipa/ipa_dyndns.c4
-rw-r--r--src/providers/ipa/ipa_opts.h1
-rw-r--r--src/providers/ldap/sdap_dyndns.c195
-rw-r--r--src/providers/ldap/sdap_dyndns.h1
-rw-r--r--src/resolv/async_resolv.c4
-rw-r--r--src/resolv/async_resolv.h7
12 files changed, 463 insertions, 128 deletions
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 003153d01..79bf6aa4e 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -129,6 +129,7 @@ option_strings = {
'dyndns_ttl' : _("The TTL to apply to the client's DNS entry after updating it"),
'dyndns_iface' : _("The interface whose IP should be used for dynamic DNS updates"),
'dyndns_refresh_interval' : _("How often to periodically update the client's DNS entry"),
+ 'dyndns_update_ptr' : _("Whether the provider should explicitly update the PTR record as well"),
# [provider/ipa]
'ipa_domain' : _('IPA domain'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index 18328d060..7add141ce 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -511,6 +511,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
'dyndns_ttl',
'dyndns_iface',
'dyndns_refresh_interval',
+ 'dyndns_update_ptr',
'override_gid',
'case_sensitive',
'override_homedir',
@@ -858,6 +859,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
'dyndns_ttl',
'dyndns_iface',
'dyndns_refresh_interval',
+ 'dyndns_update_ptr',
'override_gid',
'case_sensitive',
'override_homedir',
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index b09cbd187..396063b4f 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -126,6 +126,7 @@ dyndns_update = bool, None, false
dyndns_ttl = int, None, false
dyndns_iface = str, None, false
dyndns_refresh_interval = int, None, false
+dyndns_update_ptr = bool, None, false
# Special providers
[provider/permit]
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index 426e9a5bb..21a280479 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -220,6 +220,26 @@
</varlistentry>
<varlistentry>
+ <term>dyndns_update_ptr (bool)</term>
+ <listitem>
+ <para>
+ Whether the PTR record should also be explicitly
+ updated when updating the client's DNS records.
+ Applicable only when dyndns_update is true.
+ </para>
+ <para>
+ This options should be False in most IPA
+ deployments as the IPA server generates the
+ PTR records automatically when forward records
+ are changed.
+ </para>
+ <para>
+ Default: False (disabled)
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>ipa_hbac_search_base (string)</term>
<listitem>
<para>
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 337817fc7..79701c629 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -262,64 +262,14 @@ done:
return ret;
}
-errno_t
-be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm,
- const char *zone, const char *servername,
- const char *hostname, const unsigned int ttl,
- uint8_t remove_af, struct sss_iface_addr *addresses,
- char **_update_msg)
+static char *
+nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
+ const char *hostname, int ttl, uint8_t remove_af)
{
- int ret;
- char *realm_directive;
+ struct sss_iface_addr *new_record;
char ip_addr[INET6_ADDRSTRLEN];
const char *ip;
- struct sss_iface_addr *new_record;
- char *update_msg;
- TALLOC_CTX *tmp_ctx;
-
- /* in some cases realm could have been NULL if we weren't using TSIG */
- if (zone == NULL || hostname == NULL) {
- return EINVAL;
- }
-
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) return ENOMEM;
-
-#ifdef HAVE_NSUPDATE_REALM
- realm_directive = talloc_asprintf(tmp_ctx, "realm %s\n", realm);
-#else
- realm_directive = talloc_asprintf(tmp_ctx, "");
-#endif
- if (!realm_directive) {
- ret = ENOMEM;
- goto done;
- }
-
- /* The realm_directive would now either contain an empty string or be
- * completely empty so we don't need to add another newline here
- */
- if (servername) {
- DEBUG(SSSDBG_FUNC_DATA,
- ("Creating update message for server [%s], realm [%s] "
- "and zone [%s].\n", servername, realm, zone));
-
- /* Add the server, realm and zone headers */
- update_msg = talloc_asprintf(tmp_ctx, "server %s\n%szone %s.\n",
- servername, realm_directive, zone);
- } else {
- DEBUG(SSSDBG_FUNC_DATA,
- ("Creating update message for realm [%s] and zone [%s].\n",
- realm, zone));
-
- /* Add the realm and zone headers */
- update_msg = talloc_asprintf(tmp_ctx, "%szone %s.\n",
- realm_directive, zone);
- }
- talloc_free(realm_directive);
- if (update_msg == NULL) {
- ret = ENOMEM;
- goto done;
- }
+ errno_t ret;
/* Remove existing entries as needed */
if (remove_af & DYNDNS_REMOVE_A) {
@@ -327,8 +277,7 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm,
"update delete %s. in A\nsend\n",
hostname);
if (update_msg == NULL) {
- ret = ENOMEM;
- goto done;
+ return NULL;
}
}
if (remove_af & DYNDNS_REMOVE_AAAA) {
@@ -336,8 +285,7 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm,
"update delete %s. in AAAA\nsend\n",
hostname);
if (update_msg == NULL) {
- ret = ENOMEM;
- goto done;
+ return NULL;
}
}
@@ -349,7 +297,9 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm,
ip_addr, INET6_ADDRSTRLEN);
if (ip == NULL) {
ret = errno;
- goto done;
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("inet_ntop failed [%d]: %s\n", ret, strerror(ret)));
+ return NULL;
}
break;
@@ -359,14 +309,15 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm,
ip_addr, INET6_ADDRSTRLEN);
if (ip == NULL) {
ret = errno;
- goto done;
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("inet_ntop failed [%d]: %s\n", ret, strerror(ret)));
+ return NULL;
}
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown address family\n"));
- ret = EINVAL;
- goto done;
+ return NULL;
}
/* Format the record update */
@@ -376,12 +327,179 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm,
new_record->addr->ss_family == AF_INET ? "A" : "AAAA",
ip_addr);
if (update_msg == NULL) {
+ return NULL;
+ }
+
+ }
+
+ return talloc_asprintf_append(update_msg, "send\n");
+}
+
+static char *
+nsupdate_msg_add_ptr(char *update_msg, struct sss_iface_addr *addresses,
+ const char *hostname, int ttl, uint8_t remove_af,
+ struct sss_iface_addr *old_addresses)
+{
+ struct sss_iface_addr *new_record, *old_record;
+ char *strptr;
+ uint8_t *addr;
+
+ DLIST_FOR_EACH(old_record, old_addresses) {
+ switch(old_record->addr->ss_family) {
+ case AF_INET:
+ if (!(remove_af & DYNDNS_REMOVE_A)) {
+ continue;
+ }
+ addr = (uint8_t *) &((struct sockaddr_in *) old_record->addr)->sin_addr;
+ break;
+ case AF_INET6:
+ if (!(remove_af & DYNDNS_REMOVE_AAAA)) {
+ continue;
+ }
+ addr = (uint8_t *) &((struct sockaddr_in6 *) old_record->addr)->sin6_addr;
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown address family\n"));
+ return NULL;
+ }
+
+ strptr = resolv_get_string_ptr_address(update_msg, old_record->addr->ss_family,
+ addr);
+ if (strptr == NULL) {
+ return NULL;
+ }
+
+ /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
+ update_msg = talloc_asprintf_append(update_msg,
+ "update delete %s in PTR\n", strptr);
+ talloc_free(strptr);
+ if (update_msg == NULL) {
+ return NULL;
+ }
+ }
+
+ /* example: update add 11.78.16.10.in-addr.arpa. 85000 in PTR testvm.example.com */
+ DLIST_FOR_EACH(new_record, addresses) {
+ switch(new_record->addr->ss_family) {
+ case AF_INET:
+ addr = (uint8_t *) &((struct sockaddr_in *) new_record->addr)->sin_addr;
+ break;
+ case AF_INET6:
+ addr = (uint8_t *) &((struct sockaddr_in6 *) new_record->addr)->sin6_addr;
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown address family\n"));
+ return NULL;
+ }
+
+ strptr = resolv_get_string_ptr_address(update_msg, new_record->addr->ss_family,
+ addr);
+ if (strptr == NULL) {
+ return NULL;
+ }
+
+ /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
+ update_msg = talloc_asprintf_append(update_msg,
+ "update add %s %d in PTR %s.\n",
+ strptr, ttl, hostname);
+ talloc_free(strptr);
+ if (update_msg == NULL) {
+ return NULL;
+ }
+ }
+
+ return talloc_asprintf_append(update_msg, "send\n");
+}
+
+static char *
+nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm,
+ const char *servername)
+{
+ char *realm_directive;
+ char *update_msg;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) return NULL;
+
+#ifdef HAVE_NSUPDATE_REALM
+ realm_directive = talloc_asprintf(tmp_ctx, "realm %s\n", realm);
+#else
+ realm_directive = talloc_asprintf(tmp_ctx, "");
+#endif
+ if (!realm_directive) {
+ goto fail;
+ }
+
+ /* The realm_directive would now either contain an empty string or be
+ * completely empty so we don't need to add another newline here
+ */
+ if (servername) {
+ DEBUG(SSSDBG_FUNC_DATA,
+ ("Creating update message for server [%s] and realm [%s]\n.",
+ servername, realm));
+
+ /* Add the server, realm and headers */
+ update_msg = talloc_asprintf(tmp_ctx, "server %s\n%s",
+ servername, realm_directive);
+ } else {
+ DEBUG(SSSDBG_FUNC_DATA,
+ ("Creating update message for realm [%s].\n", realm));
+ /* Add the realm headers */
+ update_msg = talloc_asprintf(tmp_ctx, "%s", realm_directive);
+ }
+ talloc_free(realm_directive);
+ if (update_msg == NULL) {
+ goto fail;
+ }
+
+ update_msg = talloc_steal(mem_ctx, update_msg);
+ talloc_free(tmp_ctx);
+ return update_msg;
+
+fail:
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+errno_t
+be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
+ const char *zone, const char *servername,
+ const char *hostname, const unsigned int ttl,
+ uint8_t remove_af, struct sss_iface_addr *addresses,
+ struct sss_iface_addr *old_addresses,
+ char **_update_msg)
+{
+ int ret;
+ char *update_msg;
+ TALLOC_CTX *tmp_ctx;
+
+ /* in some cases realm could have been NULL if we weren't using TSIG */
+ if (hostname == NULL) {
+ return EINVAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) return ENOMEM;
+
+ update_msg = nsupdate_msg_create_common(tmp_ctx, realm, servername);
+ if (update_msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (zone) {
+ DEBUG(SSSDBG_FUNC_DATA,
+ ("Setting the zone explicitly to [%s].\n", zone));
+ update_msg = talloc_asprintf_append(update_msg, "zone %s.\n", zone);
+ if (update_msg == NULL) {
ret = ENOMEM;
goto done;
}
}
- update_msg = talloc_asprintf_append(update_msg, "send\n");
+ update_msg = nsupdate_msg_add_fwd(update_msg, addresses, hostname,
+ ttl, remove_af);
if (update_msg == NULL) {
ret = ENOMEM;
goto done;
@@ -400,6 +518,47 @@ done:
return ret;
}
+errno_t
+be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
+ const char *servername, const char *hostname,
+ const unsigned int ttl, uint8_t remove_af,
+ struct sss_iface_addr *addresses,
+ struct sss_iface_addr *old_addresses,
+ char **_update_msg)
+{
+ errno_t ret;
+ char *update_msg;
+
+ /* in some cases realm could have been NULL if we weren't using TSIG */
+ if (hostname == NULL) {
+ return EINVAL;
+ }
+
+ update_msg = nsupdate_msg_create_common(mem_ctx, realm, servername);
+ if (update_msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ update_msg = nsupdate_msg_add_ptr(update_msg, addresses, hostname,
+ ttl, remove_af, old_addresses);
+ if (update_msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ (" -- Begin nsupdate message -- \n%s",
+ update_msg));
+ DEBUG(SSSDBG_TRACE_FUNC,
+ (" -- End nsupdate message -- \n"));
+
+ ret = ERR_OK;
+ *_update_msg = talloc_steal(mem_ctx, update_msg);
+done:
+ return ret;
+}
+
struct nsupdate_get_addrs_state {
struct tevent_context *ev;
struct be_resolv_ctx *be_res;
@@ -407,7 +566,7 @@ struct nsupdate_get_addrs_state {
const char *hostname;
/* Use sss_addr in this request */
- char **addrlist;
+ struct sss_iface_addr *addrlist;
size_t count;
};
@@ -472,6 +631,7 @@ nsupdate_get_addrs_done(struct tevent_req *subreq)
struct nsupdate_get_addrs_state *state = tevent_req_data(req,
struct nsupdate_get_addrs_state);
struct resolv_hostent *rhostent;
+ struct sss_iface_addr *addr;
int i;
int resolv_status;
@@ -509,25 +669,25 @@ nsupdate_get_addrs_done(struct tevent_req *subreq)
count = 0;
}
- state->addrlist = talloc_realloc(state, state->addrlist, char *,
- state->count + count + 1);
- if (!state->addrlist) {
- ret = ENOMEM;
- goto done;
- }
-
for (i=0; i < count; i++) {
- state->addrlist[state->count + i] = \
- resolv_get_string_address_index(state->addrlist,
- rhostent, i);
+ addr = talloc(state, struct sss_iface_addr);
+ if (addr == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
- if (state->addrlist[state->count + i] == NULL) {
+ addr->addr = resolv_get_sockaddr_address_index(addr, rhostent, 0, i);
+ if (addr == NULL) {
ret = ENOMEM;
goto done;
}
+
+ if (state->addrlist) {
+ talloc_steal(state->addrlist, addr);
+ }
+ DLIST_ADD(state->addrlist, addr);
}
state->count += count;
- state->addrlist[state->count] = NULL;
/* If the resolver is set to honor both address families
* and the first one matched, retry the second one to
@@ -576,14 +736,22 @@ done:
errno_t
nsupdate_get_addrs_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
- char ***_addrlist)
+ struct sss_iface_addr **_addrlist,
+ size_t *_count)
{
struct nsupdate_get_addrs_state *state = tevent_req_data(req,
struct nsupdate_get_addrs_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
- *_addrlist = talloc_steal(mem_ctx, state->addrlist);
+ if (_addrlist) {
+ *_addrlist = talloc_steal(mem_ctx, state->addrlist);
+ }
+
+ if (_count) {
+ *_count = state->count;
+ }
+
return EOK;
}
@@ -948,6 +1116,7 @@ static struct dp_option default_dyndns_opts[] = {
{ "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
{ "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER },
+ { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE },
DP_OPTION_TERMINATOR
};
diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
index e49ab8f03..8fdbe487b 100644
--- a/src/providers/dp_dyndns.h
+++ b/src/providers/dp_dyndns.h
@@ -46,6 +46,7 @@ enum dp_dyndns_opts {
DP_OPT_DYNDNS_REFRESH_INTERVAL,
DP_OPT_DYNDNS_IFACE,
DP_OPT_DYNDNS_TTL,
+ DP_OPT_DYNDNS_UPDATE_PTR,
DP_OPT_DYNDNS /* attrs counter */
};
@@ -79,11 +80,20 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
char ***_straddrs);
errno_t
-be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm,
- const char *zone, const char *servername,
- const char *hostname, const unsigned int ttl,
- uint8_t remove_af, struct sss_iface_addr *addresses,
- char **_update_msg);
+be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
+ const char *zone, const char *servername,
+ const char *hostname, const unsigned int ttl,
+ uint8_t remove_af, struct sss_iface_addr *addresses,
+ struct sss_iface_addr *old_addresses,
+ char **_update_msg);
+
+errno_t
+be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
+ const char *servername, const char *hostname,
+ const unsigned int ttl, uint8_t remove_af,
+ struct sss_iface_addr *addresses,
+ struct sss_iface_addr *old_addresses,
+ char **_update_msg);
/* Returns:
* * ERR_OK - on success
@@ -100,8 +110,10 @@ struct tevent_req * nsupdate_get_addrs_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_resolv_ctx *be_res,
const char *hostname);
-errno_t nsupdate_get_addrs_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- char ***_addrlist);
+errno_t
+nsupdate_get_addrs_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct sss_iface_addr **_addrlist,
+ size_t *_count);
#endif /* DP_DYNDNS_H_ */
diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
index 52b8051b0..bb38d105f 100644
--- a/src/providers/ipa/ipa_dyndns.c
+++ b/src/providers/ipa/ipa_dyndns.c
@@ -242,7 +242,9 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
}
subreq = sdap_dyndns_update_send(state, sdap_ctx->be->ev,
- sdap_ctx->be, sdap_ctx,
+ sdap_ctx->be,
+ ctx->dyndns_ctx->opts,
+ sdap_ctx,
dp_opt_get_string(ctx->dyndns_ctx->opts,
DP_OPT_DYNDNS_IFACE),
dp_opt_get_string(ctx->basic,
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 57911082a..bfb09e36c 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -56,6 +56,7 @@ struct dp_option ipa_dyndns_opts[] = {
{ "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
{ "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER },
+ { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
DP_OPTION_TERMINATOR
};
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index e7fad7ba5..ccaec8e09 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);
}
diff --git a/src/providers/ldap/sdap_dyndns.h b/src/providers/ldap/sdap_dyndns.h
index 1602938e1..a18a71fc9 100644
--- a/src/providers/ldap/sdap_dyndns.h
+++ b/src/providers/ldap/sdap_dyndns.h
@@ -33,6 +33,7 @@ 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,
diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c
index f673a25c3..1eb0acf83 100644
--- a/src/resolv/async_resolv.c
+++ b/src/resolv/async_resolv.c
@@ -1453,8 +1453,8 @@ resolv_get_string_ptr_address(TALLOC_CTX *mem_ctx,
}
struct sockaddr_storage *
-resolv_get_sockaddr_address(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent,
- int port)
+resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent,
+ int port, int index)
{
struct sockaddr_storage *sockaddr;
diff --git a/src/resolv/async_resolv.h b/src/resolv/async_resolv.h
index d759a82f3..9bf5e0c40 100644
--- a/src/resolv/async_resolv.h
+++ b/src/resolv/async_resolv.h
@@ -129,8 +129,11 @@ resolv_get_string_ptr_address(TALLOC_CTX *mem_ctx,
resolv_get_string_address_index(mem_ctx, hostent, 0)
struct sockaddr_storage *
-resolv_get_sockaddr_address(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent,
- int port);
+resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent,
+ int port, int index);
+
+#define resolv_get_sockaddr_address(mem_ctx, rhostent, port) \
+ resolv_get_sockaddr_address_index(mem_ctx, rhostent, port, 0)
/** Get SRV record **/
struct tevent_req *resolv_getsrv_send(TALLOC_CTX *mem_ctx,