White space changes.
[obnox/wireshark/wip.git] / epan / addr_resolv.c
index cf158adae2f83489f9750f93eaa819e3071ddd28..093008db2e0f02c1d23dd6c5c5b4e2b284337564 100644 (file)
 #endif
 
 #ifdef NEED_INET_ATON_H
-# include "inet_aton.h"
+# include "wsutil/inet_aton.h"
 #endif
 
 #ifdef NEED_INET_V6DEFS_H
-# include "inet_v6defs.h"
+# include "wsutil/inet_v6defs.h"
 #endif
 
 #if defined(_WIN32) && defined(INET6)
 #define ENAME_MANUF     "manuf"
 #define ENAME_SERVICES  "services"
 
-#define MAXMANUFLEN 9   /* max vendor name length with ending '\0' */
-#define HASHETHSIZE            2048
-#define HASHHOSTSIZE    2048
-#define HASHIPXNETSIZE  256
-#define HASHMANUFSIZE   256
-#define HASHPORTSIZE    256
-#define SUBNETLENGTHSIZE 32 /*1-32 inc.*/
+#define HASHETHSIZE      2048
+#define HASHHOSTSIZE     2048
+#define HASHIPXNETSIZE    256
+#define HASHMANUFSIZE     256
+#define HASHPORTSIZE      256
+#define SUBNETLENGTHSIZE   32  /*1-32 inc.*/
 
 /* hash table used for IPv4 lookup */
 
 #define HASH_IPV4_ADDRESS(addr) (g_htonl(addr) & (HASHHOSTSIZE - 1))
 
