From 564884526eb1bcaa4ec0e35e3d91e4405cfb3dbf Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 10 Jun 2011 14:01:17 +0200
Subject: [PATCH 1/4] Add new resolv_hostent data structure and utility
 functions

---
 src/resolv/async_resolv.c |  171 +++++++++++++++++++++++++++++++++++++++++++++
 src/resolv/async_resolv.h |   29 ++++++++
 2 files changed, 200 insertions(+), 0 deletions(-)

diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c
index 1323209..9400021 100644
--- a/src/resolv/async_resolv.c
+++ b/src/resolv/async_resolv.c
@@ -456,6 +456,177 @@ fail:
     return NULL;
 }
 
+static errno_t
+resolv_copy_in_addr(TALLOC_CTX *mem_ctx, struct resolv_addr *ret,
+                    struct ares_addrttl *attl)
+{
+    ret->ipaddr = talloc_array(mem_ctx, uint8_t, sizeof(struct in_addr));
+    if (!ret->ipaddr) return ENOMEM;
+
+    memcpy(ret->ipaddr, &attl->ipaddr, sizeof(struct in_addr));
+    ret->ttl = attl->ttl;
+
+    return EOK;
+}
+
+static errno_t
+resolv_copy_in6_addr(TALLOC_CTX *mem_ctx, struct resolv_addr *ret,
+                     struct ares_addr6ttl *a6ttl)
+{
+    ret->ipaddr = talloc_array(mem_ctx, uint8_t, sizeof(struct in6_addr));
+    if (!ret->ipaddr) return ENOMEM;
+
+    memcpy(ret->ipaddr, &a6ttl->ip6addr, sizeof(struct in6_addr));
+    ret->ttl = a6ttl->ttl;
+
+    return EOK;
+}
+
+static struct resolv_hostent *
+resolv_copy_hostent_common(TALLOC_CTX *mem_ctx, struct hostent *src)
+{
+    struct resolv_hostent *ret;
+    int len;
+    int i;
+
+    ret = talloc_zero(mem_ctx, struct resolv_hostent);
+    if (ret == NULL) {
+        return NULL;
+    }
+
+    if (src->h_name != NULL) {
+        ret->name = talloc_strdup(ret, src->h_name);
+        if (ret->name == NULL) {
+            goto fail;
+        }
+    }
+    if (src->h_aliases != NULL) {
+        for (len = 0; src->h_aliases[len] != NULL; len++);
+
+        ret->aliases = talloc_array(ret, char *, len + 1);
+        if (ret->aliases == NULL) {
+            goto fail;
+        }
+
+        for (i = 0; i < len; i++) {
+            ret->aliases[i] = talloc_strdup(ret->aliases, src->h_aliases[i]);
+            if (ret->aliases[i] == NULL) {
+                goto fail;
+            }
+        }
+        ret->aliases[len] = NULL;
+    }
+
+    ret->family = src->h_addrtype;
+    return ret;
+
+fail:
+    talloc_free(ret);
+    return NULL;
+}
+
+struct resolv_hostent *
+resolv_copy_hostent2(TALLOC_CTX *mem_ctx, struct hostent *src)
+{
+    struct resolv_hostent *ret;
+    int len;
+    int i;
+
+    ret = resolv_copy_hostent_common(mem_ctx, src);
+    if (ret == NULL) {
+        return NULL;
+    }
+
+    if (src->h_addr_list != NULL) {
+        for (len = 0; src->h_addr_list[len] != NULL; len++);
+
+        ret->addr_list = talloc_array(ret, struct resolv_addr *, len + 1);
+        if (ret->addr_list == NULL) {
+            goto fail;
+        }
+
+        for (i = 0; i < len; i++) {
+            ret->addr_list[i] = talloc_zero(ret->addr_list,
+                                            struct resolv_addr);
+            if (ret->addr_list[i] == NULL) {
+                goto fail;
+            }
+
+            ret->addr_list[i]->ipaddr = talloc_memdup(ret->addr_list[i],
+                                                      src->h_addr_list[i],
+                                                      src->h_length);
+            if (ret->addr_list[i]->ipaddr == NULL) {
+                goto fail;
+            }
+            ret->addr_list[i]->ttl = RESOLV_DEFAULT_TTL;
+        }
+        ret->addr_list[len] = NULL;
+    }
+    return ret;
+
+fail:
+    talloc_free(ret);
+    return NULL;
+}
+
+struct resolv_hostent *
+resolv_copy_hostent_ares(TALLOC_CTX *mem_ctx, struct hostent *src,
+                         int family, void *ares_ttl_data,
+                         int num_ares_ttl_data)
+{
+    struct resolv_hostent *ret;
+    errno_t cret;
+    int i;
+
+    ret = resolv_copy_hostent_common(mem_ctx, src);
+    if (ret == NULL) {
+        return NULL;
+    }
+
+    if (num_ares_ttl_data > 0) {
+        ret->addr_list = talloc_array(ret, struct resolv_addr *,
+                                      num_ares_ttl_data + 1);
+        if (ret->addr_list == NULL) {
+            goto fail;
+        }
+
+        for (i = 0; i < num_ares_ttl_data; i++) {
+            ret->addr_list[i] = talloc_zero(ret->addr_list,
+                                            struct resolv_addr);
+            if (ret->addr_list[i] == NULL) {
+                goto fail;
+            }
+
+            switch (family) {
+            case AF_INET:
+                cret = resolv_copy_in_addr(ret->addr_list, ret->addr_list[i],
+                                &((struct ares_addrttl *) ares_ttl_data)[i]);
+                break;
+            case AF_INET6:
+                cret = resolv_copy_in6_addr(ret->addr_list, ret->addr_list[i],
+                                &((struct ares_addr6ttl *) ares_ttl_data)[i]);
+                break;
+            default:
+                DEBUG(1, ("Unknown address family %d\n"));
+                goto fail;
+            }
+
+            if (cret != EOK) {
+                DEBUG(1, ("Could not copy address\n"));
+                goto fail;
+            }
+        }
+        ret->addr_list[num_ares_ttl_data] = NULL;
+    }
+
+    ret->family = family;
+    return ret;
+
+fail:
+    talloc_free(ret);
+    return NULL;
+}
+
 /*******************************************************************
  * Get host by name.                                               *
  *******************************************************************/
