summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2013-04-30 16:40:09 +0200
committerJakub Hrozek <jhrozek@redhat.com>2013-05-03 20:25:46 +0200
commit38ebc764eeb7693e0c4f0894d6687e54fbba871b (patch)
treea02094f8985977fc2846b98c385c6169c5864e84 /src
parenta398adc5b40381fc567a2aee1841b26af78aea17 (diff)
downloadsssd2-38ebc764eeb7693e0c4f0894d6687e54fbba871b.tar.gz
sssd2-38ebc764eeb7693e0c4f0894d6687e54fbba871b.tar.xz
sssd2-38ebc764eeb7693e0c4f0894d6687e54fbba871b.zip
dyndns: New option dyndns_update_ptr
https://fedorahosted.org/sssd/ticket/1832 While some servers, such as FreeIPA allow the PTR record to be synchronized when the forward record is updated, other servers, including Active Directory, require that the PTR record is synchronized manually. This patch adds a new option, dyndns_update_ptr that automatically generates appropriate DNS update message for updating the reverse zone. This option is off by default in the IPA provider. Also renames be_nsupdate_create_msg to be_nsupdate_create_fwd_msg
Diffstat (limited to 'src')
-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 003153d0..79bf6aa4 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 18328d06..7add141c 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 b09cbd18..396063b4 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 426e9a5b..21a28047 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 337817fc..79701c62 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 e49ab8f0..8fdbe487 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 52b8051b..bb38d105 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 57911082..bfb09e36 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 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);
}
diff --git a/src/providers/ldap/sdap_dyndns.h b/src/providers/ldap/sdap_dyndns.h
index 1602938e..a18a71fc 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 f673a25c..1eb0acf8 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 d759a82f..9bf5e0c4 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,