+/*
+ * XXX Some of this is duplicated in addrinfo_list. We may want to replace the
+ * addr and name parts with a struct addrinfo or create our own addrinfo-like
+ * struct that simply points to the data below.
+ */
 typedef struct hashipv4 {
   guint             addr;
   gboolean          is_dummy_entry; /* name is IPv4 address in dot format */
-  gboolean          resolve;       /* already tried to resolve it */
+  gboolean          resolve;        /* already tried to resolve it */
   struct hashipv4   *next;
   gchar             ip[16];
   gchar             name[MAXNAMELEN];
@@ -167,17 +171,17 @@ typedef struct hashipv4 {
 typedef struct hashipv6 {
   struct e_in6_addr addr;
   gboolean          is_dummy_entry; /* name is IPv6 address in colon format */
-  gboolean          resolve;       /* */
+  gboolean          resolve;        /* */
   struct hashipv6   *next;
-  gchar             ip6[47];  /* XX */
+  gchar             ip6[MAX_IP6_STR_LEN]; /* XX */
   gchar             name[MAXNAMELEN];
 } hashipv6_t;
 
 /* Array of entries of subnets of different lengths */
 typedef struct {
-    gsize mask_length; /*1-32*/
-    guint32 mask;        /* e.g. 255.255.255.*/
-    hashipv4_t** subnet_addresses; /* Hash table of subnet addresses */
+  gsize        mask_length;      /*1-32*/
+  guint32      mask;             /* e.g. 255.255.255.*/
+  hashipv4_t** subnet_addresses; /* Hash table of subnet addresses */
 } subnet_length_entry_t;
 
 /* hash table used for TCP/UDP/SCTP port lookup */
@@ -185,9 +189,9 @@ typedef struct {
 #define HASH_PORT(port) ((port) & (HASHPORTSIZE - 1))
 
 typedef struct hashport {
-  guint16       port;
-  struct hashport   *next;
-  gchar         name[MAXNAMELEN];
+  guint16          port;
+  struct hashport *next;
+  gchar            name[MAXNAMELEN];
 } hashport_t;
 
 /* hash table used for IPX network lookup */
@@ -197,9 +201,9 @@ typedef struct hashport {
 #define HASH_IPX_NET(net)   ((net) & (HASHIPXNETSIZE - 1))
 
 typedef struct hashipxnet {
-  guint         addr;
-  struct hashipxnet     *next;
-  gchar         name[MAXNAMELEN];
+  guint               addr;
+  struct hashipxnet  *next;
+  gchar               name[MAXNAMELEN];
 } hashipxnet_t;
 
 /* hash tables used for ethernet and manufacturer lookup */
@@ -211,34 +215,43 @@ typedef struct hashipxnet {
 #define HASH_ETH_MANUF(addr) (((int)(addr)[2]) & (HASHMANUFSIZE - 1))
 
 typedef struct hashmanuf {
-  guint8        addr[3];
-  struct hashmanuf      *next;
-  char          name[MAXMANUFLEN];
+  struct hashmanuf *next;
+  guint8            addr[3];
+  char              *name;
 } hashmanuf_t;
 
+#define HASHETHER_STATUS_UNRESOLVED     1
+#define HASHETHER_STATUS_RESOLVED_DUMMY 2
+#define HASHETHER_STATUS_RESOLVED_NAME  3
+
 typedef struct hashether {
-  guint8                addr[6];
-  gboolean              is_dummy_entry;     /* not a complete entry */
-  gboolean              resolve;            /* */
-  struct hashether      *next;
-  char                  hexa[6*3];
-  char                  name[MAXNAMELEN];
+  struct hashether *next;
+  guint             status;  /* (See above) */
+  guint8            addr[6];
+  char              hexaddr[6*3];
+  char              resolved_name[MAXNAMELEN];
 } hashether_t;
 
+typedef struct hashwka {
+  struct hashwka   *next;
+  guint8            addr[6];
+  char              name[MAXNAMELEN];
+} hashwka_t;
+
 /* internal ethernet type */
 
 typedef struct _ether
 {
-  guint8        addr[6];
-  char          name[MAXNAMELEN];
+  guint8            addr[6];
+  char              name[MAXNAMELEN];
 } ether_t;
 
 /* internal ipxnet type */
 
 typedef struct _ipxnet
 {
-  guint         addr;
-  char          name[MAXNAMELEN];
+  guint             addr;
+  char              name[MAXNAMELEN];
 } ipxnet_t;
 
 static hashipv4_t   *ipv4_table[HASHHOSTSIZE];
@@ -253,23 +266,27 @@ static hashport_t   *sctp_port_table[HASHPORTSIZE];
 static hashport_t   *dccp_port_table[HASHPORTSIZE];
 static hashether_t  *eth_table[HASHETHSIZE];
 static hashmanuf_t  *manuf_table[HASHMANUFSIZE];
-static hashether_t  *(*wka_table[48])[HASHETHSIZE];
+static hashwka_t    *(*wka_table[48])[HASHETHSIZE];
 static hashipxnet_t *ipxnet_table[HASHIPXNETSIZE];
 
 static subnet_length_entry_t subnet_length_entries[SUBNETLENGTHSIZE]; /* Ordered array of entries */
 static gboolean have_subnet_entry = FALSE;
 
-static int      eth_resolution_initialized = 0;
+static gboolean eth_resolution_initialized = FALSE;
 static int      ipxnet_resolution_initialized = 0;
 static int      service_resolution_initialized = 0;
+static gboolean new_resolved_objects = FALSE;
+
+static struct addrinfo *addrinfo_list = NULL; /* IPv4 and IPv6 */
+static struct addrinfo *addrinfo_list_last = NULL;
 
 static hashether_t *add_eth_name(const guint8 *addr, const gchar *name);
-static void add_serv_port_cb(guint32 port);
+static void add_serv_port_cb(const guint32 port);
 
 /*
  * Flag controlling what names to resolve.
  */
-guint32 g_resolv_flags;
+guint32 gbl_resolv_flags;
 
 /*
  *  Global variables (can be changed in GUI sections)
@@ -277,13 +294,13 @@ guint32 g_resolv_flags;
  *  GUI code to change them.
  */
 
-gchar *g_ethers_path  = NULL;       /* global ethers file    */
-gchar *g_pethers_path = NULL;       /* personal ethers file  */
-gchar *g_ipxnets_path  = NULL;      /* global ipxnets file   */
-gchar *g_pipxnets_path = NULL;      /* personal ipxnets file */
+gchar *g_ethers_path    = NULL;     /* global ethers file     */
+gchar *g_pethers_path   = NULL;     /* personal ethers file   */
+gchar *g_ipxnets_path   = NULL;     /* global ipxnets file    */
+gchar *g_pipxnets_path  = NULL;     /* personal ipxnets file  */
 gchar *g_services_path  = NULL;     /* global services file   */
 gchar *g_pservices_path = NULL;     /* personal services file */
-                    /* first resolving call  */
+                                    /* first resolving call   */
 
 /* c-ares */
 #ifdef HAVE_C_ARES
@@ -295,8 +312,6 @@ gchar *g_pservices_path = NULL;     /* personal services file */
  * The callback processes the response, then frees the request.
  */
 #define ASYNC_DNS
-ares_channel alchan;
-
 typedef struct _async_dns_queue_msg
 {
   union {
@@ -306,6 +321,12 @@ typedef struct _async_dns_queue_msg
   int                 family;
 } async_dns_queue_msg_t;
 
+typedef struct _async_hostent {
+  int addr_size;
+  int   copied;
+  void *addrp;
+} async_hostent_t;
+
 #if ( ( ARES_VERSION_MAJOR < 1 )                                     \
  || ( 1 == ARES_VERSION_MAJOR && ARES_VERSION_MINOR < 5 ) )
 static void c_ares_ghba_cb(void *arg, int status, struct hostent *hostent);
@@ -313,6 +334,9 @@ static void c_ares_ghba_cb(void *arg, int status, struct hostent *hostent);
 static void c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *hostent);
 #endif
 
+ares_channel ghba_chan; /* ares_gethostbyaddr -- Usually non-interactive, no timeout */
+ares_channel ghbn_chan; /* ares_gethostbyname -- Usually interactive, timeout */
+
 #else
 /* GNU ADNS */
 #ifdef HAVE_GNU_ADNS
@@ -328,62 +352,63 @@ adns_state ads;
 
 typedef struct _async_dns_queue_msg
 {
-  gboolean          submitted;
-  guint32           ip4_addr;
-  int               type;
-  adns_query        query;
+  gboolean    submitted;
+  guint32     ip4_addr;
+  int         type;
+  adns_query  query;
 } async_dns_queue_msg_t;
 
 #endif /* HAVE_GNU_ADNS */
 #endif /* HAVE_C_ARES */
 #ifdef ASYNC_DNS
-static         gboolean async_dns_initialized = FALSE;
-static  int     async_dns_in_flight = 0;
-static  GList  *async_dns_queue_head = NULL;
+static  gboolean  async_dns_initialized = FALSE;
+static  int       async_dns_in_flight = 0;
+static  GList    *async_dns_queue_head = NULL;
 
 /* push a dns request */
 static void
 add_async_dns_ipv4(int type, guint32 addr)
 {
-    async_dns_queue_msg_t *msg;
+  async_dns_queue_msg_t *msg;
 
-    msg = g_malloc(sizeof(async_dns_queue_msg_t));
+  msg = g_malloc(sizeof(async_dns_queue_msg_t));
 #ifdef HAVE_C_ARES
-    msg->family = type;
-    msg->addr.ip4 = addr;
+  msg->family = type;
+  msg->addr.ip4 = addr;
 #else
-    msg->type = type;
-    msg->ip4_addr = addr;
-    msg->submitted = FALSE;
+  msg->type = type;
+  msg->ip4_addr = addr;
+  msg->submitted = FALSE;
 #endif
-    async_dns_queue_head = g_list_append(async_dns_queue_head, (gpointer) msg);
+  async_dns_queue_head = g_list_append(async_dns_queue_head, (gpointer) msg);
 }
 
 #endif
 
 typedef struct {
-    guint32 mask;
-    gsize mask_length;
-    const gchar* name; /* Shallow copy */
+  guint32      mask;
+  gsize        mask_length;
+  const gchar* name; /* Shallow copy */
 } subnet_entry_t;
 
 /*
  *  Miscellaneous functions
  */
 
-static int fgetline(char **buf, int *size, FILE *fp)
+static int
+fgetline(char **buf, int *size, FILE *fp)
 {
   int len;
   int c;
 
-  if (fp == NULL)
+  if (fp == NULL || buf == NULL)
     return -1;
 
   if (*buf == NULL) {
     if (*size == 0)
       *size = BUFSIZ;
 
-     *buf = g_malloc(*size);
+    *buf = g_malloc(*size);
   }
 
   g_assert(*buf);
@@ -414,10 +439,11 @@ static int fgetline(char **buf, int *size, FILE *fp)
  *  Local function definitions
  */
 static subnet_entry_t subnet_lookup(const guint32 addr);
-static void subnet_entry_set(guint32 subnet_addr, guint32 mask_length, const gchar* name);
+static void subnet_entry_set(guint32 subnet_addr, const guint32 mask_length, const gchar* name);
 
 
-static void add_service_name(hashport_t **proto_table, guint port, const char *service_name)
+static void
+add_service_name(hashport_t **proto_table, const guint port, const char *service_name)
 {
   int hash_idx;
   hashport_t *tp;
@@ -447,10 +473,13 @@ static void add_service_name(hashport_t **proto_table, guint port, const char *s
   tp->next = NULL;
 
   g_strlcpy(tp->name, service_name, MAXNAMELEN);
+
+  new_resolved_objects = TRUE;
 }
 
 
-static void parse_service_line (char *line)
+static void
+parse_service_line (char *line)
 {
   /*
    *  See the services(4) or services(5) man page for services file format
@@ -477,7 +506,7 @@ static void parse_service_line (char *line)
 
   port = cp;
 
-  if ((cp = strtok(cp, "/")) == NULL)
+  if (strtok(cp, "/") == NULL)
     return;
 
   if ((cp = strtok(NULL, "/")) == NULL)
@@ -515,15 +544,16 @@ static void parse_service_line (char *line)
 
 
 static void
-add_serv_port_cb(guint32 port)
+add_serv_port_cb(const guint32 port)
 {
-    if ( port ) {
-      add_service_name(cb_port_table, port, cb_service);
-    }
+  if ( port ) {
+    add_service_name(cb_port_table, port, cb_service);
+  }
 }
 
 
-static void parse_services_file(const char * path)
+static void
+parse_services_file(const char * path)
 {
   FILE *serv_p;
   static int     size = 0;
@@ -542,7 +572,8 @@ static void parse_services_file(const char * path)
   fclose(serv_p);
 }
 
-static void initialize_services(void)
+static void
+initialize_services(void)
 {
 
   /* the hash table won't ignore duplicates, so use the personal path first */
@@ -564,7 +595,8 @@ static void initialize_services(void)
 
 
 
-static gchar *serv_name_lookup(guint port, port_type proto)
+static gchar
+*serv_name_lookup(const guint port, const port_type proto)
 {
   int hash_idx;
   hashport_t *tp;
@@ -609,12 +641,12 @@ static gchar *serv_name_lookup(guint port, port_type proto)
   } else {
     while(1) {
       if( tp->port == port ) {
-    return tp->name;
+        return tp->name;
       }
       if (tp->next == NULL) {
-    tp->next = (hashport_t *)g_malloc(sizeof(hashport_t));
-    tp = tp->next;
-    break;
+        tp->next = (hashport_t *)g_malloc(sizeof(hashport_t));
+        tp = tp->next;
+        break;
       }
       tp = tp->next;
     }
@@ -624,10 +656,10 @@ static gchar *serv_name_lookup(guint port, port_type proto)
   tp->port = port;
   tp->next = NULL;
 
-  if (!(g_resolv_flags & RESOLV_TRANSPORT) ||
+  if (!(gbl_resolv_flags & RESOLV_TRANSPORT) ||
       (servp = getservbyport(g_htons(port), serv_proto)) == NULL) {
     /* unknown port */
-    g_snprintf(tp->name, MAXNAMELEN, "%d", port);
+    guint32_to_str_buf(port, tp->name, MAXNAMELEN);
   } else {
     g_strlcpy(tp->name, servp->s_name, MAXNAMELEN);
   }
@@ -640,7 +672,8 @@ static gchar *serv_name_lookup(guint port, port_type proto)
 /* Fill in an IP4 structure with info from subnets file or just with the
  * string form of the address.
  */
-static void fill_dummy_ip4(guint addr, hashipv4_t* volatile tp)
+static void
+fill_dummy_ip4(const guint addr, hashipv4_t* volatile tp)
 {
   subnet_entry_t subnet_entry;
 
@@ -652,34 +685,34 @@ static void fill_dummy_ip4(guint addr, hashipv4_t* volatile tp)
   /* Do we have a subnet for this address? */
   subnet_entry = subnet_lookup(addr);
   if(0 != subnet_entry.mask) {
-        /* Print name, then '.' then IP address after subnet mask */
-      guint32 host_addr;
-      gchar buffer[MAX_IP_STR_LEN];
-      gchar* paddr;
-      gsize i;
-
-      host_addr = addr & (~(guint32)subnet_entry.mask);
-      ip_to_str_buf((guint8 *)&host_addr, buffer, MAX_IP_STR_LEN);
-      paddr = buffer;
-
-      /* Skip to first octet that is not totally masked
-       * If length of mask is 32, we chomp the whole address.
-       * If the address string starts '.' (should not happen?),
-       * we skip that '.'.
-       */
-      i = subnet_entry.mask_length / 8;
-      while(*(paddr) != '\0' && i > 0) {
-        if(*(++paddr) == '.') {
-            --i;
-        }
+    /* Print name, then '.' then IP address after subnet mask */
+    guint32 host_addr;
+    gchar buffer[MAX_IP_STR_LEN];
+    gchar* paddr;
+    gsize i;
+
+    host_addr = addr & (~(guint32)subnet_entry.mask);
+    ip_to_str_buf((guint8 *)&host_addr, buffer, MAX_IP_STR_LEN);
+    paddr = buffer;
+
+    /* Skip to first octet that is not totally masked
+     * If length of mask is 32, we chomp the whole address.
+     * If the address string starts '.' (should not happen?),
+     * we skip that '.'.
+     */
+    i = subnet_entry.mask_length / 8;
+    while(*(paddr) != '\0' && i > 0) {
+      if(*(++paddr) == '.') {
+        --i;
       }
+    }
 
-      /* There are more efficient ways to do this, but this is safe if we
-       * trust g_snprintf and MAXNAMELEN
-       */
-      g_snprintf(tp->name, MAXNAMELEN, "%s%s", subnet_entry.name, paddr);
+    /* There are more efficient ways to do this, but this is safe if we
+     * trust g_snprintf and MAXNAMELEN
+     */
+    g_snprintf(tp->name, MAXNAMELEN, "%s%s", subnet_entry.name, paddr);
   } else {
-      ip_to_str_buf((guint8 *)&addr, tp->name, MAXNAMELEN);
+    ip_to_str_buf((const guint8 *)&addr, tp->name, MAXNAMELEN);
   }
 }
 
@@ -701,15 +734,15 @@ c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
   if (status == ARES_SUCCESS) {
     for (p = he->h_addr_list; *p != NULL; p++) {
       switch(caqm->family) {
-        case AF_INET:
-          add_ipv4_name(caqm->addr.ip4, he->h_name);
-          break;
-        case AF_INET6:
-          add_ipv6_name(&caqm->addr.ip6, he->h_name);
-          break;
-        default:
-          /* Throw an exception? */
-          break;
+      case AF_INET:
+        add_ipv4_name(caqm->addr.ip4, he->h_name);
+        break;
+      case AF_INET6:
+        add_ipv6_name(&caqm->addr.ip6, he->h_name);
+        break;
+      default:
+        /* Throw an exception? */
+        break;
       }
     }
   }
@@ -718,18 +751,20 @@ c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
 #endif /* HAVE_C_ARES */
 
 /* --------------- */
-static hashipv4_t *new_ipv4(guint addr)
+static hashipv4_t *
+new_ipv4(const guint addr)
 {
-    hashipv4_t *tp = g_malloc(sizeof(hashipv4_t));
-    tp->addr = addr;
-    tp->next = NULL;
-    tp->resolve = FALSE;
-    tp->is_dummy_entry = FALSE;
-    ip_to_str_buf((guint8 *)&addr, tp->ip, sizeof(tp->ip));
-    return tp;
+  hashipv4_t *tp = g_malloc(sizeof(hashipv4_t));
+  tp->addr = addr;
+  tp->next = NULL;
+  tp->resolve = FALSE;
+  tp->is_dummy_entry = FALSE;
+  ip_to_str_buf((const guint8 *)&addr, tp->ip, sizeof(tp->ip));
+  return tp;
 }
 
-static hashipv4_t *host_lookup(guint addr, gboolean resolve, gboolean *found)
+static hashipv4_t *
+host_lookup(const guint addr, const gboolean resolve, gboolean *found)
 {
   int hash_idx;
   hashipv4_t * volatile tp;
@@ -746,57 +781,57 @@ static hashipv4_t *host_lookup(guint addr, gboolean resolve, gboolean *found)
   } else {
     while(1) {
       if( tp->addr == addr ) {
-          if (tp->is_dummy_entry && !tp->resolve)
-              break;
-          if (tp->is_dummy_entry)
-              *found = FALSE;
-          return tp;
+        if (tp->is_dummy_entry && !tp->resolve)
+          break;
+        if (tp->is_dummy_entry)
+          *found = FALSE;
+        return tp;
       }
       if (tp->next == NULL) {
-          tp->next = new_ipv4(addr);
-          tp = tp->next;
-          break;
+        tp->next = new_ipv4(addr);
+        tp = tp->next;
+        break;
       }
       tp = tp->next;
     }
   }
 
   if (resolve) {
-      tp->resolve = TRUE;
+    tp->resolve = TRUE;
 #ifdef ASYNC_DNS
-  if ((g_resolv_flags & RESOLV_CONCURRENT) &&
-      prefs.name_resolve_concurrency > 0 &&
-      async_dns_initialized) {
-                 add_async_dns_ipv4(AF_INET, addr);
-                 /* XXX found is set to TRUE, which seems a bit odd, but I'm not
-                  * going to risk changing the semantics.
-                  */
-                 fill_dummy_ip4(addr, tp);
-                 return tp;
-  }
+    if ((gbl_resolv_flags & RESOLV_CONCURRENT) &&
+        prefs.name_resolve_concurrency > 0 &&
+        async_dns_initialized) {
+        add_async_dns_ipv4(AF_INET, addr);
+      /* XXX found is set to TRUE, which seems a bit odd, but I'm not
+       * going to risk changing the semantics.
+       */
+      fill_dummy_ip4(addr, tp);
+      return tp;
+    }
 #endif /* ASYNC_DNS */
 
-  /*
-   * The Windows "gethostbyaddr()" insists on translating 0.0.0.0 to
-   * the name of the host on which it's running; to work around that
-   * botch, we don't try to translate an all-zero IP address to a host
-   * name.
-   */
-  if (addr != 0 && (g_resolv_flags & RESOLV_NETWORK)) {
-  /* Use async DNS if possible, else fall back to timeouts,
-   * else call gethostbyaddr and hope for the best
-   */
+    /*
+     * The Windows "gethostbyaddr()" insists on translating 0.0.0.0 to
+     * the name of the host on which it's running; to work around that
+     * botch, we don't try to translate an all-zero IP address to a host
+     * name.
+     */
+    if (addr != 0 && (gbl_resolv_flags & RESOLV_NETWORK)) {
+      /* Use async DNS if possible, else fall back to timeouts,
+       * else call gethostbyaddr and hope for the best
+       */
 
       hostp = gethostbyaddr((char *)&addr, 4, AF_INET);
 
       if (hostp != NULL) {
-          g_strlcpy(tp->name, hostp->h_name, MAXNAMELEN);
-          tp->is_dummy_entry = FALSE;
-          return tp;
+        g_strlcpy(tp->name, hostp->h_name, MAXNAMELEN);
+        tp->is_dummy_entry = FALSE;
+        return tp;
       }
-  }
+    }
 
-  /* unknown host or DNS timeout */
+    /* unknown host or DNS timeout */
 
   }
 
@@ -807,7 +842,8 @@ static hashipv4_t *host_lookup(guint addr, gboolean resolve, gboolean *found)
 
 } /* host_name_lookup */
 
-static gchar *host_name_lookup(guint addr, gboolean *found)
+static gchar *
+host_name_lookup(const guint addr, gboolean *found)
 {
   hashipv4_t *tp;
   tp = host_lookup(addr, TRUE, found);
@@ -816,28 +852,30 @@ static gchar *host_name_lookup(guint addr, gboolean *found)
 
 
 /* --------------- */
-static hashipv6_t *new_ipv6(const struct e_in6_addr *addr)
+static hashipv6_t *
+new_ipv6(const struct e_in6_addr *addr)
 {
-    hashipv6_t *tp = g_malloc(sizeof(hashipv6_t));
-    tp->addr = *addr;
-    tp->next = NULL;
-    tp->resolve = FALSE;
-    tp->is_dummy_entry = FALSE;
-    ip6_to_str_buf(addr, tp->ip6);
-    return tp;
+  hashipv6_t *tp = g_malloc(sizeof(hashipv6_t));
+  tp->addr = *addr;
+  tp->next = NULL;
+  tp->resolve = FALSE;
+  tp->is_dummy_entry = FALSE;
+  ip6_to_str_buf(addr, tp->ip6);
+  return tp;
 }
 
 /* ------------------------------------ */
-static hashipv6_t *host_lookup6(const struct e_in6_addr *addr, gboolean resolve, gboolean *found)
+static hashipv6_t *
+host_lookup6(const struct e_in6_addr *addr, const gboolean resolve, gboolean *found)
 {
   int hash_idx;
   hashipv6_t * volatile tp;
+#ifdef INET6
 #ifdef HAVE_C_ARES
   async_dns_queue_msg_t *caqm;
 #endif /* HAVE_C_ARES */
-#ifdef INET6
   struct hostent *hostp;
-#endif
+#endif /* INET6 */
 
   *found = TRUE;
 
@@ -850,27 +888,27 @@ static hashipv6_t *host_lookup6(const struct e_in6_addr *addr, gboolean resolve,
   } else {
     while(1) {
       if( memcmp(&tp->addr, addr, sizeof (struct e_in6_addr)) == 0 ) {
-          if (tp->is_dummy_entry && !tp->resolve)
-              break;
-          if (tp->is_dummy_entry)
-              *found = FALSE;
-          return tp;
+        if (tp->is_dummy_entry && !tp->resolve)
+          break;
+        if (tp->is_dummy_entry)
+          *found = FALSE;
+        return tp;
       }
       if (tp->next == NULL) {
-          tp->next = new_ipv6(addr);
-          tp = tp->next;
-          break;
+        tp->next = new_ipv6(addr);
+        tp = tp->next;
+        break;
       }
       tp = tp->next;
     }
   }
 
   if (resolve) {
-      tp->resolve = TRUE;
+    tp->resolve = TRUE;
 #ifdef INET6
 
 #ifdef HAVE_C_ARES
-  if ((g_resolv_flags & RESOLV_CONCURRENT) &&
+  if ((gbl_resolv_flags & RESOLV_CONCURRENT) &&
       prefs.name_resolve_concurrency > 0 &&
       async_dns_initialized) {
     caqm = g_malloc(sizeof(async_dns_queue_msg_t));
@@ -882,29 +920,29 @@ static hashipv6_t *host_lookup6(const struct e_in6_addr *addr, gboolean resolve,
      * going to risk changing the semantics.
      */
     if (!tp->is_dummy_entry) {
-               strcpy(tp->name, tp->ip6);
-        ip6_to_str_buf(addr, tp->name);
-        tp->is_dummy_entry = TRUE;
+      g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
+      ip6_to_str_buf(addr, tp->name);
+      tp->is_dummy_entry = TRUE;
     }
     return tp;
   }
 #endif /* HAVE_C_ARES */
 
-    /* Quick hack to avoid DNS/YP timeout */
-      hostp = gethostbyaddr((char *)addr, sizeof(*addr), AF_INET6);
+  /* Quick hack to avoid DNS/YP timeout */
+  hostp = gethostbyaddr((char *)addr, sizeof(*addr), AF_INET6);
 
-      if (hostp != NULL) {
-          g_strlcpy(tp->name, hostp->h_name, MAXNAMELEN);
-          tp->is_dummy_entry = FALSE;
-          return tp;
-      }
+  if (hostp != NULL) {
+    g_strlcpy(tp->name, hostp->h_name, MAXNAMELEN);
+    tp->is_dummy_entry = FALSE;
+    return tp;
+  }
 #endif /* INET6 */
   }
 
   /* unknown host or DNS timeout */
   if (!tp->is_dummy_entry) {
     tp->is_dummy_entry = TRUE;
-    strcpy(tp->name, tp->ip6);
+    g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
   }
   *found = FALSE;
   return tp;
@@ -912,7 +950,8 @@ static hashipv6_t *host_lookup6(const struct e_in6_addr *addr, gboolean resolve,
 } /* host_lookup6 */
 
 #if 0
-static gchar *host_name_lookup6(struct e_in6_addr *addr, gboolean *found)
+static gchar *
+host_name_lookup6(struct e_in6_addr *addr, gboolean *found)
 {
   hashipv6_t *tp;
   tp = host_lookup6(addr, TRUE, found);
@@ -920,7 +959,8 @@ static gchar *host_name_lookup6(struct e_in6_addr *addr, gboolean *found)
 }
 #endif
 
-static const gchar *solve_address_to_name(const address *addr)
+static const gchar *
+solve_address_to_name(const address *addr)
 {
   switch (addr->type) {
 
@@ -928,15 +968,15 @@ static const gchar *solve_address_to_name(const address *addr)
     return get_ether_name(addr->data);
 
   case AT_IPv4: {
-    guint32 ipv4_addr;
-    memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
-    return get_hostname(ipv4_addr);
+    guint32 ip4_addr;
+    memcpy(&ip4_addr, addr->data, sizeof ip4_addr);
+    return get_hostname(ip4_addr);
   }
 
   case AT_IPv6: {
-    struct e_in6_addr ipv6_addr;
-    memcpy(&ipv6_addr.bytes, addr->data, sizeof ipv6_addr.bytes);
-    return get_hostname6(&ipv6_addr);
+    struct e_in6_addr ip6_addr;
+    memcpy(&ip6_addr.bytes, addr->data, sizeof ip6_addr.bytes);
+    return get_hostname6(&ip6_addr);
   }
 
   case AT_STRINGZ:
@@ -947,7 +987,8 @@ static const gchar *solve_address_to_name(const address *addr)
   }
 }
 
-static const gchar *se_solve_address_to_name(const address *addr)
+static const gchar *
+se_solve_address_to_name(const address *addr)
 {
   switch (addr->type) {
 
@@ -955,15 +996,15 @@ static const gchar *se_solve_address_to_name(const address *addr)
     return get_ether_name(addr->data);
 
   case AT_IPv4: {
-    guint32 ipv4_addr;
-    memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
-    return get_hostname(ipv4_addr);
+    guint32 ip4_addr;
+    memcpy(&ip4_addr, addr->data, sizeof ip4_addr);
+    return get_hostname(ip4_addr);
   }
 
   case AT_IPv6: {
-    struct e_in6_addr ipv6_addr;
-    memcpy(&ipv6_addr.bytes, addr->data, sizeof ipv6_addr.bytes);
-    return get_hostname6(&ipv6_addr);
+    struct e_in6_addr ip6_addr;
+    memcpy(&ip6_addr.bytes, addr->data, sizeof ip6_addr.bytes);
+    return get_hostname6(&ip6_addr);
   }
 
   case AT_STRINGZ:
@@ -981,7 +1022,7 @@ static const gchar *se_solve_address_to_name(const address *addr)
  * ethers files parsing (see ethers(4)).
  *
  * The manuf file has the same format as ethers(4) except that names are
- * truncated to MAXMANUFLEN-1 characters and that an address contains
+ * truncated to MAXMANUFLEN-1 (8) characters and that an address contains
  * only 3 bytes (instead of 6).
  *
  * Notes:
@@ -1006,7 +1047,7 @@ static const gchar *se_solve_address_to_name(const address *addr)
  */
 static gboolean
 parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
-                    gboolean manuf_file)
+                    const gboolean manuf_file)
 {
   int i;
   unsigned long num;
@@ -1030,53 +1071,53 @@ parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
       /* "/" - this has a mask. */
       if (!manuf_file) {
         /* Entries with masks are allowed only in the "manuf" files. */
-    return FALSE;
+        return FALSE;
       }
       cp++; /* skip past the '/' to get to the mask */
       if (!isdigit((unsigned char)*cp))
-    return FALSE;   /* no sign allowed */
+        return FALSE;   /* no sign allowed */
       num = strtoul(cp, &p, 10);
       if (p == cp)
-    return FALSE;   /* failed */
+        return FALSE;   /* failed */
       cp = p;   /* skip past the number */
       if (*cp != '\0' && !isspace((unsigned char)*cp))
-    return FALSE;   /* bogus terminator */
+        return FALSE;   /* bogus terminator */
       if (num == 0 || num >= 48)
-    return FALSE;   /* bogus mask */
+        return FALSE;   /* bogus mask */
       /* Mask out the bits not covered by the mask */
       *mask = num;
       for (i = 0; num >= 8; i++, num -= 8)
-    ;   /* skip octets entirely covered by the mask */
+        ;   /* skip octets entirely covered by the mask */
       /* Mask out the first masked octet */
       eth->addr[i] &= (0xFF << (8 - num));
       i++;
       /* Mask out completely-masked-out octets */
       for (; i < 6; i++)
-    eth->addr[i] = 0;
+        eth->addr[i] = 0;
       return TRUE;
     }
     if (*cp == '\0') {
       /* We're at the end of the address, and there's no mask. */
       if (i == 2) {
-    /* We got 3 bytes, so this is a manufacturer ID. */
-    if (!manuf_file) {
-      /* Manufacturer IDs are only allowed in the "manuf"
-         files. */
-      return FALSE;
-    }
-    /* Indicate that this is a manufacturer ID (0 is not allowed
-       as a mask). */
-    *mask = 0;
-    return TRUE;
+        /* We got 3 bytes, so this is a manufacturer ID. */
+        if (!manuf_file) {
+          /* Manufacturer IDs are only allowed in the "manuf"
+             files. */
+          return FALSE;
+        }
+        /* Indicate that this is a manufacturer ID (0 is not allowed
+           as a mask). */
+        *mask = 0;
+        return TRUE;
       }
 
       if (i == 5) {
-    /* We got 6 bytes, so this is a MAC address.
-       If we're reading one of the "manuf" files, indicate that
-       this is a MAC address (48 is not allowed as a mask). */
-    if (manuf_file)
-      *mask = 48;
-    return TRUE;
+        /* We got 6 bytes, so this is a MAC address.
+           If we're reading one of the "manuf" files, indicate that
+           this is a MAC address (48 is not allowed as a mask). */
+        if (manuf_file)
+          *mask = 48;
+        return TRUE;
       }
 
       /* We didn't get 3 or 6 bytes, and there's no mask; this is
@@ -1084,15 +1125,15 @@ parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
       return FALSE;
     } else {
       if (sep == '\0') {
-    /* We don't know the separator used in this number; it can either
-       be ':', '-', or '.'. */
-    if (*cp != ':' && *cp != '-' && *cp != '.')
-      return FALSE;
-    sep = *cp;  /* subsequent separators must be the same */
+        /* We don't know the separator used in this number; it can either
+           be ':', '-', or '.'. */
+        if (*cp != ':' && *cp != '-' && *cp != '.')
+          return FALSE;
+        sep = *cp;  /* subsequent separators must be the same */
       } else {
-          /* It has to be the same as the first separator */
-          if (*cp != sep)
-            return FALSE;
+        /* It has to be the same as the first separator */
+        if (*cp != sep)
+          return FALSE;
       }
     }
     cp++;
@@ -1101,8 +1142,9 @@ parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
   return TRUE;
 }
 
-static int parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
-                gboolean manuf_file)
+static int
+parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
+                 const gboolean manuf_file)
 {
   /*
    *  See the ethers(4) or ethers(5) man page for ethers file format
@@ -1133,7 +1175,8 @@ static int parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
 
 static FILE *eth_p = NULL;
 
-static void set_ethent(char *path)
+static void
+set_ethent(char *path)
 {
   if (eth_p)
     rewind(eth_p);
@@ -1141,7 +1184,8 @@ static void set_ethent(char *path)
     eth_p = ws_fopen(path, "r");
 }
 
-static void end_ethent(void)
+static void
+end_ethent(void)
 {
   if (eth_p) {
     fclose(eth_p);
@@ -1149,7 +1193,8 @@ static void end_ethent(void)
   }
 }
 
-static ether_t *get_ethent(unsigned int *mask, gboolean manuf_file)
+static ether_t *
+get_ethent(unsigned int *mask, const gboolean manuf_file)
 {
 
   static ether_t eth;
@@ -1169,13 +1214,14 @@ static ether_t *get_ethent(unsigned int *mask, gboolean manuf_file)
 
 } /* get_ethent */
 
-static ether_t *get_ethbyname(const gchar *name)
+static ether_t *
+get_ethbyname(const gchar *name)
 {
   ether_t *eth;
 
   set_ethent(g_pethers_path);
 
-  while ((eth = get_ethent(NULL, FALSE)) && strncmp(name, eth->name, MAXNAMELEN) != 0)
+  while (((eth = get_ethent(NULL, FALSE)) != NULL) && strncmp(name, eth->name, MAXNAMELEN) != 0)
     ;
 
   if (eth == NULL) {
@@ -1183,7 +1229,7 @@ static ether_t *get_ethbyname(const gchar *name)
 
     set_ethent(g_ethers_path);
 
-    while ((eth = get_ethent(NULL, FALSE)) && strncmp(name, eth->name, MAXNAMELEN) != 0)
+    while (((eth = get_ethent(NULL, FALSE)) != NULL) && strncmp(name, eth->name, MAXNAMELEN) != 0)
       ;
 
     end_ethent();
@@ -1193,14 +1239,15 @@ static ether_t *get_ethbyname(const gchar *name)
 
 } /* get_ethbyname */
 
-static ether_t *get_ethbyaddr(const guint8 *addr)
+static ether_t *
+get_ethbyaddr(const guint8 *addr)
 {
 
   ether_t *eth;
 
   set_ethent(g_pethers_path);
 
-  while ((eth = get_ethent(NULL, FALSE)) && memcmp(addr, eth->addr, 6) != 0)
+  while (((eth = get_ethent(NULL, FALSE)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
     ;
 
   if (eth == NULL) {
@@ -1208,7 +1255,7 @@ static ether_t *get_ethbyaddr(const guint8 *addr)
 
     set_ethent(g_ethers_path);
 
-    while ((eth = get_ethent(NULL, FALSE)) && memcmp(addr, eth->addr, 6) != 0)
+    while (((eth = get_ethent(NULL, FALSE)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
       ;
 
     end_ethent();
@@ -1218,7 +1265,8 @@ static ether_t *get_ethbyaddr(const guint8 *addr)
 
 } /* get_ethbyaddr */
 
-static int hash_eth_wka(const guint8 *addr, unsigned int mask)
+static int
+hash_eth_wka(const guint8 *addr, unsigned int mask)
 {
   if (mask <= 8) {
     /* All but the topmost byte is masked out */
@@ -1241,29 +1289,64 @@ static int hash_eth_wka(const guint8 *addr, unsigned int mask)
     /* All but the topmost 4 bytes are masked out */
     return ((((addr[0] << 8) | addr[1]) ^
              ((addr[2] << 8) | (addr[3] & (0xFF << (8 - mask)))))) &
-     (HASHETHSIZE - 1);
+            (HASHETHSIZE - 1);
   }
   mask -= 8;
   if (mask <= 8) {
     /* All but the topmost 5 bytes are masked out */
     return ((((addr[1] << 8) | addr[2]) ^
              ((addr[3] << 8) | (addr[4] & (0xFF << (8 - mask)))))) &
-     (HASHETHSIZE - 1);
+            (HASHETHSIZE - 1);
   }
   mask -= 8;
   /* No bytes are fully masked out */
   return ((((addr[1] << 8) | addr[2]) ^
            ((addr[3] << 8) | (addr[4] & (0xFF << (8 - mask)))))) &
-            (HASHETHSIZE - 1);
+          (HASHETHSIZE - 1);
 }
 
-static void add_manuf_name(guint8 *addr, unsigned int mask, gchar *name)
+static hashmanuf_t *
+manuf_hash_new_entry(const guint8 *addr, gchar *name)
 {
-  int hash_idx;
-  hashmanuf_t *tp;
-  hashether_t *(*wka_tp)[HASHETHSIZE], *etp;
+  hashmanuf_t *mtp;
+
+  mtp = (hashmanuf_t *)g_malloc(sizeof(hashmanuf_t));
+  memcpy(mtp->addr, addr, sizeof(mtp->addr));
+  /*  The length of this name is limited (in the number of UTF-8 characters,
+   *  not bytes) in make-manuf.  That doesn't mean a user can't put a longer
+   *  name in their personal manuf file, though...
+   */
+  mtp->name = g_strdup(name);
+  mtp->next = NULL;
+  return mtp;
+} /* manuf_hash_new_entry */
 
-  if (mask == 48) {
+static hashwka_t *
+wka_hash_new_entry(const guint8 *addr, gchar *name)
+{
+  hashwka_t *wtp;
+
+  wtp =  (hashwka_t *)g_malloc(sizeof(hashwka_t));
+  memcpy(wtp->addr, addr, sizeof(wtp->addr));
+  g_strlcpy(wtp->name, name, MAXNAMELEN);
+  wtp->next = NULL;
+  return wtp;
+} /* wka_hash_new_entry */
+
+static void
+add_manuf_name(const guint8 *addr, unsigned int mask, gchar *name)
+{
+  gint         hash_idx;
+  hashmanuf_t *mtp;
+  hashwka_t   *(*wka_tp)[HASHETHSIZE], *wtp;
+
+  /*
+   * XXX - can we use Standard Annotation Language annotations to
+   * note that mask, as returned by parse_ether_address() (and thus
+   * by the routines that call it, and thus passed to us) cannot be > 48,
+   * or is SAL too weak to express that?
+   */
+  if (mask >= 48) {
     /* This is a well-known MAC address; just add this to the Ethernet
        hash table */
     add_eth_name(addr, name);
@@ -1274,27 +1357,21 @@ static void add_manuf_name(guint8 *addr, unsigned int mask, gchar *name)
     /* This is a manufacturer ID; add it to the manufacturer ID hash table */
 
     hash_idx = HASH_ETH_MANUF(addr);
+    mtp = manuf_table[hash_idx];
 
-    tp = manuf_table[hash_idx];
-
-    if( tp == NULL ) {
-      tp = manuf_table[hash_idx] = (hashmanuf_t *)g_malloc(sizeof(hashmanuf_t));
+    if( mtp == NULL ) {
+      manuf_table[hash_idx] = manuf_hash_new_entry(addr, name);
+      return;
     } else {
-      while(1) {
-    if (tp->next == NULL) {
-      tp->next = (hashmanuf_t *)g_malloc(sizeof(hashmanuf_t));
-      tp = tp->next;
-      break;
-    }
-    tp = tp->next;
+      while(TRUE) {
+        if (mtp->next == NULL) {
+          mtp->next = manuf_hash_new_entry(addr, name);
+          return;
+        }
+        mtp = mtp->next;
       }
     }
-
-    memcpy(tp->addr, addr, sizeof(tp->addr));
-    g_strlcpy(tp->name, name, MAXMANUFLEN);
-    tp->next = NULL;
-    return;
-  }
+  } /* mask == 0 */
 
   /* This is a range of well-known addresses; add it to the appropriate
      well-known-address table, creating that table if necessary. */
@@ -1304,47 +1381,42 @@ static void add_manuf_name(guint8 *addr, unsigned int mask, gchar *name)
 
   hash_idx = hash_eth_wka(addr, mask);
 
-  etp = (*wka_tp)[hash_idx];
+  wtp = (*wka_tp)[hash_idx];
 
-  if( etp == NULL ) {
-    etp = (*wka_tp)[hash_idx] = (hashether_t *)g_malloc(sizeof(hashether_t));
-  } else {
-    while(1) {
-      if (memcmp(etp->addr, addr, sizeof(etp->addr)) == 0) {
-    /* address already known */
+  if( wtp == NULL ) {
+    (*wka_tp)[hash_idx] = wka_hash_new_entry(addr, name);
     return;
+  } else {
+    while(TRUE) {
+      if (memcmp(wtp->addr, addr, sizeof(wtp->addr)) == 0) {
+        /* address already known */
+        return;
       }
-      if (etp->next == NULL) {
-    etp->next = (hashether_t *)g_malloc(sizeof(hashether_t));
-    etp = etp->next;
-    break;
+      if (wtp->next == NULL) {
+       wtp->next = wka_hash_new_entry(addr, name);
+        return;
       }
-      etp = etp->next;
+      wtp = wtp->next;
     }
   }
-
-  memcpy(etp->addr, addr, sizeof(etp->addr));
-  g_strlcpy(etp->name, name, MAXNAMELEN);
-  etp->next = NULL;
-  etp->is_dummy_entry = FALSE;
-
 } /* add_manuf_name */
 
-static hashmanuf_t *manuf_name_lookup(const guint8 *addr)
+static hashmanuf_t *
+manuf_name_lookup(const guint8 *addr)
 {
-  int hash_idx;
-  hashmanuf_t *tp;
-  guint8 stripped_addr[3];
+  gint         hash_idx;
+  hashmanuf_t *mtp;
+  guint8       stripped_addr[3];
 
   hash_idx = HASH_ETH_MANUF(addr);
 
   /* first try to find a "perfect match" */
-  tp = manuf_table[hash_idx];
-  while(tp != NULL) {
-    if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
-      return tp;
+  mtp = manuf_table[hash_idx];
+  while(mtp != NULL) {
+    if (memcmp(mtp->addr, addr, sizeof(mtp->addr)) == 0) {
+      return mtp;
     }
-    tp = tp->next;
+    mtp = mtp->next;
   }
 
   /* Mask out the broadcast/multicast flag but not the locally
@@ -1355,26 +1427,27 @@ static hashmanuf_t *manuf_name_lookup(const guint8 *addr)
   memcpy(stripped_addr, addr, 3);
   stripped_addr[0] &= 0xFE;
 
-  tp = manuf_table[hash_idx];
-  while(tp != NULL) {
-    if (memcmp(tp->addr, stripped_addr, sizeof(tp->addr)) == 0) {
-      return tp;
+  mtp = manuf_table[hash_idx];
+  while(mtp != NULL) {
+    if (memcmp(mtp->addr, stripped_addr, sizeof(mtp->addr)) == 0) {
+      return mtp;
     }
-    tp = tp->next;
+    mtp = mtp->next;
   }
 
   return NULL;
 
 } /* manuf_name_lookup */
 
-static hashether_t *wka_name_lookup(const guint8 *addr, unsigned int mask)
+static hashwka_t *
+wka_name_lookup(const guint8 *addr, const unsigned int mask)
 {
-  int hash_idx;
-  hashether_t *(*wka_tp)[HASHETHSIZE];
-  hashether_t *tp;
-  guint8 masked_addr[6];
-  unsigned int num;
-  int i;
+  gint       hash_idx;
+  hashwka_t *(*wka_tp)[HASHETHSIZE];
+  hashwka_t *wtp;
+  guint8     masked_addr[6];
+  guint      num;
+  gint       i;
 
   wka_tp = wka_table[mask];
   if (wka_tp == NULL) {
@@ -1395,29 +1468,30 @@ static hashether_t *wka_name_lookup(const guint8 *addr, unsigned int mask)
 
   hash_idx = hash_eth_wka(masked_addr, mask);
 
-  tp = (*wka_tp)[hash_idx];
+  wtp = (*wka_tp)[hash_idx];
 
-  while(tp != NULL) {
-    if (memcmp(tp->addr, masked_addr, sizeof(tp->addr)) == 0) {
-      return tp;
+  while(wtp != NULL) {
+    if (memcmp(wtp->addr, masked_addr, sizeof(wtp->addr)) == 0) {
+      return wtp;
     }
-    tp = tp->next;
+    wtp = wtp->next;
   }
 
   return NULL;
 
 } /* wka_name_lookup */
 
-static void initialize_ethers(void)
+static void
+initialize_ethers(void)
 {
   ether_t *eth;
-  char *manuf_path;
-  unsigned int mask;
+  char    *manuf_path;
+  guint    mask;
 
   /* Compute the pathname of the ethers file. */
   if (g_ethers_path == NULL) {
     g_ethers_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
-        get_systemfile_dir(), ENAME_ETHERS);
+                                    get_systemfile_dir(), ENAME_ETHERS);
   }
 
   /* Set g_pethers_path here, but don't actually do anything
@@ -1444,102 +1518,31 @@ static void initialize_ethers(void)
 
 } /* initialize_ethers */
 
-static hashether_t *add_eth_name(const guint8 *addr, const gchar *name)
-{
-  int hash_idx;
-  hashether_t *tp;
-  int new_one = TRUE;
-
-  hash_idx = HASH_ETH_ADDRESS(addr);
-
-  tp = eth_table[hash_idx];
-
-  if( tp == NULL ) {
-    tp = eth_table[hash_idx] = (hashether_t *)g_malloc(sizeof(hashether_t));
-  } else {
-    while(1) {
-      if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
-    /* address already known */
-    if (!tp->is_dummy_entry) {
-      return tp;
-    } else {
-      /* replace this dummy (manuf) entry with a real name */
-      new_one = FALSE;
-      break;
-    }
-      }
-      if (tp->next == NULL) {
-    tp->next = (hashether_t *)g_malloc(sizeof(hashether_t));
-    tp = tp->next;
-    break;
-      }
-      tp = tp->next;
-    }
-  }
-
-  g_strlcpy(tp->name, name, MAXNAMELEN);
-  if (new_one) {
-      memcpy(tp->addr, addr, sizeof(tp->addr));
-      g_strlcpy(tp->hexa, bytestring_to_str(addr, sizeof(tp->addr), ':'), sizeof(tp->hexa));
-      tp->next = NULL;
-  }
-  tp->is_dummy_entry = FALSE;
-
-  return tp;
-
-} /* add_eth_name */
-
-/* XXXX */
-static hashether_t *eth_name_lookup(const guint8 *addr, gboolean resolve)
-{
-  int hash_idx;
-  hashmanuf_t *manufp;
-  hashether_t *tp;
-  ether_t *eth;
-  hashether_t *etp;
-  unsigned int mask;
-
-  hash_idx = HASH_ETH_ADDRESS(addr);
-
-  tp = eth_table[hash_idx];
+/* Resolve ethernet address */
+static hashether_t *
+eth_addr_resolve(hashether_t *tp) {
+  ether_t      *eth;
+  const guint8 *addr = tp->addr;
 
-  if( tp == NULL ) {
-    tp = eth_table[hash_idx] = (hashether_t *)g_malloc(sizeof(hashether_t));
-  } else {
-    while(1) {
-      if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
+  if ( (eth = get_ethbyaddr(addr)) != NULL) {
+    g_strlcpy(tp->resolved_name, eth->name, MAXNAMELEN);
+    tp->status = HASHETHER_STATUS_RESOLVED_NAME;
     return tp;
-      }
-      if (tp->next == NULL) {
-    tp->next = (hashether_t *)g_malloc(sizeof(hashether_t));
-    tp = tp->next;
-    break;
-      }
-      tp = tp->next;
-    }
-  }
-
-  /* fill in a new entry */
-
-  memcpy(tp->addr, addr, sizeof(tp->addr));
-  tp->next = NULL;
-  g_strlcpy(tp->hexa, bytestring_to_str(addr, sizeof(tp->addr), ':'), sizeof(tp->hexa));
-  if (!resolve) {
-      strcpy(tp->name, tp->hexa);
-      return tp;
-  }
+  } else {
+    hashwka_t    *wtp;
+    hashmanuf_t  *mtp;
+    guint         mask;
 
-  if ( (eth = get_ethbyaddr(addr)) == NULL) {
     /* Unknown name.  Try looking for it in the well-known-address
        tables for well-known address ranges smaller than 2^24. */
     mask = 7;
     for (;;) {
       /* Only the topmost 5 bytes participate fully */
-      if ((etp = wka_name_lookup(addr, mask+40)) != NULL) {
-    g_snprintf(tp->name, MAXNAMELEN, "%s_%02x",
-          etp->name, addr[5] & (0xFF >> mask));
-    tp->is_dummy_entry = TRUE;
-    return tp;
+      if ((wtp = wka_name_lookup(addr, mask+40)) != NULL) {
+        g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x",
+                   wtp->name, addr[5] & (0xFF >> mask));
+        tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
+        return tp;
       }
       if (mask == 0)
         break;
@@ -1549,11 +1552,11 @@ static hashether_t *eth_name_lookup(const guint8 *addr, gboolean resolve)
     mask = 7;
     for (;;) {
       /* Only the topmost 4 bytes participate fully */
-      if ((etp = wka_name_lookup(addr, mask+32)) != NULL) {
-    g_snprintf(tp->name, MAXNAMELEN, "%s_%02x:%02x",
-          etp->name, addr[4] & (0xFF >> mask), addr[5]);
-    tp->is_dummy_entry = TRUE;
-    return tp;
+      if ((wtp = wka_name_lookup(addr, mask+32)) != NULL) {
+        g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x",
+                   wtp->name, addr[4] & (0xFF >> mask), addr[5]);
+        tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
+        return tp;
       }
       if (mask == 0)
         break;
@@ -1563,11 +1566,11 @@ static hashether_t *eth_name_lookup(const guint8 *addr, gboolean resolve)
     mask = 7;
     for (;;) {
       /* Only the topmost 3 bytes participate fully */
-      if ((etp = wka_name_lookup(addr, mask+24)) != NULL) {
-    g_snprintf(tp->name, MAXNAMELEN, "%s_%02x:%02x:%02x",
-          etp->name, addr[3] & (0xFF >> mask), addr[4], addr[5]);
-    tp->is_dummy_entry = TRUE;
-    return tp;
+      if ((wtp = wka_name_lookup(addr, mask+24)) != NULL) {
+        g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
+                   wtp->name, addr[3] & (0xFF >> mask), addr[4], addr[5]);
+        tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
+        return tp;
       }
       if (mask == 0)
         break;
@@ -1575,10 +1578,10 @@ static hashether_t *eth_name_lookup(const guint8 *addr, gboolean resolve)
     }
 
     /* Now try looking in the manufacturer table. */
-    if ((manufp = manuf_name_lookup(addr)) != NULL) {
-      g_snprintf(tp->name, MAXNAMELEN, "%s_%02x:%02x:%02x",
-          manufp->name, addr[3], addr[4], addr[5]);
-      tp->is_dummy_entry = TRUE;
+    if ((mtp = manuf_name_lookup(addr)) != NULL) {
+      g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
+                 mtp->name, addr[3], addr[4], addr[5]);
+      tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
       return tp;
     }
 
@@ -1587,12 +1590,12 @@ static hashether_t *eth_name_lookup(const guint8 *addr, gboolean resolve)
     mask = 7;
     for (;;) {
       /* Only the topmost 2 bytes participate fully */
-      if ((etp = wka_name_lookup(addr, mask+16)) != NULL) {
-    g_snprintf(tp->name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x",
-          etp->name, addr[2] & (0xFF >> mask), addr[3], addr[4],
-          addr[5]);
-    tp->is_dummy_entry = TRUE;
-    return tp;
+      if ((wtp = wka_name_lookup(addr, mask+16)) != NULL) {
+        g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x",
+                   wtp->name, addr[2] & (0xFF >> mask), addr[3], addr[4],
+                   addr[5]);
+        tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
+        return tp;
       }
       if (mask == 0)
         break;
@@ -1602,12 +1605,12 @@ static hashether_t *eth_name_lookup(const guint8 *addr, gboolean resolve)
     mask = 7;
     for (;;) {
       /* Only the topmost byte participates fully */
-      if ((etp = wka_name_lookup(addr, mask+8)) != NULL) {
-    g_snprintf(tp->name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
-          etp->name, addr[1] & (0xFF >> mask), addr[2], addr[3],
-          addr[4], addr[5]);
-    tp->is_dummy_entry = TRUE;
-    return tp;
+      if ((wtp = wka_name_lookup(addr, mask+8)) != NULL) {
+        g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
+                   wtp->name, addr[1] & (0xFF >> mask), addr[2], addr[3],
+                   addr[4], addr[5]);
+        tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
+        return tp;
       }
       if (mask == 0)
         break;
@@ -1616,41 +1619,115 @@ static hashether_t *eth_name_lookup(const guint8 *addr, gboolean resolve)
 
     for (mask = 7; mask > 0; mask--) {
       /* Not even the topmost byte participates fully */
-      if ((etp = wka_name_lookup(addr, mask)) != NULL) {
-    g_snprintf(tp->name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
-          etp->name, addr[0] & (0xFF >> mask), addr[1], addr[2],
-          addr[3], addr[4], addr[5]);
-    tp->is_dummy_entry = TRUE;
-    return tp;
+      if ((wtp = wka_name_lookup(addr, mask)) != NULL) {
+        g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
+                   wtp->name, addr[0] & (0xFF >> mask), addr[1], addr[2],
+                   addr[3], addr[4], addr[5]);
+        tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
+        return tp;
       }
     }
 
     /* No match whatsoever. */
-    g_snprintf(tp->name, MAXNAMELEN, "%s", ether_to_str(addr));
-    tp->is_dummy_entry = TRUE;
+    g_snprintf(tp->resolved_name, MAXNAMELEN, "%s", ether_to_str(addr));
+    tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
+    return tp;
+  }
+  g_assert_not_reached();
+} /* eth_addr_resolve */
+
+static hashether_t *
+eth_hash_new_entry(const guint8 *addr, const gboolean resolve) {
+  hashether_t *tp;
+
+  tp = (hashether_t *)g_malloc(sizeof(hashether_t));
+  memcpy(tp->addr, addr, sizeof(tp->addr));
+  tp->status = HASHETHER_STATUS_UNRESOLVED;
+  g_strlcpy(tp->hexaddr, bytestring_to_str(addr, sizeof(tp->addr), ':'), sizeof(tp->hexaddr));
+  tp->resolved_name[0] = '\0';
+  tp->next = NULL;
+
+  if (resolve)
+    eth_addr_resolve(tp);
+
+  return tp;
+} /* eth_hash_new_entry */
+
+static hashether_t *
+add_eth_name(const guint8 *addr, const gchar *name)
+{
+  gint         hash_idx;
+  hashether_t *tp;
+
+  hash_idx = HASH_ETH_ADDRESS(addr);
 
+  tp = eth_table[hash_idx];
+  if( tp == NULL ) {
+    tp = eth_table[hash_idx] = eth_hash_new_entry(addr, FALSE);
   } else {
-    g_strlcpy(tp->name, eth->name, MAXNAMELEN);
-    tp->is_dummy_entry = FALSE;
+    while(TRUE) {
+      if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
+        /* address already known */
+        if (tp->status == HASHETHER_STATUS_RESOLVED_NAME)
+          return tp; /* Entry with a name already in table; ignore attempted replacement */
+        break;       /* Update name of existing entry */
+        }
+      if (tp->next == NULL) {
+        tp = tp->next = eth_hash_new_entry(addr, FALSE);
+        break;
+      }
+      tp = tp->next;
+    }
   }
 
+  g_strlcpy(tp->resolved_name, name, MAXNAMELEN);
+  tp->status = HASHETHER_STATUS_RESOLVED_NAME;
+  new_resolved_objects = TRUE;
+
   return tp;
+} /* add_eth_name */
+
+static hashether_t *
+eth_name_lookup(const guint8 *addr, const gboolean resolve) {
+  gint          hash_idx;
+  hashether_t  *tp;
+
+  hash_idx = HASH_ETH_ADDRESS(addr);
 
+  tp = eth_table[hash_idx];
+  if( tp == NULL ) {
+    tp = eth_table[hash_idx] = eth_hash_new_entry(addr, resolve);
+    return tp;
+  } else {
+    while(TRUE) {
+      if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
+        if (resolve && (tp->status == HASHETHER_STATUS_UNRESOLVED))
+          eth_addr_resolve(tp); /* Found but needs to be resolved */
+        return tp;
+      }
+      if (tp->next == NULL) {
+        tp->next = eth_hash_new_entry(addr, resolve);
+        return tp->next;
+      }
+      tp = tp->next;
+    }
+  }
 } /* eth_name_lookup */
 
-static guint8 *eth_addr_lookup(const gchar *name)
+static guint8 *
+eth_addr_lookup(const gchar *name)
 {
-  ether_t *eth;
-  hashether_t *tp;
+  ether_t      *eth;
+  hashether_t  *tp;
   hashether_t **table = eth_table;
-  int i;
+  gint          i;
 
   /* to be optimized (hash table from name to addr) */
   for (i = 0; i < HASHETHSIZE; i++) {
     tp = table[i];
     while (tp) {
-      if (strcmp(tp->name, name) == 0)
-    return tp->addr;
+      if (strcmp(tp->resolved_name, name) == 0)
+        return tp->addr;
       tp = tp->next;
     }
   }
@@ -1670,7 +1747,8 @@ static guint8 *eth_addr_lookup(const gchar *name)
 
 
 /* IPXNETS */
-static int parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
+static int
+parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
 {
   /*
    *  We allow three address separators (':', '-', and '.'),
@@ -1695,11 +1773,11 @@ static int parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
     if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
       if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
         if (sscanf(cp, "%x", &a) == 1) {
-      found_single_number = TRUE;
-    }
-    else {
-      return -1;
-    }
+          found_single_number = TRUE;
+        }
+        else {
+          return -1;
+        }
       }
     }
   }
@@ -1722,7 +1800,8 @@ static int parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
 
 static FILE *ipxnet_p = NULL;
 
-static void set_ipxnetent(char *path)
+static void
+set_ipxnetent(char *path)
 {
   if (ipxnet_p)
     rewind(ipxnet_p);
@@ -1730,7 +1809,8 @@ static void set_ipxnetent(char *path)
     ipxnet_p = ws_fopen(path, "r");
 }
 
-static void end_ipxnetent(void)
+static void
+end_ipxnetent(void)
 {
   if (ipxnet_p) {
     fclose(ipxnet_p);
@@ -1738,7 +1818,8 @@ static void end_ipxnetent(void)
   }
 }
 
-static ipxnet_t *get_ipxnetent(void)
+static ipxnet_t *
+get_ipxnetent(void)
 {
 
   static ipxnet_t ipxnet;
@@ -1758,13 +1839,14 @@ static ipxnet_t *get_ipxnetent(void)
 
 } /* get_ipxnetent */
 
-static ipxnet_t *get_ipxnetbyname(const gchar *name)
+static ipxnet_t *
+get_ipxnetbyname(const gchar *name)
 {
   ipxnet_t *ipxnet;
 
   set_ipxnetent(g_ipxnets_path);
 
-  while ((ipxnet = get_ipxnetent()) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
+  while (((ipxnet = get_ipxnetent()) != NULL) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
     ;
 
   if (ipxnet == NULL) {
@@ -1772,7 +1854,7 @@ static ipxnet_t *get_ipxnetbyname(const gchar *name)
 
     set_ipxnetent(g_pipxnets_path);
 
-    while ((ipxnet = get_ipxnetent()) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
+    while (((ipxnet = get_ipxnetent()) != NULL) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
       ;
 
     end_ipxnetent();
@@ -1782,21 +1864,21 @@ static ipxnet_t *get_ipxnetbyname(const gchar *name)
 
 } /* get_ipxnetbyname */
 
-static ipxnet_t *get_ipxnetbyaddr(guint32 addr)
+static ipxnet_t *
+get_ipxnetbyaddr(guint32 addr)
 {
-
   ipxnet_t *ipxnet;
 
   set_ipxnetent(g_ipxnets_path);
 
-  while ((ipxnet = get_ipxnetent()) && (addr != ipxnet->addr) ) ;
+  while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) ) ;
 
   if (ipxnet == NULL) {
     end_ipxnetent();
 
     set_ipxnetent(g_pipxnets_path);
 
-    while ((ipxnet = get_ipxnetent()) && (addr != ipxnet->addr) )
+    while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) )
       ;
 
     end_ipxnetent();
@@ -1806,7 +1888,8 @@ static ipxnet_t *get_ipxnetbyaddr(guint32 addr)
 
 } /* get_ipxnetbyaddr */
 
-static void initialize_ipxnets(void)
+static void
+initialize_ipxnets(void)
 {
   /* Compute the pathname of the ipxnets file.
    *
@@ -1817,7 +1900,7 @@ static void initialize_ipxnets(void)
    */
   if (g_ipxnets_path == NULL) {
     g_ipxnets_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
-        get_systemfile_dir(), ENAME_IPXNETS);
+                                     get_systemfile_dir(), ENAME_IPXNETS);
   }
 
   /* Set g_pipxnets_path here, but don't actually do anything
@@ -1828,7 +1911,8 @@ static void initialize_ipxnets(void)
 
 } /* initialize_ipxnets */
 
-static hashipxnet_t *add_ipxnet_name(guint addr, const gchar *name)
+static hashipxnet_t *
+add_ipxnet_name(guint addr, const gchar *name)
 {
   int hash_idx;
   hashipxnet_t *tp;
@@ -1842,10 +1926,10 @@ static hashipxnet_t *add_ipxnet_name(guint addr, const gchar *name)
   } else {
     while(1) {
       if (tp->next == NULL) {
-    tp->next = (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
-    tp = tp->next;
-    break;
-      }
+        tp->next = (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
+        tp = tp->next;
+        break;
+      }
       tp = tp->next;
     }
   }
@@ -1853,12 +1937,14 @@ static hashipxnet_t *add_ipxnet_name(guint addr, const gchar *name)
   tp->addr = addr;
   g_strlcpy(tp->name, name, MAXNAMELEN);
   tp->next = NULL;
+  new_resolved_objects = TRUE;
 
   return tp;
 
 } /* add_ipxnet_name */
 
-static gchar *ipxnet_name_lookup(const guint addr)
+static gchar *
+ipxnet_name_lookup(const guint addr)
 {
   int hash_idx;
   hashipxnet_t *tp;
@@ -1873,12 +1959,12 @@ static gchar *ipxnet_name_lookup(const guint addr)
   } else {
     while(1) {
       if (tp->addr == addr) {
-    return tp->name;
+        return tp->name;
       }
       if (tp->next == NULL) {
-    tp->next = (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
-    tp = tp->next;
-    break;
+        tp->next = (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
+        tp = tp->next;
+        break;
       }
       tp = tp->next;
     }
@@ -1891,7 +1977,7 @@ static gchar *ipxnet_name_lookup(const guint addr)
 
   if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL) {
     /* unknown name */
-      g_snprintf(tp->name, MAXNAMELEN, "%X", addr);
+    g_snprintf(tp->name, MAXNAMELEN, "%X", addr);
 
   } else {
     g_strlcpy(tp->name, ipxnet->name, MAXNAMELEN);
@@ -1901,7 +1987,8 @@ static gchar *ipxnet_name_lookup(const guint addr)
 
 } /* ipxnet_name_lookup */
 
-static guint ipxnet_addr_lookup(const gchar *name, gboolean *success)
+static guint
+ipxnet_addr_lookup(const gchar *name, gboolean *success)
 {
   ipxnet_t *ipxnet;
   hashipxnet_t *tp;
@@ -1914,7 +2001,7 @@ static guint ipxnet_addr_lookup(const gchar *name, gboolean *success)
     while (tp) {
       if (strcmp(tp->name, name) == 0) {
         *success = TRUE;
-    return tp->addr;
+        return tp->addr;
       }
       tp = tp->next;
     }
@@ -1936,7 +2023,7 @@ static guint ipxnet_addr_lookup(const gchar *name, gboolean *success)
 
 } /* ipxnet_addr_lookup */
 
-static gboolean
+gboolean
 read_hosts_file (const char *hostspath)
 {
   FILE *hf;
@@ -1944,7 +2031,7 @@ read_hosts_file (const char *hostspath)
   int size = 0;
   gchar *cp;
   guint32 host_addr[4]; /* IPv4 or IPv6 */
-  struct e_in6_addr ipv6_addr;
+  struct e_in6_addr ip6_addr;
   gboolean is_ipv6;
   int ret;
 
@@ -1979,18 +2066,19 @@ read_hosts_file (const char *hostspath)
       continue; /* no host name */
 
     if (is_ipv6) {
-      memcpy(&ipv6_addr, host_addr, sizeof ipv6_addr);
-      add_ipv6_name(&ipv6_addr, cp);
+      memcpy(&ip6_addr, host_addr, sizeof ip6_addr);
+      add_ipv6_name(&ip6_addr, cp);
     } else
       add_ipv4_name(host_addr[0], cp);
 
     /*
      * Add the aliases, too, if there are any.
+     * XXX - host_lookup() only returns the first entry.
      */
     while ((cp = strtok(NULL, " \t")) != NULL) {
       if (is_ipv6) {
-        memcpy(&ipv6_addr, host_addr, sizeof ipv6_addr);
-        add_ipv6_name(&ipv6_addr, cp);
+        memcpy(&ip6_addr, host_addr, sizeof ip6_addr);
+        add_ipv6_name(&ip6_addr, cp);
       } else
         add_ipv4_name(host_addr[0], cp);
     }
@@ -2001,6 +2089,42 @@ read_hosts_file (const char *hostspath)
   return TRUE;
 } /* read_hosts_file */
 
+gboolean
+add_ip_name_from_string (const char *addr, const char *name)
+{
+  guint32 host_addr[4]; /* IPv4 */
+  struct e_in6_addr ip6_addr; /* IPv6 */
+  gboolean is_ipv6;
+  int ret;
+
+  ret = inet_pton(AF_INET6, addr, &ip6_addr);
+  if (ret == -1)
+    /* Error parsing address */
+    return FALSE;
+
+  if (ret == 1) {
+    /* Valid IPv6 */
+    is_ipv6 = TRUE;
+  } else {
+    /* Not valid IPv6 - valid IPv4? */
+    if (inet_pton(AF_INET, addr, &host_addr) != 1)
+      return FALSE; /* no */
+    is_ipv6 = FALSE;
+  }
+
+  if (is_ipv6) {
+    add_ipv6_name(&ip6_addr, name);
+  } else {
+    add_ipv4_name(host_addr[0], name);
+  }
+
+  return TRUE;
+} /* add_ip_name_from_string */
+
+struct addrinfo *
+get_addrinfo_list(void) {
+  return addrinfo_list;
+}
 
 /* Read in a list of subnet definition - name pairs.
  * <line> = <comment> | <entry> | <whitespace>
@@ -2067,183 +2191,188 @@ read_subnets_file (const char *subnetspath)
   return TRUE;
 } /* read_subnets_file */
 
-static subnet_entry_t subnet_lookup(const guint32 addr)
+static subnet_entry_t
+subnet_lookup(const guint32 addr)
 {
-    subnet_entry_t subnet_entry;
-    guint32 i;
+  subnet_entry_t subnet_entry;
+  guint32 i;
 
-    /* Search mask lengths linearly, longest first */
+  /* Search mask lengths linearly, longest first */
 
-    i = SUBNETLENGTHSIZE;
-    while(have_subnet_entry && i > 0) {
-        guint32 masked_addr;
-        subnet_length_entry_t* length_entry;
+  i = SUBNETLENGTHSIZE;
+  while(have_subnet_entry && i > 0) {
+    guint32 masked_addr;
+    subnet_length_entry_t* length_entry;
 
-        /* Note that we run from 31 (length 32)  to 0 (length 1)  */
-        --i;
-        g_assert(i < SUBNETLENGTHSIZE);
+    /* Note that we run from 31 (length 32)  to 0 (length 1)  */
+    --i;
+    g_assert(i < SUBNETLENGTHSIZE);
 
 
-        length_entry = &subnet_length_entries[i];
+    length_entry = &subnet_length_entries[i];
 
-        if(NULL != length_entry->subnet_addresses) {
-            hashipv4_t * tp;
-            guint32 hash_idx;
+    if(NULL != length_entry->subnet_addresses) {
+      hashipv4_t * tp;
+      guint32 hash_idx;
 
-            masked_addr = addr & length_entry->mask;
-            hash_idx = HASH_IPV4_ADDRESS(masked_addr);
+      masked_addr = addr & length_entry->mask;
+      hash_idx = HASH_IPV4_ADDRESS(masked_addr);
 
-            tp = length_entry->subnet_addresses[hash_idx];
-            while(tp != NULL && tp->addr != masked_addr) {
-                tp = tp->next;
-            }
+      tp = length_entry->subnet_addresses[hash_idx];
+      while(tp != NULL && tp->addr != masked_addr) {
+        tp = tp->next;
+      }
 
-            if(NULL != tp) {
-                subnet_entry.mask = length_entry->mask;
-                subnet_entry.mask_length = i + 1; /* Length is offset + 1 */
-                subnet_entry.name = tp->name;
-                return subnet_entry;
-            }
-        }
+      if(NULL != tp) {
+        subnet_entry.mask = length_entry->mask;
+        subnet_entry.mask_length = i + 1; /* Length is offset + 1 */
+        subnet_entry.name = tp->name;
+        return subnet_entry;
+      }
     }
+  }
 
-    subnet_entry.mask = 0;
-    subnet_entry.mask_length = 0;
-    subnet_entry.name = NULL;
+  subnet_entry.mask = 0;
+  subnet_entry.mask_length = 0;
+  subnet_entry.name = NULL;
 
-    return subnet_entry;
+  return subnet_entry;
 }
 
 /* Add a subnet-definition - name pair to the set.
  * The definition is taken by masking the address passed in with the mask of the
  * given length.
  */
-static void subnet_entry_set(guint32 subnet_addr, guint32 mask_length, const gchar* name)
+static void
+subnet_entry_set(guint32 subnet_addr, const guint32 mask_length, const gchar* name)
 {
-    subnet_length_entry_t* entry;
-    hashipv4_t * tp;
-    gsize hash_idx;
+  subnet_length_entry_t* entry;
+  hashipv4_t * tp;
+  gsize hash_idx;
 
-    g_assert(mask_length > 0 && mask_length <= 32);
+  g_assert(mask_length > 0 && mask_length <= 32);
 
-    entry = &subnet_length_entries[mask_length - 1];
+  entry = &subnet_length_entries[mask_length - 1];
 
-    subnet_addr &= entry->mask;
+  subnet_addr &= entry->mask;
 
-    hash_idx = HASH_IPV4_ADDRESS(subnet_addr);
+  hash_idx = HASH_IPV4_ADDRESS(subnet_addr);
 
-    if(NULL == entry->subnet_addresses) {
-        entry->subnet_addresses = g_new0(hashipv4_t*,HASHHOSTSIZE);
-    }
+  if(NULL == entry->subnet_addresses) {
+    entry->subnet_addresses = g_new0(hashipv4_t*,HASHHOSTSIZE);
+  }
 
-    if(NULL != (tp = entry->subnet_addresses[hash_idx])) {
-        if(tp->addr == subnet_addr) {
-            return;    /* XXX provide warning that an address was repeated? */
-        } else {
-           hashipv4_t * new_tp = g_new(hashipv4_t,1);
-           tp->next = new_tp;
-           tp = new_tp;
-        }
+  if(NULL != (tp = entry->subnet_addresses[hash_idx])) {
+    if(tp->addr == subnet_addr) {
+      return;    /* XXX provide warning that an address was repeated? */
     } else {
-        tp = entry->subnet_addresses[hash_idx] = g_new(hashipv4_t,1);
+      hashipv4_t * new_tp = g_new(hashipv4_t,1);
+      tp->next = new_tp;
+      tp = new_tp;
     }
+  } else {
+    tp = entry->subnet_addresses[hash_idx] = g_new(hashipv4_t,1);
+  }
 
-    tp->next = NULL;
-    tp->addr = subnet_addr;
-    tp->is_dummy_entry = FALSE; /*Never used again...*/
-    g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
-    have_subnet_entry = TRUE;
+  tp->next = NULL;
+  tp->addr = subnet_addr;
+  tp->is_dummy_entry = FALSE; /*Never used again...*/
+  g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
+  have_subnet_entry = TRUE;
 }
 
-static guint32 get_subnet_mask(guint32 mask_length) {
-
-    static guint32 masks[SUBNETLENGTHSIZE];
-    static gboolean initialised = FALSE;
-
-    if(!initialised) {
-        memset(masks, 0, sizeof(masks));
-
-        initialised = TRUE;
-
-        /* XXX There must be a better way to do this than
-         * hand-coding the values, but I can't seem to
-         * come up with one!
-         */
-
-        inet_pton(AF_INET, "128.0.0.0", &masks[0]);
-        inet_pton(AF_INET, "192.0.0.0", &masks[1]);
-        inet_pton(AF_INET, "224.0.0.0", &masks[2]);
-        inet_pton(AF_INET, "240.0.0.0", &masks[3]);
-        inet_pton(AF_INET, "248.0.0.0", &masks[4]);
-        inet_pton(AF_INET, "252.0.0.0", &masks[5]);
-        inet_pton(AF_INET, "254.0.0.0", &masks[6]);
-        inet_pton(AF_INET, "255.0.0.0", &masks[7]);
-
-        inet_pton(AF_INET, "255.128.0.0", &masks[8]);
-        inet_pton(AF_INET, "255.192.0.0", &masks[9]);
-        inet_pton(AF_INET, "255.224.0.0", &masks[10]);
-        inet_pton(AF_INET, "255.240.0.0", &masks[11]);
-        inet_pton(AF_INET, "255.248.0.0", &masks[12]);
-        inet_pton(AF_INET, "255.252.0.0", &masks[13]);
-        inet_pton(AF_INET, "255.254.0.0", &masks[14]);
-        inet_pton(AF_INET, "255.255.0.0", &masks[15]);
-
-        inet_pton(AF_INET, "255.255.128.0", &masks[16]);
-        inet_pton(AF_INET, "255.255.192.0", &masks[17]);
-        inet_pton(AF_INET, "255.255.224.0", &masks[18]);
-        inet_pton(AF_INET, "255.255.240.0", &masks[19]);
-        inet_pton(AF_INET, "255.255.248.0", &masks[20]);
-        inet_pton(AF_INET, "255.255.252.0", &masks[21]);
-        inet_pton(AF_INET, "255.255.254.0", &masks[22]);
-        inet_pton(AF_INET, "255.255.255.0", &masks[23]);
-
-        inet_pton(AF_INET, "255.255.255.128", &masks[24]);
-        inet_pton(AF_INET, "255.255.255.192", &masks[25]);
-        inet_pton(AF_INET, "255.255.255.224", &masks[26]);
-        inet_pton(AF_INET, "255.255.255.240", &masks[27]);
-        inet_pton(AF_INET, "255.255.255.248", &masks[28]);
-        inet_pton(AF_INET, "255.255.255.252", &masks[29]);
-        inet_pton(AF_INET, "255.255.255.254", &masks[30]);
-        inet_pton(AF_INET, "255.255.255.255", &masks[31]);
-    }
+static guint32
+get_subnet_mask(const guint32 mask_length) {
 
-    if(mask_length == 0 || mask_length > SUBNETLENGTHSIZE) {
-        g_assert_not_reached();
-        return 0;
-    } else {
-        return masks[mask_length - 1];
-    }
+  static guint32 masks[SUBNETLENGTHSIZE];
+  static gboolean initialised = FALSE;
+
+  if(!initialised) {
+    memset(masks, 0, sizeof(masks));
+
+    initialised = TRUE;
+
+    /* XXX There must be a better way to do this than
+     * hand-coding the values, but I can't seem to
+     * come up with one!
+     */
+
+    inet_pton(AF_INET, "128.0.0.0", &masks[0]);
+    inet_pton(AF_INET, "192.0.0.0", &masks[1]);
+    inet_pton(AF_INET, "224.0.0.0", &masks[2]);
+    inet_pton(AF_INET, "240.0.0.0", &masks[3]);
+    inet_pton(AF_INET, "248.0.0.0", &masks[4]);
+    inet_pton(AF_INET, "252.0.0.0", &masks[5]);
+    inet_pton(AF_INET, "254.0.0.0", &masks[6]);
+    inet_pton(AF_INET, "255.0.0.0", &masks[7]);
+
+    inet_pton(AF_INET, "255.128.0.0", &masks[8]);
+    inet_pton(AF_INET, "255.192.0.0", &masks[9]);
+    inet_pton(AF_INET, "255.224.0.0", &masks[10]);
+    inet_pton(AF_INET, "255.240.0.0", &masks[11]);
+    inet_pton(AF_INET, "255.248.0.0", &masks[12]);
+    inet_pton(AF_INET, "255.252.0.0", &masks[13]);
+    inet_pton(AF_INET, "255.254.0.0", &masks[14]);
+    inet_pton(AF_INET, "255.255.0.0", &masks[15]);
+
+    inet_pton(AF_INET, "255.255.128.0", &masks[16]);
+    inet_pton(AF_INET, "255.255.192.0", &masks[17]);
+    inet_pton(AF_INET, "255.255.224.0", &masks[18]);
+    inet_pton(AF_INET, "255.255.240.0", &masks[19]);
+    inet_pton(AF_INET, "255.255.248.0", &masks[20]);
+    inet_pton(AF_INET, "255.255.252.0", &masks[21]);
+    inet_pton(AF_INET, "255.255.254.0", &masks[22]);
+    inet_pton(AF_INET, "255.255.255.0", &masks[23]);
+
+    inet_pton(AF_INET, "255.255.255.128", &masks[24]);
+    inet_pton(AF_INET, "255.255.255.192", &masks[25]);
+    inet_pton(AF_INET, "255.255.255.224", &masks[26]);
+    inet_pton(AF_INET, "255.255.255.240", &masks[27]);
+    inet_pton(AF_INET, "255.255.255.248", &masks[28]);
+    inet_pton(AF_INET, "255.255.255.252", &masks[29]);
+    inet_pton(AF_INET, "255.255.255.254", &masks[30]);
+    inet_pton(AF_INET, "255.255.255.255", &masks[31]);
+  }
+
+  if(mask_length == 0 || mask_length > SUBNETLENGTHSIZE) {
+    g_assert_not_reached();
+    return 0;
+  } else {
+    return masks[mask_length - 1];
+  }
 }
 
-static void subnet_name_lookup_init(void)
+static void
+subnet_name_lookup_init(void)
 {
-    gchar* subnetspath;
+  gchar* subnetspath;
+  guint32 i;
 
-    guint32 i;
-    for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
-        guint32 length = i + 1;
+  for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
+    guint32 length = i + 1;
 
-        subnet_length_entries[i].subnet_addresses  = NULL;
-        subnet_length_entries[i].mask_length  = length;
-        subnet_length_entries[i].mask = get_subnet_mask(length);
-    }
+    subnet_length_entries[i].subnet_addresses  = NULL;
+    subnet_length_entries[i].mask_length  = length;
+    subnet_length_entries[i].mask = get_subnet_mask(length);
+  }
 
-    subnetspath = get_persconffile_path(ENAME_SUBNETS, FALSE, FALSE);
-    if (!read_subnets_file(subnetspath) && errno != ENOENT) {
-        report_open_failure(subnetspath, errno, FALSE);
-    }
-    g_free(subnetspath);
+  subnetspath = get_persconffile_path(ENAME_SUBNETS, FALSE, FALSE);
+  if (!read_subnets_file(subnetspath) && errno != ENOENT) {
+    report_open_failure(subnetspath, errno, FALSE);
+  }
+  g_free(subnetspath);
 
-    /*
-    * Load the global subnets file, if we have one.
-    */
-    subnetspath = get_datafile_path(ENAME_SUBNETS);
-    if (!read_subnets_file(subnetspath) && errno != ENOENT) {
-        report_open_failure(subnetspath, errno, FALSE);
-    }
-    g_free(subnetspath);
+  /*
+   * Load the global subnets file, if we have one.
+   */
+  subnetspath = get_datafile_path(ENAME_SUBNETS);
+  if (!read_subnets_file(subnetspath) && errno != ENOENT) {
+    report_open_failure(subnetspath, errno, FALSE);
+  }
+  g_free(subnetspath);
 }
 
+
 /*
  *  External Functions
  */
@@ -2251,6 +2380,7 @@ static void subnet_name_lookup_init(void)
 void
 host_name_lookup_init(void) {
   char *hostspath;
+  struct addrinfo *ai;
 
 #ifdef HAVE_GNU_ADNS
 #ifdef _WIN32
@@ -2260,6 +2390,11 @@ host_name_lookup_init(void) {
 #endif /* _WIN32 */
 #endif /*GNU_ADNS */
 
+  if (!addrinfo_list) {
+    ai = g_malloc0(sizeof(struct addrinfo));
+    addrinfo_list = addrinfo_list_last = ai;
+  }
+
   /*
    * Load the user's hosts file, if they have one.
    */
@@ -2279,9 +2414,15 @@ host_name_lookup_init(void) {
   g_free(hostspath);
 
 #ifdef HAVE_C_ARES
-  if (ares_init(&alchan) == ARES_SUCCESS) {
+#ifdef CARES_HAVE_ARES_LIBRARY_INIT
+  if (ares_library_init(ARES_LIB_INIT_ALL) == ARES_SUCCESS) {
+#endif
+  if (ares_init(&ghba_chan) == ARES_SUCCESS && ares_init(&ghbn_chan) == ARES_SUCCESS) {
     async_dns_initialized = TRUE;
   }
+#ifdef CARES_HAVE_ARES_LIBRARY_INIT
+  }
+#endif
 #else
 #ifdef HAVE_GNU_ADNS
   /*
@@ -2331,7 +2472,7 @@ host_name_lookup_init(void) {
 #endif /* HAVE_GNU_ADNS */
 #endif /* HAVE_C_ARES */
 
-    subnet_name_lookup_init();
+  subnet_name_lookup_init();
 }
 
 #ifdef HAVE_C_ARES
@@ -2341,37 +2482,40 @@ host_name_lookup_process(gpointer data _U_) {
   struct timeval tv = { 0, 0 };
   int nfds;
   fd_set rfds, wfds;
+  gboolean nro = new_resolved_objects;
+
+  new_resolved_objects = FALSE;
 
   if (!async_dns_initialized)
     /* c-ares not initialized. Bail out and cancel timers. */
-    return FALSE;
+    return nro;
 
   async_dns_queue_head = g_list_first(async_dns_queue_head);
 
-  while (async_dns_queue_head && async_dns_in_flight <= prefs.name_resolve_concurrency) {
+  while (async_dns_queue_head != NULL && async_dns_in_flight <= prefs.name_resolve_concurrency) {
     caqm = (async_dns_queue_msg_t *) async_dns_queue_head->data;
     async_dns_queue_head = g_list_remove(async_dns_queue_head, (void *) caqm);
     if (caqm->family == AF_INET) {
-      ares_gethostbyaddr(alchan, &caqm->addr.ip4, sizeof(guint32), AF_INET,
-        c_ares_ghba_cb, caqm);
+      ares_gethostbyaddr(ghba_chan, &caqm->addr.ip4, sizeof(guint32), AF_INET,
+                         c_ares_ghba_cb, caqm);
       async_dns_in_flight++;
     } else if (caqm->family == AF_INET6) {
-      ares_gethostbyaddr(alchan, &caqm->addr.ip6, sizeof(struct e_in6_addr),
-        AF_INET, c_ares_ghba_cb, caqm);
+      ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(struct e_in6_addr),
+                         AF_INET6, c_ares_ghba_cb, caqm);
       async_dns_in_flight++;
     }
   }
 
   FD_ZERO(&rfds);
   FD_ZERO(&wfds);
-  nfds = ares_fds(alchan, &rfds, &wfds);
+  nfds = ares_fds(ghba_chan, &rfds, &wfds);
   if (nfds > 0) {
     select(nfds, &rfds, &wfds, NULL, &tv);
-    ares_process(alchan, &rfds, &wfds);
+    ares_process(ghba_chan, &rfds, &wfds);
   }
 
-  /* Keep the timeout in place */
-  return TRUE;
+  /* Any new entries? */
+  return nro;
 }
 
 void
@@ -2386,8 +2530,13 @@ host_name_lookup_cleanup(void) {
 
   g_list_free(async_dns_queue_head);
 
-  if (async_dns_initialized)
-    ares_destroy(alchan);
+  if (async_dns_initialized) {
+    ares_destroy(ghba_chan);
+    ares_destroy(ghbn_chan);
+  }
+#ifdef CARES_HAVE_ARES_LIBRARY_INIT
+  ares_library_cleanup();
+#endif
   async_dns_initialized = FALSE;
 }
 
@@ -2405,7 +2554,9 @@ host_name_lookup_process(gpointer data _U_) {
   adns_answer *ans;
   int ret;
   gboolean dequeue;
+  gboolean nro = new_resolved_objects;
 
+  new_resolved_objects = FALSE;
   async_dns_queue_head = g_list_first(async_dns_queue_head);
 
   cur = async_dns_queue_head;
@@ -2414,11 +2565,11 @@ host_name_lookup_process(gpointer data _U_) {
     if (! almsg->submitted && almsg->type == AF_INET) {
       addr_bytes = (guint8 *) &almsg->ip4_addr;
       g_snprintf(addr_str, sizeof addr_str, "%u.%u.%u.%u.in-addr.arpa.", addr_bytes[3],
-          addr_bytes[2], addr_bytes[1], addr_bytes[0]);
+                 addr_bytes[2], addr_bytes[1], addr_bytes[0]);
       /* XXX - what if it fails? */
       adns_submit (ads, addr_str, adns_r_ptr, 0, NULL, &almsg->query);
       almsg->submitted = TRUE;
-       async_dns_in_flight++;
+      async_dns_in_flight++;
     }
     cur = cur->next;
   }
@@ -2430,22 +2581,22 @@ host_name_lookup_process(gpointer data _U_) {
     if (almsg->submitted) {
       ret = adns_check(ads, &almsg->query, &ans, NULL);
       if (ret == 0) {
-    if (ans->status == adns_s_ok) {
-      add_ipv4_name(almsg->ip4_addr, *ans->rrs.str);
-    }
-    dequeue = TRUE;
+        if (ans->status == adns_s_ok) {
+          add_ipv4_name(almsg->ip4_addr, *ans->rrs.str);
+        }
+        dequeue = TRUE;
       }
     }
     cur = cur->next;
     if (dequeue) {
       async_dns_queue_head = g_list_remove(async_dns_queue_head, (void *) almsg);
       g_free(almsg);
-       async_dns_in_flight--;
+      async_dns_in_flight--;
     }
   }
 
   /* Keep the timeout in place */
-  return TRUE;
+  return nro;
 }
 
 void
@@ -2461,15 +2612,18 @@ host_name_lookup_cleanup(void) {
 
   if (async_dns_initialized)
     adns_finish(ads);
-   async_dns_initialized = FALSE;
+  async_dns_initialized = FALSE;
 }
 
 #else /* HAVE_GNU_ADNS */
 
 gboolean
 host_name_lookup_process(gpointer data _U_) {
-  /* Kill the timeout, as there's nothing for it to do */
-  return FALSE;
+  gboolean nro = new_resolved_objects;
+
+  new_resolved_objects = FALSE;
+
+  return nro;
 }
 
 void
@@ -2478,10 +2632,11 @@ host_name_lookup_cleanup(void) {
 
 #endif /* HAVE_C_ARES */
 
-extern const gchar *get_hostname(guint addr)
+extern const gchar *
+get_hostname(const guint addr)
 {
   gboolean found;
-  gboolean resolve = g_resolv_flags & RESOLV_NETWORK;
+  gboolean resolve = gbl_resolv_flags & RESOLV_NETWORK;
   hashipv4_t *tp = host_lookup(addr, resolve, &found);
 
   if (!resolve)
@@ -2490,40 +2645,29 @@ extern const gchar *get_hostname(guint addr)
   return tp->name;
 }
 
-extern gchar *get_hostip(guint addr)
-{
-  gboolean found;
-  hashipv4_t *tp = host_lookup(addr, FALSE, &found);
-
-  return tp->ip;
-}
-
 /* -------------------------- */
 
-extern const gchar *get_hostname6(struct e_in6_addr *addr)
+extern const gchar *
+get_hostname6(const struct e_in6_addr *addr)
 {
   gboolean found;
-  gboolean resolve = g_resolv_flags & RESOLV_NETWORK;
+  gboolean resolve = gbl_resolv_flags & RESOLV_NETWORK;
   hashipv6_t *tp = host_lookup6(addr, resolve, &found);
 
-  if (!resolve || E_IN6_IS_ADDR_LINKLOCAL(addr) || E_IN6_IS_ADDR_MULTICAST(addr))
+  if (!resolve)
     return tp->ip6;
-  return tp->name;
-}
-
-extern gchar *get_hostip6(const struct e_in6_addr *addr)
-{
-  gboolean found;
-  hashipv6_t *tp = host_lookup6(addr, FALSE, &found);
 
-  return tp->ip6;
+  return tp->name;
 }
 
 /* -------------------------- */
-extern void add_ipv4_name(guint addr, const gchar *name)
+extern void
+add_ipv4_name(const guint addr, const gchar *name)
 {
   int hash_idx;
   hashipv4_t *tp;
+  struct addrinfo *ai;
+  struct sockaddr_in *sa4;
 
   hash_idx = HASH_IPV4_ADDRESS(addr);
 
@@ -2534,31 +2678,54 @@ extern void add_ipv4_name(guint addr, const gchar *name)
   } else {
     while(1) {
       if (tp->addr == addr) {
-    /* address already known */
-    if (!tp->is_dummy_entry) {
-      return;
-    } else {
-        /* replace this dummy entry with the new one */
-      break;
-    }
+        /* address already known */
+        if (!tp->is_dummy_entry) {
+          return;
+        } else {
+          /* replace this dummy entry with the new one */
+          break;
+        }
       }
       if (tp->next == NULL) {
-          tp->next = new_ipv4(addr);
-          tp = tp->next;
-          break;
+        tp->next = new_ipv4(addr);
+        tp = tp->next;
+        break;
       }
       tp = tp->next;
     }
   }
   g_strlcpy(tp->name, name, MAXNAMELEN);
   tp->resolve = TRUE;
+  new_resolved_objects = TRUE;
+
+  if (!addrinfo_list) {
+    ai = g_malloc0(sizeof(struct addrinfo));
+    addrinfo_list = addrinfo_list_last = ai;
+  }
+
+  sa4 = g_malloc0(sizeof(struct sockaddr_in));
+  sa4->sin_family = AF_INET;
+  sa4->sin_addr.s_addr = addr;
+
+  ai = g_malloc0(sizeof(struct addrinfo));
+  ai->ai_family = AF_INET;
+  ai->ai_addrlen = sizeof(struct sockaddr_in);
+  ai->ai_canonname = (char *) tp->name;
+  ai->ai_addr = (struct sockaddr*) sa4;
+
+  addrinfo_list_last->ai_next = ai;
+  addrinfo_list_last = ai;
+
 } /* add_ipv4_name */
 
 /* -------------------------- */
-extern void add_ipv6_name(struct e_in6_addr *addrp, const gchar *name)
+extern void
+add_ipv6_name(const struct e_in6_addr *addrp, const gchar *name)
 {
   int hash_idx;
   hashipv6_t *tp;
+  struct addrinfo *ai;
+  struct sockaddr_in6 *sa6;
 
   hash_idx = HASH_IPV6_ADDRESS(*addrp);
 
@@ -2569,49 +2736,65 @@ extern void add_ipv6_name(struct e_in6_addr *addrp, const gchar *name)
   } else {
     while(1) {
       if (memcmp(&tp->addr, addrp, sizeof (struct e_in6_addr)) == 0) {
-    /* address already known */
-    if (!tp->is_dummy_entry) {
-      return;
-    } else {
-      /* replace this dummy entry with the new one */
-      break;
-    }
+        /* address already known */
+        if (!tp->is_dummy_entry) {
+          return;
+        } else {
+          /* replace this dummy entry with the new one */
+          break;
+        }
       }
       if (tp->next == NULL) {
-          tp->next = new_ipv6(addrp);
-          tp = tp->next;
-          break;
+        tp->next = new_ipv6(addrp);
+        tp = tp->next;
+        break;
       }
       tp = tp->next;
     }
   }
-
   g_strlcpy(tp->name, name, MAXNAMELEN);
   tp->resolve = TRUE;
+  new_resolved_objects = TRUE;
+
+  if (!addrinfo_list) {
+    ai = g_malloc0(sizeof(struct addrinfo));
+    addrinfo_list = addrinfo_list_last = ai;
+  }
+
+  sa6 = g_malloc0(sizeof(struct sockaddr_in6));
+  sa6->sin6_family = AF_INET;
+  memcpy(sa6->sin6_addr.s6_addr, addrp, 16);
+
+  ai = g_malloc0(sizeof(struct addrinfo));
+  ai->ai_family = AF_INET6;
+  ai->ai_addrlen = sizeof(struct sockaddr_in);
+  ai->ai_canonname = (char *) tp->name;
+  ai->ai_addr = (struct sockaddr *) sa6;
+
+  addrinfo_list_last->ai_next = ai;
+  addrinfo_list_last = ai;
 
 } /* add_ipv6_name */
 
 /* -----------------
  * unsigned integer to ascii
 */
-static gchar *ep_utoa(guint port)
+static gchar *
+ep_utoa(guint port)
 {
   gchar *bp = ep_alloc(MAXNAMELEN);
 
-  bp = &bp[MAXNAMELEN -1];
-
-  *bp = 0;
-  do {
-      *--bp = (port % 10) +'0';
-  } while ((port /= 10) != 0);
+  /* XXX, guint32_to_str() ? */
+  guint32_to_str_buf(port, bp, MAXNAMELEN);
   return bp;
 }
 
 
-extern gchar *get_udp_port(guint port)
+extern gchar *
+get_udp_port(guint port)
 {
 
-  if (!(g_resolv_flags & RESOLV_TRANSPORT)) {
+  if (!(gbl_resolv_flags & RESOLV_TRANSPORT)) {
     return ep_utoa(port);
   }
 
@@ -2619,10 +2802,11 @@ extern gchar *get_udp_port(guint port)
 
 } /* get_udp_port */
 
-extern gchar *get_dccp_port(guint port)
+extern gchar *
+get_dccp_port(guint port)
 {
 
-  if (!(g_resolv_flags & RESOLV_TRANSPORT)) {
+  if (!(gbl_resolv_flags & RESOLV_TRANSPORT)) {
     return ep_utoa(port);
   }
 
@@ -2631,10 +2815,11 @@ extern gchar *get_dccp_port(guint port)
 } /* get_dccp_port */
 
 
-extern gchar *get_tcp_port(guint port)
+extern gchar *
+get_tcp_port(guint port)
 {
 
-  if (!(g_resolv_flags & RESOLV_TRANSPORT)) {
+  if (!(gbl_resolv_flags & RESOLV_TRANSPORT)) {
     return ep_utoa(port);
   }
 
@@ -2642,10 +2827,11 @@ extern gchar *get_tcp_port(guint port)
 
 } /* get_tcp_port */
 
-extern gchar *get_sctp_port(guint port)
+extern gchar *
+get_sctp_port(guint port)
 {
 
-  if (!(g_resolv_flags & RESOLV_TRANSPORT)) {
+  if (!(gbl_resolv_flags & RESOLV_TRANSPORT)) {
     return ep_utoa(port);
   }
 
@@ -2653,47 +2839,50 @@ extern gchar *get_sctp_port(guint port)
 
 } /* get_sctp_port */
 
-const gchar *get_addr_name(const address *addr)
+const gchar *
+get_addr_name(const address *addr)
 {
   const gchar *result;
 
   result = solve_address_to_name(addr);
 
   if (result != NULL)
-      return result;
+    return result;
 
   /* if it gets here, either it is of type AT_NONE, */
   /* or it should be solvable in address_to_str -unless addr->type is wrongly defined */
 
   if (addr->type == AT_NONE){
-      return "NONE";
+    return "NONE";
   }
 
   /* We need an ephemeral allocated string */
   return ep_address_to_str(addr);
 }
 
-const gchar *se_get_addr_name(const address *addr)
+const gchar *
+se_get_addr_name(const address *addr)
 {
   const gchar *result;
 
   result = se_solve_address_to_name(addr);
 
   if (result != NULL)
-      return result;
+    return result;
 
   /* if it gets here, either it is of type AT_NONE, */
   /* or it should be solvable in se_address_to_str -unless addr->type is wrongly defined */
 
   if (addr->type == AT_NONE){
-      return "NONE";
+    return "NONE";
   }
 
   /* We need a "permanently" allocated string */
   return se_address_to_str(addr);
 }
 
-void get_addr_name_buf(address *addr, gchar *buf, gsize size)
+void
+get_addr_name_buf(const address *addr, gchar *buf, gsize size)
 {
   const gchar *result = get_addr_name(addr);
 
@@ -2701,157 +2890,79 @@ void get_addr_name_buf(address *addr, gchar *buf, gsize size)
 } /* get_addr_name_buf */
 
 
-gchar *get_ether_name(const guint8 *addr)
+gchar *
+get_ether_name(const guint8 *addr)
 {
   hashether_t *tp;
-  gboolean resolve = g_resolv_flags & RESOLV_MAC;
-#if 0
-  if (!(g_resolv_flags & RESOLV_MAC))
-    return ether_to_str(addr);
-#endif
+  gboolean resolve = (gbl_resolv_flags & RESOLV_MAC) != 0;
+
   if (resolve && !eth_resolution_initialized) {
     initialize_ethers();
-    eth_resolution_initialized = 1;
+    eth_resolution_initialized = TRUE;
   }
 
   tp = eth_name_lookup(addr, resolve);
-  return tp->name;
-} /* get_ether_name */
-
-/* a name resolution is unset, reset name */
-void
-name_resolution_changed(guint32 action)
-{
-  guint i;
-  if ((action & RESOLV_MAC)) {
-      /* this stuff is broken but ether stuff isn't easy */
-      hashether_t *tp;
-      for (i = 0; i < HASHETHSIZE; i++) {
-         tp = eth_table[i];
-         while (tp) {
-            strcpy(tp->name, tp->hexa);
-            /* tp->is_dummy_entry = FALSE; */
-            tp = tp->next;
-       }
-      }
-  }
 
-  if ((action & RESOLV_NETWORK)) {
-      hashipv4_t *tp;
-      hashipv6_t *tp6;
-
-      for (i = 0; i < HASHHOSTSIZE; i++) {
-         tp = ipv4_table[i];
-         while (tp) {
-            strcpy(tp->name, tp->ip);
-            tp->is_dummy_entry = TRUE;
-            tp->resolve = FALSE;
-            tp = tp->next;
-       }
-      }
-
-      for (i = 0; i < HASHHOSTSIZE; i++) {
-         tp6 = ipv6_table[i];
-         while (tp6) {
-            strcpy(tp6->name, tp6->ip6);
-            tp6->is_dummy_entry = TRUE;
-            tp6->resolve = FALSE;
-            tp6 = tp6->next;
-       }
-      }
-  }
-}
-
-/* ---------------------- */
-extern gchar *get_ether_hexa(const guint8 *addr)
-{
-  hashether_t *tp;
-  tp = eth_name_lookup(addr, FALSE);
-  return tp->hexa;
-}
+  return resolve ? tp->resolved_name : tp->hexaddr;
 
+} /* get_ether_name */
 
-/* Look for an ether name in the hash, and return it if found.
- * If it's not found, simply return NULL. We DO NOT make a new
- * hash entry for it with the hex digits turned into a string.
+/* Look for a (non-dummy) ether name in the hash, and return it if found.
+ * If it's not found, simply return NULL.
  */
-gchar *get_ether_name_if_known(const guint8 *addr)
+gchar *
+get_ether_name_if_known(const guint8 *addr)
 {
-  int hash_idx;
   hashether_t *tp;
 
   /* Initialize ether structs if we're the first
    * ether-related function called */
-  if (!(g_resolv_flags & RESOLV_MAC))
+  if (!(gbl_resolv_flags & RESOLV_MAC))
     return NULL;
 
   if (!eth_resolution_initialized) {
     initialize_ethers();
-    eth_resolution_initialized = 1;
+    eth_resolution_initialized = TRUE;
   }
 
-  hash_idx = HASH_ETH_ADDRESS(addr);
-
-  tp = eth_table[hash_idx];
+  /* eth_name_lookup will create a (resolved) hash entry if it doesn't exist */
+  tp = eth_name_lookup(addr, TRUE);
+  g_assert(tp != NULL);
 
-  if( tp == NULL ) {
-      /* Hash key not found in table.
-       * Force a lookup (and a hash entry) for addr, then call
-       * myself. I plan on not getting into an infinite loop because
-       * eth_name_lookup() is guaranteed to make a hashtable entry,
-       * so when I call myself again, I can never get into this
-       * block of code again. Knock on wood...
-       */
-      (void) eth_name_lookup(addr, TRUE);
-      return get_ether_name_if_known(addr); /* a well-placed goto would suffice */
+  if (tp->status == HASHETHER_STATUS_RESOLVED_NAME) {
+    /* Name is from an ethers file (or is a "well-known" MAC address name from the manuf file) */
+    return tp->resolved_name;
   }
   else {
-    while(1) {
-      if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
-          if (!tp->is_dummy_entry) {
-        /* A name was found, and its origin is an ethers file */
-        return tp->name;
-          }
-          else {
-        /* A name was found, but it was created, not found in a file */
-        return NULL;
-          }
-      }
-      if (tp->next == NULL) {
-      /* Read my reason above for why I'm sure I can't get into an infinite loop */
-      (void) eth_name_lookup(addr, TRUE);
-      return get_ether_name_if_known(addr); /* a well-placed goto would suffice */
-      }
-      tp = tp->next;
-    }
+    /* Name was created */
+    return NULL;
   }
-  g_assert_not_reached();
-  return NULL;
 }
 
-
-extern guint8 *get_ether_addr(const gchar *name)
+extern guint8 *
+get_ether_addr(const gchar *name)
 {
 
-  /* force resolution (do not check g_resolv_flags) */
+  /* force resolution (do not check gbl_resolv_flags) */
 
   if (!eth_resolution_initialized) {
     initialize_ethers();
-    eth_resolution_initialized = 1;
+    eth_resolution_initialized = TRUE;
   }
 
   return eth_addr_lookup(name);
 
 } /* get_ether_addr */
 
-extern void add_ether_byip(guint ip, const guint8 *eth)
+extern void
+add_ether_byip(const guint ip, const guint8 *eth)
 {
 
   gchar *host;
   gboolean found;
 
   /* first check that IP address can be resolved */
-  if (!(g_resolv_flags & RESOLV_NETWORK))
+  if (!(gbl_resolv_flags & RESOLV_NETWORK))
     return;
 
   if ((host = host_name_lookup(ip, &found)) == NULL)
@@ -2864,11 +2975,12 @@ extern void add_ether_byip(guint ip, const guint8 *eth)
 
 } /* add_ether_byip */
 
-extern const gchar *get_ipxnet_name(const guint32 addr)
+extern const gchar *
+get_ipxnet_name(const guint32 addr)
 {
 
-  if (!(g_resolv_flags & RESOLV_NETWORK)) {
-      return ipxnet_to_str_punct(addr, '\0');
+  if (!(gbl_resolv_flags & RESOLV_NETWORK)) {
+    return ipxnet_to_str_punct(addr, '\0');
   }
 
   if (!ipxnet_resolution_initialized) {
@@ -2880,12 +2992,13 @@ extern const gchar *get_ipxnet_name(const guint32 addr)
 
 } /* get_ipxnet_name */
 
-extern guint32 get_ipxnet_addr(const gchar *name, gboolean *known)
+extern guint32
+get_ipxnet_addr(const gchar *name, gboolean *known)
 {
   guint32 addr;
   gboolean success;
 
-  /* force resolution (do not check g_resolv_flags) */
+  /* force resolution (do not check gbl_resolv_flags) */
 
   if (!ipxnet_resolution_initialized) {
     initialize_ipxnets();
@@ -2899,86 +3012,203 @@ extern guint32 get_ipxnet_addr(const gchar *name, gboolean *known)
 
 } /* get_ipxnet_addr */
 
-extern const gchar *get_manuf_name(const guint8 *addr)
+extern const gchar *
+get_manuf_name(const guint8 *addr)
 {
   gchar *cur;
-  hashmanuf_t  *manufp;
+  hashmanuf_t  *mtp;
 
-  if ((g_resolv_flags & RESOLV_MAC) && !eth_resolution_initialized) {
+  if ((gbl_resolv_flags & RESOLV_MAC) && !eth_resolution_initialized) {
     initialize_ethers();
-    eth_resolution_initialized = 1;
+    eth_resolution_initialized = TRUE;
   }
 
-  if (!(g_resolv_flags & RESOLV_MAC) || ((manufp = manuf_name_lookup(addr)) == NULL)) {
-    cur=ep_alloc(MAXMANUFLEN);
-    g_snprintf(cur, MAXMANUFLEN, "%02x:%02x:%02x", addr[0], addr[1], addr[2]);
+  if (!(gbl_resolv_flags & RESOLV_MAC) || ((mtp = manuf_name_lookup(addr)) == NULL)) {
+    cur=ep_strdup_printf("%02x:%02x:%02x", addr[0], addr[1], addr[2]);
     return cur;
   }
 
-  return manufp->name;
+  return mtp->name;
 
 } /* get_manuf_name */
 
+extern const gchar *
+tvb_get_manuf_name(tvbuff_t *tvb, gint offset)
+{
+       return get_manuf_name(tvb_get_ptr(tvb, offset, 3));
+}
 
-const gchar *get_manuf_name_if_known(const guint8 *addr)
+const gchar *
+get_manuf_name_if_known(const guint8 *addr)
 {
-  hashmanuf_t  *manufp;
+  hashmanuf_t  *mtp;
 
   if (!eth_resolution_initialized) {
     initialize_ethers();
-    eth_resolution_initialized = 1;
+    eth_resolution_initialized = TRUE;
   }
 
-  if ((manufp = manuf_name_lookup(addr)) == NULL) {
+  if ((mtp = manuf_name_lookup(addr)) == NULL) {
     return NULL;
   }
 
-  return manufp->name;
+  return mtp->name;
 
 } /* get_manuf_name_if_known */
 
+extern const gchar *
+tvb_get_manuf_name_if_known(tvbuff_t *tvb, gint offset)
+{
+       return get_manuf_name_if_known(tvb_get_ptr(tvb, offset, 3));
+}
+
+extern const gchar *
+get_eui64_name(const guint64 addr_eui64)
+{
+  gchar *cur;
+  hashmanuf_t  *mtp;
+  guint8 *addr = ep_alloc(8);
+
+  /* Copy and convert the address to network byte order. */
+  *(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64));
+
+  if ((gbl_resolv_flags & RESOLV_MAC) && !eth_resolution_initialized) {
+    initialize_ethers();
+    eth_resolution_initialized = TRUE;
+  }
+
+  if (!(gbl_resolv_flags & RESOLV_MAC) || ((mtp = manuf_name_lookup(addr)) == NULL)) {
+    cur=ep_strdup_printf("%02x:%02x:%02x%02x:%02x:%02x%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
+    return cur;
+  }
+  cur=ep_strdup_printf("%s_%02x:%02x:%02x:%02x:%02x", mtp->name, addr[3], addr[4], addr[5], addr[6], addr[7]);
+  return cur;
+
+} /* get_eui64_name */
+
+
+const gchar *
+get_eui64_name_if_known(const guint64 addr_eui64)
+{
+  gchar *cur;
+  hashmanuf_t  *mtp;
+  guint8 *addr = ep_alloc(8);
+
+  /* Copy and convert the address to network byte order. */
+  *(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64));
+
+  if (!eth_resolution_initialized) {
+    initialize_ethers();
+    eth_resolution_initialized = TRUE;
+  }
+
+  if ((mtp = manuf_name_lookup(addr)) == NULL) {
+    return NULL;
+  }
+
+  cur=ep_strdup_printf("%s_%02x:%02x:%02x:%02x:%02x", mtp->name, addr[3], addr[4], addr[5], addr[6], addr[7]);
+  return cur;
+
+} /* get_eui64_name_if_known */
+
+#ifdef HAVE_C_ARES
+#define GHI_TIMEOUT (250 * 1000)
+static void
+#if ( ( ARES_VERSION_MAJOR < 1 )                                     \
+ || ( 1 == ARES_VERSION_MAJOR && ARES_VERSION_MINOR < 5 ) )
+c_ares_ghi_cb(void *arg, int status, struct hostent *hp) {
+#else
+c_ares_ghi_cb(void *arg, int status, int timeouts _U_, struct hostent *hp) {
+#endif
+  /*
+   * XXX - If we wanted to be really fancy we could cache results here and
+   * look them up in get_host_ipaddr* below.
+   */
+  async_hostent_t *ahp = arg;
+  if (status == ARES_SUCCESS && hp && ahp && hp->h_length == ahp->addr_size) {
+    memcpy(ahp->addrp, hp->h_addr, hp->h_length);
+    ahp->copied = hp->h_length;
+  }
+}
+#endif /* HAVE_C_ARES */
 
 /* Translate a string, assumed either to be a dotted-quad IP address or
  * a host name, to a numeric IP address.  Return TRUE if we succeed and
  * set "*addrp" to that numeric IP address; return FALSE if we fail.
  * Used more in the dfilter parser rather than in packet dissectors */
-gboolean get_host_ipaddr(const char *host, guint32 *addrp)
+gboolean
+get_host_ipaddr(const char *host, guint32 *addrp)
 {
-    struct in_addr      ipaddr;
-    struct hostent      *hp;
+  struct in_addr      ipaddr;
+#ifdef HAVE_C_ARES
+  struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
+  int nfds;
+  fd_set rfds, wfds;
+  async_hostent_t ahe;
+#else /* HAVE_C_ARES */
+  struct hostent      *hp;
+#endif /* HAVE_C_ARES */
 
-    /*
-     * don't change it to inet_pton(AF_INET), they are not 100% compatible.
-     * inet_pton(AF_INET) does not support hexadecimal notation nor
-     * less-than-4 octet notation.
-     */
-    if (!inet_aton(host, &ipaddr)) {
-        /* It's not a valid dotted-quad IP address; is it a valid
-         * host name? */
-        hp = gethostbyname(host);
-        if (hp == NULL) {
-            /* No. */
-            return FALSE;
-            /* Apparently, some versions of gethostbyaddr can
-             * return IPv6 addresses. */
-        } else if (hp->h_length <= (int) sizeof (struct in_addr)) {
-            memcpy(&ipaddr, hp->h_addr, hp->h_length);
-        } else {
-            return FALSE;
-        }
+  /*
+   * don't change it to inet_pton(AF_INET), they are not 100% compatible.
+   * inet_pton(AF_INET) does not support hexadecimal notation nor
+   * less-than-4 octet notation.
+   */
+  if (!inet_aton(host, &ipaddr)) {
+    if (! (gbl_resolv_flags & RESOLV_NETWORK)) {
+      return FALSE;
+    }
+    /* It's not a valid dotted-quad IP address; is it a valid
+     * host name? */
+#ifdef HAVE_C_ARES
+    if (! (gbl_resolv_flags & RESOLV_CONCURRENT) ||
+        prefs.name_resolve_concurrency < 1 ||
+        ! async_dns_initialized) {
+      return FALSE;
+    }
+    ahe.addr_size = (int) sizeof (struct in_addr);
+    ahe.copied = 0;
+    ahe.addrp = addrp;
+    ares_gethostbyname(ghbn_chan, host, AF_INET, c_ares_ghi_cb, &ahe);
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    nfds = ares_fds(ghbn_chan, &rfds, &wfds);
+    if (nfds > 0) {
+      tvp = ares_timeout(ghbn_chan, &tv, &tv);
+      select(nfds, &rfds, &wfds, NULL, tvp);
+      ares_process(ghbn_chan, &rfds, &wfds);
+    }
+    ares_cancel(ghbn_chan);
+    if (ahe.addr_size == ahe.copied) {
+      return TRUE;
+    }
+    return FALSE;
+#else /* ! HAVE_C_ARES */
+    hp = gethostbyname(host);
+    if (hp == NULL) {
+      /* No. */
+      return FALSE;
+      /* Apparently, some versions of gethostbyaddr can
+       * return IPv6 addresses. */
+    } else if (hp->h_length <= (int) sizeof (struct in_addr)) {
+      memcpy(&ipaddr, hp->h_addr, hp->h_length);
     } else {
-        /* Does the string really contain dotted-quad IP?
-         * Check against inet_atons that accept strings such as
-         * "130.230" as valid addresses and try to convert them
-         * to some form of a classful (host.net) notation.
-         */
-        unsigned int a0, a1, a2, a3;
-        if (sscanf(host, "%u.%u.%u.%u", &a0, &a1, &a2, &a3) != 4)
-            return FALSE;
+      return FALSE;
     }
+#endif /* HAVE_C_ARES */
+  } else {
+    /* Does the string really contain dotted-quad IP?
+     * Check against inet_atons that accept strings such as
+     * "130.230" as valid addresses and try to convert them
+     * to some form of a classful (host.net) notation.
+     */
+    unsigned int a0, a1, a2, a3;
+    if (sscanf(host, "%u.%u.%u.%u", &a0, &a1, &a2, &a3) != 4)
+      return FALSE;
+  }
 
-    *addrp = g_ntohl(ipaddr.s_addr);
-    return TRUE;
+  *addrp = ipaddr.s_addr;
+  return TRUE;
 }
 
 /*
@@ -2986,25 +3216,57 @@ gboolean get_host_ipaddr(const char *host, guint32 *addrp)
  * Return TRUE if we succeed and set "*addrp" to that numeric IP address;
  * return FALSE if we fail.
  */
-gboolean get_host_ipaddr6(const char *host, struct e_in6_addr *addrp)
+gboolean
+get_host_ipaddr6(const char *host, struct e_in6_addr *addrp)
 {
-    struct hostent *hp;
+#ifdef HAVE_C_ARES
+  struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
+  int nfds;
+  fd_set rfds, wfds;
+  async_hostent_t ahe;
+#elif defined(HAVE_GETHOSTBYNAME2)
+  struct hostent *hp;
+#endif /* HAVE_C_ARES */
 
-    if (inet_pton(AF_INET6, host, addrp) == 1)
-        return TRUE;
+  if (inet_pton(AF_INET6, host, addrp) == 1)
+    return TRUE;
 
-    /* try FQDN */
-#ifdef HAVE_GETHOSTBYNAME2
-    hp = gethostbyname2(host, AF_INET6);
-#else
-    hp = NULL;
-#endif
-    if (hp != NULL && hp->h_length == sizeof(struct e_in6_addr)) {
-        memcpy(addrp, hp->h_addr, hp->h_length);
-        return TRUE;
-    }
+  if (! (gbl_resolv_flags & RESOLV_NETWORK)) {
+    return FALSE;
+  }
 
+  /* try FQDN */
+#ifdef HAVE_C_ARES
+  if (! (gbl_resolv_flags & RESOLV_CONCURRENT) ||
+      prefs.name_resolve_concurrency < 1 ||
+      ! async_dns_initialized) {
     return FALSE;
+  }
+  ahe.addr_size = (int) sizeof (struct e_in6_addr);
+  ahe.copied = 0;
+  ahe.addrp = addrp;
+  ares_gethostbyname(ghbn_chan, host, AF_INET6, c_ares_ghi_cb, &ahe);
+  FD_ZERO(&rfds);
+  FD_ZERO(&wfds);
+  nfds = ares_fds(ghbn_chan, &rfds, &wfds);
+  if (nfds > 0) {
+    tvp = ares_timeout(ghbn_chan, &tv, &tv);
+    select(nfds, &rfds, &wfds, NULL, tvp);
+    ares_process(ghbn_chan, &rfds, &wfds);
+  }
+  ares_cancel(ghbn_chan);
+  if (ahe.addr_size == ahe.copied) {
+    return TRUE;
+  }
+#elif defined(HAVE_GETHOSTBYNAME2)
+  hp = gethostbyname2(host, AF_INET6);
+  if (hp != NULL && hp->h_length == sizeof(struct e_in6_addr)) {
+    memcpy(addrp, hp->h_addr, hp->h_length);
+    return TRUE;
+  }
+#endif
+
+  return FALSE;
 }
 
 /*
@@ -3019,9 +3281,9 @@ _U_
 )
 {
 #ifdef HAVE_GETHOSTBYNAME2
-    struct hostent *h;
-    return (h = gethostbyname2(host, AF_INET6)) && h->h_addrtype == AF_INET6 ? "ip6" : "ip";
+  struct hostent *h;
+  return (h = gethostbyname2(host, AF_INET6)) && h->h_addrtype == AF_INET6 ? "ip6" : "ip";
 #else
-    return "ip";
+  return "ip";
 #endif
 }