wmem: allow wmem_destroy_list to ignore a NULL list.
[wireshark-sm.git] / epan / addr_resolv.c
blob858acc4af165e6fa3771caea94cc0044a1a6c8c7
1 /* addr_resolv.c
2 * Routines for network object lookup
4 * Laurent Deniel <laurent.deniel@free.fr>
6 * Add option to resolv VLAN ID to describing name
7 * Uli Heilmeier, March 2016
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include "config.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
23 #include <wsutil/strtoi.h>
24 #include <wsutil/ws_assert.h>
26 #include "enterprises.h"
27 #include "manuf.h"
30 * Win32 doesn't have SIGALRM (and it's the OS where name lookup calls
31 * are most likely to take a long time, given the way address-to-name
32 * lookups are done over NBNS).
34 * macOS does have SIGALRM, but if you longjmp() out of a name resolution
35 * call in a signal handler, you might crash, because the state of the
36 * resolution code that sends messages to lookupd might be inconsistent
37 * if you jump out of it in middle of a call.
39 * There's no guarantee that longjmp()ing out of name resolution calls
40 * will work on *any* platform; OpenBSD got rid of the alarm/longjmp
41 * code in tcpdump, to avoid those sorts of problems, and that was
42 * picked up by tcpdump.org tcpdump.
44 * So, for now, we do not use alarm() and SIGALRM to time out host name
45 * lookups. If we get a lot of complaints about lookups taking a long time,
46 * we can reconsider that decision. (Note that tcpdump originally added
47 * such a timeout mechanism that for the benefit of systems using NIS to
48 * look up host names; that might now be fixed in NIS implementations, for
49 * those sites still using NIS rather than DNS for that.... tcpdump no
50 * longer does that, for the same reasons that we don't.)
52 * If we're using an asynchronous DNS resolver, that shouldn't be an issue.
53 * If we're using a synchronous name lookup mechanism (which we'd do mainly
54 * to support resolving addresses and host names using more mechanisms than
55 * just DNS, such as NIS, NBNS, or Mr. Hosts File), we could do that in
56 * a separate thread, making it, in effect, asynchronous.
59 #ifdef HAVE_NETINET_IN_H
60 # include <netinet/in.h>
61 #endif
63 #ifdef HAVE_NETDB_H
64 #include <netdb.h>
65 #endif
67 #ifdef HAVE_SYS_SOCKET_H
68 #include <sys/socket.h> /* needed to define AF_ values on UNIX */
69 #endif
71 #ifdef _WIN32
72 #include <winsock2.h> /* needed to define AF_ values on Windows */
73 #include <ws2tcpip.h>
74 #endif
76 #ifdef _WIN32
77 # define socklen_t unsigned int
78 #endif
79 #include <ares.h>
80 #include <ares_version.h>
82 #include <glib.h>
84 #include "packet.h"
85 #include "addr_resolv.h"
86 #include "wsutil/filesystem.h"
88 #include <wsutil/report_message.h>
89 #include <wsutil/file_util.h>
90 #include <wsutil/pint.h>
91 #include <wsutil/inet_cidr.h>
93 #include <epan/strutil.h>
94 #include <epan/to_str.h>
95 #include <epan/maxmind_db.h>
96 #include <epan/prefs.h>
97 #include <epan/uat.h>
98 #include "services.h"
100 #define ENAME_HOSTS "hosts"
101 #define ENAME_SUBNETS "subnets"
102 #define ENAME_ETHERS "ethers"
103 #define ENAME_IPXNETS "ipxnets"
104 #define ENAME_MANUF "manuf"
105 #define ENAME_WKA "wka"
106 #define ENAME_SERVICES "services"
107 #define ENAME_VLANS "vlans"
108 #define ENAME_SS7PCS "ss7pcs"
109 #define ENAME_ENTERPRISES "enterprises"
111 #define HASHETHSIZE 2048
112 #define HASHHOSTSIZE 2048
113 #define HASHIPXNETSIZE 256
114 #define SUBNETLENGTHSIZE 32 /*1-32 inc.*/
116 /* hash table used for IPv4 lookup */
118 #define HASH_IPV4_ADDRESS(addr) (g_htonl(addr) & (HASHHOSTSIZE - 1))
121 typedef struct sub_net_hashipv4 {
122 unsigned addr;
123 /* XXX: No longer needed?*/
124 uint8_t flags; /* B0 dummy_entry, B1 resolve, B2 If the address is used in the trace */
125 struct sub_net_hashipv4 *next;
126 char name[MAXNAMELEN];
127 } sub_net_hashipv4_t;
129 /* Array of entries of subnets of different lengths */
130 typedef struct {
131 size_t mask_length; /*1-32*/
132 uint32_t mask; /* e.g. 255.255.255.*/
133 sub_net_hashipv4_t** subnet_addresses; /* Hash table of subnet addresses */
134 } subnet_length_entry_t;
137 /* hash table used for IPX network lookup */
139 /* XXX - check goodness of hash function */
141 #define HASH_IPX_NET(net) ((net) & (HASHIPXNETSIZE - 1))
143 typedef struct hashipxnet {
144 unsigned addr;
145 struct hashipxnet *next;
146 char name[MAXNAMELEN];
147 } hashipxnet_t;
149 typedef struct hashvlan {
150 unsigned id;
151 /* struct hashvlan *next; */
152 char name[MAXVLANNAMELEN];
153 } hashvlan_t;
155 typedef struct ss7pc {
156 uint32_t id; /* 1st byte NI, 3 following bytes: Point Code */
157 char pc_addr[MAXNAMELEN];
158 char name[MAXNAMELEN];
159 } hashss7pc_t;
161 /* hash tables used for ethernet and manufacturer lookup */
162 struct hashether {
163 uint8_t flags; /* (See above) */
164 uint8_t addr[6];
165 char hexaddr[6*3];
166 char resolved_name[MAXNAMELEN];
169 struct hashwka {
170 uint8_t flags; /* (See above) */
171 char* name;
174 struct hashmanuf {
175 uint8_t flags; /* (See above) */
176 uint8_t addr[3];
177 char hexaddr[3*3];
178 char resolved_name[MAXNAMELEN];
179 char resolved_longname[MAXNAMELEN];
182 /* internal ethernet type */
183 typedef struct _ether
185 uint8_t addr[6];
186 char name[MAXNAMELEN];
187 char longname[MAXNAMELEN];
188 } ether_t;
190 /* internal ipxnet type */
191 typedef struct _ipxnet
193 unsigned addr;
194 char name[MAXNAMELEN];
195 } ipxnet_t;
197 /* internal vlan type */
198 typedef struct _vlan
200 unsigned id;
201 char name[MAXVLANNAMELEN];
202 } vlan_t;
204 /* internal services custom type */
205 typedef struct _serv_port_custom_key {
206 uint16_t port;
207 port_type type;
208 } serv_port_custom_key_t;
210 static wmem_allocator_t *addr_resolv_scope;
212 // Maps unsigned -> hashipxnet_t*
213 static wmem_map_t *ipxnet_hash_table;
214 static wmem_map_t *ipv4_hash_table;
215 static wmem_map_t *ipv6_hash_table;
216 // Maps unsigned -> hashvlan_t*
217 static wmem_map_t *vlan_hash_table;
218 static wmem_map_t *ss7pc_hash_table;
220 // Maps IP address -> manually set hostname.
221 static wmem_map_t *manually_resolved_ipv4_list;
222 static wmem_map_t *manually_resolved_ipv6_list;
224 static addrinfo_lists_t addrinfo_lists;
226 struct cb_serv_data {
227 char *service;
228 port_type proto;
231 // Maps unsigned -> hashmanuf_t*
232 // XXX: Note that hashmanuf_t* only accommodates 24-bit OUIs.
233 // We might want to store vendor names from MA-M and MA-S to
234 // present in the Resolved Addresses dialog.
235 static wmem_map_t *manuf_hashtable;
236 // Maps address -> hashwka_t*
237 static wmem_map_t *wka_hashtable;
238 // Maps address -> hashether_t*
239 static wmem_map_t *eth_hashtable;
240 // Maps unsigned -> serv_port_t*
241 static wmem_map_t *serv_port_hashtable;
242 static wmem_map_t *serv_port_custom_hashtable;
244 // Maps enterprise-id -> enterprise-desc (only used for user additions)
245 static GHashTable *enterprises_hashtable;
247 static subnet_length_entry_t subnet_length_entries[SUBNETLENGTHSIZE]; /* Ordered array of entries */
248 static bool have_subnet_entry;
250 static bool new_resolved_objects;
252 static GPtrArray* extra_hosts_files;
254 static hashether_t *add_eth_name(const uint8_t *addr, const char *name);
255 static void add_serv_port_cb(const uint32_t port, void *ptr);
257 /* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
258 * One-at-a-Time hash
260 unsigned
261 ipv6_oat_hash(const void *key)
263 int len = 16;
264 const unsigned char *p = (const unsigned char *)key;
265 unsigned h = 0;
266 int i;
268 for ( i = 0; i < len; i++ ) {
269 h += p[i];
270 h += ( h << 10 );
271 h ^= ( h >> 6 );
274 h += ( h << 3 );
275 h ^= ( h >> 11 );
276 h += ( h << 15 );
278 return h;
281 gboolean
282 ipv6_equal(const void *v1, const void *v2)
285 if (memcmp(v1, v2, sizeof (ws_in6_addr)) == 0) {
286 return true;
289 return false;
293 * Flag controlling what names to resolve.
295 e_addr_resolve gbl_resolv_flags = {
296 true, /* mac_name */
297 false, /* network_name */
298 false, /* transport_name */
299 true, /* dns_pkt_addr_resolution */
300 false, /* handshake_sni_addr_resolution */
301 true, /* use_external_net_name_resolver */
302 false, /* vlan_name */
303 false, /* ss7 point code names */
304 true, /* maxmind_geoip */
307 /* XXX - ares_init_options(3) says:
308 * "The recommended concurrent query limit is about 32k queries"
310 static unsigned name_resolve_concurrency = 500;
311 static bool resolve_synchronously;
314 * Global variables (can be changed in GUI sections)
315 * XXX - they could be changed in GUI code, but there's currently no
316 * GUI code to change them.
319 char *g_ethers_path; /* global ethers file */
320 char *g_pethers_path; /* personal ethers file */
321 char *g_wka_path; /* global well-known-addresses file */
322 char *g_manuf_path; /* global manuf file */
323 char *g_pmanuf_path; /* personal manuf file */
324 char *g_ipxnets_path; /* global ipxnets file */
325 char *g_pipxnets_path; /* personal ipxnets file */
326 char *g_services_path; /* global services file */
327 char *g_pservices_path; /* personal services file */
328 char *g_pvlan_path; /* personal vlans file */
329 char *g_ss7pcs_path; /* personal ss7pcs file */
330 char *g_enterprises_path; /* global enterprises file */
331 char *g_penterprises_path; /* personal enterprises file */
332 /* first resolving call */
335 * Submitted asynchronous queries trigger a callback (c_ares_ghba_cb()).
336 * Queries are added to c_ares_queue_head. During processing, queries are
337 * popped off the front of c_ares_queue_head and submitted using
338 * ares_gethostbyaddr().
339 * The callback processes the response, then frees the request.
341 typedef struct _async_dns_queue_msg
343 union {
344 uint32_t ip4;
345 ws_in6_addr ip6;
346 } addr;
347 int family;
348 } async_dns_queue_msg_t;
350 typedef struct _async_hostent {
351 int addr_size;
352 int copied;
353 void *addrp;
354 } async_hostent_t;
356 static void
357 c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *he);
360 * Submitted synchronous queries trigger a callback (c_ares_ghba_sync_cb()).
361 * The callback processes the response, sets completed to true if
362 * completed is non-NULL, then frees the request.
364 typedef struct _sync_dns_data
366 union {
367 uint32_t ip4;
368 ws_in6_addr ip6;
369 } addr;
370 int family;
371 bool *completed;
372 } sync_dns_data_t;
374 static ares_channel ghba_chan; /* ares_gethostbyaddr -- Usually non-interactive, no timeout */
375 static ares_channel ghbn_chan; /* ares_gethostbyname -- Usually interactive, timeout */
377 static bool async_dns_initialized;
378 static unsigned async_dns_in_flight;
379 static wmem_list_t *async_dns_queue_head;
380 static GMutex async_dns_queue_mtx;
382 //UAT for providing a list of DNS servers to C-ARES for name resolution
383 bool use_custom_dns_server_list;
384 struct dns_server_data {
385 char *ipaddr;
386 uint32_t udp_port;
387 uint32_t tcp_port;
390 UAT_CSTRING_CB_DEF(dnsserverlist_uats, ipaddr, struct dns_server_data)
391 UAT_DEC_CB_DEF(dnsserverlist_uats, tcp_port, struct dns_server_data)
392 UAT_DEC_CB_DEF(dnsserverlist_uats, udp_port, struct dns_server_data)
394 static uat_t *dnsserver_uat;
395 static struct dns_server_data *dnsserverlist_uats;
396 static unsigned ndnsservers;
398 static void
399 dns_server_free_cb(void *data)
401 struct dns_server_data *h = (struct dns_server_data*)data;
403 g_free(h->ipaddr);
406 static void*
407 dns_server_copy_cb(void *dst_, const void *src_, size_t len _U_)
409 const struct dns_server_data *src = (const struct dns_server_data *)src_;
410 struct dns_server_data *dst = (struct dns_server_data *)dst_;
412 dst->ipaddr = g_strdup(src->ipaddr);
413 dst->udp_port = src->udp_port;
414 dst->tcp_port = src->tcp_port;
416 return dst;
419 static bool
420 dnsserver_uat_fld_ip_chk_cb(void* r _U_, const char* ipaddr, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
422 //Check for a valid IPv4 or IPv6 address.
423 if (ipaddr && g_hostname_is_ip_address(ipaddr)) {
424 *err = NULL;
425 return true;
428 *err = ws_strdup_printf("No valid IP address given.");
429 return false;
432 static bool
433 dnsserver_uat_fld_port_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
435 if (!p || strlen(p) == 0u) {
436 // This should be removed in favor of Decode As. Make it optional.
437 *err = NULL;
438 return true;
441 if (strcmp(p, "53") != 0){
442 uint16_t port;
443 if (!ws_strtou16(p, NULL, &port)) {
444 *err = g_strdup("Invalid port given.");
445 return false;
449 *err = NULL;
450 return true;
453 static void
454 c_ares_ghba_sync_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
455 sync_dns_data_t *sdd = (sync_dns_data_t *)arg;
456 char **p;
458 if (status == ARES_SUCCESS) {
459 for (p = he->h_addr_list; *p != NULL; p++) {
460 switch(sdd->family) {
461 case AF_INET:
462 add_ipv4_name(sdd->addr.ip4, he->h_name, false);
463 break;
464 case AF_INET6:
465 add_ipv6_name(&sdd->addr.ip6, he->h_name, false);
466 break;
467 default:
468 /* Throw an exception? */
469 break;
476 * Let our caller know that this is complete.
478 *sdd->completed = true;
481 * Free the structure for this call.
483 g_free(sdd);
486 static void
487 wait_for_sync_resolv(bool *completed) {
488 int nfds;
489 fd_set rfds, wfds;
490 struct timeval tv;
492 while (!*completed) {
494 * Not yet resolved; wait for something to show up on the
495 * address-to-name C-ARES channel.
497 * To quote the source code for ares_timeout() as of C-ARES
498 * 1.12.0, "WARNING: Beware that this is linear in the number
499 * of outstanding requests! You are probably far better off
500 * just calling ares_process() once per second, rather than
501 * calling ares_timeout() to figure out when to next call
502 * ares_process().", although we should have only one request
503 * outstanding.
504 * As of C-ARES 1.20.0, the ares_timeout() function is now O(1),
505 * but we don't require that minimum version.
506 * https://github.com/c-ares/c-ares/commit/cf99c025cfb3e21295b59923876a31a68ea2cb4b
508 * And, yes, we have to reset it each time, as select(), in
509 * some OSes modifies the timeout to reflect the time remaining
510 * (e.g., Linux) and select() in other OSes doesn't (most if not
511 * all other UN*Xes, Windows?), so we can't rely on *either*
512 * behavior.
514 tv.tv_sec = 1;
515 tv.tv_usec = 0;
517 FD_ZERO(&rfds);
518 FD_ZERO(&wfds);
519 nfds = ares_fds(ghba_chan, &rfds, &wfds);
520 if (nfds > 0) {
521 if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
522 /* If it's interrupted by a signal, no need to put out a message */
523 if (errno != EINTR)
524 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
525 return;
527 ares_process(ghba_chan, &rfds, &wfds);
532 static void
533 process_async_dns_queue(void)
535 wmem_list_frame_t* head;
536 async_dns_queue_msg_t *caqm;
538 if (async_dns_queue_head == NULL)
539 return;
541 if (!g_mutex_trylock(&async_dns_queue_mtx))
542 return;
544 head = wmem_list_head(async_dns_queue_head);
546 while (head != NULL && async_dns_in_flight <= name_resolve_concurrency) {
547 caqm = (async_dns_queue_msg_t *)wmem_list_frame_data(head);
548 wmem_list_remove_frame(async_dns_queue_head, head);
549 if (caqm->family == AF_INET) {
550 ares_gethostbyaddr(ghba_chan, &caqm->addr.ip4, sizeof(uint32_t), AF_INET,
551 c_ares_ghba_cb, caqm);
552 async_dns_in_flight++;
553 } else if (caqm->family == AF_INET6) {
554 ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(ws_in6_addr),
555 AF_INET6, c_ares_ghba_cb, caqm);
556 async_dns_in_flight++;
559 head = wmem_list_head(async_dns_queue_head);
562 g_mutex_unlock(&async_dns_queue_mtx);
565 static void
566 wait_for_async_queue(void)
568 struct timeval tv = { 0, 0 };
569 int nfds;
570 fd_set rfds, wfds;
572 new_resolved_objects = false;
574 if (!async_dns_initialized) {
575 maxmind_db_lookup_process();
576 return;
579 while (1) {
580 /* We're switching to synchronous lookups, so process anything in
581 * the asynchronous queue. There might be more in the queue than
582 * name_resolve_concurrency allows, so check each cycle.
584 process_async_dns_queue();
586 FD_ZERO(&rfds);
587 FD_ZERO(&wfds);
588 nfds = ares_fds(ghba_chan, &rfds, &wfds);
589 if (nfds == 0) {
590 /* No more requests waiting for reply; we're done here. */
591 break;
594 /* See comment in wait_for_sync_resolv() about ares_timeout() being
595 * O(N) in the number of outstanding requests until c-ares 1.20, and
596 * why we might as well just set a 1 second to select().
598 tv.tv_sec = 1;
599 tv.tv_usec = 0;
601 if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
602 /* If it's interrupted by a signal, no need to put out a message */
603 if (errno != EINTR)
604 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
605 return;
607 ares_process(ghba_chan, &rfds, &wfds);
610 maxmind_db_lookup_process();
611 return;
614 static void
615 sync_lookup_ip4(const uint32_t addr)
617 bool completed = false;
618 sync_dns_data_t *sdd;
620 if (!async_dns_initialized) {
622 * c-ares not initialized. Bail out.
624 return;
628 * Start the request.
630 sdd = g_new(sync_dns_data_t, 1);
631 sdd->family = AF_INET;
632 sdd->addr.ip4 = addr;
633 sdd->completed = &completed;
634 ares_gethostbyaddr(ghba_chan, &addr, sizeof(uint32_t), AF_INET,
635 c_ares_ghba_sync_cb, sdd);
638 * Now wait for it to finish.
640 wait_for_sync_resolv(&completed);
643 static void
644 sync_lookup_ip6(const ws_in6_addr *addrp)
646 bool completed = false;
647 sync_dns_data_t *sdd;
649 if (!async_dns_initialized) {
651 * c-ares not initialized. Bail out.
653 return;
657 * Start the request.
659 sdd = g_new(sync_dns_data_t, 1);
660 sdd->family = AF_INET6;
661 memcpy(&sdd->addr.ip6, addrp, sizeof(sdd->addr.ip6));
662 sdd->completed = &completed;
663 ares_gethostbyaddr(ghba_chan, addrp, sizeof(ws_in6_addr), AF_INET6,
664 c_ares_ghba_sync_cb, sdd);
667 * Now wait for it to finish.
669 wait_for_sync_resolv(&completed);
672 void
673 set_resolution_synchrony(bool synchronous)
675 resolve_synchronously = synchronous;
676 maxmind_db_set_synchrony(synchronous);
678 if (synchronous) {
679 wait_for_async_queue();
683 static void
684 c_ares_set_dns_servers(void)
686 if ((!async_dns_initialized) || (!use_custom_dns_server_list))
687 return;
689 if (ndnsservers == 0) {
690 //clear the list of servers. This may effectively disable name resolution
691 ares_set_servers_ports(ghba_chan, NULL);
692 ares_set_servers_ports(ghbn_chan, NULL);
693 } else {
694 struct ares_addr_port_node* servers = wmem_alloc_array(NULL, struct ares_addr_port_node, ndnsservers);
695 ws_in4_addr ipv4addr;
696 ws_in6_addr ipv6addr;
697 bool invalid_IP_found = false;
698 struct ares_addr_port_node* server;
699 unsigned i;
700 for (i = 0, server = servers; i < ndnsservers-1; i++, server++) {
701 if (ws_inet_pton6(dnsserverlist_uats[i].ipaddr, &ipv6addr)) {
702 server->family = AF_INET6;
703 memcpy(&server->addr.addr6, &ipv6addr, 16);
704 } else if (ws_inet_pton4(dnsserverlist_uats[i].ipaddr, &ipv4addr)) {
705 server->family = AF_INET;
706 memcpy(&server->addr.addr4, &ipv4addr, 4);
707 } else {
708 //This shouldn't happen, but just in case...
709 invalid_IP_found = true;
710 server->family = 0;
711 memset(&server->addr.addr4, 0, 4);
712 break;
715 server->udp_port = (int)dnsserverlist_uats[i].udp_port;
716 server->tcp_port = (int)dnsserverlist_uats[i].tcp_port;
718 server->next = (server+1);
720 if (!invalid_IP_found) {
721 if (ws_inet_pton6(dnsserverlist_uats[i].ipaddr, &ipv6addr)) {
722 server->family = AF_INET6;
723 memcpy(&server->addr.addr6, &ipv6addr, 16);
725 else if (ws_inet_pton4(dnsserverlist_uats[i].ipaddr, &ipv4addr)) {
726 server->family = AF_INET;
727 memcpy(&server->addr.addr4, &ipv4addr, 4);
728 } else {
729 //This shouldn't happen, but just in case...
730 server->family = 0;
731 memset(&server->addr.addr4, 0, 4);
734 server->udp_port = (int)dnsserverlist_uats[i].udp_port;
735 server->tcp_port = (int)dnsserverlist_uats[i].tcp_port;
737 server->next = NULL;
739 ares_set_servers_ports(ghba_chan, servers);
740 ares_set_servers_ports(ghbn_chan, servers);
741 wmem_free(NULL, servers);
745 typedef struct {
746 uint32_t mask;
747 size_t mask_length;
748 const char* name; /* Shallow copy */
749 } subnet_entry_t;
751 /* Maximum supported line length of hosts, services, manuf, etc. */
752 #define MAX_LINELEN 1024
754 /** Read a line without trailing (CR)LF. Returns -1 on failure. */
755 static int
756 fgetline(char *buf, int size, FILE *fp)
758 if (fgets(buf, size, fp)) {
759 int len = (int)strcspn(buf, "\r\n");
760 buf[len] = '\0';
761 return len;
763 return -1;
765 } /* fgetline */
769 * Local function definitions
771 static subnet_entry_t subnet_lookup(const uint32_t addr);
772 static void subnet_entry_set(uint32_t subnet_addr, const uint8_t mask_length, const char* name);
774 static unsigned serv_port_custom_hash(const void *k)
776 const serv_port_custom_key_t *key = (const serv_port_custom_key_t*)k;
777 return key->port + (key->type << 16);
780 static gboolean serv_port_custom_equal(const void *k1, const void *k2)
782 const serv_port_custom_key_t *key1 = (const serv_port_custom_key_t*)k1;
783 const serv_port_custom_key_t *key2 = (const serv_port_custom_key_t*)k2;
785 return (key1->port == key2->port) && (key1->type == key2->type);
788 static void
789 add_custom_service_name(port_type proto, const unsigned port, const char *service_name)
791 char *name;
792 serv_port_custom_key_t *key, *orig_key;
794 key = wmem_new(addr_resolv_scope, serv_port_custom_key_t);
795 key->port = (uint16_t)port;
796 key->type = proto;
798 if (wmem_map_lookup_extended(serv_port_custom_hashtable, key, (const void**)&orig_key, (void**)&name)) {
799 wmem_free(addr_resolv_scope, orig_key);
800 wmem_free(addr_resolv_scope, name);
803 name = wmem_strdup(addr_resolv_scope, service_name);
804 wmem_map_insert(serv_port_custom_hashtable, key, name);
806 // A new custom entry is not a new resolved object.
807 // new_resolved_objects = true;
810 static serv_port_t*
811 add_service_name(port_type proto, const unsigned port, const char *service_name)
813 serv_port_t *serv_port_names;
815 serv_port_names = (serv_port_t *)wmem_map_lookup(serv_port_hashtable, GUINT_TO_POINTER(port));
816 if (serv_port_names == NULL) {
817 serv_port_names = wmem_new0(addr_resolv_scope, serv_port_t);
818 wmem_map_insert(serv_port_hashtable, GUINT_TO_POINTER(port), serv_port_names);
821 /* We don't need to strdup because service_name is owned by either
822 * the global arrays or the custom table, which manage the memory
823 * and have lifespans at least as long as the addr_resolv_scope.
825 switch(proto) {
826 case PT_TCP:
827 serv_port_names->tcp_name = service_name;
828 break;
829 case PT_UDP:
830 serv_port_names->udp_name = service_name;
831 break;
832 case PT_SCTP:
833 serv_port_names->sctp_name = service_name;
834 break;
835 case PT_DCCP:
836 serv_port_names->dccp_name = service_name;
837 break;
838 default:
839 return serv_port_names;
840 /* Should not happen */
843 new_resolved_objects = true;
844 return serv_port_names;
847 static void
848 parse_service_line (char *line)
850 char *cp;
851 char *service;
852 char *port;
853 port_type proto;
854 struct cb_serv_data cb_data;
855 range_t *port_rng = NULL;
857 if ((cp = strchr(line, '#')))
858 *cp = '\0';
860 if ((cp = strtok(line, " \t")) == NULL)
861 return;
863 service = cp;
865 if ((cp = strtok(NULL, " \t")) == NULL)
866 return;
868 port = cp;
870 if (strtok(cp, "/") == NULL)
871 return;
873 if (range_convert_str(NULL, &port_rng, port, UINT16_MAX) != CVT_NO_ERROR) {
874 wmem_free (NULL, port_rng);
875 return;
878 while ((cp = strtok(NULL, "/")) != NULL) {
879 if (strcmp(cp, "tcp") == 0) {
880 proto = PT_TCP;
882 else if (strcmp(cp, "udp") == 0) {
883 proto = PT_UDP;
885 else if (strcmp(cp, "sctp") == 0) {
886 proto = PT_SCTP;
888 else if (strcmp(cp, "dccp") == 0) {
889 proto = PT_DCCP;
891 else {
892 break;
894 cb_data.service = service;
895 cb_data.proto = proto;
896 range_foreach(port_rng, add_serv_port_cb, &cb_data);
899 wmem_free (NULL, port_rng);
900 } /* parse_service_line */
903 static void
904 add_serv_port_cb(const uint32_t port, void *ptr)
906 struct cb_serv_data *cb_data = (struct cb_serv_data *)ptr;
908 if ( port ) {
909 add_custom_service_name(cb_data->proto, port, cb_data->service);
914 static bool
915 parse_services_file(const char * path)
917 FILE *serv_p;
918 char buf[MAX_LINELEN];
920 /* services hash table initialization */
921 serv_p = ws_fopen(path, "r");
923 if (serv_p == NULL)
924 return false;
926 while (fgetline(buf, sizeof(buf), serv_p) >= 0) {
927 parse_service_line(buf);
930 fclose(serv_p);
931 return true;
934 /* -----------------
935 * unsigned integer to ascii
937 static char *
938 wmem_utoa(wmem_allocator_t *allocator, unsigned port)
940 char *bp = (char *)wmem_alloc(allocator, MAXNAMELEN);
942 /* XXX, uint32_to_str() ? */
943 uint32_to_str_buf(port, bp, MAXNAMELEN);
944 return bp;
947 static const char *
948 _serv_name_lookup(port_type proto, unsigned port, serv_port_t **value_ret)
950 serv_port_t *serv_port_names;
951 const char* name = NULL;
952 ws_services_proto_t p;
953 ws_services_entry_t const *serv;
955 /* Look in the cache */
956 serv_port_names = (serv_port_t *)wmem_map_lookup(serv_port_hashtable, GUINT_TO_POINTER(port));
958 if (serv_port_names == NULL) {
959 /* Try the user custom table */
960 serv_port_custom_key_t custom_key = { (uint16_t)port, proto };
961 name = wmem_map_lookup(serv_port_custom_hashtable, &custom_key);
964 if (name == NULL) {
965 /* now look in the global tables */
966 bool valid_proto = true;
967 switch(proto) {
968 case PT_TCP: p = ws_tcp; break;
969 case PT_UDP: p = ws_udp; break;
970 case PT_SCTP: p = ws_sctp; break;
971 case PT_DCCP: p = ws_dccp; break;
972 default: valid_proto = false;
974 if (valid_proto) {
975 serv = global_services_lookup(port, p);
976 if (serv) {
977 name = serv->name;
982 if (name) {
983 /* Cache result */
984 serv_port_names = add_service_name(proto, port, name);
987 if (value_ret != NULL)
988 *value_ret = serv_port_names;
990 if (serv_port_names == NULL)
991 return NULL;
993 switch (proto) {
994 case PT_UDP:
995 return serv_port_names->udp_name;
996 case PT_TCP:
997 return serv_port_names->tcp_name;
998 case PT_SCTP:
999 return serv_port_names->sctp_name;
1000 case PT_DCCP:
1001 return serv_port_names->dccp_name;
1002 default:
1003 break;
1005 return NULL;
1008 const char *
1009 try_serv_name_lookup(port_type proto, unsigned port)
1011 return (proto == PT_NONE) ? NULL : _serv_name_lookup(proto, port, NULL);
1014 const char *
1015 serv_name_lookup(port_type proto, unsigned port)
1017 serv_port_t *serv_port_names = NULL;
1018 const char *name;
1020 /* first look for the name */
1021 name = _serv_name_lookup(proto, port, &serv_port_names);
1022 if (name != NULL)
1023 return name;
1025 if (serv_port_names == NULL) {
1026 serv_port_names = wmem_new0(addr_resolv_scope, serv_port_t);
1027 wmem_map_insert(serv_port_hashtable, GUINT_TO_POINTER(port), serv_port_names);
1030 /* No name; create the numeric string. */
1031 if (serv_port_names->numeric == NULL) {
1032 serv_port_names->numeric = wmem_strdup_printf(addr_resolv_scope, "%u", port);
1035 return serv_port_names->numeric;
1038 static void
1039 initialize_services(void)
1041 ws_assert(serv_port_hashtable == NULL);
1042 serv_port_hashtable = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
1043 ws_assert(serv_port_custom_hashtable == NULL);
1044 serv_port_custom_hashtable = wmem_map_new(addr_resolv_scope, serv_port_custom_hash, serv_port_custom_equal);
1046 /* Compute the pathname of the global services file. */
1047 if (g_services_path == NULL) {
1048 g_services_path = get_datafile_path(ENAME_SERVICES);
1050 parse_services_file(g_services_path);
1052 /* Compute the pathname of the personal services file */
1053 if (g_pservices_path == NULL) {
1054 /* Check profile directory before personal configuration */
1055 g_pservices_path = get_persconffile_path(ENAME_SERVICES, true);
1056 if (!parse_services_file(g_pservices_path)) {
1057 g_free(g_pservices_path);
1058 g_pservices_path = get_persconffile_path(ENAME_SERVICES, false);
1059 parse_services_file(g_pservices_path);
1064 static void
1065 service_name_lookup_cleanup(void)
1067 serv_port_hashtable = NULL;
1068 serv_port_custom_hashtable = NULL;
1069 g_free(g_services_path);
1070 g_services_path = NULL;
1071 g_free(g_pservices_path);
1072 g_pservices_path = NULL;
1075 static void
1076 parse_enterprises_line (char *line)
1078 char *tok, *dec_str, *org_str;
1079 uint32_t dec;
1080 bool had_comment = false;
1082 /* Stop the line at any comment found */
1083 if ((tok = strchr(line, '#'))) {
1084 *tok = '\0';
1085 had_comment = true;
1087 /* Get enterprise number */
1088 dec_str = strtok(line, " \t");
1089 if (!dec_str)
1090 return;
1091 /* Get enterprise name */
1092 org_str = strtok(NULL, ""); /* everything else */
1093 if (org_str && had_comment) {
1094 /* Only need to strip after (between name and where comment was) */
1095 org_str = g_strchomp(org_str);
1097 if (!org_str)
1098 return;
1100 /* Add entry using number as key */
1101 if (!ws_strtou32(dec_str, NULL, &dec))
1102 return;
1103 g_hash_table_insert(enterprises_hashtable, GUINT_TO_POINTER(dec), g_strdup(org_str));
1107 static bool
1108 parse_enterprises_file(const char * path)
1110 FILE *fp;
1111 char buf[MAX_LINELEN];
1113 fp = ws_fopen(path, "r");
1114 if (fp == NULL)
1115 return false;
1117 while (fgetline(buf, sizeof(buf), fp) >= 0) {
1118 parse_enterprises_line(buf);
1121 fclose(fp);
1122 return true;
1125 static void
1126 initialize_enterprises(void)
1128 ws_assert(enterprises_hashtable == NULL);
1129 enterprises_hashtable = g_hash_table_new_full(NULL, NULL, NULL, g_free);
1131 if (g_enterprises_path == NULL) {
1132 g_enterprises_path = get_datafile_path(ENAME_ENTERPRISES);
1134 parse_enterprises_file(g_enterprises_path);
1136 /* Populate entries from profile or personal */
1137 if (g_penterprises_path == NULL) {
1138 /* Check profile directory before personal configuration */
1139 g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES, true);
1140 if (!file_exists(g_penterprises_path)) {
1141 g_free(g_penterprises_path);
1142 g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES, false);
1145 /* Parse personal file (if present) */
1146 parse_enterprises_file(g_penterprises_path);
1149 const char *
1150 try_enterprises_lookup(uint32_t value)
1152 /* Trying extra entries first. N.B. This does allow entries to be overwritten and found.. */
1153 const char *name = (const char *)g_hash_table_lookup(enterprises_hashtable, GUINT_TO_POINTER(value));
1154 if (name) {
1155 return name;
1157 else {
1158 return global_enterprises_lookup(value);
1162 const char *
1163 enterprises_lookup(uint32_t value, const char *unknown_str)
1165 const char *s;
1167 s = try_enterprises_lookup(value);
1168 if (s != NULL)
1169 return s;
1170 if (unknown_str != NULL)
1171 return unknown_str;
1172 return "<Unknown>";
1175 void
1176 enterprises_base_custom(char *buf, uint32_t value)
1178 const char *s;
1180 if ((s = try_enterprises_lookup(value)) == NULL)
1181 s = ITEM_LABEL_UNKNOWN_STR;
1182 snprintf(buf, ITEM_LABEL_LENGTH, "%s (%u)", s, value);
1185 static void
1186 enterprises_cleanup(void)
1188 ws_assert(enterprises_hashtable);
1189 g_hash_table_destroy(enterprises_hashtable);
1190 enterprises_hashtable = NULL;
1191 g_free(g_enterprises_path);
1192 g_enterprises_path = NULL;
1193 g_free(g_penterprises_path);
1194 g_penterprises_path = NULL;
1197 /* Fill in an IP4 structure with info from subnets file or just with the
1198 * string form of the address.
1200 bool
1201 fill_dummy_ip4(const unsigned addr, hashipv4_t* volatile tp)
1203 subnet_entry_t subnet_entry;
1205 /* return value : true if addr matches any subnet */
1206 bool cidr_covered = false;
1208 /* Overwrite if we get async DNS reply */
1210 /* Do we have a subnet for this address? */
1211 subnet_entry = subnet_lookup(addr);
1212 if (0 != subnet_entry.mask) {
1213 /* Print name, then '.' then IP address after subnet mask */
1214 uint32_t host_addr;
1215 char buffer[WS_INET_ADDRSTRLEN];
1216 char* paddr;
1217 size_t i;
1219 host_addr = addr & (~subnet_entry.mask);
1220 ip_addr_to_str_buf(&host_addr, buffer, WS_INET_ADDRSTRLEN);
1221 paddr = buffer;
1223 /* Skip to first octet that is not totally masked
1224 * If length of mask is 32, we chomp the whole address.
1225 * If the address string starts '.' (should not happen?),
1226 * we skip that '.'.
1228 i = subnet_entry.mask_length / 8;
1229 while(*(paddr) != '\0' && i > 0) {
1230 if (*(++paddr) == '.') {
1231 --i;
1235 /* There are more efficient ways to do this, but this is safe if we
1236 * trust snprintf and MAXDNSNAMELEN
1238 snprintf(tp->name, MAXDNSNAMELEN, "%s%s", subnet_entry.name, paddr);
1240 /* Evaluate the subnet in CIDR notation
1241 * Reuse buffers built above
1243 uint32_t subnet_addr;
1244 subnet_addr = addr & subnet_entry.mask;
1246 char buffer_subnet[WS_INET_ADDRSTRLEN];
1247 ip_addr_to_str_buf(&subnet_addr, buffer_subnet, WS_INET_ADDRSTRLEN);
1249 char buffer_cidr[WS_INET_CIDRADDRSTRLEN];
1250 snprintf(buffer_cidr, WS_INET_CIDRADDRSTRLEN, "%s%s%u", buffer_subnet, "/", (unsigned)subnet_entry.mask_length);
1252 snprintf(tp->cidr_addr, WS_INET_CIDRADDRSTRLEN, "%s%s%u", buffer_subnet, "/", (unsigned)subnet_entry.mask_length);
1253 cidr_covered = true;
1254 } else {
1255 /* XXX: This means we end up printing "1.2.3.4 (1.2.3.4)" in many cases */
1256 ip_addr_to_str_buf(&addr, tp->name, MAXDNSNAMELEN);
1258 /* IP does not belong to any known subnet, just indicate this IP without "/.32" */
1259 ip_addr_to_str_buf(&addr, tp->cidr_addr, MAXDNSNAMELEN);
1261 return cidr_covered;
1265 /* Fill in an IP6 structure with the string form of the address.
1267 static void
1268 fill_dummy_ip6(hashipv6_t* volatile tp)
1270 /* Overwrite if we get async DNS reply */
1271 (void) g_strlcpy(tp->name, tp->ip6, MAXDNSNAMELEN);
1274 static void
1275 c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
1276 async_dns_queue_msg_t *caqm = (async_dns_queue_msg_t *)arg;
1277 char **p;
1279 if (!caqm) return;
1280 /* XXX, what to do if async_dns_in_flight == 0? */
1281 async_dns_in_flight--;
1283 if (status == ARES_SUCCESS) {
1284 for (p = he->h_addr_list; *p != NULL; p++) {
1285 switch(caqm->family) {
1286 case AF_INET:
1287 add_ipv4_name(caqm->addr.ip4, he->h_name, false);
1288 break;
1289 case AF_INET6:
1290 add_ipv6_name(&caqm->addr.ip6, he->h_name, false);
1291 break;
1292 default:
1293 /* Throw an exception? */
1294 break;
1298 wmem_free(addr_resolv_scope, caqm);
1301 /* --------------- */
1302 hashipv4_t *
1303 new_ipv4(const unsigned addr)
1305 hashipv4_t *tp = wmem_new(addr_resolv_scope, hashipv4_t);
1306 tp->addr = addr;
1307 tp->flags = 0;
1308 tp->name[0] = '\0';
1309 ip_addr_to_str_buf(&addr, tp->ip, sizeof(tp->ip));
1310 return tp;
1313 static hashipv4_t *
1314 host_lookup(const unsigned addr)
1316 hashipv4_t * volatile tp;
1318 tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
1319 if (tp == NULL) {
1321 * We don't already have an entry for this host name; create one,
1322 * and then try to resolve it.
1324 tp = new_ipv4(addr);
1325 fill_dummy_ip4(addr, tp);
1326 wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
1327 } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
1328 return tp;
1332 * This hasn't been resolved yet, and we haven't tried to
1333 * resolve it already.
1336 if (!gbl_resolv_flags.network_name)
1337 return tp;
1339 if (gbl_resolv_flags.use_external_net_name_resolver) {
1340 tp->flags |= TRIED_RESOLVE_ADDRESS;
1342 if (async_dns_initialized) {
1343 /* c-ares is initialized, so we can use it */
1344 if (resolve_synchronously || name_resolve_concurrency == 0) {
1346 * Either all names are to be resolved synchronously or
1347 * the concurrencly level is 0; do the resolution
1348 * synchronously.
1350 sync_lookup_ip4(addr);
1351 } else {
1353 * Names are to be resolved asynchronously, and we
1354 * allow at least one asynchronous request in flight;
1355 * post an asynchronous request.
1357 async_dns_queue_msg_t *caqm;
1359 caqm = wmem_new(addr_resolv_scope, async_dns_queue_msg_t);
1360 caqm->family = AF_INET;
1361 caqm->addr.ip4 = addr;
1362 wmem_list_append(async_dns_queue_head, (void *) caqm);
1367 return tp;
1369 } /* host_lookup */
1371 /* --------------- */
1372 static hashipv6_t *
1373 new_ipv6(const ws_in6_addr *addr)
1375 hashipv6_t *tp = wmem_new(addr_resolv_scope, hashipv6_t);
1376 memcpy(tp->addr, addr->bytes, sizeof tp->addr);
1377 tp->flags = 0;
1378 tp->name[0] = '\0';
1379 ip6_to_str_buf(addr, tp->ip6, sizeof(tp->ip6));
1380 return tp;
1383 /* ------------------------------------ */
1384 static hashipv6_t *
1385 host_lookup6(const ws_in6_addr *addr)
1387 hashipv6_t * volatile tp;
1389 tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addr);
1390 if (tp == NULL) {
1392 * We don't already have an entry for this host name; create one,
1393 * and then try to resolve it.
1395 ws_in6_addr *addr_key;
1397 addr_key = wmem_new(addr_resolv_scope, ws_in6_addr);
1398 tp = new_ipv6(addr);
1399 memcpy(addr_key, addr, 16);
1400 fill_dummy_ip6(tp);
1401 wmem_map_insert(ipv6_hash_table, addr_key, tp);
1402 } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
1403 return tp;
1407 * This hasn't been resolved yet, and we haven't tried to
1408 * resolve it already.
1411 if (!gbl_resolv_flags.network_name)
1412 return tp;
1414 if (gbl_resolv_flags.use_external_net_name_resolver) {
1415 tp->flags |= TRIED_RESOLVE_ADDRESS;
1417 if (async_dns_initialized) {
1418 /* c-ares is initialized, so we can use it */
1419 if (resolve_synchronously || name_resolve_concurrency == 0) {
1421 * Either all names are to be resolved synchronously or
1422 * the concurrencly level is 0; do the resolution
1423 * synchronously.
1425 sync_lookup_ip6(addr);
1426 } else {
1428 * Names are to be resolved asynchronously, and we
1429 * allow at least one asynchronous request in flight;
1430 * post an asynchronous request.
1432 async_dns_queue_msg_t *caqm;
1434 caqm = wmem_new(addr_resolv_scope, async_dns_queue_msg_t);
1435 caqm->family = AF_INET6;
1436 memcpy(&caqm->addr.ip6, addr, sizeof(caqm->addr.ip6));
1437 wmem_list_append(async_dns_queue_head, (void *) caqm);
1442 return tp;
1444 } /* host_lookup6 */
1447 * Ethernet / manufacturer resolution
1449 * The following functions implement ethernet address resolution and
1450 * ethers files parsing (see ethers(4)).
1452 * The manuf file has the same format as ethers(4) except that names are
1453 * truncated to MAXMANUFLEN-1 (8) characters and that an address contains
1454 * only 3 bytes (instead of 6).
1456 * Notes:
1458 * I decide to not use the existing functions (see ethers(3) on some
1459 * operating systems) for the following reasons:
1460 * - performance gains (use of hash tables and some other enhancements),
1461 * - use of two ethers files (system-wide and per user),
1462 * - avoid the use of NIS maps,
1463 * - lack of these functions on some systems.
1465 * So the following functions do _not_ behave as the standard ones.
1467 * -- Laurent.
1471 * Converts Ethernet addresses of the form aa:bb:cc or aa:bb:cc:dd:ee:ff/28.
1472 * '-' is also supported as a separator. The
1473 * octets must be exactly two hexadecimal characters and the mask must be either
1474 * 28 or 36. Pre-condition: cp MUST be at least 21 bytes.
1476 static bool
1477 parse_ether_address_fast(const unsigned char *cp, ether_t *eth, unsigned int *mask,
1478 const bool accept_mask)
1480 /* XXX copied from strutil.c */
1481 /* a map from ASCII hex chars to their value */
1482 static const int8_t str_to_nibble[256] = {
1483 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1484 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1485 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1486 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
1487 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1488 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1489 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1490 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1491 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1492 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1493 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1494 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1495 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1496 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1497 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1498 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1500 const uint8_t *str_to_nibble_usg = (const uint8_t *)str_to_nibble;
1502 unsigned char sep = cp[2];
1503 if ((sep != ':' && sep != '-') || cp[5] != sep) {
1504 /* Unexpected separators. */
1505 return false;
1508 /* N.B. store octet values in an int to detect invalid (-1) entries */
1509 int num0 = (str_to_nibble_usg[cp[0]] << 4) | (int8_t)str_to_nibble_usg[cp[1]];
1510 int num1 = (str_to_nibble_usg[cp[3]] << 4) | (int8_t)str_to_nibble_usg[cp[4]];
1511 int num2 = (str_to_nibble_usg[cp[6]] << 4) | (int8_t)str_to_nibble_usg[cp[7]];
1513 if ((num0 | num1 | num2) & 0x100) {
1514 /* Not hexadecimal numbers. */
1515 return false;
1518 eth->addr[0] = (uint8_t)num0;
1519 eth->addr[1] = (uint8_t)num1;
1520 eth->addr[2] = (uint8_t)num2;
1522 if (cp[8] == '\0' && accept_mask) {
1523 /* Indicate that this is a manufacturer ID (0 is not allowed as a mask). */
1524 *mask = 0;
1525 return true;
1526 } else if (cp[8] != sep || !accept_mask) {
1527 /* Format not handled by this fast path. */
1528 return false;
1531 /* N.B. store octet values in an int to detect invalid (-1) entries */
1532 int num3 = (str_to_nibble_usg[cp[9]] << 4) | (int8_t)str_to_nibble_usg[cp[10]];
1533 int num4 = (str_to_nibble_usg[cp[12]] << 4) | (int8_t)str_to_nibble_usg[cp[13]];
1534 int num5 = (str_to_nibble_usg[cp[15]] << 4) | (int8_t)str_to_nibble_usg[cp[16]];
1536 if (((num3 | num4 | num5) & 0x100) || cp[11] != sep || cp[14] != sep) {
1537 /* Not hexadecimal numbers or invalid separators. */
1538 return false;
1541 eth->addr[3] = (uint8_t)num3;
1542 eth->addr[4] = (uint8_t)num4;
1543 eth->addr[5] = (uint8_t)num5;
1544 if (cp[17] == '\0') {
1545 /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1546 *mask = 48;
1547 return true;
1548 } else if (cp[17] != '/' || cp[20] != '\0') {
1549 /* Format not handled by this fast path. */
1550 return false;
1553 int m1 = cp[18];
1554 int m2 = cp[19];
1555 if (m1 == '3' && m2 == '6') { /* Mask /36 */
1556 eth->addr[4] &= 0xf0;
1557 eth->addr[5] = 0;
1558 *mask = 36;
1559 return true;
1561 if (m1 == '2' && m2 == '8') { /* Mask /28 */
1562 eth->addr[3] &= 0xf0;
1563 eth->addr[4] = 0;
1564 eth->addr[5] = 0;
1565 *mask = 28;
1566 return true;
1568 /* Unsupported mask */
1569 return false;
1573 * If "accept_mask" is false, cp must point to an address that consists
1574 * of exactly 6 bytes.
1575 * If "accept_mask" is true, parse an up-to-6-byte sequence with an optional
1576 * mask.
1578 static bool
1579 parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
1580 const bool accept_mask)
1582 int i;
1583 unsigned long num;
1584 char *p;
1585 char sep = '\0';
1587 for (i = 0; i < 6; i++) {
1588 /* Get a hex number, 1 or 2 digits, no sign characters allowed. */
1589 if (!g_ascii_isxdigit(*cp))
1590 return false;
1591 num = strtoul(cp, &p, 16);
1592 if (p == cp)
1593 return false; /* failed */
1594 if (num > 0xFF)
1595 return false; /* not a valid octet */
1596 eth->addr[i] = (uint8_t) num;
1597 cp = p; /* skip past the number */
1599 /* OK, what character terminated the octet? */
1600 if (*cp == '/') {
1601 /* "/" - this has a mask. */
1602 if (!accept_mask) {
1603 /* Entries with masks are not allowed in this file. */
1604 return false;
1606 cp++; /* skip past the '/' to get to the mask */
1607 if (!g_ascii_isdigit(*cp))
1608 return false; /* no sign allowed */
1609 num = strtoul(cp, &p, 10);
1610 if (p == cp)
1611 return false; /* failed */
1612 cp = p; /* skip past the number */
1613 if (*cp != '\0' && !g_ascii_isspace(*cp))
1614 return false; /* bogus terminator */
1615 if (num == 0 || num >= 48)
1616 return false; /* bogus mask */
1617 /* Mask out the bits not covered by the mask */
1618 *mask = (int)num;
1619 for (i = 0; num >= 8; i++, num -= 8)
1620 ; /* skip octets entirely covered by the mask */
1621 /* Mask out the first masked octet */
1622 eth->addr[i] &= (0xFF << (8 - num));
1623 i++;
1624 /* Mask out completely-masked-out octets */
1625 for (; i < 6; i++)
1626 eth->addr[i] = 0;
1627 return true;
1629 if (*cp == '\0') {
1630 /* We're at the end of the address, and there's no mask. */
1631 if (i == 2) {
1632 /* We got 3 bytes, so this is a manufacturer ID. */
1633 if (!accept_mask) {
1634 /* Manufacturer IDs are not allowed in this file */
1635 return false;
1637 /* Indicate that this is a manufacturer ID (0 is not allowed
1638 as a mask). */
1639 *mask = 0;
1640 return true;
1643 if (i == 5) {
1644 /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1645 if (accept_mask)
1646 *mask = 48;
1647 return true;
1650 /* We didn't get 3 or 6 bytes, and there's no mask; this is
1651 illegal. */
1652 return false;
1653 } else {
1654 if (sep == '\0') {
1655 /* We don't know the separator used in this number; it can either
1656 be ':', '-', or '.'. */
1657 if (*cp != ':' && *cp != '-' && *cp != '.')
1658 return false;
1659 sep = *cp; /* subsequent separators must be the same */
1660 } else {
1661 /* It has to be the same as the first separator */
1662 if (*cp != sep)
1663 return false;
1666 cp++;
1669 return true;
1672 static int
1673 parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
1674 const bool accept_mask)
1677 * See the ethers(4) or ethers(5) man page for ethers file format
1678 * (not available on all systems).
1679 * We allow both ethernet address separators (':' and '-'),
1680 * as well as Wireshark's '.' separator.
1683 char *cp;
1685 line = g_strstrip(line);
1686 if (line[0] == '\0' || line[0] == '#')
1687 return -1;
1689 if ((cp = strchr(line, '#'))) {
1690 *cp = '\0';
1691 g_strchomp(line);
1694 if ((cp = strtok(line, " \t")) == NULL)
1695 return -1;
1697 /* First try to match the common format for the large ethers file. */
1698 if (!parse_ether_address_fast(cp, eth, mask, accept_mask)) {
1699 /* Fallback for the well-known addresses (wka) file. */
1700 if (!parse_ether_address(cp, eth, mask, accept_mask))
1701 return -1;
1704 if ((cp = strtok(NULL, " \t")) == NULL)
1705 return -1;
1707 (void) g_strlcpy(eth->name, cp, MAXNAMELEN);
1709 if ((cp = strtok(NULL, "\t")) != NULL)
1711 (void) g_strlcpy(eth->longname, cp, MAXNAMELEN);
1712 } else {
1713 /* Make the long name the short name */
1714 (void) g_strlcpy(eth->longname, eth->name, MAXNAMELEN);
1717 return 0;
1719 } /* parse_ether_line */
1721 static FILE *eth_p;
1723 static void
1724 set_ethent(char *path)
1726 if (eth_p)
1727 rewind(eth_p);
1728 else
1729 eth_p = ws_fopen(path, "r");
1732 static void
1733 end_ethent(void)
1735 if (eth_p) {
1736 fclose(eth_p);
1737 eth_p = NULL;
1741 static ether_t *
1742 get_ethent(unsigned int *mask, const bool accept_mask)
1745 static ether_t eth;
1746 char buf[MAX_LINELEN];
1748 if (eth_p == NULL)
1749 return NULL;
1751 while (fgetline(buf, sizeof(buf), eth_p) >= 0) {
1752 if (parse_ether_line(buf, &eth, mask, accept_mask) == 0) {
1753 return &eth;
1757 return NULL;
1759 } /* get_ethent */
1761 static ether_t *
1762 get_ethbyaddr(const uint8_t *addr)
1765 ether_t *eth;
1767 set_ethent(g_pethers_path);
1769 while (((eth = get_ethent(NULL, false)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
1772 if (eth == NULL) {
1773 end_ethent();
1775 set_ethent(g_ethers_path);
1777 while (((eth = get_ethent(NULL, false)) != NULL) && memcmp(addr, eth->addr, 6) != 0)
1780 end_ethent();
1783 return eth;
1785 } /* get_ethbyaddr */
1787 static hashmanuf_t *
1788 manuf_hash_new_entry(const uint8_t *addr, const char* name, const char* longname)
1790 unsigned manuf_key;
1791 hashmanuf_t *manuf_value;
1792 char *endp;
1794 /* manuf needs only the 3 most significant octets of the ethernet address */
1795 manuf_key = (addr[0] << 16) + (addr[1] << 8) + addr[2];
1796 manuf_value = wmem_new(addr_resolv_scope, hashmanuf_t);
1798 memcpy(manuf_value->addr, addr, 3);
1799 if (name != NULL) {
1800 (void) g_strlcpy(manuf_value->resolved_name, name, MAXNAMELEN);
1801 manuf_value->flags = NAME_RESOLVED;
1802 if (longname != NULL) {
1803 (void) g_strlcpy(manuf_value->resolved_longname, longname, MAXNAMELEN);
1805 else {
1806 (void) g_strlcpy(manuf_value->resolved_longname, name, MAXNAMELEN);
1809 else {
1810 manuf_value->flags = 0;
1811 manuf_value->resolved_name[0] = '\0';
1812 manuf_value->resolved_longname[0] = '\0';
1814 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
1815 endp = bytes_to_hexstr_punct(manuf_value->hexaddr, addr, sizeof(manuf_value->addr), ':');
1816 *endp = '\0';
1818 wmem_map_insert(manuf_hashtable, GUINT_TO_POINTER(manuf_key), manuf_value);
1819 return manuf_value;
1822 static hashwka_t*
1823 wka_hash_new_entry(const uint8_t *addr, char* name)
1825 uint8_t *wka_key;
1826 hashwka_t *wka_value;
1828 wka_key = (uint8_t *)wmem_alloc(addr_resolv_scope, 6);
1829 memcpy(wka_key, addr, 6);
1831 wka_value = (hashwka_t*)wmem_new(addr_resolv_scope, hashwka_t);
1832 wka_value->flags = NAME_RESOLVED;
1833 wka_value->name = wmem_strdup(addr_resolv_scope, name);
1835 wmem_map_insert(wka_hashtable, wka_key, wka_value);
1836 return wka_value;
1839 static void
1840 add_manuf_name(const uint8_t *addr, unsigned int mask, char *name, char *longname)
1842 switch (mask)
1844 case 0:
1846 /* This is a manufacturer ID; add it to the manufacturer ID hash table */
1847 hashmanuf_t *entry = manuf_hash_new_entry(addr, name, longname);
1848 entry->flags |= STATIC_HOSTNAME;
1849 break;
1851 case 48:
1853 /* This is a well-known MAC address; add it to the Ethernet hash table */
1854 hashether_t *entry = add_eth_name(addr, name);
1855 entry->flags |= STATIC_HOSTNAME;
1856 break;
1858 default:
1860 /* This is a range of well-known addresses; add it to the well-known-address table */
1861 hashwka_t *entry = wka_hash_new_entry(addr, name);
1862 entry->flags |= STATIC_HOSTNAME;
1863 break;
1866 } /* add_manuf_name */
1868 /* XXX: manuf_name_lookup returns a hashmanuf_t*, which cannot hold a 28 or
1869 * 36 bit MA-M or MA-S. So it returns those as unresolved. For EUI-48 and
1870 * EUI-64, MA-M and MA-S should be checked for separately in the global
1871 * tables.
1873 * XXX - size_t is used only in a ws_return_val_if() that checks
1874 * whether the argument has at least 3 bytes; that's done only if
1875 * assertions are enabled, so it's used only if assertions are
1876 * enabled. This means that, if assertions aren't enabled, a
1877 * warning that the argument is unused will be issued by at least
1878 * some compilers, so we mark it as unused. Should we do that
1879 * check unconditionally, and just emit a warning if assertions
1880 * are enabled?
1882 static hashmanuf_t *
1883 manuf_name_lookup(const uint8_t *addr, size_t size _U_)
1885 uint32_t manuf_key;
1886 uint8_t oct;
1887 hashmanuf_t *manuf_value;
1889 ws_return_val_if(size < 3, NULL);
1891 /* manuf needs only the 3 most significant octets of the ethernet address */
1892 manuf_key = addr[0];
1893 manuf_key = manuf_key<<8;
1894 oct = addr[1];
1895 manuf_key = manuf_key | oct;
1896 manuf_key = manuf_key<<8;
1897 oct = addr[2];
1898 manuf_key = manuf_key | oct;
1901 /* first try to find a "perfect match" */
1902 manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, GUINT_TO_POINTER(manuf_key));
1903 if (manuf_value != NULL) {
1904 manuf_value->flags |= TRIED_RESOLVE_ADDRESS;
1905 return manuf_value;
1908 /* Mask out the broadcast/multicast flag but not the locally
1909 * administered flag as locally administered means: not assigned
1910 * by the IEEE but the local administrator instead.
1911 * 0x01 multicast / broadcast bit
1912 * 0x02 locally administered bit */
1913 if ((manuf_key & 0x00010000) != 0) {
1914 manuf_key &= 0x00FEFFFF;
1915 manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, GUINT_TO_POINTER(manuf_key));
1916 if (manuf_value != NULL) {
1917 manuf_value->flags |= TRIED_RESOLVE_ADDRESS;
1918 return manuf_value;
1922 /* Try the global manuf tables. */
1923 const char *short_name, *long_name;
1924 /* We can't insert a 28 or 36 bit entry into the used hash table. */
1925 short_name = ws_manuf_lookup_oui24(addr, &long_name);
1926 if (short_name != NULL) {
1927 /* Found it */
1928 manuf_value = manuf_hash_new_entry(addr, short_name, long_name);
1929 } else {
1930 /* Add the address as a hex string */
1931 manuf_value = manuf_hash_new_entry(addr, NULL, NULL);
1934 manuf_value->flags |= TRIED_RESOLVE_ADDRESS;
1935 return manuf_value;
1937 } /* manuf_name_lookup */
1939 static char *
1940 wka_name_lookup(const uint8_t *addr, const unsigned int mask)
1942 uint8_t masked_addr[6];
1943 unsigned num;
1944 int i;
1945 hashwka_t *value;
1947 if (wka_hashtable == NULL) {
1948 return NULL;
1950 /* Get the part of the address covered by the mask. */
1951 for (i = 0, num = mask; num >= 8; i++, num -= 8)
1952 masked_addr[i] = addr[i]; /* copy octets entirely covered by the mask */
1953 /* Mask out the first masked octet */
1954 masked_addr[i] = addr[i] & (0xFF << (8 - num));
1955 i++;
1956 /* Zero out completely-masked-out octets */
1957 for (; i < 6; i++)
1958 masked_addr[i] = 0;
1960 value = (hashwka_t*)wmem_map_lookup(wka_hashtable, masked_addr);
1962 if (value) {
1963 value->flags |= TRIED_RESOLVE_ADDRESS;
1964 return value->name;
1967 return NULL;
1969 } /* wka_name_lookup */
1971 unsigned get_hash_ether_status(hashether_t* ether)
1973 return ether->flags;
1976 bool get_hash_ether_used(hashether_t* ether)
1978 return ((ether->flags & TRIED_OR_RESOLVED_MASK) == TRIED_OR_RESOLVED_MASK);
1981 char* get_hash_ether_hexaddr(hashether_t* ether)
1983 return ether->hexaddr;
1986 char* get_hash_ether_resolved_name(hashether_t* ether)
1988 return ether->resolved_name;
1991 bool get_hash_wka_used(hashwka_t* wka)
1993 return ((wka->flags & TRIED_OR_RESOLVED_MASK) == TRIED_OR_RESOLVED_MASK);
1996 char* get_hash_wka_resolved_name(hashwka_t* wka)
1998 return wka->name;
2001 static unsigned
2002 eth_addr_hash(const void *key)
2004 return wmem_strong_hash((const uint8_t *)key, 6);
2007 static gboolean
2008 eth_addr_cmp(const void *a, const void *b)
2010 return (memcmp(a, b, 6) == 0);
2013 static void
2014 initialize_ethers(void)
2016 ether_t *eth;
2017 unsigned mask = 0;
2019 /* hash table initialization */
2020 ws_assert(wka_hashtable == NULL);
2021 wka_hashtable = wmem_map_new(addr_resolv_scope, eth_addr_hash, eth_addr_cmp);
2022 ws_assert(manuf_hashtable == NULL);
2023 manuf_hashtable = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
2024 ws_assert(eth_hashtable == NULL);
2025 eth_hashtable = wmem_map_new(addr_resolv_scope, eth_addr_hash, eth_addr_cmp);
2027 /* Compute the pathname of the ethers file. */
2028 if (g_ethers_path == NULL) {
2029 g_ethers_path = g_build_filename(get_systemfile_dir(), ENAME_ETHERS, NULL);
2032 /* Set g_pethers_path here, but don't actually do anything
2033 * with it. It's used in get_ethbyaddr().
2035 if (g_pethers_path == NULL) {
2036 /* Check profile directory before personal configuration */
2037 g_pethers_path = get_persconffile_path(ENAME_ETHERS, true);
2038 if (!file_exists(g_pethers_path)) {
2039 g_free(g_pethers_path);
2040 g_pethers_path = get_persconffile_path(ENAME_ETHERS, false);
2044 /* Compute the pathname of the global manuf file */
2045 if (g_manuf_path == NULL)
2046 g_manuf_path = get_datafile_path(ENAME_MANUF);
2047 /* Read it and initialize the hash table */
2048 if (file_exists(g_manuf_path)) {
2049 set_ethent(g_manuf_path);
2050 while ((eth = get_ethent(&mask, true))) {
2051 add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2053 end_ethent();
2056 /* Compute the pathname of the personal manuf file */
2057 if (g_pmanuf_path == NULL) {
2058 /* Check profile directory before personal configuration */
2059 g_pmanuf_path = get_persconffile_path(ENAME_MANUF, true);
2060 if (!file_exists(g_pmanuf_path)) {
2061 g_free(g_pmanuf_path);
2062 g_pmanuf_path = get_persconffile_path(ENAME_MANUF, false);
2065 /* Read it and initialize the hash table */
2066 if (file_exists(g_pmanuf_path)) {
2067 set_ethent(g_pmanuf_path);
2068 while ((eth = get_ethent(&mask, true))) {
2069 add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2071 end_ethent();
2074 /* Compute the pathname of the wka file */
2075 if (g_wka_path == NULL)
2076 g_wka_path = get_datafile_path(ENAME_WKA);
2078 /* Read it and initialize the hash table */
2079 set_ethent(g_wka_path);
2080 while ((eth = get_ethent(&mask, true))) {
2081 add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2083 end_ethent();
2085 } /* initialize_ethers */
2087 static void
2088 ethers_cleanup(void)
2090 wka_hashtable = NULL;
2091 manuf_hashtable = NULL;
2092 eth_hashtable = NULL;
2093 g_free(g_ethers_path);
2094 g_ethers_path = NULL;
2095 g_free(g_pethers_path);
2096 g_pethers_path = NULL;
2097 g_free(g_manuf_path);
2098 g_manuf_path = NULL;
2099 g_free(g_pmanuf_path);
2100 g_pmanuf_path = NULL;
2101 g_free(g_wka_path);
2102 g_wka_path = NULL;
2105 static void
2106 eth_resolved_name_fill(hashether_t *tp, const char *name, unsigned mask, const uint8_t *addr)
2108 switch (mask) {
2109 case 24:
2110 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
2111 name, addr[3], addr[4], addr[5]);
2112 break;
2113 case 28:
2114 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%01x:%02x:%02x",
2115 name, addr[3] & 0x0F, addr[4], addr[5]);
2116 break;
2117 case 36:
2118 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%01x:%02x",
2119 name, addr[4] & 0x0F, addr[5]);
2120 break;
2121 default: // Future-proof generic algorithm
2123 unsigned bytes = mask / 8;
2124 unsigned bitmask = mask % 8;
2126 int pos = snprintf(tp->resolved_name, MAXNAMELEN, "%s", name);
2127 if (pos >= MAXNAMELEN) return;
2129 if (bytes < 6) {
2130 pos += snprintf(tp->resolved_name + pos, MAXNAMELEN - pos,
2131 bitmask >= 4 ? "_%01x" : "_%02x",
2132 addr[bytes] & (0xFF >> bitmask));
2133 bytes++;
2136 while (bytes < 6) {
2137 if (pos >= MAXNAMELEN) return;
2138 pos += snprintf(tp->resolved_name + pos, MAXNAMELEN - pos, ":%02x",
2139 addr[bytes]);
2140 bytes++;
2146 /* Resolve ethernet address */
2147 static hashether_t *
2148 eth_addr_resolve(hashether_t *tp) {
2149 ether_t *eth;
2150 hashmanuf_t *manuf_value;
2151 const uint8_t *addr = tp->addr;
2152 size_t addr_size = sizeof(tp->addr);
2154 if ( (eth = get_ethbyaddr(addr)) != NULL) {
2155 (void) g_strlcpy(tp->resolved_name, eth->name, MAXNAMELEN);
2156 tp->flags |= NAME_RESOLVED | STATIC_HOSTNAME;
2157 return tp;
2158 } else if (!(tp->flags & NAME_RESOLVED)) {
2159 unsigned mask;
2160 char *name;
2161 address ether_addr;
2163 /* Unknown name. Try looking for it in the well-known-address
2164 tables for well-known address ranges smaller than 2^24. */
2165 mask = 7;
2166 do {
2167 /* Only the topmost 5 bytes participate fully */
2168 if ((name = wka_name_lookup(addr, mask+40)) != NULL) {
2169 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x",
2170 name, addr[5] & (0xFF >> mask));
2171 tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2172 return tp;
2174 } while (mask--);
2176 mask = 7;
2177 do {
2178 /* Only the topmost 4 bytes participate fully */
2179 if ((name = wka_name_lookup(addr, mask+32)) != NULL) {
2180 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x",
2181 name, addr[4] & (0xFF >> mask), addr[5]);
2182 tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2183 return tp;
2185 } while (mask--);
2187 mask = 7;
2188 do {
2189 /* Only the topmost 3 bytes participate fully */
2190 if ((name = wka_name_lookup(addr, mask+24)) != NULL) {
2191 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
2192 name, addr[3] & (0xFF >> mask), addr[4], addr[5]);
2193 tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2194 return tp;
2196 } while (mask--);
2198 /* Now try looking in the manufacturer table. */
2199 manuf_value = manuf_name_lookup(addr, addr_size);
2200 if ((manuf_value != NULL) && ((manuf_value->flags & NAME_RESOLVED) == NAME_RESOLVED)) {
2201 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
2202 manuf_value->resolved_name, addr[3], addr[4], addr[5]);
2203 tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2204 return tp;
2207 /* Now try looking for it in the well-known-address
2208 tables for well-known address ranges larger than 2^24. */
2209 mask = 7;
2210 do {
2211 /* Only the topmost 2 bytes participate fully */
2212 if ((name = wka_name_lookup(addr, mask+16)) != NULL) {
2213 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x",
2214 name, addr[2] & (0xFF >> mask), addr[3], addr[4],
2215 addr[5]);
2216 tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2217 return tp;
2219 } while (mask--);
2221 mask = 7;
2222 do {
2223 /* Only the topmost byte participates fully */
2224 if ((name = wka_name_lookup(addr, mask+8)) != NULL) {
2225 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
2226 name, addr[1] & (0xFF >> mask), addr[2], addr[3],
2227 addr[4], addr[5]);
2228 tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2229 return tp;
2231 } while (mask--);
2233 mask = 7;
2234 do {
2235 /* Not even the topmost byte participates fully */
2236 if ((name = wka_name_lookup(addr, mask)) != NULL) {
2237 snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
2238 name, addr[0] & (0xFF >> mask), addr[1], addr[2],
2239 addr[3], addr[4], addr[5]);
2240 tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2241 return tp;
2243 } while (--mask); /* Work down to the last bit */
2245 /* Now try looking in the global manuf data for a MA-M or MA-S
2246 * match. We do this last so that the other files override this
2247 * result.
2249 const char *short_name, *long_name;
2250 short_name = ws_manuf_lookup(addr, &long_name, &mask);
2251 if (short_name != NULL) {
2252 if (mask == 24) {
2253 /* This shouldn't happen as it should be handled above,
2254 * but it doesn't hurt.
2256 manuf_hash_new_entry(addr, short_name, long_name);
2258 eth_resolved_name_fill(tp, short_name, mask, addr);
2259 tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2260 return tp;
2262 /* No match whatsoever. */
2263 set_address(&ether_addr, AT_ETHER, 6, addr);
2264 address_to_str_buf(&ether_addr, tp->resolved_name, MAXNAMELEN);
2265 return tp;
2267 return tp;
2268 } /* eth_addr_resolve */
2270 static hashether_t *
2271 eth_hash_new_entry(const uint8_t *addr, const bool resolve)
2273 hashether_t *tp;
2274 char *endp;
2276 tp = wmem_new(addr_resolv_scope, hashether_t);
2277 memcpy(tp->addr, addr, sizeof(tp->addr));
2278 tp->flags = 0;
2279 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
2280 endp = bytes_to_hexstr_punct(tp->hexaddr, addr, sizeof(tp->addr), ':');
2281 *endp = '\0';
2282 tp->resolved_name[0] = '\0';
2284 if (resolve)
2285 eth_addr_resolve(tp);
2287 wmem_map_insert(eth_hashtable, tp->addr, tp);
2289 return tp;
2290 } /* eth_hash_new_entry */
2292 static hashether_t *
2293 add_eth_name(const uint8_t *addr, const char *name)
2295 hashether_t *tp;
2297 tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
2299 if (tp == NULL) {
2300 tp = eth_hash_new_entry(addr, false);
2303 if (strcmp(tp->resolved_name, name) != 0) {
2304 (void) g_strlcpy(tp->resolved_name, name, MAXNAMELEN);
2305 tp->flags |= NAME_RESOLVED;
2306 new_resolved_objects = true;
2309 return tp;
2310 } /* add_eth_name */
2312 static hashether_t *
2313 eth_name_lookup(const uint8_t *addr, const bool resolve)
2315 hashether_t *tp;
2317 tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
2319 if (tp == NULL) {
2320 tp = eth_hash_new_entry(addr, resolve);
2321 } else {
2322 if (resolve && !(tp->flags & TRIED_RESOLVE_ADDRESS)) {
2323 /* We don't test TRIED_OR_RESOLVED_MASK (but check
2324 * RESOLVED_NAME in eth_addr_resolve) so that the ethers
2325 * files take precendent over wka, NRBs, ARP discovery, etc.
2326 * XXX: What _is_ the proper precedence, and should it
2327 * be configurable? (cf. #18075) */
2328 eth_addr_resolve(tp); /* Found but needs to be resolved */
2331 if (resolve) {
2332 tp->flags |= TRIED_RESOLVE_ADDRESS;
2335 return tp;
2337 } /* eth_name_lookup */
2340 /* IPXNETS */
2341 static int
2342 parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
2345 * We allow three address separators (':', '-', and '.'),
2346 * as well as no separators
2349 char *cp;
2350 uint32_t a, a0, a1, a2, a3;
2351 bool found_single_number = false;
2353 if ((cp = strchr(line, '#')))
2354 *cp = '\0';
2356 if ((cp = strtok(line, " \t\n")) == NULL)
2357 return -1;
2359 /* Either fill a0,a1,a2,a3 and found_single_number is false,
2360 * fill a and found_single_number is true,
2361 * or return -1
2363 if (sscanf(cp, "%x:%x:%x:%x", &a0, &a1, &a2, &a3) != 4) {
2364 if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
2365 if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
2366 if (sscanf(cp, "%x", &a) == 1) {
2367 found_single_number = true;
2369 else {
2370 return -1;
2376 if ((cp = strtok(NULL, " \t\n")) == NULL)
2377 return -1;
2379 if (found_single_number) {
2380 ipxnet->addr = a;
2382 else {
2383 ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
2386 (void) g_strlcpy(ipxnet->name, cp, MAXNAMELEN);
2388 return 0;
2390 } /* parse_ipxnets_line */
2392 static FILE *ipxnet_p;
2394 static void
2395 set_ipxnetent(char *path)
2397 if (ipxnet_p)
2398 rewind(ipxnet_p);
2399 else
2400 ipxnet_p = ws_fopen(path, "r");
2403 static void
2404 end_ipxnetent(void)
2406 if (ipxnet_p) {
2407 fclose(ipxnet_p);
2408 ipxnet_p = NULL;
2412 static ipxnet_t *
2413 get_ipxnetent(void)
2416 static ipxnet_t ipxnet;
2417 char buf[MAX_LINELEN];
2419 if (ipxnet_p == NULL)
2420 return NULL;
2422 while (fgetline(buf, sizeof(buf), ipxnet_p) >= 0) {
2423 if (parse_ipxnets_line(buf, &ipxnet) == 0) {
2424 return &ipxnet;
2428 return NULL;
2430 } /* get_ipxnetent */
2432 static ipxnet_t *
2433 get_ipxnetbyaddr(uint32_t addr)
2435 ipxnet_t *ipxnet;
2437 set_ipxnetent(g_ipxnets_path);
2439 while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) ) ;
2441 if (ipxnet == NULL) {
2442 end_ipxnetent();
2444 set_ipxnetent(g_pipxnets_path);
2446 while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) )
2449 end_ipxnetent();
2452 return ipxnet;
2454 } /* get_ipxnetbyaddr */
2456 static void
2457 initialize_ipxnets(void)
2459 /* Compute the pathname of the ipxnets file.
2461 * XXX - is there a notion of an "ipxnets file" in any flavor of
2462 * UNIX, or with any add-on Netware package for UNIX? If not,
2463 * should the UNIX version of the ipxnets file be in the datafile
2464 * directory as well?
2466 if (g_ipxnets_path == NULL) {
2467 g_ipxnets_path = wmem_strdup_printf(addr_resolv_scope, "%s" G_DIR_SEPARATOR_S "%s",
2468 get_systemfile_dir(), ENAME_IPXNETS);
2471 /* Set g_pipxnets_path here, but don't actually do anything
2472 * with it. It's used in get_ipxnetbyaddr().
2474 if (g_pipxnets_path == NULL) {
2475 /* Check profile directory before personal configuration */
2476 g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, true);
2477 if (!file_exists(g_pipxnets_path)) {
2478 g_free(g_pipxnets_path);
2479 g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, false);
2483 } /* initialize_ipxnets */
2485 static void
2486 ipx_name_lookup_cleanup(void)
2488 g_ipxnets_path = NULL;
2489 g_free(g_pipxnets_path);
2490 g_pipxnets_path = NULL;
2493 static char *
2494 ipxnet_name_lookup(wmem_allocator_t *allocator, const unsigned addr)
2496 hashipxnet_t *tp;
2497 ipxnet_t *ipxnet;
2499 tp = (hashipxnet_t *)wmem_map_lookup(ipxnet_hash_table, GUINT_TO_POINTER(addr));
2500 if (tp == NULL) {
2501 tp = wmem_new(addr_resolv_scope, hashipxnet_t);
2502 wmem_map_insert(ipxnet_hash_table, GUINT_TO_POINTER(addr), tp);
2503 } else {
2504 return wmem_strdup(allocator, tp->name);
2507 /* fill in a new entry */
2509 tp->addr = addr;
2511 if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL) {
2512 /* unknown name */
2513 snprintf(tp->name, MAXNAMELEN, "%X", addr);
2515 } else {
2516 (void) g_strlcpy(tp->name, ipxnet->name, MAXNAMELEN);
2519 return wmem_strdup(allocator, tp->name);
2521 } /* ipxnet_name_lookup */
2523 /* VLANS */
2524 static int
2525 parse_vlan_line(char *line, vlan_t *vlan)
2527 char *cp;
2528 uint16_t id;
2530 if ((cp = strchr(line, '#')))
2531 *cp = '\0';
2533 if ((cp = strtok(line, " \t\n")) == NULL)
2534 return -1;
2536 if (sscanf(cp, "%" SCNu16, &id) == 1) {
2537 vlan->id = id;
2539 else {
2540 return -1;
2543 if ((cp = strtok(NULL, "\t\n")) == NULL)
2544 return -1;
2546 (void) g_strlcpy(vlan->name, cp, MAXVLANNAMELEN);
2548 return 0;
2550 } /* parse_vlan_line */
2552 static FILE *vlan_p;
2554 static void
2555 set_vlanent(char *path)
2557 if (vlan_p)
2558 rewind(vlan_p);
2559 else
2560 vlan_p = ws_fopen(path, "r");
2563 static void
2564 end_vlanent(void)
2566 if (vlan_p) {
2567 fclose(vlan_p);
2568 vlan_p = NULL;
2572 static vlan_t *
2573 get_vlanent(void)
2576 static vlan_t vlan;
2577 char buf[MAX_LINELEN];
2579 if (vlan_p == NULL)
2580 return NULL;
2582 while (fgetline(buf, sizeof(buf), vlan_p) >= 0) {
2583 if (parse_vlan_line(buf, &vlan) == 0) {
2584 return &vlan;
2588 return NULL;
2590 } /* get_vlanent */
2592 static vlan_t *
2593 get_vlannamebyid(uint16_t id)
2595 vlan_t *vlan;
2597 set_vlanent(g_pvlan_path);
2599 while (((vlan = get_vlanent()) != NULL) && (id != vlan->id) ) ;
2601 if (vlan == NULL) {
2602 end_vlanent();
2606 return vlan;
2608 } /* get_vlannamebyid */
2610 static void
2611 initialize_vlans(void)
2613 ws_assert(vlan_hash_table == NULL);
2614 vlan_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
2616 /* Set g_pvlan_path here, but don't actually do anything
2617 * with it. It's used in get_vlannamebyid()
2619 if (g_pvlan_path == NULL) {
2620 /* Check profile directory before personal configuration */
2621 g_pvlan_path = get_persconffile_path(ENAME_VLANS, true);
2622 if (!file_exists(g_pvlan_path)) {
2623 g_free(g_pvlan_path);
2624 g_pvlan_path = get_persconffile_path(ENAME_VLANS, false);
2627 } /* initialize_vlans */
2629 static void
2630 vlan_name_lookup_cleanup(void)
2632 end_vlanent();
2633 vlan_hash_table = NULL;
2634 g_free(g_pvlan_path);
2635 g_pvlan_path = NULL;
2638 static const char *
2639 vlan_name_lookup(const unsigned id)
2641 hashvlan_t *tp;
2642 vlan_t *vlan;
2644 tp = (hashvlan_t *)wmem_map_lookup(vlan_hash_table, GUINT_TO_POINTER(id));
2645 if (tp == NULL) {
2646 tp = wmem_new(addr_resolv_scope, hashvlan_t);
2647 wmem_map_insert(vlan_hash_table, GUINT_TO_POINTER(id), tp);
2648 } else {
2649 return tp->name;
2652 /* fill in a new entry */
2654 tp->id = id;
2656 if ( (vlan = get_vlannamebyid(id)) == NULL) {
2657 /* unknown name */
2658 snprintf(tp->name, MAXVLANNAMELEN, "<%u>", id);
2660 } else {
2661 (void) g_strlcpy(tp->name, vlan->name, MAXVLANNAMELEN);
2664 return tp->name;
2666 } /* vlan_name_lookup */
2667 /* VLAN END */
2669 static bool
2670 read_hosts_file (const char *hostspath, bool store_entries)
2672 FILE *hf;
2673 char line[MAX_LINELEN];
2674 char *cp;
2675 union {
2676 uint32_t ip4_addr;
2677 ws_in6_addr ip6_addr;
2678 } host_addr;
2679 bool is_ipv6, entry_found = false;
2682 * See the hosts(4) or hosts(5) man page for hosts file format
2683 * (not available on all systems).
2685 if ((hf = ws_fopen(hostspath, "r")) == NULL)
2686 return false;
2688 while (fgetline(line, sizeof(line), hf) >= 0) {
2689 if ((cp = strchr(line, '#')))
2690 *cp = '\0';
2692 if ((cp = strtok(line, " \t")) == NULL)
2693 continue; /* no tokens in the line */
2695 if (ws_inet_pton6(cp, &host_addr.ip6_addr)) {
2696 /* Valid IPv6 */
2697 is_ipv6 = true;
2698 } else if (ws_inet_pton4(cp, &host_addr.ip4_addr)) {
2699 /* Valid IPv4 */
2700 is_ipv6 = false;
2701 } else {
2702 continue;
2705 if ((cp = strtok(NULL, " \t")) == NULL)
2706 continue; /* no host name */
2708 entry_found = true;
2709 if (store_entries) {
2710 if (is_ipv6) {
2711 add_ipv6_name(&host_addr.ip6_addr, cp, true);
2712 } else {
2713 add_ipv4_name(host_addr.ip4_addr, cp, true);
2718 fclose(hf);
2719 return entry_found ? true : false;
2720 } /* read_hosts_file */
2722 bool
2723 add_hosts_file (const char *hosts_file)
2725 bool found = false;
2726 unsigned i;
2728 if (!hosts_file)
2729 return false;
2731 if (!extra_hosts_files)
2732 extra_hosts_files = g_ptr_array_new();
2734 for (i = 0; i < extra_hosts_files->len; i++) {
2735 if (strcmp(hosts_file, (const char *) g_ptr_array_index(extra_hosts_files, i)) == 0)
2736 found = true;
2739 if (!found) {
2740 g_ptr_array_add(extra_hosts_files, wmem_strdup(addr_resolv_scope, hosts_file));
2741 return read_hosts_file (hosts_file, false);
2743 return true;
2746 bool
2747 add_ip_name_from_string (const char *addr, const char *name)
2749 union {
2750 uint32_t ip4_addr;
2751 ws_in6_addr ip6_addr;
2752 } host_addr;
2753 bool is_ipv6;
2754 resolved_name_t *resolved_entry;
2756 if (ws_inet_pton6(addr, &host_addr.ip6_addr)) {
2757 is_ipv6 = true;
2758 } else if (ws_inet_pton4(addr, &host_addr.ip4_addr)) {
2759 is_ipv6 = false;
2760 } else {
2761 return false;
2764 if (is_ipv6) {
2765 resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv6_list, &host_addr.ip6_addr);
2766 if (resolved_entry)
2768 // If we found a previous matching key (IP address), then just update the value (custom hostname);
2769 (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN);
2771 else
2773 // Add a new mapping entry, if this IP address isn't already in the list.
2774 ws_in6_addr* addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr);
2775 memcpy(addr_key, &host_addr.ip6_addr, sizeof(ws_in6_addr));
2777 resolved_entry = wmem_new(wmem_epan_scope(), resolved_name_t);
2778 (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN);
2780 wmem_map_insert(manually_resolved_ipv6_list, addr_key, resolved_entry);
2782 } else {
2783 resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv4_list, GUINT_TO_POINTER(host_addr.ip4_addr));
2784 if (resolved_entry)
2786 // If we found a previous matching key (IP address), then just update the value (custom hostname);
2787 (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN);
2789 else
2791 // Add a new mapping entry, if this IP address isn't already in the list.
2792 resolved_entry = wmem_new(wmem_epan_scope(), resolved_name_t);
2793 (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN);
2795 wmem_map_insert(manually_resolved_ipv4_list, GUINT_TO_POINTER(host_addr.ip4_addr), resolved_entry);
2799 return true;
2800 } /* add_ip_name_from_string */
2802 extern resolved_name_t* get_edited_resolved_name(const char* addr)
2804 uint32_t ip4_addr;
2805 ws_in6_addr ip6_addr;
2806 resolved_name_t* resolved_entry = NULL;
2808 if (ws_inet_pton6(addr, &ip6_addr)) {
2809 resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv6_list, &ip6_addr);
2811 else if (ws_inet_pton4(addr, &ip4_addr)) {
2812 resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv4_list, GUINT_TO_POINTER(ip4_addr));
2815 return resolved_entry;
2819 * Add the resolved addresses that are in use to the list used to create the pcapng NRB
2821 static void
2822 ipv4_hash_table_resolved_to_list(void *key _U_, void *value, void *user_data)
2824 addrinfo_lists_t *lists = (addrinfo_lists_t *)user_data;
2825 hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value;
2827 if ((ipv4_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
2828 lists->ipv4_addr_list = g_list_prepend(lists->ipv4_addr_list, ipv4_hash_table_entry);
2833 * Add the resolved addresses that are in use to the list used to create the pcapng NRB
2835 static void
2836 ipv6_hash_table_resolved_to_list(void *key _U_, void *value, void *user_data)
2838 addrinfo_lists_t *lists = (addrinfo_lists_t *)user_data;
2839 hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value;
2841 if ((ipv6_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
2842 lists->ipv6_addr_list = g_list_prepend(lists->ipv6_addr_list, ipv6_hash_table_entry);
2846 addrinfo_lists_t *
2847 get_addrinfo_list(void)
2849 if (ipv4_hash_table) {
2850 wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_resolved_to_list, &addrinfo_lists);
2853 if (ipv6_hash_table) {
2854 wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_resolved_to_list, &addrinfo_lists);
2857 return &addrinfo_lists;
2860 /* Read in a list of subnet definition - name pairs.
2861 * <line> = <comment> | <entry> | <whitespace>
2862 * <comment> = <whitespace>#<any>
2863 * <entry> = <subnet_definition> <whitespace> <subnet_name> [<comment>|<whitespace><any>]
2864 * <subnet_definition> = <ipv4_address> / <subnet_mask_length>
2865 * <ipv4_address> is a full address; it will be masked to get the subnet-ID.
2866 * <subnet_mask_length> is a decimal 1-31
2867 * <subnet_name> is a string containing no whitespace.
2868 * <whitespace> = (space | tab)+
2869 * Any malformed entries are ignored.
2870 * Any trailing data after the subnet_name is ignored.
2872 * XXX Support IPv6
2874 static bool
2875 read_subnets_file (const char *subnetspath)
2877 FILE *hf;
2878 char line[MAX_LINELEN];
2879 char *cp, *cp2;
2880 uint32_t host_addr; /* IPv4 ONLY */
2881 uint8_t mask_length;
2883 if ((hf = ws_fopen(subnetspath, "r")) == NULL)
2884 return false;
2886 while (fgetline(line, sizeof(line), hf) >= 0) {
2887 if ((cp = strchr(line, '#')))
2888 *cp = '\0';
2890 if ((cp = strtok(line, " \t")) == NULL)
2891 continue; /* no tokens in the line */
2894 /* Expected format is <IP4 address>/<subnet length> */
2895 cp2 = strchr(cp, '/');
2896 if (NULL == cp2) {
2897 /* No length */
2898 continue;
2900 *cp2 = '\0'; /* Cut token */
2901 ++cp2 ;
2903 /* Check if this is a valid IPv4 address */
2904 if (!str_to_ip(cp, &host_addr)) {
2905 continue; /* no */
2908 if (!ws_strtou8(cp2, NULL, &mask_length) || mask_length == 0 || mask_length > 32) {
2909 continue; /* invalid mask length */
2912 if ((cp = strtok(NULL, " \t")) == NULL)
2913 continue; /* no subnet name */
2915 subnet_entry_set(host_addr, mask_length, cp);
2918 fclose(hf);
2919 return true;
2920 } /* read_subnets_file */
2922 static subnet_entry_t
2923 subnet_lookup(const uint32_t addr)
2925 subnet_entry_t subnet_entry;
2926 uint32_t i;
2928 /* Search mask lengths linearly, longest first */
2930 i = SUBNETLENGTHSIZE;
2931 while(have_subnet_entry && i > 0) {
2932 uint32_t masked_addr;
2933 subnet_length_entry_t* length_entry;
2935 /* Note that we run from 31 (length 32) to 0 (length 1) */
2936 --i;
2937 ws_assert(i < SUBNETLENGTHSIZE);
2940 length_entry = &subnet_length_entries[i];
2942 if (NULL != length_entry->subnet_addresses) {
2943 sub_net_hashipv4_t * tp;
2944 uint32_t hash_idx;
2946 masked_addr = addr & length_entry->mask;
2947 hash_idx = HASH_IPV4_ADDRESS(masked_addr);
2949 tp = length_entry->subnet_addresses[hash_idx];
2950 while(tp != NULL && tp->addr != masked_addr) {
2951 tp = tp->next;
2954 if (NULL != tp) {
2955 subnet_entry.mask = length_entry->mask;
2956 subnet_entry.mask_length = i + 1; /* Length is offset + 1 */
2957 subnet_entry.name = tp->name;
2958 return subnet_entry;
2963 subnet_entry.mask = 0;
2964 subnet_entry.mask_length = 0;
2965 subnet_entry.name = NULL;
2967 return subnet_entry;
2970 /* Add a subnet-definition - name pair to the set.
2971 * The definition is taken by masking the address passed in with the mask of the
2972 * given length.
2974 static void
2975 subnet_entry_set(uint32_t subnet_addr, const uint8_t mask_length, const char* name)
2977 subnet_length_entry_t* entry;
2978 sub_net_hashipv4_t * tp;
2979 size_t hash_idx;
2981 ws_assert(mask_length > 0 && mask_length <= 32);
2983 entry = &subnet_length_entries[mask_length - 1];
2985 subnet_addr &= entry->mask;
2987 hash_idx = HASH_IPV4_ADDRESS(subnet_addr);
2989 if (NULL == entry->subnet_addresses) {
2990 entry->subnet_addresses = (sub_net_hashipv4_t**)wmem_alloc0(addr_resolv_scope, sizeof(sub_net_hashipv4_t*) * HASHHOSTSIZE);
2993 if (NULL != (tp = entry->subnet_addresses[hash_idx])) {
2994 sub_net_hashipv4_t * new_tp;
2996 while (tp->next) {
2997 if (tp->addr == subnet_addr) {
2998 return; /* XXX provide warning that an address was repeated? */
2999 } else {
3000 tp = tp->next;
3004 new_tp = wmem_new(addr_resolv_scope, sub_net_hashipv4_t);
3005 tp->next = new_tp;
3006 tp = new_tp;
3007 } else {
3008 tp = entry->subnet_addresses[hash_idx] = wmem_new(addr_resolv_scope, sub_net_hashipv4_t);
3011 tp->next = NULL;
3012 tp->addr = subnet_addr;
3013 (void) g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
3014 have_subnet_entry = true;
3017 static void
3018 subnet_name_lookup_init(void)
3020 char* subnetspath;
3021 uint32_t i;
3023 for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
3024 uint32_t length = i + 1;
3026 subnet_length_entries[i].subnet_addresses = NULL;
3027 subnet_length_entries[i].mask_length = length;
3028 subnet_length_entries[i].mask = g_htonl(ws_ipv4_get_subnet_mask(length));
3031 /* Check profile directory before personal configuration */
3032 subnetspath = get_persconffile_path(ENAME_SUBNETS, true);
3033 if (!read_subnets_file(subnetspath)) {
3034 if (errno != ENOENT) {
3035 report_open_failure(subnetspath, errno, false);
3038 g_free(subnetspath);
3039 subnetspath = get_persconffile_path(ENAME_SUBNETS, false);
3040 if (!read_subnets_file(subnetspath) && errno != ENOENT) {
3041 report_open_failure(subnetspath, errno, false);
3044 g_free(subnetspath);
3047 * Load the global subnets file, if we have one.
3049 subnetspath = get_datafile_path(ENAME_SUBNETS);
3050 if (!read_subnets_file(subnetspath) && errno != ENOENT) {
3051 report_open_failure(subnetspath, errno, false);
3053 g_free(subnetspath);
3056 /* SS7 PC Name Resolution Portion */
3057 static hashss7pc_t *
3058 new_ss7pc(const uint8_t ni, const uint32_t pc)
3060 hashss7pc_t *tp = wmem_new(addr_resolv_scope, hashss7pc_t);
3061 tp->id = (ni<<24) + (pc&0xffffff);
3062 tp->pc_addr[0] = '\0';
3063 tp->name[0] = '\0';
3065 return tp;
3068 static hashss7pc_t *
3069 host_lookup_ss7pc(const uint8_t ni, const uint32_t pc)
3071 hashss7pc_t * volatile tp;
3072 uint32_t id;
3074 id = (ni<<24) + (pc&0xffffff);
3076 tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
3077 if (tp == NULL) {
3078 tp = new_ss7pc(ni, pc);
3079 wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
3082 return tp;
3085 void fill_unresolved_ss7pc(const char * pc_addr, const uint8_t ni, const uint32_t pc)
3087 hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
3089 (void) g_strlcpy(tp->pc_addr, pc_addr, MAXNAMELEN);
3092 const char *
3093 get_hostname_ss7pc(const uint8_t ni, const uint32_t pc)
3095 hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
3097 /* never resolved yet*/
3098 if (tp->pc_addr[0] == '\0')
3099 return tp->pc_addr;
3101 /* Don't have name in file */
3102 if (tp->name[0] == '\0')
3103 return tp->pc_addr;
3105 if (!gbl_resolv_flags.ss7pc_name)
3106 return tp->pc_addr;
3108 return tp->name;
3111 static void
3112 add_ss7pc_name(const uint8_t ni, uint32_t pc, const char *name)
3114 hashss7pc_t *tp;
3115 uint32_t id;
3117 if (!name || name[0] == '\0')
3118 return;
3120 id = (ni<<24) + (pc&0xffffff);
3121 tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
3122 if (!tp) {
3123 tp = new_ss7pc(ni, pc);
3124 wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
3127 if (g_ascii_strcasecmp(tp->name, name)) {
3128 (void) g_strlcpy(tp->name, name, MAXNAMELEN);
3132 static bool
3133 read_ss7pcs_file(const char *ss7pcspath)
3135 FILE *hf;
3136 char line[MAX_LINELEN];
3137 char *cp;
3138 uint8_t ni;
3139 uint32_t pc;
3140 bool entry_found = false;
3143 * File format is Network Indicator (decimal)<dash>Point Code (Decimal)<tab/space>Hostname
3145 if ((hf = ws_fopen(ss7pcspath, "r")) == NULL)
3146 return false;
3148 while (fgetline(line, sizeof(line), hf) >= 0) {
3149 if ((cp = strchr(line, '#')))
3150 *cp = '\0';
3152 if ((cp = strtok(line, "-")) == NULL)
3153 continue; /*no ni-pc separator*/
3154 if (!ws_strtou8(cp, NULL, &ni))
3155 continue;
3156 if (ni > 3)
3157 continue;
3159 if ((cp = strtok(NULL, " \t")) == NULL)
3160 continue; /* no tokens for pc and name */
3161 if (!ws_strtou32(cp, NULL, &pc))
3162 continue;
3163 if (pc >> 24 > 0)
3164 continue;
3166 if ((cp = strtok(NULL, " \t")) == NULL)
3167 continue; /* no host name */
3169 entry_found = true;
3170 add_ss7pc_name(ni, pc, cp);
3173 fclose(hf);
3174 return entry_found ? true : false;
3177 static void
3178 ss7pc_name_lookup_init(void)
3180 char *ss7pcspath;
3182 ws_assert(ss7pc_hash_table == NULL);
3184 ss7pc_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
3187 * Load the user's ss7pcs file
3189 ss7pcspath = get_persconffile_path(ENAME_SS7PCS, true);
3190 if (!read_ss7pcs_file(ss7pcspath) && errno != ENOENT) {
3191 report_open_failure(ss7pcspath, errno, false);
3193 g_free(ss7pcspath);
3196 /* SS7PC Name Resolution End*/
3200 * External Functions
3203 void
3204 addr_resolve_pref_init(module_t *nameres)
3206 prefs_register_bool_preference(nameres, "mac_name",
3207 "Resolve MAC addresses",
3208 "Resolve Ethernet MAC addresses to host names from the preferences"
3209 " or system's Ethers file, or to a manufacturer based name.",
3210 &gbl_resolv_flags.mac_name);
3212 prefs_register_bool_preference(nameres, "transport_name",
3213 "Resolve transport names",
3214 "Resolve TCP/UDP ports into service names",
3215 &gbl_resolv_flags.transport_name);
3217 prefs_register_bool_preference(nameres, "network_name",
3218 "Resolve network (IP) addresses",
3219 "Resolve IPv4, IPv6, and IPX addresses into host names."
3220 " The next set of check boxes determines how name resolution should be performed."
3221 " If no other options are checked name resolution is made from Wireshark's host file"
3222 " and capture file name resolution blocks.",
3223 &gbl_resolv_flags.network_name);
3225 prefs_register_bool_preference(nameres, "dns_pkt_addr_resolution",
3226 "Use captured DNS packet data for name resolution",
3227 "Use address/name pairs found in captured DNS packets for name resolution.",
3228 &gbl_resolv_flags.dns_pkt_addr_resolution);
3230 prefs_register_bool_preference(nameres, "handshake_sni_addr_resolution",
3231 "Use SNI information from captured handshake packets",
3232 "Use the Server Name Indication found in TLS handshakes for name resolution.",
3233 &gbl_resolv_flags.handshake_sni_addr_resolution);
3235 prefs_register_bool_preference(nameres, "use_external_name_resolver",
3236 "Use your system's DNS settings for name resolution",
3237 "Use your system's configured name resolver"
3238 " (usually DNS) to resolve network names."
3239 " Only applies when network name resolution"
3240 " is enabled.",
3241 &gbl_resolv_flags.use_external_net_name_resolver);
3243 prefs_register_bool_preference(nameres, "use_custom_dns_servers",
3244 "Use a custom list of DNS servers for name resolution",
3245 "Use a DNS Servers list to resolve network names if true. If false, default information is used",
3246 &use_custom_dns_server_list);
3248 static uat_field_t dns_server_uats_flds[] = {
3249 UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, ipaddr, "IP address", dnsserver_uat_fld_ip_chk_cb, "IPv4 or IPv6 address"),
3250 UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, tcp_port, "TCP Port", dnsserver_uat_fld_port_chk_cb, "Port Number (TCP)"),
3251 UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, udp_port, "UDP Port", dnsserver_uat_fld_port_chk_cb, "Port Number (UDP)"),
3252 UAT_END_FIELDS
3255 dnsserver_uat = uat_new("DNS Servers",
3256 sizeof(struct dns_server_data),
3257 "addr_resolve_dns_servers", /* filename */
3258 true, /* from_profile */
3259 &dnsserverlist_uats, /* data_ptr */
3260 &ndnsservers, /* numitems_ptr */
3261 UAT_AFFECTS_DISSECTION,
3262 NULL,
3263 dns_server_copy_cb,
3264 NULL,
3265 dns_server_free_cb,
3266 c_ares_set_dns_servers,
3267 NULL,
3268 dns_server_uats_flds);
3269 static const char *dnsserver_uat_defaults[] = { NULL, "53", "53" };
3270 uat_set_default_values(dnsserver_uat, dnsserver_uat_defaults);
3271 prefs_register_uat_preference(nameres, "dns_servers",
3272 "DNS Servers",
3273 "A table of IPv4 and IPv6 addresses of DNS servers to be used to resolve IP names and addresses",
3274 dnsserver_uat);
3276 prefs_register_obsolete_preference(nameres, "concurrent_dns");
3278 prefs_register_uint_preference(nameres, "name_resolve_concurrency",
3279 "Maximum concurrent requests",
3280 "The maximum number of DNS requests that may"
3281 " be active at any time. A large value (many"
3282 " thousands) might overload the network or make"
3283 " your DNS server behave badly.",
3285 &name_resolve_concurrency);
3287 prefs_register_obsolete_preference(nameres, "hosts_file_handling");
3289 prefs_register_bool_preference(nameres, "vlan_name",
3290 "Resolve VLAN IDs",
3291 "Resolve VLAN IDs to network names from the preferences \"vlans\" file."
3292 " Format of the file is: \"ID<Tab>Name\"."
3293 " One line per VLAN, e.g.: 1 Management",
3294 &gbl_resolv_flags.vlan_name);
3296 prefs_register_bool_preference(nameres, "ss7_pc_name",
3297 "Resolve SS7 PCs",
3298 "Resolve SS7 Point Codes to node names from the profiles \"ss7pcs\" file."
3299 " Format of the file is: \"Network_Indicator<Dash>PC_Decimal<Tab>Name\"."
3300 " One line per Point Code, e.g.: 2-1234 MyPointCode1",
3301 &gbl_resolv_flags.ss7pc_name);
3305 void addr_resolve_pref_apply(void)
3307 c_ares_set_dns_servers();
3308 maxmind_db_pref_apply();
3311 void
3312 disable_name_resolution(void) {
3313 gbl_resolv_flags.mac_name = false;
3314 gbl_resolv_flags.network_name = false;
3315 gbl_resolv_flags.transport_name = false;
3316 gbl_resolv_flags.dns_pkt_addr_resolution = false;
3317 gbl_resolv_flags.handshake_sni_addr_resolution = false;
3318 gbl_resolv_flags.use_external_net_name_resolver = false;
3319 gbl_resolv_flags.vlan_name = false;
3320 gbl_resolv_flags.ss7pc_name = false;
3321 gbl_resolv_flags.maxmind_geoip = false;
3324 bool
3325 host_name_lookup_process(void) {
3326 struct timeval tv = { 0, 0 };
3327 int nfds;
3328 fd_set rfds, wfds;
3329 bool nro = new_resolved_objects;
3331 new_resolved_objects = false;
3332 nro |= maxmind_db_lookup_process();
3334 if (!async_dns_initialized)
3335 /* c-ares not initialized. Bail out and cancel timers. */
3336 return nro;
3338 process_async_dns_queue();
3340 FD_ZERO(&rfds);
3341 FD_ZERO(&wfds);
3342 nfds = ares_fds(ghba_chan, &rfds, &wfds);
3343 if (nfds > 0) {
3344 if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
3345 /* If it's interrupted by a signal, no need to put out a message */
3346 if (errno != EINTR)
3347 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
3348 return nro;
3350 ares_process(ghba_chan, &rfds, &wfds);
3353 /* Any new entries? */
3354 return nro;
3357 static void
3358 _host_name_lookup_cleanup(void) {
3359 async_dns_queue_head = NULL;
3361 if (async_dns_initialized) {
3362 ares_destroy(ghba_chan);
3363 ares_destroy(ghbn_chan);
3365 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
3366 ares_library_cleanup();
3367 #endif
3368 async_dns_initialized = false;
3371 const char *
3372 get_hostname(const unsigned addr)
3374 /* XXX why do we call this if we're not resolving? To create hash entries?
3375 * Why? So that we can return a const char*?
3377 * Note the returned string is in addr_resolv_scope, which has a similar
3378 * life to the global file scope (slightly larger, in that the resolved
3379 * addresses need to be available during dissector registration, e.g.
3380 * for RADIUS and enterprises), so if not copied it is possible to use
3381 * it after freeing.
3383 * Should this be deprecated in favor of get_hostname_wmem so that
3384 * host name lookups don't increase persistent memory usage even when
3385 * hostname lookups are disabled? (An alternative would be to return
3386 * NULL when lookups are disabled, but callers don't expect that.)
3388 hashipv4_t *tp = host_lookup(addr);
3390 if (!gbl_resolv_flags.network_name)
3391 return tp->ip;
3393 tp->flags |= RESOLVED_ADDRESS_USED;
3395 return tp->name;
3398 char *
3399 get_hostname_wmem(wmem_allocator_t *allocator, const unsigned addr)
3401 if (!gbl_resolv_flags.network_name)
3402 return ip_addr_to_str(allocator, &addr);
3404 hashipv4_t *tp = host_lookup(addr);
3406 tp->flags |= RESOLVED_ADDRESS_USED;
3408 return wmem_strdup(allocator, tp->name);
3410 /* -------------------------- */
3412 const char *
3413 get_hostname6(const ws_in6_addr *addr)
3415 /* XXX why do we call this if we're not resolving? To create hash entries?
3416 * Why? The same comments as get_hostname above apply.
3418 hashipv6_t *tp = host_lookup6(addr);
3420 if (!gbl_resolv_flags.network_name)
3421 return tp->ip6;
3423 tp->flags |= RESOLVED_ADDRESS_USED;
3425 return tp->name;
3428 char *
3429 get_hostname6_wmem(wmem_allocator_t *allocator, const ws_in6_addr *addr)
3431 if (!gbl_resolv_flags.network_name)
3432 return ip6_to_str(allocator, addr);
3434 hashipv6_t *tp = host_lookup6(addr);
3436 tp->flags |= RESOLVED_ADDRESS_USED;
3438 return wmem_strdup(allocator, tp->name);
3440 /* -------------------------- */
3441 void
3442 add_ipv4_name(const unsigned addr, const char *name, bool static_entry)
3444 hashipv4_t *tp;
3447 * Don't add zero-length names; apparently, some resolvers will return
3448 * them if they get them from DNS.
3450 if (!name || name[0] == '\0')
3451 return;
3453 tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
3454 if (!tp) {
3455 tp = new_ipv4(addr);
3456 wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
3459 if (g_ascii_strcasecmp(tp->name, name) && (static_entry || !(tp->flags & STATIC_HOSTNAME))) {
3460 (void) g_strlcpy(tp->name, name, MAXDNSNAMELEN);
3461 new_resolved_objects = true;
3462 if (static_entry)
3463 tp->flags |= STATIC_HOSTNAME;
3465 tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
3466 } /* add_ipv4_name */
3468 /* -------------------------- */
3469 void
3470 add_ipv6_name(const ws_in6_addr *addrp, const char *name, const bool static_entry)
3472 hashipv6_t *tp;
3475 * Don't add zero-length names; apparently, some resolvers will return
3476 * them if they get them from DNS.
3478 if (!name || name[0] == '\0')
3479 return;
3481 tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addrp);
3482 if (!tp) {
3483 ws_in6_addr *addr_key;
3485 addr_key = wmem_new(addr_resolv_scope, ws_in6_addr);
3486 tp = new_ipv6(addrp);
3487 memcpy(addr_key, addrp, 16);
3488 wmem_map_insert(ipv6_hash_table, addr_key, tp);
3491 if (g_ascii_strcasecmp(tp->name, name) && (static_entry || !(tp->flags & STATIC_HOSTNAME))) {
3492 (void) g_strlcpy(tp->name, name, MAXDNSNAMELEN);
3493 new_resolved_objects = true;
3494 if (static_entry)
3495 tp->flags |= STATIC_HOSTNAME;
3497 tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
3498 } /* add_ipv6_name */
3500 static void
3501 add_manually_resolved_ipv4(void *key, void *value, void *user_data _U_)
3503 resolved_name_t *resolved_ipv4_entry = (resolved_name_t*)value;
3504 add_ipv4_name(GPOINTER_TO_UINT(key), resolved_ipv4_entry->name, true);
3507 static void
3508 add_manually_resolved_ipv6(void *key, void *value, void *user_data _U_)
3510 resolved_name_t *resolved_ipv6_entry = (resolved_name_t*)value;
3511 add_ipv6_name((ws_in6_addr*)key, resolved_ipv6_entry->name, true);
3514 static void
3515 add_manually_resolved(void)
3517 if (manually_resolved_ipv4_list) {
3518 wmem_map_foreach(manually_resolved_ipv4_list, add_manually_resolved_ipv4, NULL);
3521 if (manually_resolved_ipv6_list) {
3522 wmem_map_foreach(manually_resolved_ipv6_list, add_manually_resolved_ipv6, NULL);
3526 static void
3527 host_name_lookup_init(void)
3529 char *hostspath;
3530 unsigned i;
3532 ws_assert(ipxnet_hash_table == NULL);
3533 ipxnet_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
3535 ws_assert(ipv4_hash_table == NULL);
3536 ipv4_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
3538 ws_assert(ipv6_hash_table == NULL);
3539 ipv6_hash_table = wmem_map_new(addr_resolv_scope, ipv6_oat_hash, ipv6_equal);
3541 ws_assert(async_dns_queue_head == NULL);
3542 async_dns_queue_head = wmem_list_new(addr_resolv_scope);
3545 * The manually resolved lists are the only address resolution maps
3546 * that are not reset by addr_resolv_cleanup(), because they are
3547 * the only ones that do not have entries from personal configuration
3548 * files that can change when changing configurations. All their
3549 * entries must also be in epan scope.
3551 if (manually_resolved_ipv4_list == NULL)
3552 manually_resolved_ipv4_list = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
3554 if (manually_resolved_ipv6_list == NULL)
3555 manually_resolved_ipv6_list = wmem_map_new(wmem_epan_scope(), ipv6_oat_hash, ipv6_equal);
3558 * Load the global hosts file, if we have one.
3560 hostspath = get_datafile_path(ENAME_HOSTS);
3561 if (!read_hosts_file(hostspath, true) && errno != ENOENT) {
3562 report_open_failure(hostspath, errno, false);
3564 g_free(hostspath);
3566 * Load the user's hosts file no matter what, if they have one.
3568 hostspath = get_persconffile_path(ENAME_HOSTS, true);
3569 if (!read_hosts_file(hostspath, true) && errno != ENOENT) {
3570 report_open_failure(hostspath, errno, false);
3572 g_free(hostspath);
3573 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
3574 if (ares_library_init(ARES_LIB_INIT_ALL) == ARES_SUCCESS) {
3575 #endif
3576 /* XXX - Check which options we should set */
3577 if (ares_init_options(&ghba_chan, NULL, 0) == ARES_SUCCESS && ares_init_options(&ghbn_chan, NULL, 0) == ARES_SUCCESS) {
3578 async_dns_initialized = true;
3579 c_ares_set_dns_servers();
3581 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
3583 #endif
3585 if (extra_hosts_files) {
3586 for (i = 0; i < extra_hosts_files->len; i++) {
3587 read_hosts_file((const char *) g_ptr_array_index(extra_hosts_files, i), true);
3591 subnet_name_lookup_init();
3593 add_manually_resolved();
3595 ss7pc_name_lookup_init();
3598 static void
3599 host_name_lookup_cleanup(void)
3601 uint32_t i, j;
3602 sub_net_hashipv4_t *entry, *next_entry;
3604 _host_name_lookup_cleanup();
3606 ipxnet_hash_table = NULL;
3607 ipv4_hash_table = NULL;
3608 ipv6_hash_table = NULL;
3609 ss7pc_hash_table = NULL;
3611 for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
3612 if (subnet_length_entries[i].subnet_addresses != NULL) {
3613 for (j = 0; j < HASHHOSTSIZE; j++) {
3614 for (entry = subnet_length_entries[i].subnet_addresses[j];
3615 entry != NULL; entry = next_entry) {
3616 next_entry = entry->next;
3617 wmem_free(addr_resolv_scope, entry);
3620 wmem_free(addr_resolv_scope, subnet_length_entries[i].subnet_addresses);
3621 subnet_length_entries[i].subnet_addresses = NULL;
3625 have_subnet_entry = false;
3626 new_resolved_objects = false;
3630 void host_name_lookup_reset(void)
3632 addr_resolv_cleanup();
3633 addr_resolv_init();
3636 char *
3637 udp_port_to_display(wmem_allocator_t *allocator, unsigned port)
3640 if (!gbl_resolv_flags.transport_name) {
3641 return wmem_utoa(allocator, port);
3644 return wmem_strdup(allocator, serv_name_lookup(PT_UDP, port));
3646 } /* udp_port_to_display */
3648 char *
3649 dccp_port_to_display(wmem_allocator_t *allocator, unsigned port)
3652 if (!gbl_resolv_flags.transport_name) {
3653 return wmem_utoa(allocator, port);
3656 return wmem_strdup(allocator, serv_name_lookup(PT_DCCP, port));
3658 } /* dccp_port_to_display */
3660 char *
3661 tcp_port_to_display(wmem_allocator_t *allocator, unsigned port)
3664 if (!gbl_resolv_flags.transport_name) {
3665 return wmem_utoa(allocator, port);
3668 return wmem_strdup(allocator, serv_name_lookup(PT_TCP, port));
3670 } /* tcp_port_to_display */
3672 char *
3673 sctp_port_to_display(wmem_allocator_t *allocator, unsigned port)
3676 if (!gbl_resolv_flags.transport_name) {
3677 return wmem_utoa(allocator, port);
3680 return wmem_strdup(allocator, serv_name_lookup(PT_SCTP, port));
3682 } /* sctp_port_to_display */
3684 char *
3685 port_with_resolution_to_str(wmem_allocator_t *scope, port_type proto, unsigned port)
3687 const char *port_str;
3689 if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
3690 /* No name resolution support, just return port string */
3691 return wmem_strdup_printf(scope, "%u", port);
3693 port_str = serv_name_lookup(proto, port);
3694 ws_assert(port_str);
3695 return wmem_strdup_printf(scope, "%s (%u)", port_str, port);
3699 port_with_resolution_to_str_buf(char *buf, unsigned long buf_size, port_type proto, unsigned port)
3701 const char *port_str;
3703 if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
3704 /* No name resolution support, just return port string */
3705 return snprintf(buf, buf_size, "%u", port);
3707 port_str = serv_name_lookup(proto, port);
3708 ws_assert(port_str);
3709 return snprintf(buf, buf_size, "%s (%u)", port_str, port);
3712 const char *
3713 get_ether_name(const uint8_t *addr)
3715 hashether_t *tp;
3716 bool resolve = gbl_resolv_flags.mac_name;
3718 tp = eth_name_lookup(addr, resolve);
3720 return resolve ? tp->resolved_name : tp->hexaddr;
3722 } /* get_ether_name */
3724 const char *
3725 tvb_get_ether_name(tvbuff_t *tvb, int offset)
3727 return get_ether_name(tvb_get_ptr(tvb, offset, 6));
3730 /* Look for a (non-dummy) ether name in the hash, and return it if found.
3731 * If it's not found, simply return NULL.
3733 const char *
3734 get_ether_name_if_known(const uint8_t *addr)
3736 hashether_t *tp;
3738 /* Initialize ether structs if we're the first
3739 * ether-related function called */
3740 if (!gbl_resolv_flags.mac_name)
3741 return NULL;
3743 /* eth_name_lookup will create a (resolved) hash entry
3744 * if it doesn't exist, so it never returns NULL */
3745 tp = eth_name_lookup(addr, true);
3747 if ((tp->flags & (NAME_RESOLVED | NAME_RESOLVED_PREFIX)) == NAME_RESOLVED) {
3748 /* Name is from an exact match, not a prefix/OUI */
3749 return tp->resolved_name;
3751 else {
3752 /* Name was created */
3753 return NULL;
3757 void
3758 add_ether_byip(const unsigned ip, const uint8_t *eth)
3760 hashipv4_t *tp;
3762 /* first check that IP address can be resolved */
3763 if (!gbl_resolv_flags.network_name)
3764 return;
3766 tp = host_lookup(ip);
3769 * Was this IP address resolved to a host name?
3771 if (tp->flags & NAME_RESOLVED) {
3773 * Yes, so add an entry in the ethers hashtable resolving
3774 * the MAC address to that name.
3776 add_eth_name(eth, tp->name);
3779 } /* add_ether_byip */
3781 char *
3782 get_ipxnet_name(wmem_allocator_t *allocator, const uint32_t addr)
3785 if (!gbl_resolv_flags.network_name) {
3786 return ipxnet_to_str_punct(allocator, addr, '\0');
3789 return ipxnet_name_lookup(allocator, addr);
3791 } /* get_ipxnet_name */
3793 char *
3794 get_vlan_name(wmem_allocator_t *allocator, const uint16_t id)
3797 if (!gbl_resolv_flags.vlan_name) {
3798 return NULL;
3801 return wmem_strdup(allocator, vlan_name_lookup(id));
3803 } /* get_vlan_name */
3805 const char *
3806 get_manuf_name(const uint8_t *addr, size_t size)
3808 hashmanuf_t *manuf_value;
3810 ws_return_val_if(size < 3, NULL);
3812 manuf_value = manuf_name_lookup(addr, size);
3813 if (gbl_resolv_flags.mac_name && ((manuf_value->flags & NAME_RESOLVED) == NAME_RESOLVED))
3814 return manuf_value->resolved_name;
3816 return manuf_value->hexaddr;
3818 } /* get_manuf_name */
3820 const char *
3821 tvb_get_manuf_name(tvbuff_t *tvb, int offset)
3823 uint8_t buf[3] = { 0 };
3824 tvb_memcpy(tvb, buf, offset, 3);
3825 return get_manuf_name(buf, sizeof(buf));
3828 const char *
3829 get_manuf_name_if_known(const uint8_t *addr, size_t size)
3831 hashmanuf_t *manuf_value;
3833 ws_return_val_if(size < 3, NULL);
3835 manuf_value = manuf_name_lookup(addr, size);
3836 if (manuf_value != NULL && ((manuf_value->flags & NAME_RESOLVED) == NAME_RESOLVED)) {
3837 return manuf_value->resolved_longname;
3840 if (size >= 6) {
3841 /* Try the global manuf tables. */
3842 const char *short_name, *long_name;
3843 short_name = ws_manuf_lookup_str(addr, &long_name);
3844 if (short_name != NULL) {
3845 /* Found it */
3846 return long_name;
3850 return NULL;
3852 } /* get_manuf_name_if_known */
3854 const char *
3855 uint_get_manuf_name_if_known(const uint32_t manuf_key)
3857 uint8_t addr[6] = { 0 };
3858 addr[0] = (manuf_key >> 16) & 0xFF;
3859 addr[1] = (manuf_key >> 8) & 0xFF;
3860 addr[2] = manuf_key & 0xFF;
3862 return get_manuf_name_if_known(addr, sizeof(addr));
3865 const char *
3866 tvb_get_manuf_name_if_known(tvbuff_t *tvb, int offset)
3868 uint8_t buf[3] = { 0 };
3869 tvb_memcpy(tvb, buf, offset, 3);
3870 return get_manuf_name_if_known(buf, sizeof(buf));
3873 bool get_hash_manuf_used(hashmanuf_t* manuf)
3875 return ((manuf->flags & TRIED_OR_RESOLVED_MASK) == TRIED_OR_RESOLVED_MASK);
3878 char* get_hash_manuf_resolved_name(hashmanuf_t* manuf)
3880 return manuf->resolved_longname;
3883 char *
3884 eui64_to_display(wmem_allocator_t *allocator, const uint64_t addr_eui64)
3886 uint8_t *addr = (uint8_t *)wmem_alloc(NULL, 8);
3887 hashmanuf_t *manuf_value;
3888 char *ret;
3890 /* Copy and convert the address to network byte order. */
3891 *(uint64_t *)(void *)(addr) = pntoh64(&(addr_eui64));
3893 /* manuf_name_lookup returns a hashmanuf_t* that covers an entire /24,
3894 * so we can't properly use it for MA-M and MA-S. We do want to check
3895 * it first so it also covers the user-defined tables.
3897 manuf_value = manuf_name_lookup(addr, 8);
3898 if (!gbl_resolv_flags.mac_name || !manuf_value || ((manuf_value->flags & NAME_RESOLVED) == 0)) {
3899 /* Now try looking in the global manuf data for a MA-M or MA-S match.
3901 const char *short_name, *long_name;
3902 unsigned mask;
3903 short_name = ws_manuf_lookup(addr, &long_name, &mask);
3904 if (short_name != NULL) {
3905 switch (mask) {
3906 case 24:
3907 /* This shouldn't happen as it should be handled above. */
3908 manuf_hash_new_entry(addr, short_name, long_name);
3909 ret = wmem_strdup_printf(allocator, "%s_%02x:%02x:%02x:%02x:%02x", short_name, addr[3], addr[4], addr[5], addr[6], addr[7]);
3910 break;
3911 case 28:
3912 ret = wmem_strdup_printf(allocator, "%s_%01x:%02x:%02x:%02x:%02x", short_name, addr[3] & 0x0F, addr[4], addr[5], addr[6], addr[7]);
3913 break;
3914 case 36:
3915 ret = wmem_strdup_printf(allocator, "%s_%01x:%02x:%02x:%02x", short_name, addr[4] & 0x0F, addr[5], addr[6], addr[7]);
3916 break;
3917 default:
3918 /* Doesn't happen, ignore for now. */
3919 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]);
3920 break;
3922 } else {
3923 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]);
3925 } else {
3926 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]);
3929 wmem_free(NULL, addr);
3930 return ret;
3931 } /* eui64_to_display */
3933 #define GHI_TIMEOUT (250 * 1000)
3934 static void
3935 c_ares_ghi_cb(void *arg, int status, int timeouts _U_, struct hostent *hp) {
3937 * XXX - If we wanted to be really fancy we could cache results here and
3938 * look them up in get_host_ipaddr* below.
3940 * XXX - This only gets the first host address if there's more than one.
3942 async_hostent_t *ahp = (async_hostent_t *)arg;
3943 if (status == ARES_SUCCESS && hp && ahp && hp->h_length == ahp->addr_size) {
3944 memcpy(ahp->addrp, hp->h_addr, hp->h_length);
3945 ahp->copied = hp->h_length;
3949 /* Translate a string, assumed either to be a dotted-quad IPv4 address or
3950 * a host name, to a numeric IPv4 address. Return true if we succeed and
3951 * set "*addrp" to that numeric IPv4 address; return false if we fail. */
3952 bool
3953 get_host_ipaddr(const char *host, uint32_t *addrp)
3955 struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
3956 int nfds;
3957 fd_set rfds, wfds;
3958 async_hostent_t ahe;
3961 * XXX - are there places where this is used to translate something
3962 * that's *only* supposed to be an IPv4 address, and where it
3963 * *shouldn't* translate host names?
3965 if (!ws_inet_pton4(host, addrp)) {
3967 /* It's not a valid dotted-quad IP address; is it a valid
3968 * host name?
3971 /* If we're not allowed to do name resolution, don't do name
3972 * resolution...
3973 * XXX - What if we're allowed to do name resolution, and the name
3974 * is in a DNS packet we've dissected or in a Name Resolution Block,
3975 * or a user-entered manual name resolution?
3977 if (!gbl_resolv_flags.network_name ||
3978 !gbl_resolv_flags.use_external_net_name_resolver) {
3979 return false;
3982 if (!async_dns_initialized || name_resolve_concurrency < 1) {
3983 return false;
3985 ahe.addr_size = (int) sizeof (struct in_addr);
3986 ahe.copied = 0;
3987 ahe.addrp = addrp;
3988 ares_gethostbyname(ghbn_chan, host, AF_INET, c_ares_ghi_cb, &ahe);
3989 FD_ZERO(&rfds);
3990 FD_ZERO(&wfds);
3991 nfds = ares_fds(ghbn_chan, &rfds, &wfds);
3992 if (nfds > 0) {
3993 tvp = ares_timeout(ghbn_chan, &tv, &tv);
3994 if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
3995 /* If it's interrupted by a signal, no need to put out a message */
3996 if (errno != EINTR)
3997 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
3998 return false;
4000 ares_process(ghbn_chan, &rfds, &wfds);
4002 ares_cancel(ghbn_chan);
4003 if (ahe.addr_size == ahe.copied) {
4004 return true;
4006 return false;
4009 return true;
4013 * Translate IPv6 numeric address or FQDN hostname into binary IPv6 address.
4014 * Return true if we succeed and set "*addrp" to that numeric IPv6 address;
4015 * return false if we fail.
4017 bool
4018 get_host_ipaddr6(const char *host, ws_in6_addr *addrp)
4020 struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
4021 int nfds;
4022 fd_set rfds, wfds;
4023 async_hostent_t ahe;
4025 if (str_to_ip6(host, addrp))
4026 return true;
4028 /* It's not a valid dotted-quad IP address; is it a valid
4029 * host name?
4031 * XXX - are there places where this is used to translate something
4032 * that's *only* supposed to be an IPv6 address, and where it
4033 * *shouldn't* translate host names?
4036 /* If we're not allowed to do name resolution, don't do name
4037 * resolution...
4038 * XXX - What if we're allowed to do name resolution, and the name
4039 * is in a DNS packet we've dissected or in a Name Resolution Block,
4040 * or a user-entered manual name resolution?
4042 if (!gbl_resolv_flags.network_name ||
4043 !gbl_resolv_flags.use_external_net_name_resolver) {
4044 return false;
4047 /* try FQDN */
4048 if (!async_dns_initialized || name_resolve_concurrency < 1) {
4049 return false;
4051 ahe.addr_size = (int) sizeof (ws_in6_addr);
4052 ahe.copied = 0;
4053 ahe.addrp = addrp;
4054 ares_gethostbyname(ghbn_chan, host, AF_INET6, c_ares_ghi_cb, &ahe);
4055 FD_ZERO(&rfds);
4056 FD_ZERO(&wfds);
4057 nfds = ares_fds(ghbn_chan, &rfds, &wfds);
4058 if (nfds > 0) {
4059 tvp = ares_timeout(ghbn_chan, &tv, &tv);
4060 if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
4061 /* If it's interrupted by a signal, no need to put out a message */
4062 if (errno != EINTR)
4063 fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
4064 return false;
4066 ares_process(ghbn_chan, &rfds, &wfds);
4068 ares_cancel(ghbn_chan);
4069 if (ahe.addr_size == ahe.copied) {
4070 return true;
4073 return false;
4076 wmem_map_t *
4077 get_manuf_hashtable(void)
4079 return manuf_hashtable;
4082 wmem_map_t *
4083 get_wka_hashtable(void)
4085 return wka_hashtable;
4088 wmem_map_t *
4089 get_eth_hashtable(void)
4091 return eth_hashtable;
4094 wmem_map_t *
4095 get_serv_port_hashtable(void)
4097 return serv_port_hashtable;
4100 wmem_map_t *
4101 get_ipxnet_hash_table(void)
4103 return ipxnet_hash_table;
4106 wmem_map_t *
4107 get_vlan_hash_table(void)
4109 return vlan_hash_table;
4112 wmem_map_t *
4113 get_ipv4_hash_table(void)
4115 return ipv4_hash_table;
4118 wmem_map_t *
4119 get_ipv6_hash_table(void)
4121 return ipv6_hash_table;
4123 /* Initialize all the address resolution subsystems in this file */
4124 void
4125 addr_resolv_init(void)
4127 ws_assert(addr_resolv_scope == NULL);
4128 addr_resolv_scope = wmem_allocator_new(WMEM_ALLOCATOR_BLOCK);
4129 initialize_services();
4130 initialize_ethers();
4131 initialize_ipxnets();
4132 initialize_vlans();
4133 initialize_enterprises();
4134 host_name_lookup_init();
4137 /* Clean up all the address resolution subsystems in this file */
4138 void
4139 addr_resolv_cleanup(void)
4141 vlan_name_lookup_cleanup();
4142 service_name_lookup_cleanup();
4143 ethers_cleanup();
4144 ipx_name_lookup_cleanup();
4145 enterprises_cleanup();
4146 host_name_lookup_cleanup();
4148 wmem_destroy_allocator(addr_resolv_scope);
4149 addr_resolv_scope = NULL;
4152 bool
4153 str_to_ip(const char *str, void *dst)
4155 return ws_inet_pton4(str, (uint32_t *)dst);
4158 bool
4159 str_to_ip6(const char *str, void *dst)
4161 return ws_inet_pton6(str, (ws_in6_addr *)dst);
4165 * convert a 0-terminated string that contains an ethernet address into
4166 * the corresponding sequence of 6 bytes
4167 * eth_bytes is a buffer >= 6 bytes that was allocated by the caller
4169 bool
4170 str_to_eth(const char *str, char *eth_bytes)
4172 ether_t eth;
4174 if (!parse_ether_address(str, &eth, NULL, false))
4175 return false;
4177 memcpy(eth_bytes, eth.addr, sizeof(eth.addr));
4178 return true;
4182 * Editor modelines - https://www.wireshark.org/tools/modelines.html
4184 * Local variables:
4185 * c-basic-offset: 4
4186 * tab-width: 8
4187 * indent-tabs-mode: nil
4188 * End:
4190 * vi: set shiftwidth=4 tabstop=8 expandtab:
4191 * :indentSize=4:tabSize=8:noTabs=true: