NAS EPS: upgrade dissector to v15.4.0
[metze/wireshark/wip.git] / epan / addr_resolv.c
1 /* addr_resolv.c
2  * Routines for network object lookup
3  *
4  * Laurent Deniel <laurent.deniel@free.fr>
5  *
6  * Add option to resolv VLAN ID to describing name
7  * Uli Heilmeier, March 2016
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * SPDX-License-Identifier: GPL-2.0-or-later
14  */
15
16 #include "config.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22
23 #include <wsutil/strtoi.h>
24
25 /*
26  * Win32 doesn't have SIGALRM (and it's the OS where name lookup calls
27  * are most likely to take a long time, given the way address-to-name
28  * lookups are done over NBNS).
29  *
30  * macOS does have SIGALRM, but if you longjmp() out of a name resolution
31  * call in a signal handler, you might crash, because the state of the
32  * resolution code that sends messages to lookupd might be inconsistent
33  * if you jump out of it in middle of a call.
34  *
35  * There's no guarantee that longjmp()ing out of name resolution calls
36  * will work on *any* platform; OpenBSD got rid of the alarm/longjmp
37  * code in tcpdump, to avoid those sorts of problems, and that was
38  * picked up by tcpdump.org tcpdump.
39  *
40  * So, for now, we do not use alarm() and SIGALRM to time out host name
41  * lookups.  If we get a lot of complaints about lookups taking a long time,
42  * we can reconsider that decision.  (Note that tcpdump originally added
43  * such a timeout mechanism that for the benefit of systems using NIS to
44  * look up host names; that might now be fixed in NIS implementations, for
45  * those sites still using NIS rather than DNS for that....  tcpdump no
46  * longer does that, for the same reasons that we don't.)
47  *
48  * If we're using an asynchronous DNS resolver, that shouldn't be an issue.
49  * If we're using a synchronous name lookup mechanism (which we'd do mainly
50  * to support resolving addresses and host names using more mechanisms than
51  * just DNS, such as NIS, NBNS, or Mr. Hosts File), we could do that in
52  * a separate thread, making it, in effect, asynchronous.
53  */
54
55 #ifdef HAVE_NETINET_IN_H
56 # include <netinet/in.h>
57 #endif
58
59 #ifdef HAVE_NETDB_H
60 #include <netdb.h>
61 #endif
62
63 #ifdef HAVE_SYS_SOCKET_H
64 #include <sys/socket.h>     /* needed to define AF_ values on UNIX */
65 #endif
66
67 #ifdef _WIN32
68 #include <winsock2.h>       /* needed to define AF_ values on Windows */
69 #include <ws2tcpip.h>
70 #endif
71
72 #ifdef HAVE_C_ARES
73 # ifdef _WIN32
74 #  define socklen_t unsigned int
75 # endif
76 # include <ares.h>
77 # include <ares_version.h>
78 #endif  /* HAVE_C_ARES */
79
80 #include <glib.h>
81
82 #include "packet.h"
83 #include "addr_and_mask.h"
84 #include "ipv6.h"
85 #include "addr_resolv.h"
86 #include "wsutil/filesystem.h"
87
88 #include <wsutil/report_message.h>
89 #include <wsutil/file_util.h>
90 #include <wsutil/pint.h>
91 #include <wsutil/inet_addr.h>
92
93 #include <epan/strutil.h>
94 #include <epan/to_str-int.h>
95 #include <epan/maxmind_db.h>
96 #include <epan/prefs.h>
97
98 #define ENAME_HOSTS     "hosts"
99 #define ENAME_SUBNETS   "subnets"
100 #define ENAME_ETHERS    "ethers"
101 #define ENAME_IPXNETS   "ipxnets"
102 #define ENAME_MANUF     "manuf"
103 #define ENAME_WKA       "wka"
104 #define ENAME_SERVICES  "services"
105 #define ENAME_VLANS     "vlans"
106 #define ENAME_SS7PCS    "ss7pcs"
107 #define ENAME_ENTERPRISES "enterprises.tsv"
108
109 #define HASHETHSIZE      2048
110 #define HASHHOSTSIZE     2048
111 #define HASHIPXNETSIZE    256
112 #define SUBNETLENGTHSIZE   32  /*1-32 inc.*/
113
114 /* hash table used for IPv4 lookup */
115
116 #define HASH_IPV4_ADDRESS(addr) (g_htonl(addr) & (HASHHOSTSIZE - 1))
117
118
119 typedef struct sub_net_hashipv4 {
120     guint             addr;
121     /* XXX: No longer needed?*/
122     guint8            flags;          /* B0 dummy_entry, B1 resolve, B2 If the address is used in the trace */
123     struct sub_net_hashipv4   *next;
124     gchar             name[MAXNAMELEN];
125 } sub_net_hashipv4_t;
126
127 /* Array of entries of subnets of different lengths */
128 typedef struct {
129     gsize        mask_length;      /*1-32*/
130     guint32      mask;             /* e.g. 255.255.255.*/
131     sub_net_hashipv4_t** subnet_addresses; /* Hash table of subnet addresses */
132 } subnet_length_entry_t;
133
134
135 /* hash table used for IPX network lookup */
136
137 /* XXX - check goodness of hash function */
138
139 #define HASH_IPX_NET(net)   ((net) & (HASHIPXNETSIZE - 1))
140
141 typedef struct hashipxnet {
142     guint               addr;
143     struct hashipxnet  *next;
144     gchar               name[MAXNAMELEN];
145 } hashipxnet_t;
146
147 typedef struct hashvlan {
148     guint               id;
149 /*    struct hashvlan     *next; */
150     gchar               name[MAXVLANNAMELEN];
151 } hashvlan_t;
152
153 typedef struct ss7pc {
154     guint32             id; /* 1st byte NI, 3 following bytes: Point Code */
155     gchar               pc_addr[MAXNAMELEN];
156     gchar               name[MAXNAMELEN];
157 } hashss7pc_t;
158
159 /* hash tables used for ethernet and manufacturer lookup */
160 #define HASHETHER_STATUS_UNRESOLVED     1
161 #define HASHETHER_STATUS_RESOLVED_DUMMY 2
162 #define HASHETHER_STATUS_RESOLVED_NAME  3
163
164 struct hashether {
165     guint             status;  /* (See above) */
166     guint8            addr[6];
167     char              hexaddr[6*3];
168     char              resolved_name[MAXNAMELEN];
169 };
170
171 struct hashmanuf {
172     guint             status;  /* (See above) */
173     guint8            addr[3];
174     char              hexaddr[3*3];
175     char              resolved_name[MAXNAMELEN];
176     char              resolved_longname[MAXNAMELEN];
177 };
178
179 /* internal ethernet type */
180 typedef struct _ether
181 {
182     guint8            addr[6];
183     char              name[MAXNAMELEN];
184     char              longname[MAXNAMELEN];
185 } ether_t;
186
187 /* internal ipxnet type */
188 typedef struct _ipxnet
189 {
190     guint             addr;
191     char              name[MAXNAMELEN];
192 } ipxnet_t;
193
194 /* internal vlan type */
195 typedef struct _vlan
196 {
197     guint             id;
198     char              name[MAXVLANNAMELEN];
199 } vlan_t;
200
201 static wmem_map_t *ipxnet_hash_table = NULL;
202 static wmem_map_t *ipv4_hash_table = NULL;
203 static wmem_map_t *ipv6_hash_table = NULL;
204 static wmem_map_t *vlan_hash_table = NULL;
205 static wmem_map_t *ss7pc_hash_table = NULL;
206
207 static wmem_list_t *manually_resolved_ipv4_list = NULL;
208 static wmem_list_t *manually_resolved_ipv6_list = NULL;
209
210 typedef struct _resolved_ipv4
211 {
212     guint32          host_addr;
213     char             name[MAXNAMELEN];
214 } resolved_ipv4_t;
215
216 typedef struct _resolved_ipv6
217 {
218     ws_in6_addr  ip6_addr;
219     char               name[MAXNAMELEN];
220 } resolved_ipv6_t;
221
222 static addrinfo_lists_t addrinfo_lists = { NULL, NULL};
223
224 struct cb_serv_data {
225     gchar       *service;
226     port_type    proto;
227 };
228
229 static wmem_map_t *manuf_hashtable = NULL;
230 static wmem_map_t *wka_hashtable = NULL;
231 static wmem_map_t *eth_hashtable = NULL;
232 static wmem_map_t *serv_port_hashtable = NULL;
233 static GHashTable *enterprises_hashtable = NULL;
234
235 static subnet_length_entry_t subnet_length_entries[SUBNETLENGTHSIZE]; /* Ordered array of entries */
236 static gboolean have_subnet_entry = FALSE;
237
238 static gboolean new_resolved_objects = FALSE;
239
240 static GPtrArray* extra_hosts_files = NULL;
241
242 static hashether_t *add_eth_name(const guint8 *addr, const gchar *name);
243 static void add_serv_port_cb(const guint32 port, gpointer ptr);
244
245
246 /* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
247  * One-at-a-Time hash
248  */
249 guint
250 ipv6_oat_hash(gconstpointer key)
251 {
252     int len = 16;
253     const unsigned char *p = (const unsigned char *)key;
254     guint h = 0;
255     int i;
256
257     for ( i = 0; i < len; i++ ) {
258         h += p[i];
259         h += ( h << 10 );
260         h ^= ( h >> 6 );
261     }
262
263     h += ( h << 3 );
264     h ^= ( h >> 11 );
265     h += ( h << 15 );
266
267     return h;
268 }
269
270 gboolean
271 ipv6_equal(gconstpointer v1, gconstpointer v2)
272 {
273
274     if (memcmp(v1, v2, sizeof (ws_in6_addr)) == 0) {
275         return TRUE;
276     }
277
278     return FALSE;
279 }
280
281 /*
282  * Flag controlling what names to resolve.
283  */
284 e_addr_resolve gbl_resolv_flags = {
285     TRUE,   /* mac_name */
286     FALSE,  /* network_name */
287     FALSE,  /* transport_name */
288     TRUE,   /* dns_pkt_addr_resolution */
289     TRUE,   /* use_external_net_name_resolver */
290     FALSE,  /* load_hosts_file_from_profile_only */
291     FALSE,  /* vlan_name */
292     FALSE   /* ss7 point code names */
293 };
294 #ifdef HAVE_C_ARES
295 static guint name_resolve_concurrency = 500;
296 static gboolean resolve_synchronously = FALSE;
297 #endif
298
299 /*
300  *  Global variables (can be changed in GUI sections)
301  *  XXX - they could be changed in GUI code, but there's currently no
302  *  GUI code to change them.
303  */
304
305 gchar *g_ethers_path    = NULL;     /* global ethers file     */
306 gchar *g_pethers_path   = NULL;     /* personal ethers file   */
307 gchar *g_wka_path       = NULL;     /* global well-known-addresses file */
308 gchar *g_manuf_path     = NULL;     /* global manuf file      */
309 gchar *g_ipxnets_path   = NULL;     /* global ipxnets file    */
310 gchar *g_pipxnets_path  = NULL;     /* personal ipxnets file  */
311 gchar *g_services_path  = NULL;     /* global services file   */
312 gchar *g_pservices_path = NULL;     /* personal services file */
313 gchar *g_pvlan_path     = NULL;     /* personal vlans file    */
314 gchar *g_ss7pcs_path    = NULL;     /* personal ss7pcs file   */
315 gchar *g_enterprises_path = NULL;   /* global enterprises file   */
316 gchar *g_penterprises_path = NULL;  /* personal enterprises file */
317                                     /* first resolving call   */
318
319 /* c-ares */
320 #ifdef HAVE_C_ARES
321 /*
322  * Submitted asynchronous queries trigger a callback (c_ares_ghba_cb()).
323  * Queries are added to c_ares_queue_head. During processing, queries are
324  * popped off the front of c_ares_queue_head and submitted using
325  * ares_gethostbyaddr().
326  * The callback processes the response, then frees the request.
327  */
328 typedef struct _async_dns_queue_msg
329 {
330     union {
331         guint32           ip4;
332         ws_in6_addr ip6;
333     } addr;
334     int                 family;
335 } async_dns_queue_msg_t;
336
337 typedef struct _async_hostent {
338     int addr_size;
339     int   copied;
340     void *addrp;
341 } async_hostent_t;
342
343 /*
344  * Submitted synchronous queries trigger a callback (c_ares_ghba_sync_cb()).
345  * The callback processes the response, sets completed to TRUE if
346  * completed is non-NULL, then frees the request.
347  */
348 typedef struct _sync_dns_data
349 {
350     union {
351         guint32      ip4;
352         ws_in6_addr  ip6;
353     } addr;
354     int              family;
355     gboolean        *completed;
356 } sync_dns_data_t;
357
358 static ares_channel ghba_chan; /* ares_gethostbyaddr -- Usually non-interactive, no timeout */
359 static ares_channel ghbn_chan; /* ares_gethostbyname -- Usually interactive, timeout */
360
361 static  gboolean  async_dns_initialized = FALSE;
362 static  guint       async_dns_in_flight = 0;
363 static  wmem_list_t *async_dns_queue_head = NULL;
364
365 static void
366 c_ares_ghba_sync_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
367     sync_dns_data_t *sdd = (sync_dns_data_t *)arg;
368     char **p;
369
370     if (status == ARES_SUCCESS) {
371         for (p = he->h_addr_list; *p != NULL; p++) {
372             switch(sdd->family) {
373                 case AF_INET:
374                     add_ipv4_name(sdd->addr.ip4, he->h_name);
375                     break;
376                 case AF_INET6:
377                     add_ipv6_name(&sdd->addr.ip6, he->h_name);
378                     break;
379                 default:
380                     /* Throw an exception? */
381                     break;
382             }
383         }
384
385     }
386
387     /*
388      * Let our caller know that this is complete.
389      */
390     *sdd->completed = TRUE;
391
392     /*
393      * Free the structure for this call.
394      */
395     g_free(sdd);
396 }
397
398 static void
399 wait_for_sync_resolv(gboolean *completed) {
400     int nfds;
401     fd_set rfds, wfds;
402     struct timeval tv;
403
404     while (!*completed) {
405         /*
406          * Not yet resolved; wait for something to show up on the
407          * address-to-name C-ARES channel.
408          *
409          * To quote the source code for ares_timeout() as of C-ARES
410          * 1.12.0, "WARNING: Beware that this is linear in the number
411          * of outstanding requests! You are probably far better off
412          * just calling ares_process() once per second, rather than
413          * calling ares_timeout() to figure out when to next call
414          * ares_process().", although we should have only one request
415          * outstanding.
416          *
417          * And, yes, we have to reset it each time, as select(), in
418          * some OSes modifies the timeout to reflect the time remaining
419          * (e.g., Linux) and select() in other OSes doesn't (most if not
420          * all other UN*Xes, Windows?), so we can't rely on *either*
421          * behavior.
422          */
423         tv.tv_sec = 1;
424         tv.tv_usec = 0;
425
426         FD_ZERO(&rfds);
427         FD_ZERO(&wfds);
428         nfds = ares_fds(ghba_chan, &rfds, &wfds);
429         if (nfds > 0) {
430             if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
431                 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
432                 return;
433             }
434             ares_process(ghba_chan, &rfds, &wfds);
435         }
436     }
437 }
438
439 static void
440 sync_lookup_ip4(const guint32 addr)
441 {
442     gboolean completed = FALSE;
443     sync_dns_data_t *sdd;
444
445     if (!async_dns_initialized) {
446         /*
447          * c-ares not initialized.  Bail out.
448          */
449         return;
450     }
451
452     /*
453      * Start the request.
454      */
455     sdd = g_new(sync_dns_data_t, 1);
456     sdd->family = AF_INET;
457     sdd->addr.ip4 = addr;
458     sdd->completed = &completed;
459     ares_gethostbyaddr(ghba_chan, &addr, sizeof(guint32), AF_INET,
460                        c_ares_ghba_sync_cb, sdd);
461
462     /*
463      * Now wait for it to finish.
464      */
465     wait_for_sync_resolv(&completed);
466 }
467
468 static void
469 sync_lookup_ip6(const ws_in6_addr *addr)
470 {
471     gboolean completed = FALSE;
472     sync_dns_data_t *sdd;
473
474     if (!async_dns_initialized) {
475         /*
476          * c-ares not initialized.  Bail out.
477          */
478         return;
479     }
480
481     /*
482      * Start the request.
483      */
484     sdd = g_new(sync_dns_data_t, 1);
485     sdd->family = AF_INET6;
486     memcpy(&sdd->addr.ip6, addr, sizeof(sdd->addr.ip6));
487     sdd->completed = &completed;
488     ares_gethostbyaddr(ghba_chan, &addr, sizeof(ws_in6_addr), AF_INET6,
489                        c_ares_ghba_sync_cb, sdd);
490
491     /*
492      * Now wait for it to finish.
493      */
494     wait_for_sync_resolv(&completed);
495 }
496
497 void
498 set_resolution_synchrony(gboolean synchronous)
499 {
500     resolve_synchronously = synchronous;
501 }
502 #else
503 void
504 set_resolution_synchrony(gboolean synchronous _U_)
505 {
506     /* Nothing to set. */
507 }
508 #endif /* HAVE_C_ARES */
509
510 typedef struct {
511     guint32      mask;
512     gsize        mask_length;
513     const gchar* name; /* Shallow copy */
514 } subnet_entry_t;
515
516 /*
517  *  Miscellaneous functions
518  */
519
520 static int
521 fgetline(char **buf, int *size, FILE *fp)
522 {
523     int len;
524     int c;
525
526     if (fp == NULL || buf == NULL)
527         return -1;
528
529     if (*buf == NULL) {
530         if (*size == 0)
531             *size = BUFSIZ;
532
533         *buf = (char *)wmem_alloc(wmem_epan_scope(), *size);
534     }
535
536     g_assert(*buf);
537     g_assert(*size > 0);
538
539     if (feof(fp))
540         return -1;
541
542     len = 0;
543     while ((c = ws_getc_unlocked(fp)) != EOF && c != '\r' && c != '\n') {
544         if (len+1 >= *size) {
545             *buf = (char *)wmem_realloc(wmem_epan_scope(), *buf, *size += BUFSIZ);
546         }
547         (*buf)[len++] = c;
548     }
549
550     if (len == 0 && c == EOF)
551         return -1;
552
553     (*buf)[len] = '\0';
554
555     return len;
556
557 } /* fgetline */
558
559
560 /*
561  *  Local function definitions
562  */
563 static subnet_entry_t subnet_lookup(const guint32 addr);
564 static void subnet_entry_set(guint32 subnet_addr, const guint8 mask_length, const gchar* name);
565
566
567 static void
568 add_service_name(port_type proto, const guint port, const char *service_name)
569 {
570     serv_port_t *serv_port_table;
571     int *key;
572
573     key = (int *)wmem_new(wmem_epan_scope(), int);
574     *key = port;
575
576     serv_port_table = (serv_port_t *)wmem_map_lookup(serv_port_hashtable, &port);
577     if (serv_port_table == NULL) {
578         serv_port_table = wmem_new0(wmem_epan_scope(), serv_port_t);
579         wmem_map_insert(serv_port_hashtable, key, serv_port_table);
580     }
581     else {
582         wmem_free(wmem_epan_scope(), key);
583     }
584
585     switch(proto) {
586         case PT_TCP:
587             wmem_free(wmem_epan_scope(), serv_port_table->tcp_name);
588             serv_port_table->tcp_name = wmem_strdup(wmem_epan_scope(), service_name);
589             break;
590         case PT_UDP:
591             wmem_free(wmem_epan_scope(), serv_port_table->udp_name);
592             serv_port_table->udp_name = wmem_strdup(wmem_epan_scope(), service_name);
593             break;
594         case PT_SCTP:
595             wmem_free(wmem_epan_scope(), serv_port_table->sctp_name);
596             serv_port_table->sctp_name = wmem_strdup(wmem_epan_scope(), service_name);
597             break;
598         case PT_DCCP:
599             wmem_free(wmem_epan_scope(), serv_port_table->dccp_name);
600             serv_port_table->dccp_name = wmem_strdup(wmem_epan_scope(), service_name);
601             break;
602         default:
603             return;
604             /* Should not happen */
605     }
606
607     new_resolved_objects = TRUE;
608 }
609
610
611 static void
612 parse_service_line (char *line)
613 {
614     gchar *cp;
615     gchar *service;
616     gchar *port;
617     port_type proto;
618     struct cb_serv_data cb_data;
619     range_t *port_rng = NULL;
620
621     if ((cp = strchr(line, '#')))
622         *cp = '\0';
623
624     if ((cp = strtok(line, " \t")) == NULL)
625         return;
626
627     service = cp;
628
629     if ((cp = strtok(NULL, " \t")) == NULL)
630         return;
631
632     port = cp;
633
634     if (strtok(cp, "/") == NULL)
635         return;
636
637     if (range_convert_str(NULL, &port_rng, port, G_MAXUINT16) != CVT_NO_ERROR) {
638         wmem_free (NULL, port_rng);
639         return;
640     }
641
642     while ((cp = strtok(NULL, "/")) != NULL) {
643         if (strcmp(cp, "tcp") == 0) {
644             proto = PT_TCP;
645         }
646         else if (strcmp(cp, "udp") == 0) {
647             proto = PT_UDP;
648         }
649         else if (strcmp(cp, "sctp") == 0) {
650             proto = PT_SCTP;
651         }
652         else if (strcmp(cp, "dccp") == 0) {
653             proto = PT_DCCP;
654         }
655         else {
656             break;
657         }
658         cb_data.service = service;
659         cb_data.proto = proto;
660         range_foreach(port_rng, add_serv_port_cb, &cb_data);
661     }
662
663     wmem_free (NULL, port_rng);
664 } /* parse_service_line */
665
666
667 static void
668 add_serv_port_cb(const guint32 port, gpointer ptr)
669 {
670     struct cb_serv_data *cb_data = (struct cb_serv_data *)ptr;
671
672     if ( port ) {
673         add_service_name(cb_data->proto, port, cb_data->service);
674     }
675 }
676
677
678 static gboolean
679 parse_services_file(const char * path)
680 {
681     FILE *serv_p;
682     static int     size = 0;
683     static char   *buf = NULL;
684
685     /* services hash table initialization */
686     serv_p = ws_fopen(path, "r");
687
688     if (serv_p == NULL)
689         return FALSE;
690
691     while (fgetline(&buf, &size, serv_p) >= 0) {
692         parse_service_line(buf);
693     }
694
695     fclose(serv_p);
696     return TRUE;
697 }
698
699 /* -----------------
700  * unsigned integer to ascii
701  */
702 static gchar *
703 wmem_utoa(wmem_allocator_t *allocator, guint port)
704 {
705     gchar *bp = (gchar *)wmem_alloc(allocator, MAXNAMELEN);
706
707     /* XXX, guint32_to_str() ? */
708     guint32_to_str_buf(port, bp, MAXNAMELEN);
709     return bp;
710 }
711
712 static const gchar *
713 _serv_name_lookup(port_type proto, guint port, serv_port_t **value_ret)
714 {
715     serv_port_t *serv_port_table;
716
717     serv_port_table = (serv_port_t *)wmem_map_lookup(serv_port_hashtable, &port);
718
719     if (value_ret != NULL)
720         *value_ret = serv_port_table;
721
722     if (serv_port_table == NULL)
723         return NULL;
724
725     switch (proto) {
726         case PT_UDP:
727             return serv_port_table->udp_name;
728         case PT_TCP:
729             return serv_port_table->tcp_name;
730         case PT_SCTP:
731             return serv_port_table->sctp_name;
732         case PT_DCCP:
733             return serv_port_table->dccp_name;
734         default:
735             break;
736     }
737     return NULL;
738 }
739
740 const gchar *
741 try_serv_name_lookup(port_type proto, guint port)
742 {
743     return _serv_name_lookup(proto, port, NULL);
744 }
745
746 const gchar *
747 serv_name_lookup(port_type proto, guint port)
748 {
749     serv_port_t *serv_port_table = NULL;
750     const char *name;
751     guint *key;
752
753     name = _serv_name_lookup(proto, port, &serv_port_table);
754     if (name != NULL)
755         return name;
756
757     if (serv_port_table == NULL) {
758         key = (guint *)wmem_new(wmem_epan_scope(), guint);
759         *key = port;
760         serv_port_table = wmem_new0(wmem_epan_scope(), serv_port_t);
761         wmem_map_insert(serv_port_hashtable, key, serv_port_table);
762     }
763     if (serv_port_table->numeric == NULL) {
764         serv_port_table->numeric = wmem_strdup_printf(wmem_epan_scope(), "%u", port);
765     }
766
767     return serv_port_table->numeric;
768 }
769
770 static void
771 initialize_services(void)
772 {
773     gboolean parse_file = TRUE;
774     g_assert(serv_port_hashtable == NULL);
775     serv_port_hashtable = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
776
777     /* Compute the pathname of the services file. */
778     if (g_services_path == NULL) {
779         g_services_path = get_datafile_path(ENAME_SERVICES);
780     }
781     parse_services_file(g_services_path);
782
783     /* Compute the pathname of the personal services file */
784     if (g_pservices_path == NULL) {
785         /* Check profile directory before personal configuration */
786         g_pservices_path = get_persconffile_path(ENAME_SERVICES, TRUE);
787         if (!parse_services_file(g_pservices_path)) {
788             g_free(g_pservices_path);
789             g_pservices_path = get_persconffile_path(ENAME_SERVICES, FALSE);
790         } else {
791             parse_file = FALSE;
792         }
793     }
794     if (parse_file) {
795         parse_services_file(g_pservices_path);
796     }
797 }
798
799 static void
800 service_name_lookup_cleanup(void)
801 {
802     serv_port_hashtable = NULL;
803     g_free(g_services_path);
804     g_services_path = NULL;
805     g_free(g_pservices_path);
806     g_pservices_path = NULL;
807 }
808
809 static void
810 parse_enterprises_line (char *line)
811 {
812     char *tok, *dec_str, *org_str;
813     guint32 dec;
814
815     if ((tok = strchr(line, '#')))
816         *tok = '\0';
817     dec_str = strtok(line, " \t");
818     if (!dec_str)
819         return;
820     org_str = strtok(NULL, ""); /* everything else */
821     if (org_str)
822         org_str = g_strstrip(org_str);
823     if (!org_str)
824         return;
825     if (!ws_strtou32(dec_str, NULL, &dec))
826         return;
827     g_hash_table_replace(enterprises_hashtable, GUINT_TO_POINTER(dec), g_strdup(org_str));
828 }
829
830
831 static gboolean
832 parse_enterprises_file(const char * path)
833 {
834     FILE *fp;
835     static int size = 0;
836     static char *buf = NULL;
837
838     fp = ws_fopen(path, "r");
839     if (fp == NULL)
840         return FALSE;
841
842     while (fgetline(&buf, &size, fp) >= 0) {
843         parse_enterprises_line(buf);
844     }
845
846     fclose(fp);
847     return TRUE;
848 }
849
850 static void
851 initialize_enterprises(void)
852 {
853     g_assert(enterprises_hashtable == NULL);
854     enterprises_hashtable = g_hash_table_new_full(NULL, NULL, NULL, g_free);
855
856     if (g_enterprises_path == NULL) {
857         g_enterprises_path = get_datafile_path(ENAME_ENTERPRISES);
858     }
859     parse_enterprises_file(g_enterprises_path);
860
861     if (g_penterprises_path == NULL) {
862         g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES, FALSE);
863     }
864     parse_enterprises_file(g_penterprises_path);
865 }
866
867 const gchar *
868 try_enterprises_lookup(guint32 value)
869 {
870     return (const gchar *)g_hash_table_lookup(enterprises_hashtable, GUINT_TO_POINTER(value));
871 }
872
873 const gchar *
874 enterprises_lookup(guint32 value, const char *unknown_str)
875 {
876     const gchar *s;
877
878     s = try_enterprises_lookup(value);
879     if (s != NULL)
880         return s;
881     if (unknown_str != NULL)
882         return unknown_str;
883     return "<Unknown>";
884 }
885
886 void
887 enterprises_base_custom(char *buf, guint32 value)
888 {
889     const gchar *s;
890
891     if ((s = try_enterprises_lookup(value)) == NULL)
892         s = ITEM_LABEL_UNKNOWN_STR;
893     g_snprintf(buf, ITEM_LABEL_LENGTH, "%s (%u)", s, value);
894 }
895
896 static void
897 enterprises_cleanup(void)
898 {
899     g_assert(enterprises_hashtable);
900     g_hash_table_destroy(enterprises_hashtable);
901     enterprises_hashtable = NULL;
902     g_assert(g_enterprises_path);
903     g_free(g_enterprises_path);
904     g_enterprises_path = NULL;
905     g_free(g_penterprises_path);
906     g_penterprises_path = NULL;
907     g_free(g_pservices_path);
908     g_pservices_path = NULL;
909 }
910
911 /* Fill in an IP4 structure with info from subnets file or just with the
912  * string form of the address.
913  */
914 static void
915 fill_dummy_ip4(const guint addr, hashipv4_t* volatile tp)
916 {
917     subnet_entry_t subnet_entry;
918
919     /* Overwrite if we get async DNS reply */
920
921     /* Do we have a subnet for this address? */
922     subnet_entry = subnet_lookup(addr);
923     if (0 != subnet_entry.mask) {
924         /* Print name, then '.' then IP address after subnet mask */
925         guint32 host_addr;
926         gchar buffer[WS_INET_ADDRSTRLEN];
927         gchar* paddr;
928         gsize i;
929
930         host_addr = addr & (~(guint32)subnet_entry.mask);
931         ip_to_str_buf((guint8 *)&host_addr, buffer, WS_INET_ADDRSTRLEN);
932         paddr = buffer;
933
934         /* Skip to first octet that is not totally masked
935          * If length of mask is 32, we chomp the whole address.
936          * If the address string starts '.' (should not happen?),
937          * we skip that '.'.
938          */
939         i = subnet_entry.mask_length / 8;
940         while(*(paddr) != '\0' && i > 0) {
941             if (*(++paddr) == '.') {
942                 --i;
943             }
944         }
945
946         /* There are more efficient ways to do this, but this is safe if we
947          * trust g_snprintf and MAXNAMELEN
948          */
949         g_snprintf(tp->name, MAXNAMELEN, "%s%s", subnet_entry.name, paddr);
950     } else {
951         /* XXX: This means we end up printing "1.2.3.4 (1.2.3.4)" in many cases */
952         ip_to_str_buf((const guint8 *)&addr, tp->name, MAXNAMELEN);
953     }
954 }
955
956
957 /* Fill in an IP6 structure with the string form of the address.
958  */
959 static void
960 fill_dummy_ip6(hashipv6_t* volatile tp)
961 {
962     /* Overwrite if we get async DNS reply */
963     g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
964 }
965
966 #ifdef HAVE_C_ARES
967
968 static void
969 c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
970     async_dns_queue_msg_t *caqm = (async_dns_queue_msg_t *)arg;
971     char **p;
972
973     if (!caqm) return;
974     /* XXX, what to do if async_dns_in_flight == 0? */
975     async_dns_in_flight--;
976
977     if (status == ARES_SUCCESS) {
978         for (p = he->h_addr_list; *p != NULL; p++) {
979             switch(caqm->family) {
980                 case AF_INET:
981                     add_ipv4_name(caqm->addr.ip4, he->h_name);
982                     break;
983                 case AF_INET6:
984                     add_ipv6_name(&caqm->addr.ip6, he->h_name);
985                     break;
986                 default:
987                     /* Throw an exception? */
988                     break;
989             }
990         }
991     }
992     wmem_free(wmem_epan_scope(), caqm);
993 }
994 #endif /* HAVE_C_ARES */
995
996 /* --------------- */
997 static hashipv4_t *
998 new_ipv4(const guint addr)
999 {
1000     hashipv4_t *tp = wmem_new(wmem_epan_scope(), hashipv4_t);
1001     tp->addr = addr;
1002     tp->flags = 0;
1003     tp->name[0] = '\0';
1004     ip_to_str_buf((const guint8 *)&addr, tp->ip, sizeof(tp->ip));
1005     return tp;
1006 }
1007
1008 static hashipv4_t *
1009 host_lookup(const guint addr)
1010 {
1011     hashipv4_t * volatile tp;
1012
1013     tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
1014     if (tp == NULL) {
1015         /*
1016          * We don't already have an entry for this host name; create one,
1017          * and then try to resolve it.
1018          */
1019         tp = new_ipv4(addr);
1020         fill_dummy_ip4(addr, tp);
1021         wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
1022     } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
1023         return tp;
1024     }
1025
1026     /*
1027      * This hasn't been resolved yet, and we haven't tried to
1028      * resolve it already.
1029      */
1030
1031     if (!gbl_resolv_flags.network_name)
1032         return tp;
1033
1034     if (gbl_resolv_flags.use_external_net_name_resolver) {
1035         tp->flags |= TRIED_RESOLVE_ADDRESS;
1036
1037 #ifdef HAVE_C_ARES
1038         if (async_dns_initialized) {
1039             /* c-ares is initialized, so we can use it */
1040             if (resolve_synchronously || name_resolve_concurrency == 0) {
1041                 /*
1042                  * Either all names are to be resolved synchronously or
1043                  * the concurrencly level is 0; do the resolution
1044                  * synchronously.
1045                  */
1046                 sync_lookup_ip4(addr);
1047             } else {
1048                 /*
1049                  * Names are to be resolved asynchronously, and we
1050                  * allow at least one asynchronous request in flight;
1051                  * post an asynchronous request.
1052                  */
1053                 async_dns_queue_msg_t *caqm;
1054
1055                 caqm = wmem_new(wmem_epan_scope(), async_dns_queue_msg_t);
1056                 caqm->family = AF_INET;
1057                 caqm->addr.ip4 = addr;
1058                 wmem_list_append(async_dns_queue_head, (gpointer) caqm);
1059             }
1060         }
1061 #endif
1062     }
1063
1064     return tp;
1065
1066 } /* host_lookup */
1067
1068 /* --------------- */
1069 static hashipv6_t *
1070 new_ipv6(const ws_in6_addr *addr)
1071 {
1072     hashipv6_t *tp = wmem_new(wmem_epan_scope(), hashipv6_t);
1073     memcpy(tp->addr, addr->bytes, sizeof tp->addr);
1074     tp->flags = 0;
1075     tp->name[0] = '\0';
1076     ip6_to_str_buf(addr, tp->ip6, sizeof(tp->ip6));
1077     return tp;
1078 }
1079
1080 /* ------------------------------------ */
1081 static hashipv6_t *
1082 host_lookup6(const ws_in6_addr *addr)
1083 {
1084     hashipv6_t * volatile tp;
1085
1086     tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addr);
1087     if (tp == NULL) {
1088         /*
1089          * We don't already have an entry for this host name; create one,
1090          * and then try to resolve it.
1091          */
1092         ws_in6_addr *addr_key;
1093
1094         addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr);
1095         tp = new_ipv6(addr);
1096         memcpy(addr_key, addr, 16);
1097         fill_dummy_ip6(tp);
1098         wmem_map_insert(ipv6_hash_table, addr_key, tp);
1099     } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
1100         return tp;
1101     }
1102
1103     /*
1104      * This hasn't been resolved yet, and we haven't tried to
1105      * resolve it already.
1106      */
1107
1108     if (!gbl_resolv_flags.network_name)
1109         return tp;
1110
1111     if (gbl_resolv_flags.use_external_net_name_resolver) {
1112         tp->flags |= TRIED_RESOLVE_ADDRESS;
1113
1114 #ifdef HAVE_C_ARES
1115         if (async_dns_initialized) {
1116             /* c-ares is initialized, so we can use it */
1117             if (resolve_synchronously || name_resolve_concurrency == 0) {
1118                 /*
1119                  * Either all names are to be resolved synchronously or
1120                  * the concurrencly level is 0; do the resolution
1121                  * synchronously.
1122                  */
1123                 sync_lookup_ip6(addr);
1124             } else {
1125                 /*
1126                  * Names are to be resolved asynchronously, and we
1127                  * allow at least one asynchronous request in flight;
1128                  * post an asynchronous request.
1129                  */
1130                 async_dns_queue_msg_t *caqm;
1131
1132                 caqm = wmem_new(wmem_epan_scope(), async_dns_queue_msg_t);
1133                 caqm->family = AF_INET6;
1134                 memcpy(&caqm->addr.ip6, addr, sizeof(caqm->addr.ip6));
1135                 wmem_list_append(async_dns_queue_head, (gpointer) caqm);
1136             }
1137         }
1138 #endif
1139     }
1140
1141     return tp;
1142
1143 } /* host_lookup6 */
1144
1145 /*
1146  * Ethernet / manufacturer resolution
1147  *
1148  * The following functions implement ethernet address resolution and
1149  * ethers files parsing (see ethers(4)).
1150  *
1151  * The manuf file has the same format as ethers(4) except that names are
1152  * truncated to MAXMANUFLEN-1 (8) characters and that an address contains
1153  * only 3 bytes (instead of 6).
1154  *
1155  * Notes:
1156  *
1157  * I decide to not use the existing functions (see ethers(3) on some
1158  * operating systems) for the following reasons:
1159  * - performance gains (use of hash tables and some other enhancements),
1160  * - use of two ethers files (system-wide and per user),
1161  * - avoid the use of NIS maps,
1162  * - lack of these functions on some systems.
1163  *
1164  * So the following functions do _not_ behave as the standard ones.
1165  *
1166  * -- Laurent.
1167  */
1168
1169
1170 /*
1171  * If "accept_mask" is FALSE,  either 3 or 6 bytes are valid, but no other number of bytes is.
1172  * If "accept_mask" is TRUE, parse an up-to-6-byte sequence with an optional
1173  * mask.
1174  */
1175 static gboolean
1176 parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
1177         const gboolean accept_mask)
1178 {
1179     int i;
1180     unsigned long num;
1181     char *p;
1182     char sep = '\0';
1183
1184     for (i = 0; i < 6; i++) {
1185         /* Get a hex number, 1 or 2 digits, no sign characters allowed. */
1186         if (!g_ascii_isxdigit(*cp))
1187             return FALSE;
1188         num = strtoul(cp, &p, 16);
1189         if (p == cp)
1190             return FALSE; /* failed */
1191         if (num > 0xFF)
1192             return FALSE; /* not a valid octet */
1193         eth->addr[i] = (guint8) num;
1194         cp = p;     /* skip past the number */
1195
1196         /* OK, what character terminated the octet? */
1197         if (*cp == '/') {
1198             /* "/" - this has a mask. */
1199             if (!accept_mask) {
1200                 /* Entries with masks are not allowed in this file. */
1201                 return FALSE;
1202             }
1203             cp++; /* skip past the '/' to get to the mask */
1204             if (!g_ascii_isdigit(*cp))
1205                 return FALSE;   /* no sign allowed */
1206             num = strtoul(cp, &p, 10);
1207             if (p == cp)
1208                 return FALSE;   /* failed */
1209             cp = p;   /* skip past the number */
1210             if (*cp != '\0' && !g_ascii_isspace(*cp))
1211                 return FALSE;   /* bogus terminator */
1212             if (num == 0 || num >= 48)
1213                 return FALSE;   /* bogus mask */
1214             /* Mask out the bits not covered by the mask */
1215             *mask = (int)num;
1216             for (i = 0; num >= 8; i++, num -= 8)
1217                 ;   /* skip octets entirely covered by the mask */
1218             /* Mask out the first masked octet */
1219             eth->addr[i] &= (0xFF << (8 - num));
1220             i++;
1221             /* Mask out completely-masked-out octets */
1222             for (; i < 6; i++)
1223                 eth->addr[i] = 0;
1224             return TRUE;
1225         }
1226         if (*cp == '\0') {
1227             /* We're at the end of the address, and there's no mask. */
1228             if (i == 2) {
1229                 /* We got 3 bytes, so this is a manufacturer ID. */
1230                 if (!accept_mask) {
1231                     /* Manufacturer IDs are not allowed in this file */
1232                     return FALSE;
1233                 }
1234                 /* Indicate that this is a manufacturer ID (0 is not allowed
1235                    as a mask). */
1236                 *mask = 0;
1237                 return TRUE;
1238             }
1239
1240             if (i == 5) {
1241                 /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1242                 if (accept_mask)
1243                     *mask = 48;
1244                 return TRUE;
1245             }
1246
1247             /* We didn't get 3 or 6 bytes, and there's no mask; this is
1248                illegal. */
1249             return FALSE;
1250         } else {
1251             if (sep == '\0') {
1252                 /* We don't know the separator used in this number; it can either
1253                    be ':', '-', or '.'. */
1254                 if (*cp != ':' && *cp != '-' && *cp != '.')
1255                     return FALSE;
1256                 sep = *cp;  /* subsequent separators must be the same */
1257             } else {
1258                 /* It has to be the same as the first separator */
1259                 if (*cp != sep)
1260                     return FALSE;
1261             }
1262         }
1263         cp++;
1264     }
1265
1266     return TRUE;
1267 }
1268
1269 static int
1270 parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
1271         const gboolean accept_mask)
1272 {
1273     /*
1274      *  See the ethers(4) or ethers(5) man page for ethers file format
1275      *  (not available on all systems).
1276      *  We allow both ethernet address separators (':' and '-'),
1277      *  as well as Wireshark's '.' separator.
1278      */
1279
1280     gchar *cp;
1281
1282     line = g_strstrip(line);
1283     if (line[0] == '\0' || line[0] == '#')
1284         return -1;
1285
1286     if ((cp = strchr(line, '#'))) {
1287         *cp = '\0';
1288         g_strchomp(line);
1289     }
1290
1291     if ((cp = strtok(line, " \t")) == NULL)
1292         return -1;
1293
1294     if (!parse_ether_address(cp, eth, mask, accept_mask))
1295         return -1;
1296
1297     if ((cp = strtok(NULL, " \t")) == NULL)
1298         return -1;
1299
1300     g_strlcpy(eth->name, cp, MAXNAMELEN);
1301
1302     if ((cp = strtok(NULL, "\t")) != NULL)
1303     {
1304         g_strlcpy(eth->longname, cp, MAXNAMELEN);
1305     } else {
1306         /* Make the long name the short name */
1307         g_strlcpy(eth->longname, eth->name, MAXNAMELEN);
1308     }
1309
1310     return 0;
1311
1312 } /* parse_ether_line */
1313
1314 static FILE *eth_p = NULL;
1315
1316 static void
1317 set_ethent(char *path)
1318 {
1319     if (eth_p)
1320         rewind(eth_p);
1321     else
1322         eth_p = ws_fopen(path, "r");
1323 }
1324
1325 static void
1326 end_ethent(void)
1327 {
1328     if (eth_p) {
1329         fclose(eth_p);
1330         eth_p = NULL;
1331     }
1332 }
1333
1334 static ether_t *
1335 get_ethent(unsigned int *mask, const gboolean accept_mask)
1336 {
1337
1338     static ether_t eth;
1339     static int     size = 0;
1340     static char   *buf = NULL;
1341
1342     if (eth_p == NULL)
1343         return NULL;
1344
1345     while (fgetline(&buf, &size, eth_p) >= 0) {
1346         if (parse_ether_line(buf, &eth, mask, accept_mask) == 0) {
1347             return &eth;
1348         }
1349     }
1350
1351     return NULL;
1352
1353 } /* get_ethent */
1354
1355 static ether_t *
1356 get_ethbyaddr(const guint8 *addr)
1357 {
1358
1359     ether_t *eth;
1360
1361     set_ethent(g_pethers_path);
1362
1363     while (((eth = get_ethent(NULL, FALSE)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
1364         ;
1365
1366     if (eth == NULL) {
1367         end_ethent();
1368
1369         set_ethent(g_ethers_path);
1370
1371         while (((eth = get_ethent(NULL, FALSE)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
1372             ;
1373
1374         end_ethent();
1375     }
1376
1377     return eth;
1378
1379 } /* get_ethbyaddr */
1380
1381 static hashmanuf_t *
1382 manuf_hash_new_entry(const guint8 *addr, char* name, char* longname)
1383 {
1384     int    *manuf_key;
1385     hashmanuf_t *manuf_value;
1386     char *endp;
1387
1388     /* manuf needs only the 3 most significant octets of the ethernet address */
1389     manuf_key = (int *)wmem_new(wmem_epan_scope(), int);
1390     *manuf_key = (int)((addr[0] << 16) + (addr[1] << 8) + addr[2]);
1391     manuf_value = wmem_new(wmem_epan_scope(), hashmanuf_t);
1392
1393     memcpy(manuf_value->addr, addr, 3);
1394     if (name != NULL) {
1395         g_strlcpy(manuf_value->resolved_name, name, MAXNAMELEN);
1396         manuf_value->status = HASHETHER_STATUS_RESOLVED_NAME;
1397         if (longname != NULL) {
1398             g_strlcpy(manuf_value->resolved_longname, longname, MAXNAMELEN);
1399         }
1400         else {
1401             g_strlcpy(manuf_value->resolved_longname, name, MAXNAMELEN);
1402         }
1403     }
1404     else {
1405         manuf_value->status = HASHETHER_STATUS_UNRESOLVED;
1406         manuf_value->resolved_name[0] = '\0';
1407         manuf_value->resolved_longname[0] = '\0';
1408     }
1409     /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
1410     endp = bytes_to_hexstr_punct(manuf_value->hexaddr, addr, sizeof(manuf_value->addr), ':');
1411     *endp = '\0';
1412
1413     wmem_map_insert(manuf_hashtable, manuf_key, manuf_value);
1414     return manuf_value;
1415 }
1416
1417 static void
1418 wka_hash_new_entry(const guint8 *addr, char* name)
1419 {
1420     guint8 *wka_key;
1421
1422     wka_key = (guint8 *)wmem_alloc(wmem_epan_scope(), 6);
1423     memcpy(wka_key, addr, 6);
1424
1425     wmem_map_insert(wka_hashtable, wka_key, wmem_strdup(wmem_epan_scope(), name));
1426 }
1427
1428 static void
1429 add_manuf_name(const guint8 *addr, unsigned int mask, gchar *name, gchar *longname)
1430 {
1431     switch (mask)
1432     {
1433     case 0:
1434         /* This is a manufacturer ID; add it to the manufacturer ID hash table */
1435         manuf_hash_new_entry(addr, name, longname);
1436         break;
1437
1438     case 48:
1439         /* This is a well-known MAC address; add it to the Ethernet hash table */
1440         add_eth_name(addr, name);
1441         break;
1442
1443     default:
1444         /* This is a range of well-known addresses; add it to the well-known-address table */
1445         wka_hash_new_entry(addr, name);
1446         break;
1447     }
1448 } /* add_manuf_name */
1449
1450 static hashmanuf_t *
1451 manuf_name_lookup(const guint8 *addr)
1452 {
1453     gint32       manuf_key = 0;
1454     guint8       oct;
1455     hashmanuf_t  *manuf_value;
1456
1457     /* manuf needs only the 3 most significant octets of the ethernet address */
1458     manuf_key = addr[0];
1459     manuf_key = manuf_key<<8;
1460     oct = addr[1];
1461     manuf_key = manuf_key | oct;
1462     manuf_key = manuf_key<<8;
1463     oct = addr[2];
1464     manuf_key = manuf_key | oct;
1465
1466
1467     /* first try to find a "perfect match" */
1468     manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, &manuf_key);
1469     if (manuf_value != NULL) {
1470         return manuf_value;
1471     }
1472
1473     /* Mask out the broadcast/multicast flag but not the locally
1474      * administered flag as locally administered means: not assigned
1475      * by the IEEE but the local administrator instead.
1476      * 0x01 multicast / broadcast bit
1477      * 0x02 locally administered bit */
1478     if ((manuf_key & 0x00010000) != 0) {
1479         manuf_key &= 0x00FEFFFF;
1480         manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, &manuf_key);
1481         if (manuf_value != NULL) {
1482             return manuf_value;
1483         }
1484     }
1485
1486     /* Add the address as a hex string */
1487     return manuf_hash_new_entry(addr, NULL, NULL);
1488
1489 } /* manuf_name_lookup */
1490
1491 static gchar *
1492 wka_name_lookup(const guint8 *addr, const unsigned int mask)
1493 {
1494     guint8     masked_addr[6];
1495     guint      num;
1496     gint       i;
1497     gchar     *name;
1498
1499     if (wka_hashtable == NULL) {
1500         return NULL;
1501     }
1502     /* Get the part of the address covered by the mask. */
1503     for (i = 0, num = mask; num >= 8; i++, num -= 8)
1504         masked_addr[i] = addr[i];   /* copy octets entirely covered by the mask */
1505     /* Mask out the first masked octet */
1506     masked_addr[i] = addr[i] & (0xFF << (8 - num));
1507     i++;
1508     /* Zero out completely-masked-out octets */
1509     for (; i < 6; i++)
1510         masked_addr[i] = 0;
1511
1512     name = (gchar *)wmem_map_lookup(wka_hashtable, masked_addr);
1513
1514     return name;
1515
1516 } /* wka_name_lookup */
1517
1518
1519 guint get_hash_ether_status(hashether_t* ether)
1520 {
1521     return ether->status;
1522 }
1523
1524 char* get_hash_ether_hexaddr(hashether_t* ether)
1525 {
1526     return ether->hexaddr;
1527 }
1528
1529 char* get_hash_ether_resolved_name(hashether_t* ether)
1530 {
1531     return ether->resolved_name;
1532 }
1533
1534 static guint
1535 eth_addr_hash(gconstpointer key)
1536 {
1537     return wmem_strong_hash((const guint8 *)key, 6);
1538 }
1539
1540 static gboolean
1541 eth_addr_cmp(gconstpointer a, gconstpointer b)
1542 {
1543     return (memcmp(a, b, 6) == 0);
1544 }
1545
1546 static void
1547 initialize_ethers(void)
1548 {
1549     ether_t *eth;
1550     guint    mask = 0;
1551
1552     /* hash table initialization */
1553     wka_hashtable   = wmem_map_new(wmem_epan_scope(), eth_addr_hash, eth_addr_cmp);
1554     manuf_hashtable = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
1555     eth_hashtable   = wmem_map_new(wmem_epan_scope(), eth_addr_hash, eth_addr_cmp);
1556
1557     /* Compute the pathname of the ethers file. */
1558     if (g_ethers_path == NULL) {
1559         g_ethers_path = g_build_filename(get_systemfile_dir(), ENAME_ETHERS, NULL);
1560     }
1561
1562     /* Set g_pethers_path here, but don't actually do anything
1563      * with it. It's used in get_ethbyaddr().
1564      */
1565     if (g_pethers_path == NULL)
1566         g_pethers_path = get_persconffile_path(ENAME_ETHERS, FALSE);
1567
1568     /* Compute the pathname of the manuf file */
1569     if (g_manuf_path == NULL)
1570         g_manuf_path = get_datafile_path(ENAME_MANUF);
1571
1572     /* Read it and initialize the hash table */
1573     set_ethent(g_manuf_path);
1574     while ((eth = get_ethent(&mask, TRUE))) {
1575         add_manuf_name(eth->addr, mask, eth->name, eth->longname);
1576     }
1577     end_ethent();
1578
1579     /* Compute the pathname of the wka file */
1580     if (g_wka_path == NULL)
1581         g_wka_path = get_datafile_path(ENAME_WKA);
1582
1583     /* Read it and initialize the hash table */
1584     set_ethent(g_wka_path);
1585     while ((eth = get_ethent(&mask, TRUE))) {
1586         add_manuf_name(eth->addr, mask, eth->name, eth->longname);
1587     }
1588     end_ethent();
1589
1590 } /* initialize_ethers */
1591
1592 static void
1593 ethers_cleanup(void)
1594 {
1595     g_free(g_ethers_path);
1596     g_ethers_path = NULL;
1597     g_free(g_pethers_path);
1598     g_pethers_path = NULL;
1599     g_free(g_manuf_path);
1600     g_manuf_path = NULL;
1601     g_free(g_wka_path);
1602     g_wka_path = NULL;
1603 }
1604
1605 /* Resolve ethernet address */
1606 static hashether_t *
1607 eth_addr_resolve(hashether_t *tp) {
1608     ether_t      *eth;
1609     hashmanuf_t *manuf_value;
1610     const guint8 *addr = tp->addr;
1611
1612     if ( (eth = get_ethbyaddr(addr)) != NULL) {
1613         g_strlcpy(tp->resolved_name, eth->name, MAXNAMELEN);
1614         tp->status = HASHETHER_STATUS_RESOLVED_NAME;
1615         return tp;
1616     } else {
1617         guint         mask;
1618         gchar        *name;
1619         address       ether_addr;
1620
1621         /* Unknown name.  Try looking for it in the well-known-address
1622            tables for well-known address ranges smaller than 2^24. */
1623         mask = 7;
1624         do {
1625             /* Only the topmost 5 bytes participate fully */
1626             if ((name = wka_name_lookup(addr, mask+40)) != NULL) {
1627                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x",
1628                         name, addr[5] & (0xFF >> mask));
1629                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1630                 return tp;
1631             }
1632         } while (mask--);
1633
1634         mask = 7;
1635         do {
1636             /* Only the topmost 4 bytes participate fully */
1637             if ((name = wka_name_lookup(addr, mask+32)) != NULL) {
1638                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x",
1639                         name, addr[4] & (0xFF >> mask), addr[5]);
1640                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1641                 return tp;
1642             }
1643         } while (mask--);
1644
1645         mask = 7;
1646         do {
1647             /* Only the topmost 3 bytes participate fully */
1648             if ((name = wka_name_lookup(addr, mask+24)) != NULL) {
1649                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
1650                         name, addr[3] & (0xFF >> mask), addr[4], addr[5]);
1651                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1652                 return tp;
1653             }
1654         } while (mask--);
1655
1656         /* Now try looking in the manufacturer table. */
1657         manuf_value = manuf_name_lookup(addr);
1658         if ((manuf_value != NULL) && (manuf_value->status != HASHETHER_STATUS_UNRESOLVED)) {
1659             g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
1660                     manuf_value->resolved_name, addr[3], addr[4], addr[5]);
1661             tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1662             return tp;
1663         }
1664
1665         /* Now try looking for it in the well-known-address
1666            tables for well-known address ranges larger than 2^24. */
1667         mask = 7;
1668         do {
1669             /* Only the topmost 2 bytes participate fully */
1670             if ((name = wka_name_lookup(addr, mask+16)) != NULL) {
1671                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x",
1672                         name, addr[2] & (0xFF >> mask), addr[3], addr[4],
1673                         addr[5]);
1674                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1675                 return tp;
1676             }
1677         } while (mask--);
1678
1679         mask = 7;
1680         do {
1681             /* Only the topmost byte participates fully */
1682             if ((name = wka_name_lookup(addr, mask+8)) != NULL) {
1683                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
1684                         name, addr[1] & (0xFF >> mask), addr[2], addr[3],
1685                         addr[4], addr[5]);
1686                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1687                 return tp;
1688             }
1689         } while (mask--);
1690
1691         mask = 7;
1692         do {
1693             /* Not even the topmost byte participates fully */
1694             if ((name = wka_name_lookup(addr, mask)) != NULL) {
1695                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
1696                         name, addr[0] & (0xFF >> mask), addr[1], addr[2],
1697                         addr[3], addr[4], addr[5]);
1698                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1699                 return tp;
1700             }
1701         } while (--mask); /* Work down to the last bit */
1702
1703         /* No match whatsoever. */
1704         set_address(&ether_addr, AT_ETHER, 6, addr);
1705         address_to_str_buf(&ether_addr, tp->resolved_name, MAXNAMELEN);
1706         tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
1707         return tp;
1708     }
1709     g_assert_not_reached();
1710 } /* eth_addr_resolve */
1711
1712 static hashether_t *
1713 eth_hash_new_entry(const guint8 *addr, const gboolean resolve)
1714 {
1715     hashether_t *tp;
1716     char *endp;
1717
1718     tp = wmem_new(wmem_epan_scope(), hashether_t);
1719     memcpy(tp->addr, addr, sizeof(tp->addr));
1720     tp->status = HASHETHER_STATUS_UNRESOLVED;
1721     /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
1722     endp = bytes_to_hexstr_punct(tp->hexaddr, addr, sizeof(tp->addr), ':');
1723     *endp = '\0';
1724     tp->resolved_name[0] = '\0';
1725
1726     if (resolve)
1727         eth_addr_resolve(tp);
1728
1729     wmem_map_insert(eth_hashtable, tp->addr, tp);
1730
1731     return tp;
1732 } /* eth_hash_new_entry */
1733
1734 static hashether_t *
1735 add_eth_name(const guint8 *addr, const gchar *name)
1736 {
1737     hashether_t *tp;
1738
1739     tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
1740
1741     if (tp == NULL) {
1742         tp = eth_hash_new_entry(addr, FALSE);
1743     }
1744
1745     if (strcmp(tp->resolved_name, name) != 0) {
1746         g_strlcpy(tp->resolved_name, name, MAXNAMELEN);
1747         tp->status = HASHETHER_STATUS_RESOLVED_NAME;
1748         new_resolved_objects = TRUE;
1749     }
1750
1751     return tp;
1752 } /* add_eth_name */
1753
1754 static hashether_t *
1755 eth_name_lookup(const guint8 *addr, const gboolean resolve)
1756 {
1757     hashether_t  *tp;
1758
1759     tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
1760
1761     if (tp == NULL) {
1762         tp = eth_hash_new_entry(addr, resolve);
1763     } else {
1764         if (resolve && (tp->status == HASHETHER_STATUS_UNRESOLVED)) {
1765             eth_addr_resolve(tp); /* Found but needs to be resolved */
1766         }
1767     }
1768
1769     return tp;
1770
1771 } /* eth_name_lookup */
1772
1773
1774 /* IPXNETS */
1775 static int
1776 parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
1777 {
1778     /*
1779      *  We allow three address separators (':', '-', and '.'),
1780      *  as well as no separators
1781      */
1782
1783     gchar     *cp;
1784     guint32   a, a0, a1, a2, a3;
1785     gboolean  found_single_number = FALSE;
1786
1787     if ((cp = strchr(line, '#')))
1788         *cp = '\0';
1789
1790     if ((cp = strtok(line, " \t\n")) == NULL)
1791         return -1;
1792
1793     /* Either fill a0,a1,a2,a3 and found_single_number is FALSE,
1794      * fill a and found_single_number is TRUE,
1795      * or return -1
1796      */
1797     if (sscanf(cp, "%x:%x:%x:%x", &a0, &a1, &a2, &a3) != 4) {
1798         if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
1799             if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
1800                 if (sscanf(cp, "%x", &a) == 1) {
1801                     found_single_number = TRUE;
1802                 }
1803                 else {
1804                     return -1;
1805                 }
1806             }
1807         }
1808     }
1809
1810     if ((cp = strtok(NULL, " \t\n")) == NULL)
1811         return -1;
1812
1813     if (found_single_number) {
1814         ipxnet->addr = a;
1815     }
1816     else {
1817         ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
1818     }
1819
1820     g_strlcpy(ipxnet->name, cp, MAXNAMELEN);
1821
1822     return 0;
1823
1824 } /* parse_ipxnets_line */
1825
1826 static FILE *ipxnet_p = NULL;
1827
1828 static void
1829 set_ipxnetent(char *path)
1830 {
1831     if (ipxnet_p)
1832         rewind(ipxnet_p);
1833     else
1834         ipxnet_p = ws_fopen(path, "r");
1835 }
1836
1837 static void
1838 end_ipxnetent(void)
1839 {
1840     if (ipxnet_p) {
1841         fclose(ipxnet_p);
1842         ipxnet_p = NULL;
1843     }
1844 }
1845
1846 static ipxnet_t *
1847 get_ipxnetent(void)
1848 {
1849
1850     static ipxnet_t ipxnet;
1851     static int     size = 0;
1852     static char   *buf = NULL;
1853
1854     if (ipxnet_p == NULL)
1855         return NULL;
1856
1857     while (fgetline(&buf, &size, ipxnet_p) >= 0) {
1858         if (parse_ipxnets_line(buf, &ipxnet) == 0) {
1859             return &ipxnet;
1860         }
1861     }
1862
1863     return NULL;
1864
1865 } /* get_ipxnetent */
1866
1867 static ipxnet_t *
1868 get_ipxnetbyaddr(guint32 addr)
1869 {
1870     ipxnet_t *ipxnet;
1871
1872     set_ipxnetent(g_ipxnets_path);
1873
1874     while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) ) ;
1875
1876     if (ipxnet == NULL) {
1877         end_ipxnetent();
1878
1879         set_ipxnetent(g_pipxnets_path);
1880
1881         while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) )
1882             ;
1883
1884         end_ipxnetent();
1885     }
1886
1887     return ipxnet;
1888
1889 } /* get_ipxnetbyaddr */
1890
1891 static void
1892 initialize_ipxnets(void)
1893 {
1894     /* Compute the pathname of the ipxnets file.
1895      *
1896      * XXX - is there a notion of an "ipxnets file" in any flavor of
1897      * UNIX, or with any add-on Netware package for UNIX?  If not,
1898      * should the UNIX version of the ipxnets file be in the datafile
1899      * directory as well?
1900      */
1901     if (g_ipxnets_path == NULL) {
1902         g_ipxnets_path = wmem_strdup_printf(wmem_epan_scope(), "%s" G_DIR_SEPARATOR_S "%s",
1903                 get_systemfile_dir(), ENAME_IPXNETS);
1904     }
1905
1906     /* Set g_pipxnets_path here, but don't actually do anything
1907      * with it. It's used in get_ipxnetbyaddr().
1908      */
1909     if (g_pipxnets_path == NULL)
1910         g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, FALSE);
1911
1912 } /* initialize_ipxnets */
1913
1914 static void
1915 ipx_name_lookup_cleanup(void)
1916 {
1917     ipxnet_hash_table = NULL;
1918     g_free(g_pipxnets_path);
1919     g_pipxnets_path = NULL;
1920 }
1921
1922 static gchar *
1923 ipxnet_name_lookup(wmem_allocator_t *allocator, const guint addr)
1924 {
1925     hashipxnet_t *tp;
1926     ipxnet_t *ipxnet;
1927
1928     tp = (hashipxnet_t *)wmem_map_lookup(ipxnet_hash_table, &addr);
1929     if (tp == NULL) {
1930         int *key;
1931
1932         key = (int *)wmem_new(wmem_epan_scope(), int);
1933         *key = addr;
1934         tp = wmem_new(wmem_epan_scope(), hashipxnet_t);
1935         wmem_map_insert(ipxnet_hash_table, key, tp);
1936     } else {
1937         return wmem_strdup(allocator, tp->name);
1938     }
1939
1940     /* fill in a new entry */
1941
1942     tp->addr = addr;
1943
1944     if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL) {
1945         /* unknown name */
1946         g_snprintf(tp->name, MAXNAMELEN, "%X", addr);
1947
1948     } else {
1949         g_strlcpy(tp->name, ipxnet->name, MAXNAMELEN);
1950     }
1951
1952     return wmem_strdup(allocator, tp->name);
1953
1954 } /* ipxnet_name_lookup */
1955
1956 /* VLANS */
1957 static int
1958 parse_vlan_line(char *line, vlan_t *vlan)
1959 {
1960     gchar     *cp;
1961     guint16   id;
1962
1963     if ((cp = strchr(line, '#')))
1964         *cp = '\0';
1965
1966     if ((cp = strtok(line, " \t\n")) == NULL)
1967         return -1;
1968
1969     if (sscanf(cp, "%" G_GUINT16_FORMAT, &id) == 1) {
1970         vlan->id = id;
1971     }
1972     else {
1973         return -1;
1974     }
1975
1976     if ((cp = strtok(NULL, "\t\n")) == NULL)
1977         return -1;
1978
1979     g_strlcpy(vlan->name, cp, MAXVLANNAMELEN);
1980
1981     return 0;
1982
1983 } /* parse_vlan_line */
1984
1985 static FILE *vlan_p = NULL;
1986
1987 static void
1988 set_vlanent(char *path)
1989 {
1990     if (vlan_p)
1991         rewind(vlan_p);
1992     else
1993         vlan_p = ws_fopen(path, "r");
1994 }
1995
1996 static void
1997 end_vlanent(void)
1998 {
1999     if (vlan_p) {
2000         fclose(vlan_p);
2001         vlan_p = NULL;
2002     }
2003 }
2004
2005 static vlan_t *
2006 get_vlanent(void)
2007 {
2008
2009     static vlan_t vlan;
2010     static int     size = 0;
2011     static char   *buf = NULL;
2012
2013     if (vlan_p == NULL)
2014         return NULL;
2015
2016     while (fgetline(&buf, &size, vlan_p) >= 0) {
2017         if (parse_vlan_line(buf, &vlan) == 0) {
2018             return &vlan;
2019         }
2020     }
2021
2022     return NULL;
2023
2024 } /* get_vlanent */
2025
2026 static vlan_t *
2027 get_vlannamebyid(guint16 id)
2028 {
2029     vlan_t *vlan;
2030
2031     set_vlanent(g_pvlan_path);
2032
2033     while (((vlan = get_vlanent()) != NULL) && (id != vlan->id) ) ;
2034
2035     if (vlan == NULL) {
2036         end_vlanent();
2037
2038     }
2039
2040     return vlan;
2041
2042 } /* get_vlannamebyid */
2043
2044 static void
2045 initialize_vlans(void)
2046 {
2047     g_assert(vlan_hash_table == NULL);
2048     vlan_hash_table = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
2049
2050     /* Set g_pvlan_path here, but don't actually do anything
2051      * with it. It's used in get_vlannamebyid()
2052      */
2053     if (g_pvlan_path == NULL)
2054         g_pvlan_path = get_persconffile_path(ENAME_VLANS, FALSE);
2055
2056 } /* initialize_vlans */
2057
2058 static void
2059 vlan_name_lookup_cleanup(void)
2060 {
2061     vlan_hash_table = NULL;
2062     g_free(g_pvlan_path);
2063     g_pvlan_path = NULL;
2064 }
2065
2066 static const gchar *
2067 vlan_name_lookup(const guint id)
2068 {
2069     hashvlan_t *tp;
2070     vlan_t *vlan;
2071
2072     tp = (hashvlan_t *)wmem_map_lookup(vlan_hash_table, &id);
2073     if (tp == NULL) {
2074         int *key;
2075
2076         key = (int *)wmem_new(wmem_epan_scope(), int);
2077         *key = id;
2078         tp = wmem_new(wmem_epan_scope(), hashvlan_t);
2079         wmem_map_insert(vlan_hash_table, key, tp);
2080     } else {
2081         return tp->name;
2082     }
2083
2084     /* fill in a new entry */
2085
2086     tp->id = id;
2087
2088     if ( (vlan = get_vlannamebyid(id)) == NULL) {
2089         /* unknown name */
2090         g_snprintf(tp->name, MAXVLANNAMELEN, "<%u>", id);
2091
2092     } else {
2093         g_strlcpy(tp->name, vlan->name, MAXVLANNAMELEN);
2094     }
2095
2096     return tp->name;
2097
2098 } /* vlan_name_lookup */
2099 /* VLAN END */
2100
2101 static gboolean
2102 read_hosts_file (const char *hostspath, gboolean store_entries)
2103 {
2104     FILE *hf;
2105     char *line = NULL;
2106     int size = 0;
2107     gchar *cp;
2108     union {
2109         guint32 ip4_addr;
2110         ws_in6_addr ip6_addr;
2111     } host_addr;
2112     gboolean is_ipv6, entry_found = FALSE;
2113
2114     /*
2115      *  See the hosts(4) or hosts(5) man page for hosts file format
2116      *  (not available on all systems).
2117      */
2118     if ((hf = ws_fopen(hostspath, "r")) == NULL)
2119         return FALSE;
2120
2121     while (fgetline(&line, &size, hf) >= 0) {
2122         if ((cp = strchr(line, '#')))
2123             *cp = '\0';
2124
2125         if ((cp = strtok(line, " \t")) == NULL)
2126             continue; /* no tokens in the line */
2127
2128         if (ws_inet_pton6(cp, &host_addr.ip6_addr)) {
2129             /* Valid IPv6 */
2130             is_ipv6 = TRUE;
2131         } else if (ws_inet_pton4(cp, &host_addr.ip4_addr)) {
2132             /* Valid IPv4 */
2133             is_ipv6 = FALSE;
2134         } else {
2135             continue;
2136         }
2137
2138         if ((cp = strtok(NULL, " \t")) == NULL)
2139             continue; /* no host name */
2140
2141         entry_found = TRUE;
2142         if (store_entries) {
2143             if (is_ipv6) {
2144                 add_ipv6_name(&host_addr.ip6_addr, cp);
2145             } else {
2146                 add_ipv4_name(host_addr.ip4_addr, cp);
2147             }
2148         }
2149     }
2150     wmem_free(wmem_epan_scope(), line);
2151
2152     fclose(hf);
2153     return entry_found ? TRUE : FALSE;
2154 } /* read_hosts_file */
2155
2156 gboolean
2157 add_hosts_file (const char *hosts_file)
2158 {
2159     gboolean found = FALSE;
2160     guint i;
2161
2162     if (!hosts_file)
2163         return FALSE;
2164
2165     if (!extra_hosts_files)
2166         extra_hosts_files = g_ptr_array_new();
2167
2168     for (i = 0; i < extra_hosts_files->len; i++) {
2169         if (strcmp(hosts_file, (const char *) g_ptr_array_index(extra_hosts_files, i)) == 0)
2170             found = TRUE;
2171     }
2172
2173     if (!found) {
2174         g_ptr_array_add(extra_hosts_files, wmem_strdup(wmem_epan_scope(), hosts_file));
2175         return read_hosts_file (hosts_file, FALSE);
2176     }
2177     return TRUE;
2178 }
2179
2180 gboolean
2181 add_ip_name_from_string (const char *addr, const char *name)
2182 {
2183     union {
2184         guint32 ip4_addr;
2185         ws_in6_addr ip6_addr;
2186     } host_addr;
2187     gboolean is_ipv6;
2188     resolved_ipv4_t *resolved_ipv4_entry;
2189     resolved_ipv6_t *resolved_ipv6_entry;
2190
2191     if (ws_inet_pton6(addr, &host_addr.ip6_addr)) {
2192         is_ipv6 = TRUE;
2193     } else if (ws_inet_pton4(addr, &host_addr.ip4_addr)) {
2194         is_ipv6 = FALSE;
2195     } else {
2196         return FALSE;
2197     }
2198
2199     if (is_ipv6) {
2200         resolved_ipv6_entry = wmem_new(wmem_epan_scope(), resolved_ipv6_t);
2201         memcpy(&(resolved_ipv6_entry->ip6_addr), &host_addr.ip6_addr, 16);
2202         g_strlcpy(resolved_ipv6_entry->name, name, MAXNAMELEN);
2203         wmem_list_prepend(manually_resolved_ipv6_list, resolved_ipv6_entry);
2204     } else {
2205         resolved_ipv4_entry = wmem_new(wmem_epan_scope(), resolved_ipv4_t);
2206         resolved_ipv4_entry->host_addr = host_addr.ip4_addr;
2207         g_strlcpy(resolved_ipv4_entry->name, name, MAXNAMELEN);
2208         wmem_list_prepend(manually_resolved_ipv4_list, resolved_ipv4_entry);
2209     }
2210
2211     return TRUE;
2212 } /* add_ip_name_from_string */
2213
2214 /*
2215  * Add the resolved addresses that are in use to the list used to create the NRB
2216  */
2217 static void
2218 ipv4_hash_table_resolved_to_list(gpointer key _U_, gpointer value, gpointer user_data)
2219 {
2220     addrinfo_lists_t *lists = (addrinfo_lists_t*)user_data;
2221     hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value;
2222
2223     if ((ipv4_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
2224         lists->ipv4_addr_list = g_list_prepend(lists->ipv4_addr_list, ipv4_hash_table_entry);
2225     }
2226
2227 }
2228
2229 /*
2230  * Add the resolved addresses that are in use to the list used to create the NRB
2231  */
2232
2233 static void
2234 ipv6_hash_table_resolved_to_list(gpointer key _U_, gpointer value, gpointer user_data)
2235 {
2236     addrinfo_lists_t *lists = (addrinfo_lists_t*)user_data;
2237     hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value;
2238
2239     if ((ipv6_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
2240         lists->ipv6_addr_list = g_list_prepend (lists->ipv6_addr_list, ipv6_hash_table_entry);
2241     }
2242
2243 }
2244
2245 addrinfo_lists_t *
2246 get_addrinfo_list(void)
2247 {
2248     if (ipv4_hash_table) {
2249         wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_resolved_to_list, &addrinfo_lists);
2250     }
2251
2252     if (ipv6_hash_table) {
2253         wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_resolved_to_list, &addrinfo_lists);
2254     }
2255
2256     return &addrinfo_lists;
2257 }
2258
2259 /* Read in a list of subnet definition - name pairs.
2260  * <line> = <comment> | <entry> | <whitespace>
2261  * <comment> = <whitespace>#<any>
2262  * <entry> = <subnet_definition> <whitespace> <subnet_name> [<comment>|<whitespace><any>]
2263  * <subnet_definition> = <ipv4_address> / <subnet_mask_length>
2264  * <ipv4_address> is a full address; it will be masked to get the subnet-ID.
2265  * <subnet_mask_length> is a decimal 1-31
2266  * <subnet_name> is a string containing no whitespace.
2267  * <whitespace> = (space | tab)+
2268  * Any malformed entries are ignored.
2269  * Any trailing data after the subnet_name is ignored.
2270  *
2271  * XXX Support IPv6
2272  */
2273 static gboolean
2274 read_subnets_file (const char *subnetspath)
2275 {
2276     FILE *hf;
2277     char *line = NULL;
2278     int size = 0;
2279     gchar *cp, *cp2;
2280     guint32 host_addr; /* IPv4 ONLY */
2281     guint8 mask_length;
2282
2283     if ((hf = ws_fopen(subnetspath, "r")) == NULL)
2284         return FALSE;
2285
2286     while (fgetline(&line, &size, hf) >= 0) {
2287         if ((cp = strchr(line, '#')))
2288             *cp = '\0';
2289
2290         if ((cp = strtok(line, " \t")) == NULL)
2291             continue; /* no tokens in the line */
2292
2293
2294         /* Expected format is <IP4 address>/<subnet length> */
2295         cp2 = strchr(cp, '/');
2296         if (NULL == cp2) {
2297             /* No length */
2298             continue;
2299         }
2300         *cp2 = '\0'; /* Cut token */
2301         ++cp2    ;
2302
2303         /* Check if this is a valid IPv4 address */
2304         if (!str_to_ip(cp, &host_addr)) {
2305             continue; /* no */
2306         }
2307
2308         if (!ws_strtou8(cp2, NULL, &mask_length) || mask_length == 0 || mask_length > 32) {
2309             continue; /* invalid mask length */
2310         }
2311
2312         if ((cp = strtok(NULL, " \t")) == NULL)
2313             continue; /* no subnet name */
2314
2315         subnet_entry_set(host_addr, mask_length, cp);
2316     }
2317     wmem_free(wmem_epan_scope(), line);
2318
2319     fclose(hf);
2320     return TRUE;
2321 } /* read_subnets_file */
2322
2323 static subnet_entry_t
2324 subnet_lookup(const guint32 addr)
2325 {
2326     subnet_entry_t subnet_entry;
2327     guint32 i;
2328
2329     /* Search mask lengths linearly, longest first */
2330
2331     i = SUBNETLENGTHSIZE;
2332     while(have_subnet_entry && i > 0) {
2333         guint32 masked_addr;
2334         subnet_length_entry_t* length_entry;
2335
2336         /* Note that we run from 31 (length 32)  to 0 (length 1)  */
2337         --i;
2338         g_assert(i < SUBNETLENGTHSIZE);
2339
2340
2341         length_entry = &subnet_length_entries[i];
2342
2343         if (NULL != length_entry->subnet_addresses) {
2344             sub_net_hashipv4_t * tp;
2345             guint32 hash_idx;
2346
2347             masked_addr = addr & length_entry->mask;
2348             hash_idx = HASH_IPV4_ADDRESS(masked_addr);
2349
2350             tp = length_entry->subnet_addresses[hash_idx];
2351             while(tp != NULL && tp->addr != masked_addr) {
2352                 tp = tp->next;
2353             }
2354
2355             if (NULL != tp) {
2356                 subnet_entry.mask = length_entry->mask;
2357                 subnet_entry.mask_length = i + 1; /* Length is offset + 1 */
2358                 subnet_entry.name = tp->name;
2359                 return subnet_entry;
2360             }
2361         }
2362     }
2363
2364     subnet_entry.mask = 0;
2365     subnet_entry.mask_length = 0;
2366     subnet_entry.name = NULL;
2367
2368     return subnet_entry;
2369 }
2370
2371 /* Add a subnet-definition - name pair to the set.
2372  * The definition is taken by masking the address passed in with the mask of the
2373  * given length.
2374  */
2375 static void
2376 subnet_entry_set(guint32 subnet_addr, const guint8 mask_length, const gchar* name)
2377 {
2378     subnet_length_entry_t* entry;
2379     sub_net_hashipv4_t * tp;
2380     gsize hash_idx;
2381
2382     g_assert(mask_length > 0 && mask_length <= 32);
2383
2384     entry = &subnet_length_entries[mask_length - 1];
2385
2386     subnet_addr &= entry->mask;
2387
2388     hash_idx = HASH_IPV4_ADDRESS(subnet_addr);
2389
2390     if (NULL == entry->subnet_addresses) {
2391         entry->subnet_addresses = (sub_net_hashipv4_t**)wmem_alloc0(wmem_epan_scope(), sizeof(sub_net_hashipv4_t*) * HASHHOSTSIZE);
2392     }
2393
2394     if (NULL != (tp = entry->subnet_addresses[hash_idx])) {
2395         sub_net_hashipv4_t * new_tp;
2396
2397         while (tp->next) {
2398             if (tp->addr == subnet_addr) {
2399                 return; /* XXX provide warning that an address was repeated? */
2400             } else {
2401                 tp = tp->next;
2402             }
2403         }
2404
2405         new_tp = wmem_new(wmem_epan_scope(), sub_net_hashipv4_t);
2406         tp->next = new_tp;
2407         tp = new_tp;
2408     } else {
2409         tp = entry->subnet_addresses[hash_idx] = wmem_new(wmem_epan_scope(), sub_net_hashipv4_t);
2410     }
2411
2412     tp->next = NULL;
2413     tp->addr = subnet_addr;
2414     g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
2415     have_subnet_entry = TRUE;
2416 }
2417
2418 static void
2419 subnet_name_lookup_init(void)
2420 {
2421     gchar* subnetspath;
2422     guint32 i;
2423
2424     for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
2425         guint32 length = i + 1;
2426
2427         subnet_length_entries[i].subnet_addresses  = NULL;
2428         subnet_length_entries[i].mask_length  = length;
2429         subnet_length_entries[i].mask = g_htonl(ip_get_subnet_mask(length));
2430     }
2431
2432     /* Check profile directory before personal configuration */
2433     subnetspath = get_persconffile_path(ENAME_SUBNETS, TRUE);
2434     if (!read_subnets_file(subnetspath)) {
2435         if (errno != ENOENT) {
2436             report_open_failure(subnetspath, errno, FALSE);
2437         }
2438
2439         g_free(subnetspath);
2440         subnetspath = get_persconffile_path(ENAME_SUBNETS, FALSE);
2441         if (!read_subnets_file(subnetspath) && errno != ENOENT) {
2442             report_open_failure(subnetspath, errno, FALSE);
2443         }
2444     }
2445     g_free(subnetspath);
2446
2447     /*
2448      * Load the global subnets file, if we have one.
2449      */
2450     subnetspath = get_datafile_path(ENAME_SUBNETS);
2451     if (!read_subnets_file(subnetspath) && errno != ENOENT) {
2452         report_open_failure(subnetspath, errno, FALSE);
2453     }
2454     g_free(subnetspath);
2455 }
2456
2457 /* SS7 PC Name Resolution Portion */
2458 static hashss7pc_t *
2459 new_ss7pc(const guint8 ni, const guint32 pc)
2460 {
2461     hashss7pc_t *tp = wmem_new(wmem_epan_scope(), hashss7pc_t);
2462     tp->id = (ni<<24) + (pc&0xffffff);
2463     tp->pc_addr[0] = '\0';
2464     tp->name[0] = '\0';
2465
2466     return tp;
2467 }
2468
2469 static hashss7pc_t *
2470 host_lookup_ss7pc(const guint8 ni, const guint32 pc)
2471 {
2472     hashss7pc_t * volatile tp;
2473     guint32 id;
2474
2475     id = (ni<<24) + (pc&0xffffff);
2476
2477     tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
2478     if (tp == NULL) {
2479         tp = new_ss7pc(ni, pc);
2480         wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
2481     }
2482
2483     return tp;
2484 }
2485
2486 void fill_unresolved_ss7pc(const gchar * pc_addr, const guint8 ni, const guint32 pc)
2487 {
2488     hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
2489
2490     g_strlcpy(tp->pc_addr, pc_addr, MAXNAMELEN);
2491 }
2492
2493 const gchar *
2494 get_hostname_ss7pc(const guint8 ni, const guint32 pc)
2495 {
2496     hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
2497
2498     /* never resolved yet*/
2499     if (tp->pc_addr[0] == '\0')
2500         return tp->pc_addr;
2501
2502     /* Don't have name in file */
2503     if (tp->name[0] == '\0')
2504         return tp->pc_addr;
2505
2506     if (!gbl_resolv_flags.ss7pc_name)
2507         return tp->pc_addr;
2508
2509     return tp->name;
2510 }
2511
2512 static void
2513 add_ss7pc_name(const guint8 ni, guint32 pc, const gchar *name)
2514 {
2515     hashss7pc_t *tp;
2516     guint32 id;
2517
2518     if (!name || name[0] == '\0')
2519         return;
2520
2521     id = (ni<<24) + (pc&0xffffff);
2522     tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
2523     if (!tp) {
2524         tp = new_ss7pc(ni, pc);
2525         wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
2526     }
2527
2528     if (g_ascii_strcasecmp(tp->name, name)) {
2529         g_strlcpy(tp->name, name, MAXNAMELEN);
2530     }
2531 }
2532
2533 static gboolean
2534 read_ss7pcs_file(const char *ss7pcspath)
2535 {
2536     FILE *hf;
2537     char *line = NULL;
2538     int size = 0;
2539     gchar *cp;
2540     guint8 ni;
2541     guint32 pc;
2542     gboolean entry_found = FALSE;
2543
2544     /*
2545     *  File format is Network Indicator (decimal)<dash>Point Code (Decimal)<tab/space>Hostname
2546     */
2547     if ((hf = ws_fopen(ss7pcspath, "r")) == NULL)
2548         return FALSE;
2549
2550     while (fgetline(&line, &size, hf) >= 0) {
2551         if ((cp = strchr(line, '#')))
2552             *cp = '\0';
2553
2554         if ((cp = strtok(line, "-")) == NULL)
2555             continue; /*no ni-pc separator*/
2556         if (!ws_strtou8(cp, NULL, &ni))
2557             continue;
2558         if (ni > 3)
2559              continue;
2560
2561         if ((cp = strtok(NULL, " \t")) == NULL)
2562             continue; /* no tokens for pc and name */
2563         if (!ws_strtou32(cp, NULL, &pc))
2564             continue;
2565         if (pc >> 24 > 0)
2566             continue;
2567
2568         if ((cp = strtok(NULL, " \t")) == NULL)
2569             continue; /* no host name */
2570
2571         entry_found = TRUE;
2572         add_ss7pc_name(ni, pc, cp);
2573     }
2574     wmem_free(wmem_epan_scope(), line);
2575
2576     fclose(hf);
2577     return entry_found ? TRUE : FALSE;
2578 }
2579
2580 static void
2581 ss7pc_name_lookup_init(void)
2582 {
2583     char *ss7pcspath;
2584
2585     g_assert(ss7pc_hash_table == NULL);
2586
2587     ss7pc_hash_table = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
2588
2589     /*
2590      * Load the user's ss7pcs file
2591      */
2592     ss7pcspath = get_persconffile_path(ENAME_SS7PCS, TRUE);
2593     if (!read_ss7pcs_file(ss7pcspath) && errno != ENOENT) {
2594         report_open_failure(ss7pcspath, errno, FALSE);
2595     }
2596     g_free(ss7pcspath);
2597 }
2598
2599 /* SS7PC Name Resolution End*/
2600
2601
2602 /*
2603  *  External Functions
2604  */
2605
2606 void
2607 addr_resolve_pref_init(module_t *nameres)
2608 {
2609     prefs_register_bool_preference(nameres, "mac_name",
2610             "Resolve MAC addresses",
2611             "Resolve Ethernet MAC addresses to host names from the preferences"
2612             " or system's Ethers file, or to a manufacturer based name.",
2613             &gbl_resolv_flags.mac_name);
2614
2615     prefs_register_bool_preference(nameres, "transport_name",
2616             "Resolve transport names",
2617             "Resolve TCP/UDP ports into service names",
2618             &gbl_resolv_flags.transport_name);
2619
2620     prefs_register_bool_preference(nameres, "network_name",
2621             "Resolve network (IP) addresses",
2622             "Resolve IPv4, IPv6, and IPX addresses into host names."
2623             " The next set of check boxes determines how name resolution should be performed."
2624             " If no other options are checked name resolution is made from Wireshark's host file,"
2625             " capture file name resolution blocks and DNS packets in the capture.",
2626             &gbl_resolv_flags.network_name);
2627
2628     prefs_register_bool_preference(nameres, "dns_pkt_addr_resolution",
2629             "Use captured DNS packet data for address resolution",
2630             "Whether address/name pairs found in captured DNS packets should be used by Wireshark for name resolution.",
2631             &gbl_resolv_flags.dns_pkt_addr_resolution);
2632
2633 #ifdef HAVE_C_ARES
2634     prefs_register_bool_preference(nameres, "use_external_name_resolver",
2635             "Use an external network name resolver",
2636             "Use your system's configured name resolver"
2637             " (usually DNS) to resolve network names."
2638             " Only applies when network name resolution"
2639             " is enabled.",
2640             &gbl_resolv_flags.use_external_net_name_resolver);
2641
2642     prefs_register_obsolete_preference(nameres, "concurrent_dns");
2643
2644     prefs_register_uint_preference(nameres, "name_resolve_concurrency",
2645             "Maximum concurrent requests",
2646             "The maximum number of DNS requests that may"
2647             " be active at any time. A large value (many"
2648             " thousands) might overload the network or make"
2649             " your DNS server behave badly.",
2650             10,
2651             &name_resolve_concurrency);
2652 #else
2653     prefs_register_static_text_preference(nameres, "use_external_name_resolver",
2654             "Use an external network name resolver: N/A",
2655             "Support for using a concurrent external name resolver was not"
2656             " compiled into this version of Wireshark");
2657 #endif
2658
2659     prefs_register_bool_preference(nameres, "hosts_file_handling",
2660             "Only use the profile \"hosts\" file",
2661             "By default \"hosts\" files will be loaded from multiple sources."
2662             " Checking this box only loads the \"hosts\" in the current profile.",
2663             &gbl_resolv_flags.load_hosts_file_from_profile_only);
2664
2665     prefs_register_bool_preference(nameres, "vlan_name",
2666             "Resolve VLAN IDs",
2667             "Resolve VLAN IDs to network names from the preferences \"vlans\" file."
2668             " Format of the file is: \"ID<Tab>Name\"."
2669             " One line per VLAN, e.g.: 1 Management",
2670             &gbl_resolv_flags.vlan_name);
2671
2672     prefs_register_bool_preference(nameres, "ss7_pc_name",
2673             "Resolve SS7 PCs",
2674             "Resolve SS7 Point Codes to node names from the profiles \"ss7pcs\" file."
2675             " Format of the file is: \"Network_Indicator<Dash>PC_Decimal<Tab>Name\"."
2676             " One line per Point Code, e.g.: 2-1234 MyPointCode1",
2677             &gbl_resolv_flags.ss7pc_name);
2678
2679 }
2680
2681 void
2682 disable_name_resolution(void) {
2683     gbl_resolv_flags.mac_name                           = FALSE;
2684     gbl_resolv_flags.network_name                       = FALSE;
2685     gbl_resolv_flags.transport_name                     = FALSE;
2686     gbl_resolv_flags.dns_pkt_addr_resolution            = FALSE;
2687     gbl_resolv_flags.use_external_net_name_resolver     = FALSE;
2688     gbl_resolv_flags.vlan_name                          = FALSE;
2689     gbl_resolv_flags.ss7pc_name                         = FALSE;
2690 }
2691
2692 #ifdef HAVE_C_ARES
2693 gboolean
2694 host_name_lookup_process(void) {
2695     async_dns_queue_msg_t *caqm;
2696     struct timeval tv = { 0, 0 };
2697     int nfds;
2698     fd_set rfds, wfds;
2699     gboolean nro = new_resolved_objects;
2700     wmem_list_frame_t* head;
2701
2702     new_resolved_objects = FALSE;
2703     nro |= maxmind_db_lookup_process();
2704
2705     if (!async_dns_initialized)
2706         /* c-ares not initialized. Bail out and cancel timers. */
2707         return nro;
2708
2709     head = wmem_list_head(async_dns_queue_head);
2710
2711     while (head != NULL && async_dns_in_flight <= name_resolve_concurrency) {
2712         caqm = (async_dns_queue_msg_t *)wmem_list_frame_data(head);
2713         wmem_list_remove_frame(async_dns_queue_head, head);
2714         if (caqm->family == AF_INET) {
2715             ares_gethostbyaddr(ghba_chan, &caqm->addr.ip4, sizeof(guint32), AF_INET,
2716                     c_ares_ghba_cb, caqm);
2717             async_dns_in_flight++;
2718         } else if (caqm->family == AF_INET6) {
2719             ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(ws_in6_addr),
2720                     AF_INET6, c_ares_ghba_cb, caqm);
2721             async_dns_in_flight++;
2722         }
2723
2724         head = wmem_list_head(async_dns_queue_head);
2725     }
2726
2727     FD_ZERO(&rfds);
2728     FD_ZERO(&wfds);
2729     nfds = ares_fds(ghba_chan, &rfds, &wfds);
2730     if (nfds > 0) {
2731         if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
2732             fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
2733             return nro;
2734         }
2735         ares_process(ghba_chan, &rfds, &wfds);
2736     }
2737
2738     /* Any new entries? */
2739     return nro;
2740 }
2741
2742 static void
2743 _host_name_lookup_cleanup(void) {
2744     async_dns_queue_head = NULL;
2745
2746     if (async_dns_initialized) {
2747         ares_destroy(ghba_chan);
2748         ares_destroy(ghbn_chan);
2749     }
2750 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2751     ares_library_cleanup();
2752 #endif
2753     async_dns_initialized = FALSE;
2754 }
2755
2756 #else
2757
2758 gboolean
2759 host_name_lookup_process(void) {
2760     gboolean nro = new_resolved_objects;
2761
2762     new_resolved_objects = FALSE;
2763
2764     nro |= maxmind_db_lookup_process();
2765
2766     return nro;
2767 }
2768
2769 static void
2770 _host_name_lookup_cleanup(void) {
2771 }
2772
2773 #endif /* HAVE_C_ARES */
2774
2775 const gchar *
2776 get_hostname(const guint addr)
2777 {
2778     /* XXX why do we call this if we're not resolving? To create hash entries?
2779      * Why?
2780      */
2781     hashipv4_t *tp = host_lookup(addr);
2782
2783     if (!gbl_resolv_flags.network_name)
2784         return tp->ip;
2785
2786     tp->flags |= RESOLVED_ADDRESS_USED;
2787
2788     return tp->name;
2789 }
2790
2791 /* -------------------------- */
2792
2793 const gchar *
2794 get_hostname6(const ws_in6_addr *addr)
2795 {
2796     /* XXX why do we call this if we're not resolving? To create hash entries?
2797      * Why?
2798      */
2799     hashipv6_t *tp = host_lookup6(addr);
2800
2801     if (!gbl_resolv_flags.network_name)
2802         return tp->ip6;
2803
2804     tp->flags |= RESOLVED_ADDRESS_USED;
2805
2806     return tp->name;
2807 }
2808
2809 /* -------------------------- */
2810 void
2811 add_ipv4_name(const guint addr, const gchar *name)
2812 {
2813     hashipv4_t *tp;
2814
2815     /*
2816      * Don't add zero-length names; apparently, some resolvers will return
2817      * them if they get them from DNS.
2818      */
2819     if (!name || name[0] == '\0')
2820         return;
2821
2822     tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
2823     if (!tp) {
2824         tp = new_ipv4(addr);
2825         wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
2826     }
2827
2828     if (g_ascii_strcasecmp(tp->name, name)) {
2829         g_strlcpy(tp->name, name, MAXNAMELEN);
2830         new_resolved_objects = TRUE;
2831     }
2832     tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
2833 } /* add_ipv4_name */
2834
2835 /* -------------------------- */
2836 void
2837 add_ipv6_name(const ws_in6_addr *addrp, const gchar *name)
2838 {
2839     hashipv6_t *tp;
2840
2841     /*
2842      * Don't add zero-length names; apparently, some resolvers will return
2843      * them if they get them from DNS.
2844      */
2845     if (!name || name[0] == '\0')
2846         return;
2847
2848     tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addrp);
2849     if (!tp) {
2850         ws_in6_addr *addr_key;
2851
2852         addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr);
2853         tp = new_ipv6(addrp);
2854         memcpy(addr_key, addrp, 16);
2855         wmem_map_insert(ipv6_hash_table, addr_key, tp);
2856     }
2857
2858     if (g_ascii_strcasecmp(tp->name, name)) {
2859         g_strlcpy(tp->name, name, MAXNAMELEN);
2860         new_resolved_objects = TRUE;
2861     }
2862     tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
2863 } /* add_ipv6_name */
2864
2865 static void
2866 add_manually_resolved_ipv4(gpointer data, gpointer user_data _U_)
2867 {
2868     resolved_ipv4_t *resolved_ipv4_entry = (resolved_ipv4_t *)data;
2869
2870     add_ipv4_name(resolved_ipv4_entry->host_addr, resolved_ipv4_entry->name);
2871 }
2872
2873 static void
2874 add_manually_resolved_ipv6(gpointer data, gpointer user_data _U_)
2875 {
2876     resolved_ipv6_t *resolved_ipv6_entry = (resolved_ipv6_t *)data;
2877
2878     add_ipv6_name(&(resolved_ipv6_entry->ip6_addr), resolved_ipv6_entry->name);
2879 }
2880
2881 static void
2882 add_manually_resolved(void)
2883 {
2884     if (manually_resolved_ipv4_list) {
2885         wmem_list_foreach(manually_resolved_ipv4_list, add_manually_resolved_ipv4, NULL);
2886     }
2887
2888     if (manually_resolved_ipv6_list) {
2889         wmem_list_foreach(manually_resolved_ipv6_list, add_manually_resolved_ipv6, NULL);
2890     }
2891 }
2892
2893 static void
2894 host_name_lookup_init(void)
2895 {
2896     char *hostspath;
2897     guint i;
2898
2899     g_assert(ipxnet_hash_table == NULL);
2900     ipxnet_hash_table = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
2901
2902     g_assert(ipv4_hash_table == NULL);
2903     ipv4_hash_table = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
2904
2905     g_assert(ipv6_hash_table == NULL);
2906     ipv6_hash_table = wmem_map_new(wmem_epan_scope(), ipv6_oat_hash, ipv6_equal);
2907
2908 #ifdef HAVE_C_ARES
2909     g_assert(async_dns_queue_head == NULL);
2910     async_dns_queue_head = wmem_list_new(wmem_epan_scope());
2911 #endif
2912
2913     if (manually_resolved_ipv4_list == NULL)
2914         manually_resolved_ipv4_list = wmem_list_new(wmem_epan_scope());
2915
2916     if (manually_resolved_ipv6_list == NULL)
2917         manually_resolved_ipv6_list = wmem_list_new(wmem_epan_scope());
2918
2919     /*
2920      * Load the global hosts file, if we have one.
2921      */
2922     if (!gbl_resolv_flags.load_hosts_file_from_profile_only) {
2923         hostspath = get_datafile_path(ENAME_HOSTS);
2924         if (!read_hosts_file(hostspath, TRUE) && errno != ENOENT) {
2925             report_open_failure(hostspath, errno, FALSE);
2926         }
2927         g_free(hostspath);
2928     }
2929     /*
2930      * Load the user's hosts file no matter what, if they have one.
2931      */
2932     hostspath = get_persconffile_path(ENAME_HOSTS, TRUE);
2933     if (!read_hosts_file(hostspath, TRUE) && errno != ENOENT) {
2934         report_open_failure(hostspath, errno, FALSE);
2935     }
2936     g_free(hostspath);
2937 #ifdef HAVE_C_ARES
2938 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2939     if (ares_library_init(ARES_LIB_INIT_ALL) == ARES_SUCCESS) {
2940 #endif
2941         if (ares_init(&ghba_chan) == ARES_SUCCESS && ares_init(&ghbn_chan) == ARES_SUCCESS) {
2942             async_dns_initialized = TRUE;
2943         }
2944 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
2945     }
2946 #endif
2947 #else
2948 #endif /* HAVE_C_ARES */
2949
2950     if (extra_hosts_files && !gbl_resolv_flags.load_hosts_file_from_profile_only) {
2951         for (i = 0; i < extra_hosts_files->len; i++) {
2952             read_hosts_file((const char *) g_ptr_array_index(extra_hosts_files, i), TRUE);
2953         }
2954     }
2955
2956     subnet_name_lookup_init();
2957
2958     add_manually_resolved();
2959
2960     ss7pc_name_lookup_init();
2961 }
2962
2963 static void
2964 host_name_lookup_cleanup(void)
2965 {
2966     guint32 i, j;
2967     sub_net_hashipv4_t *entry, *next_entry;
2968
2969     _host_name_lookup_cleanup();
2970
2971     ipxnet_hash_table = NULL;
2972     ipv4_hash_table = NULL;
2973     ipv6_hash_table = NULL;
2974     ss7pc_hash_table = NULL;
2975
2976     for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
2977         if (subnet_length_entries[i].subnet_addresses != NULL) {
2978             for (j = 0; j < HASHHOSTSIZE; j++) {
2979                 for (entry = subnet_length_entries[i].subnet_addresses[j];
2980                      entry != NULL; entry = next_entry) {
2981                     next_entry = entry->next;
2982                     wmem_free(wmem_epan_scope(), entry);
2983                 }
2984             }
2985             wmem_free(wmem_epan_scope(), subnet_length_entries[i].subnet_addresses);
2986             subnet_length_entries[i].subnet_addresses = NULL;
2987         }
2988     }
2989
2990     have_subnet_entry = FALSE;
2991     new_resolved_objects = FALSE;
2992 }
2993
2994
2995 void host_name_lookup_reset(void)
2996 {
2997     host_name_lookup_cleanup();
2998     host_name_lookup_init();
2999 }
3000
3001 void
3002 manually_resolve_cleanup(void)
3003 {
3004     if (manually_resolved_ipv4_list) {
3005         wmem_destroy_list(manually_resolved_ipv4_list);
3006         manually_resolved_ipv4_list = NULL;
3007     }
3008     if (manually_resolved_ipv6_list) {
3009         wmem_destroy_list(manually_resolved_ipv6_list);
3010         manually_resolved_ipv6_list = NULL;
3011     }
3012 }
3013
3014 gchar *
3015 udp_port_to_display(wmem_allocator_t *allocator, guint port)
3016 {
3017
3018     if (!gbl_resolv_flags.transport_name) {
3019         return wmem_utoa(allocator, port);
3020     }
3021
3022     return wmem_strdup(allocator, serv_name_lookup(PT_UDP, port));
3023
3024 } /* udp_port_to_display */
3025
3026 gchar *
3027 dccp_port_to_display(wmem_allocator_t *allocator, guint port)
3028 {
3029
3030     if (!gbl_resolv_flags.transport_name) {
3031         return wmem_utoa(allocator, port);
3032     }
3033
3034     return wmem_strdup(allocator, serv_name_lookup(PT_DCCP, port));
3035
3036 } /* dccp_port_to_display */
3037
3038 gchar *
3039 tcp_port_to_display(wmem_allocator_t *allocator, guint port)
3040 {
3041
3042     if (!gbl_resolv_flags.transport_name) {
3043         return wmem_utoa(allocator, port);
3044     }
3045
3046     return wmem_strdup(allocator, serv_name_lookup(PT_TCP, port));
3047
3048 } /* tcp_port_to_display */
3049
3050 gchar *
3051 sctp_port_to_display(wmem_allocator_t *allocator, guint port)
3052 {
3053
3054     if (!gbl_resolv_flags.transport_name) {
3055         return wmem_utoa(allocator, port);
3056     }
3057
3058     return wmem_strdup(allocator, serv_name_lookup(PT_SCTP, port));
3059
3060 } /* sctp_port_to_display */
3061
3062 gchar *
3063 port_with_resolution_to_str(wmem_allocator_t *scope, port_type proto, guint port)
3064 {
3065     const gchar *port_str;
3066
3067     if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
3068         /* No name resolution support, just return port string */
3069         return wmem_strdup_printf(scope, "%u", port);
3070     }
3071     port_str = serv_name_lookup(proto, port);
3072     g_assert(port_str);
3073     return wmem_strdup_printf(scope, "%s (%u)", port_str, port);
3074 }
3075
3076 int
3077 port_with_resolution_to_str_buf(gchar *buf, gulong buf_size, port_type proto, guint port)
3078 {
3079     const gchar *port_str;
3080
3081     if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
3082         /* No name resolution support, just return port string */
3083         return g_snprintf(buf, buf_size, "%u", port);
3084     }
3085     port_str = serv_name_lookup(proto, port);
3086     g_assert(port_str);
3087     return g_snprintf(buf, buf_size, "%s (%u)", port_str, port);
3088 }
3089
3090 const gchar *
3091 get_ether_name(const guint8 *addr)
3092 {
3093     hashether_t *tp;
3094     gboolean resolve = gbl_resolv_flags.mac_name;
3095
3096     tp = eth_name_lookup(addr, resolve);
3097
3098     return resolve ? tp->resolved_name : tp->hexaddr;
3099
3100 } /* get_ether_name */
3101
3102 const gchar *
3103 tvb_get_ether_name(tvbuff_t *tvb, gint offset)
3104 {
3105     return get_ether_name(tvb_get_ptr(tvb, offset, 6));
3106 }
3107
3108 /* Look for a (non-dummy) ether name in the hash, and return it if found.
3109  * If it's not found, simply return NULL.
3110  */
3111 const gchar *
3112 get_ether_name_if_known(const guint8 *addr)
3113 {
3114     hashether_t *tp;
3115
3116     /* Initialize ether structs if we're the first
3117      * ether-related function called */
3118     if (!gbl_resolv_flags.mac_name)
3119         return NULL;
3120
3121     /* eth_name_lookup will create a (resolved) hash entry if it doesn't exist */
3122     tp = eth_name_lookup(addr, TRUE);
3123     g_assert(tp != NULL);
3124
3125     if (tp->status == HASHETHER_STATUS_RESOLVED_NAME) {
3126         /* Name is from an ethers file */
3127         return tp->resolved_name;
3128     }
3129     else {
3130         /* Name was created */
3131         return NULL;
3132     }
3133 }
3134
3135 void
3136 add_ether_byip(const guint ip, const guint8 *eth)
3137 {
3138     hashipv4_t *tp;
3139
3140     /* first check that IP address can be resolved */
3141     if (!gbl_resolv_flags.network_name)
3142         return;
3143
3144     tp = host_lookup(ip);
3145
3146     /*
3147      * Was this IP address resolved to a host name?
3148      */
3149     if (tp->flags & NAME_RESOLVED) {
3150         /*
3151          * Yes, so add an entry in the ethers hashtable resolving
3152          * the MAC address to that name.
3153          */
3154         add_eth_name(eth, tp->name);
3155     }
3156
3157 } /* add_ether_byip */
3158
3159 gchar *
3160 ipxnet_to_str_punct(wmem_allocator_t *allocator, const guint32 ad, const char punct)
3161 {
3162     gchar *buf = (gchar *)wmem_alloc(allocator, 12);
3163
3164     *dword_to_hex_punct(buf, ad, punct) = '\0';
3165     return buf;
3166 }
3167
3168 gchar *
3169 get_ipxnet_name(wmem_allocator_t *allocator, const guint32 addr)
3170 {
3171
3172     if (!gbl_resolv_flags.network_name) {
3173         return ipxnet_to_str_punct(allocator, addr, '\0');
3174     }
3175
3176     return ipxnet_name_lookup(allocator, addr);
3177
3178 } /* get_ipxnet_name */
3179
3180 gchar *
3181 get_vlan_name(wmem_allocator_t *allocator, const guint16 id)
3182 {
3183
3184     if (!gbl_resolv_flags.vlan_name) {
3185         return NULL;
3186     }
3187
3188     return wmem_strdup(allocator, vlan_name_lookup(id));
3189
3190 } /* get_vlan_name */
3191
3192 const gchar *
3193 get_manuf_name(const guint8 *addr)
3194 {
3195     hashmanuf_t *manuf_value;
3196
3197     manuf_value = manuf_name_lookup(addr);
3198     if (gbl_resolv_flags.mac_name && manuf_value->status != HASHETHER_STATUS_UNRESOLVED)
3199         return manuf_value->resolved_name;
3200
3201     return manuf_value->hexaddr;
3202
3203 } /* get_manuf_name */
3204
3205 const gchar *
3206 tvb_get_manuf_name(tvbuff_t *tvb, gint offset)
3207 {
3208     return get_manuf_name(tvb_get_ptr(tvb, offset, 3));
3209 }
3210
3211 const gchar *
3212 get_manuf_name_if_known(const guint8 *addr)
3213 {
3214     hashmanuf_t *manuf_value;
3215     int manuf_key;
3216     guint8 oct;
3217
3218     /* manuf needs only the 3 most significant octets of the ethernet address */
3219     manuf_key = addr[0];
3220     manuf_key = manuf_key<<8;
3221     oct = addr[1];
3222     manuf_key = manuf_key | oct;
3223     manuf_key = manuf_key<<8;
3224     oct = addr[2];
3225     manuf_key = manuf_key | oct;
3226
3227     manuf_value = (hashmanuf_t *)wmem_map_lookup(manuf_hashtable, &manuf_key);
3228     if ((manuf_value == NULL) || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
3229         return NULL;
3230     }
3231
3232     return manuf_value->resolved_longname;
3233
3234 } /* get_manuf_name_if_known */
3235
3236 const gchar *
3237 uint_get_manuf_name_if_known(const guint manuf_key)
3238 {
3239     hashmanuf_t *manuf_value;
3240
3241     manuf_value = (hashmanuf_t *)wmem_map_lookup(manuf_hashtable, &manuf_key);
3242     if ((manuf_value == NULL) || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
3243         return NULL;
3244     }
3245
3246     return manuf_value->resolved_longname;
3247 }
3248
3249 const gchar *
3250 tvb_get_manuf_name_if_known(tvbuff_t *tvb, gint offset)
3251 {
3252     return get_manuf_name_if_known(tvb_get_ptr(tvb, offset, 3));
3253 }
3254
3255 char* get_hash_manuf_resolved_name(hashmanuf_t* manuf)
3256 {
3257     return manuf->resolved_longname;
3258 }
3259
3260 gchar *
3261 eui64_to_display(wmem_allocator_t *allocator, const guint64 addr_eui64)
3262 {
3263     guint8 *addr = (guint8 *)wmem_alloc(NULL, 8);
3264     hashmanuf_t *manuf_value;
3265     gchar *ret;
3266
3267     /* Copy and convert the address to network byte order. */
3268     *(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64));
3269
3270     manuf_value = manuf_name_lookup(addr);
3271     if (!gbl_resolv_flags.mac_name || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
3272         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]);
3273     } else {
3274         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]);
3275     }
3276
3277     wmem_free(NULL, addr);
3278     return ret;
3279 } /* eui64_to_display */
3280
3281 #ifdef HAVE_C_ARES
3282 #define GHI_TIMEOUT (250 * 1000)
3283 static void
3284 c_ares_ghi_cb(void *arg, int status, int timeouts _U_, struct hostent *hp) {
3285     /*
3286      * XXX - If we wanted to be really fancy we could cache results here and
3287      * look them up in get_host_ipaddr* below.
3288      */
3289     async_hostent_t *ahp = (async_hostent_t *)arg;
3290     if (status == ARES_SUCCESS && hp && ahp && hp->h_length == ahp->addr_size) {
3291         memcpy(ahp->addrp, hp->h_addr, hp->h_length);
3292         ahp->copied = hp->h_length;
3293     }
3294 }
3295 #endif /* HAVE_C_ARES */
3296
3297 /* Translate a string, assumed either to be a dotted-quad IPv4 address or
3298  * a host name, to a numeric IPv4 address.  Return TRUE if we succeed and
3299  * set "*addrp" to that numeric IPv4 address; return FALSE if we fail. */
3300 gboolean
3301 get_host_ipaddr(const char *host, guint32 *addrp)
3302 {
3303 #ifdef HAVE_C_ARES
3304     struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
3305     int nfds;
3306     fd_set rfds, wfds;
3307     async_hostent_t ahe;
3308 #endif
3309
3310     /*
3311      * XXX - are there places where this is used to translate something
3312      * that's *only* supposed to be an IPv4 address, and where it
3313      * *shouldn't* translate host names?
3314      */
3315     if (!ws_inet_pton4(host, addrp)) {
3316
3317         /* It's not a valid dotted-quad IP address; is it a valid
3318          * host name?
3319          */
3320
3321         /* If we're not allowed to do name resolution, don't do name
3322          * resolution...
3323          */
3324         if (!gbl_resolv_flags.network_name ||
3325                 !gbl_resolv_flags.use_external_net_name_resolver) {
3326             return FALSE;
3327         }
3328
3329 #ifdef HAVE_C_ARES
3330         if (!async_dns_initialized || name_resolve_concurrency < 1) {
3331             return FALSE;
3332         }
3333         ahe.addr_size = (int) sizeof (struct in_addr);
3334         ahe.copied = 0;
3335         ahe.addrp = addrp;
3336         ares_gethostbyname(ghbn_chan, host, AF_INET, c_ares_ghi_cb, &ahe);
3337         FD_ZERO(&rfds);
3338         FD_ZERO(&wfds);
3339         nfds = ares_fds(ghbn_chan, &rfds, &wfds);
3340         if (nfds > 0) {
3341             tvp = ares_timeout(ghbn_chan, &tv, &tv);
3342             if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
3343                 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
3344                 return FALSE;
3345             }
3346             ares_process(ghbn_chan, &rfds, &wfds);
3347         }
3348         ares_cancel(ghbn_chan);
3349         if (ahe.addr_size == ahe.copied) {
3350             return TRUE;
3351         }
3352         return FALSE;
3353 #endif
3354     }
3355
3356     return TRUE;
3357 }
3358
3359 /*
3360  * Translate IPv6 numeric address or FQDN hostname into binary IPv6 address.
3361  * Return TRUE if we succeed and set "*addrp" to that numeric IPv6 address;
3362  * return FALSE if we fail.
3363  */
3364 gboolean
3365 get_host_ipaddr6(const char *host, ws_in6_addr *addrp)
3366 {
3367 #ifdef HAVE_C_ARES
3368     struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
3369     int nfds;
3370     fd_set rfds, wfds;
3371     async_hostent_t ahe;
3372 #endif /* HAVE_C_ARES */
3373
3374     if (str_to_ip6(host, addrp))
3375         return TRUE;
3376
3377     /* It's not a valid dotted-quad IP address; is it a valid
3378      * host name?
3379      *
3380      * XXX - are there places where this is used to translate something
3381      * that's *only* supposed to be an IPv6 address, and where it
3382      * *shouldn't* translate host names?
3383      */
3384
3385     /* If we're not allowed to do name resolution, don't do name
3386      * resolution...
3387      */
3388     if (!gbl_resolv_flags.network_name ||
3389             !gbl_resolv_flags.use_external_net_name_resolver) {
3390         return FALSE;
3391     }
3392
3393     /* try FQDN */
3394 #ifdef HAVE_C_ARES
3395     if (!async_dns_initialized || name_resolve_concurrency < 1) {
3396         return FALSE;
3397     }
3398     ahe.addr_size = (int) sizeof (ws_in6_addr);
3399     ahe.copied = 0;
3400     ahe.addrp = addrp;
3401     ares_gethostbyname(ghbn_chan, host, AF_INET6, c_ares_ghi_cb, &ahe);
3402     FD_ZERO(&rfds);
3403     FD_ZERO(&wfds);
3404     nfds = ares_fds(ghbn_chan, &rfds, &wfds);
3405     if (nfds > 0) {
3406         tvp = ares_timeout(ghbn_chan, &tv, &tv);
3407         if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
3408             fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
3409             return FALSE;
3410         }
3411         ares_process(ghbn_chan, &rfds, &wfds);
3412     }
3413     ares_cancel(ghbn_chan);
3414     if (ahe.addr_size == ahe.copied) {
3415         return TRUE;
3416     }
3417 #endif
3418
3419     return FALSE;
3420 }
3421
3422 wmem_map_t *
3423 get_manuf_hashtable(void)
3424 {
3425     return manuf_hashtable;
3426 }
3427
3428 wmem_map_t *
3429 get_wka_hashtable(void)
3430 {
3431     return wka_hashtable;
3432 }
3433
3434 wmem_map_t *
3435 get_eth_hashtable(void)
3436 {
3437     return eth_hashtable;
3438 }
3439
3440 wmem_map_t *
3441 get_serv_port_hashtable(void)
3442 {
3443     return serv_port_hashtable;
3444 }
3445
3446 wmem_map_t *
3447 get_ipxnet_hash_table(void)
3448 {
3449         return ipxnet_hash_table;
3450 }
3451
3452 wmem_map_t *
3453 get_vlan_hash_table(void)
3454 {
3455         return vlan_hash_table;
3456 }
3457
3458 wmem_map_t *
3459 get_ipv4_hash_table(void)
3460 {
3461         return ipv4_hash_table;
3462 }
3463
3464 wmem_map_t *
3465 get_ipv6_hash_table(void)
3466 {
3467         return ipv6_hash_table;
3468 }
3469 /* Initialize all the address resolution subsystems in this file */
3470 void
3471 addr_resolv_init(void)
3472 {
3473     initialize_services();
3474     initialize_ethers();
3475     initialize_ipxnets();
3476     initialize_vlans();
3477     initialize_enterprises();
3478     host_name_lookup_init();
3479 }
3480
3481 /* Clean up all the address resolution subsystems in this file */
3482 void
3483 addr_resolv_cleanup(void)
3484 {
3485     vlan_name_lookup_cleanup();
3486     service_name_lookup_cleanup();
3487     ethers_cleanup();
3488     ipx_name_lookup_cleanup();
3489     enterprises_cleanup();
3490     host_name_lookup_cleanup();
3491 }
3492
3493 gboolean
3494 str_to_ip(const char *str, void *dst)
3495 {
3496     return ws_inet_pton4(str, (guint32 *)dst);
3497 }
3498
3499 gboolean
3500 str_to_ip6(const char *str, void *dst)
3501 {
3502     return ws_inet_pton6(str, (ws_in6_addr *)dst);
3503 }
3504
3505 /*
3506  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
3507  *
3508  * Local variables:
3509  * c-basic-offset: 4
3510  * tab-width: 8
3511  * indent-tabs-mode: nil
3512  * End:
3513  *
3514  * vi: set shiftwidth=4 tabstop=8 expandtab:
3515  * :indentSize=4:tabSize=8:noTabs=true:
3516  */