I hope attached patch set addresses all concerns, thanks!
>From 228335d2a51b5624f8500e69418e0df1355dc64c Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Wed, 8 Jul 2015 09:01:24 -0400
Subject: [PATCH 1/5] DYNDNS: sss_iface_addr_list_get return ENOENT

If none of eligible interfaces matches ifname then ENOENT is returned.

Resolves:
https://fedorahosted.org/sssd/ticket/2549
---
 src/providers/dp_dyndns.c        | 13 +++++++++++--
 src/providers/ldap/sdap_dyndns.c |  6 +++++-
 src/tests/cmocka/test_dyndns.c   | 20 ++++++++++++++++++++
 3 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 1cac3d0fae2454cea823ed640a4325f27580353f..2ac43a108ff6197d9e2662198a6da976ca348e76 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -222,8 +222,17 @@ sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
         }
     }
 
-    ret = EOK;
-    *_addrlist = addrlist;
+    if (addrlist != NULL) {
+        /* OK, some result was found */
+        ret = EOK;
+        *_addrlist = addrlist;
+    } else {
+        /* No result was found */
+        DEBUG(SSSDBG_TRACE_FUNC,
+              "No IPs usable for DNS was found for interface: %s.\n", ifname);
+        ret = ENOENT;
+    }
+
 done:
     freeifaddrs(ifaces);
     return ret;
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index 0d9c9205792062378aa25aad6ac706058001433a..e99a4f6687035928f6775c38b9df6b2a06d38f38 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -502,8 +502,12 @@ sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
     if (iface) {
         ret = sss_iface_addr_list_get(state, iface, &state->addresses);
         if (ret != EOK) {
-            DEBUG(SSSDBG_OP_FAILURE,
+            DEBUG(ret == ENOENT ? SSSDBG_MINOR_FAILURE : SSSDBG_OP_FAILURE,
                   "Cannot get list of addresses from interface %s\n", iface);
+            /* non critical failure */
+            if (ret == ENOENT) {
+                ret = EOK;
+            }
         }
         /* We're done. Just fake an async request completion */
         goto done;
diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
index 689e333d4e68c4a2582894d06b8b7b20c76b9be8..3214e90c063ea9a4cf6f6bc6507bf4e37b7d23a4 100644
--- a/src/tests/cmocka/test_dyndns.c
+++ b/src/tests/cmocka/test_dyndns.c
@@ -247,6 +247,23 @@ void dyndns_test_get_multi_ifaddr(void **state)
     assert_true(check_leaks_pop(dyndns_test_ctx) == true);
 }
 
+void dyndns_test_get_ifaddr_enoent(void **state)
+{
+    errno_t ret;
+    struct sss_iface_addr *addrlist = NULL;
+
+    check_leaks_push(dyndns_test_ctx);
+    will_return_getifaddrs("eth0", "192.168.0.1");
+    will_return_getifaddrs("eth1", "192.168.0.2");
+    will_return_getifaddrs(NULL, NULL); /* sentinel */
+    ret = sss_iface_addr_list_get(dyndns_test_ctx, "non_existing_interface",
+                                  &addrlist);
+    assert_int_equal(ret, ENOENT);
+    talloc_free(addrlist);
+
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
 void dyndns_test_ok(void **state)
 {
     struct tevent_req *req;
@@ -460,6 +477,9 @@ int main(int argc, const char *argv[])
         cmocka_unit_test_setup_teardown(dyndns_test_get_multi_ifaddr,
                                         dyndns_test_simple_setup,
                                         dyndns_test_teardown),
+        cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr_enoent,
+                                        dyndns_test_simple_setup,
+                                        dyndns_test_teardown),
 
         /* Dynamic DNS update unit tests*/
         cmocka_unit_test_setup_teardown(dyndns_test_ok,
-- 
2.4.3

>From 85f0066770be3c9b6b1591071c218162e8f9b25b Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Wed, 8 Jul 2015 09:08:03 -0400
Subject: [PATCH 2/5] DYNDNS: support mult. interfaces for dyndns_iface opt

Resolves:
https://fedorahosted.org/sssd/ticket/2549
---
 src/man/sssd-ad.5.xml            | 11 +++---
 src/man/sssd-ipa.5.xml           | 10 ++++--
 src/providers/dp_dyndns.c        |  6 ++++
 src/providers/dp_dyndns.h        |  4 +++
 src/providers/ldap/sdap_dyndns.c | 72 +++++++++++++++++++++++++++++++++++-----
 5 files changed, 87 insertions(+), 16 deletions(-)

diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
index 938a443e027b9bf83c75c240a7d6b2a0876b92c8..ff43ea37066514a87934d07b141e680416dcc05b 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -754,15 +754,16 @@ ad_gpo_map_deny = +my_pam_service
                     <listitem>
                         <para>
                             Optional. Applicable only when dyndns_update
-                            is true. Choose the interface whose IP address
-                            should be used for dynamic DNS updates.
-                        </para>
-                        <para>
-                            NOTE: This option currently supports only one interface.
+                            is true. Choose the interface or a list of interfaces
+                            whose IP addresses should be used for dynamic DNS
+                            updates.
                         </para>
                         <para>
                             Default: Use the IP address of the AD LDAP connection
                         </para>
+                        <para>
+                            Example: dyndns_iface = em1, vnet1, vnet2
+                        </para>
                     </listitem>
                 </varlistentry>
 
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index 0716b6235f93965170983856b930799bfded6258..d450c2fadbb1713096ff766bf536702195cfd137 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -166,11 +166,12 @@
                     <listitem>
                         <para>
                             Optional. Applicable only when dyndns_update
-                            is true. Choose the interface whose IP address
-                            should be used for dynamic DNS updates.
+                            is true. Choose the interface or a list of interfaces
+                            whose IP addresses should be used for dynamic DNS
+                            updates.
                         </para>
                         <para>
-                            NOTE: This option currently supports only one interface.
+                            NOTE: This option currently supports multiple interfaces.
                         </para>
                         <para>
                             NOTE: While it is still possible to use the old
@@ -181,6 +182,9 @@
                         <para>
                             Default: Use the IP address of the IPA LDAP connection
                         </para>
+                        <para>
+                            Example: dyndns_iface = em1, vnet1, vnet2
+                        </para>
                     </listitem>
                 </varlistentry>
 
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 2ac43a108ff6197d9e2662198a6da976ca348e76..76562840ef1d427629e41617b871caaedab779d4 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -49,6 +49,12 @@ struct sss_iface_addr {
     struct sockaddr_storage *addr;
 };
 
+void sss_iface_addr_concatenate(struct sss_iface_addr **list,
+                                struct sss_iface_addr *list2)
+{
+    DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
+}
+
 struct sss_iface_addr *
 sss_iface_addr_add(TALLOC_CTX *mem_ctx, struct sss_iface_addr **list,
                    struct sockaddr_storage *ss)
diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
index 23b833dace58a0ecbb1e2e21963a55186f1d06a8..deba112538ad22cd7f59be07934778ee9d4361e7 100644
--- a/src/providers/dp_dyndns.h
+++ b/src/providers/dp_dyndns.h
@@ -128,4 +128,8 @@ nsupdate_get_addrs_recv(struct tevent_req *req,
                         struct sss_iface_addr **_addrlist,
                         size_t *_count);
 
+void
+sss_iface_addr_concatenate(struct sss_iface_addr **list,
+                           struct sss_iface_addr *list2);
+
 #endif /* DP_DYNDNS_H_ */
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index e99a4f6687035928f6775c38b9df6b2a06d38f38..f5929cff3db6f724efcedeb963e3a12d04f6e1d3 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -482,6 +482,65 @@ static void sdap_dyndns_get_addrs_done(struct tevent_req *subreq);
 static errno_t sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
                                          struct sdap_handle *sh);
 
+static errno_t get_ifaces_addrs(TALLOC_CTX *mem_ctx,
+                                const char *iface,
+                                struct sss_iface_addr **_result)
+{
+    struct sss_iface_addr *result_addrs = NULL;
+    struct sss_iface_addr *intf_addrs;
+    TALLOC_CTX *tmp_ctx;
+    char **list_of_intfs;
+    int num_of_intfs;
+    errno_t ret;
+    int i;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = split_on_separator(tmp_ctx, iface, ',', true, true, &list_of_intfs,
+                             &num_of_intfs);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              "Parsing names of interfaces failed - %d:[%s].\n",
+              ret, sss_strerror(ret));
+        goto done;
+    }
+
+    for (i = 0; i < num_of_intfs; i++) {
+        ret = sss_iface_addr_list_get(tmp_ctx, list_of_intfs[i], &intf_addrs);
+        if (ret == EOK) {
+            if (result_addrs != NULL) {
+                /* If there is already an existing list, head of this existing
+                 * list will be considered as parent talloc context for the
+                 * new list.
+                 */
+                talloc_steal(result_addrs, intf_addrs);
+            }
+            sss_iface_addr_concatenate(&result_addrs, intf_addrs);
+        } else if (ret == ENOENT) {
+            /* non-critical failure */
+            DEBUG(SSSDBG_TRACE_FUNC,
+                  "Cannot get interface %s or there are no addresses "
+                  "bind to it.\n", list_of_intfs[i]);
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Cannot get list of addresses from interface %s - %d:[%s]\n",
+                  list_of_intfs[i], ret, sss_strerror(ret));
+            goto done;
+        }
+    }
+
+    ret = EOK;
+    *_result = talloc_steal(mem_ctx, result_addrs);
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 static struct tevent_req *
 sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
                            struct tevent_context *ev,
@@ -500,14 +559,11 @@ sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
     }
 
     if (iface) {
-        ret = sss_iface_addr_list_get(state, iface, &state->addresses);
-        if (ret != EOK) {
-            DEBUG(ret == ENOENT ? SSSDBG_MINOR_FAILURE : SSSDBG_OP_FAILURE,
-                  "Cannot get list of addresses from interface %s\n", iface);
-            /* non critical failure */
-            if (ret == ENOENT) {
-                ret = EOK;
-            }
+        ret = get_ifaces_addrs(state, iface, &state->addresses);
+        if (ret != EOK || state->addresses == NULL) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "get_ifaces_addrs() failed: %d:[%s]\n",
+                  ret, sss_strerror(ret));
         }
         /* We're done. Just fake an async request completion */
         goto done;
-- 
2.4.3

>From 7e934dbd7f045d7411181103c7fcc60033c2c8fd Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Tue, 14 Jul 2015 04:21:34 -0400
Subject: [PATCH 3/5] DYNDNS: special value '*' for dyndns_iface option

Option dyndns_iface has now special value '*' which implies that IPs
from add interfaces should be sent during DDNS update.
---
 src/man/sssd-ad.5.xml     |  6 ++++--
 src/man/sssd-ipa.5.xml    |  9 ++++-----
 src/providers/dp_dyndns.c | 20 ++++++++++++++++----
 3 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
index ff43ea37066514a87934d07b141e680416dcc05b..3cbc10520098372d984d00425d03832d002d6672 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -756,10 +756,12 @@ ad_gpo_map_deny = +my_pam_service
                             Optional. Applicable only when dyndns_update
                             is true. Choose the interface or a list of interfaces
                             whose IP addresses should be used for dynamic DNS
-                            updates.
+                            updates. Special value <quote>*</quote> implies that
+                            IPs from all interfaces should be used.
                         </para>
                         <para>
-                            Default: Use the IP address of the AD LDAP connection
+                            Default: Use the IP addresses of the interface which
+                            is used for AD LDAP connection
                         </para>
                         <para>
                             Example: dyndns_iface = em1, vnet1, vnet2
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index d450c2fadbb1713096ff766bf536702195cfd137..2e985991fde10827aff0e7c8e67f29a009683450 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -168,10 +168,8 @@
                             Optional. Applicable only when dyndns_update
                             is true. Choose the interface or a list of interfaces
                             whose IP addresses should be used for dynamic DNS
-                            updates.
-                        </para>
-                        <para>
-                            NOTE: This option currently supports multiple interfaces.
+                            updates. Special value <quote>*</quote> implies that
+                            IPs from all interfaces should be used.
                         </para>
                         <para>
                             NOTE: While it is still possible to use the old
@@ -180,7 +178,8 @@
                             in their config file.
                         </para>
                         <para>
-                            Default: Use the IP address of the IPA LDAP connection
+                            Default: Use the IP addresses of the interface which
+                            is used for IPA LDAP connection
                         </para>
                         <para>
                             Example: dyndns_iface = em1, vnet1, vnet2
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 76562840ef1d427629e41617b871caaedab779d4..03389acfba13e566540ca8b0570c0d009173575f 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -42,6 +42,9 @@
 #define DYNDNS_TIMEOUT 15
 #endif /* DYNDNS_TIMEOUT */
 
+/* MASK represents special value for matching all interfaces */
+#define MASK "*"
+
 struct sss_iface_addr {
     struct sss_iface_addr *next;
     struct sss_iface_addr *prev;
@@ -171,6 +174,16 @@ ok_for_dns(struct sockaddr *sa)
     return true;
 }
 
+static bool supported_address_family(sa_family_t sa_family)
+{
+    return sa_family == AF_INET || sa_family == AF_INET6;
+}
+
+static bool matching_name(const char *ifname, const char *ifname2)
+{
+    return (strcmp(MASK, ifname) == 0) || (strcasecmp(ifname, ifname2) == 0);
+}
+
 /* Collect IP addresses associated with an interface */
 errno_t
 sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
@@ -200,10 +213,9 @@ sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
         if (!ifa->ifa_addr) continue;
 
         /* Add IP addresses to the list */
-        if ((ifa->ifa_addr->sa_family == AF_INET ||
-             ifa->ifa_addr->sa_family == AF_INET6) &&
-             strcasecmp(ifa->ifa_name, ifname) == 0 &&
-             ok_for_dns(ifa->ifa_addr)) {
+        if (supported_address_family(ifa->ifa_addr->sa_family)
+                && matching_name(ifname, ifa->ifa_name)
+                && ok_for_dns(ifa->ifa_addr)) {
 
             /* Add this address to the IP address list */
             address = talloc_zero(mem_ctx, struct sss_iface_addr);
-- 
2.4.3

>From 5f5b582a863f839633927c87de9b1e289f1e5eb4 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Wed, 15 Jul 2015 10:58:38 -0400
Subject: [PATCH 4/5] TESTS: dyndns tests support AAAA addresses

Resolves:
https://fedorahosted.org/sssd/ticket/2558
---
 src/tests/cmocka/test_dyndns.c | 51 +++++++++++++++++++++++++++++++-----------
 1 file changed, 38 insertions(+), 13 deletions(-)

diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
index 3214e90c063ea9a4cf6f6bc6507bf4e37b7d23a4..e9d42cea37472b38ae2eb900368f2ce3f409fefc 100644
--- a/src/tests/cmocka/test_dyndns.c
+++ b/src/tests/cmocka/test_dyndns.c
@@ -97,7 +97,9 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap)
     struct ifaddrs *ifap_head = NULL;
     char *name;
     char *straddr;
+    int ad_family;
     struct sockaddr_in *sa;
+    void *dst;
 
     while ((name = sss_mock_ptr_type(char *)) != NULL) {
         straddr = sss_mock_ptr_type(char *);
@@ -105,6 +107,7 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap)
             errno = EINVAL;
             goto fail;
         }
+        ad_family = sss_mock_type(int);
 
         ifap = talloc_zero(global_mock_context, struct ifaddrs);
         if (ifap == NULL) {
@@ -127,15 +130,33 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap)
 
         /* Do not alocate directly on ifap->ifa_addr to
          * avoid alignment warnings */
-        sa = talloc(ifap, struct sockaddr_in);
+        if (ad_family == AF_INET) {
+            sa = talloc(ifap, struct sockaddr_in);
+        } else if (ad_family == AF_INET6) {
+            sa = (struct sockaddr_in *) talloc(ifap, struct sockaddr_in6);
+        } else {
+            errno = EINVAL;
+            goto fail;
+        }
+
         if (sa == NULL) {
             errno = ENOMEM;
             goto fail;
         }
-        sa->sin_family = AF_INET;
+
+        sa->sin_family = ad_family;
+
+        if (ad_family == AF_INET) {
+            dst = &sa->sin_addr;
+        } else if (ad_family == AF_INET6) {
+            dst = &((struct sockaddr_in6 *)sa)->sin6_addr;
+        } else {
+            errno = EINVAL;
+            goto fail;
+        }
 
         /* convert straddr into ifa_addr */
-        if (inet_pton(AF_INET, straddr, &sa->sin_addr) != 1) {
+        if (inet_pton(ad_family, straddr, dst) != 1) {
             goto fail;
         }
 
@@ -167,12 +188,16 @@ static void dyndns_test_done(struct tevent_req *req)
     ctx->tctx->done = true;
 }
 
-void will_return_getifaddrs(const char *ifname, const char *straddr)
+void will_return_getifaddrs(const char *ifname, const char *straddr,
+                            int af_family)
 {
     will_return(__wrap_getifaddrs, ifname);
     if (ifname) {
         will_return(__wrap_getifaddrs, straddr);
     }
+    if (straddr) {
+        will_return(__wrap_getifaddrs, af_family);
+    }
 }
 
 void dyndns_test_get_ifaddr(void **state)
@@ -182,9 +207,9 @@ void dyndns_test_get_ifaddr(void **state)
     char straddr[128];
 
     check_leaks_push(dyndns_test_ctx);
-    will_return_getifaddrs("eth0", "192.168.0.1");
-    will_return_getifaddrs("eth1", "192.168.0.2");
-    will_return_getifaddrs(NULL, NULL); /* sentinel */
+    will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
+    will_return_getifaddrs("eth1", "192.168.0.2", AF_INET);
+    will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
     ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
     assert_int_equal(ret, EOK);
 
@@ -212,9 +237,9 @@ void dyndns_test_get_multi_ifaddr(void **state)
     char straddr[128];
 
     check_leaks_push(dyndns_test_ctx);
-    will_return_getifaddrs("eth0", "192.168.0.2");
-    will_return_getifaddrs("eth0", "192.168.0.1");
-    will_return_getifaddrs(NULL, NULL); /* sentinel */
+    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 */
     ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
     assert_int_equal(ret, EOK);
 
@@ -253,9 +278,9 @@ void dyndns_test_get_ifaddr_enoent(void **state)
     struct sss_iface_addr *addrlist = NULL;
 
     check_leaks_push(dyndns_test_ctx);
-    will_return_getifaddrs("eth0", "192.168.0.1");
-    will_return_getifaddrs("eth1", "192.168.0.2");
-    will_return_getifaddrs(NULL, NULL); /* sentinel */
+    will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
+    will_return_getifaddrs("eth1", "192.168.0.2", AF_INET);
+    will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
     ret = sss_iface_addr_list_get(dyndns_test_ctx, "non_existing_interface",
                                   &addrlist);
     assert_int_equal(ret, ENOENT);
-- 
2.4.3

>From 9270b22ded3d4ec42fa16deac7acb5969cfd6eea Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Tue, 14 Jul 2015 09:56:59 -0400
Subject: [PATCH 5/5] DYNDNS: support for dualstack

When dyndns_iface option was not used, address of connection to LDAP
was used. This patch proposes following change:
  * Interface containing address of connection is found.
  * All A and AAAA addresses of this interface are collected.
  * Collected addresses are sent during DDNS update.
  * Function sss_iface_addr_add() is removed.

Resolves:
https://fedorahosted.org/sssd/ticket/2558
---
 src/providers/dp_dyndns.c        | 135 +++++++++++++++++++++++------
 src/providers/dp_dyndns.h        |   8 +-
 src/providers/ldap/sdap_dyndns.c |  20 ++---
 src/tests/cmocka/test_dyndns.c   | 178 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 302 insertions(+), 39 deletions(-)

diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 03389acfba13e566540ca8b0570c0d009173575f..c254d78936f412626db0533f559350de57017618 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -58,31 +58,6 @@ void sss_iface_addr_concatenate(struct sss_iface_addr **list,
     DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
 }
 
-struct sss_iface_addr *
-sss_iface_addr_add(TALLOC_CTX *mem_ctx, struct sss_iface_addr **list,
-                   struct sockaddr_storage *ss)
-{
-    struct sss_iface_addr *address;
-
-    address = talloc(mem_ctx, struct sss_iface_addr);
-    if (address == NULL) {
-        return NULL;
-    }
-
-    address->addr = talloc_memdup(address, ss,
-                                  sizeof(struct sockaddr_storage));
-    if(address->addr == NULL) {
-        talloc_zfree(address);
-        return NULL;
-    }
-
-    /* steal old dlist to the new head */
-    talloc_steal(address, *list);
-    DLIST_ADD(*list, address);
-
-    return address;
-}
-
 errno_t
 sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
                                 struct sss_iface_addr *ifaddr_list,
@@ -1258,3 +1233,113 @@ errno_t be_nsupdate_init_timer(struct be_nsupdate_ctx *ctx,
 
     return ERR_OK;
 }
+
+static bool match_ip(const struct sockaddr *sa,
+                     const struct sockaddr *sb)
+{
+    size_t addrsize;
+    bool res;
+    const void *addr_a;
+    const void *addr_b;
+
+    if (sa->sa_family == AF_INET) {
+        addrsize = sizeof(struct in_addr);
+        addr_a = (const void *) &((const struct sockaddr_in *) sa)->sin_addr;
+        addr_b = (const void *) &((const struct sockaddr_in *) sb)->sin_addr;
+    } else if (sa->sa_family == AF_INET6) {
+        addrsize = sizeof(struct in6_addr);
+        addr_a = (const void *) &((const struct sockaddr_in6 *) sa)->sin6_addr;
+        addr_b = (const void *) &((const struct sockaddr_in6 *) sb)->sin6_addr;
+    } else {
+        res = false;
+        goto done;
+    }
+
+    if (sa->sa_family != sb->sa_family) {
+        res = false;
+        goto done;
+    }
+
+    res = memcmp(addr_a, addr_b, addrsize) == 0;
+
+done:
+    return res;
+}
+
+static errno_t find_iface_by_addr(TALLOC_CTX *mem_ctx,
+                                  const struct sockaddr *ss,
+                                  const char **_iface_name)
+{
+    struct ifaddrs *ifaces = NULL;
+    struct ifaddrs *ifa;
+    errno_t ret;
+
+    ret = getifaddrs(&ifaces);
+    if (ret == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_OP_FAILURE,
+              "Could not read interfaces [%d][%s]\n", ret, sss_strerror(ret));
+        goto done;
+    }
+
+    for (ifa = ifaces; ifa != NULL; ifa = ifa->ifa_next) {
+
+        /* Some interfaces don't have an ifa_addr */
+        if (!ifa->ifa_addr) continue;
+
+        if (match_ip(ss, ifa->ifa_addr)) {
+            const char *iface_name;
+            iface_name = talloc_strdup(mem_ctx, ifa->ifa_name);
+            if (iface_name == NULL) {
+                ret = ENOMEM;
+            } else {
+                *_iface_name = iface_name;
+                ret = EOK;
+            }
+            goto done;
+        }
+    }
+    ret = ENOENT;
+
+done:
+    freeifaddrs(ifaces);
+    return ret;
+}
+
+errno_t sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
+                                    struct sockaddr *ss,
+                                    struct sss_iface_addr **_iface_addrs)
+{
+    struct sss_iface_addr *iface_addrs;
+    const char *iface_name = NULL;
+    TALLOC_CTX *tmp_ctx;
+    errno_t ret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = find_iface_by_addr(tmp_ctx, ss, &iface_name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "find_iface_by_addr failed: %d:[%s]\n",
+              ret, sss_strerror(ret));
+        goto done;
+    }
+
+    ret = sss_iface_addr_list_get(tmp_ctx, iface_name, &iface_addrs);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              "sss_iface_addr_list_get failed: %d:[%s]\n",
+              ret, sss_strerror(ret));
+        goto done;
+    }
+
+    ret = EOK;
+    *_iface_addrs = talloc_steal(mem_ctx, iface_addrs);
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
index deba112538ad22cd7f59be07934778ee9d4361e7..a8a20ec6f8a1a63cd8c85aaec3f54f9fddb42049 100644
--- a/src/providers/dp_dyndns.h
+++ b/src/providers/dp_dyndns.h
@@ -81,10 +81,6 @@ errno_t
 sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
                         struct sss_iface_addr **_addrlist);
 
