2 * Routines for network object lookup
4 * Laurent Deniel <laurent.deniel@free.fr>
6 * Add option to resolv VLAN ID to describing name
7 * Uli Heilmeier, March 2016
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include <wsutil/strtoi.h>
38 * Win32 doesn't have SIGALRM (and it's the OS where name lookup calls
39 * are most likely to take a long time, given the way address-to-name
40 * lookups are done over NBNS).
42 * macOS does have SIGALRM, but if you longjmp() out of a name resolution
43 * call in a signal handler, you might crash, because the state of the
44 * resolution code that sends messages to lookupd might be inconsistent
45 * if you jump out of it in middle of a call.
47 * There's no guarantee that longjmp()ing out of name resolution calls
48 * will work on *any* platform; OpenBSD got rid of the alarm/longjmp
49 * code in tcpdump, to avoid those sorts of problems, and that was
50 * picked up by tcpdump.org tcpdump.
52 * So, for now, we do not use alarm() and SIGALRM to time out host name
53 * lookups. If we get a lot of complaints about lookups taking a long time,
54 * we can reconsider that decision. (Note that tcpdump originally added
55 * such a timeout mechanism that for the benefit of systems using NIS to
56 * look up host names; that might now be fixed in NIS implementations, for
57 * those sites still using NIS rather than DNS for that.... tcpdump no
58 * longer does that, for the same reasons that we don't.)
60 * If we're using an asynchronous DNS resolver, that shouldn't be an issue.
61 * If we're using a synchronous name lookup mechanism (which we'd do mainly
62 * to support resolving addresses and host names using more mechanisms than
63 * just DNS, such as NIS, NBNS, or Mr. Hosts File), we could do that in
64 * a separate thread, making it, in effect, asynchronous.
67 #ifdef HAVE_NETINET_IN_H
68 # include <netinet/in.h>
75 #ifdef HAVE_SYS_SOCKET_H
76 #include <sys/socket.h> /* needed to define AF_ values on UNIX */
80 #include <winsock2.h> /* needed to define AF_ values on Windows */
86 # define socklen_t unsigned int
89 # include <ares_version.h>
90 #endif /* HAVE_C_ARES */
95 #include "addr_and_mask.h"
97 #include "addr_resolv.h"
98 #include "wsutil/filesystem.h"
100 #include <wsutil/report_message.h>
101 #include <wsutil/file_util.h>
102 #include <wsutil/pint.h>
103 #include <wsutil/inet_addr.h>
105 #include <epan/strutil.h>
106 #include <epan/to_str-int.h>
107 #include <epan/prefs.h>
109 #define ENAME_HOSTS "hosts"
110 #define ENAME_SUBNETS "subnets"
111 #define ENAME_ETHERS "ethers"
112 #define ENAME_IPXNETS "ipxnets"
113 #define ENAME_MANUF "manuf"
114 #define ENAME_WKA "wka"
115 #define ENAME_SERVICES "services"
116 #define ENAME_VLANS "vlans"
117 #define ENAME_SS7PCS "ss7pcs"
118 #define ENAME_ENTERPRISES "enterprises.tsv"
120 #define HASHETHSIZE 2048
121 #define HASHHOSTSIZE 2048
122 #define HASHIPXNETSIZE 256
123 #define SUBNETLENGTHSIZE 32 /*1-32 inc.*/
125 /* hash table used for IPv4 lookup */
127 #define HASH_IPV4_ADDRESS(addr) (g_htonl(addr) & (HASHHOSTSIZE - 1))
130 typedef struct sub_net_hashipv4 {
132 /* XXX: No longer needed?*/
133 guint8 flags; /* B0 dummy_entry, B1 resolve, B2 If the address is used in the trace */
134 struct sub_net_hashipv4 *next;
135 gchar name[MAXNAMELEN];
136 } sub_net_hashipv4_t;
138 /* Array of entries of subnets of different lengths */
140 gsize mask_length; /*1-32*/
141 guint32 mask; /* e.g. 255.255.255.*/
142 sub_net_hashipv4_t** subnet_addresses; /* Hash table of subnet addresses */
143 } subnet_length_entry_t;
146 /* hash table used for IPX network lookup */
148 /* XXX - check goodness of hash function */
150 #define HASH_IPX_NET(net) ((net) & (HASHIPXNETSIZE - 1))
152 typedef struct hashipxnet {
154 struct hashipxnet *next;
155 gchar name[MAXNAMELEN];
158 typedef struct hashvlan {
160 /* struct hashvlan *next; */
161 gchar name[MAXVLANNAMELEN];
164 typedef struct ss7pc {
165 guint32 id; /* 1st byte NI, 3 following bytes: Point Code */
166 gchar pc_addr[MAXNAMELEN];
167 gchar name[MAXNAMELEN];
170 /* hash tables used for ethernet and manufacturer lookup */
171 #define HASHETHER_STATUS_UNRESOLVED 1
172 #define HASHETHER_STATUS_RESOLVED_DUMMY 2
173 #define HASHETHER_STATUS_RESOLVED_NAME 3
176 guint status; /* (See above) */
179 char resolved_name[MAXNAMELEN];
183 guint status; /* (See above) */
186 char resolved_name[MAXNAMELEN];
187 char resolved_longname[MAXNAMELEN];
190 /* internal ethernet type */
191 typedef struct _ether
194 char name[MAXNAMELEN];
195 char longname[MAXNAMELEN];
198 /* internal ipxnet type */
199 typedef struct _ipxnet
202 char name[MAXNAMELEN];
205 /* internal vlan type */
209 char name[MAXVLANNAMELEN];
212 static wmem_map_t *ipxnet_hash_table = NULL;
213 static wmem_map_t *ipv4_hash_table = NULL;
214 static wmem_map_t *ipv6_hash_table = NULL;
215 static wmem_map_t *vlan_hash_table = NULL;
216 static wmem_map_t *ss7pc_hash_table = NULL;
218 static wmem_list_t *manually_resolved_ipv4_list = NULL;
219 static wmem_list_t *manually_resolved_ipv6_list = NULL;
221 typedef struct _resolved_ipv4
224 char name[MAXNAMELEN];
227 typedef struct _resolved_ipv6
229 ws_in6_addr ip6_addr;
230 char name[MAXNAMELEN];
233 static addrinfo_lists_t addrinfo_lists = { NULL, NULL};
235 struct cb_serv_data {
240 static wmem_map_t *manuf_hashtable = NULL;
241 static wmem_map_t *wka_hashtable = NULL;
242 static wmem_map_t *eth_hashtable = NULL;
243 static wmem_map_t *serv_port_hashtable = NULL;
244 static GHashTable *enterprises_hashtable = NULL;
246 static subnet_length_entry_t subnet_length_entries[SUBNETLENGTHSIZE]; /* Ordered array of entries */
247 static gboolean have_subnet_entry = FALSE;
249 static gboolean new_resolved_objects = FALSE;
251 static GPtrArray* extra_hosts_files = NULL;
253 static hashether_t *add_eth_name(const guint8 *addr, const gchar *name);
254 static void add_serv_port_cb(const guint32 port, gpointer ptr);
257 /* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
261 ipv6_oat_hash(gconstpointer key)
264 const unsigned char *p = (const unsigned char *)key;
268 for ( i = 0; i < len; i++ ) {
282 ipv6_equal(gconstpointer v1, gconstpointer v2)
285 if (memcmp(v1, v2, sizeof (ws_in6_addr)) == 0) {
293 * Flag controlling what names to resolve.
295 e_addr_resolve gbl_resolv_flags = {
297 FALSE, /* network_name */
298 FALSE, /* transport_name */
299 TRUE, /* dns_pkt_addr_resolution */
300 TRUE, /* use_external_net_name_resolver */
301 FALSE, /* load_hosts_file_from_profile_only */
302 FALSE, /* vlan_name */
303 FALSE /* ss7 point code names */
306 static guint name_resolve_concurrency = 500;
310 * Global variables (can be changed in GUI sections)
311 * XXX - they could be changed in GUI code, but there's currently no
312 * GUI code to change them.
315 gchar *g_ethers_path = NULL; /* global ethers file */
316 gchar *g_pethers_path = NULL; /* personal ethers file */
317 gchar *g_wka_path = NULL; /* global well-known-addresses file */
318 gchar *g_manuf_path = NULL; /* global manuf file */
319 gchar *g_ipxnets_path = NULL; /* global ipxnets file */
320 gchar *g_pipxnets_path = NULL; /* personal ipxnets file */
321 gchar *g_services_path = NULL; /* global services file */
322 gchar *g_pservices_path = NULL; /* personal services file */
323 gchar *g_pvlan_path = NULL; /* personal vlans file */
324 gchar *g_ss7pcs_path = NULL; /* personal ss7pcs file */
325 gchar *g_enterprises_path = NULL; /* global enterprises file */
326 gchar *g_penterprises_path = NULL; /* personal enterprises file */
327 /* first resolving call */
332 * Submitted queries trigger a callback (c_ares_ghba_cb()).
333 * Queries are added to c_ares_queue_head. During processing, queries are
334 * popped off the front of c_ares_queue_head and submitted using
335 * ares_gethostbyaddr().
336 * The callback processes the response, then frees the request.
338 typedef struct _async_dns_queue_msg
345 } async_dns_queue_msg_t;
347 typedef struct _async_hostent {
353 ares_channel ghba_chan; /* ares_gethostbyaddr -- Usually non-interactive, no timeout */
354 ares_channel ghbn_chan; /* ares_gethostbyname -- Usually interactive, timeout */
356 static gboolean async_dns_initialized = FALSE;
357 static guint async_dns_in_flight = 0;
358 static wmem_list_t *async_dns_queue_head = NULL;
360 /* push a dns request */
362 add_async_dns_ipv4(int type, guint32 addr)
364 async_dns_queue_msg_t *msg;
366 msg = wmem_new(wmem_epan_scope(), async_dns_queue_msg_t);
368 msg->addr.ip4 = addr;
369 wmem_list_append(async_dns_queue_head, (gpointer) msg);
371 #endif /* HAVE_C_ARES */
376 const gchar* name; /* Shallow copy */
380 * Miscellaneous functions
384 fgetline(char **buf, int *size, FILE *fp)
389 if (fp == NULL || buf == NULL)
396 *buf = (char *)wmem_alloc(wmem_epan_scope(), *size);
406 while ((c = ws_getc_unlocked(fp)) != EOF && c != '\r' && c != '\n') {
407 if (len+1 >= *size) {
408 *buf = (char *)wmem_realloc(wmem_epan_scope(), *buf, *size += BUFSIZ);
413 if (len == 0 && c == EOF)
424 * Local function definitions
426 static subnet_entry_t subnet_lookup(const guint32 addr);
427 static void subnet_entry_set(guint32 subnet_addr, const guint8 mask_length, const gchar* name);
431 add_service_name(port_type proto, const guint port, const char *service_name)
433 serv_port_t *serv_port_table;
436 key = (int *)wmem_new(wmem_epan_scope(), int);
439 serv_port_table = (serv_port_t *)wmem_map_lookup(serv_port_hashtable, &port);
440 if (serv_port_table == NULL) {
441 serv_port_table = wmem_new0(wmem_epan_scope(), serv_port_t);
442 wmem_map_insert(serv_port_hashtable, key, serv_port_table);
445 wmem_free(wmem_epan_scope(), key);
450 wmem_free(wmem_epan_scope(), serv_port_table->tcp_name);
451 serv_port_table->tcp_name = wmem_strdup(wmem_epan_scope(), service_name);
454 wmem_free(wmem_epan_scope(), serv_port_table->udp_name);
455 serv_port_table->udp_name = wmem_strdup(wmem_epan_scope(), service_name);
458 wmem_free(wmem_epan_scope(), serv_port_table->sctp_name);
459 serv_port_table->sctp_name = wmem_strdup(wmem_epan_scope(), service_name);
462 wmem_free(wmem_epan_scope(), serv_port_table->dccp_name);
463 serv_port_table->dccp_name = wmem_strdup(wmem_epan_scope(), service_name);
467 /* Should not happen */
470 new_resolved_objects = TRUE;
475 parse_service_line (char *line)
481 struct cb_serv_data cb_data;
482 range_t *port_rng = NULL;
484 if ((cp = strchr(line, '#')))
487 if ((cp = strtok(line, " \t")) == NULL)
492 if ((cp = strtok(NULL, " \t")) == NULL)
497 if (strtok(cp, "/") == NULL)
500 if (range_convert_str(NULL, &port_rng, port, G_MAXUINT16) != CVT_NO_ERROR) {
501 wmem_free (NULL, port_rng);
505 while ((cp = strtok(NULL, "/")) != NULL) {
506 if (strcmp(cp, "tcp") == 0) {
509 else if (strcmp(cp, "udp") == 0) {
512 else if (strcmp(cp, "sctp") == 0) {
515 else if (strcmp(cp, "dccp") == 0) {
521 cb_data.service = service;
522 cb_data.proto = proto;
523 range_foreach(port_rng, add_serv_port_cb, &cb_data);
526 wmem_free (NULL, port_rng);
527 } /* parse_service_line */
531 add_serv_port_cb(const guint32 port, gpointer ptr)
533 struct cb_serv_data *cb_data = (struct cb_serv_data *)ptr;
536 add_service_name(cb_data->proto, port, cb_data->service);
542 parse_services_file(const char * path)
546 static char *buf = NULL;
548 /* services hash table initialization */
549 serv_p = ws_fopen(path, "r");
554 while (fgetline(&buf, &size, serv_p) >= 0) {
555 parse_service_line(buf);
563 * unsigned integer to ascii
566 wmem_utoa(wmem_allocator_t *allocator, guint port)
568 gchar *bp = (gchar *)wmem_alloc(allocator, MAXNAMELEN);
570 /* XXX, guint32_to_str() ? */
571 guint32_to_str_buf(port, bp, MAXNAMELEN);
576 _serv_name_lookup(port_type proto, guint port, serv_port_t **value_ret)
578 serv_port_t *serv_port_table;
580 serv_port_table = (serv_port_t *)wmem_map_lookup(serv_port_hashtable, &port);
582 if (value_ret != NULL)
583 *value_ret = serv_port_table;
585 if (serv_port_table == NULL)
590 return serv_port_table->udp_name;
592 return serv_port_table->tcp_name;
594 return serv_port_table->sctp_name;
596 return serv_port_table->dccp_name;
604 try_serv_name_lookup(port_type proto, guint port)
606 return _serv_name_lookup(proto, port, NULL);
610 serv_name_lookup(port_type proto, guint port)
612 serv_port_t *serv_port_table = NULL;
616 name = _serv_name_lookup(proto, port, &serv_port_table);
620 if (serv_port_table == NULL) {
621 key = (guint *)wmem_new(wmem_epan_scope(), guint);
623 serv_port_table = wmem_new0(wmem_epan_scope(), serv_port_t);
624 wmem_map_insert(serv_port_hashtable, key, serv_port_table);
626 if (serv_port_table->numeric == NULL) {
627 serv_port_table->numeric = wmem_strdup_printf(wmem_epan_scope(), "%u", port);
630 return serv_port_table->numeric;
634 initialize_services(void)
636 gboolean parse_file = TRUE;
637 g_assert(serv_port_hashtable == NULL);
638 serv_port_hashtable = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
640 /* Compute the pathname of the services file. */
641 if (g_services_path == NULL) {
642 g_services_path = get_datafile_path(ENAME_SERVICES);
644 parse_services_file(g_services_path);
646 /* Compute the pathname of the personal services file */
647 if (g_pservices_path == NULL) {
648 /* Check profile directory before personal configuration */
649 g_pservices_path = get_persconffile_path(ENAME_SERVICES, TRUE);
650 if (!parse_services_file(g_pservices_path)) {
651 g_free(g_pservices_path);
652 g_pservices_path = get_persconffile_path(ENAME_SERVICES, FALSE);
658 parse_services_file(g_pservices_path);
663 service_name_lookup_cleanup(void)
665 serv_port_hashtable = NULL;
666 g_free(g_services_path);
667 g_services_path = NULL;
668 g_free(g_pservices_path);
669 g_pservices_path = NULL;
673 parse_enterprises_line (char *line)
675 char *tok, *dec_str, *org_str;
678 if ((tok = strchr(line, '#')))
680 dec_str = strtok(line, " \t");
683 org_str = strtok(NULL, ""); /* everything else */
685 org_str = g_strstrip(org_str);
688 if (!ws_strtou32(dec_str, NULL, &dec))
690 g_hash_table_replace(enterprises_hashtable, GUINT_TO_POINTER(dec), g_strdup(org_str));
695 parse_enterprises_file(const char * path)
699 static char *buf = NULL;
701 fp = ws_fopen(path, "r");
705 while (fgetline(&buf, &size, fp) >= 0) {
706 parse_enterprises_line(buf);
714 initialize_enterprises(void)
716 g_assert(enterprises_hashtable == NULL);
717 enterprises_hashtable = g_hash_table_new_full(NULL, NULL, NULL, g_free);
719 if (g_enterprises_path == NULL) {
720 g_enterprises_path = get_datafile_path(ENAME_ENTERPRISES);
722 parse_enterprises_file(g_enterprises_path);
724 if (g_penterprises_path == NULL) {
725 g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES, FALSE);
727 parse_enterprises_file(g_penterprises_path);
731 try_enterprises_lookup(guint32 value)
733 return (const gchar *)g_hash_table_lookup(enterprises_hashtable, GUINT_TO_POINTER(value));
737 enterprises_lookup(guint32 value, const char *unknown_str)
741 s = try_enterprises_lookup(value);
744 if (unknown_str != NULL)
750 enterprises_base_custom(char *buf, guint32 value)
754 if ((s = try_enterprises_lookup(value)) == NULL)
755 s = ITEM_LABEL_UNKNOWN_STR;
756 g_snprintf(buf, ITEM_LABEL_LENGTH, "%s (%u)", s, value);
760 enterprises_cleanup(void)
762 g_assert(enterprises_hashtable);
763 g_hash_table_destroy(enterprises_hashtable);
764 enterprises_hashtable = NULL;
765 g_assert(g_enterprises_path);
766 g_free(g_enterprises_path);
767 g_enterprises_path = NULL;
768 if (g_pservices_path) {
769 g_free(g_pservices_path);
770 g_pservices_path = NULL;
774 /* Fill in an IP4 structure with info from subnets file or just with the
775 * string form of the address.
778 fill_dummy_ip4(const guint addr, hashipv4_t* volatile tp)
780 subnet_entry_t subnet_entry;
782 /* Overwrite if we get async DNS reply */
784 /* Do we have a subnet for this address? */
785 subnet_entry = subnet_lookup(addr);
786 if (0 != subnet_entry.mask) {
787 /* Print name, then '.' then IP address after subnet mask */
789 gchar buffer[WS_INET_ADDRSTRLEN];
793 host_addr = addr & (~(guint32)subnet_entry.mask);
794 ip_to_str_buf((guint8 *)&host_addr, buffer, WS_INET_ADDRSTRLEN);
797 /* Skip to first octet that is not totally masked
798 * If length of mask is 32, we chomp the whole address.
799 * If the address string starts '.' (should not happen?),
802 i = subnet_entry.mask_length / 8;
803 while(*(paddr) != '\0' && i > 0) {
804 if (*(++paddr) == '.') {
809 /* There are more efficient ways to do this, but this is safe if we
810 * trust g_snprintf and MAXNAMELEN
812 g_snprintf(tp->name, MAXNAMELEN, "%s%s", subnet_entry.name, paddr);
814 /* XXX: This means we end up printing "1.2.3.4 (1.2.3.4)" in many cases */
815 ip_to_str_buf((const guint8 *)&addr, tp->name, MAXNAMELEN);
820 /* Fill in an IP6 structure with the string form of the address.
823 fill_dummy_ip6(hashipv6_t* volatile tp)
825 /* Overwrite if we get async DNS reply */
826 g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
832 c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
833 async_dns_queue_msg_t *caqm = (async_dns_queue_msg_t *)arg;
837 /* XXX, what to do if async_dns_in_flight == 0? */
838 async_dns_in_flight--;
840 if (status == ARES_SUCCESS) {
841 for (p = he->h_addr_list; *p != NULL; p++) {
842 switch(caqm->family) {
844 add_ipv4_name(caqm->addr.ip4, he->h_name);
847 add_ipv6_name(&caqm->addr.ip6, he->h_name);
850 /* Throw an exception? */
855 wmem_free(wmem_epan_scope(), caqm);
857 #endif /* HAVE_C_ARES */
859 /* --------------- */
861 new_ipv4(const guint addr)
863 hashipv4_t *tp = wmem_new(wmem_epan_scope(), hashipv4_t);
867 ip_to_str_buf((const guint8 *)&addr, tp->ip, sizeof(tp->ip));
872 host_lookup(const guint addr)
874 hashipv4_t * volatile tp;
876 tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
879 * We don't already have an entry for this host name; create one,
880 * and then try to resolve it.
883 fill_dummy_ip4(addr, tp);
884 wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
885 } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
890 * This hasn't been resolved yet, and we haven't tried to
891 * resolve it already.
894 if (!gbl_resolv_flags.network_name)
897 if (gbl_resolv_flags.use_external_net_name_resolver) {
898 tp->flags |= TRIED_RESOLVE_ADDRESS;
901 if (async_dns_initialized && name_resolve_concurrency > 0) {
902 add_async_dns_ipv4(AF_INET, addr);
911 /* --------------- */
913 new_ipv6(const ws_in6_addr *addr)
915 hashipv6_t *tp = wmem_new(wmem_epan_scope(), hashipv6_t);
916 memcpy(tp->addr, addr->bytes, sizeof tp->addr);
919 ip6_to_str_buf(addr, tp->ip6, sizeof(tp->ip6));
923 /* ------------------------------------ */
925 host_lookup6(const ws_in6_addr *addr)
927 hashipv6_t * volatile tp;
929 async_dns_queue_msg_t *caqm;
932 tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addr);
935 * We don't already have an entry for this host name; create one,
936 * and then try to resolve it.
938 ws_in6_addr *addr_key;
940 addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr);
942 memcpy(addr_key, addr, 16);
944 wmem_map_insert(ipv6_hash_table, addr_key, tp);
945 } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
950 * This hasn't been resolved yet, and we haven't tried to
951 * resolve it already.
954 if (!gbl_resolv_flags.network_name)
957 if (gbl_resolv_flags.use_external_net_name_resolver) {
958 tp->flags |= TRIED_RESOLVE_ADDRESS;
960 if (async_dns_initialized && name_resolve_concurrency > 0) {
961 caqm = wmem_new(wmem_epan_scope(), async_dns_queue_msg_t);
962 caqm->family = AF_INET6;
963 memcpy(&caqm->addr.ip6, addr, sizeof(caqm->addr.ip6));
964 wmem_list_append(async_dns_queue_head, (gpointer) caqm);
974 * Ethernet / manufacturer resolution
976 * The following functions implement ethernet address resolution and
977 * ethers files parsing (see ethers(4)).
979 * The manuf file has the same format as ethers(4) except that names are
980 * truncated to MAXMANUFLEN-1 (8) characters and that an address contains
981 * only 3 bytes (instead of 6).
985 * I decide to not use the existing functions (see ethers(3) on some
986 * operating systems) for the following reasons:
987 * - performance gains (use of hash tables and some other enhancements),
988 * - use of two ethers files (system-wide and per user),
989 * - avoid the use of NIS maps,
990 * - lack of these functions on some systems.
992 * So the following functions do _not_ behave as the standard ones.
999 * If "accept_mask" is FALSE, either 3 or 6 bytes are valid, but no other number of bytes is.
1000 * If "accept_mask" is TRUE, parse an up-to-6-byte sequence with an optional
1004 parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
1005 const gboolean accept_mask)
1012 for (i = 0; i < 6; i++) {
1013 /* Get a hex number, 1 or 2 digits, no sign characters allowed. */
1014 if (!g_ascii_isxdigit(*cp))
1016 num = strtoul(cp, &p, 16);
1018 return FALSE; /* failed */
1020 return FALSE; /* not a valid octet */
1021 eth->addr[i] = (guint8) num;
1022 cp = p; /* skip past the number */
1024 /* OK, what character terminated the octet? */
1026 /* "/" - this has a mask. */
1028 /* Entries with masks are not allowed in this file. */
1031 cp++; /* skip past the '/' to get to the mask */
1032 if (!g_ascii_isdigit(*cp))
1033 return FALSE; /* no sign allowed */
1034 num = strtoul(cp, &p, 10);
1036 return FALSE; /* failed */
1037 cp = p; /* skip past the number */
1038 if (*cp != '\0' && !g_ascii_isspace(*cp))
1039 return FALSE; /* bogus terminator */
1040 if (num == 0 || num >= 48)
1041 return FALSE; /* bogus mask */
1042 /* Mask out the bits not covered by the mask */
1044 for (i = 0; num >= 8; i++, num -= 8)
1045 ; /* skip octets entirely covered by the mask */
1046 /* Mask out the first masked octet */
1047 eth->addr[i] &= (0xFF << (8 - num));
1049 /* Mask out completely-masked-out octets */
1055 /* We're at the end of the address, and there's no mask. */
1057 /* We got 3 bytes, so this is a manufacturer ID. */
1059 /* Manufacturer IDs are not allowed in this file */
1062 /* Indicate that this is a manufacturer ID (0 is not allowed
1069 /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1075 /* We didn't get 3 or 6 bytes, and there's no mask; this is
1080 /* We don't know the separator used in this number; it can either
1081 be ':', '-', or '.'. */
1082 if (*cp != ':' && *cp != '-' && *cp != '.')
1084 sep = *cp; /* subsequent separators must be the same */
1086 /* It has to be the same as the first separator */
1098 parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
1099 const gboolean accept_mask)
1102 * See the ethers(4) or ethers(5) man page for ethers file format
1103 * (not available on all systems).
1104 * We allow both ethernet address separators (':' and '-'),
1105 * as well as Wireshark's '.' separator.
1110 line = g_strstrip(line);
1111 if (line[0] == '\0' || line[0] == '#')
1114 if ((cp = strchr(line, '#'))) {
1116 while (g_ascii_isspace(*cp)) {
1122 if ((cp = strtok(line, " \t")) == NULL)
1125 if (!parse_ether_address(cp, eth, mask, accept_mask))
1128 if ((cp = strtok(NULL, " \t")) == NULL)
1131 g_strlcpy(eth->name, cp, MAXNAMELEN);
1133 if ((cp = strtok(NULL, "")) != NULL)
1135 g_strlcpy(eth->longname, cp, MAXNAMELEN);
1137 /* Make the long name the short name */
1138 g_strlcpy(eth->longname, eth->name, MAXNAMELEN);
1143 } /* parse_ether_line */
1145 static FILE *eth_p = NULL;
1148 set_ethent(char *path)
1153 eth_p = ws_fopen(path, "r");
1166 get_ethent(unsigned int *mask, const gboolean accept_mask)
1170 static int size = 0;
1171 static char *buf = NULL;
1176 while (fgetline(&buf, &size, eth_p) >= 0) {
1177 if (parse_ether_line(buf, ð, mask, accept_mask) == 0) {
1187 get_ethbyaddr(const guint8 *addr)
1192 set_ethent(g_pethers_path);
1194 while (((eth = get_ethent(NULL, FALSE)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
1200 set_ethent(g_ethers_path);
1202 while (((eth = get_ethent(NULL, FALSE)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
1210 } /* get_ethbyaddr */
1212 static hashmanuf_t *
1213 manuf_hash_new_entry(const guint8 *addr, char* name, char* longname)
1216 hashmanuf_t *manuf_value;
1219 /* manuf needs only the 3 most significant octets of the ethernet address */
1220 manuf_key = (int *)wmem_new(wmem_epan_scope(), int);
1221 *manuf_key = (int)((addr[0] << 16) + (addr[1] << 8) + addr[2]);
1222 manuf_value = wmem_new(wmem_epan_scope(), hashmanuf_t);
1224 memcpy(manuf_value->addr, addr, 3);
1226 g_strlcpy(manuf_value->resolved_name, name, MAXNAMELEN);
1227 manuf_value->status = HASHETHER_STATUS_RESOLVED_NAME;
1228 if (longname != NULL) {
1229 g_strlcpy(manuf_value->resolved_longname, longname, MAXNAMELEN);
1232 g_strlcpy(manuf_value->resolved_longname, name, MAXNAMELEN);
1236 manuf_value->status = HASHETHER_STATUS_UNRESOLVED;
1237 manuf_value->resolved_name[0] = '\0';
1238 manuf_value->resolved_longname[0] = '\0';
1240 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
1241 endp = bytes_to_hexstr_punct(manuf_value->hexaddr, addr, sizeof(manuf_value->addr), ':');
1244 wmem_map_insert(manuf_hashtable, manuf_key, manuf_value);
1249 wka_hash_new_entry(const guint8 *addr, char* name)
1253 wka_key = (guint8 *)wmem_alloc(wmem_epan_scope(), 6);
1254 memcpy(wka_key, addr, 6);
1256 wmem_map_insert(wka_hashtable, wka_key, wmem_strdup(wmem_epan_scope(), name));
1260 add_manuf_name(const guint8 *addr, unsigned int mask, gchar *name, gchar *longname)
1265 /* This is a manufacturer ID; add it to the manufacturer ID hash table */
1266 manuf_hash_new_entry(addr, name, longname);
1270 /* This is a well-known MAC address; add it to the Ethernet hash table */
1271 add_eth_name(addr, name);
1275 /* This is a range of well-known addresses; add it to the well-known-address table */
1276 wka_hash_new_entry(addr, name);
1279 } /* add_manuf_name */
1281 static hashmanuf_t *
1282 manuf_name_lookup(const guint8 *addr)
1284 gint32 manuf_key = 0;
1286 hashmanuf_t *manuf_value;
1288 /* manuf needs only the 3 most significant octets of the ethernet address */
1289 manuf_key = addr[0];
1290 manuf_key = manuf_key<<8;
1292 manuf_key = manuf_key | oct;
1293 manuf_key = manuf_key<<8;
1295 manuf_key = manuf_key | oct;
1298 /* first try to find a "perfect match" */
1299 manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, &manuf_key);
1300 if (manuf_value != NULL) {
1304 /* Mask out the broadcast/multicast flag but not the locally
1305 * administered flag as locally administered means: not assigned
1306 * by the IEEE but the local administrator instead.
1307 * 0x01 multicast / broadcast bit
1308 * 0x02 locally administered bit */
1309 if ((manuf_key & 0x00010000) != 0) {
1310 manuf_key &= 0x00FEFFFF;
1311 manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, &manuf_key);
1312 if (manuf_value != NULL) {
1317 /* Add the address as a hex string */
1318 return manuf_hash_new_entry(addr, NULL, NULL);
1320 } /* manuf_name_lookup */
1323 wka_name_lookup(const guint8 *addr, const unsigned int mask)
1325 guint8 masked_addr[6];
1330 if (wka_hashtable == NULL) {
1333 /* Get the part of the address covered by the mask. */
1334 for (i = 0, num = mask; num >= 8; i++, num -= 8)
1335 masked_addr[i] = addr[i]; /* copy octets entirely covered by the mask */
1336 /* Mask out the first masked octet */
1337 masked_addr[i] = addr[i] & (0xFF << (8 - num));
1339 /* Zero out completely-masked-out octets */
1343 name = (gchar *)wmem_map_lookup(wka_hashtable, masked_addr);
1347 } /* wka_name_lookup */
1350 guint get_hash_ether_status(hashether_t* ether)
1352 return ether->status;
1355 char* get_hash_ether_hexaddr(hashether_t* ether)
1357 return ether->hexaddr;
1360 char* get_hash_ether_resolved_name(hashether_t* ether)
1362 return ether->resolved_name;
1366 eth_addr_hash(gconstpointer key)
1368 return wmem_strong_hash((const guint8 *)key, 6);
1372 eth_addr_cmp(gconstpointer a, gconstpointer b)
1374 return (memcmp(a, b, 6) == 0);
1378 initialize_ethers(void)
1383 /* hash table initialization */
1384 wka_hashtable = wmem_map_new(wmem_epan_scope(), eth_addr_hash, eth_addr_cmp);
1385 manuf_hashtable = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
1386 eth_hashtable = wmem_map_new(wmem_epan_scope(), eth_addr_hash, eth_addr_cmp);
1388 /* Compute the pathname of the ethers file. */
1389 if (g_ethers_path == NULL) {
1390 g_ethers_path = g_build_filename(get_systemfile_dir(), ENAME_ETHERS, NULL);
1393 /* Set g_pethers_path here, but don't actually do anything
1394 * with it. It's used in get_ethbyaddr().
1396 if (g_pethers_path == NULL)
1397 g_pethers_path = get_persconffile_path(ENAME_ETHERS, FALSE);
1399 /* Compute the pathname of the manuf file */
1400 if (g_manuf_path == NULL)
1401 g_manuf_path = get_datafile_path(ENAME_MANUF);
1403 /* Read it and initialize the hash table */
1404 set_ethent(g_manuf_path);
1405 while ((eth = get_ethent(&mask, TRUE))) {
1406 add_manuf_name(eth->addr, mask, eth->name, eth->longname);
1410 /* Compute the pathname of the wka file */
1411 if (g_wka_path == NULL)
1412 g_wka_path = get_datafile_path(ENAME_WKA);
1414 /* Read it and initialize the hash table */
1415 set_ethent(g_wka_path);
1416 while ((eth = get_ethent(&mask, TRUE))) {
1417 add_manuf_name(eth->addr, mask, eth->name, eth->longname);
1421 } /* initialize_ethers */
1424 ethers_cleanup(void)
1426 g_free(g_ethers_path);
1427 g_ethers_path = NULL;
1428 g_free(g_pethers_path);
1429 g_pethers_path = NULL;
1430 g_free(g_manuf_path);
1431 g_manuf_path = NULL;
1436 /* Resolve ethernet address */
1437 static hashether_t *
1438 eth_addr_resolve(hashether_t *tp) {
1440 hashmanuf_t *manuf_value;
1441 const guint8 *addr = tp->addr;
1443 if ( (eth = get_ethbyaddr(addr)) != NULL) {
1444 g_strlcpy(tp->resolved_name, eth->name, MAXNAMELEN);
1445 tp->status = HASHETHER_STATUS_RESOLVED_NAME;
1452 /* Unknown name. Try looking for it in the well-known-address
1453 tables for well-known address ranges smaller than 2^24. */
1456 /* Only the topmost 5 bytes participate fully */
1457 if ((name = wka_name_lookup(addr, mask+40)) != NULL) {
1458 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x",
1459 name, addr[5] & (0xFF >> mask));
1460 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1467 /* Only the topmost 4 bytes participate fully */
1468 if ((name = wka_name_lookup(addr, mask+32)) != NULL) {
1469 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x",
1470 name, addr[4] & (0xFF >> mask), addr[5]);
1471 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1478 /* Only the topmost 3 bytes participate fully */
1479 if ((name = wka_name_lookup(addr, mask+24)) != NULL) {
1480 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
1481 name, addr[3] & (0xFF >> mask), addr[4], addr[5]);
1482 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1487 /* Now try looking in the manufacturer table. */
1488 manuf_value = manuf_name_lookup(addr);
1489 if ((manuf_value != NULL) && (manuf_value->status != HASHETHER_STATUS_UNRESOLVED)) {
1490 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
1491 manuf_value->resolved_name, addr[3], addr[4], addr[5]);
1492 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1496 /* Now try looking for it in the well-known-address
1497 tables for well-known address ranges larger than 2^24. */
1500 /* Only the topmost 2 bytes participate fully */
1501 if ((name = wka_name_lookup(addr, mask+16)) != NULL) {
1502 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x",
1503 name, addr[2] & (0xFF >> mask), addr[3], addr[4],
1505 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1512 /* Only the topmost byte participates fully */
1513 if ((name = wka_name_lookup(addr, mask+8)) != NULL) {
1514 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
1515 name, addr[1] & (0xFF >> mask), addr[2], addr[3],
1517 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1524 /* Not even the topmost byte participates fully */
1525 if ((name = wka_name_lookup(addr, mask)) != NULL) {
1526 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
1527 name, addr[0] & (0xFF >> mask), addr[1], addr[2],
1528 addr[3], addr[4], addr[5]);
1529 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1532 } while (--mask); /* Work down to the last bit */
1534 /* No match whatsoever. */
1535 set_address(ðer_addr, AT_ETHER, 6, addr);
1536 address_to_str_buf(ðer_addr, tp->resolved_name, MAXNAMELEN);
1537 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1540 g_assert_not_reached();
1541 } /* eth_addr_resolve */
1543 static hashether_t *
1544 eth_hash_new_entry(const guint8 *addr, const gboolean resolve)
1549 tp = wmem_new(wmem_epan_scope(), hashether_t);
1550 memcpy(tp->addr, addr, sizeof(tp->addr));
1551 tp->status = HASHETHER_STATUS_UNRESOLVED;
1552 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
1553 endp = bytes_to_hexstr_punct(tp->hexaddr, addr, sizeof(tp->addr), ':');
1555 tp->resolved_name[0] = '\0';
1558 eth_addr_resolve(tp);
1560 wmem_map_insert(eth_hashtable, tp->addr, tp);
1563 } /* eth_hash_new_entry */
1565 static hashether_t *
1566 add_eth_name(const guint8 *addr, const gchar *name)
1570 tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
1573 tp = eth_hash_new_entry(addr, FALSE);
1576 if (strcmp(tp->resolved_name, name) != 0) {
1577 g_strlcpy(tp->resolved_name, name, MAXNAMELEN);
1578 tp->status = HASHETHER_STATUS_RESOLVED_NAME;
1579 new_resolved_objects = TRUE;
1583 } /* add_eth_name */
1585 static hashether_t *
1586 eth_name_lookup(const guint8 *addr, const gboolean resolve)
1590 tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
1593 tp = eth_hash_new_entry(addr, resolve);
1595 if (resolve && (tp->status == HASHETHER_STATUS_UNRESOLVED)) {
1596 eth_addr_resolve(tp); /* Found but needs to be resolved */
1602 } /* eth_name_lookup */
1607 parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
1610 * We allow three address separators (':', '-', and '.'),
1611 * as well as no separators
1615 guint32 a, a0, a1, a2, a3;
1616 gboolean found_single_number = FALSE;
1618 if ((cp = strchr(line, '#')))
1621 if ((cp = strtok(line, " \t\n")) == NULL)
1624 /* Either fill a0,a1,a2,a3 and found_single_number is FALSE,
1625 * fill a and found_single_number is TRUE,
1628 if (sscanf(cp, "%x:%x:%x:%x", &a0, &a1, &a2, &a3) != 4) {
1629 if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
1630 if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
1631 if (sscanf(cp, "%x", &a) == 1) {
1632 found_single_number = TRUE;
1641 if ((cp = strtok(NULL, " \t\n")) == NULL)
1644 if (found_single_number) {
1648 ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
1651 g_strlcpy(ipxnet->name, cp, MAXNAMELEN);
1655 } /* parse_ipxnets_line */
1657 static FILE *ipxnet_p = NULL;
1660 set_ipxnetent(char *path)
1665 ipxnet_p = ws_fopen(path, "r");
1681 static ipxnet_t ipxnet;
1682 static int size = 0;
1683 static char *buf = NULL;
1685 if (ipxnet_p == NULL)
1688 while (fgetline(&buf, &size, ipxnet_p) >= 0) {
1689 if (parse_ipxnets_line(buf, &ipxnet) == 0) {
1696 } /* get_ipxnetent */
1699 get_ipxnetbyaddr(guint32 addr)
1703 set_ipxnetent(g_ipxnets_path);
1705 while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) ) ;
1707 if (ipxnet == NULL) {
1710 set_ipxnetent(g_pipxnets_path);
1712 while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) )
1720 } /* get_ipxnetbyaddr */
1723 initialize_ipxnets(void)
1725 /* Compute the pathname of the ipxnets file.
1727 * XXX - is there a notion of an "ipxnets file" in any flavor of
1728 * UNIX, or with any add-on Netware package for UNIX? If not,
1729 * should the UNIX version of the ipxnets file be in the datafile
1730 * directory as well?
1732 if (g_ipxnets_path == NULL) {
1733 g_ipxnets_path = wmem_strdup_printf(wmem_epan_scope(), "%s" G_DIR_SEPARATOR_S "%s",
1734 get_systemfile_dir(), ENAME_IPXNETS);
1737 /* Set g_pipxnets_path here, but don't actually do anything
1738 * with it. It's used in get_ipxnetbyaddr().
1740 if (g_pipxnets_path == NULL)
1741 g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, FALSE);
1743 } /* initialize_ipxnets */
1746 ipx_name_lookup_cleanup(void)
1748 ipxnet_hash_table = NULL;
1749 g_free(g_pipxnets_path);
1750 g_pipxnets_path = NULL;
1754 ipxnet_name_lookup(wmem_allocator_t *allocator, const guint addr)
1759 tp = (hashipxnet_t *)wmem_map_lookup(ipxnet_hash_table, &addr);
1763 key = (int *)wmem_new(wmem_epan_scope(), int);
1765 tp = wmem_new(wmem_epan_scope(), hashipxnet_t);
1766 wmem_map_insert(ipxnet_hash_table, key, tp);
1768 return wmem_strdup(allocator, tp->name);
1771 /* fill in a new entry */
1775 if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL) {
1777 g_snprintf(tp->name, MAXNAMELEN, "%X", addr);
1780 g_strlcpy(tp->name, ipxnet->name, MAXNAMELEN);
1783 return wmem_strdup(allocator, tp->name);
1785 } /* ipxnet_name_lookup */
1789 parse_vlan_line(char *line, vlan_t *vlan)
1794 if ((cp = strchr(line, '#')))
1797 if ((cp = strtok(line, " \t\n")) == NULL)
1800 if (sscanf(cp, "%" G_GUINT16_FORMAT, &id) == 1) {
1807 if ((cp = strtok(NULL, "\t\n")) == NULL)
1810 g_strlcpy(vlan->name, cp, MAXVLANNAMELEN);
1814 } /* parse_vlan_line */
1816 static FILE *vlan_p = NULL;
1819 set_vlanent(char *path)
1824 vlan_p = ws_fopen(path, "r");
1841 static int size = 0;
1842 static char *buf = NULL;
1847 while (fgetline(&buf, &size, vlan_p) >= 0) {
1848 if (parse_vlan_line(buf, &vlan) == 0) {
1858 get_vlannamebyid(guint16 id)
1862 set_vlanent(g_pvlan_path);
1864 while (((vlan = get_vlanent()) != NULL) && (id != vlan->id) ) ;
1873 } /* get_vlannamebyid */
1876 initialize_vlans(void)
1878 g_assert(vlan_hash_table == NULL);
1879 vlan_hash_table = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
1881 /* Set g_pvlan_path here, but don't actually do anything
1882 * with it. It's used in get_vlannamebyid()
1884 if (g_pvlan_path == NULL)
1885 g_pvlan_path = get_persconffile_path(ENAME_VLANS, FALSE);
1887 } /* initialize_vlans */
1890 vlan_name_lookup_cleanup(void)
1892 vlan_hash_table = NULL;
1893 g_free(g_pvlan_path);
1894 g_pvlan_path = NULL;
1897 static const gchar *
1898 vlan_name_lookup(const guint id)
1903 tp = (hashvlan_t *)wmem_map_lookup(vlan_hash_table, &id);
1907 key = (int *)wmem_new(wmem_epan_scope(), int);
1909 tp = wmem_new(wmem_epan_scope(), hashvlan_t);
1910 wmem_map_insert(vlan_hash_table, key, tp);
1915 /* fill in a new entry */
1919 if ( (vlan = get_vlannamebyid(id)) == NULL) {
1921 g_snprintf(tp->name, MAXVLANNAMELEN, "<%u>", id);
1924 g_strlcpy(tp->name, vlan->name, MAXVLANNAMELEN);
1929 } /* vlan_name_lookup */
1933 read_hosts_file (const char *hostspath, gboolean store_entries)
1941 ws_in6_addr ip6_addr;
1943 gboolean is_ipv6, entry_found = FALSE;
1946 * See the hosts(4) or hosts(5) man page for hosts file format
1947 * (not available on all systems).
1949 if ((hf = ws_fopen(hostspath, "r")) == NULL)
1952 while (fgetline(&line, &size, hf) >= 0) {
1953 if ((cp = strchr(line, '#')))
1956 if ((cp = strtok(line, " \t")) == NULL)
1957 continue; /* no tokens in the line */
1959 if (ws_inet_pton6(cp, &host_addr.ip6_addr)) {
1962 } else if (ws_inet_pton4(cp, &host_addr.ip4_addr)) {
1969 if ((cp = strtok(NULL, " \t")) == NULL)
1970 continue; /* no host name */
1973 if (store_entries) {
1975 add_ipv6_name(&host_addr.ip6_addr, cp);
1977 add_ipv4_name(host_addr.ip4_addr, cp);
1981 wmem_free(wmem_epan_scope(), line);
1984 return entry_found ? TRUE : FALSE;
1985 } /* read_hosts_file */
1988 add_hosts_file (const char *hosts_file)
1990 gboolean found = FALSE;
1996 if (!extra_hosts_files)
1997 extra_hosts_files = g_ptr_array_new();
1999 for (i = 0; i < extra_hosts_files->len; i++) {
2000 if (strcmp(hosts_file, (const char *) g_ptr_array_index(extra_hosts_files, i)) == 0)
2005 g_ptr_array_add(extra_hosts_files, wmem_strdup(wmem_epan_scope(), hosts_file));
2006 return read_hosts_file (hosts_file, FALSE);
2012 add_ip_name_from_string (const char *addr, const char *name)
2016 ws_in6_addr ip6_addr;
2019 resolved_ipv4_t *resolved_ipv4_entry;
2020 resolved_ipv6_t *resolved_ipv6_entry;
2022 if (ws_inet_pton6(addr, &host_addr.ip6_addr)) {
2024 } else if (ws_inet_pton4(addr, &host_addr.ip4_addr)) {
2031 resolved_ipv6_entry = wmem_new(wmem_epan_scope(), resolved_ipv6_t);
2032 memcpy(&(resolved_ipv6_entry->ip6_addr), &host_addr.ip6_addr, 16);
2033 g_strlcpy(resolved_ipv6_entry->name, name, MAXNAMELEN);
2034 wmem_list_prepend(manually_resolved_ipv6_list, resolved_ipv6_entry);
2036 resolved_ipv4_entry = wmem_new(wmem_epan_scope(), resolved_ipv4_t);
2037 resolved_ipv4_entry->host_addr = host_addr.ip4_addr;
2038 g_strlcpy(resolved_ipv4_entry->name, name, MAXNAMELEN);
2039 wmem_list_prepend(manually_resolved_ipv4_list, resolved_ipv4_entry);
2043 } /* add_ip_name_from_string */
2046 * Add the resolved addresses that are in use to the list used to create the NRB
2049 ipv4_hash_table_resolved_to_list(gpointer key _U_, gpointer value, gpointer user_data)
2051 addrinfo_lists_t *lists = (addrinfo_lists_t*)user_data;
2052 hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value;
2054 if ((ipv4_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
2055 lists->ipv4_addr_list = g_list_prepend(lists->ipv4_addr_list, ipv4_hash_table_entry);
2061 * Add the resolved addresses that are in use to the list used to create the NRB
2065 ipv6_hash_table_resolved_to_list(gpointer key _U_, gpointer value, gpointer user_data)
2067 addrinfo_lists_t *lists = (addrinfo_lists_t*)user_data;
2068 hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value;
2070 if ((ipv6_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
2071 lists->ipv6_addr_list = g_list_prepend (lists->ipv6_addr_list, ipv6_hash_table_entry);
2077 get_addrinfo_list(void)
2079 if (ipv4_hash_table) {
2080 wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_resolved_to_list, &addrinfo_lists);
2083 if (ipv6_hash_table) {
2084 wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_resolved_to_list, &addrinfo_lists);
2087 return &addrinfo_lists;
2090 /* Read in a list of subnet definition - name pairs.
2091 * <line> = <comment> | <entry> | <whitespace>
2092 * <comment> = <whitespace>#<any>
2093 * <entry> = <subnet_definition> <whitespace> <subnet_name> [<comment>|<whitespace><any>]
2094 * <subnet_definition> = <ipv4_address> / <subnet_mask_length>
2095 * <ipv4_address> is a full address; it will be masked to get the subnet-ID.
2096 * <subnet_mask_length> is a decimal 1-31
2097 * <subnet_name> is a string containing no whitespace.
2098 * <whitespace> = (space | tab)+
2099 * Any malformed entries are ignored.
2100 * Any trailing data after the subnet_name is ignored.
2105 read_subnets_file (const char *subnetspath)
2111 guint32 host_addr; /* IPv4 ONLY */
2114 if ((hf = ws_fopen(subnetspath, "r")) == NULL)
2117 while (fgetline(&line, &size, hf) >= 0) {
2118 if ((cp = strchr(line, '#')))
2121 if ((cp = strtok(line, " \t")) == NULL)
2122 continue; /* no tokens in the line */
2125 /* Expected format is <IP4 address>/<subnet length> */
2126 cp2 = strchr(cp, '/');
2131 *cp2 = '\0'; /* Cut token */
2134 /* Check if this is a valid IPv4 address */
2135 if (!str_to_ip(cp, &host_addr)) {
2139 if (!ws_strtou8(cp2, NULL, &mask_length) || mask_length == 0 || mask_length > 32) {
2140 continue; /* invalid mask length */
2143 if ((cp = strtok(NULL, " \t")) == NULL)
2144 continue; /* no subnet name */
2146 subnet_entry_set(host_addr, mask_length, cp);
2148 wmem_free(wmem_epan_scope(), line);
2152 } /* read_subnets_file */
2154 static subnet_entry_t
2155 subnet_lookup(const guint32 addr)
2157 subnet_entry_t subnet_entry;
2160 /* Search mask lengths linearly, longest first */
2162 i = SUBNETLENGTHSIZE;
2163 while(have_subnet_entry && i > 0) {
2164 guint32 masked_addr;
2165 subnet_length_entry_t* length_entry;
2167 /* Note that we run from 31 (length 32) to 0 (length 1) */
2169 g_assert(i < SUBNETLENGTHSIZE);
2172 length_entry = &subnet_length_entries[i];
2174 if (NULL != length_entry->subnet_addresses) {
2175 sub_net_hashipv4_t * tp;
2178 masked_addr = addr & length_entry->mask;
2179 hash_idx = HASH_IPV4_ADDRESS(masked_addr);
2181 tp = length_entry->subnet_addresses[hash_idx];
2182 while(tp != NULL && tp->addr != masked_addr) {
2187 subnet_entry.mask = length_entry->mask;
2188 subnet_entry.mask_length = i + 1; /* Length is offset + 1 */
2189 subnet_entry.name = tp->name;
2190 return subnet_entry;
2195 subnet_entry.mask = 0;
2196 subnet_entry.mask_length = 0;
2197 subnet_entry.name = NULL;
2199 return subnet_entry;
2202 /* Add a subnet-definition - name pair to the set.
2203 * The definition is taken by masking the address passed in with the mask of the
2207 subnet_entry_set(guint32 subnet_addr, const guint8 mask_length, const gchar* name)
2209 subnet_length_entry_t* entry;
2210 sub_net_hashipv4_t * tp;
2213 g_assert(mask_length > 0 && mask_length <= 32);
2215 entry = &subnet_length_entries[mask_length - 1];
2217 subnet_addr &= entry->mask;
2219 hash_idx = HASH_IPV4_ADDRESS(subnet_addr);
2221 if (NULL == entry->subnet_addresses) {
2222 entry->subnet_addresses = (sub_net_hashipv4_t**)wmem_alloc0(wmem_epan_scope(), sizeof(sub_net_hashipv4_t*) * HASHHOSTSIZE);
2225 if (NULL != (tp = entry->subnet_addresses[hash_idx])) {
2226 sub_net_hashipv4_t * new_tp;
2229 if (tp->addr == subnet_addr) {
2230 return; /* XXX provide warning that an address was repeated? */
2236 new_tp = wmem_new(wmem_epan_scope(), sub_net_hashipv4_t);
2240 tp = entry->subnet_addresses[hash_idx] = wmem_new(wmem_epan_scope(), sub_net_hashipv4_t);
2244 tp->addr = subnet_addr;
2245 g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
2246 have_subnet_entry = TRUE;
2250 subnet_name_lookup_init(void)
2255 for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
2256 guint32 length = i + 1;
2258 subnet_length_entries[i].subnet_addresses = NULL;
2259 subnet_length_entries[i].mask_length = length;
2260 subnet_length_entries[i].mask = g_htonl(ip_get_subnet_mask(length));
2263 /* Check profile directory before personal configuration */
2264 subnetspath = get_persconffile_path(ENAME_SUBNETS, TRUE);
2265 if (!read_subnets_file(subnetspath)) {
2266 if (errno != ENOENT) {
2267 report_open_failure(subnetspath, errno, FALSE);
2270 g_free(subnetspath);
2271 subnetspath = get_persconffile_path(ENAME_SUBNETS, FALSE);
2272 if (!read_subnets_file(subnetspath) && errno != ENOENT) {
2273 report_open_failure(subnetspath, errno, FALSE);
2276 g_free(subnetspath);
2279 * Load the global subnets file, if we have one.
2281 subnetspath = get_datafile_path(ENAME_SUBNETS);
2282 if (!read_subnets_file(subnetspath) && errno != ENOENT) {
2283 report_open_failure(subnetspath, errno, FALSE);
2285 g_free(subnetspath);
2288 /* SS7 PC Name Resolution Portion */
2289 static hashss7pc_t *
2290 new_ss7pc(const guint8 ni, const guint32 pc)
2292 hashss7pc_t *tp = wmem_new(wmem_epan_scope(), hashss7pc_t);
2293 tp->id = (ni<<24) + (pc&0xffffff);
2294 tp->pc_addr[0] = '\0';
2300 static hashss7pc_t *
2301 host_lookup_ss7pc(const guint8 ni, const guint32 pc)
2303 hashss7pc_t * volatile tp;
2306 id = (ni<<24) + (pc&0xffffff);
2308 tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
2310 tp = new_ss7pc(ni, pc);
2311 wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
2317 void fill_unresolved_ss7pc(const gchar * pc_addr, const guint8 ni, const guint32 pc)
2319 hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
2321 g_strlcpy(tp->pc_addr, pc_addr, MAXNAMELEN);
2325 get_hostname_ss7pc(const guint8 ni, const guint32 pc)
2327 hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
2329 /* never resolved yet*/
2330 if (tp->pc_addr[0] == '\0')
2333 /* Don't have name in file */
2334 if (tp->name[0] == '\0')
2337 if (!gbl_resolv_flags.ss7pc_name)
2344 add_ss7pc_name(const guint8 ni, guint32 pc, const gchar *name)
2349 if (!name || name[0] == '\0')
2352 id = (ni<<24) + (pc&0xffffff);
2353 tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
2355 tp = new_ss7pc(ni, pc);
2356 wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
2359 if (g_ascii_strcasecmp(tp->name, name)) {
2360 g_strlcpy(tp->name, name, MAXNAMELEN);
2365 read_ss7pcs_file(const char *ss7pcspath)
2373 gboolean entry_found = FALSE;
2376 * File format is Network Indicator (decimal)<dash>Point Code (Decimal)<tab/space>Hostname
2378 if ((hf = ws_fopen(ss7pcspath, "r")) == NULL)
2381 while (fgetline(&line, &size, hf) >= 0) {
2382 if ((cp = strchr(line, '#')))
2385 if ((cp = strtok(line, "-")) == NULL)
2386 continue; /*no ni-pc separator*/
2387 if (!ws_strtou8(cp, NULL, &ni))
2392 if ((cp = strtok(NULL, " \t")) == NULL)
2393 continue; /* no tokens for pc and name */
2394 if (!ws_strtou32(cp, NULL, &pc))
2399 if ((cp = strtok(NULL, " \t")) == NULL)
2400 continue; /* no host name */
2403 add_ss7pc_name(ni, pc, cp);
2405 wmem_free(wmem_epan_scope(), line);
2408 return entry_found ? TRUE : FALSE;
2412 ss7pc_name_lookup_init(void)
2416 g_assert(ss7pc_hash_table == NULL);
2418 ss7pc_hash_table = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
2421 * Load the user's ss7pcs file
2423 ss7pcspath = get_persconffile_path(ENAME_SS7PCS, TRUE);
2424 if (!read_ss7pcs_file(ss7pcspath) && errno != ENOENT) {
2425 report_open_failure(ss7pcspath, errno, FALSE);
2430 /* SS7PC Name Resolution End*/
2434 * External Functions
2438 addr_resolve_pref_init(module_t *nameres)
2440 prefs_register_bool_preference(nameres, "mac_name",
2441 "Resolve MAC addresses",
2442 "Resolve Ethernet MAC addresses to host names from the preferences"
2443 " or system's Ethers file, or to a manufacturer based name.",
2444 &gbl_resolv_flags.mac_name);
2446 prefs_register_bool_preference(nameres, "transport_name",
2447 "Resolve transport names",
2448 "Resolve TCP/UDP ports into service names",
2449 &gbl_resolv_flags.transport_name);
2451 prefs_register_bool_preference(nameres, "network_name",
2452 "Resolve network (IP) addresses",
2453 "Resolve IPv4, IPv6, and IPX addresses into host names."
2454 " The next set of check boxes determines how name resolution should be performed."
2455 " If no other options are checked name resolution is made from Wireshark's host file,"
2456 " capture file name resolution blocks and DNS packets in the capture.",
2457 &gbl_resolv_flags.network_name);
2459 prefs_register_bool_preference(nameres, "dns_pkt_addr_resolution",
2460 "Use captured DNS packet data for address resolution",
2461 "Whether address/name pairs found in captured DNS packets should be used by Wireshark for name resolution.",
2462 &gbl_resolv_flags.dns_pkt_addr_resolution);
2465 prefs_register_bool_preference(nameres, "use_external_name_resolver",
2466 "Use an external network name resolver",
2467 "Use your system's configured name resolver"
2468 " (usually DNS) to resolve network names."
2469 " Only applies when network name resolution"
2471 &gbl_resolv_flags.use_external_net_name_resolver);
2473 prefs_register_obsolete_preference(nameres, "concurrent_dns");
2475 prefs_register_uint_preference(nameres, "name_resolve_concurrency",
2476 "Maximum concurrent requests",
2477 "The maximum number of DNS requests that may"
2478 " be active at any time. A large value (many"
2479 " thousands) might overload the network or make"
2480 " your DNS server behave badly.",
2482 &name_resolve_concurrency);
2484 prefs_register_static_text_preference(nameres, "use_external_name_resolver",
2485 "Use an external network name resolver: N/A",
2486 "Support for using a concurrent external name resolver was not"
2487 " compiled into this version of Wireshark");
2490 prefs_register_bool_preference(nameres, "hosts_file_handling",
2491 "Only use the profile \"hosts\" file",
2492 "By default \"hosts\" files will be loaded from multiple sources."
2493 " Checking this box only loads the \"hosts\" in the current profile.",
2494 &gbl_resolv_flags.load_hosts_file_from_profile_only);
2496 prefs_register_bool_preference(nameres, "vlan_name",
2498 "Resolve VLAN IDs to network names from the preferences \"vlans\" file."
2499 " Format of the file is: \"ID<Tab>Name\"."
2500 " One line per VLAN, e.g.: 1 Management",
2501 &gbl_resolv_flags.vlan_name);
2503 prefs_register_bool_preference(nameres, "ss7_pc_name",
2505 "Resolve SS7 Point Codes to node names from the profiles \"ss7pcs\" file."
2506 " Format of the file is: \"Network_Indicator<Dash>PC_Decimal<Tab>Name\"."
2507 " One line per Point Code, e.g.: 2-1234 MyPointCode1",
2508 &gbl_resolv_flags.ss7pc_name);
2513 disable_name_resolution(void) {
2514 gbl_resolv_flags.mac_name = FALSE;
2515 gbl_resolv_flags.network_name = FALSE;
2516 gbl_resolv_flags.transport_name = FALSE;
2517 gbl_resolv_flags.dns_pkt_addr_resolution = FALSE;
2518 gbl_resolv_flags.use_external_net_name_resolver = FALSE;
2519 gbl_resolv_flags.vlan_name = FALSE;
2520 gbl_resolv_flags.ss7pc_name = FALSE;
2525 host_name_lookup_process(void) {
2526 async_dns_queue_msg_t *caqm;
2527 struct timeval tv = { 0, 0 };
2530 gboolean nro = new_resolved_objects;
2531 wmem_list_frame_t* head;
2533 new_resolved_objects = FALSE;
2535 if (!async_dns_initialized)
2536 /* c-ares not initialized. Bail out and cancel timers. */
2539 head = wmem_list_head(async_dns_queue_head);
2541 while (head != NULL && async_dns_in_flight <= name_resolve_concurrency) {
2542 caqm = (async_dns_queue_msg_t *)wmem_list_frame_data(head);
2543 wmem_list_remove_frame(async_dns_queue_head, head);
2544 if (caqm->family == AF_INET) {
2545 ares_gethostbyaddr(ghba_chan, &caqm->addr.ip4, sizeof(guint32), AF_INET,
2546 c_ares_ghba_cb, caqm);
2547 async_dns_in_flight++;
2548 } else if (caqm->family == AF_INET6) {
2549 ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(ws_in6_addr),
2550 AF_INET6, c_ares_ghba_cb, caqm);
2551 async_dns_in_flight++;
2554 head = wmem_list_head(async_dns_queue_head);
2559 nfds = ares_fds(ghba_chan, &rfds, &wfds);
2561 if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
2562 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
2565 ares_process(ghba_chan, &rfds, &wfds);
2568 /* Any new entries? */
2573 _host_name_lookup_cleanup(void) {
2574 async_dns_queue_head = NULL;
2576 if (async_dns_initialized) {
2577 ares_destroy(ghba_chan);
2578 ares_destroy(ghbn_chan);
2580 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2581 ares_library_cleanup();
2583 async_dns_initialized = FALSE;
2589 host_name_lookup_process(void) {
2590 gboolean nro = new_resolved_objects;
2592 new_resolved_objects = FALSE;
2598 _host_name_lookup_cleanup(void) {
2601 #endif /* HAVE_C_ARES */
2604 get_hostname(const guint addr)
2606 /* XXX why do we call this if we're not resolving? To create hash entries?
2609 hashipv4_t *tp = host_lookup(addr);
2611 if (!gbl_resolv_flags.network_name)
2614 tp->flags |= RESOLVED_ADDRESS_USED;
2619 /* -------------------------- */
2622 get_hostname6(const ws_in6_addr *addr)
2624 /* XXX why do we call this if we're not resolving? To create hash entries?
2627 hashipv6_t *tp = host_lookup6(addr);
2629 if (!gbl_resolv_flags.network_name)
2632 tp->flags |= RESOLVED_ADDRESS_USED;
2637 /* -------------------------- */
2639 add_ipv4_name(const guint addr, const gchar *name)
2644 * Don't add zero-length names; apparently, some resolvers will return
2645 * them if they get them from DNS.
2647 if (!name || name[0] == '\0')
2650 tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
2652 tp = new_ipv4(addr);
2653 wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
2656 if (g_ascii_strcasecmp(tp->name, name)) {
2657 g_strlcpy(tp->name, name, MAXNAMELEN);
2658 new_resolved_objects = TRUE;
2660 tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
2661 } /* add_ipv4_name */
2663 /* -------------------------- */
2665 add_ipv6_name(const ws_in6_addr *addrp, const gchar *name)
2670 * Don't add zero-length names; apparently, some resolvers will return
2671 * them if they get them from DNS.
2673 if (!name || name[0] == '\0')
2676 tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addrp);
2678 ws_in6_addr *addr_key;
2680 addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr);
2681 tp = new_ipv6(addrp);
2682 memcpy(addr_key, addrp, 16);
2683 wmem_map_insert(ipv6_hash_table, addr_key, tp);
2686 if (g_ascii_strcasecmp(tp->name, name)) {
2687 g_strlcpy(tp->name, name, MAXNAMELEN);
2688 new_resolved_objects = TRUE;
2690 tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
2691 } /* add_ipv6_name */
2694 add_manually_resolved_ipv4(gpointer data, gpointer user_data _U_)
2696 resolved_ipv4_t *resolved_ipv4_entry = (resolved_ipv4_t *)data;
2698 add_ipv4_name(resolved_ipv4_entry->host_addr, resolved_ipv4_entry->name);
2702 add_manually_resolved_ipv6(gpointer data, gpointer user_data _U_)
2704 resolved_ipv6_t *resolved_ipv6_entry = (resolved_ipv6_t *)data;
2706 add_ipv6_name(&(resolved_ipv6_entry->ip6_addr), resolved_ipv6_entry->name);
2710 add_manually_resolved(void)
2712 if (manually_resolved_ipv4_list) {
2713 wmem_list_foreach(manually_resolved_ipv4_list, add_manually_resolved_ipv4, NULL);
2716 if (manually_resolved_ipv6_list) {
2717 wmem_list_foreach(manually_resolved_ipv6_list, add_manually_resolved_ipv6, NULL);
2722 host_name_lookup_init(void)
2727 g_assert(ipxnet_hash_table == NULL);
2728 ipxnet_hash_table = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
2730 g_assert(ipv4_hash_table == NULL);
2731 ipv4_hash_table = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
2733 g_assert(ipv6_hash_table == NULL);
2734 ipv6_hash_table = wmem_map_new(wmem_epan_scope(), ipv6_oat_hash, ipv6_equal);
2737 g_assert(async_dns_queue_head == NULL);
2738 async_dns_queue_head = wmem_list_new(wmem_epan_scope());
2741 if (manually_resolved_ipv4_list == NULL)
2742 manually_resolved_ipv4_list = wmem_list_new(wmem_epan_scope());
2744 if (manually_resolved_ipv6_list == NULL)
2745 manually_resolved_ipv6_list = wmem_list_new(wmem_epan_scope());
2748 * Load the global hosts file, if we have one.
2750 if (!gbl_resolv_flags.load_hosts_file_from_profile_only) {
2751 hostspath = get_datafile_path(ENAME_HOSTS);
2752 if (!read_hosts_file(hostspath, TRUE) && errno != ENOENT) {
2753 report_open_failure(hostspath, errno, FALSE);
2758 * Load the user's hosts file no matter what, if they have one.
2760 hostspath = get_persconffile_path(ENAME_HOSTS, TRUE);
2761 if (!read_hosts_file(hostspath, TRUE) && errno != ENOENT) {
2762 report_open_failure(hostspath, errno, FALSE);
2766 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2767 if (ares_library_init(ARES_LIB_INIT_ALL) == ARES_SUCCESS) {
2769 if (ares_init(&ghba_chan) == ARES_SUCCESS && ares_init(&ghbn_chan) == ARES_SUCCESS) {
2770 async_dns_initialized = TRUE;
2772 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2776 #endif /* HAVE_C_ARES */
2778 if (extra_hosts_files && !gbl_resolv_flags.load_hosts_file_from_profile_only) {
2779 for (i = 0; i < extra_hosts_files->len; i++) {
2780 read_hosts_file((const char *) g_ptr_array_index(extra_hosts_files, i), TRUE);
2784 subnet_name_lookup_init();
2786 add_manually_resolved();
2788 ss7pc_name_lookup_init();
2792 host_name_lookup_cleanup(void)
2795 sub_net_hashipv4_t *entry, *next_entry;
2797 _host_name_lookup_cleanup();
2799 ipxnet_hash_table = NULL;
2800 ipv4_hash_table = NULL;
2801 ipv6_hash_table = NULL;
2802 ss7pc_hash_table = NULL;
2804 for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
2805 if (subnet_length_entries[i].subnet_addresses != NULL) {
2806 for (j = 0; j < HASHHOSTSIZE; j++) {
2807 for (entry = subnet_length_entries[i].subnet_addresses[j];
2808 entry != NULL; entry = next_entry) {
2809 next_entry = entry->next;
2810 wmem_free(wmem_epan_scope(), entry);
2813 wmem_free(wmem_epan_scope(), subnet_length_entries[i].subnet_addresses);
2814 subnet_length_entries[i].subnet_addresses = NULL;
2818 have_subnet_entry = FALSE;
2819 new_resolved_objects = FALSE;
2823 manually_resolve_cleanup(void)
2825 wmem_destroy_list(manually_resolved_ipv4_list);
2826 manually_resolved_ipv4_list = NULL;
2827 wmem_destroy_list(manually_resolved_ipv6_list);
2828 manually_resolved_ipv6_list = NULL;
2832 udp_port_to_display(wmem_allocator_t *allocator, guint port)
2835 if (!gbl_resolv_flags.transport_name) {
2836 return wmem_utoa(allocator, port);
2839 return wmem_strdup(allocator, serv_name_lookup(PT_UDP, port));
2841 } /* udp_port_to_display */
2844 dccp_port_to_display(wmem_allocator_t *allocator, guint port)
2847 if (!gbl_resolv_flags.transport_name) {
2848 return wmem_utoa(allocator, port);
2851 return wmem_strdup(allocator, serv_name_lookup(PT_DCCP, port));
2853 } /* dccp_port_to_display */
2856 tcp_port_to_display(wmem_allocator_t *allocator, guint port)
2859 if (!gbl_resolv_flags.transport_name) {
2860 return wmem_utoa(allocator, port);
2863 return wmem_strdup(allocator, serv_name_lookup(PT_TCP, port));
2865 } /* tcp_port_to_display */
2868 sctp_port_to_display(wmem_allocator_t *allocator, guint port)
2871 if (!gbl_resolv_flags.transport_name) {
2872 return wmem_utoa(allocator, port);
2875 return wmem_strdup(allocator, serv_name_lookup(PT_SCTP, port));
2877 } /* sctp_port_to_display */
2880 port_with_resolution_to_str(wmem_allocator_t *scope, port_type proto, guint port)
2882 const gchar *port_str;
2884 if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
2885 /* No name resolution support, just return port string */
2886 return wmem_strdup_printf(scope, "%u", port);
2888 port_str = serv_name_lookup(proto, port);
2890 return wmem_strdup_printf(scope, "%s (%u)", port_str, port);
2894 port_with_resolution_to_str_buf(gchar *buf, gulong buf_size, port_type proto, guint port)
2896 const gchar *port_str;
2898 if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
2899 /* No name resolution support, just return port string */
2900 return g_snprintf(buf, buf_size, "%u", port);
2902 port_str = serv_name_lookup(proto, port);
2904 return g_snprintf(buf, buf_size, "%s (%u)", port_str, port);
2908 get_ether_name(const guint8 *addr)
2911 gboolean resolve = gbl_resolv_flags.mac_name;
2913 tp = eth_name_lookup(addr, resolve);
2915 return resolve ? tp->resolved_name : tp->hexaddr;
2917 } /* get_ether_name */
2920 tvb_get_ether_name(tvbuff_t *tvb, gint offset)
2922 return get_ether_name(tvb_get_ptr(tvb, offset, 6));
2925 /* Look for a (non-dummy) ether name in the hash, and return it if found.
2926 * If it's not found, simply return NULL.
2929 get_ether_name_if_known(const guint8 *addr)
2933 /* Initialize ether structs if we're the first
2934 * ether-related function called */
2935 if (!gbl_resolv_flags.mac_name)
2938 /* eth_name_lookup will create a (resolved) hash entry if it doesn't exist */
2939 tp = eth_name_lookup(addr, TRUE);
2940 g_assert(tp != NULL);
2942 if (tp->status == HASHETHER_STATUS_RESOLVED_NAME) {
2943 /* Name is from an ethers file */
2944 return tp->resolved_name;
2947 /* Name was created */
2953 add_ether_byip(const guint ip, const guint8 *eth)
2957 /* first check that IP address can be resolved */
2958 if (!gbl_resolv_flags.network_name)
2961 tp = host_lookup(ip);
2964 * Was this IP address resolved to a host name?
2966 if (tp->flags & NAME_RESOLVED) {
2968 * Yes, so add an entry in the ethers hashtable resolving
2969 * the MAC address to that name.
2971 add_eth_name(eth, tp->name);
2974 } /* add_ether_byip */
2977 ipxnet_to_str_punct(wmem_allocator_t *allocator, const guint32 ad, const char punct)
2979 gchar *buf = (gchar *)wmem_alloc(allocator, 12);
2981 *dword_to_hex_punct(buf, ad, punct) = '\0';
2986 get_ipxnet_name(wmem_allocator_t *allocator, const guint32 addr)
2989 if (!gbl_resolv_flags.network_name) {
2990 return ipxnet_to_str_punct(allocator, addr, '\0');
2993 return ipxnet_name_lookup(allocator, addr);
2995 } /* get_ipxnet_name */
2998 get_vlan_name(wmem_allocator_t *allocator, const guint16 id)
3001 if (!gbl_resolv_flags.vlan_name) {
3005 return wmem_strdup(allocator, vlan_name_lookup(id));
3007 } /* get_vlan_name */
3010 get_manuf_name(const guint8 *addr)
3012 hashmanuf_t *manuf_value;
3014 manuf_value = manuf_name_lookup(addr);
3015 if (gbl_resolv_flags.mac_name && manuf_value->status != HASHETHER_STATUS_UNRESOLVED)
3016 return manuf_value->resolved_name;
3018 return manuf_value->hexaddr;
3020 } /* get_manuf_name */
3023 tvb_get_manuf_name(tvbuff_t *tvb, gint offset)
3025 return get_manuf_name(tvb_get_ptr(tvb, offset, 3));
3029 get_manuf_name_if_known(const guint8 *addr)
3031 hashmanuf_t *manuf_value;
3035 /* manuf needs only the 3 most significant octets of the ethernet address */
3036 manuf_key = addr[0];
3037 manuf_key = manuf_key<<8;
3039 manuf_key = manuf_key | oct;
3040 manuf_key = manuf_key<<8;
3042 manuf_key = manuf_key | oct;
3044 manuf_value = (hashmanuf_t *)wmem_map_lookup(manuf_hashtable, &manuf_key);
3045 if ((manuf_value == NULL) || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
3049 return manuf_value->resolved_longname;
3051 } /* get_manuf_name_if_known */
3054 uint_get_manuf_name_if_known(const guint manuf_key)
3056 hashmanuf_t *manuf_value;
3058 manuf_value = (hashmanuf_t *)wmem_map_lookup(manuf_hashtable, &manuf_key);
3059 if ((manuf_value == NULL) || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
3063 return manuf_value->resolved_longname;
3067 tvb_get_manuf_name_if_known(tvbuff_t *tvb, gint offset)
3069 return get_manuf_name_if_known(tvb_get_ptr(tvb, offset, 3));
3072 char* get_hash_manuf_resolved_name(hashmanuf_t* manuf)
3074 return manuf->resolved_longname;
3078 eui64_to_display(wmem_allocator_t *allocator, const guint64 addr_eui64)
3080 guint8 *addr = (guint8 *)wmem_alloc(NULL, 8);
3081 hashmanuf_t *manuf_value;
3084 /* Copy and convert the address to network byte order. */
3085 *(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64));
3087 manuf_value = manuf_name_lookup(addr);
3088 if (!gbl_resolv_flags.mac_name || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
3089 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]);
3091 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]);
3094 wmem_free(NULL, addr);
3096 } /* eui64_to_display */
3099 #define GHI_TIMEOUT (250 * 1000)
3101 c_ares_ghi_cb(void *arg, int status, int timeouts _U_, struct hostent *hp) {
3103 * XXX - If we wanted to be really fancy we could cache results here and
3104 * look them up in get_host_ipaddr* below.
3106 async_hostent_t *ahp = (async_hostent_t *)arg;
3107 if (status == ARES_SUCCESS && hp && ahp && hp->h_length == ahp->addr_size) {
3108 memcpy(ahp->addrp, hp->h_addr, hp->h_length);
3109 ahp->copied = hp->h_length;
3112 #endif /* HAVE_C_ARES */
3114 /* Translate a string, assumed either to be a dotted-quad IPv4 address or
3115 * a host name, to a numeric IPv4 address. Return TRUE if we succeed and
3116 * set "*addrp" to that numeric IPv4 address; return FALSE if we fail. */
3118 get_host_ipaddr(const char *host, guint32 *addrp)
3121 struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
3124 async_hostent_t ahe;
3128 * XXX - are there places where this is used to translate something
3129 * that's *only* supposed to be an IPv4 address, and where it
3130 * *shouldn't* translate host names?
3132 if (!ws_inet_pton4(host, addrp)) {
3134 /* It's not a valid dotted-quad IP address; is it a valid
3138 /* If we're not allowed to do name resolution, don't do name
3141 if (!gbl_resolv_flags.network_name ||
3142 !gbl_resolv_flags.use_external_net_name_resolver) {
3147 if (!async_dns_initialized || name_resolve_concurrency < 1) {
3150 ahe.addr_size = (int) sizeof (struct in_addr);
3153 ares_gethostbyname(ghbn_chan, host, AF_INET, c_ares_ghi_cb, &ahe);
3156 nfds = ares_fds(ghbn_chan, &rfds, &wfds);
3158 tvp = ares_timeout(ghbn_chan, &tv, &tv);
3159 if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
3160 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
3163 ares_process(ghbn_chan, &rfds, &wfds);
3165 ares_cancel(ghbn_chan);
3166 if (ahe.addr_size == ahe.copied) {
3177 * Translate IPv6 numeric address or FQDN hostname into binary IPv6 address.
3178 * Return TRUE if we succeed and set "*addrp" to that numeric IPv6 address;
3179 * return FALSE if we fail.
3182 get_host_ipaddr6(const char *host, ws_in6_addr *addrp)
3185 struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
3188 async_hostent_t ahe;
3189 #endif /* HAVE_C_ARES */
3191 if (str_to_ip6(host, addrp))
3194 /* It's not a valid dotted-quad IP address; is it a valid
3197 * XXX - are there places where this is used to translate something
3198 * that's *only* supposed to be an IPv6 address, and where it
3199 * *shouldn't* translate host names?
3202 /* If we're not allowed to do name resolution, don't do name
3205 if (!gbl_resolv_flags.network_name ||
3206 !gbl_resolv_flags.use_external_net_name_resolver) {
3212 if (!async_dns_initialized || name_resolve_concurrency < 1) {
3215 ahe.addr_size = (int) sizeof (ws_in6_addr);
3218 ares_gethostbyname(ghbn_chan, host, AF_INET6, c_ares_ghi_cb, &ahe);
3221 nfds = ares_fds(ghbn_chan, &rfds, &wfds);
3223 tvp = ares_timeout(ghbn_chan, &tv, &tv);
3224 if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
3225 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
3228 ares_process(ghbn_chan, &rfds, &wfds);
3230 ares_cancel(ghbn_chan);
3231 if (ahe.addr_size == ahe.copied) {
3240 get_manuf_hashtable(void)
3242 return manuf_hashtable;
3246 get_wka_hashtable(void)
3248 return wka_hashtable;
3252 get_eth_hashtable(void)
3254 return eth_hashtable;
3258 get_serv_port_hashtable(void)
3260 return serv_port_hashtable;
3264 get_ipxnet_hash_table(void)
3266 return ipxnet_hash_table;
3270 get_vlan_hash_table(void)
3272 return vlan_hash_table;
3276 get_ipv4_hash_table(void)
3278 return ipv4_hash_table;
3282 get_ipv6_hash_table(void)
3284 return ipv6_hash_table;
3286 /* Initialize all the address resolution subsystems in this file */
3288 addr_resolv_init(void)
3290 initialize_services();
3291 initialize_ethers();
3292 initialize_ipxnets();
3294 initialize_enterprises();
3295 /* host name initialization is done on a per-capture-file basis */
3296 /*host_name_lookup_init();*/
3299 /* Clean up all the address resolution subsystems in this file */
3301 addr_resolv_cleanup(void)
3303 vlan_name_lookup_cleanup();
3304 service_name_lookup_cleanup();
3306 ipx_name_lookup_cleanup();
3307 enterprises_cleanup();
3308 /* host name initialization is done on a per-capture-file basis */
3309 /*host_name_lookup_cleanup();*/
3313 str_to_ip(const char *str, void *dst)
3315 return ws_inet_pton4(str, (guint32 *)dst);
3319 str_to_ip6(const char *str, void *dst)
3321 return ws_inet_pton6(str, (ws_in6_addr *)dst);
3325 * Editor modelines - http://www.wireshark.org/tools/modelines.html
3330 * indent-tabs-mode: nil
3333 * vi: set shiftwidth=4 tabstop=8 expandtab:
3334 * :indentSize=4:tabSize=8:noTabs=true: