From e1c4cb7adf3546cafa4653bd9e9e74b3a6545ef8 Mon Sep 17 00:00:00 2001 From: chris <> Date: Thu, 24 Oct 2002 14:41:03 +0000 Subject: [PATCH] "" --- Makefile | 34 ++++++++++++-- resolver.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 155 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 043b0e1..27ab9b1 100644 --- a/Makefile +++ b/Makefile @@ -21,19 +21,43 @@ CFLAGS += -I/usr/include/pcap # LDFLAGS += -pg -a # -# Uncomment to use libresolv +# Name resolution. Sensible systems have gethostbyaddr_r, which is reentrant +# and can be called from several threads of a multithreaded program. Other +# systems don't, or their implementations don't work ([cough] FreeBSD). For +# these you can use gethostbyaddr (not recommended, since then only one thread +# can resolve a name at once), libresolv (not recommended and may not work +# depending on which header files you have), or ares, an asynchronous DNS +# resolution library from +# ftp://athena-dist.mit.edu/pub/ATHENA/ares/ +# For systems without a working gethostbyaddr_r, this is recommended. # -#CFLAGS += -DUSELIBRESOLV +# Leave exactly one of these uncommented, or comment all of them out if you +# don't care about name resolution at all. +# +CFLAGS += -DUSE_GETHOSTBYADDR_R +#CFLAGS += -DUSE_GETHOSTBYADDR +#CFLAGS += -DUSE_LIBRESOLV +#CFLAGS += -DUSE_ARES -# This may be needed to use libresolv on Linux. -#LDLIBS += /usr/lib/libresolv.a +# +# Uncomment if you are using libresolv. +# +#LDLIBS += -lresolv # or /usr/lib/libresolv.a on Linux? + +# +# Uncomment if you are using ares. +# +#LDLIBS += -lares +# ... and uncomment these if your libares is in an unusual place. +#CFLAGS += -I/software/include +#LDFLAGS += -L/software/lib # PREFIX specifies the base directory for the installation. PREFIX = /usr/local #PREFIX = /software -# BINDIR is where the binary lives. No leading /. +# BINDIR is where the binary lives relative to PREFIX (no leading /). BINDIR = sbin # MANDIR is where the manual page goes. diff --git a/resolver.c b/resolver.c index aa30910..d790b24 100644 --- a/resolver.c +++ b/resolver.c @@ -14,11 +14,6 @@ #include #include -#ifdef USELIBRESOLV -#include -#include -#endif - #include "ns_hash.h" #include "iftop.h" @@ -39,7 +34,14 @@ int head; int tail; -#ifndef USELIBRESOLV +/* + * We have a choice of resolver methods. Real computers have gethostbyaddr_r, + * which is reentrant and therefore thread safe. Other machines don't, and so + * we can use non-reentrant gethostbyaddr and have only one resolver thread. + * Alternatively, we can use the MIT ares asynchronous DNS library to do this. + */ + +#if defined(USE_GETHOSTBYADDR_R) /** * Implementation of do_resolve for platforms with working gethostbyaddr_r */ @@ -75,7 +77,29 @@ char* do_resolve(struct in_addr * addr) { return ret; } -#else +#elif defined(USE_GETHOSTBYADDR) + +/** + * Implementation using gethostbyname. Since this is nonreentrant, we have to + * wrap it in a mutex, losing all benefit of multithreaded resolution. + */ +char *do_resolve(struct in_addr *addr) { + static pthread_mutex_t ghba_mtx = PTHREAD_MUTEX_INITIALIZER; + char *s = NULL; + struct hostent *he; + pthread_mutex_lock(&ghba_mtx); + he = gethostbyaddr((char*)addr, sizeof *addr, AF_INET); + if (he) + s = xstrdup(he->h_name); + pthread_mutex_unlock(&ghba_mtx); + return s; +} + + +#elif defined(USE_LIBRESOLV) + +#include +#include /** * libresolv implementation @@ -106,13 +130,107 @@ char* do_resolve(struct in_addr * addr) { ns_name_uncompress(msg, msg + l, ns_rr_rdata(rr), buf, 256); ret = xstrdup(buf); } - } } } } return ret; } + +#elif defined(USE_ARES) + +/** + * ares implementation + */ + +#include +#include +#include + +/* callback function for ares */ +struct ares_callback_comm { + struct in_addr *addr; + int result; + char *name; +}; + +static void do_resolve_ares_callback(void *arg, int status, unsigned char *abuf, int alen) { + struct hostent *he; + struct ares_callback_comm *C; + C = (struct ares_callback_comm*)arg; + + if (status == ARES_SUCCESS) { + C->result = 1; + ares_parse_ptr_reply(abuf, alen, C->addr, sizeof *C->addr, AF_INET, &he); + C->name = xstrdup(he->h_name);; + ares_free_hostent(he); + } else { + C->result = -1; + } +} + +char *do_resolve(struct in_addr * addr) { + struct ares_callback_comm C; + char s[35]; + unsigned char *a; + ares_channel *chan; + static pthread_mutex_t ares_init_mtx = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t ares_key; + static int gotkey; + + /* Make sure we have an ARES channel for this thread. */ + pthread_mutex_lock(&ares_init_mtx); + if (!gotkey) { + pthread_key_create(&ares_key, NULL); + gotkey = 1; + + } + pthread_mutex_unlock(&ares_init_mtx); + + chan = pthread_getspecific(ares_key); + if (!chan) { + chan = xmalloc(sizeof *chan); + pthread_setspecific(ares_key, chan); + if (ares_init(chan) != ARES_SUCCESS) return NULL; + } + + a = (unsigned char*)addr; + sprintf(s, "%d.%d.%d.%d.in-addr.arpa.", a[3], a[2], a[1], a[0]); + + C.result = 0; + C.addr = addr; + ares_query(*chan, s, C_IN, T_PTR, do_resolve_ares_callback, &C); + while (C.result == 0) { + int n; + fd_set readfds, writefds; + struct timeval tv; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + n = ares_fds(*chan, &readfds, &writefds); + ares_timeout(*chan, NULL, &tv); + select(n, &readfds, &writefds, NULL, &tv); + ares_process(*chan, &readfds, &writefds); + } + + /* At this stage, the query should be complete. */ + switch (C.result) { + case -1: + case 0: /* shouldn't happen */ + return NULL; + + default: + return C.name; + } +} + +#else + +# warning No name resolution method specified; name resolution will not work + +char *do_resolve(struct in_addr *addr) { + return NULL; +} + #endif void resolver_worker(void* ptr) {