compat: add getnameinfo, gethostbyaddr and res_query
authorPavel Šimerda <psimerda@redhat.com>
Tue, 28 Oct 2014 12:52:55 +0000 (13:52 +0100)
committerPavel Šimerda <psimerda@redhat.com>
Tue, 28 Oct 2014 16:52:53 +0000 (17:52 +0100)
compat/compat.c
compat/libc.c
compat/netresolve-compat.h
tests/data/gethostbyaddr [new file with mode: 0644]
tests/data/getnameinfo [new file with mode: 0644]
tests/test-compat.sh

index ba90f6dabb7474b12047504db8a1567b32a85ef0..55d39f51ad2ffbbe2153bc56373615d448b9b3d1 100644 (file)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#include <netresolve-compat.h>
 #include <stdlib.h>
 #include <string.h>
 
+/* FIXME: Would be nicer to only require `netresolve-compat.h`. */
+#include <netresolve-private.h>
+
 /* netresolve_query_getaddrinfo:
  *
  * Configures the channel and calls `netresolve_query()` according to the
@@ -98,19 +100,42 @@ netresolve_query_getaddrinfo_done(netresolve_query_t query, struct addrinfo **re
        return *res ? 0 : EAI_NODATA;
 }
 
-void
-netresolve_query_getaddrinfo_free(struct addrinfo *ai)
+netresolve_query_t
+netresolve_query_getnameinfo(netresolve_t channel, const struct sockaddr *sa, socklen_t salen, int flags)
 {
-       struct addrinfo *tmp;
-
-       while (ai) {
-               tmp = ai;
-               ai = ai->ai_next;
-               free(tmp->ai_canonname);
-               free(tmp);
+       struct sockaddr_in *sa4 = (void *) sa;
+       struct sockaddr_in6 *sa6 = (void *) sa;
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               if (salen != sizeof *sa4)
+                       return NULL;
+               return netresolve_query_reverse(channel, sa4->sin_family, &sa4->sin_addr, 0, ntohs(sa4->sin_port));
+       case AF_INET6:
+               if (salen != sizeof *sa6)
+                       return NULL;
+               return netresolve_query_reverse(channel, sa6->sin6_family, &sa6->sin6_addr, sa6->sin6_scope_id, ntohs(sa6->sin6_port));
+       default:
+               return NULL;
        }
 }
 
+int
+netresolve_query_getnameinfo_done(netresolve_query_t query, char **node, char **service, int32_t *ttl)
+{
+       const char *mynode = netresolve_query_get_node_name(query);
+       const char *myservice = netresolve_query_get_service_name(query);
+
+       if (node)
+               *node = mynode ? strdup(mynode) : NULL;
+       if (service)
+               *service = myservice ? strdup(myservice) : NULL;
+
+       netresolve_query_done(query);
+
+       return 0;
+}
+
 /* netresolve_query_gethostbyname:
  *
  * Calls `netresolve_query()` to just resolve a node name. As its operation
@@ -129,8 +154,8 @@ netresolve_query_gethostbyname(netresolve_t channel, const char *name, int famil
        return netresolve_query(channel, name, NULL);
 }
 
-struct hostent *
-netresolve_query_gethostbyname_done(netresolve_query_t query, int *errnop, int *h_errnop, int32_t *ttlp)
+static struct hostent *
+get_hostent(netresolve_query_t query, int *h_errnop, int32_t *ttlp)
 {
        size_t npaths = netresolve_query_get_count(query);
        const char *canonname = netresolve_query_get_node_name(query);
@@ -138,11 +163,6 @@ netresolve_query_gethostbyname_done(netresolve_query_t query, int *errnop, int *
        int idx;
        int n = 0;
 
-       if (!npaths) {
-               *h_errnop = HOST_NOT_FOUND;
-               goto out;
-       }
-
        if (!(he = calloc(1, sizeof *he))) {
                *h_errnop = NO_RECOVERY;
                goto out;
@@ -192,8 +212,63 @@ out:
        return he;
 }
 
+struct hostent *
+netresolve_query_gethostbyname_done(netresolve_query_t query, int *h_errnop, int32_t *ttlp)
+{
+       size_t npaths = netresolve_query_get_count(query);
+
+       if (!npaths) {
+               *h_errnop = HOST_NOT_FOUND;
+               return NULL;
+       }
+
+       return get_hostent(query, h_errnop, ttlp);
+}
+
+netresolve_query_t
+netresolve_query_gethostbyaddr(netresolve_t channel, const void *address, int length, int family)
+{
+       switch (family) {
+       case AF_INET:
+               if (length != 4)
+                       return NULL;
+               break;
+       case AF_INET6:
+               if (length != 16)
+                       return NULL;
+       default:
+               return NULL;
+       }
+
+       netresolve_query_t query = netresolve_query_reverse(channel, family, address, 0, 0);
+
+       if (query)
+               netresolve_backend_add_path(query, family, address, 0, 0, 0, 0, 0, 0, 0);
+
+       return query;
+}
+
+struct hostent *
+netresolve_query_gethostbyaddr_done(netresolve_query_t query, int *h_errnop, int32_t *ttlp)
+{
+       return get_hostent(query, h_errnop, ttlp);
+}
+
+void
+netresolve_freeaddrinfo(struct addrinfo *ai)
+{
+       struct addrinfo *tmp;
+
+       while (ai) {
+               tmp = ai;
+               ai = ai->ai_next;
+               free(tmp->ai_canonname);
+               free(tmp);
+       }
+}
+
 void
-netresolve_query_gethostbyname_free(struct hostent *he)
+netresolve_freehostent(struct hostent *he)
 {
        char **p;
 
index 5ff92d73e3a85bd5c41a3abaf3486dd1ed70c0c3..d40308f85d781c7bf9abed0b676a8338ec9aabe7 100644 (file)
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
+#include <resolv.h>
 
 /* getaddrinfo:
  *
- * Resolve `nodename` and `servname` using `hints` into a linked list of
+ * Translate `nodename` and `servname` using `hints` into a linked list of
  * address records including both L3 and L4 information. Canonical name,
  * if requested, is present in the first address record.
  *
@@ -64,7 +65,55 @@ getaddrinfo(const char *nodename, const char *servname,
 void
 freeaddrinfo(struct addrinfo *result)
 {
-       netresolve_query_getaddrinfo_free(result);
+       netresolve_freeaddrinfo(result);
+}
+
+/* getnameinfo:
+ *
+ * Translate the `sa` into `host` and `serv`. The caller supplies buffers to
+ * store the result.
+ *
+ * Defined in POSIX.1-2008.
+ */
+int getnameinfo(const struct sockaddr *sa, socklen_t salen,
+               char *host, socklen_t hostlen,
+               char *serv, socklen_t servlen,
+               int flags)
+{
+       netresolve_t channel;
+       netresolve_query_t query;
+       int status = EAI_SYSTEM;
+       char *myhost = NULL;
+       char *myserv = NULL;
+       int myhostlen, myservlen;
+
+       if (!(channel = netresolve_open()))
+               return status;
+
+       if ((query = netresolve_query_getnameinfo(channel, sa, salen, flags)))
+               status = netresolve_query_getnameinfo_done(query, &myhost, &myserv, NULL);
+
+       if (!status) {
+               myhostlen = myhost ? strlen(myhost) + 1 : 0;
+               myservlen = myserv ? strlen(myserv) + 1 : 0;
+               if ((host && myhostlen > hostlen) || (serv && myservlen > servlen)) {
+                       status = EAI_OVERFLOW;
+                       goto out;
+               }
+               if (host) {
+                       memset(host, 0, hostlen);
+                       if (myhost)
+                               memcpy(host, myhost, myhostlen);
+               }
+               if (serv)
+                       memset(serv, 0, servlen);
+                       if (myserv)
+                               memcpy(serv, myserv, myservlen);
+       }
+
+out:
+       netresolve_close(channel);
+       return status;
 }
 
 /* gethostbyname2:
@@ -94,8 +143,8 @@ gethostbyname2(const char *node, int family)
                return NULL;
 
        if ((query = netresolve_query_gethostbyname(channel, node, family))) {
-               netresolve_query_gethostbyname_free(he);
-               he = netresolve_query_gethostbyname_done(query, &errno, &h_errno, NULL);
+               netresolve_freehostent(he);
+               he = netresolve_query_gethostbyname_done(query, &h_errno, NULL);
        }
 
        netresolve_close(channel);
@@ -129,6 +178,27 @@ gethostbyname(const char *node)
        return gethostbyname2(node, GETHOSTBYNAME_FAMILY);
 }
 
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int type)
+{
+       static struct hostent *he = NULL;
+
+       netresolve_t channel;
+       netresolve_query_t query;
+
+       if (!(channel = netresolve_open()))
+               return NULL;
+
+       if ((query = netresolve_query_gethostbyaddr(channel, addr, len, type))) {
+               netresolve_freehostent(he);
+               he = netresolve_query_gethostbyaddr_done(query, &h_errno, NULL);
+       }
+
+       netresolve_close(channel);
+       return he;
+}
+
+
 /* gethostbyname2_r:
  *
  * Reentrant version of `gethostbyname2()`, see notes for `gethostbyname()`.
@@ -141,7 +211,6 @@ gethostbyname2_r(const char *name, int family,
        netresolve_t channel;
        netresolve_query_t query;
        struct hostent *tmp;
-       int lerrno;
 
        if (!(channel = netresolve_open())) {
                *result = NULL;
@@ -154,7 +223,7 @@ gethostbyname2_r(const char *name, int family,
                return errno;
        }
 
-       tmp = netresolve_query_gethostbyname_done(query, &lerrno, h_errnop, NULL);
+       tmp = netresolve_query_gethostbyname_done(query, h_errnop, NULL);
 
        size_t len_name = tmp->h_name ? strlen(tmp->h_name) + 1 : 0;
        size_t count = 0;
@@ -187,7 +256,7 @@ gethostbyname2_r(const char *name, int family,
                memcpy(he->h_addr_list[i], tmp->h_addr_list[i], he->h_length);
        }
 
-       netresolve_query_gethostbyname_free(tmp);
+       netresolve_freehostent(tmp);
        netresolve_close(channel);
 
        *result = he;
@@ -206,3 +275,41 @@ gethostbyname_r(const char *name,
 {
        return gethostbyname2_r(name, GETHOSTBYNAME_FAMILY, he, buffer, buflen, result, h_errnop);
 }
+
+static int
+_res_query(const char *dname, int class, int type, bool search, unsigned char *answer, int length)
+{
+       netresolve_t channel;
+       netresolve_query_t query;
+       const char *myanswer;
+       size_t mylength = -1;
+
+       if (!(channel = netresolve_open()))
+               return mylength;
+
+       if ((query = netresolve_query_dns(channel, dname, class, type))) {
+               myanswer = netresolve_query_get_dns_answer(query, &mylength);
+
+               if (mylength > length)
+                       goto out;
+
+               memcpy(answer, myanswer, mylength);
+       }
+
+out:
+       netresolve_query_done(query);
+       netresolve_close(channel);
+       return mylength;
+}
+
+int
+res_query(const char *dname, int class, int type, unsigned char *answer, int anslen)
+{
+       return _res_query(dname, class, type, false, answer, anslen);
+}
+
+int
+res_search(const char *dname, int class, int type, unsigned char *answer, int anslen)
+{
+       return _res_query(dname, class, type, true, answer, anslen);
+}
index 2d11e887344d6c79907bc25f7e6f5c90869ac72e..7629e7b22d3764c962313b49163b146a4bb792e6 100644 (file)
 netresolve_query_t netresolve_query_getaddrinfo(netresolve_t channel,
                const char *node, const char *service, const struct addrinfo *hints);
 int netresolve_query_getaddrinfo_done(netresolve_query_t query, struct addrinfo **res, int32_t *ttlp);
-void netresolve_query_getaddrinfo_free(struct addrinfo *ai);
+
+netresolve_query_t netresolve_query_getnameinfo(netresolve_t channel, const struct sockaddr *sa, socklen_t salen, int flags);
+int netresolve_query_getnameinfo_done(netresolve_query_t query, char **host, char **serv, int32_t *ttlp);
+
+netresolve_query_t netresolve_query_res_query(netresolve_t channel, const char *dname, int cls, int type);
+int netresolve_query_res_query_done(netresolve_query_t query, uint8_t **answer);
+
+netresolve_query_t netresolve_query_getnameinfo(netresolve_t channel, const struct sockaddr *sa, socklen_t salen, int flags);
+int netresolve_query_getnameinfo_done(netresolve_query_t query, char **host, char **serv, int32_t *ttlp);
+
+netresolve_query_t netresolve_query_res_query(netresolve_t channel, const char *dname, int cls, int type);
+int netresolve_query_res_query_done(netresolve_query_t query, uint8_t **answer);
 
 netresolve_query_t netresolve_query_gethostbyname(netresolve_t channel, const char *name, int family);
-struct hostent *netresolve_query_gethostbyname_done(netresolve_query_t query, int *errnop, int *h_errnop, int32_t *ttlp);
-void netresolve_query_gethostbyname_free(struct hostent *he);
+struct hostent *netresolve_query_gethostbyname_done(netresolve_query_t query, int *h_errnop, int32_t *ttlp);
+netresolve_query_t netresolve_query_gethostbyaddr(netresolve_t channel, const void *address, int length, int family);
+struct hostent *netresolve_query_gethostbyaddr_done(netresolve_query_t query, int *h_errnop, int32_t *ttlp);
+
+void netresolve_freeaddrinfo(struct addrinfo *ai);
+void netresolve_freehostent(struct hostent *he);
 
 #endif /* NETRESOLVE_COMPAT_H */
diff --git a/tests/data/gethostbyaddr b/tests/data/gethostbyaddr
new file mode 100644 (file)
index 0000000..5548fc5
--- /dev/null
@@ -0,0 +1,10 @@
+query:
+  address = 127.0.0.1
+result:
+  name = localhost
+  aliases:
+  addrtype = 2
+  length = 4
+  address = 7f000001
+  addresses:
+    #0 = 7f000001
diff --git a/tests/data/getnameinfo b/tests/data/getnameinfo
new file mode 100644 (file)
index 0000000..9ab28f9
--- /dev/null
@@ -0,0 +1,6 @@
+query:
+  address = 127.0.0.1
+status = 0
+result:
+  host = localhost
+  serv = http
index cd5801ae1ec3b666056c46e5864110c42f180c67..cb0326c61dc5d2739d17ae3e76daa5e0eb470b3f 100755 (executable)
@@ -1,6 +1,17 @@
 #!/bin/bash -e
 
+DIFF="diff -u"
+DATA="${srcdir:-.}/tests/data"
+
+test_command() {
+    $DIFF <(./$@) tests/data/$1
+    $DIFF <(./wrapresolve ./"$@") tests/data/$1
+}
+
 for name in getaddrinfo gethostbyname{,2,_r,2_r}; do
     ./test-$name
     ./wrapresolve ./test-$name
 done
+
+test_command getnameinfo --address 127.0.0.1 --port 80
+test_command gethostbyaddr --address 127.0.0.1
This page took 0.057715 seconds and 5 git commands to generate.