diff --git a/src/resolv/async_resolv.h b/src/resolv/async_resolv.h
index d6cbe14..00e1bdf 100644
--- a/src/resolv/async_resolv.h
+++ b/src/resolv/async_resolv.h
@@ -37,6 +37,10 @@
 #include "resolv/ares/ares_data.h"
 #endif /* HAVE_ARES_DATA */
 
+#ifndef RESOLV_DEFAULT_TTL
+#define RESOLV_DEFAULT_TTL 7200
+#endif  /* RESOLV_DEFAULT_TTL */
+
 /*
  * An opaque structure which holds context for a module using the async
  * resolver. Is should be used as a "local-global" variable - in sssd,
@@ -53,6 +57,31 @@ void resolv_reread_configuration(void);
 
 const char *resolv_strerror(int ares_code);
 
+/* If resolv_hostent->family is AF_INET, then ipaddr points to
+ * struct in_addr, else if family is AF_INET6, ipaddr points to
+ * struct in6_addr
+ */
+struct resolv_addr {
+    uint8_t *ipaddr;
+    int ttl;
+};
+
+struct resolv_hostent {
+    char  *name;            /* official name of host */
+    char **aliases;         /* alias list */
+    int    family;          /* host address type */
+
+    struct resolv_addr **addr_list; /* list of addresses */
+};
+
+struct resolv_hostent *
+resolv_copy_hostent2(TALLOC_CTX *mem_ctx, struct hostent *src);
+
+struct resolv_hostent *
+resolv_copy_hostent_ares(TALLOC_CTX *mem_ctx, struct hostent *src,
+                         int family, void *ares_ttl_data,
+                         int num_ares_ttl_data);
+
 struct hostent *resolv_copy_hostent(TALLOC_CTX *mem_ctx,
                                     struct hostent *src);
 
-- 
1.7.5.2

