summaryrefslogtreecommitdiffstats
path: root/src/providers
diff options
context:
space:
mode:
authorPavel Reichl <preichl@redhat.com>2015-07-14 09:56:59 -0400
committerJakub Hrozek <jhrozek@redhat.com>2015-07-24 09:30:41 +0200
commitb0a8ed519554f8896e35812e0759862c33f157fe (patch)
treee608043a83649d19ce1e26502a874be1f68e0f89 /src/providers
parent1112e84494bcfd0f658e073d25f15ed877d047aa (diff)
downloadsssd-b0a8ed519554f8896e35812e0759862c33f157fe.tar.gz
sssd-b0a8ed519554f8896e35812e0759862c33f157fe.tar.xz
sssd-b0a8ed519554f8896e35812e0759862c33f157fe.zip
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
Diffstat (limited to 'src/providers')
-rw-r--r--src/providers/dp_dyndns.c135
-rw-r--r--src/providers/dp_dyndns.h8
-rw-r--r--src/providers/ldap/sdap_dyndns.c20
3 files changed, 124 insertions, 39 deletions
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 03389acfb..c254d7893 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 deba11253..a8a20ec6f 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 f5929cff3..a463a2fce 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;
}