* (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
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
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);
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;
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;
#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.
*
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:
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);
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()`.
netresolve_t channel;
netresolve_query_t query;
struct hostent *tmp;
- int lerrno;
if (!(channel = netresolve_open())) {
*result = NULL;
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;
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;
{
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);
+}
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 */
--- /dev/null
+query:
+ address = 127.0.0.1
+result:
+ name = localhost
+ aliases:
+ addrtype = 2
+ length = 4
+ address = 7f000001
+ addresses:
+ #0 = 7f000001
--- /dev/null
+query:
+ address = 127.0.0.1
+status = 0
+result:
+ host = localhost
+ serv = http
#!/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