* a separate thread, making it, in effect, asynchronous.
*/
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
# include "wsutil/inet_v6defs.h"
#endif
-#if defined(_WIN32) && defined(INET6)
+#ifdef _WIN32
# include <ws2tcpip.h>
#endif
#ifdef HAVE_C_ARES
-# if defined(_WIN32) && !defined(INET6)
+# ifdef _WIN32
# define socklen_t unsigned int
# endif
# include <ares.h>
#include "packet.h"
#include "addr_and_mask.h"
-#include "ipv6-utils.h"
+#include "ipv6.h"
#include "addr_resolv.h"
#include "wsutil/filesystem.h"
} subnet_length_entry_t;
-#if 0
-typedef struct serv_port {
- gchar *udp_name;
- gchar *tcp_name;
- gchar *sctp_name;
- gchar *dccp_name;
-} serv_port_t;
-#endif
/* hash table used for IPX network lookup */
/* XXX - check goodness of hash function */
/*
* Flag controlling what names to resolve.
*/
-e_addr_resolve gbl_resolv_flags = {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE};
+e_addr_resolve gbl_resolv_flags = {
+ TRUE, /* mac_name */
+ FALSE, /* network_name */
+ FALSE, /* transport_name */
+ TRUE, /* concurrent_dns */
+ TRUE, /* dns_pkt_addr_resolution */
+ TRUE, /* use_external_net_name_resolver */
+ FALSE /* load_hosts_file_from_profile_only */
+};
#if defined(HAVE_C_ARES) || defined(HAVE_GNU_ADNS)
static guint name_resolve_concurrency = 500;
#endif
return bp;
}
-
-static gchar
-*serv_name_lookup(const guint port, const port_type proto)
+static const gchar *
+_serv_name_lookup(port_type proto, guint port, serv_port_t **value_ret)
{
serv_port_t *serv_port_table;
- gchar *name;
serv_port_table = (serv_port_t *)g_hash_table_lookup(serv_port_hashtable, &port);
- if (serv_port_table) {
- /* Set which table we should look up port in */
- switch(proto) {
- case PT_UDP:
- if (serv_port_table->udp_name) {
- return serv_port_table->udp_name;
- }
- break;
- case PT_TCP:
- if (serv_port_table->tcp_name) {
- return serv_port_table->tcp_name;
- }
- break;
- case PT_SCTP:
- if (serv_port_table->sctp_name) {
- return serv_port_table->sctp_name;
- }
- break;
- case PT_DCCP:
- if (serv_port_table->dccp_name) {
- return serv_port_table->dccp_name;
- }
- break;
- default:
- /* not yet implemented */
- return NULL;
- /*NOTREACHED*/
- } /* proto */
- }
-
- /* getservbyport() was used here but it was to expensive, if the functionality is desired
- * it would be better to pre parse etc/services or C:\Windows\System32\drivers\etc at
- * startup
- */
- name = (gchar*)g_malloc(16);
- guint32_to_str_buf(port, name, 16);
+ if (value_ret != NULL)
+ *value_ret = serv_port_table;
- if (serv_port_table == NULL) {
- int *key;
+ if (serv_port_table == NULL)
+ return NULL;
- key = (int *)g_new(int, 1);
- *key = port;
- serv_port_table = g_new0(serv_port_t,1);
- g_hash_table_insert(serv_port_hashtable, key, serv_port_table);
- }
- switch(proto) {
+ switch (proto) {
case PT_UDP:
- serv_port_table->udp_name = name;
- break;
+ return serv_port_table->udp_name;
case PT_TCP:
- serv_port_table->tcp_name = name;
- break;
+ return serv_port_table->tcp_name;
case PT_SCTP:
- serv_port_table->sctp_name = name;
- break;
+ return serv_port_table->sctp_name;
case PT_DCCP:
- serv_port_table->dccp_name = name;
- break;
+ return serv_port_table->dccp_name;
default:
- return NULL;
- /*NOTREACHED*/
+ break;
}
- return name;
+ return NULL;
+}
+
+const gchar *
+try_serv_name_lookup(port_type proto, guint port)
+{
+ return _serv_name_lookup(proto, port, NULL);
+}
+
+const gchar *
+serv_name_lookup(port_type proto, guint port)
+{
+ serv_port_t *serv_port_table = NULL;
+ const char *name;
+ guint *key;
-} /* serv_name_lookup */
+ name = _serv_name_lookup(proto, port, &serv_port_table);
+ if (name != NULL)
+ return name;
+
+ if (serv_port_table == NULL) {
+ key = (guint *)g_new(guint, 1);
+ *key = port;
+ serv_port_table = g_new0(serv_port_t, 1);
+ g_hash_table_insert(serv_port_hashtable, key, serv_port_table);
+ }
+ if (serv_port_table->numeric == NULL) {
+ serv_port_table->numeric = g_strdup_printf("%u", port);
+ }
+
+ return serv_port_table->numeric;
+}
static void
destroy_serv_port(gpointer data)
g_free(table->tcp_name);
g_free(table->sctp_name);
g_free(table->dccp_name);
+ g_free(table->numeric);
g_free(table);
}
static void
initialize_services(void)
{
-#ifdef _WIN32
- char *hostspath;
- char *sysroot;
- static char rootpath_nt[] = "\\system32\\drivers\\etc\\services";
-#endif /* _WIN32 */
-
- /* the hash table won't ignore duplicates, so use the personal path first */
g_assert(serv_port_hashtable == NULL);
serv_port_hashtable = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, destroy_serv_port);
-/* Read the system services file first */
-#ifdef _WIN32
-
- sysroot = getenv_utf8("WINDIR");
- if (sysroot != NULL) {
- /*
- * The file should be under WINDIR.
- * If this is Windows NT (NT 4.0,2K,XP,Server2K3), it's in
- * %WINDIR%\system32\drivers\etc\services.
- */
- hostspath = g_strconcat(sysroot, rootpath_nt, NULL);
- parse_services_file(hostspath);
- g_free(hostspath);
- }
-#else
- parse_services_file("/etc/services");
-
-#endif /* _WIN32 */
-
- /* set personal services path */
- if (g_pservices_path == NULL)
- g_pservices_path = get_persconffile_path(ENAME_SERVICES, FALSE);
-
- parse_services_file(g_pservices_path);
-
/* Compute the pathname of the services file. */
if (g_services_path == NULL) {
g_services_path = get_datafile_path(ENAME_SERVICES);
}
-
parse_services_file(g_services_path);
-} /* initialize_services */
+ /* Compute the pathname of the personal services file */
+ if (g_pservices_path == NULL) {
+ g_pservices_path = get_persconffile_path(ENAME_SERVICES, FALSE);
+ }
+ parse_services_file(g_pservices_path);
+}
static void
service_name_lookup_cleanup(void)
{
subnet_entry_t subnet_entry;
- if ((tp->flags & DUMMY_ADDRESS_ENTRY) == DUMMY_ADDRESS_ENTRY)
+ if (tp->flags & DUMMY_ADDRESS_ENTRY)
return; /* already done */
- tp->flags = tp->flags | DUMMY_ADDRESS_ENTRY; /* Overwrite if we get async DNS reply */
+ tp->flags |= DUMMY_ADDRESS_ENTRY; /* Overwrite if we get async DNS reply */
/* Do we have a subnet for this address? */
subnet_entry = subnet_lookup(addr);
}
}
+
+/* Fill in an IP6 structure with the string form of the address.
+ */
+static void
+fill_dummy_ip6(hashipv6_t* volatile tp)
+{
+ if (tp->flags & DUMMY_ADDRESS_ENTRY)
+ return; /* already done */
+
+ tp->flags |= DUMMY_ADDRESS_ENTRY; /* Overwrite if we get async DNS reply */
+ g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
+}
+
#ifdef HAVE_C_ARES
static void
}
static hashipv4_t *
-host_lookup(const guint addr, gboolean *found)
+host_lookup(const guint addr)
{
hashipv4_t * volatile tp;
- *found = TRUE;
-
tp = (hashipv4_t *)g_hash_table_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
if (tp == NULL) {
+ /*
+ * We don't already have an entry for this host name; create one,
+ * and then try to resolve it.
+ */
tp = new_ipv4(addr);
g_hash_table_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
} else {
- if ((tp->flags & DUMMY_AND_RESOLVE_FLGS) == DUMMY_ADDRESS_ENTRY) {
+ if ((tp->flags & DUMMY_AND_RESOLVE_FLGS) == DUMMY_ADDRESS_ENTRY) {
+ /*
+ * This hasn't been resolved yet, and we haven't tried to
+ * resolve it already, so try.
+ */
goto try_resolv;
}
- if ((tp->flags & DUMMY_ADDRESS_ENTRY) == DUMMY_ADDRESS_ENTRY) {
- *found = FALSE;
- }
return tp;
}
try_resolv:
if (gbl_resolv_flags.network_name && gbl_resolv_flags.use_external_net_name_resolver) {
- tp->flags = tp->flags|TRIED_RESOLVE_ADDRESS;
+ tp->flags |= TRIED_RESOLVE_ADDRESS;
#ifdef ASYNC_DNS
if (gbl_resolv_flags.concurrent_dns &&
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;
}
/* unknown host or DNS timeout */
}
- *found = FALSE;
fill_dummy_ip4(addr, tp);
return tp;
new_ipv6(const struct e_in6_addr *addr)
{
hashipv6_t *tp = g_new(hashipv6_t,1);
- tp->addr = *addr;
+ memcpy(tp->addr, addr->bytes, sizeof tp->addr);
tp->flags = 0;
tp->name[0] = '\0';
ip6_to_str_buf(addr, tp->ip6);
/* ------------------------------------ */
static hashipv6_t *
-host_lookup6(const struct e_in6_addr *addr, gboolean *found)
+host_lookup6(const struct e_in6_addr *addr)
{
hashipv6_t * volatile tp;
-#ifdef INET6
#ifdef HAVE_C_ARES
async_dns_queue_msg_t *caqm;
#elif defined(HAVE_GETADDRINFO)
#elif defined(HAVE_GETHOSTBYNAME)
struct hostent *hostp;
#endif
-#endif /* INET6 */
-
- *found = TRUE;
tp = (hashipv6_t *)g_hash_table_lookup(ipv6_hash_table, addr);
if (tp == NULL) {
+ /*
+ * We don't already have an entry for this host name; create one,
+ * and then try to resolve it.
+ */
struct e_in6_addr *addr_key;
addr_key = g_new(struct e_in6_addr,1);
memcpy(addr_key, addr, 16);
g_hash_table_insert(ipv6_hash_table, addr_key, tp);
} else {
- if ((tp->flags & DUMMY_AND_RESOLVE_FLGS) == DUMMY_ADDRESS_ENTRY) {
+ if ((tp->flags & DUMMY_AND_RESOLVE_FLGS) == DUMMY_ADDRESS_ENTRY) {
+ /*
+ * This hasn't been resolved yet, and we haven't tried to
+ * resolve it already, so try.
+ */
goto try_resolv;
}
- if ((tp->flags & DUMMY_ADDRESS_ENTRY) == DUMMY_ADDRESS_ENTRY) {
- *found = FALSE;
- }
return tp;
}
try_resolv:
if (gbl_resolv_flags.network_name &&
gbl_resolv_flags.use_external_net_name_resolver) {
- tp->flags = tp->flags|TRIED_RESOLVE_ADDRESS;
-#ifdef INET6
+ tp->flags |= TRIED_RESOLVE_ADDRESS;
#ifdef HAVE_C_ARES
if ((gbl_resolv_flags.concurrent_dns) &&
name_resolve_concurrency > 0 &&
caqm->family = AF_INET6;
memcpy(&caqm->addr.ip6, addr, sizeof(caqm->addr.ip6));
async_dns_queue_head = g_list_append(async_dns_queue_head, (gpointer) caqm);
-
- /* XXX found is set to TRUE, which seems a bit odd, but I'm not
- * going to risk changing the semantics.
- */
- if ((tp->flags & DUMMY_ADDRESS_ENTRY) == 0) {
- g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
- ip6_to_str_buf(addr, tp->name);
- tp->flags = tp->flags | DUMMY_ADDRESS_ENTRY;
- }
+ fill_dummy_ip6(tp);
return tp;
}
#elif defined(HAVE_GETADDRINFO)
return tp;
}
#endif
-#endif /* INET6 */
}
/* unknown host or DNS timeout */
- if ((tp->flags & DUMMY_ADDRESS_ENTRY) == 0) {
- tp->flags = tp->flags | DUMMY_ADDRESS_ENTRY;
- g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
- }
- *found = FALSE;
+ fill_dummy_ip6(tp);
return tp;
} /* host_lookup6 */
-static const gchar *
-solve_address_to_name(const address *addr)
-{
- switch (addr->type) {
-
- case AT_ETHER:
- return get_ether_name((const guint8 *)addr->data);
-
- case AT_IPv4: {
- guint32 ip4_addr;
- memcpy(&ip4_addr, addr->data, sizeof ip4_addr);
- return get_hostname(ip4_addr);
- }
-
- case AT_IPv6: {
- struct e_in6_addr ip6_addr;
- memcpy(&ip6_addr.bytes, addr->data, sizeof ip6_addr.bytes);
- return get_hostname6(&ip6_addr);
- }
-
- case AT_STRINGZ:
- return (const gchar *)addr->data;
-
- default:
- return NULL;
- }
-}
-
/*
* Ethernet / manufacturer resolution
*
}
/* Mask out the broadcast/multicast flag but not the locally
- * administered flag as localy administered means: not assigend
+ * administered flag as locally administered means: not assigned
* by the IEEE but the local administrator instead.
* 0x01 multicast / broadcast bit
* 0x02 locally administered bit */
{
ether_t *eth;
char *manuf_path;
- guint mask;
+ guint mask = 0;
/* hash table initialization */
wka_hashtable = g_hash_table_new_full(eth_addr_hash, eth_addr_cmp, g_free, g_free);
}
/* No match whatsoever. */
- SET_ADDRESS(ðer_addr, AT_ETHER, 6, addr);
+ set_address(ðer_addr, AT_ETHER, 6, addr);
address_to_str_buf(ðer_addr, tp->resolved_name, MAXNAMELEN);
tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
return tp;
/*
* Add the aliases, too, if there are any.
* XXX - except we only store the last one added. The name
- * resolver returns the first name in the hosts file, we should
- * too.
+ * resolver returns the first name in the hosts file, we should
+ * too.
*/
while ((cp = strtok(NULL, " \t")) != NULL) {
if (is_ipv6) {
}
mask_length = atoi(cp2);
- if (0 >= mask_length || mask_length > 31) {
+ if (0 >= mask_length || mask_length > 32) {
continue; /* invalid mask length */
}
}
if (NULL != (tp = entry->subnet_addresses[hash_idx])) {
- if (tp->addr == subnet_addr) {
- return; /* XXX provide warning that an address was repeated? */
- } else {
- sub_net_hashipv4_t * new_tp = g_new(sub_net_hashipv4_t, 1);
- tp->next = new_tp;
- tp = new_tp;
+ sub_net_hashipv4_t * new_tp;
+
+ while (tp->next) {
+ if (tp->addr == subnet_addr) {
+ return; /* XXX provide warning that an address was repeated? */
+ } else {
+ tp = tp->next;
+ }
}
+
+ new_tp = g_new(sub_net_hashipv4_t, 1);
+ tp->next = new_tp;
+ tp = new_tp;
} else {
tp = entry->subnet_addresses[hash_idx] = g_new(sub_net_hashipv4_t, 1);
}
tp->next = NULL;
tp->addr = subnet_addr;
/* Clear DUMMY_ADDRESS_ENTRY */
- tp->flags = tp->flags & 0xfe; /*Never used again...*/
+ tp->flags &= ~DUMMY_ADDRESS_ENTRY; /*Never used again...*/
g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
have_subnet_entry = TRUE;
}
" capture file name resolution blocks and DNS packets in the capture.",
&gbl_resolv_flags.network_name);
+ prefs_register_bool_preference(nameres, "dns_pkt_addr_resolution",
+ "Use captured DNS packet data for address resolution",
+ "Whether address/name pairs found in captured DNS packets should be used by Wireshark for name resolution.",
+ &gbl_resolv_flags.dns_pkt_addr_resolution);
+
prefs_register_bool_preference(nameres, "use_external_name_resolver",
"Use an external network name resolver",
"Use your system's configured name resolver"
}
+void
+disable_name_resolution(void) {
+ gbl_resolv_flags.mac_name = FALSE;
+ gbl_resolv_flags.network_name = FALSE;
+ gbl_resolv_flags.transport_name = FALSE;
+ gbl_resolv_flags.concurrent_dns = FALSE;
+ gbl_resolv_flags.dns_pkt_addr_resolution = FALSE;
+ gbl_resolv_flags.use_external_net_name_resolver = FALSE;
+}
+
#ifdef HAVE_C_ARES
gboolean
host_name_lookup_process(void) {
const gchar *
get_hostname(const guint addr)
{
- gboolean found;
-
/* XXX why do we call this if we're not resolving? To create hash entries?
* Why?
*/
- hashipv4_t *tp = host_lookup(addr, &found);
+ hashipv4_t *tp = host_lookup(addr);
if (!gbl_resolv_flags.network_name)
return tp->ip;
- tp->flags = tp->flags | RESOLVED_ADDRESS_USED;
+ tp->flags |= RESOLVED_ADDRESS_USED;
return tp->name;
}
const gchar *
get_hostname6(const struct e_in6_addr *addr)
{
- gboolean found;
-
/* XXX why do we call this if we're not resolving? To create hash entries?
* Why?
*/
- hashipv6_t *tp = host_lookup6(addr, &found);
+ hashipv6_t *tp = host_lookup6(addr);
if (!gbl_resolv_flags.network_name)
return tp->ip6;
- tp->flags = tp->flags | RESOLVED_ADDRESS_USED;
+ tp->flags |= RESOLVED_ADDRESS_USED;
return tp->name;
}
if (!name || name[0] == '\0')
return;
-
tp = (hashipv4_t *)g_hash_table_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
if (!tp) {
tp = new_ipv4(addr);
g_strlcpy(tp->name, name, MAXNAMELEN);
new_resolved_objects = TRUE;
}
- tp->flags = tp->flags | TRIED_RESOLVE_ADDRESS;
-
+ tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
} /* add_ipv4_name */
/* -------------------------- */
g_strlcpy(tp->name, name, MAXNAMELEN);
new_resolved_objects = TRUE;
}
- tp->flags = tp->flags | TRIED_RESOLVE_ADDRESS;
-
+ tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
} /* add_ipv6_name */
static void
return wmem_utoa(allocator, port);
}
- return wmem_strdup(allocator, serv_name_lookup(port, PT_UDP));
+ return wmem_strdup(allocator, serv_name_lookup(PT_UDP, port));
} /* udp_port_to_display */
return wmem_utoa(allocator, port);
}
- return wmem_strdup(allocator, serv_name_lookup(port, PT_DCCP));
+ return wmem_strdup(allocator, serv_name_lookup(PT_DCCP, port));
} /* dccp_port_to_display */
return wmem_utoa(allocator, port);
}
- return wmem_strdup(allocator, serv_name_lookup(port, PT_TCP));
+ return wmem_strdup(allocator, serv_name_lookup(PT_TCP, port));
} /* tcp_port_to_display */
return wmem_utoa(allocator, port);
}
- return wmem_strdup(allocator, serv_name_lookup(port, PT_SCTP));
+ return wmem_strdup(allocator, serv_name_lookup(PT_SCTP, port));
} /* sctp_port_to_display */
-const gchar *
-address_to_display(wmem_allocator_t *allocator, const address *addr)
+gchar *
+port_with_resolution_to_str(wmem_allocator_t *scope, port_type proto, guint port)
{
- gchar *str = NULL;
- const gchar *result = solve_address_to_name(addr);
+ const gchar *port_str;
- if (result != NULL) {
- str = wmem_strdup(allocator, result);
- }
- else if (addr->type == AT_NONE) {
- str = wmem_strdup(allocator, "NONE");
+ if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
+ /* No name resolution support, just return port string */
+ return wmem_strdup_printf(scope, "%u", port);
}
- else {
- str = (gchar *) wmem_alloc(allocator, MAX_ADDR_STR_LEN);
- address_to_str_buf(addr, str, MAX_ADDR_STR_LEN);
- }
-
- return str;
+ port_str = serv_name_lookup(proto, port);
+ g_assert(port_str);
+ return wmem_strdup_printf(scope, "%s (%u)", port_str, port);
}
-const gchar *
-get_addr_name(const address *addr)
+int
+port_with_resolution_to_str_buf(gchar *buf, gulong buf_size, port_type proto, guint port)
{
- return solve_address_to_name(addr);
+ const gchar *port_str;
+
+ if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
+ /* No name resolution support, just return port string */
+ return g_snprintf(buf, buf_size, "%u", port);
+ }
+ port_str = serv_name_lookup(proto, port);
+ g_assert(port_str);
+ return g_snprintf(buf, buf_size, "%s (%u)", port_str, port);
}
gchar *
/* Look for a (non-dummy) ether name in the hash, and return it if found.
* If it's not found, simply return NULL.
*/
-gchar *
+const gchar *
get_ether_name_if_known(const guint8 *addr)
{
hashether_t *tp;
void
add_ether_byip(const guint ip, const guint8 *eth)
{
- gboolean found;
hashipv4_t *tp;
/* first check that IP address can be resolved */
if (!gbl_resolv_flags.network_name)
return;
- tp = host_lookup(ip, &found);
- if (found) {
- /* ok, we can add this entry in the ethers hashtable */
+ tp = host_lookup(ip);
+
+ /*
+ * Was this IP address resolved to a host name?
+ */
+ if (tp->flags & NAME_RESOLVED) {
+ /*
+ * Yes, so add an entry in the ethers hashtable resolving
+ * the MAC address to that name.
+ */
add_eth_name(eth, tp->name);
}
return buf;
}
-const gchar *
+gchar *
get_ipxnet_name(wmem_allocator_t *allocator, const guint32 addr)
{
const gchar *
eui64_to_display(wmem_allocator_t *allocator, const guint64 addr_eui64)
{
- guint8 *addr = (guint8 *)wmem_alloc(allocator, 8);
+ guint8 *addr = (guint8 *)wmem_alloc(NULL, 8);
hashmanuf_t *manuf_value;
+ const gchar *ret;
/* Copy and convert the address to network byte order. */
*(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64));
manuf_value = manuf_name_lookup(addr);
if (!gbl_resolv_flags.mac_name || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
- return wmem_strdup_printf(allocator, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
+ ret = wmem_strdup_printf(allocator, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
+ } else {
+ ret = wmem_strdup_printf(allocator, "%s_%02x:%02x:%02x:%02x:%02x", manuf_value->resolved_name, addr[3], addr[4], addr[5], addr[6], addr[7]);
}
- return wmem_strdup_printf(allocator, "%s_%02x:%02x:%02x:%02x:%02x", manuf_value->resolved_name, addr[3], addr[4], addr[5], addr[6], addr[7]);
+ wmem_free(NULL, addr);
+ return ret;
} /* eui64_to_display */
#ifdef HAVE_C_ARES