-struct sss_iface_addr *
-sss_iface_addr_add(TALLOC_CTX *mem_ctx, struct sss_iface_addr **list,
-                   struct sockaddr_storage *ss);
-
 errno_t
 sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
                                 struct sss_iface_addr *ifaddr_list,
@@ -132,4 +128,8 @@ void
 sss_iface_addr_concatenate(struct sss_iface_addr **list,
                            struct sss_iface_addr *list2);
 
+errno_t
+sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
+                            struct sockaddr *ss,
+                            struct sss_iface_addr **_iface_addrs);
 #endif /* DP_DYNDNS_H_ */
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index f5929cff3db6f724efcedeb963e3a12d04f6e1d3..a463a2fce08f42b325010cd37c501ef23aee173f 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -644,7 +644,6 @@ sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
 {
     int ret;
     int fd;
-    struct sss_iface_addr *address;
     struct sockaddr_storage ss;
     socklen_t ss_len = sizeof(ss);
 
@@ -666,20 +665,21 @@ sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
         return ret;
     }
 
-    switch(ss.ss_family) {
-    case AF_INET:
-    case AF_INET6:
-        address = sss_iface_addr_add(state, &state->addresses, &ss);
-        if (address == NULL) {
-            return ENOMEM;
-        }
-        break;
-    default:
+    if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Connection to LDAP is neither IPv4 nor IPv6\n");
         return EIO;
     }
 
+    ret = sss_get_dualstack_addresses(state, (struct sockaddr *) &ss,
+                                      &state->addresses);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              "sss_get_dualstack_addresses failed: %d:[%s]\n",
+              ret, sss_strerror(ret));
+        return ret;
+    }
+
     return EOK;
 }
 
diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
index e9d42cea37472b38ae2eb900368f2ce3f409fefc..8118e9438e89465674155c11f4523d2313f6a59c 100644
--- a/src/tests/cmocka/test_dyndns.c
+++ b/src/tests/cmocka/test_dyndns.c
@@ -289,6 +289,173 @@ void dyndns_test_get_ifaddr_enoent(void **state)
     assert_true(check_leaks_pop(dyndns_test_ctx) == true);
 }
 
+void dyndns_test_dualstack(void **state)
+{
+    errno_t ret;
+    struct sss_iface_addr *addrlist;
+    struct sss_iface_addr *sss_if_addrs;
+    char straddr[128];
+    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);
+
+    sss_if_addrs = addrlist;
+    assert_non_null(sss_if_addrs);
+    assert_non_null(sss_if_addrs->addr);
+    assert_non_null(sss_if_addrs->next);
+    assert_null(sss_if_addrs->prev);
+
+    assert_non_null(inet_ntop(AF_INET6,
+                              &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
+                              straddr, INET6_ADDRSTRLEN));
+    /* ip addresses are returned in different order */
+    assert_string_equal(straddr, "2001:cdba::555");
+
+    sss_if_addrs = addrlist->next;
+    assert_non_null(sss_if_addrs);
+    assert_non_null(sss_if_addrs->addr);
+    assert_null(sss_if_addrs->next);
+    assert_non_null(sss_if_addrs->prev);
+
+    assert_non_null(inet_ntop(AF_INET,
+                              &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
+                              straddr, INET_ADDRSTRLEN));
+    /* ip addresses are returned in different order */
+    assert_string_equal(straddr, "192.168.0.2");
+
+    talloc_free(addrlist);
+
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
+void dyndns_test_dualstack_multiple_addresses(void **state)
+{
+    errno_t ret;
+    struct sss_iface_addr *addrlist;
+    struct sss_iface_addr *sss_if_addrs;
+    char straddr[128];
+    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);
+        /* loopback - invalid for dns (should be skipped) */
+        will_return_getifaddrs("eth0", "::1", AF_INET6);
+        /* linklocal - invalid for dns (should be skipped) */
+        will_return_getifaddrs("eth0", "fe80::5054:ff:fe4a:65ae", AF_INET6);
+        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);
+
+    sss_if_addrs = addrlist;
+    assert_non_null(sss_if_addrs);
+    assert_non_null(sss_if_addrs->addr);
+    assert_non_null(sss_if_addrs->next);
+    assert_null(sss_if_addrs->prev);
+
+    assert_non_null(inet_ntop(AF_INET6,
+                              &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
+                              straddr, INET6_ADDRSTRLEN));
+    /* ip addresses are returned in different order */
+    assert_string_equal(straddr, "2001:cdba::444");
+
+    sss_if_addrs = sss_if_addrs->next;
+    assert_non_null(sss_if_addrs);
+    assert_non_null(sss_if_addrs->addr);
+    assert_non_null(sss_if_addrs->prev);
+    assert_non_null(sss_if_addrs->next);
+
+    assert_non_null(inet_ntop(AF_INET6,
+                              &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
+                              straddr, INET6_ADDRSTRLEN));
+    /* ip addresses are returned in different order */
+    assert_string_equal(straddr, "2001:cdba::555");
+
+    sss_if_addrs = sss_if_addrs->next;
+    assert_non_null(sss_if_addrs);
+    assert_non_null(sss_if_addrs->addr);
+    assert_non_null(sss_if_addrs->next);
+    assert_non_null(sss_if_addrs->prev);
+
+    assert_non_null(inet_ntop(AF_INET,
+                              &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
+                              straddr, INET_ADDRSTRLEN));
+    /* ip addresses are returned in different order */
+    assert_string_equal(straddr, "192.168.0.1");
+
+    sss_if_addrs = sss_if_addrs->next;
+    assert_non_null(sss_if_addrs);
+    assert_non_null(sss_if_addrs->addr);
+    assert_null(sss_if_addrs->next);
+    assert_non_null(sss_if_addrs->prev);
+
+    assert_non_null(inet_ntop(AF_INET,
+                              &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
+                              straddr, INET_ADDRSTRLEN));
+    /* ip addresses are returned in different order */
+    assert_string_equal(straddr, "192.168.0.2");
+
+    talloc_free(addrlist);
+
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
+void dyndns_test_dualstack_no_iface(void **state)
+{
+    errno_t ret;
+    struct sss_iface_addr *addrlist;
+
+    check_leaks_push(dyndns_test_ctx);
+
+    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.3");
+    ret = sss_get_dualstack_addresses(dyndns_test_ctx,
+                                      (struct sockaddr *) &sin,
+                                      &addrlist);
+    assert_int_equal(ret, ENOENT);
+
+    assert_true(check_leaks_pop(dyndns_test_ctx) == true);
+}
+
 void dyndns_test_ok(void **state)
 {
     struct tevent_req *req;
@@ -519,6 +686,17 @@ int main(int argc, const char *argv[])
         cmocka_unit_test_setup_teardown(dyndns_test_interval,
                                         dyndns_test_setup,
                                         dyndns_test_teardown),
+
+        /* Dynamic DNS dualstack unit tests*/
+        cmocka_unit_test_setup_teardown(dyndns_test_dualstack,
+                                        dyndns_test_simple_setup,
+                                        dyndns_test_teardown),
+        cmocka_unit_test_setup_teardown(dyndns_test_dualstack_multiple_addresses,
+                                        dyndns_test_simple_setup,
+                                        dyndns_test_teardown),
+        cmocka_unit_test_setup_teardown(dyndns_test_dualstack_no_iface,
+                                        dyndns_test_simple_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
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to