FIXUP: WIP: verification_trailer
[wireshark-wip.git] / epan / addr_resolv.c
blob4322d1cb2a75f43f769e0d9f6d0fce84e93c780d
1 /* addr_resolv.c
2 * Routines for network object lookup
4 * $Id$
6 * Laurent Deniel <laurent.deniel@free.fr>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "config.h"
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
36 * Win32 doesn't have SIGALRM (and it's the OS where name lookup calls
37 * are most likely to take a long time, given the way address-to-name
38 * lookups are done over NBNS).
40 * Mac OS X does have SIGALRM, but if you longjmp() out of a name resolution
41 * call in a signal handler, you might crash, because the state of the
42 * resolution code that sends messages to lookupd might be inconsistent
43 * if you jump out of it in middle of a call.
45 * In at least some Linux distributions (e.g., RedHat Linux 9), if ADNS
46 * is used, we appear to hang in host_name_lookup6() in a gethostbyaddr()
47 * call (and possibly in other gethostbyaddr() calls), because there's
48 * a mutex lock held in gethostbyaddr() and it doesn't get released
49 * if we longjmp out of it.
51 * There's no guarantee that longjmp()ing out of name resolution calls
52 * will work on *any* platform; OpenBSD got rid of the alarm/longjmp
53 * code in tcpdump, to avoid those sorts of problems, and that was
54 * picked up by tcpdump.org tcpdump.
56 * So, for now, we do not define AVOID_DNS_TIMEOUT. If we get a
57 * significantly more complaints about lookups taking a long time,
58 * we can reconsider that decision. (Note that tcpdump originally
59 * added that for the benefit of systems using NIS to look up host
60 * names; that might now be fixed in NIS implementations, for those
61 * sites still using NIS rather than DNS for that....)
64 #ifdef HAVE_UNISTD_H
65 #include <unistd.h>
66 #endif
68 #ifdef HAVE_NETINET_IN_H
69 # include <netinet/in.h>
70 #endif
72 #ifdef HAVE_NETDB_H
73 #include <netdb.h>
74 #endif
76 #ifdef HAVE_ARPA_INET_H
77 #include <arpa/inet.h>
78 #endif
80 #include <signal.h>
82 #ifdef HAVE_SYS_SOCKET_H
83 #include <sys/socket.h> /* needed to define AF_ values on UNIX */
84 #endif
86 #ifdef HAVE_WINSOCK2_H
87 #include <winsock2.h> /* needed to define AF_ values on Windows */
88 #endif
90 #ifndef HAVE_INET_ATON_H
91 # include "wsutil/inet_aton.h"
92 #endif
94 #ifdef NEED_INET_V6DEFS_H
95 # include "wsutil/inet_v6defs.h"
96 #endif
98 #if defined(_WIN32) && defined(INET6)
99 # include <ws2tcpip.h>
100 #endif
102 #ifdef HAVE_C_ARES
103 # if defined(_WIN32) && !defined(INET6)
104 # define socklen_t unsigned int
105 # endif
106 # include <ares.h>
107 # include <ares_version.h>
108 #else
109 # ifdef HAVE_GNU_ADNS
110 # include <errno.h>
111 # include <adns.h>
112 # if defined(inet_aton) && defined(_WIN32)
113 # undef inet_aton
114 # endif
115 # endif /* HAVE_GNU_ADNS */
116 #endif /* HAVE_C_ARES */
119 #include <glib.h>
121 #include "packet.h"
122 #include "addr_and_mask.h"
123 #include "ipv6-utils.h"
124 #include "addr_resolv.h"
125 #include "filesystem.h"
127 #include <wsutil/report_err.h>
128 #include <wsutil/file_util.h>
129 #include <wsutil/pint.h>
131 #include <epan/strutil.h>
132 #include <epan/prefs.h>
133 #include <epan/emem.h>
135 #define ENAME_HOSTS "hosts"
136 #define ENAME_SUBNETS "subnets"
137 #define ENAME_ETHERS "ethers"
138 #define ENAME_IPXNETS "ipxnets"
139 #define ENAME_MANUF "manuf"
140 #define ENAME_SERVICES "services"
142 #define HASHETHSIZE 2048
143 #define HASHHOSTSIZE 2048
144 #define HASHIPXNETSIZE 256
145 #define SUBNETLENGTHSIZE 32 /*1-32 inc.*/
147 /* g_int64_hash() and g_int64_equal() first appear in GLib 2.22, make a local copy here */
148 #if !GLIB_CHECK_VERSION(2,22,0)
150 * g_int64_equal:
151 * @v1: a pointer to a #gint64 key
152 * @v2: a pointer to a #gint64 key to compare with @v1
154 * Compares the two #gint64 values being pointed to and returns
155 * %TRUE if they are equal.
156 * It can be passed to g_hash_table_new() as the @key_equal_func
157 * parameter, when using non-%NULL pointers to 64-bit integers as keys in a
158 * #GHashTable.
160 * Returns: %TRUE if the two keys match.
162 * Since: 2.22
164 static gboolean
165 g_int64_equal (gconstpointer v1,
166 gconstpointer v2)
168 return *((const gint64*) v1) == *((const gint64*) v2);
172 * g_int64_hash:
173 * @v: a pointer to a #gint64 key
175 * Converts a pointer to a #gint64 to a hash value.
177 * It can be passed to g_hash_table_new() as the @hash_func parameter,
178 * when using non-%NULL pointers to 64-bit integer values as keys in a
179 * #GHashTable.
181 * Returns: a hash value corresponding to the key.
183 * Since: 2.22
185 static guint
186 g_int64_hash (gconstpointer v)
188 return (guint) *(const gint64*) v;
191 #endif /* GLIB_CHECK_VERSION(2,22,0) */
192 /* hash table used for IPv4 lookup */
194 #define HASH_IPV4_ADDRESS(addr) (g_htonl(addr) & (HASHHOSTSIZE - 1))
197 typedef struct sub_net_hashipv4 {
198 guint addr;
199 guint8 flags; /* B0 dummy_entry, B1 resolve, B2 If the address is used in the trace */
200 struct sub_net_hashipv4 *next;
201 gchar ip[16];
202 gchar name[MAXNAMELEN];
203 } sub_net_hashipv4_t;
205 /* Array of entries of subnets of different lengths */
206 typedef struct {
207 gsize mask_length; /*1-32*/
208 guint32 mask; /* e.g. 255.255.255.*/
209 sub_net_hashipv4_t** subnet_addresses; /* Hash table of subnet addresses */
210 } subnet_length_entry_t;
213 #if 0
214 typedef struct serv_port {
215 gchar *udp_name;
216 gchar *tcp_name;
217 gchar *sctp_name;
218 gchar *dccp_name;
219 } serv_port_t;
220 #endif
221 /* hash table used for IPX network lookup */
223 /* XXX - check goodness of hash function */
225 #define HASH_IPX_NET(net) ((net) & (HASHIPXNETSIZE - 1))
227 typedef struct hashipxnet {
228 guint addr;
229 struct hashipxnet *next;
230 gchar name[MAXNAMELEN];
231 } hashipxnet_t;
233 /* hash tables used for ethernet and manufacturer lookup */
234 #define HASHETHER_STATUS_UNRESOLVED 1
235 #define HASHETHER_STATUS_RESOLVED_DUMMY 2
236 #define HASHETHER_STATUS_RESOLVED_NAME 3
238 #if 0
239 typedef struct hashether {
240 struct hashether *next;
241 guint status; /* (See above) */
242 guint8 addr[6];
243 char hexaddr[6*3];
244 char resolved_name[MAXNAMELEN];
245 } hashether_t;
246 #endif
247 /* internal ethernet type */
249 typedef struct _ether
251 guint8 addr[6];
252 char name[MAXNAMELEN];
253 } ether_t;
255 /* internal ipxnet type */
257 typedef struct _ipxnet
259 guint addr;
260 char name[MAXNAMELEN];
261 } ipxnet_t;
263 static GHashTable *ipxnet_hash_table = NULL;
264 static GHashTable *ipv4_hash_table = NULL;
265 static GHashTable *ipv6_hash_table = NULL;
267 static GSList *manually_resolved_ipv4_list = NULL;
268 static GSList *manually_resolved_ipv6_list = NULL;
270 typedef struct _resolved_ipv4
272 guint32 host_addr;
273 char name[MAXNAMELEN];
274 } resolved_ipv4_t;
276 typedef struct _resolved_ipv6
278 struct e_in6_addr ip6_addr;
279 char name[MAXNAMELEN];
280 } resolved_ipv6_t;
282 static addrinfo_lists_t addrinfo_lists = { NULL, NULL};
284 static gchar *cb_service;
285 static port_type cb_proto = PT_NONE;
288 static GHashTable *manuf_hashtable = NULL;
289 static GHashTable *wka_hashtable = NULL;
290 static GHashTable *eth_hashtable = NULL;
291 static GHashTable *serv_port_hashtable = NULL;
293 static subnet_length_entry_t subnet_length_entries[SUBNETLENGTHSIZE]; /* Ordered array of entries */
294 static gboolean have_subnet_entry = FALSE;
296 static gboolean new_resolved_objects = FALSE;
298 static GPtrArray* extra_hosts_files = NULL;
300 static hashether_t *add_eth_name(const guint8 *addr, const gchar *name);
301 static void add_serv_port_cb(const guint32 port);
304 /* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
305 * One-at-a-Time hash
307 static guint32
308 ipv6_oat_hash(gconstpointer key)
310 int len = 16;
311 const unsigned char *p = (const unsigned char *)key;
312 guint32 h = 0;
313 int i;
315 for ( i = 0; i < len; i++ ) {
316 h += p[i];
317 h += ( h << 10 );
318 h ^= ( h >> 6 );
321 h += ( h << 3 );
322 h ^= ( h >> 11 );
323 h += ( h << 15 );
325 return h;
328 static gboolean
329 ipv6_equal(gconstpointer v1, gconstpointer v2)
332 if( memcmp(v1, v2, sizeof (struct e_in6_addr)) == 0 ) {
333 return TRUE;
336 return FALSE;
340 * Flag controlling what names to resolve.
342 e_addr_resolve gbl_resolv_flags = {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE};
343 #if defined(HAVE_C_ARES) || defined(HAVE_GNU_ADNS)
344 static guint name_resolve_concurrency = 500;
345 #endif
348 * Global variables (can be changed in GUI sections)
349 * XXX - they could be changed in GUI code, but there's currently no
350 * GUI code to change them.
353 gchar *g_ethers_path = NULL; /* global ethers file */
354 gchar *g_pethers_path = NULL; /* personal ethers file */
355 gchar *g_ipxnets_path = NULL; /* global ipxnets file */
356 gchar *g_pipxnets_path = NULL; /* personal ipxnets file */
357 gchar *g_services_path = NULL; /* global services file */
358 gchar *g_pservices_path = NULL; /* personal services file */
359 /* first resolving call */
361 /* c-ares */
362 #ifdef HAVE_C_ARES
364 * Submitted queries trigger a callback (c_ares_ghba_cb()).
365 * Queries are added to c_ares_queue_head. During processing, queries are
366 * popped off the front of c_ares_queue_head and submitted using
367 * ares_gethostbyaddr().
368 * The callback processes the response, then frees the request.
370 #define ASYNC_DNS
371 typedef struct _async_dns_queue_msg
373 union {
374 guint32 ip4;
375 struct e_in6_addr ip6;
376 } addr;
377 int family;
378 } async_dns_queue_msg_t;
380 typedef struct _async_hostent {
381 int addr_size;
382 int copied;
383 void *addrp;
384 } async_hostent_t;
386 #if ( ( ARES_VERSION_MAJOR < 1 ) \
387 || ( 1 == ARES_VERSION_MAJOR && ARES_VERSION_MINOR < 5 ) )
388 static void c_ares_ghba_cb(void *arg, int status, struct hostent *hostent);
389 #else
390 static void c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *hostent);
391 #endif
393 ares_channel ghba_chan; /* ares_gethostbyaddr -- Usually non-interactive, no timeout */
394 ares_channel ghbn_chan; /* ares_gethostbyname -- Usually interactive, timeout */
396 #else
397 /* GNU ADNS */
398 #ifdef HAVE_GNU_ADNS
399 #define ASYNC_DNS
401 * Submitted queries have to be checked individually using adns_check().
402 * Queries are added to adns_queue_head. During processing, the list is
403 * iterated twice: once to request queries up to the concurrency limit,
404 * and once to check the status of each query.
407 adns_state ads;
409 typedef struct _async_dns_queue_msg
411 gboolean submitted;
412 guint32 ip4_addr;
413 int type;
414 adns_query query;
415 } async_dns_queue_msg_t;
417 #endif /* HAVE_GNU_ADNS */
418 #endif /* HAVE_C_ARES */
419 #ifdef ASYNC_DNS
420 static gboolean async_dns_initialized = FALSE;
421 static guint async_dns_in_flight = 0;
422 static GList *async_dns_queue_head = NULL;
424 /* push a dns request */
425 static void
426 add_async_dns_ipv4(int type, guint32 addr)
428 async_dns_queue_msg_t *msg;
430 msg = g_new(async_dns_queue_msg_t,1);
431 #ifdef HAVE_C_ARES
432 msg->family = type;
433 msg->addr.ip4 = addr;
434 #else
435 msg->type = type;
436 msg->ip4_addr = addr;
437 msg->submitted = FALSE;
438 #endif
439 async_dns_queue_head = g_list_append(async_dns_queue_head, (gpointer) msg);
442 #endif
444 typedef struct {
445 guint32 mask;
446 gsize mask_length;
447 const gchar* name; /* Shallow copy */
448 } subnet_entry_t;
451 * Miscellaneous functions
454 static int
455 fgetline(char **buf, int *size, FILE *fp)
457 int len;
458 int c;
460 if (fp == NULL || buf == NULL)
461 return -1;
463 if (*buf == NULL) {
464 if (*size == 0)
465 *size = BUFSIZ;
467 *buf = (char *)g_malloc(*size);
470 g_assert(*buf);
471 g_assert(*size > 0);
473 if (feof(fp))
474 return -1;
476 len = 0;
477 while ((c = getc(fp)) != EOF && c != '\r' && c != '\n') {
478 if (len+1 >= *size) {
479 *buf = (char *)g_realloc(*buf, *size += BUFSIZ);
481 (*buf)[len++] = c;
484 if (len == 0 && c == EOF)
485 return -1;
487 (*buf)[len] = '\0';
489 return len;
491 } /* fgetline */
495 * Local function definitions
497 static subnet_entry_t subnet_lookup(const guint32 addr);
498 static void subnet_entry_set(guint32 subnet_addr, const guint32 mask_length, const gchar* name);
501 static void
502 add_service_name(port_type proto, const guint port, const char *service_name)
504 serv_port_t *serv_port_table;
505 int *key;
507 key = (int *)g_new(int, 1);
508 *key = port;
510 serv_port_table = (serv_port_t *)g_hash_table_lookup(serv_port_hashtable, &port);
511 if (serv_port_table == NULL) {
512 serv_port_table = g_new0(serv_port_t,1);
513 g_hash_table_insert(serv_port_hashtable, key, serv_port_table);
515 else {
516 g_free(key);
519 switch(proto){
520 case PT_TCP:
521 g_free(serv_port_table->tcp_name);
522 serv_port_table->tcp_name = g_strdup(service_name);
523 break;
524 case PT_UDP:
525 g_free(serv_port_table->udp_name);
526 serv_port_table->udp_name = g_strdup(service_name);
527 break;
528 case PT_SCTP:
529 g_free(serv_port_table->sctp_name);
530 serv_port_table->sctp_name = g_strdup(service_name);
531 break;
532 case PT_DCCP:
533 g_free(serv_port_table->dccp_name);
534 serv_port_table->dccp_name = g_strdup(service_name);
535 break;
536 default:
537 return;
538 /* Should not happen */
541 new_resolved_objects = TRUE;
545 static void
546 parse_service_line (char *line)
549 * See the services(4) or services(5) man page for services file format
550 * (not available on all systems).
553 gchar *cp;
554 gchar *service;
555 gchar *port;
556 port_type proto;
558 range_t *port_rng = NULL;
559 guint32 max_port = MAX_UDP_PORT;
561 if ((cp = strchr(line, '#')))
562 *cp = '\0';
564 if ((cp = strtok(line, " \t")) == NULL)
565 return;
567 service = cp;
569 if ((cp = strtok(NULL, " \t")) == NULL)
570 return;
572 port = cp;
574 if (strtok(cp, "/") == NULL)
575 return;
577 if ((cp = strtok(NULL, "/")) == NULL)
578 return;
580 /* seems we got all interesting things from the file */
581 if(strcmp(cp, "tcp") == 0) {
582 max_port = MAX_TCP_PORT;
583 proto = PT_TCP;
585 else if(strcmp(cp, "udp") == 0) {
586 max_port = MAX_UDP_PORT;
587 proto = PT_UDP;
589 else if(strcmp(cp, "sctp") == 0) {
590 max_port = MAX_SCTP_PORT;
591 proto = PT_SCTP;
593 else if(strcmp(cp, "dccp") == 0) {
594 max_port = MAX_DCCP_PORT;
595 proto = PT_DCCP;
596 } else {
597 return;
600 if(CVT_NO_ERROR != range_convert_str(&port_rng, port, max_port) ) {
601 /* some assertion here? */
602 return;
605 cb_service = service;
606 cb_proto = proto;
607 range_foreach(port_rng, add_serv_port_cb);
608 g_free (port_rng);
609 cb_proto = PT_NONE;
610 } /* parse_service_line */
613 static void
614 add_serv_port_cb(const guint32 port)
616 if ( port ) {
617 add_service_name(cb_proto, port, cb_service);
622 static void
623 parse_services_file(const char * path)
625 FILE *serv_p;
626 static int size = 0;
627 static char *buf = NULL;
629 /* services hash table initialization */
630 serv_p = ws_fopen(path, "r");
632 if (serv_p == NULL)
633 return;
635 while (fgetline(&buf, &size, serv_p) >= 0) {
636 parse_service_line (buf);
639 fclose(serv_p);
642 /* -----------------
643 * unsigned integer to ascii
645 static gchar *
646 ep_utoa(guint port)
648 gchar *bp = (gchar *)ep_alloc(MAXNAMELEN);
650 /* XXX, guint32_to_str() ? */
651 guint32_to_str_buf(port, bp, MAXNAMELEN);
652 return bp;
656 static gchar
657 *serv_name_lookup(const guint port, const port_type proto)
659 serv_port_t *serv_port_table;
660 gchar *name;
662 serv_port_table = (serv_port_t *)g_hash_table_lookup(serv_port_hashtable, &port);
664 if(serv_port_table){
665 /* Set which table we should look up port in */
666 switch(proto) {
667 case PT_UDP:
668 if(serv_port_table->udp_name){
669 return serv_port_table->udp_name;
671 break;
672 case PT_TCP:
673 if(serv_port_table->tcp_name){
674 return serv_port_table->tcp_name;
676 break;
677 case PT_SCTP:
678 if(serv_port_table->sctp_name){
679 return serv_port_table->sctp_name;
681 break;
682 case PT_DCCP:
683 if(serv_port_table->dccp_name){
684 return serv_port_table->dccp_name;
686 break;
687 default:
688 /* not yet implemented */
689 return NULL;
690 /*NOTREACHED*/
691 } /* proto */
694 /* getservbyport() was used here but it was to expensive, if the functionality is desired
695 * it would be better to pre parse etc/services or C:\Windows\System32\drivers\etc at
696 * startup
698 name = (gchar*)g_malloc(16);
699 guint32_to_str_buf(port, name, 16);
701 if(serv_port_table == NULL){
702 int *key;
704 key = (int *)g_new(int, 1);
705 *key = port;
706 serv_port_table = g_new0(serv_port_t,1);
707 g_hash_table_insert(serv_port_hashtable, key, serv_port_table);
709 switch(proto) {
710 case PT_UDP:
711 serv_port_table->udp_name = name;
712 break;
713 case PT_TCP:
714 serv_port_table->tcp_name = name;
715 break;
716 case PT_SCTP:
717 serv_port_table->sctp_name = name;
718 break;
719 case PT_DCCP:
720 serv_port_table->dccp_name = name;
721 break;
722 default:
723 return NULL;
724 /*NOTREACHED*/
726 return name;
728 } /* serv_name_lookup */
730 static void
731 destroy_serv_port(gpointer data)
733 serv_port_t *table = (serv_port_t*)data;
734 g_free(table->udp_name);
735 g_free(table->tcp_name);
736 g_free(table->sctp_name);
737 g_free(table->dccp_name);
738 g_free(table);
741 static void
742 initialize_services(void)
744 #ifdef _WIN32
745 char *hostspath;
746 char *sysroot;
747 static char rootpath_nt[] = "\\system32\\drivers\\etc\\services";
748 #endif /* _WIN32 */
750 /* the hash table won't ignore duplicates, so use the personal path first */
751 g_assert(serv_port_hashtable == NULL);
752 serv_port_hashtable = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, destroy_serv_port);
754 /* Read the system services file first */
755 #ifdef _WIN32
757 sysroot = getenv_utf8("WINDIR");
758 if (sysroot != NULL) {
760 * The file should be under WINDIR.
761 * If this is Windows NT (NT 4.0,2K,XP,Server2K3), it's in
762 * %WINDIR%\system32\drivers\etc\services.
764 hostspath = g_strconcat(sysroot, rootpath_nt, NULL);
765 parse_services_file(hostspath);
766 g_free(hostspath);
768 #else
769 parse_services_file("/etc/services");
771 #endif /* _WIN32 */
773 /* set personal services path */
774 if (g_pservices_path == NULL)
775 g_pservices_path = get_persconffile_path(ENAME_SERVICES, FALSE);
777 parse_services_file(g_pservices_path);
779 /* Compute the pathname of the services file. */
780 if (g_services_path == NULL) {
781 g_services_path = get_datafile_path(ENAME_SERVICES);
784 parse_services_file(g_services_path);
786 } /* initialize_services */
788 static void
789 service_name_lookup_cleanup(void)
791 if(serv_port_hashtable){
792 g_hash_table_destroy(serv_port_hashtable);
793 serv_port_hashtable = NULL;
797 /* Fill in an IP4 structure with info from subnets file or just with the
798 * string form of the address.
800 static void
801 fill_dummy_ip4(const guint addr, hashipv4_t* volatile tp)
803 subnet_entry_t subnet_entry;
805 if ((tp->flags & DUMMY_ADDRESS_ENTRY) == DUMMY_ADDRESS_ENTRY)
806 return; /* already done */
808 tp->flags = tp->flags | DUMMY_ADDRESS_ENTRY; /* Overwrite if we get async DNS reply */
810 /* Do we have a subnet for this address? */
811 subnet_entry = subnet_lookup(addr);
812 if(0 != subnet_entry.mask) {
813 /* Print name, then '.' then IP address after subnet mask */
814 guint32 host_addr;
815 gchar buffer[MAX_IP_STR_LEN];
816 gchar* paddr;
817 gsize i;
819 host_addr = addr & (~(guint32)subnet_entry.mask);
820 ip_to_str_buf((guint8 *)&host_addr, buffer, MAX_IP_STR_LEN);
821 paddr = buffer;
823 /* Skip to first octet that is not totally masked
824 * If length of mask is 32, we chomp the whole address.
825 * If the address string starts '.' (should not happen?),
826 * we skip that '.'.
828 i = subnet_entry.mask_length / 8;
829 while(*(paddr) != '\0' && i > 0) {
830 if(*(++paddr) == '.') {
831 --i;
835 /* There are more efficient ways to do this, but this is safe if we
836 * trust g_snprintf and MAXNAMELEN
838 g_snprintf(tp->name, MAXNAMELEN, "%s%s", subnet_entry.name, paddr);
839 } else {
840 ip_to_str_buf((const guint8 *)&addr, tp->name, MAXNAMELEN);
844 #ifdef HAVE_C_ARES
846 static void
847 c_ares_ghba_cb(
848 void *arg,
849 int status,
850 #if ( ( ARES_VERSION_MAJOR < 1 ) \
851 || ( 1 == ARES_VERSION_MAJOR && ARES_VERSION_MINOR < 5 ) )
852 struct hostent *he
853 #else
854 int timeouts _U_,
855 struct hostent *he
856 #endif
859 async_dns_queue_msg_t *caqm = (async_dns_queue_msg_t *)arg;
860 char **p;
862 if (!caqm) return;
863 /* XXX, what to do if async_dns_in_flight == 0? */
864 async_dns_in_flight--;
866 if (status == ARES_SUCCESS) {
867 for (p = he->h_addr_list; *p != NULL; p++) {
868 switch(caqm->family) {
869 case AF_INET:
870 add_ipv4_name(caqm->addr.ip4, he->h_name);
871 break;
872 case AF_INET6:
873 add_ipv6_name(&caqm->addr.ip6, he->h_name);
874 break;
875 default:
876 /* Throw an exception? */
877 break;
881 g_free(caqm);
883 #endif /* HAVE_C_ARES */
885 /* --------------- */
886 static hashipv4_t *
887 new_ipv4(const guint addr)
889 hashipv4_t *tp = g_new(hashipv4_t, 1);
890 tp->addr = addr;
891 tp->flags = 0;
892 ip_to_str_buf((const guint8 *)&addr, tp->ip, sizeof(tp->ip));
893 return tp;
896 static hashipv4_t *
897 host_lookup(const guint addr, gboolean *found)
899 hashipv4_t * volatile tp;
901 *found = TRUE;
903 tp = (hashipv4_t *)g_hash_table_lookup(ipv4_hash_table, &addr);
904 if(tp == NULL){
905 int *key;
907 key = (int *)g_new(int, 1);
908 *key = addr;
909 tp = new_ipv4(addr);
910 g_hash_table_insert(ipv4_hash_table, key, tp);
911 }else{
912 if ((tp->flags & DUMMY_AND_RESOLVE_FLGS) == DUMMY_ADDRESS_ENTRY){
913 goto try_resolv;
915 if ((tp->flags & DUMMY_ADDRESS_ENTRY) == DUMMY_ADDRESS_ENTRY){
916 *found = FALSE;
918 return tp;
921 try_resolv:
922 if (gbl_resolv_flags.network_name && gbl_resolv_flags.use_external_net_name_resolver) {
923 tp->flags = tp->flags|TRIED_RESOLVE_ADDRESS;
925 #ifdef ASYNC_DNS
926 if (gbl_resolv_flags.concurrent_dns &&
927 name_resolve_concurrency > 0 &&
928 async_dns_initialized) {
929 add_async_dns_ipv4(AF_INET, addr);
930 /* XXX found is set to TRUE, which seems a bit odd, but I'm not
931 * going to risk changing the semantics.
933 fill_dummy_ip4(addr, tp);
934 return tp;
936 #endif /* ASYNC_DNS */
938 /* unknown host or DNS timeout */
942 *found = FALSE;
944 fill_dummy_ip4(addr, tp);
945 return tp;
947 } /* host_lookup */
949 /* --------------- */
950 static hashipv6_t *
951 new_ipv6(const struct e_in6_addr *addr)
953 hashipv6_t *tp = g_new(hashipv6_t,1);
954 tp->addr = *addr;
955 tp->flags = 0;
956 ip6_to_str_buf(addr, tp->ip6);
957 return tp;
960 /* ------------------------------------ */
961 static hashipv6_t *
962 host_lookup6(const struct e_in6_addr *addr, gboolean *found)
964 hashipv6_t * volatile tp;
965 #ifdef INET6
966 #ifdef HAVE_C_ARES
967 async_dns_queue_msg_t *caqm;
968 #endif /* HAVE_C_ARES */
969 #endif /* INET6 */
971 *found = TRUE;
973 tp = (hashipv6_t *)g_hash_table_lookup(ipv6_hash_table, addr);
974 if(tp == NULL){
975 struct e_in6_addr *addr_key;
977 addr_key = g_new(struct e_in6_addr,1);
978 tp = new_ipv6(addr);
979 memcpy(addr_key, addr, 16);
980 g_hash_table_insert(ipv6_hash_table, addr_key, tp);
981 }else{
982 if ((tp->flags & DUMMY_AND_RESOLVE_FLGS) == DUMMY_ADDRESS_ENTRY){
983 goto try_resolv;
985 if ((tp->flags & DUMMY_ADDRESS_ENTRY) == DUMMY_ADDRESS_ENTRY){
986 *found = FALSE;
988 return tp;
991 try_resolv:
992 if (gbl_resolv_flags.network_name &&
993 gbl_resolv_flags.use_external_net_name_resolver) {
994 tp->flags = tp->flags|TRIED_RESOLVE_ADDRESS;
995 #ifdef INET6
997 #ifdef HAVE_C_ARES
998 if ((gbl_resolv_flags.concurrent_dns) &&
999 name_resolve_concurrency > 0 &&
1000 async_dns_initialized) {
1001 caqm = g_new(async_dns_queue_msg_t,1);
1002 caqm->family = AF_INET6;
1003 memcpy(&caqm->addr.ip6, addr, sizeof(caqm->addr.ip6));
1004 async_dns_queue_head = g_list_append(async_dns_queue_head, (gpointer) caqm);
1006 /* XXX found is set to TRUE, which seems a bit odd, but I'm not
1007 * going to risk changing the semantics.
1009 if ((tp->flags & DUMMY_ADDRESS_ENTRY) == 0){
1010 g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
1011 ip6_to_str_buf(addr, tp->name);
1012 tp->flags = tp->flags | DUMMY_ADDRESS_ENTRY;
1014 return tp;
1016 #endif /* HAVE_C_ARES */
1018 #endif /* INET6 */
1021 /* unknown host or DNS timeout */
1022 if ((tp->flags & DUMMY_ADDRESS_ENTRY) == 0) {
1023 tp->flags = tp->flags | DUMMY_ADDRESS_ENTRY;
1024 g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
1026 *found = FALSE;
1027 return tp;
1029 } /* host_lookup6 */
1031 static const gchar *
1032 solve_address_to_name(const address *addr)
1034 switch (addr->type) {
1036 case AT_ETHER:
1037 return get_ether_name((const guint8 *)addr->data);
1039 case AT_IPv4: {
1040 guint32 ip4_addr;
1041 memcpy(&ip4_addr, addr->data, sizeof ip4_addr);
1042 return get_hostname(ip4_addr);
1045 case AT_IPv6: {
1046 struct e_in6_addr ip6_addr;
1047 memcpy(&ip6_addr.bytes, addr->data, sizeof ip6_addr.bytes);
1048 return get_hostname6(&ip6_addr);
1051 case AT_STRINGZ:
1052 return (const gchar *)addr->data;
1054 default:
1055 return NULL;
1059 static const gchar *
1060 se_solve_address_to_name(const address *addr)
1062 switch (addr->type) {
1064 case AT_ETHER:
1065 return get_ether_name((const guint8 *)addr->data);
1067 case AT_IPv4: {
1068 guint32 ip4_addr;
1069 memcpy(&ip4_addr, addr->data, sizeof ip4_addr);
1070 return get_hostname(ip4_addr);
1073 case AT_IPv6: {
1074 struct e_in6_addr ip6_addr;
1075 memcpy(&ip6_addr.bytes, addr->data, sizeof ip6_addr.bytes);
1076 return get_hostname6(&ip6_addr);
1079 case AT_STRINGZ:
1080 return se_strdup((const gchar *)addr->data);
1082 default:
1083 return NULL;
1088 * Ethernet / manufacturer resolution
1090 * The following functions implement ethernet address resolution and
1091 * ethers files parsing (see ethers(4)).
1093 * The manuf file has the same format as ethers(4) except that names are
1094 * truncated to MAXMANUFLEN-1 (8) characters and that an address contains
1095 * only 3 bytes (instead of 6).
1097 * Notes:
1099 * I decide to not use the existing functions (see ethers(3) on some
1100 * operating systems) for the following reasons:
1101 * - performance gains (use of hash tables and some other enhancements),
1102 * - use of two ethers files (system-wide and per user),
1103 * - avoid the use of NIS maps,
1104 * - lack of these functions on some systems.
1106 * So the following functions do _not_ behave as the standard ones.
1108 * -- Laurent.
1113 * If "manuf_file" is FALSE, parse a 6-byte MAC address.
1114 * If "manuf_file" is TRUE, parse an up-to-6-byte sequence with an optional
1115 * mask.
1117 static gboolean
1118 parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
1119 const gboolean manuf_file)
1121 int i;
1122 unsigned long num;
1123 char *p;
1124 char sep = '\0';
1126 for (i = 0; i < 6; i++) {
1127 /* Get a hex number, 1 or 2 digits, no sign characters allowed. */
1128 if (!isxdigit((unsigned char)*cp))
1129 return FALSE;
1130 num = strtoul(cp, &p, 16);
1131 if (p == cp)
1132 return FALSE; /* failed */
1133 if (num > 0xFF)
1134 return FALSE; /* not a valid octet */
1135 eth->addr[i] = (guint8) num;
1136 cp = p; /* skip past the number */
1138 /* OK, what character terminated the octet? */
1139 if (*cp == '/') {
1140 /* "/" - this has a mask. */
1141 if (!manuf_file) {
1142 /* Entries with masks are allowed only in the "manuf" files. */
1143 return FALSE;
1145 cp++; /* skip past the '/' to get to the mask */
1146 if (!isdigit((unsigned char)*cp))
1147 return FALSE; /* no sign allowed */
1148 num = strtoul(cp, &p, 10);
1149 if (p == cp)
1150 return FALSE; /* failed */
1151 cp = p; /* skip past the number */
1152 if (*cp != '\0' && !isspace((unsigned char)*cp))
1153 return FALSE; /* bogus terminator */
1154 if (num == 0 || num >= 48)
1155 return FALSE; /* bogus mask */
1156 /* Mask out the bits not covered by the mask */
1157 *mask = (int)num;
1158 for (i = 0; num >= 8; i++, num -= 8)
1159 ; /* skip octets entirely covered by the mask */
1160 /* Mask out the first masked octet */
1161 eth->addr[i] &= (0xFF << (8 - num));
1162 i++;
1163 /* Mask out completely-masked-out octets */
1164 for (; i < 6; i++)
1165 eth->addr[i] = 0;
1166 return TRUE;
1168 if (*cp == '\0') {
1169 /* We're at the end of the address, and there's no mask. */
1170 if (i == 2) {
1171 /* We got 3 bytes, so this is a manufacturer ID. */
1172 if (!manuf_file) {
1173 /* Manufacturer IDs are only allowed in the "manuf"
1174 files. */
1175 return FALSE;
1177 /* Indicate that this is a manufacturer ID (0 is not allowed
1178 as a mask). */
1179 *mask = 0;
1180 return TRUE;
1183 if (i == 5) {
1184 /* We got 6 bytes, so this is a MAC address.
1185 If we're reading one of the "manuf" files, indicate that
1186 this is a MAC address (48 is not allowed as a mask). */
1187 if (manuf_file)
1188 *mask = 48;
1189 return TRUE;
1192 /* We didn't get 3 or 6 bytes, and there's no mask; this is
1193 illegal. */
1194 return FALSE;
1195 } else {
1196 if (sep == '\0') {
1197 /* We don't know the separator used in this number; it can either
1198 be ':', '-', or '.'. */
1199 if (*cp != ':' && *cp != '-' && *cp != '.')
1200 return FALSE;
1201 sep = *cp; /* subsequent separators must be the same */
1202 } else {
1203 /* It has to be the same as the first separator */
1204 if (*cp != sep)
1205 return FALSE;
1208 cp++;
1211 return TRUE;
1214 static int
1215 parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
1216 const gboolean manuf_file)
1219 * See the ethers(4) or ethers(5) man page for ethers file format
1220 * (not available on all systems).
1221 * We allow both ethernet address separators (':' and '-'),
1222 * as well as Wireshark's '.' separator.
1225 gchar *cp;
1227 if ((cp = strchr(line, '#')))
1228 *cp = '\0';
1230 if ((cp = strtok(line, " \t")) == NULL)
1231 return -1;
1233 if (!parse_ether_address(cp, eth, mask, manuf_file))
1234 return -1;
1236 if ((cp = strtok(NULL, " \t")) == NULL)
1237 return -1;
1239 g_strlcpy(eth->name, cp, MAXNAMELEN);
1241 return 0;
1243 } /* parse_ether_line */
1245 static FILE *eth_p = NULL;
1247 static void
1248 set_ethent(char *path)
1250 if (eth_p)
1251 rewind(eth_p);
1252 else
1253 eth_p = ws_fopen(path, "r");
1256 static void
1257 end_ethent(void)
1259 if (eth_p) {
1260 fclose(eth_p);
1261 eth_p = NULL;
1265 static ether_t *
1266 get_ethent(unsigned int *mask, const gboolean manuf_file)
1269 static ether_t eth;
1270 static int size = 0;
1271 static char *buf = NULL;
1273 if (eth_p == NULL)
1274 return NULL;
1276 while (fgetline(&buf, &size, eth_p) >= 0) {
1277 if (parse_ether_line(buf, &eth, mask, manuf_file) == 0) {
1278 return &eth;
1282 return NULL;
1284 } /* get_ethent */
1286 #if 0
1287 static ether_t *
1288 get_ethbyname(const gchar *name)
1290 ether_t *eth;
1292 set_ethent(g_pethers_path);
1294 while (((eth = get_ethent(NULL, FALSE)) != NULL) && strncmp(name, eth->name, MAXNAMELEN) != 0)
1297 if (eth == NULL) {
1298 end_ethent();
1300 set_ethent(g_ethers_path);
1302 while (((eth = get_ethent(NULL, FALSE)) != NULL) && strncmp(name, eth->name, MAXNAMELEN) != 0)
1305 end_ethent();
1308 return eth;
1310 } /* get_ethbyname */
1311 #endif
1313 static ether_t *
1314 get_ethbyaddr(const guint8 *addr)
1317 ether_t *eth;
1319 set_ethent(g_pethers_path);
1321 while (((eth = get_ethent(NULL, FALSE)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
1324 if (eth == NULL) {
1325 end_ethent();
1327 set_ethent(g_ethers_path);
1329 while (((eth = get_ethent(NULL, FALSE)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
1332 end_ethent();
1335 return eth;
1337 } /* get_ethbyaddr */
1340 static void
1341 add_manuf_name(const guint8 *addr, unsigned int mask, gchar *name)
1343 guint8 oct;
1344 gint64 eth_as_int64, *wka_key;
1345 int eth_as_int, *manuf_key;
1348 * XXX - can we use Standard Annotation Language annotations to
1349 * note that mask, as returned by parse_ethe)r_address() (and thus
1350 * by the routines that call it, and thus passed to us) cannot be > 48,
1351 * or is SAL too weak to express that?
1353 if (mask >= 48) {
1354 /* This is a well-known MAC address; just add this to the Ethernet
1355 hash table */
1356 add_eth_name(addr, name);
1357 return;
1360 eth_as_int64 = addr[0];
1361 eth_as_int64 = eth_as_int64<<8;
1362 oct = addr[1];
1363 eth_as_int64 = eth_as_int64 | oct;
1364 eth_as_int64 = eth_as_int64<<8;
1365 oct = addr[2];
1366 eth_as_int64 = eth_as_int64 | oct;
1367 eth_as_int64 = eth_as_int64<<8;
1368 oct = addr[3];
1369 eth_as_int64 = eth_as_int64 | oct;
1370 eth_as_int64 = eth_as_int64<<8;
1371 oct = addr[4];
1372 eth_as_int64 = eth_as_int64 | oct;
1373 eth_as_int64 = eth_as_int64<<8;
1374 oct = addr[5];
1375 eth_as_int64 = eth_as_int64 | oct;
1377 if (mask == 0) {
1378 /* This is a manufacturer ID; add it to the manufacturer ID hash table */
1380 /* manuf needs only the 3 most significant octets of the ethernet address */
1381 manuf_key = (int *)g_new(int, 1);
1382 eth_as_int = (int)(eth_as_int64>>24)&0xffffff;
1383 *manuf_key = eth_as_int;
1385 g_hash_table_insert(manuf_hashtable, manuf_key, g_strdup(name));
1386 return;
1387 } /* mask == 0 */
1389 /* This is a range of well-known addresses; add it to the appropriate
1390 well-known-address table, creating that table if necessary. */
1392 wka_key = (gint64 *)g_new(gint64, 1);
1393 *wka_key = eth_as_int64;
1395 g_hash_table_insert(wka_hashtable, wka_key, g_strdup(name));
1397 } /* add_manuf_name */
1399 gchar *
1400 manuf_name_lookup(const guint8 *addr)
1402 gint32 manuf_key = 0;
1403 guint8 oct;
1404 gchar *name;
1406 /* manuf needs only the 3 most significant octets of the ethernet address */
1407 manuf_key = addr[0];
1408 manuf_key = manuf_key<<8;
1409 oct = addr[1];
1410 manuf_key = manuf_key | oct;
1411 manuf_key = manuf_key<<8;
1412 oct = addr[2];
1413 manuf_key = manuf_key | oct;
1416 /* first try to find a "perfect match" */
1417 name = (gchar *)g_hash_table_lookup(manuf_hashtable, &manuf_key);
1418 if(name != NULL){
1419 return name;
1422 /* Mask out the broadcast/multicast flag but not the locally
1423 * administered flag as localy administered means: not assigend
1424 * by the IEEE but the local administrator instead.
1425 * 0x01 multicast / broadcast bit
1426 * 0x02 locally administered bit */
1427 if((manuf_key & 0x00010000) != 0){
1428 manuf_key &= 0x00FEFFFF;
1429 name = (gchar *)g_hash_table_lookup(manuf_hashtable, &manuf_key);
1430 if(name != NULL){
1431 return name;
1435 return NULL;
1437 } /* manuf_name_lookup */
1439 static gchar *
1440 wka_name_lookup(const guint8 *addr, const unsigned int mask)
1442 guint8 masked_addr[6];
1443 guint num;
1444 gint i;
1445 gint64 eth_as_int64;
1446 guint8 oct;
1447 gchar *name;
1449 if(wka_hashtable == NULL){
1450 return NULL;
1452 /* Get the part of the address covered by the mask. */
1453 for (i = 0, num = mask; num >= 8; i++, num -= 8)
1454 masked_addr[i] = addr[i]; /* copy octets entirely covered by the mask */
1455 /* Mask out the first masked octet */
1456 masked_addr[i] = addr[i] & (0xFF << (8 - num));
1457 i++;
1458 /* Zero out completely-masked-out octets */
1459 for (; i < 6; i++)
1460 masked_addr[i] = 0;
1462 eth_as_int64 = masked_addr[0];
1463 eth_as_int64 = eth_as_int64<<8;
1464 oct = masked_addr[1];
1465 eth_as_int64 = eth_as_int64 | oct;
1466 eth_as_int64 = eth_as_int64<<8;
1467 oct = masked_addr[2];
1468 eth_as_int64 = eth_as_int64 | oct;
1469 eth_as_int64 = eth_as_int64<<8;
1470 oct = masked_addr[3];
1471 eth_as_int64 = eth_as_int64 | oct;
1472 eth_as_int64 = eth_as_int64<<8;
1473 oct = masked_addr[4];
1474 eth_as_int64 = eth_as_int64 | oct;
1475 eth_as_int64 = eth_as_int64<<8;
1476 oct = masked_addr[5];
1477 eth_as_int64 = eth_as_int64 | oct;
1479 name = (gchar *)g_hash_table_lookup(wka_hashtable, &eth_as_int64);
1481 return name;
1483 } /* wka_name_lookup */
1485 static void
1486 initialize_ethers(void)
1488 ether_t *eth;
1489 char *manuf_path;
1490 guint mask;
1492 /* hash table initialization */
1493 wka_hashtable = g_hash_table_new_full(g_int64_hash, g_int64_equal, g_free, g_free);
1494 manuf_hashtable = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
1495 eth_hashtable = g_hash_table_new_full(g_int64_hash, g_int64_equal, g_free, g_free);
1497 /* Compute the pathname of the ethers file. */
1498 if (g_ethers_path == NULL) {
1499 g_ethers_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
1500 get_systemfile_dir(), ENAME_ETHERS);
1503 /* Set g_pethers_path here, but don't actually do anything
1504 * with it. It's used in get_ethbyname() and get_ethbyaddr()
1506 if (g_pethers_path == NULL)
1507 g_pethers_path = get_persconffile_path(ENAME_ETHERS, FALSE);
1509 /* Compute the pathname of the manuf file */
1510 manuf_path = get_datafile_path(ENAME_MANUF);
1512 /* Read it and initialize the hash table */
1513 set_ethent(manuf_path);
1515 while ((eth = get_ethent(&mask, TRUE))) {
1516 add_manuf_name(eth->addr, mask, eth->name);
1519 end_ethent();
1521 g_free(manuf_path);
1523 } /* initialize_ethers */
1525 /* this is only needed when shuting down application (if at all) */
1526 static void
1527 eth_name_lookup_cleanup(void)
1530 if(manuf_hashtable) {
1531 g_hash_table_destroy(manuf_hashtable);
1532 manuf_hashtable = NULL;
1534 if(wka_hashtable) {
1535 g_hash_table_destroy(wka_hashtable);
1536 wka_hashtable = NULL;
1539 if(eth_hashtable) {
1540 g_hash_table_destroy(eth_hashtable);
1541 eth_hashtable = NULL;
1546 /* Resolve ethernet address */
1547 static hashether_t *
1548 eth_addr_resolve(hashether_t *tp) {
1549 ether_t *eth;
1550 const guint8 *addr = tp->addr;
1552 if ( (eth = get_ethbyaddr(addr)) != NULL) {
1553 g_strlcpy(tp->resolved_name, eth->name, MAXNAMELEN);
1554 tp->status = HASHETHER_STATUS_RESOLVED_NAME;
1555 return tp;
1556 } else {
1557 guint mask;
1558 gchar *name;
1560 /* Unknown name. Try looking for it in the well-known-address
1561 tables for well-known address ranges smaller than 2^24. */
1562 mask = 7;
1563 for (;;) {
1564 /* Only the topmost 5 bytes participate fully */
1565 if ((name = wka_name_lookup(addr, mask+40)) != NULL) {
1566 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x",
1567 name, addr[5] & (0xFF >> mask));
1568 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1569 return tp;
1571 if (mask == 0)
1572 break;
1573 mask--;
1576 mask = 7;
1577 for (;;) {
1578 /* Only the topmost 4 bytes participate fully */
1579 if ((name = wka_name_lookup(addr, mask+32)) != NULL) {
1580 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x",
1581 name, addr[4] & (0xFF >> mask), addr[5]);
1582 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1583 return tp;
1585 if (mask == 0)
1586 break;
1587 mask--;
1590 mask = 7;
1591 for (;;) {
1592 /* Only the topmost 3 bytes participate fully */
1593 if ((name = wka_name_lookup(addr, mask+24)) != NULL) {
1594 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
1595 name, addr[3] & (0xFF >> mask), addr[4], addr[5]);
1596 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1597 return tp;
1599 if (mask == 0)
1600 break;
1601 mask--;
1604 /* Now try looking in the manufacturer table. */
1605 if ((name = manuf_name_lookup(addr)) != NULL) {
1606 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
1607 name, addr[3], addr[4], addr[5]);
1608 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1609 return tp;
1612 /* Now try looking for it in the well-known-address
1613 tables for well-known address ranges larger than 2^24. */
1614 mask = 7;
1615 for (;;) {
1616 /* Only the topmost 2 bytes participate fully */
1617 if ((name = wka_name_lookup(addr, mask+16)) != NULL) {
1618 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x",
1619 name, addr[2] & (0xFF >> mask), addr[3], addr[4],
1620 addr[5]);
1621 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1622 return tp;
1624 if (mask == 0)
1625 break;
1626 mask--;
1629 mask = 7;
1630 for (;;) {
1631 /* Only the topmost byte participates fully */
1632 if ((name = wka_name_lookup(addr, mask+8)) != NULL) {
1633 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
1634 name, addr[1] & (0xFF >> mask), addr[2], addr[3],
1635 addr[4], addr[5]);
1636 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1637 return tp;
1639 if (mask == 0)
1640 break;
1641 mask--;
1644 for (mask = 7; mask > 0; mask--) {
1645 /* Not even the topmost byte participates fully */
1646 if ((name = wka_name_lookup(addr, mask)) != NULL) {
1647 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
1648 name, addr[0] & (0xFF >> mask), addr[1], addr[2],
1649 addr[3], addr[4], addr[5]);
1650 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1651 return tp;
1655 /* No match whatsoever. */
1656 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s", ether_to_str(addr));
1657 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1658 return tp;
1660 g_assert_not_reached();
1661 } /* eth_addr_resolve */
1663 static gint64
1664 eth_to_int64(const guint8 *addr)
1666 guint8 oct;
1667 gint64 eth_as_int64;
1669 eth_as_int64 = addr[0];
1670 eth_as_int64 = eth_as_int64<<8;
1671 oct = addr[1];
1672 eth_as_int64 = eth_as_int64 | oct;
1673 eth_as_int64 = eth_as_int64<<8;
1674 oct = addr[2];
1675 eth_as_int64 = eth_as_int64 | oct;
1676 eth_as_int64 = eth_as_int64<<8;
1677 oct = addr[3];
1678 eth_as_int64 = eth_as_int64 | oct;
1679 eth_as_int64 = eth_as_int64<<8;
1680 oct = addr[4];
1681 eth_as_int64 = eth_as_int64 | oct;
1682 eth_as_int64 = eth_as_int64<<8;
1683 oct = addr[5];
1684 eth_as_int64 = eth_as_int64 | oct;
1686 return eth_as_int64;
1689 static hashether_t *
1690 eth_hash_new_entry(const guint8 *addr, const gboolean resolve)
1692 hashether_t *tp;
1693 gint64 eth_as_int64, *key;
1695 eth_as_int64 = eth_to_int64(addr);
1697 key = (gint64 *)g_new(gint64, 1);
1698 *key = eth_as_int64;
1700 tp = g_new(hashether_t, 1);
1701 memcpy(tp->addr, addr, sizeof(tp->addr));
1702 tp->status = HASHETHER_STATUS_UNRESOLVED;
1703 g_strlcpy(tp->hexaddr, bytestring_to_str(addr, sizeof(tp->addr), ':'), sizeof(tp->hexaddr));
1704 tp->resolved_name[0] = '\0';
1706 if (resolve)
1707 eth_addr_resolve(tp);
1709 g_hash_table_insert(eth_hashtable, key, tp);
1711 return tp;
1712 } /* eth_hash_new_entry */
1714 static hashether_t *
1715 add_eth_name(const guint8 *addr, const gchar *name)
1717 hashether_t *tp;
1718 gint64 eth_as_int64;
1720 eth_as_int64 = eth_to_int64(addr);
1722 tp = (hashether_t *)g_hash_table_lookup(eth_hashtable, &eth_as_int64);
1724 if( tp == NULL ){
1725 tp = eth_hash_new_entry(addr, FALSE);
1728 g_strlcpy(tp->resolved_name, name, MAXNAMELEN);
1729 tp->status = HASHETHER_STATUS_RESOLVED_NAME;
1730 new_resolved_objects = TRUE;
1732 return tp;
1733 } /* add_eth_name */
1735 static hashether_t *
1736 eth_name_lookup(const guint8 *addr, const gboolean resolve)
1738 hashether_t *tp;
1739 gint64 eth_as_int64;
1741 eth_as_int64 = eth_to_int64(addr);
1743 tp = (hashether_t *)g_hash_table_lookup(eth_hashtable, &eth_as_int64);
1744 if( tp == NULL ) {
1745 tp = eth_hash_new_entry(addr, resolve);
1746 } else {
1747 if (resolve && (tp->status == HASHETHER_STATUS_UNRESOLVED)){
1748 eth_addr_resolve(tp); /* Found but needs to be resolved */
1752 return tp;
1754 } /* eth_name_lookup */
1756 static guint8 *
1757 eth_addr_lookup(const gchar *name _U_)
1759 #if 0
1760 /* XXX Do we need reverse lookup??? */
1761 ether_t *eth;
1762 hashether_t *tp;
1763 hashether_t **table = eth_table;
1764 gint i;
1766 /* to be optimized (hash table from name to addr) */
1767 for (i = 0; i < HASHETHSIZE; i++) {
1768 tp = table[i];
1769 while (tp) {
1770 if (strcmp(tp->resolved_name, name) == 0)
1771 return tp->addr;
1772 tp = tp->next;
1776 /* not in hash table : performs a file lookup */
1778 if ((eth = get_ethbyname(name)) == NULL)
1779 return NULL;
1781 /* add new entry in hash table */
1783 tp = add_eth_name(eth->addr, name);
1785 return tp->addr;
1786 #endif
1787 return NULL;
1789 } /* eth_addr_lookup */
1792 /* IPXNETS */
1793 static int
1794 parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
1797 * We allow three address separators (':', '-', and '.'),
1798 * as well as no separators
1801 gchar *cp;
1802 guint32 a, a0, a1, a2, a3;
1803 gboolean found_single_number = FALSE;
1805 if ((cp = strchr(line, '#')))
1806 *cp = '\0';
1808 if ((cp = strtok(line, " \t\n")) == NULL)
1809 return -1;
1811 /* Either fill a0,a1,a2,a3 and found_single_number is FALSE,
1812 * fill a and found_single_number is TRUE,
1813 * or return -1
1815 if (sscanf(cp, "%x:%x:%x:%x", &a0, &a1, &a2, &a3) != 4) {
1816 if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
1817 if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
1818 if (sscanf(cp, "%x", &a) == 1) {
1819 found_single_number = TRUE;
1821 else {
1822 return -1;
1828 if ((cp = strtok(NULL, " \t\n")) == NULL)
1829 return -1;
1831 if (found_single_number) {
1832 ipxnet->addr = a;
1834 else {
1835 ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
1838 g_strlcpy(ipxnet->name, cp, MAXNAMELEN);
1840 return 0;
1842 } /* parse_ipxnets_line */
1844 static FILE *ipxnet_p = NULL;
1846 static void
1847 set_ipxnetent(char *path)
1849 if (ipxnet_p)
1850 rewind(ipxnet_p);
1851 else
1852 ipxnet_p = ws_fopen(path, "r");
1855 static void
1856 end_ipxnetent(void)
1858 if (ipxnet_p) {
1859 fclose(ipxnet_p);
1860 ipxnet_p = NULL;
1864 static ipxnet_t *
1865 get_ipxnetent(void)
1868 static ipxnet_t ipxnet;
1869 static int size = 0;
1870 static char *buf = NULL;
1872 if (ipxnet_p == NULL)
1873 return NULL;
1875 while (fgetline(&buf, &size, ipxnet_p) >= 0) {
1876 if (parse_ipxnets_line(buf, &ipxnet) == 0) {
1877 return &ipxnet;
1881 return NULL;
1883 } /* get_ipxnetent */
1885 /* Unused ??? */
1886 #if 0
1887 static ipxnet_t *
1888 get_ipxnetbyname(const gchar *name)
1890 ipxnet_t *ipxnet;
1892 set_ipxnetent(g_ipxnets_path);
1894 while (((ipxnet = get_ipxnetent()) != NULL) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
1897 if (ipxnet == NULL) {
1898 end_ipxnetent();
1900 set_ipxnetent(g_pipxnets_path);
1902 while (((ipxnet = get_ipxnetent()) != NULL) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
1905 end_ipxnetent();
1908 return ipxnet;
1910 } /* get_ipxnetbyname */
1911 #endif
1913 static ipxnet_t *
1914 get_ipxnetbyaddr(guint32 addr)
1916 ipxnet_t *ipxnet;
1918 set_ipxnetent(g_ipxnets_path);
1920 while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) ) ;
1922 if (ipxnet == NULL) {
1923 end_ipxnetent();
1925 set_ipxnetent(g_pipxnets_path);
1927 while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) )
1930 end_ipxnetent();
1933 return ipxnet;
1935 } /* get_ipxnetbyaddr */
1937 static void
1938 initialize_ipxnets(void)
1940 /* Compute the pathname of the ipxnets file.
1942 * XXX - is there a notion of an "ipxnets file" in any flavor of
1943 * UNIX, or with any add-on Netware package for UNIX? If not,
1944 * should the UNIX version of the ipxnets file be in the datafile
1945 * directory as well?
1947 if (g_ipxnets_path == NULL) {
1948 g_ipxnets_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
1949 get_systemfile_dir(), ENAME_IPXNETS);
1952 /* Set g_pipxnets_path here, but don't actually do anything
1953 * with it. It's used in get_ipxnetbyname() and get_ipxnetbyaddr()
1955 if (g_pipxnets_path == NULL)
1956 g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, FALSE);
1958 } /* initialize_ipxnets */
1960 static void
1961 ipx_name_lookup_cleanup(void)
1963 if(ipxnet_hash_table){
1964 g_hash_table_destroy(ipxnet_hash_table);
1965 ipxnet_hash_table = NULL;
1970 #if 0
1971 static hashipxnet_t *
1972 add_ipxnet_name(guint addr, const gchar *name)
1974 hashipxnet_t *tp;
1976 tp = (hashipxnet_t *)g_hash_table_lookup(ipxnet_hash_table, &addr);
1977 if(tp){
1978 g_strlcpy(tp->name, name, MAXNAMELEN);
1979 }else{
1980 int *key;
1982 key = (int *)g_new(int, 1);
1983 *key = addr;
1984 tp = g_new(hashipxnet_t,1);
1985 g_strlcpy(tp->name, name, MAXNAMELEN);
1986 g_hash_table_insert(ipxnet_hash_table, key, tp);
1989 tp->addr = addr;
1990 g_strlcpy(tp->name, name, MAXNAMELEN);
1991 tp->next = NULL;
1992 new_resolved_objects = TRUE;
1994 return tp;
1996 } /* add_ipxnet_name */
1997 #endif
1999 static gchar *
2000 ipxnet_name_lookup(const guint addr)
2002 hashipxnet_t *tp;
2003 ipxnet_t *ipxnet;
2005 tp = (hashipxnet_t *)g_hash_table_lookup(ipxnet_hash_table, &addr);
2006 if(tp == NULL){
2007 int *key;
2009 key = (int *)g_new(int, 1);
2010 *key = addr;
2011 tp = g_new(hashipxnet_t, 1);
2012 g_hash_table_insert(ipxnet_hash_table, key, tp);
2013 }else{
2014 return tp->name;
2017 /* fill in a new entry */
2019 tp->addr = addr;
2021 if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL) {
2022 /* unknown name */
2023 g_snprintf(tp->name, MAXNAMELEN, "%X", addr);
2025 } else {
2026 g_strlcpy(tp->name, ipxnet->name, MAXNAMELEN);
2029 return (tp->name);
2031 } /* ipxnet_name_lookup */
2033 static guint
2034 ipxnet_addr_lookup(const gchar *name _U_, gboolean *success)
2036 *success = FALSE;
2037 return 0;
2038 #if 0
2039 /* XXX Do we need reverse lookup??? */
2040 ipxnet_t *ipxnet;
2041 hashipxnet_t *tp;
2042 hashipxnet_t **table = ipxnet_table;
2043 int i;
2045 /* to be optimized (hash table from name to addr) */
2046 for (i = 0; i < HASHIPXNETSIZE; i++) {
2047 tp = table[i];
2048 while (tp) {
2049 if (strcmp(tp->name, name) == 0) {
2050 *success = TRUE;
2051 return tp->addr;
2053 tp = tp->next;
2057 /* not in hash table : performs a file lookup */
2059 if ((ipxnet = get_ipxnetbyname(name)) == NULL) {
2060 *success = FALSE;
2061 return 0;
2064 /* add new entry in hash table */
2066 tp = add_ipxnet_name(ipxnet->addr, name);
2068 *success = TRUE;
2069 return tp->addr;
2070 #endif
2071 } /* ipxnet_addr_lookup */
2073 static gboolean
2074 read_hosts_file (const char *hostspath)
2076 FILE *hf;
2077 char *line = NULL;
2078 int size = 0;
2079 gchar *cp;
2080 guint32 host_addr[4]; /* IPv4 or IPv6 */
2081 struct e_in6_addr ip6_addr;
2082 gboolean is_ipv6;
2083 int ret;
2086 * See the hosts(4) or hosts(5) man page for hosts file format
2087 * (not available on all systems).
2089 if ((hf = ws_fopen(hostspath, "r")) == NULL)
2090 return FALSE;
2092 while (fgetline(&line, &size, hf) >= 0) {
2093 if ((cp = strchr(line, '#')))
2094 *cp = '\0';
2096 if ((cp = strtok(line, " \t")) == NULL)
2097 continue; /* no tokens in the line */
2099 ret = inet_pton(AF_INET6, cp, &host_addr);
2100 if (ret < 0)
2101 continue; /* error parsing */
2102 if (ret > 0) {
2103 /* Valid IPv6 */
2104 is_ipv6 = TRUE;
2105 } else {
2106 /* Not valid IPv6 - valid IPv4? */
2107 if (inet_pton(AF_INET, cp, &host_addr) <= 0)
2108 continue; /* no */
2109 is_ipv6 = FALSE;
2112 if ((cp = strtok(NULL, " \t")) == NULL)
2113 continue; /* no host name */
2115 if (is_ipv6) {
2116 memcpy(&ip6_addr, host_addr, sizeof ip6_addr);
2117 add_ipv6_name(&ip6_addr, cp);
2118 } else
2119 add_ipv4_name(host_addr[0], cp);
2122 * Add the aliases, too, if there are any.
2123 * XXX - host_lookup() only returns the first entry.
2125 while ((cp = strtok(NULL, " \t")) != NULL) {
2126 if (is_ipv6) {
2127 memcpy(&ip6_addr, host_addr, sizeof ip6_addr);
2128 add_ipv6_name(&ip6_addr, cp);
2129 } else
2130 add_ipv4_name(host_addr[0], cp);
2133 g_free(line);
2135 fclose(hf);
2136 return TRUE;
2137 } /* read_hosts_file */
2139 gboolean
2140 add_hosts_file (const char *hosts_file)
2142 gboolean found = FALSE;
2143 guint i;
2145 if (!hosts_file)
2146 return FALSE;
2148 if (!extra_hosts_files)
2149 extra_hosts_files = g_ptr_array_new();
2151 for (i = 0; i < extra_hosts_files->len; i++) {
2152 if (strcmp(hosts_file, (const char *) g_ptr_array_index(extra_hosts_files, i)) == 0)
2153 found = TRUE;
2156 if (!found) {
2157 g_ptr_array_add(extra_hosts_files, g_strdup(hosts_file));
2158 return read_hosts_file (hosts_file);
2160 return TRUE;
2163 gboolean
2164 add_ip_name_from_string (const char *addr, const char *name)
2166 guint32 host_addr[4]; /* IPv4 */
2167 struct e_in6_addr ip6_addr; /* IPv6 */
2168 gboolean is_ipv6;
2169 int ret;
2170 resolved_ipv4_t *resolved_ipv4_entry;
2171 resolved_ipv6_t *resolved_ipv6_entry;
2173 ret = inet_pton(AF_INET6, addr, &ip6_addr);
2174 if (ret < 0)
2175 /* Error parsing address */
2176 return FALSE;
2178 if (ret > 0) {
2179 /* Valid IPv6 */
2180 is_ipv6 = TRUE;
2181 } else {
2182 /* Not valid IPv6 - valid IPv4? */
2183 if (inet_pton(AF_INET, addr, &host_addr) <= 0)
2184 return FALSE; /* no */
2185 is_ipv6 = FALSE;
2188 if (is_ipv6) {
2189 resolved_ipv6_entry = g_new(resolved_ipv6_t, 1);
2190 memcpy(&(resolved_ipv6_entry->ip6_addr), &ip6_addr, 16);
2191 g_strlcpy(resolved_ipv6_entry->name, name, MAXNAMELEN);
2192 manually_resolved_ipv6_list = g_slist_prepend(manually_resolved_ipv6_list, resolved_ipv6_entry);
2193 } else {
2194 resolved_ipv4_entry = g_new(resolved_ipv4_t, 1);
2195 resolved_ipv4_entry->host_addr = host_addr[0];
2196 g_strlcpy(resolved_ipv4_entry->name, name, MAXNAMELEN);
2197 manually_resolved_ipv4_list = g_slist_prepend(manually_resolved_ipv4_list, resolved_ipv4_entry);
2200 return TRUE;
2201 } /* add_ip_name_from_string */
2204 * Add the resolved addresses that are in use to the list used to create the NRB
2206 static void
2207 ipv4_hash_table_resolved_to_list(gpointer key _U_, gpointer value, gpointer user_data)
2209 addrinfo_lists_t *lists = (addrinfo_lists_t*)user_data;
2210 hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value;
2212 if((ipv4_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == RESOLVED_ADDRESS_USED){
2213 lists->ipv4_addr_list = g_list_prepend (lists->ipv4_addr_list, ipv4_hash_table_entry);
2219 * Add the resolved addresses that are in use to the list used to create the NRB
2222 static void
2223 ipv6_hash_table_resolved_to_list(gpointer key _U_, gpointer value, gpointer user_data)
2225 addrinfo_lists_t *lists = (addrinfo_lists_t*)user_data;
2226 hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value;
2228 if((ipv6_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == RESOLVED_ADDRESS_USED){
2229 lists->ipv6_addr_list = g_list_prepend (lists->ipv6_addr_list, ipv6_hash_table_entry);
2234 addrinfo_lists_t *
2235 get_addrinfo_list(void) {
2237 if(ipv4_hash_table){
2238 g_hash_table_foreach(ipv4_hash_table, ipv4_hash_table_resolved_to_list, &addrinfo_lists);
2241 if(ipv6_hash_table){
2242 g_hash_table_foreach(ipv6_hash_table, ipv6_hash_table_resolved_to_list, &addrinfo_lists);
2245 return &addrinfo_lists;
2248 /* Read in a list of subnet definition - name pairs.
2249 * <line> = <comment> | <entry> | <whitespace>
2250 * <comment> = <whitespace>#<any>
2251 * <entry> = <subnet_definition> <whitespace> <subnet_name> [<comment>|<whitespace><any>]
2252 * <subnet_definition> = <ipv4_address> / <subnet_mask_length>
2253 * <ipv4_address> is a full address; it will be masked to get the subnet-ID.
2254 * <subnet_mask_length> is a decimal 1-31
2255 * <subnet_name> is a string containing no whitespace.
2256 * <whitespace> = (space | tab)+
2257 * Any malformed entries are ignored.
2258 * Any trailing data after the subnet_name is ignored.
2260 * XXX Support IPv6
2262 static gboolean
2263 read_subnets_file (const char *subnetspath)
2265 FILE *hf;
2266 char *line = NULL;
2267 int size = 0;
2268 gchar *cp, *cp2;
2269 guint32 host_addr; /* IPv4 ONLY */
2270 int mask_length;
2272 if ((hf = ws_fopen(subnetspath, "r")) == NULL)
2273 return FALSE;
2275 while (fgetline(&line, &size, hf) >= 0) {
2276 if ((cp = strchr(line, '#')))
2277 *cp = '\0';
2279 if ((cp = strtok(line, " \t")) == NULL)
2280 continue; /* no tokens in the line */
2283 /* Expected format is <IP4 address>/<subnet length> */
2284 cp2 = strchr(cp, '/');
2285 if(NULL == cp2) {
2286 /* No length */
2287 continue;
2289 *cp2 = '\0'; /* Cut token */
2290 ++cp2 ;
2292 /* Check if this is a valid IPv4 address */
2293 if (inet_pton(AF_INET, cp, &host_addr) <= 0) {
2294 continue; /* no */
2297 mask_length = atoi(cp2);
2298 if(0 >= mask_length || mask_length > 31) {
2299 continue; /* invalid mask length */
2302 if ((cp = strtok(NULL, " \t")) == NULL)
2303 continue; /* no subnet name */
2305 subnet_entry_set(host_addr, (guint32)mask_length, cp);
2307 g_free(line);
2309 fclose(hf);
2310 return TRUE;
2311 } /* read_subnets_file */
2313 static subnet_entry_t
2314 subnet_lookup(const guint32 addr)
2316 subnet_entry_t subnet_entry;
2317 guint32 i;
2319 /* Search mask lengths linearly, longest first */
2321 i = SUBNETLENGTHSIZE;
2322 while(have_subnet_entry && i > 0) {
2323 guint32 masked_addr;
2324 subnet_length_entry_t* length_entry;
2326 /* Note that we run from 31 (length 32) to 0 (length 1) */
2327 --i;
2328 g_assert(i < SUBNETLENGTHSIZE);
2331 length_entry = &subnet_length_entries[i];
2333 if(NULL != length_entry->subnet_addresses) {
2334 sub_net_hashipv4_t * tp;
2335 guint32 hash_idx;
2337 masked_addr = addr & length_entry->mask;
2338 hash_idx = HASH_IPV4_ADDRESS(masked_addr);
2340 tp = length_entry->subnet_addresses[hash_idx];
2341 while(tp != NULL && tp->addr != masked_addr) {
2342 tp = tp->next;
2345 if(NULL != tp) {
2346 subnet_entry.mask = length_entry->mask;
2347 subnet_entry.mask_length = i + 1; /* Length is offset + 1 */
2348 subnet_entry.name = tp->name;
2349 return subnet_entry;
2354 subnet_entry.mask = 0;
2355 subnet_entry.mask_length = 0;
2356 subnet_entry.name = NULL;
2358 return subnet_entry;
2361 /* Add a subnet-definition - name pair to the set.
2362 * The definition is taken by masking the address passed in with the mask of the
2363 * given length.
2365 static void
2366 subnet_entry_set(guint32 subnet_addr, const guint32 mask_length, const gchar* name)
2368 subnet_length_entry_t* entry;
2369 sub_net_hashipv4_t * tp;
2370 gsize hash_idx;
2372 g_assert(mask_length > 0 && mask_length <= 32);
2374 entry = &subnet_length_entries[mask_length - 1];
2376 subnet_addr &= entry->mask;
2378 hash_idx = HASH_IPV4_ADDRESS(subnet_addr);
2380 if(NULL == entry->subnet_addresses) {
2381 entry->subnet_addresses = (sub_net_hashipv4_t**) se_alloc0(sizeof(sub_net_hashipv4_t*) * HASHHOSTSIZE);
2384 if(NULL != (tp = entry->subnet_addresses[hash_idx])) {
2385 if(tp->addr == subnet_addr) {
2386 return; /* XXX provide warning that an address was repeated? */
2387 } else {
2388 sub_net_hashipv4_t * new_tp = se_new(sub_net_hashipv4_t);
2389 tp->next = new_tp;
2390 tp = new_tp;
2392 } else {
2393 tp = entry->subnet_addresses[hash_idx] = se_new(sub_net_hashipv4_t);
2396 tp->next = NULL;
2397 tp->addr = subnet_addr;
2398 /* Clear DUMMY_ADDRESS_ENTRY */
2399 tp->flags = tp->flags & 0xfe; /*Never used again...*/
2400 g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
2401 have_subnet_entry = TRUE;
2404 static void
2405 subnet_name_lookup_init(void)
2407 gchar* subnetspath;
2408 guint32 i;
2410 for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
2411 guint32 length = i + 1;
2413 subnet_length_entries[i].subnet_addresses = NULL;
2414 subnet_length_entries[i].mask_length = length;
2415 subnet_length_entries[i].mask = g_htonl(ip_get_subnet_mask(length));
2418 subnetspath = get_persconffile_path(ENAME_SUBNETS, FALSE);
2419 if (!read_subnets_file(subnetspath) && errno != ENOENT) {
2420 report_open_failure(subnetspath, errno, FALSE);
2422 g_free(subnetspath);
2425 * Load the global subnets file, if we have one.
2427 subnetspath = get_datafile_path(ENAME_SUBNETS);
2428 if (!read_subnets_file(subnetspath) && errno != ENOENT) {
2429 report_open_failure(subnetspath, errno, FALSE);
2431 g_free(subnetspath);
2436 * External Functions
2439 void
2440 addr_resolve_pref_init(module_t *nameres)
2442 prefs_register_bool_preference(nameres, "mac_name",
2443 "Resolve MAC addresses",
2444 "Resolve Ethernet MAC address to manufacturer names",
2445 &gbl_resolv_flags.mac_name);
2447 prefs_register_bool_preference(nameres, "transport_name",
2448 "Resolve transport names",
2449 "Resolve TCP/UDP ports into service names",
2450 &gbl_resolv_flags.transport_name);
2452 prefs_register_bool_preference(nameres, "network_name",
2453 "Resolve network (IP) addresses",
2454 "Resolve IPv4, IPv6, and IPX addresses into host names."
2455 " The next set of check boxes determines how name resolution should be performed."
2456 " If no other options are checked name resolution is made from Wireshark's host file,"
2457 " capture file name resolution blocks and DNS packets in the capture.",
2458 &gbl_resolv_flags.network_name);
2460 prefs_register_bool_preference(nameres, "use_external_name_resolver",
2461 "Use an external network name resolver",
2462 "Use your system's configured name resolver"
2463 " (usually DNS) to resolve network names."
2464 " Only applies when network name resolution"
2465 " is enabled.",
2466 &gbl_resolv_flags.use_external_net_name_resolver);
2468 #if defined(HAVE_C_ARES) || defined(HAVE_GNU_ADNS)
2469 prefs_register_bool_preference(nameres, "concurrent_dns",
2470 "Enable concurrent DNS name resolution",
2471 "Enable concurrent DNS name resolution. Only"
2472 " applies when network name resolution is"
2473 " enabled. You probably want to enable this.",
2474 &gbl_resolv_flags.concurrent_dns);
2476 prefs_register_uint_preference(nameres, "name_resolve_concurrency",
2477 "Maximum concurrent requests",
2478 "The maximum number of DNS requests that may"
2479 " be active at any time. A large value (many"
2480 " thousands) might overload the network or make"
2481 " your DNS server behave badly.",
2483 &name_resolve_concurrency);
2484 #else
2485 prefs_register_static_text_preference(nameres, "concurrent_dns",
2486 "Enable concurrent DNS name resolution: N/A",
2487 "Support for concurrent DNS name resolution was not"
2488 " compiled into this version of Wireshark");
2489 #endif
2491 prefs_register_bool_preference(nameres, "hosts_file_handling",
2492 "Only use the profile \"hosts\" file",
2493 "By default \"hosts\" files will be loaded from multiple sources."
2494 " Checking this box only loads the \"hosts\" in the current profile.",
2495 &gbl_resolv_flags.load_hosts_file_from_profile_only);
2499 #ifdef HAVE_C_ARES
2500 gboolean
2501 host_name_lookup_process(void) {
2502 async_dns_queue_msg_t *caqm;
2503 struct timeval tv = { 0, 0 };
2504 int nfds;
2505 fd_set rfds, wfds;
2506 gboolean nro = new_resolved_objects;
2508 new_resolved_objects = FALSE;
2510 if (!async_dns_initialized)
2511 /* c-ares not initialized. Bail out and cancel timers. */
2512 return nro;
2514 async_dns_queue_head = g_list_first(async_dns_queue_head);
2516 while (async_dns_queue_head != NULL && async_dns_in_flight <= name_resolve_concurrency) {
2517 caqm = (async_dns_queue_msg_t *) async_dns_queue_head->data;
2518 async_dns_queue_head = g_list_remove(async_dns_queue_head, (void *) caqm);
2519 if (caqm->family == AF_INET) {
2520 ares_gethostbyaddr(ghba_chan, &caqm->addr.ip4, sizeof(guint32), AF_INET,
2521 c_ares_ghba_cb, caqm);
2522 async_dns_in_flight++;
2523 } else if (caqm->family == AF_INET6) {
2524 ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(struct e_in6_addr),
2525 AF_INET6, c_ares_ghba_cb, caqm);
2526 async_dns_in_flight++;
2530 FD_ZERO(&rfds);
2531 FD_ZERO(&wfds);
2532 nfds = ares_fds(ghba_chan, &rfds, &wfds);
2533 if (nfds > 0) {
2534 if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
2535 fprintf(stderr, "Warning: call to select() failed, error is %s\n", strerror(errno));
2536 return nro;
2538 ares_process(ghba_chan, &rfds, &wfds);
2541 /* Any new entries? */
2542 return nro;
2545 static void
2546 _host_name_lookup_cleanup(void) {
2547 GList *cur;
2549 cur = g_list_first(async_dns_queue_head);
2550 while (cur) {
2551 g_free(cur->data);
2552 cur = g_list_next (cur);
2555 g_list_free(async_dns_queue_head);
2556 async_dns_queue_head = NULL;
2558 if (async_dns_initialized) {
2559 ares_destroy(ghba_chan);
2560 ares_destroy(ghbn_chan);
2562 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2563 ares_library_cleanup();
2564 #endif
2565 async_dns_initialized = FALSE;
2568 #elif defined(HAVE_GNU_ADNS)
2570 /* XXX - The ADNS "documentation" isn't very clear:
2571 * - Do we need to keep our query structures around?
2573 gboolean
2574 host_name_lookup_process(void) {
2575 async_dns_queue_msg_t *almsg;
2576 GList *cur;
2577 char addr_str[] = "111.222.333.444.in-addr.arpa.";
2578 guint8 *addr_bytes;
2579 adns_answer *ans;
2580 int ret;
2581 gboolean dequeue;
2582 gboolean nro = new_resolved_objects;
2584 new_resolved_objects = FALSE;
2585 async_dns_queue_head = g_list_first(async_dns_queue_head);
2587 cur = async_dns_queue_head;
2588 while (cur && async_dns_in_flight <= name_resolve_concurrency) {
2589 almsg = (async_dns_queue_msg_t *) cur->data;
2590 if (! almsg->submitted && almsg->type == AF_INET) {
2591 addr_bytes = (guint8 *) &almsg->ip4_addr;
2592 g_snprintf(addr_str, sizeof addr_str, "%u.%u.%u.%u.in-addr.arpa.", addr_bytes[3],
2593 addr_bytes[2], addr_bytes[1], addr_bytes[0]);
2594 /* XXX - what if it fails? */
2595 adns_submit (ads, addr_str, adns_r_ptr, adns_qf_none, NULL, &almsg->query);
2596 almsg->submitted = TRUE;
2597 async_dns_in_flight++;
2599 cur = cur->next;
2602 cur = async_dns_queue_head;
2603 while (cur) {
2604 dequeue = FALSE;
2605 almsg = (async_dns_queue_msg_t *) cur->data;
2606 if (almsg->submitted) {
2607 ret = adns_check(ads, &almsg->query, &ans, NULL);
2608 if (ret == 0) {
2609 if (ans->status == adns_s_ok) {
2610 add_ipv4_name(almsg->ip4_addr, *ans->rrs.str);
2612 dequeue = TRUE;
2615 cur = cur->next;
2616 if (dequeue) {
2617 async_dns_queue_head = g_list_remove(async_dns_queue_head, (void *) almsg);
2618 g_free(almsg);
2619 /* XXX, what to do if async_dns_in_flight == 0? */
2620 async_dns_in_flight--;
2624 /* Keep the timeout in place */
2625 return nro;
2628 static void
2629 _host_name_lookup_cleanup(void) {
2630 void *qdata;
2632 async_dns_queue_head = g_list_first(async_dns_queue_head);
2633 while (async_dns_queue_head) {
2634 qdata = async_dns_queue_head->data;
2635 async_dns_queue_head = g_list_remove(async_dns_queue_head, qdata);
2636 g_free(qdata);
2639 if (async_dns_initialized)
2640 adns_finish(ads);
2641 async_dns_initialized = FALSE;
2644 #else /* HAVE_GNU_ADNS */
2646 gboolean
2647 host_name_lookup_process(void) {
2648 gboolean nro = new_resolved_objects;
2650 new_resolved_objects = FALSE;
2652 return nro;
2655 static void
2656 _host_name_lookup_cleanup(void) {
2659 #endif /* HAVE_C_ARES */
2661 const gchar *
2662 get_hostname(const guint addr)
2664 gboolean found;
2666 /* XXX why do we call this if we're not resolving? To create hash entries?
2667 * Why?
2669 hashipv4_t *tp = host_lookup(addr, &found);
2671 if (!gbl_resolv_flags.network_name)
2672 return tp->ip;
2674 tp->flags = tp->flags | RESOLVED_ADDRESS_USED;
2676 return tp->name;
2679 /* -------------------------- */
2681 const gchar *
2682 get_hostname6(const struct e_in6_addr *addr)
2684 gboolean found;
2686 /* XXX why do we call this if we're not resolving? To create hash entries?
2687 * Why?
2689 hashipv6_t *tp = host_lookup6(addr, &found);
2691 if (!gbl_resolv_flags.network_name)
2692 return tp->ip6;
2694 tp->flags = tp->flags | RESOLVED_ADDRESS_USED;
2696 return tp->name;
2699 /* -------------------------- */
2700 void
2701 add_ipv4_name(const guint addr, const gchar *name)
2703 hashipv4_t *tp;
2706 * Don't add zero-length names; apparently, some resolvers will return
2707 * them if they get them from DNS.
2709 if (name[0] == '\0')
2710 return;
2713 tp = (hashipv4_t *)g_hash_table_lookup(ipv4_hash_table, &addr);
2714 if(tp){
2715 g_strlcpy(tp->name, name, MAXNAMELEN);
2716 }else{
2717 int *key;
2719 key = (int *)g_new(int, 1);
2720 *key = addr;
2721 tp = new_ipv4(addr);
2722 g_strlcpy(tp->name, name, MAXNAMELEN);
2723 g_hash_table_insert(ipv4_hash_table, key, tp);
2726 g_strlcpy(tp->name, name, MAXNAMELEN);
2727 tp->flags = tp->flags | TRIED_RESOLVE_ADDRESS;
2728 new_resolved_objects = TRUE;
2730 } /* add_ipv4_name */
2732 /* -------------------------- */
2733 void
2734 add_ipv6_name(const struct e_in6_addr *addrp, const gchar *name)
2736 hashipv6_t *tp;
2739 * Don't add zero-length names; apparently, some resolvers will return
2740 * them if they get them from DNS.
2742 if (name[0] == '\0')
2743 return;
2745 tp = (hashipv6_t *)g_hash_table_lookup(ipv6_hash_table, addrp);
2746 if(tp){
2747 g_strlcpy(tp->name, name, MAXNAMELEN);
2748 }else{
2749 struct e_in6_addr *addr_key;
2751 addr_key = g_new(struct e_in6_addr,1);
2752 tp = new_ipv6(addrp);
2753 memcpy(addr_key, addrp, 16);
2754 g_strlcpy(tp->name, name, MAXNAMELEN);
2755 g_hash_table_insert(ipv6_hash_table, addr_key, tp);
2758 g_strlcpy(tp->name, name, MAXNAMELEN);
2759 tp->flags = tp->flags | TRIED_RESOLVE_ADDRESS;
2760 new_resolved_objects = TRUE;
2762 } /* add_ipv6_name */
2764 static void
2765 add_manually_resolved_ipv4(gpointer data, gpointer user_data _U_)
2767 resolved_ipv4_t *resolved_ipv4_entry = (resolved_ipv4_t *)data;
2769 add_ipv4_name(resolved_ipv4_entry->host_addr, resolved_ipv4_entry->name);
2772 static void
2773 add_manually_resolved_ipv6(gpointer data, gpointer user_data _U_)
2775 resolved_ipv6_t *resolved_ipv6_entry = (resolved_ipv6_t *)data;
2777 add_ipv6_name(&(resolved_ipv6_entry->ip6_addr), resolved_ipv6_entry->name);
2780 static void
2781 add_manually_resolved(void)
2783 if(manually_resolved_ipv4_list){
2784 g_slist_foreach(manually_resolved_ipv4_list, add_manually_resolved_ipv4, NULL);
2787 if(manually_resolved_ipv6_list){
2788 g_slist_foreach(manually_resolved_ipv6_list, add_manually_resolved_ipv6, NULL);
2792 void
2793 host_name_lookup_init(void)
2795 char *hostspath;
2796 guint i;
2798 #ifdef HAVE_GNU_ADNS
2799 #ifdef _WIN32
2800 char *sysroot;
2801 static char rootpath_nt[] = "\\system32\\drivers\\etc\\hosts";
2802 static char rootpath_ot[] = "\\hosts";
2803 #endif /* _WIN32 */
2804 #endif /*GNU_ADNS */
2806 g_assert(ipxnet_hash_table == NULL);
2807 ipxnet_hash_table = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
2809 g_assert(ipv4_hash_table == NULL);
2810 ipv4_hash_table = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
2812 g_assert(ipv6_hash_table == NULL);
2813 ipv6_hash_table = g_hash_table_new_full(ipv6_oat_hash, ipv6_equal, g_free, g_free);
2816 * Load the global hosts file, if we have one.
2818 if(!gbl_resolv_flags.load_hosts_file_from_profile_only){
2819 hostspath = get_datafile_path(ENAME_HOSTS);
2820 if (!read_hosts_file(hostspath) && errno != ENOENT) {
2821 report_open_failure(hostspath, errno, FALSE);
2823 g_free(hostspath);
2826 * Load the user's hosts file no matter what, if they have one.
2828 hostspath = get_persconffile_path(ENAME_HOSTS, TRUE);
2829 if (!read_hosts_file(hostspath) && errno != ENOENT) {
2830 report_open_failure(hostspath, errno, FALSE);
2832 g_free(hostspath);
2833 #ifdef HAVE_C_ARES
2834 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2835 if (ares_library_init(ARES_LIB_INIT_ALL) == ARES_SUCCESS) {
2836 #endif
2837 if (ares_init(&ghba_chan) == ARES_SUCCESS && ares_init(&ghbn_chan) == ARES_SUCCESS) {
2838 async_dns_initialized = TRUE;
2840 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2842 #endif
2843 #else
2844 #ifdef HAVE_GNU_ADNS
2846 * We're using GNU ADNS, which doesn't check the system hosts file;
2847 * we load that file ourselves.
2849 #ifdef _WIN32
2851 sysroot = getenv_utf8("WINDIR");
2852 if (sysroot != NULL) {
2854 * The file should be under WINDIR.
2855 * If this is Windows NT (NT 4.0,2K,XP,Server2K3), it's in
2856 * %WINDIR%\system32\drivers\etc\hosts.
2857 * If this is Windows OT (95,98,Me), it's in %WINDIR%\hosts.
2858 * Try both.
2859 * XXX - should we base it on the dwPlatformId value from
2860 * GetVersionEx()?
2862 if(!gbl_resolv_flags.load_hosts_file_from_profile_only){
2863 hostspath = g_strconcat(sysroot, rootpath_nt, NULL);
2864 if (!read_hosts_file(hostspath)) {
2865 g_free(hostspath);
2866 hostspath = g_strconcat(sysroot, rootpath_ot, NULL);
2867 read_hosts_file(hostspath);
2869 g_free(hostspath);
2872 #else /* _WIN32 */
2873 if(!gbl_resolv_flags.load_hosts_file_from_profile_only){
2874 read_hosts_file("/etc/hosts");
2876 #endif /* _WIN32 */
2878 /* XXX - Any flags we should be using? */
2879 /* XXX - We could provide config settings for DNS servers, and
2880 pass them to ADNS with adns_init_strcfg */
2881 if (adns_init(&ads, adns_if_none, 0 /*0=>stderr*/) != 0) {
2883 * XXX - should we report the error? I'm assuming that some crashes
2884 * reported on a Windows machine with TCP/IP not configured are due
2885 * to "adns_init()" failing (due to the lack of TCP/IP) and leaving
2886 * ADNS in a state where it crashes due to that. We'll still try
2887 * doing name resolution anyway.
2889 return;
2891 async_dns_initialized = TRUE;
2892 async_dns_in_flight = 0;
2893 #endif /* HAVE_GNU_ADNS */
2894 #endif /* HAVE_C_ARES */
2896 if(extra_hosts_files && !gbl_resolv_flags.load_hosts_file_from_profile_only){
2897 for (i = 0; i < extra_hosts_files->len; i++) {
2898 read_hosts_file((const char *) g_ptr_array_index(extra_hosts_files, i));
2902 subnet_name_lookup_init();
2904 add_manually_resolved();
2907 void
2908 host_name_lookup_cleanup(void)
2910 _host_name_lookup_cleanup();
2912 if(ipxnet_hash_table){
2913 g_hash_table_destroy(ipxnet_hash_table);
2914 ipxnet_hash_table = NULL;
2917 if(ipv4_hash_table){
2918 g_hash_table_destroy(ipv4_hash_table);
2919 ipv4_hash_table = NULL;
2922 if(ipv6_hash_table){
2923 g_hash_table_destroy(ipv6_hash_table);
2924 ipv6_hash_table = NULL;
2927 memset(subnet_length_entries, 0, sizeof(subnet_length_entries));
2929 have_subnet_entry = FALSE;
2930 new_resolved_objects = FALSE;
2933 static void
2934 free_manually_resolved_ipv4(gpointer data, gpointer user_data _U_)
2936 resolved_ipv4_t *resolved_ipv4_entry = (resolved_ipv4_t *)data;
2938 g_free(resolved_ipv4_entry);
2942 static void
2943 free_manually_resolved_ipv6(gpointer data, gpointer user_data _U_)
2945 resolved_ipv6_t *resolved_ipv6_entry = (resolved_ipv6_t *)data;
2947 g_free(resolved_ipv6_entry);
2951 void
2952 manually_resolve_cleanup(void)
2954 if(manually_resolved_ipv4_list){
2955 g_slist_foreach(manually_resolved_ipv4_list, free_manually_resolved_ipv4, NULL);
2956 g_slist_free(manually_resolved_ipv4_list);
2957 manually_resolved_ipv4_list = NULL;
2960 if(manually_resolved_ipv6_list){
2961 g_slist_foreach(manually_resolved_ipv6_list, free_manually_resolved_ipv6, NULL);
2962 g_slist_free(manually_resolved_ipv6_list);
2963 manually_resolved_ipv6_list = NULL;
2968 gchar *
2969 get_udp_port(guint port)
2972 if (!gbl_resolv_flags.transport_name) {
2973 return ep_utoa(port);
2976 return serv_name_lookup(port, PT_UDP);
2978 } /* get_udp_port */
2980 gchar *
2981 get_dccp_port(guint port)
2984 if (!gbl_resolv_flags.transport_name) {
2985 return ep_utoa(port);
2988 return serv_name_lookup(port, PT_DCCP);
2990 } /* get_dccp_port */
2992 gchar *
2993 get_tcp_port(guint port)
2996 if (!gbl_resolv_flags.transport_name) {
2997 return ep_utoa(port);
3000 return serv_name_lookup(port, PT_TCP);
3002 } /* get_tcp_port */
3004 gchar *
3005 get_sctp_port(guint port)
3008 if (!gbl_resolv_flags.transport_name) {
3009 return ep_utoa(port);
3012 return serv_name_lookup(port, PT_SCTP);
3014 } /* get_sctp_port */
3016 const gchar *
3017 get_addr_name(const address *addr)
3019 const gchar *result;
3021 result = solve_address_to_name(addr);
3023 if (result != NULL)
3024 return result;
3026 /* if it gets here, either it is of type AT_NONE, */
3027 /* or it should be solvable in address_to_str -unless addr->type is wrongly defined */
3029 if (addr->type == AT_NONE){
3030 return "NONE";
3033 /* We need an ephemeral allocated string */
3034 return ep_address_to_str(addr);
3037 const gchar *
3038 se_get_addr_name(const address *addr)
3040 const gchar *result;
3042 result = se_solve_address_to_name(addr);
3044 if (result != NULL)
3045 return result;
3047 /* if it gets here, either it is of type AT_NONE, */
3048 /* or it should be solvable in se_address_to_str -unless addr->type is wrongly defined */
3050 if (addr->type == AT_NONE){
3051 return "NONE";
3054 /* We need a "permanently" allocated string */
3055 return se_address_to_str(addr);
3058 void
3059 get_addr_name_buf(const address *addr, gchar *buf, gsize size)
3061 const gchar *result = get_addr_name(addr);
3063 g_strlcpy(buf, result, size);
3064 } /* get_addr_name_buf */
3067 gchar *
3068 get_ether_name(const guint8 *addr)
3070 hashether_t *tp;
3071 gboolean resolve = gbl_resolv_flags.mac_name;
3073 tp = eth_name_lookup(addr, resolve);
3075 return resolve ? tp->resolved_name : tp->hexaddr;
3077 } /* get_ether_name */
3079 /* Look for a (non-dummy) ether name in the hash, and return it if found.
3080 * If it's not found, simply return NULL.
3082 gchar *
3083 get_ether_name_if_known(const guint8 *addr)
3085 hashether_t *tp;
3087 /* Initialize ether structs if we're the first
3088 * ether-related function called */
3089 if (!gbl_resolv_flags.mac_name)
3090 return NULL;
3092 /* eth_name_lookup will create a (resolved) hash entry if it doesn't exist */
3093 tp = eth_name_lookup(addr, TRUE);
3094 g_assert(tp != NULL);
3096 if (tp->status == HASHETHER_STATUS_RESOLVED_NAME) {
3097 /* Name is from an ethers file (or is a "well-known" MAC address name from the manuf file) */
3098 return tp->resolved_name;
3100 else {
3101 /* Name was created */
3102 return NULL;
3106 guint8 *
3107 get_ether_addr(const gchar *name)
3110 /* force resolution (do not check gbl_resolv_flags) */
3111 return eth_addr_lookup(name);
3113 } /* get_ether_addr */
3115 void
3116 add_ether_byip(const guint ip, const guint8 *eth)
3118 gboolean found;
3119 hashipv4_t *tp;
3121 /* first check that IP address can be resolved */
3122 if (!gbl_resolv_flags.network_name)
3123 return;
3125 tp = host_lookup(ip, &found);
3126 if (found) {
3127 /* ok, we can add this entry in the ethers hashtable */
3128 add_eth_name(eth, tp->name);
3131 } /* add_ether_byip */
3133 const gchar *
3134 get_ipxnet_name(const guint32 addr)
3137 if (!gbl_resolv_flags.network_name) {
3138 return ipxnet_to_str_punct(addr, '\0');
3141 return ipxnet_name_lookup(addr);
3143 } /* get_ipxnet_name */
3145 guint32
3146 get_ipxnet_addr(const gchar *name, gboolean *known)
3148 guint32 addr;
3149 gboolean success;
3151 /* force resolution (do not check gbl_resolv_flags) */
3152 addr = ipxnet_addr_lookup(name, &success);
3154 *known = success;
3155 return addr;
3157 } /* get_ipxnet_addr */
3159 const gchar *
3160 get_manuf_name(const guint8 *addr)
3162 gchar *cur;
3163 int manuf_key;
3164 guint8 oct;
3166 /* manuf needs only the 3 most significant octets of the ethernet address */
3167 manuf_key = addr[0];
3168 manuf_key = manuf_key<<8;
3169 oct = addr[1];
3170 manuf_key = manuf_key | oct;
3171 manuf_key = manuf_key<<8;
3172 oct = addr[2];
3173 manuf_key = manuf_key | oct;
3175 if (!gbl_resolv_flags.mac_name || ((cur = (gchar *)g_hash_table_lookup(manuf_hashtable, &manuf_key)) == NULL)) {
3176 cur=ep_strdup_printf("%02x:%02x:%02x", addr[0], addr[1], addr[2]);
3177 return cur;
3180 return cur;
3182 } /* get_manuf_name */
3184 const gchar *
3185 uint_get_manuf_name(const guint oid)
3187 guint8 addr[3];
3189 addr[0] = (oid >> 16) & 0xFF;
3190 addr[1] = (oid >> 8) & 0xFF;
3191 addr[2] = (oid >> 0) & 0xFF;
3192 return get_manuf_name(addr);
3195 const gchar *
3196 tvb_get_manuf_name(tvbuff_t *tvb, gint offset)
3198 return get_manuf_name(tvb_get_ptr(tvb, offset, 3));
3201 const gchar *
3202 get_manuf_name_if_known(const guint8 *addr)
3204 gchar *cur;
3205 int manuf_key;
3206 guint8 oct;
3208 /* manuf needs only the 3 most significant octets of the ethernet address */
3209 manuf_key = addr[0];
3210 manuf_key = manuf_key<<8;
3211 oct = addr[1];
3212 manuf_key = manuf_key | oct;
3213 manuf_key = manuf_key<<8;
3214 oct = addr[2];
3215 manuf_key = manuf_key | oct;
3217 if ((cur = (gchar *)g_hash_table_lookup(manuf_hashtable, &manuf_key)) == NULL) {
3218 return NULL;
3221 return cur;
3223 } /* get_manuf_name_if_known */
3225 const gchar *
3226 uint_get_manuf_name_if_known(const guint manuf_key)
3228 gchar *cur;
3230 if ((cur = (gchar *)g_hash_table_lookup(manuf_hashtable, &manuf_key)) == NULL) {
3231 return NULL;
3234 return cur;
3237 const gchar *
3238 tvb_get_manuf_name_if_known(tvbuff_t *tvb, gint offset)
3240 return get_manuf_name_if_known(tvb_get_ptr(tvb, offset, 3));
3243 const gchar *
3244 get_eui64_name(const guint64 addr_eui64)
3246 gchar *cur, *name;
3247 guint8 *addr = (guint8 *)ep_alloc(8);
3249 /* Copy and convert the address to network byte order. */
3250 *(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64));
3252 if (!gbl_resolv_flags.mac_name || ((name = manuf_name_lookup(addr)) == NULL)) {
3253 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]);
3254 return cur;
3256 cur=ep_strdup_printf("%s_%02x:%02x:%02x:%02x:%02x", name, addr[3], addr[4], addr[5], addr[6], addr[7]);
3257 return cur;
3259 } /* get_eui64_name */
3262 const gchar *
3263 get_eui64_name_if_known(const guint64 addr_eui64)
3265 gchar *cur, *name;
3266 guint8 *addr = (guint8 *)ep_alloc(8);
3268 /* Copy and convert the address to network byte order. */
3269 *(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64));
3271 if ((name = manuf_name_lookup(addr)) == NULL) {
3272 return NULL;
3275 cur=ep_strdup_printf("%s_%02x:%02x:%02x:%02x:%02x", name, addr[3], addr[4], addr[5], addr[6], addr[7]);
3276 return cur;
3278 } /* get_eui64_name_if_known */
3280 #ifdef HAVE_C_ARES
3281 #define GHI_TIMEOUT (250 * 1000)
3282 static void
3283 c_ares_ghi_cb(
3284 void *arg,
3285 int status,
3286 #if ( ( ARES_VERSION_MAJOR < 1 ) \
3287 || ( 1 == ARES_VERSION_MAJOR && ARES_VERSION_MINOR < 5 ) )
3288 struct hostent *hp
3289 #else
3290 int timeouts _U_,
3291 struct hostent *hp
3292 #endif
3296 * XXX - If we wanted to be really fancy we could cache results here and
3297 * look them up in get_host_ipaddr* below.
3299 async_hostent_t *ahp = (async_hostent_t *)arg;
3300 if (status == ARES_SUCCESS && hp && ahp && hp->h_length == ahp->addr_size) {
3301 memcpy(ahp->addrp, hp->h_addr, hp->h_length);
3302 ahp->copied = hp->h_length;
3305 #endif /* HAVE_C_ARES */
3307 /* Translate a string, assumed either to be a dotted-quad IP address or
3308 * a host name, to a numeric IP address. Return TRUE if we succeed and
3309 * set "*addrp" to that numeric IP address; return FALSE if we fail.
3310 * Used more in the dfilter parser rather than in packet dissectors */
3311 gboolean
3312 get_host_ipaddr(const char *host, guint32 *addrp)
3314 struct in_addr ipaddr;
3315 #ifdef HAVE_C_ARES
3316 struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
3317 int nfds;
3318 fd_set rfds, wfds;
3319 async_hostent_t ahe;
3320 #else /* HAVE_C_ARES */
3321 struct hostent *hp;
3322 #endif /* HAVE_C_ARES */
3325 * don't change it to inet_pton(AF_INET), they are not 100% compatible.
3326 * inet_pton(AF_INET) does not support hexadecimal notation nor
3327 * less-than-4 octet notation.
3329 if (!inet_aton(host, &ipaddr)) {
3331 /* It's not a valid dotted-quad IP address; is it a valid
3332 * host name?
3335 /* If we're not allowed to do name resolution, don't do name
3336 * resolution...
3338 if (!gbl_resolv_flags.network_name ||
3339 !gbl_resolv_flags.use_external_net_name_resolver) {
3340 return FALSE;
3343 #ifdef HAVE_C_ARES
3344 if (! (gbl_resolv_flags.concurrent_dns) ||
3345 name_resolve_concurrency < 1 ||
3346 ! async_dns_initialized) {
3347 return FALSE;
3349 ahe.addr_size = (int) sizeof (struct in_addr);
3350 ahe.copied = 0;
3351 ahe.addrp = addrp;
3352 ares_gethostbyname(ghbn_chan, host, AF_INET, c_ares_ghi_cb, &ahe);
3353 FD_ZERO(&rfds);
3354 FD_ZERO(&wfds);
3355 nfds = ares_fds(ghbn_chan, &rfds, &wfds);
3356 if (nfds > 0) {
3357 tvp = ares_timeout(ghbn_chan, &tv, &tv);
3358 if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
3359 fprintf(stderr, "Warning: call to select() failed, error is %s\n", strerror(errno));
3360 return FALSE;
3362 ares_process(ghbn_chan, &rfds, &wfds);
3364 ares_cancel(ghbn_chan);
3365 if (ahe.addr_size == ahe.copied) {
3366 return TRUE;
3368 return FALSE;
3369 #else /* ! HAVE_C_ARES */
3370 hp = gethostbyname(host);
3371 if (hp == NULL) {
3372 /* No. */
3373 return FALSE;
3374 /* Apparently, some versions of gethostbyaddr can
3375 * return IPv6 addresses. */
3376 } else if (hp->h_length <= (int) sizeof (struct in_addr)) {
3377 memcpy(&ipaddr, hp->h_addr, hp->h_length);
3378 } else {
3379 return FALSE;
3381 #endif /* HAVE_C_ARES */
3382 } else {
3383 /* Does the string really contain dotted-quad IP?
3384 * Check against inet_atons that accept strings such as
3385 * "130.230" as valid addresses and try to convert them
3386 * to some form of a classful (host.net) notation.
3388 unsigned int a0, a1, a2, a3;
3389 if (sscanf(host, "%u.%u.%u.%u", &a0, &a1, &a2, &a3) != 4)
3390 return FALSE;
3393 *addrp = ipaddr.s_addr;
3394 return TRUE;
3398 * Translate IPv6 numeric address or FQDN hostname, into binary IPv6 address.
3399 * Return TRUE if we succeed and set "*addrp" to that numeric IP address;
3400 * return FALSE if we fail.
3402 gboolean
3403 get_host_ipaddr6(const char *host, struct e_in6_addr *addrp)
3405 #ifdef HAVE_C_ARES
3406 struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
3407 int nfds;
3408 fd_set rfds, wfds;
3409 async_hostent_t ahe;
3410 #elif defined(HAVE_GETHOSTBYNAME2)
3411 struct hostent *hp;
3412 #endif /* HAVE_C_ARES */
3414 if (inet_pton(AF_INET6, host, addrp) > 0)
3415 return TRUE;
3417 /* It's not a valid dotted-quad IP address; is it a valid
3418 * host name?
3421 /* If we're not allowed to do name resolution, don't do name
3422 * resolution...
3424 if (!gbl_resolv_flags.network_name ||
3425 !gbl_resolv_flags.use_external_net_name_resolver) {
3426 return FALSE;
3429 /* try FQDN */
3430 #ifdef HAVE_C_ARES
3431 if (! (gbl_resolv_flags.concurrent_dns) ||
3432 name_resolve_concurrency < 1 ||
3433 ! async_dns_initialized) {
3434 return FALSE;
3436 ahe.addr_size = (int) sizeof (struct e_in6_addr);
3437 ahe.copied = 0;
3438 ahe.addrp = addrp;
3439 ares_gethostbyname(ghbn_chan, host, AF_INET6, c_ares_ghi_cb, &ahe);
3440 FD_ZERO(&rfds);
3441 FD_ZERO(&wfds);
3442 nfds = ares_fds(ghbn_chan, &rfds, &wfds);
3443 if (nfds > 0) {
3444 tvp = ares_timeout(ghbn_chan, &tv, &tv);
3445 if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
3446 fprintf(stderr, "Warning: call to select() failed, error is %s\n", strerror(errno));
3447 return FALSE;
3449 ares_process(ghbn_chan, &rfds, &wfds);
3451 ares_cancel(ghbn_chan);
3452 if (ahe.addr_size == ahe.copied) {
3453 return TRUE;
3455 #elif defined(HAVE_GETHOSTBYNAME2)
3456 hp = gethostbyname2(host, AF_INET6);
3457 if (hp != NULL && hp->h_length == sizeof(struct e_in6_addr)) {
3458 memcpy(addrp, hp->h_addr, hp->h_length);
3459 return TRUE;
3461 #endif
3463 return FALSE;
3467 * Find out whether a hostname resolves to an ip or ipv6 address
3468 * Return "ip6" if it is IPv6, "ip" otherwise (including the case
3469 * that we don't know)
3471 const char* host_ip_af(const char *host
3472 #ifndef HAVE_GETHOSTBYNAME2
3474 #endif
3477 #ifdef HAVE_GETHOSTBYNAME2
3478 struct hostent *h;
3479 return (h = gethostbyname2(host, AF_INET6)) && h->h_addrtype == AF_INET6 ? "ip6" : "ip";
3480 #else
3481 return "ip";
3482 #endif
3485 GHashTable *
3486 get_manuf_hashtable(void)
3488 return manuf_hashtable;
3491 GHashTable *
3492 get_wka_hashtable(void)
3494 return wka_hashtable;
3497 GHashTable *
3498 get_eth_hashtable(void)
3500 return eth_hashtable;
3503 GHashTable *
3504 get_serv_port_hashtable(void)
3506 return serv_port_hashtable;
3509 GHashTable *
3510 get_ipxnet_hash_table(void)
3512 return ipxnet_hash_table;
3515 GHashTable *
3516 get_ipv4_hash_table(void)
3518 return ipv4_hash_table;
3521 GHashTable *
3522 get_ipv6_hash_table(void)
3524 return ipv6_hash_table;
3526 /* Initialize all the address resolution subsystems in this file */
3527 void
3528 addr_resolv_init(void)
3530 initialize_services();
3531 initialize_ethers();
3532 initialize_ipxnets();
3533 /* host name initialization is done on a per-capture-file basis */
3534 /*host_name_lookup_init();*/
3537 /* Clean up all the address resolution subsystems in this file */
3538 void
3539 addr_resolv_cleanup(void)
3541 service_name_lookup_cleanup();
3542 eth_name_lookup_cleanup();
3543 ipx_name_lookup_cleanup();
3544 /* host name initialization is done on a per-capture-file basis */
3545 /*host_name_lookup_cleanup();*/
3549 * Editor modelines - http://www.wireshark.org/tools/modelines.html
3551 * Local variables:
3552 * c-basic-offset: 4
3553 * tab-width: 8
3554 * indent-tabs-mode: nil
3555 * End:
3557 * vi: set shiftwidth=4 tabstop=8 expandtab:
3558 * :indentSize=4:tabSize=8:noTabs=true: