Sorry, this time with correct patches!
>From 0bf3a47fc71fe230dbdce0466be01c2fea6103e1 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Sun, 6 Jul 2014 22:53:27 +0200
Subject: [PATCH 1/9] DYNDNS: Add a new option dyndns_server

Some environments use a different DNS server than identity server. For
these environments, it would be useful to be able to override the DNS
server used to perform DNS updates.

This patch adds a new option dyndns_server that, if set, would be used
to hardcode a DNS server address into the nsupdate message.
---
 src/config/SSSDConfig/__init__.py.in |  1 +
 src/config/SSSDConfigTest.py         |  2 ++
 src/config/etc/sssd.api.conf         |  1 +
 src/man/sssd-ad.5.xml                | 20 ++++++++++++++++++++
 src/man/sssd-ipa.5.xml               | 19 +++++++++++++++++++
 src/providers/ad/ad_opts.h           |  1 +
 src/providers/dp_dyndns.c            |  1 +
 src/providers/dp_dyndns.h            |  1 +
 src/providers/ipa/ipa_opts.h         |  1 +
 src/providers/ldap/sdap_dyndns.c     |  7 +++++++
 10 files changed, 54 insertions(+)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 49de53eaa9aadda9d3ceb0eea6fee647b4f667a2..e724f037c2f57b8f51aa2dc3178b4b4b8c50a946 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -147,6 +147,7 @@ option_strings = {
     'dyndns_update_ptr' : _("Whether the provider should explicitly update the PTR record as well"),
     'dyndns_force_tcp' : _("Whether the nsupdate utility should default to using TCP"),
     'dyndns_auth' : _("What kind of authentication should be used to perform the DNS update"),
+    'dyndns_server' : _("Override the DNS server used to perform the DNS update"),
     'subdomain_enumerate' : _('Control enumeration of trusted domains'),
     'subdomain_refresh_interval' : _('How often should subdomains list be refreshed'),
     'subdomain_inherit' : _('List of options that should be inherited into a subdomain'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index 67289e012b863501cfae7761794633193e6a51c0..4aefe6702dbaef23ce013bf80f9d71b7928d73ff 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -527,6 +527,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
             'dyndns_update_ptr',
             'dyndns_force_tcp',
             'dyndns_auth',
+            'dyndns_server',
             'subdomain_enumerate',
             'override_gid',
             'case_sensitive',
@@ -891,6 +892,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
             'dyndns_update_ptr',
             'dyndns_force_tcp',
             'dyndns_auth',
+            'dyndns_server',
             'subdomain_enumerate',
             'override_gid',
             'case_sensitive',
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index cf6ce63012176d49f757afbc8a343b24aef869e8..35b84889e727ccdf082acda17f536c5077200df0 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -154,6 +154,7 @@ dyndns_refresh_interval = int, None, false
 dyndns_update_ptr = bool, None, false
 dyndns_force_tcp = bool, None, false
 dyndns_auth = str, None, false
+dyndns_server = str, None, false
 
 # Special providers
 [provider/permit]
diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
index 3cbc10520098372d984d00425d03832d002d6672..7ccd29794a89fa6b69b744a47da04f908efc7ef9 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -812,6 +812,26 @@ ad_gpo_map_deny = +my_pam_service
                     </listitem>
                 </varlistentry>
 
+                <varlistentry>
+                    <term>dyndns_server (string)</term>
+                    <listitem>
+                        <para>
+                            The DNS server to use when performing a DNS
+                            update. In most setups, it's recommended to leave
+                            this option unset.
+                        </para>
+                        <para>
+                            Setting this option makes sense for environments
+                            where the DNS server is different from the identity
+                            server.
+                        </para>
+                        <para>
+                            Default: None (let nsupdate choose the server)
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+
                 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; href="include/override_homedir.xml" />
                 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; href="include/homedir_substring.xml" />
 
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index 2e985991fde10827aff0e7c8e67f29a009683450..871c41607b97bd24fe5feaa282258def0fd0cc8b 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -263,6 +263,25 @@
                 </varlistentry>
 
                 <varlistentry>
+                    <term>dyndns_server (string)</term>
+                    <listitem>
+                        <para>
+                            The DNS server to use when performing a DNS
+                            update. In most setups, it's recommended to leave
+                            this option unset.
+                        </para>
+                        <para>
+                            Setting this option makes sense for environments
+                            where the DNS server is different from the identity
+                            server.
+                        </para>
+                        <para>
+                            Default: None (let nsupdate choose the server)
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
                     <term>ipa_hbac_search_base (string)</term>
                     <listitem>
                         <para>
diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
index d685edcb44c771b0afc7a232a82c21fc9d1c89f9..00586a7ada63ad4c89630e9589d3ff75d1726703 100644
--- a/src/providers/ad/ad_opts.h
+++ b/src/providers/ad/ad_opts.h
@@ -275,6 +275,7 @@ struct dp_option ad_dyndns_opts[] = {
     { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
     { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
+    { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     DP_OPTION_TERMINATOR
 };
 
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index c254d78936f412626db0533f559350de57017618..9a726bd431854342993212ce0a9759b86069cd5e 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -1180,6 +1180,7 @@ static struct dp_option default_dyndns_opts[] = {
     { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE },
     { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
+    { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
 
     DP_OPTION_TERMINATOR
 };
diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
index a8a20ec6f8a1a63cd8c85aaec3f54f9fddb42049..3cc8d122646590365a3fb6dafa6a0f699b620ad9 100644
--- a/src/providers/dp_dyndns.h
+++ b/src/providers/dp_dyndns.h
@@ -55,6 +55,7 @@ enum dp_dyndns_opts {
     DP_OPT_DYNDNS_UPDATE_PTR,
     DP_OPT_DYNDNS_FORCE_TCP,
     DP_OPT_DYNDNS_AUTH,
+    DP_OPT_DYNDNS_SERVER,
 
     DP_OPT_DYNDNS /* attrs counter */
 };
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 9576228d1bf3424c8867bda058b59c3ca6b2216b..231616b908891f4bf7d85f74143e8feba1ce8410 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -62,6 +62,7 @@ struct dp_option ipa_dyndns_opts[] = {
     { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
+    { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     DP_OPTION_TERMINATOR
 };
 
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index a463a2fce08f42b325010cd37c501ef23aee173f..01f4f17226f1b7dd417699403b425c571b780c3a 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -92,6 +92,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
     struct tevent_req *req;
     struct tevent_req *subreq;
     struct sdap_dyndns_update_state *state;
+    const char *conf_servername;
 
     req = tevent_req_create(mem_ctx, &state, struct sdap_dyndns_update_state);
     if (req == NULL) {
@@ -111,6 +112,12 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
     state->auth_type = auth_type;
     state->pass_num = 0;
 
+    conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
+    if (conf_servername != NULL) {
+        state->servername = conf_servername;
+        state->use_server_with_nsupdate = true;
+    }
+
     if (ifname) {
        /* Unless one family is restricted, just replace all
         * address families during the update
-- 
2.4.3

>From dde0b0b9b8159669f5545cafff5c29e1c0915cc0 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Thu, 23 Jul 2015 04:40:03 -0400
Subject: [PATCH 2/9] DYNDNS: Don't use server cmd in nsupdate by default

nsupdate command `server` should not be used for the first attempt
to udpate DNS. It should be used only in subsequent attempts after the
first attempt failed.

Resolves:
https://fedorahosted.org/sssd/ticket/2495
---
 src/providers/ldap/sdap_dyndns.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index 01f4f17226f1b7dd417699403b425c571b780c3a..0f0e63ee2259d017c3e94afca5f3148f4fc2ce04 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -112,10 +112,10 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
     state->auth_type = auth_type;
     state->pass_num = 0;
 
+    /* fallback servername is overriden by user option */
     conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
     if (conf_servername != NULL) {
         state->servername = conf_servername;
-        state->use_server_with_nsupdate = true;
     }
 
     if (ifname) {
-- 
2.4.3

>From 95fae9983f77fffa228decd7b8fabf054a8aa2f0 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Thu, 23 Jul 2015 04:50:38 -0400
Subject: [PATCH 3/9] DYNDNS: remove redundant talloc_steal()

String 'update_msg' was already allocated on mem_ctx, so, there is no
need to steal it.
---
 src/providers/dp_dyndns.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 9a726bd431854342993212ce0a9759b86069cd5e..3171e6909e5f92a98cd506278e6e8c3418b979fe 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -525,7 +525,8 @@ be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
           update_msg);
 
     ret = ERR_OK;
-    *_update_msg = talloc_steal(mem_ctx, update_msg);
+    *_update_msg = update_msg;
+
 done:
     return ret;
 }
-- 
2.4.3

>From 8b81def6e9dda9c47f8370b88be41e62c4ffe9c3 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Thu, 23 Jul 2015 05:30:34 -0400
Subject: [PATCH 4/9] DYNDNS: remove zone command

Remove zone command from message to nsupsate. This command is generally
used to hint nsupdate. In correctly configured environment such
information should be obtained via DNS.

If DNS does not provide necessary information we give other hints.

For more details see:
https://fedorahosted.org/sssd/wiki/DesignDocs/DDNSMessagesUpdate

Resolves:
https://fedorahosted.org/sssd/ticket/2495
---
 src/providers/ad/ad_dyndns.c     |  1 -
 src/providers/dp_dyndns.c        | 12 +-----------
 src/providers/dp_dyndns.h        |  2 +-
 src/providers/ipa/ipa_dyndns.c   | 16 ----------------
 src/providers/ldap/sdap_dyndns.c | 13 +------------
 src/providers/ldap/sdap_dyndns.h |  1 -
 6 files changed, 3 insertions(+), 42 deletions(-)

diff --git a/src/providers/ad/ad_dyndns.c b/src/providers/ad/ad_dyndns.c
index aac7d8b0a170e07cba0cd150a6f19c538948d657..5f8638128b966f0981c85a44e50e3201c73d561e 100644
--- a/src/providers/ad/ad_dyndns.c
+++ b/src/providers/ad/ad_dyndns.c
@@ -233,7 +233,6 @@ ad_dyndns_update_send(struct ad_options *ctx)
                                                        DP_OPT_DYNDNS_IFACE),
                                      dp_opt_get_string(ctx->basic,
                                                        AD_HOSTNAME),
-                                     NULL,
                                      dp_opt_get_string(ctx->basic,
                                                        AD_KRB5_REALM),
                                      state->servername,
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 3171e6909e5f92a98cd506278e6e8c3418b979fe..ae3f913ee392a6513f75aab497e7f2d784784748 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -436,7 +436,7 @@ fail:
 
 errno_t
 be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
-                           const char *zone, const char *servername,
+                           const char *servername,
                            const char *hostname, const unsigned int ttl,
                            uint8_t remove_af, struct sss_iface_addr *addresses,
                            char **_update_msg)
@@ -459,16 +459,6 @@ be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
         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 = nsupdate_msg_add_fwd(update_msg, addresses, hostname,
                                       ttl, remove_af);
     if (update_msg == NULL) {
diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
index 3cc8d122646590365a3fb6dafa6a0f699b620ad9..9f72331b6fd68e17e9eb91505a13fc839d3f54e1 100644
--- a/src/providers/dp_dyndns.h
+++ b/src/providers/dp_dyndns.h
@@ -89,7 +89,7 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
 
 errno_t
 be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
-                           const char *zone, const char *servername,
+                           const char *servername,
                            const char *hostname, const unsigned int ttl,
                            uint8_t remove_af, struct sss_iface_addr *addresses,
                            char **_update_msg);
diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
index 83009ff2a08cb8e4ae2b7a1e89039539b23b6d79..e7026eb275798f0ed21fb8490295b6e6d419d8ee 100644
--- a/src/providers/ipa/ipa_dyndns.c
+++ b/src/providers/ipa/ipa_dyndns.c
@@ -153,9 +153,7 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
     struct ipa_dyndns_update_state *state;
     struct tevent_req *req, *subreq;
     struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
-    char *dns_zone;
     const char *servername;
-    int i;
 
     DEBUG(SSSDBG_TRACE_FUNC, "Performing update\n");
 
@@ -175,19 +173,6 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
     }
     state->ipa_ctx->dyndns_ctx->last_refresh = time(NULL);
 
-    dns_zone = dp_opt_get_string(ctx->basic, IPA_DOMAIN);
-    if (!dns_zone) {
-        ret = EIO;
-        goto done;
-    }
-
-    /* The DNS zone for IPA is the lower-case
-     * version of the IPA domain
-     */
-    for (i = 0; dns_zone[i] != '\0'; i++) {
-        dns_zone[i] = tolower(dns_zone[i]);
-    }
-
     if (strncmp(ctx->service->sdap->uri,
                 "ldap://";, 7) != 0) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected format of LDAP URI.\n");
@@ -209,7 +194,6 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
                                                        DP_OPT_DYNDNS_IFACE),
                                      dp_opt_get_string(ctx->basic,
                                                        IPA_HOSTNAME),
-                                     dns_zone,
                                      dp_opt_get_string(ctx->basic,
                                                        IPA_KRB5_REALM),
                                      servername,
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index 0f0e63ee2259d017c3e94afca5f3148f4fc2ce04..f0e3dd855005d00ea19cb5dc283375f58b0d2cca 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -47,7 +47,6 @@ struct sdap_dyndns_update_state {
     struct dp_option *opts;
 
     const char *hostname;
-    const char *dns_zone;
     const char *realm;
     const char *servername;
     int ttl;
@@ -61,7 +60,6 @@ struct sdap_dyndns_update_state {
     enum be_nsupdate_auth auth_type;
     bool use_server_with_nsupdate;
     char *update_msg;
-    size_t pass_num;
 };
 
 static void sdap_dyndns_update_addrs_done(struct tevent_req *subreq);
@@ -82,7 +80,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
                         enum be_nsupdate_auth auth_type,
                         const char *ifname,
                         const char *hostname,
-                        const char *dns_zone,
                         const char *realm,
                         const char *servername,
                         const int ttl,
@@ -101,7 +98,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
     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;
     state->servername = servername;
     state->use_server_with_nsupdate = false;
@@ -110,7 +106,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
     state->ev = ev;
     state->opts = opts;
     state->auth_type = auth_type;
-    state->pass_num = 0;
 
     /* fallback servername is overriden by user option */
     conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
@@ -317,7 +312,6 @@ sdap_dyndns_update_step(struct tevent_req *req)
     struct sdap_dyndns_update_state *state;
     const char *servername;
     struct tevent_req *subreq;
-    const char *dns_zone = NULL;
 
     state = tevent_req_data(req, struct sdap_dyndns_update_state);
 
@@ -327,11 +321,7 @@ sdap_dyndns_update_step(struct tevent_req *req)
         servername = state->servername;
     }
 
-    if (state->pass_num > 0) {
-        dns_zone = state->dns_zone;
-    }
-
-    ret = be_nsupdate_create_fwd_msg(state, state->realm, dns_zone,
+    ret = be_nsupdate_create_fwd_msg(state, state->realm,
                                      servername, state->hostname,
                                      state->ttl, state->remove_af,
                                      state->addresses,
@@ -340,7 +330,6 @@ sdap_dyndns_update_step(struct tevent_req *req)
         DEBUG(SSSDBG_OP_FAILURE, "Can't get addresses for DNS update\n");
         return ret;
     }
-    state->pass_num++;
 
     /* Fork a child process to perform the DNS update */
     subreq = be_nsupdate_send(state, state->ev, state->auth_type,
diff --git a/src/providers/ldap/sdap_dyndns.h b/src/providers/ldap/sdap_dyndns.h
index 7aaff5d2c69fbda55fff5208c97b953b970c55cc..a9481b7941be6af0f172afce5f4d54f57ef85e48 100644
--- a/src/providers/ldap/sdap_dyndns.h
+++ b/src/providers/ldap/sdap_dyndns.h
@@ -39,7 +39,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
                         enum be_nsupdate_auth auth_type,
                         const char *ifname,
                         const char *hostname,
-                        const char *dns_zone,
                         const char *realm,
                         const char *servername,
                         const int ttl,
-- 
2.4.3

>From 846d943830f3ce25e01a16e118fa748c33eb5663 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Thu, 23 Jul 2015 09:52:47 -0400
Subject: [PATCH 5/9] DYNDNS: rename field of sdap_dyndns_update_state

Rename 'use_server_with_nsupdate' to more general name 'fallback_mode'.

Resolves:
https://fedorahosted.org/sssd/ticket/2495
---
 src/providers/ldap/sdap_dyndns.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index f0e3dd855005d00ea19cb5dc283375f58b0d2cca..2a179fd1b5e88bdf2442657ff6fa1dcc55417467 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -58,7 +58,7 @@ struct sdap_dyndns_update_state {
     bool update_ptr;
     bool check_diff;
     enum be_nsupdate_auth auth_type;
-    bool use_server_with_nsupdate;
+    bool fallback_mode;
     char *update_msg;
 };
 
@@ -100,7 +100,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
     state->hostname = hostname;
     state->realm = realm;
     state->servername = servername;
-    state->use_server_with_nsupdate = false;
+    state->fallback_mode = false;
     state->ttl = ttl;
     state->be_res = be_ctx->be_res;
     state->ev = ev;
@@ -316,7 +316,7 @@ sdap_dyndns_update_step(struct tevent_req *req)
     state = tevent_req_data(req, struct sdap_dyndns_update_state);
 
     servername = NULL;
-    if (state->use_server_with_nsupdate == true &&
+    if (state->fallback_mode == true &&
         state->servername) {
         servername = state->servername;
     }
@@ -359,9 +359,9 @@ sdap_dyndns_update_done(struct tevent_req *subreq)
     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 &&
+        if (state->fallback_mode == false && state->servername &&
             WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
-            state->use_server_with_nsupdate = true;
+            state->fallback_mode = true;
             DEBUG(SSSDBG_MINOR_FAILURE,
                    "nsupdate failed, retrying with server name\n");
             ret = sdap_dyndns_update_step(req);
@@ -400,7 +400,7 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
     state = tevent_req_data(req, struct sdap_dyndns_update_state);
 
     servername = NULL;
-    if (state->use_server_with_nsupdate == true &&
+    if (state->fallback_mode == true &&
         state->servername) {
         servername = state->servername;
     }
@@ -443,9 +443,9 @@ sdap_dyndns_update_ptr_done(struct tevent_req *subreq)
     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 &&
+        if (state->fallback_mode == false && state->servername &&
             WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
-            state->use_server_with_nsupdate = true;
+            state->fallback_mode = true;
             DEBUG(SSSDBG_MINOR_FAILURE,
                    "nsupdate failed, retrying with server name\n");
             ret = sdap_dyndns_update_ptr_step(req);
-- 
2.4.3

>From 38d3206286356f3db6a3c78386c856d0570b9802 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Thu, 23 Jul 2015 10:51:50 -0400
Subject: [PATCH 6/9] DYNDNS: use realm and server commands only as fallback

Resolves:
https://fedorahosted.org/sssd/ticket/2195
---
 src/providers/ad/ad_dyndns.c     |  9 ---------
 src/providers/dp_dyndns.c        | 23 ++++++++++++++++++-----
 src/providers/ipa/ipa_dyndns.c   |  7 -------
 src/providers/ldap/sdap_dyndns.c | 37 ++++++++++++++++++++-----------------
 src/providers/ldap/sdap_dyndns.h |  1 -
 5 files changed, 38 insertions(+), 39 deletions(-)

diff --git a/src/providers/ad/ad_dyndns.c b/src/providers/ad/ad_dyndns.c
index 5f8638128b966f0981c85a44e50e3201c73d561e..a4d38c442a69ff0440e459da32d8852bda314484 100644
--- a/src/providers/ad/ad_dyndns.c
+++ b/src/providers/ad/ad_dyndns.c
@@ -159,7 +159,6 @@ static void ad_dyndns_nsupdate_done(struct tevent_req *req)
 
 struct ad_dyndns_update_state {
     struct ad_options *ad_ctx;
-    const char *servername;
 };
 
 static void ad_dyndns_sdap_update_done(struct tevent_req *subreq);
@@ -217,13 +216,6 @@ ad_dyndns_update_send(struct ad_options *ctx)
         goto done;
     }
 
-    state->servername = talloc_strdup(state, lud->lud_host);
-    ldap_free_urldesc(lud);
-    if (!state->servername) {
-        ret = ENOMEM;
-        goto done;
-    }
-
     subreq = sdap_dyndns_update_send(state, sdap_ctx->be->ev,
                                      sdap_ctx->be,
                                      ctx->dyndns_ctx->opts,
@@ -235,7 +227,6 @@ ad_dyndns_update_send(struct ad_options *ctx)
                                                        AD_HOSTNAME),
                                      dp_opt_get_string(ctx->basic,
                                                        AD_KRB5_REALM),
-                                     state->servername,
                                      dp_opt_get_int(ctx->dyndns_ctx->opts,
                                                     DP_OPT_DYNDNS_TTL),
                                      false);
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index ae3f913ee392a6513f75aab497e7f2d784784748..7484f7fb1663040e2acc67cebb0c7366cbbacbf7 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -383,6 +383,23 @@ nsupdate_msg_add_ptr(char *update_msg, struct sss_iface_addr *addresses,
     return update_msg;
 }
 
+#ifdef HAVE_NSUPDATE_REALM
+static char *
+nsupdate_msg_add_realm_cmd(TALLOC_CTX *mem_ctx, const char *realm)
+{
+    if (realm != NULL) {
+        return talloc_asprintf(mem_ctx, "realm %s\n", realm);
+    }
+    return talloc_asprintf(mem_ctx, "\n");
+}
+#else
+static char *
+nsupdate_msg_add_realm_cmd(TALLOC_CTX *mem_ctx, const char *realm)
+{
+    return talloc_asprintf(mem_ctx, "\n");
+}
+#endif
+
 static char *
 nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm,
                            const char *servername)
@@ -394,11 +411,7 @@ nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm,
     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, "\n");
-#endif
+    realm_directive = nsupdate_msg_add_realm_cmd(tmp_ctx, realm);
     if (!realm_directive) {
         goto fail;
     }
diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
index e7026eb275798f0ed21fb8490295b6e6d419d8ee..1a7014718366ce3c898eef24eabd6903101dc92e 100644
--- a/src/providers/ipa/ipa_dyndns.c
+++ b/src/providers/ipa/ipa_dyndns.c
@@ -153,7 +153,6 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
     struct ipa_dyndns_update_state *state;
     struct tevent_req *req, *subreq;
     struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
-    const char *servername;
 
     DEBUG(SSSDBG_TRACE_FUNC, "Performing update\n");
 
@@ -179,11 +178,6 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
         ret = EIO;
         goto done;
     }
-    servername = ctx->service->sdap->uri + 7;
-    if (servername[0] == '\0') {
-        ret = EIO;
-        goto done;
-    }
 
     subreq = sdap_dyndns_update_send(state, sdap_ctx->be->ev,
                                      sdap_ctx->be,
@@ -196,7 +190,6 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
                                                        IPA_HOSTNAME),
                                      dp_opt_get_string(ctx->basic,
                                                        IPA_KRB5_REALM),
-                                     servername,
                                      dp_opt_get_int(ctx->dyndns_ctx->opts,
                                                     DP_OPT_DYNDNS_TTL),
                                      true);
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index 2a179fd1b5e88bdf2442657ff6fa1dcc55417467..8a8940c60334c71b50a92dcc2eb740a9ea5fc486 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -81,7 +81,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
                         const char *ifname,
                         const char *hostname,
                         const char *realm,
-                        const char *servername,
                         const int ttl,
                         bool check_diff)
 {
@@ -99,7 +98,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
     state->update_ptr = dp_opt_get_bool(opts, DP_OPT_DYNDNS_UPDATE_PTR);
     state->hostname = hostname;
     state->realm = realm;
-    state->servername = servername;
+    state->servername = NULL;
     state->fallback_mode = false;
     state->ttl = ttl;
     state->be_res = be_ctx->be_res;
@@ -311,18 +310,20 @@ sdap_dyndns_update_step(struct tevent_req *req)
     errno_t ret;
     struct sdap_dyndns_update_state *state;
     const char *servername;
+    const char *realm;
     struct tevent_req *subreq;
 
     state = tevent_req_data(req, struct sdap_dyndns_update_state);
 
     servername = NULL;
-    if (state->fallback_mode == true &&
-        state->servername) {
+    realm = NULL;
+    if (state->fallback_mode) {
         servername = state->servername;
+        realm = state->realm;
     }
 
-    ret = be_nsupdate_create_fwd_msg(state, state->realm,
-                                     servername, state->hostname,
+    ret = be_nsupdate_create_fwd_msg(state, realm, servername,
+                                     state->hostname,
                                      state->ttl, state->remove_af,
                                      state->addresses,
                                      &state->update_msg);
@@ -359,11 +360,12 @@ sdap_dyndns_update_done(struct tevent_req *subreq)
     talloc_zfree(subreq);
     if (ret != EOK) {
         /* If the update didn't succeed, we can retry using the server name */
-        if (state->fallback_mode == false && state->servername &&
-            WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
+        if (state->fallback_mode == false
+                && WIFEXITED(child_status)
+                && WEXITSTATUS(child_status) != 0) {
             state->fallback_mode = true;
             DEBUG(SSSDBG_MINOR_FAILURE,
-                   "nsupdate failed, retrying with server name\n");
+                  "nsupdate failed, retrying.\n");
             ret = sdap_dyndns_update_step(req);
             if (ret == EOK) {
                 return;
@@ -395,18 +397,19 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
     errno_t ret;
     struct sdap_dyndns_update_state *state;
     const char *servername;
+    const char *realm;
     struct tevent_req *subreq;
 
     state = tevent_req_data(req, struct sdap_dyndns_update_state);
 
     servername = NULL;
-    if (state->fallback_mode == true &&
-        state->servername) {
+    realm = NULL;
+    if (state->fallback_mode == true) {
         servername = state->servername;
+        realm = state->realm;
     }
 
-    ret = be_nsupdate_create_ptr_msg(state, state->realm,
-                                     servername, state->hostname,
+    ret = be_nsupdate_create_ptr_msg(state, realm, servername, state->hostname,
                                      state->ttl, state->remove_af,
                                      state->addresses, state->dns_addrlist,
                                      &state->update_msg);
@@ -443,11 +446,11 @@ sdap_dyndns_update_ptr_done(struct tevent_req *subreq)
     talloc_zfree(subreq);
     if (ret != EOK) {
         /* If the update didn't succeed, we can retry using the server name */
-        if (state->fallback_mode == false && state->servername &&
-            WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
+        if (state->fallback_mode == false
+                && WIFEXITED(child_status)
+                && WEXITSTATUS(child_status) != 0) {
             state->fallback_mode = true;
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                   "nsupdate failed, retrying with server name\n");
+            DEBUG(SSSDBG_MINOR_FAILURE, "nsupdate failed, retrying\n");
             ret = sdap_dyndns_update_ptr_step(req);
             if (ret == EOK) {
                 return;
diff --git a/src/providers/ldap/sdap_dyndns.h b/src/providers/ldap/sdap_dyndns.h
index a9481b7941be6af0f172afce5f4d54f57ef85e48..fda4530b61cfcfcf98207638efd4de70498d90dc 100644
--- a/src/providers/ldap/sdap_dyndns.h
+++ b/src/providers/ldap/sdap_dyndns.h
@@ -40,7 +40,6 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
                         const char *ifname,
                         const char *hostname,
                         const char *realm,
-                        const char *servername,
                         const int ttl,
                         bool check_diff);
 
-- 
2.4.3

>From 7a0dc132c7392a06cba4f9c181c0425b766a295c Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Fri, 24 Jul 2015 08:24:48 -0400
Subject: [PATCH 7/9] DYNDNS: remove code duplication

Move copy pasted code for converting sockaddr_storage to string into
function.

Resolves:
https://fedorahosted.org/sssd/ticket/2495
---
 src/providers/dp_dyndns.c | 99 +++++++++++++++++++++--------------------------
 src/util/util_errors.c    |  1 +
 src/util/util_errors.h    |  1 +
 3 files changed, 46 insertions(+), 55 deletions(-)

diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 7484f7fb1663040e2acc67cebb0c7366cbbacbf7..c1836837d00ed995c0f1942ca2a86f0d9d2ba27b 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -58,6 +58,39 @@ void sss_iface_addr_concatenate(struct sss_iface_addr **list,
     DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
 }
 
+static errno_t addr_to_str(struct sockaddr_storage *addr,
+                           char *dst, size_t size)
+{
+    const void *src;
+    const char *res;
+    errno_t ret;
+
+    switch(addr->ss_family) {
+    case AF_INET:
+        src = &(((struct sockaddr_in *)addr)->sin_addr);
+        break;
+    case AF_INET6:
+        src = &(((struct sockaddr_in6 *)addr)->sin6_addr);
+        break;
+    default:
+        ret = ERR_ADDR_FAMILY_NOT_SUPPORTED;
+        goto done;
+    }
+
+    res = inet_ntop(addr->ss_family, src, dst, size);
+    if (res == NULL) {
+        ret = errno;
+        DEBUG(SSSDBG_OP_FAILURE, "inet_ntop failed [%d]: %s\n",
+              ret, sss_strerror(ret));
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    return ret;
+}
+
 errno_t
 sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
                                 struct sss_iface_addr *ifaddr_list,
@@ -67,7 +100,6 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
     size_t count;
     int ai;
     char **straddrs;
-    const char *ip;
     char ip_addr[INET6_ADDRSTRLEN];
     errno_t ret;
 
@@ -83,35 +115,17 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
 
     ai = 0;
     DLIST_FOR_EACH(ifaddr, ifaddr_list) {
-        switch(ifaddr->addr->ss_family) {
-        case AF_INET:
-            errno = 0;
-            ip = inet_ntop(ifaddr->addr->ss_family,
-                           &(((struct sockaddr_in *)ifaddr->addr)->sin_addr),
-                           ip_addr, INET6_ADDRSTRLEN);
-            if (ip == NULL) {
-                ret = errno;
-                goto fail;
-            }
-            break;
 
-        case AF_INET6:
-            errno = 0;
-            ip = inet_ntop(ifaddr->addr->ss_family,
-                           &(((struct sockaddr_in6 *)ifaddr->addr)->sin6_addr),
-                           ip_addr, INET6_ADDRSTRLEN);
-            if (ip == NULL) {
-                ret = errno;
-                goto fail;
-            }
-            break;
-
-        default:
-            DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
+        ret = addr_to_str(ifaddr->addr, ip_addr, INET6_ADDRSTRLEN);
+        if (ret == ERR_ADDR_FAMILY_NOT_SUPPORTED) {
             continue;
+        } else if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
+                  ret, sss_strerror(ret));
+            goto fail;
         }
 
-        straddrs[ai] = talloc_strdup(straddrs, ip);
+        straddrs[ai] = talloc_strdup(straddrs, ip_addr);
         if (straddrs[ai] == NULL) {
             ret = ENOMEM;
             goto fail;
@@ -237,7 +251,6 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
 {
     struct sss_iface_addr *new_record;
     char ip_addr[INET6_ADDRSTRLEN];
-    const char *ip;
     errno_t ret;
 
     /* Remove existing entries as needed */
@@ -259,33 +272,10 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
     }
 
     DLIST_FOR_EACH(new_record, addresses) {
-        switch(new_record->addr->ss_family) {
-        case AF_INET:
-            ip = inet_ntop(new_record->addr->ss_family,
-                           &(((struct sockaddr_in *)new_record->addr)->sin_addr),
-                           ip_addr, INET6_ADDRSTRLEN);
-            if (ip == NULL) {
-                ret = errno;
-                DEBUG(SSSDBG_OP_FAILURE,
-                      "inet_ntop failed [%d]: %s\n", ret, strerror(ret));
-                return NULL;
-            }
-            break;
-
-        case AF_INET6:
-            ip = inet_ntop(new_record->addr->ss_family,
-                           &(((struct sockaddr_in6 *)new_record->addr)->sin6_addr),
-                           ip_addr, INET6_ADDRSTRLEN);
-            if (ip == NULL) {
-                ret = errno;
-                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 = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
+                  ret, sss_strerror(ret));
             return NULL;
         }
 
@@ -298,7 +288,6 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
         if (update_msg == NULL) {
             return NULL;
         }
-
     }
 
     return talloc_asprintf_append(update_msg, "send\n");
diff --git a/src/util/util_errors.c b/src/util/util_errors.c
index 735f6dcfc7af33edcc886fd106cb3655bcc9566a..ba61630c3b4b5b9b5d15324154b7dbbfa34e620f 100644
--- a/src/util/util_errors.c
+++ b/src/util/util_errors.c
@@ -79,6 +79,7 @@ struct err_string error_to_str[] = {
     { "Retrieving keytab failed" }, /* ERR_IPA_GETKEYTAB_FAILED */
     { "Trusted forest root unknown" }, /* ERR_TRUST_FOREST_UNKNOWN */
     { "p11_child failed" }, /* ERR_P11_CHILD */
+    { "Address family not supported" }, /* ERR_ADDR_FAMILY_NOT_SUPPORTED */
     { "ERR_LAST" } /* ERR_LAST */
 };
 
diff --git a/src/util/util_errors.h b/src/util/util_errors.h
index fbfbdef334be1fb8a525b78ab6336d616b31a189..aa00cc592b38e7bbf6f95cfb6348f0bdc6ae2ed0 100644
--- a/src/util/util_errors.h
+++ b/src/util/util_errors.h
@@ -101,6 +101,7 @@ enum sssd_errors {
     ERR_IPA_GETKEYTAB_FAILED,
     ERR_TRUST_FOREST_UNKNOWN,
     ERR_P11_CHILD,
+    ERR_ADDR_FAMILY_NOT_SUPPORTED,
     ERR_LAST            /* ALWAYS LAST */
 };
 
-- 
2.4.3

>From 3e269d27fae21396d318cf620d9238aa44a8df37 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Fri, 24 Jul 2015 10:41:42 -0400
Subject: [PATCH 8/9] TESTS: UT for sss_iface_addr_list_as_str_list()

Resolves:
https://fedorahosted.org/sssd/ticket/2495
---
 src/tests/cmocka/test_dyndns.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
index 8118e9438e89465674155c11f4523d2313f6a59c..691378ee6edc5b0238adc8404ea0a433ae3cf907 100644
--- a/src/tests/cmocka/test_dyndns.c
+++ b/src/tests/cmocka/test_dyndns.c
@@ -289,6 +289,45 @@ void dyndns_test_get_ifaddr_enoent(void **state)
     assert_true(check_leaks_pop(dyndns_test_ctx) == true);
 }
 
+void dyndns_test_addr_list_as_str_list(void **state)
+{
+    int i;
+    char **output;
+    errno_t ret;
+    struct sss_iface_addr *addrlist;
+    struct {
+        const char* addr;
+        int af;
+    } input[] = {
+        {"2001:cdba::555", AF_INET6},
+        {"192.168.0.1", AF_INET},
+        {"192.168.0.2", AF_INET},
+        {"2001:cdba::444", AF_INET6}
+    };
+    int size = 4;
+
+    check_leaks_push(dyndns_test_ctx);
+
+    for (i = 0; i < size; i++) {
+        will_return_getifaddrs("eth0", input[i].addr, input[i].af);
+    }
+    will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
+
+    ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
+    assert_int_equal(ret, EOK);
+
+    ret = sss_iface_addr_list_as_str_list(dyndns_test_ctx, addrlist, &output);
+    assert_int_equal(ret, EOK);
+    for (i = 0; i < size; i++) {
+        /* addresses are returned in reversed order */
+        assert_int_equal(strcmp(input[i].addr, output[size - 1 - i]), 0);
+    }
+
+    talloc_free(addrlist);
+    talloc_free(output);
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
 void dyndns_test_dualstack(void **state)
 {
     errno_t ret;
@@ -672,6 +711,9 @@ int main(int argc, const char *argv[])
         cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr_enoent,
                                         dyndns_test_simple_setup,
                                         dyndns_test_teardown),
+        cmocka_unit_test_setup_teardown(dyndns_test_addr_list_as_str_list,
+                                        dyndns_test_simple_setup,
+                                        dyndns_test_teardown),
 
         /* Dynamic DNS update unit tests*/
         cmocka_unit_test_setup_teardown(dyndns_test_ok,
-- 
2.4.3

>From c75dcca759a2e2a022e565fd9f45d2f16522eee2 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Fri, 24 Jul 2015 13:25:56 -0400
Subject: [PATCH 9/9] DYNDNS: improve nsupdate_msg_add_fwd()

Update nsupdate_msg_add_fwd() to group commands by address family
processed IP address belongs to.

It's better to group removing old A addresses and adding new A
addresses in a single transaction. Same goes for AAAA addresses.

Separate transaction for A and AAAA addresses updates are important
because server might block updates for one of these families and thus
the update even for the non-blocked address family would unnecessarily
fail.

For more details please see:
https://fedorahosted.org/sssd/wiki/DesignDocs/DDNSMessagesUpdate

Resolves:
https://fedorahosted.org/sssd/ticket/2495
---
 src/providers/dp_dyndns.c      |  56 ++++++---
 src/tests/cmocka/test_dyndns.c | 280 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 316 insertions(+), 20 deletions(-)

diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index c1836837d00ed995c0f1942ca2a86f0d9d2ba27b..74575b95359cf87b6f46f5b4418a7a41d59b8cb9 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -253,40 +253,62 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
     char ip_addr[INET6_ADDRSTRLEN];
     errno_t ret;
 
+    /* A addresses first */
     /* Remove existing entries as needed */
     if (remove_af & DYNDNS_REMOVE_A) {
         update_msg = talloc_asprintf_append(update_msg,
-                                            "update delete %s. in A\nsend\n",
+                                            "update delete %s. in A\n",
                                             hostname);
         if (update_msg == NULL) {
             return NULL;
         }
     }
+    DLIST_FOR_EACH(new_record, addresses) {
+        if (new_record->addr->ss_family == AF_INET) {
+            ret = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
+                      ret, sss_strerror(ret));
+                return NULL;
+            }
+
+            /* Format the record update */
+            update_msg = talloc_asprintf_append(update_msg,
+                                                "update add %s. %d in %s %s\n",
+                                                hostname, ttl, "A", ip_addr);
+            if (update_msg == NULL) {
+                return NULL;
+            }
+        }
+    }
+    update_msg = talloc_asprintf_append(update_msg, "send\n");
+
+    /* AAAA addresses first */
+    /* Remove existing entries as needed */
     if (remove_af & DYNDNS_REMOVE_AAAA) {
         update_msg = talloc_asprintf_append(update_msg,
-                                            "update delete %s. in AAAA\nsend\n",
+                                            "update delete %s. in AAAA\n",
                                             hostname);
         if (update_msg == NULL) {
             return NULL;
         }
     }
-
     DLIST_FOR_EACH(new_record, addresses) {
-        ret = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
-                  ret, sss_strerror(ret));
-            return NULL;
-        }
+        if (new_record->addr->ss_family == AF_INET6) {
+            ret = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
+                      ret, sss_strerror(ret));
+                return NULL;
+            }
 
-        /* Format the record update */
-        update_msg = talloc_asprintf_append(update_msg,
-                "update add %s. %d in %s %s\n",
-                hostname, ttl,
-                new_record->addr->ss_family == AF_INET ? "A" : "AAAA",
-                ip_addr);
-        if (update_msg == NULL) {
-            return NULL;
+            /* Format the record update */
+            update_msg = talloc_asprintf_append(update_msg,
+                                                "update add %s. %d in %s %s\n",
+                                                hostname, ttl, "AAAA", ip_addr);
+            if (update_msg == NULL) {
+                return NULL;
+            }
         }
     }
 
diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
index 691378ee6edc5b0238adc8404ea0a433ae3cf907..e0a8ba76c7bb9590205511b16de0463b3900faa7 100644
--- a/src/tests/cmocka/test_dyndns.c
+++ b/src/tests/cmocka/test_dyndns.c
@@ -328,6 +328,266 @@ void dyndns_test_addr_list_as_str_list(void **state)
     assert_true(check_leaks_pop(dyndns_test_ctx) == true);
 }
 
+void dyndns_test_create_fwd_msg(void **state)
+{
+    errno_t ret;
+    char *msg;
+    struct sss_iface_addr *addrlist;
+    int i;
+
+    check_leaks_push(dyndns_test_ctx);
+
+    /* getifaddrs is called twice in sss_get_dualstack_addresses() */
+    for (i = 0; i < 2; i++) {
+        will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
+        will_return_getifaddrs("eth1", "192.168.0.1", AF_INET);
+        will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
+        will_return_getifaddrs("eth1", "2001:cdba::444", AF_INET6);
+        will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
+    }
+
+    struct sockaddr_in sin;
+    memset(&sin, 0, sizeof (sin));
+    sin.sin_family = AF_INET;
+    sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
+    ret = sss_get_dualstack_addresses(dyndns_test_ctx,
+                                      (struct sockaddr *) &sin,
+                                      &addrlist);
+    assert_int_equal(ret, EOK);
+
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
+                                     1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "\nupdate delete bran_stark. in A\n"
+                        "update add bran_stark. 1234 in A 192.168.0.2\n"
+                        "send\n"
+                        "update delete bran_stark. in AAAA\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    /* fallback case realm and server */
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, "North", "Winterfell",
+                                     "bran_stark",
+                                     1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "server Winterfell\n"
+                        "realm North\n"
+                        "update delete bran_stark. in A\n"
+                        "update add bran_stark. 1234 in A 192.168.0.2\n"
+                        "send\n"
+                        "update delete bran_stark. in AAAA\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    /* just realm */
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, "North", NULL,
+                                     "bran_stark",
+                                     1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "realm North\n"
+                        "update delete bran_stark. in A\n"
+                        "update add bran_stark. 1234 in A 192.168.0.2\n"
+                        "send\n"
+                        "update delete bran_stark. in AAAA\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    /* just server */
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, "Winterfell",
+                                     "bran_stark",
+                                     1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "server Winterfell\n"
+                        "\n"
+                        "update delete bran_stark. in A\n"
+                        "update add bran_stark. 1234 in A 192.168.0.2\n"
+                        "send\n"
+                        "update delete bran_stark. in AAAA\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    /* remove just A */
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
+                                     1234, DYNDNS_REMOVE_A,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "\nupdate delete bran_stark. in A\n"
+                        "update add bran_stark. 1234 in A 192.168.0.2\n"
+                        "send\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    /* remove just AAAA */
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
+                                     1234, DYNDNS_REMOVE_AAAA,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "\nupdate add bran_stark. 1234 in A 192.168.0.2\n"
+                        "send\n"
+                        "update delete bran_stark. in AAAA\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    talloc_free(addrlist);
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
+void dyndns_test_create_fwd_msg_mult(void **state)
+{
+    errno_t ret;
+    char *msg;
+    struct sss_iface_addr *addrlist;
+    int i;
+
+    check_leaks_push(dyndns_test_ctx);
+
+    /* getifaddrs is called twice in sss_get_dualstack_addresses() */
+    for (i = 0; i < 2; i++) {
+        will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
+        will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
+        will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
+        will_return_getifaddrs("eth0", "2001:cdba::444", AF_INET6);
+        will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
+    }
+
+    struct sockaddr_in sin;
+    memset(&sin, 0, sizeof (sin));
+    sin.sin_family = AF_INET;
+    sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
+    ret = sss_get_dualstack_addresses(dyndns_test_ctx,
+                                      (struct sockaddr *) &sin,
+                                      &addrlist);
+    assert_int_equal(ret, EOK);
+
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
+                                     1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "\nupdate delete bran_stark. in A\n"
+                        "update add bran_stark. 1234 in A 192.168.0.1\n"
+                        "update add bran_stark. 1234 in A 192.168.0.2\n"
+                        "send\n"
+                        "update delete bran_stark. in AAAA\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::444\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    talloc_free(addrlist);
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
+void dyndns_test_create_fwd_msg_A(void **state)
+{
+    errno_t ret;
+    char *msg;
+    struct sss_iface_addr *addrlist;
+    int i;
+
+    check_leaks_push(dyndns_test_ctx);
+
+    /* getifaddrs is called twice in sss_get_dualstack_addresses() */
+    for (i = 0; i < 2; i++) {
+        will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
+        will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
+        will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
+    }
+
+    struct sockaddr_in sin;
+    memset(&sin, 0, sizeof (sin));
+    sin.sin_family = AF_INET;
+    sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
+    ret = sss_get_dualstack_addresses(dyndns_test_ctx,
+                                      (struct sockaddr *) &sin,
+                                      &addrlist);
+    assert_int_equal(ret, EOK);
+
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
+                                     1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "\nupdate delete bran_stark. in A\n"
+                        "update add bran_stark. 1234 in A 192.168.0.1\n"
+                        "update add bran_stark. 1234 in A 192.168.0.2\n"
+                        "send\n"
+                        "update delete bran_stark. in AAAA\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    talloc_free(addrlist);
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
+void dyndns_test_create_fwd_msg_AAAA(void **state)
+{
+    errno_t ret;
+    char *msg;
+    struct sss_iface_addr *addrlist;
+    int i;
+
+    check_leaks_push(dyndns_test_ctx);
+
+    /* getifaddrs is called twice in sss_get_dualstack_addresses() */
+    for (i = 0; i < 2; i++) {
+        will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
+        will_return_getifaddrs("eth0", "2001:cdba::444", AF_INET6);
+        will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
+    }
+
+    struct sockaddr_in6 sin;
+    memset(&sin, 0, sizeof (sin));
+    sin.sin6_family = AF_INET6;
+    ret = inet_pton(AF_INET6, "2001:cdba::555", &sin.sin6_addr.s6_addr);
+    assert_int_equal(ret, 1);
+    ret = sss_get_dualstack_addresses(dyndns_test_ctx,
+                                      (struct sockaddr *) &sin,
+                                      &addrlist);
+    assert_int_equal(ret, EOK);
+
+    ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
+                                     1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
+                                     addrlist, &msg);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(msg,
+                        "\nupdate delete bran_stark. in A\n"
+                        "send\n"
+                        "update delete bran_stark. in AAAA\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::444\n"
+                        "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
+                        "send\n");
+    talloc_zfree(msg);
+
+    talloc_free(addrlist);
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
 void dyndns_test_dualstack(void **state)
 {
     errno_t ret;
@@ -348,7 +608,7 @@ void dyndns_test_dualstack(void **state)
     }
 
     struct sockaddr_in sin;
-    memset (&sin, 0, sizeof (sin));
+    memset(&sin, 0, sizeof (sin));
     sin.sin_family = AF_INET;
     sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
     ret = sss_get_dualstack_addresses(dyndns_test_ctx,
@@ -409,7 +669,7 @@ void dyndns_test_dualstack_multiple_addresses(void **state)
     }
 
     struct sockaddr_in sin;
-    memset (&sin, 0, sizeof (sin));
+    memset(&sin, 0, sizeof (sin));
     sin.sin_family = AF_INET;
     sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
     ret = sss_get_dualstack_addresses(dyndns_test_ctx,
@@ -484,7 +744,7 @@ void dyndns_test_dualstack_no_iface(void **state)
     will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
 
     struct sockaddr_in sin;
-    memset (&sin, 0, sizeof (sin));
+    memset(&sin, 0, sizeof (sin));
     sin.sin_family = AF_INET;
     sin.sin_addr.s_addr = inet_addr ("192.168.0.3");
     ret = sss_get_dualstack_addresses(dyndns_test_ctx,
@@ -739,6 +999,20 @@ int main(int argc, const char *argv[])
         cmocka_unit_test_setup_teardown(dyndns_test_dualstack_no_iface,
                                         dyndns_test_simple_setup,
                                         dyndns_test_teardown),
+
+        /* Messages for nsupdate */
+        cmocka_unit_test_setup_teardown(dyndns_test_create_fwd_msg,
+                                        dyndns_test_setup,
+                                        dyndns_test_teardown),
+        cmocka_unit_test_setup_teardown(dyndns_test_create_fwd_msg_mult,
+                                        dyndns_test_setup,
+                                        dyndns_test_teardown),
+        cmocka_unit_test_setup_teardown(dyndns_test_create_fwd_msg_A,
+                                        dyndns_test_setup,
+                                        dyndns_test_teardown),
+        cmocka_unit_test_setup_teardown(dyndns_test_create_fwd_msg_AAAA,
+                                        dyndns_test_setup,
+                                        dyndns_test_teardown),
     };
 
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
-- 
2.4.3

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to