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
23 #include <wsutil/strtoi.h>
24 #include <wsutil/ws_assert.h>
26 #include "enterprises.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>
67 #ifdef HAVE_SYS_SOCKET_H
68 #include <sys/socket.h> /* needed to define AF_ values on UNIX */
72 #include <winsock2.h> /* needed to define AF_ values on Windows */
77 # define socklen_t unsigned int
80 #include <ares_version.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>
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
{
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 */
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
{
145 struct hashipxnet
*next
;
146 char name
[MAXNAMELEN
];
149 typedef struct hashvlan
{
151 /* struct hashvlan *next; */
152 char name
[MAXVLANNAMELEN
];
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
];
161 /* hash tables used for ethernet and manufacturer lookup */
163 uint8_t flags
; /* (See above) */
166 char resolved_name
[MAXNAMELEN
];
170 uint8_t flags
; /* (See above) */
175 uint8_t flags
; /* (See above) */
178 char resolved_name
[MAXNAMELEN
];
179 char resolved_longname
[MAXNAMELEN
];
182 /* internal ethernet type */
183 typedef struct _ether
186 char name
[MAXNAMELEN
];
187 char longname
[MAXNAMELEN
];
190 /* internal ipxnet type */
191 typedef struct _ipxnet
194 char name
[MAXNAMELEN
];
197 /* internal vlan type */
201 char name
[MAXVLANNAMELEN
];
204 /* internal services custom type */
205 typedef struct _serv_port_custom_key
{
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
{
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
261 ipv6_oat_hash(const void *key
)
264 const unsigned char *p
= (const unsigned char *)key
;
268 for ( i
= 0; i
< len
; i
++ ) {
282 ipv6_equal(const void *v1
, const void *v2
)
285 if (memcmp(v1
, v2
, sizeof (ws_in6_addr
)) == 0) {
293 * Flag controlling what names to resolve.
295 e_addr_resolve gbl_resolv_flags
= {
297 false, /* network_name */
298 false, /* transport_name */
299 true, /* dns_pkt_addr_resolution */
300 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
348 } async_dns_queue_msg_t
;
350 typedef struct _async_hostent
{
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
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
{
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
;
399 dns_server_free_cb(void *data
)
401 struct dns_server_data
*h
= (struct dns_server_data
*)data
;
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
;
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
)) {
428 *err
= ws_strdup_printf("No valid IP address given.");
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.
441 if (strcmp(p
, "53") != 0){
443 if (!ws_strtou16(p
, NULL
, &port
)) {
444 *err
= g_strdup("Invalid port given.");
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
;
458 if (status
== ARES_SUCCESS
) {
459 for (p
= he
->h_addr_list
; *p
!= NULL
; p
++) {
460 switch(sdd
->family
) {
462 add_ipv4_name(sdd
->addr
.ip4
, he
->h_name
, false);
465 add_ipv6_name(&sdd
->addr
.ip6
, he
->h_name
, false);
468 /* Throw an exception? */
476 * Let our caller know that this is complete.
478 *sdd
->completed
= true;
481 * Free the structure for this call.
487 wait_for_sync_resolv(bool *completed
) {
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
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*
519 nfds
= ares_fds(ghba_chan
, &rfds
, &wfds
);
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 */
524 fprintf(stderr
, "Warning: call to select() failed, error is %s\n", g_strerror(errno
));
527 ares_process(ghba_chan
, &rfds
, &wfds
);
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
)
541 if (!g_mutex_trylock(&async_dns_queue_mtx
))
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
);
566 wait_for_async_queue(void)
568 struct timeval tv
= { 0, 0 };
572 new_resolved_objects
= false;
574 if (!async_dns_initialized
) {
575 maxmind_db_lookup_process();
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();
588 nfds
= ares_fds(ghba_chan
, &rfds
, &wfds
);
590 /* No more requests waiting for reply; we're done here. */
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().
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 */
604 fprintf(stderr
, "Warning: call to select() failed, error is %s\n", g_strerror(errno
));
607 ares_process(ghba_chan
, &rfds
, &wfds
);
610 maxmind_db_lookup_process();
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.
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
);
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.
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
);
673 set_resolution_synchrony(bool synchronous
)
675 resolve_synchronously
= synchronous
;
676 maxmind_db_set_synchrony(synchronous
);
679 wait_for_async_queue();
684 c_ares_set_dns_servers(void)
686 if ((!async_dns_initialized
) || (!use_custom_dns_server_list
))
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
);
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
;
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);
708 //This shouldn't happen, but just in case...
709 invalid_IP_found
= true;
711 memset(&server
->addr
.addr4
, 0, 4);
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);
729 //This shouldn't happen, but just in case...
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
;
739 ares_set_servers_ports(ghba_chan
, servers
);
740 ares_set_servers_ports(ghbn_chan
, servers
);
741 wmem_free(NULL
, servers
);
748 const char* name
; /* Shallow copy */
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. */
756 fgetline(char *buf
, int size
, FILE *fp
)
758 if (fgets(buf
, size
, fp
)) {
759 int len
= (int)strcspn(buf
, "\r\n");
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
);
789 add_custom_service_name(port_type proto
, const unsigned port
, const char *service_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
;
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;
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.
827 serv_port_names
->tcp_name
= service_name
;
830 serv_port_names
->udp_name
= service_name
;
833 serv_port_names
->sctp_name
= service_name
;
836 serv_port_names
->dccp_name
= service_name
;
839 return serv_port_names
;
840 /* Should not happen */
843 new_resolved_objects
= true;
844 return serv_port_names
;
848 parse_service_line (char *line
)
854 struct cb_serv_data cb_data
;
855 range_t
*port_rng
= NULL
;
857 if ((cp
= strchr(line
, '#')))
860 if ((cp
= strtok(line
, " \t")) == NULL
)
865 if ((cp
= strtok(NULL
, " \t")) == NULL
)
870 if (strtok(cp
, "/") == NULL
)
873 if (range_convert_str(NULL
, &port_rng
, port
, UINT16_MAX
) != CVT_NO_ERROR
) {
874 wmem_free (NULL
, port_rng
);
878 while ((cp
= strtok(NULL
, "/")) != NULL
) {
879 if (strcmp(cp
, "tcp") == 0) {
882 else if (strcmp(cp
, "udp") == 0) {
885 else if (strcmp(cp
, "sctp") == 0) {
888 else if (strcmp(cp
, "dccp") == 0) {
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 */
904 add_serv_port_cb(const uint32_t port
, void *ptr
)
906 struct cb_serv_data
*cb_data
= (struct cb_serv_data
*)ptr
;
909 add_custom_service_name(cb_data
->proto
, port
, cb_data
->service
);
915 parse_services_file(const char * path
)
918 char buf
[MAX_LINELEN
];
920 /* services hash table initialization */
921 serv_p
= ws_fopen(path
, "r");
926 while (fgetline(buf
, sizeof(buf
), serv_p
) >= 0) {
927 parse_service_line(buf
);
935 * unsigned integer to ascii
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
);
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
);
965 /* now look in the global tables */
966 bool valid_proto
= true;
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;
975 serv
= global_services_lookup(port
, p
);
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
)
995 return serv_port_names
->udp_name
;
997 return serv_port_names
->tcp_name
;
999 return serv_port_names
->sctp_name
;
1001 return serv_port_names
->dccp_name
;
1009 try_serv_name_lookup(port_type proto
, unsigned port
)
1011 return (proto
== PT_NONE
) ? NULL
: _serv_name_lookup(proto
, port
, NULL
);
1015 serv_name_lookup(port_type proto
, unsigned port
)
1017 serv_port_t
*serv_port_names
= NULL
;
1020 /* first look for the name */
1021 name
= _serv_name_lookup(proto
, port
, &serv_port_names
);
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
;
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
);
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
;
1076 parse_enterprises_line (char *line
)
1078 char *tok
, *dec_str
, *org_str
;
1080 bool had_comment
= false;
1082 /* Stop the line at any comment found */
1083 if ((tok
= strchr(line
, '#'))) {
1087 /* Get enterprise number */
1088 dec_str
= strtok(line
, " \t");
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
);
1100 /* Add entry using number as key */
1101 if (!ws_strtou32(dec_str
, NULL
, &dec
))
1103 g_hash_table_insert(enterprises_hashtable
, GUINT_TO_POINTER(dec
), g_strdup(org_str
));
1108 parse_enterprises_file(const char * path
)
1111 char buf
[MAX_LINELEN
];
1113 fp
= ws_fopen(path
, "r");
1117 while (fgetline(buf
, sizeof(buf
), fp
) >= 0) {
1118 parse_enterprises_line(buf
);
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
);
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
));
1158 return global_enterprises_lookup(value
);
1163 enterprises_lookup(uint32_t value
, const char *unknown_str
)
1167 s
= try_enterprises_lookup(value
);
1170 if (unknown_str
!= NULL
)
1176 enterprises_base_custom(char *buf
, uint32_t value
)
1180 if ((s
= try_enterprises_lookup(value
)) == NULL
)
1181 s
= ITEM_LABEL_UNKNOWN_STR
;
1182 snprintf(buf
, ITEM_LABEL_LENGTH
, "%s (%u)", s
, value
);
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.
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 */
1215 char buffer
[WS_INET_ADDRSTRLEN
];
1219 host_addr
= addr
& (~subnet_entry
.mask
);
1220 ip_addr_to_str_buf(&host_addr
, buffer
, WS_INET_ADDRSTRLEN
);
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?),
1228 i
= subnet_entry
.mask_length
/ 8;
1229 while(*(paddr
) != '\0' && i
> 0) {
1230 if (*(++paddr
) == '.') {
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;
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.
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
);
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
;
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
) {
1287 add_ipv4_name(caqm
->addr
.ip4
, he
->h_name
, false);
1290 add_ipv6_name(&caqm
->addr
.ip6
, he
->h_name
, false);
1293 /* Throw an exception? */
1298 wmem_free(addr_resolv_scope
, caqm
);
1301 /* --------------- */
1303 new_ipv4(const unsigned addr
)
1305 hashipv4_t
*tp
= wmem_new(addr_resolv_scope
, hashipv4_t
);
1309 ip_addr_to_str_buf(&addr
, tp
->ip
, sizeof(tp
->ip
));
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
));
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
) {
1332 * This hasn't been resolved yet, and we haven't tried to
1333 * resolve it already.
1336 if (!gbl_resolv_flags
.network_name
)
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
1350 sync_lookup_ip4(addr
);
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
);
1371 /* --------------- */
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
);
1379 ip6_to_str_buf(addr
, tp
->ip6
, sizeof(tp
->ip6
));
1383 /* ------------------------------------ */
1385 host_lookup6(const ws_in6_addr
*addr
)
1387 hashipv6_t
* volatile tp
;
1389 tp
= (hashipv6_t
*)wmem_map_lookup(ipv6_hash_table
, addr
);
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);
1401 wmem_map_insert(ipv6_hash_table
, addr_key
, tp
);
1402 } else if (tp
->flags
& TRIED_OR_RESOLVED_MASK
) {
1407 * This hasn't been resolved yet, and we haven't tried to
1408 * resolve it already.
1411 if (!gbl_resolv_flags
.network_name
)
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
1425 sync_lookup_ip6(addr
);
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
);
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).
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.
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.
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. */
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. */
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). */
1526 } else if (cp
[8] != sep
|| !accept_mask
) {
1527 /* Format not handled by this fast path. */
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. */
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). */
1548 } else if (cp
[17] != '/' || cp
[20] != '\0') {
1549 /* Format not handled by this fast path. */
1555 if (m1
== '3' && m2
== '6') { /* Mask /36 */
1556 eth
->addr
[4] &= 0xf0;
1561 if (m1
== '2' && m2
== '8') { /* Mask /28 */
1562 eth
->addr
[3] &= 0xf0;
1568 /* Unsupported mask */
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
1579 parse_ether_address(const char *cp
, ether_t
*eth
, unsigned int *mask
,
1580 const bool accept_mask
)
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
))
1591 num
= strtoul(cp
, &p
, 16);
1593 return false; /* failed */
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? */
1601 /* "/" - this has a mask. */
1603 /* Entries with masks are not allowed in this file. */
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);
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 */
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
));
1624 /* Mask out completely-masked-out octets */
1630 /* We're at the end of the address, and there's no mask. */
1632 /* We got 3 bytes, so this is a manufacturer ID. */
1634 /* Manufacturer IDs are not allowed in this file */
1637 /* Indicate that this is a manufacturer ID (0 is not allowed
1644 /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1650 /* We didn't get 3 or 6 bytes, and there's no mask; this is
1655 /* We don't know the separator used in this number; it can either
1656 be ':', '-', or '.'. */
1657 if (*cp
!= ':' && *cp
!= '-' && *cp
!= '.')
1659 sep
= *cp
; /* subsequent separators must be the same */
1661 /* It has to be the same as the first separator */
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.
1685 line
= g_strstrip(line
);
1686 if (line
[0] == '\0' || line
[0] == '#')
1689 if ((cp
= strchr(line
, '#'))) {
1694 if ((cp
= strtok(line
, " \t")) == NULL
)
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
))
1704 if ((cp
= strtok(NULL
, " \t")) == NULL
)
1707 (void) g_strlcpy(eth
->name
, cp
, MAXNAMELEN
);
1709 if ((cp
= strtok(NULL
, "\t")) != NULL
)
1711 (void) g_strlcpy(eth
->longname
, cp
, MAXNAMELEN
);
1713 /* Make the long name the short name */
1714 (void) g_strlcpy(eth
->longname
, eth
->name
, MAXNAMELEN
);
1719 } /* parse_ether_line */
1724 set_ethent(char *path
)
1729 eth_p
= ws_fopen(path
, "r");
1742 get_ethent(unsigned int *mask
, const bool accept_mask
)
1746 char buf
[MAX_LINELEN
];
1751 while (fgetline(buf
, sizeof(buf
), eth_p
) >= 0) {
1752 if (parse_ether_line(buf
, ð
, mask
, accept_mask
) == 0) {
1762 get_ethbyaddr(const uint8_t *addr
)
1767 set_ethent(g_pethers_path
);
1769 while (((eth
= get_ethent(NULL
, false)) != NULL
) && memcmp(addr
, eth
->addr
, 6) != 0)
1775 set_ethent(g_ethers_path
);
1777 while (((eth
= get_ethent(NULL
, false)) != NULL
) && memcmp(addr
, eth
->addr
, 6) != 0)
1785 } /* get_ethbyaddr */
1787 static hashmanuf_t
*
1788 manuf_hash_new_entry(const uint8_t *addr
, const char* name
, const char* longname
)
1791 hashmanuf_t
*manuf_value
;
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);
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
);
1806 (void) g_strlcpy(manuf_value
->resolved_longname
, name
, MAXNAMELEN
);
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
), ':');
1818 wmem_map_insert(manuf_hashtable
, GUINT_TO_POINTER(manuf_key
), manuf_value
);
1823 wka_hash_new_entry(const uint8_t *addr
, char* name
)
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
);
1840 add_manuf_name(const uint8_t *addr
, unsigned int mask
, char *name
, char *longname
)
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
;
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
;
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
;
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
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
1882 static hashmanuf_t
*
1883 manuf_name_lookup(const uint8_t *addr
, size_t size _U_
)
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;
1895 manuf_key
= manuf_key
| oct
;
1896 manuf_key
= manuf_key
<<8;
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
;
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
;
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
) {
1928 manuf_value
= manuf_hash_new_entry(addr
, short_name
, long_name
);
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
;
1937 } /* manuf_name_lookup */
1940 wka_name_lookup(const uint8_t *addr
, const unsigned int mask
)
1942 uint8_t masked_addr
[6];
1947 if (wka_hashtable
== 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
));
1956 /* Zero out completely-masked-out octets */
1960 value
= (hashwka_t
*)wmem_map_lookup(wka_hashtable
, masked_addr
);
1963 value
->flags
|= TRIED_RESOLVE_ADDRESS
;
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
)
2002 eth_addr_hash(const void *key
)
2004 return wmem_strong_hash((const uint8_t *)key
, 6);
2008 eth_addr_cmp(const void *a
, const void *b
)
2010 return (memcmp(a
, b
, 6) == 0);
2014 initialize_ethers(void)
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
);
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
);
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
);
2085 } /* initialize_ethers */
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
;
2106 eth_resolved_name_fill(hashether_t
*tp
, const char *name
, unsigned mask
, const uint8_t *addr
)
2110 snprintf(tp
->resolved_name
, MAXNAMELEN
, "%s_%02x:%02x:%02x",
2111 name
, addr
[3], addr
[4], addr
[5]);
2114 snprintf(tp
->resolved_name
, MAXNAMELEN
, "%s_%01x:%02x:%02x",
2115 name
, addr
[3] & 0x0F, addr
[4], addr
[5]);
2118 snprintf(tp
->resolved_name
, MAXNAMELEN
, "%s_%01x:%02x",
2119 name
, addr
[4] & 0x0F, addr
[5]);
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;
2130 pos
+= snprintf(tp
->resolved_name
+ pos
, MAXNAMELEN
- pos
,
2131 bitmask
>= 4 ? "_%01x" : "_%02x",
2132 addr
[bytes
] & (0xFF >> bitmask
));
2137 if (pos
>= MAXNAMELEN
) return;
2138 pos
+= snprintf(tp
->resolved_name
+ pos
, MAXNAMELEN
- pos
, ":%02x",
2146 /* Resolve ethernet address */
2147 static hashether_t
*
2148 eth_addr_resolve(hashether_t
*tp
) {
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
;
2158 } else if (!(tp
->flags
& NAME_RESOLVED
)) {
2163 /* Unknown name. Try looking for it in the well-known-address
2164 tables for well-known address ranges smaller than 2^24. */
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
;
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
;
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
;
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
;
2207 /* Now try looking for it in the well-known-address
2208 tables for well-known address ranges larger than 2^24. */
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],
2216 tp
->flags
|= NAME_RESOLVED
| NAME_RESOLVED_PREFIX
;
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],
2228 tp
->flags
|= NAME_RESOLVED
| NAME_RESOLVED_PREFIX
;
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
;
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
2249 const char *short_name
, *long_name
;
2250 short_name
= ws_manuf_lookup(addr
, &long_name
, &mask
);
2251 if (short_name
!= NULL
) {
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
;
2262 /* No match whatsoever. */
2263 set_address(ðer_addr
, AT_ETHER
, 6, addr
);
2264 address_to_str_buf(ðer_addr
, tp
->resolved_name
, MAXNAMELEN
);
2268 } /* eth_addr_resolve */
2270 static hashether_t
*
2271 eth_hash_new_entry(const uint8_t *addr
, const bool resolve
)
2276 tp
= wmem_new(addr_resolv_scope
, hashether_t
);
2277 memcpy(tp
->addr
, addr
, sizeof(tp
->addr
));
2279 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
2280 endp
= bytes_to_hexstr_punct(tp
->hexaddr
, addr
, sizeof(tp
->addr
), ':');
2282 tp
->resolved_name
[0] = '\0';
2285 eth_addr_resolve(tp
);
2287 wmem_map_insert(eth_hashtable
, tp
->addr
, tp
);
2290 } /* eth_hash_new_entry */
2292 static hashether_t
*
2293 add_eth_name(const uint8_t *addr
, const char *name
)
2297 tp
= (hashether_t
*)wmem_map_lookup(eth_hashtable
, addr
);
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;
2310 } /* add_eth_name */
2312 static hashether_t
*
2313 eth_name_lookup(const uint8_t *addr
, const bool resolve
)
2317 tp
= (hashether_t
*)wmem_map_lookup(eth_hashtable
, addr
);
2320 tp
= eth_hash_new_entry(addr
, resolve
);
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 */
2332 tp
->flags
|= TRIED_RESOLVE_ADDRESS
;
2337 } /* eth_name_lookup */
2342 parse_ipxnets_line(char *line
, ipxnet_t
*ipxnet
)
2345 * We allow three address separators (':', '-', and '.'),
2346 * as well as no separators
2350 uint32_t a
, a0
, a1
, a2
, a3
;
2351 bool found_single_number
= false;
2353 if ((cp
= strchr(line
, '#')))
2356 if ((cp
= strtok(line
, " \t\n")) == NULL
)
2359 /* Either fill a0,a1,a2,a3 and found_single_number is false,
2360 * fill a and found_single_number is true,
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;
2376 if ((cp
= strtok(NULL
, " \t\n")) == NULL
)
2379 if (found_single_number
) {
2383 ipxnet
->addr
= (a0
<< 24) | (a1
<< 16) | (a2
<< 8) | a3
;
2386 (void) g_strlcpy(ipxnet
->name
, cp
, MAXNAMELEN
);
2390 } /* parse_ipxnets_line */
2392 static FILE *ipxnet_p
;
2395 set_ipxnetent(char *path
)
2400 ipxnet_p
= ws_fopen(path
, "r");
2416 static ipxnet_t ipxnet
;
2417 char buf
[MAX_LINELEN
];
2419 if (ipxnet_p
== NULL
)
2422 while (fgetline(buf
, sizeof(buf
), ipxnet_p
) >= 0) {
2423 if (parse_ipxnets_line(buf
, &ipxnet
) == 0) {
2430 } /* get_ipxnetent */
2433 get_ipxnetbyaddr(uint32_t addr
)
2437 set_ipxnetent(g_ipxnets_path
);
2439 while (((ipxnet
= get_ipxnetent()) != NULL
) && (addr
!= ipxnet
->addr
) ) ;
2441 if (ipxnet
== NULL
) {
2444 set_ipxnetent(g_pipxnets_path
);
2446 while (((ipxnet
= get_ipxnetent()) != NULL
) && (addr
!= ipxnet
->addr
) )
2454 } /* get_ipxnetbyaddr */
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 */
2486 ipx_name_lookup_cleanup(void)
2488 g_ipxnets_path
= NULL
;
2489 g_free(g_pipxnets_path
);
2490 g_pipxnets_path
= NULL
;
2494 ipxnet_name_lookup(wmem_allocator_t
*allocator
, const unsigned addr
)
2499 tp
= (hashipxnet_t
*)wmem_map_lookup(ipxnet_hash_table
, GUINT_TO_POINTER(addr
));
2501 tp
= wmem_new(addr_resolv_scope
, hashipxnet_t
);
2502 wmem_map_insert(ipxnet_hash_table
, GUINT_TO_POINTER(addr
), tp
);
2504 return wmem_strdup(allocator
, tp
->name
);
2507 /* fill in a new entry */
2511 if ( (ipxnet
= get_ipxnetbyaddr(addr
)) == NULL
) {
2513 snprintf(tp
->name
, MAXNAMELEN
, "%X", addr
);
2516 (void) g_strlcpy(tp
->name
, ipxnet
->name
, MAXNAMELEN
);
2519 return wmem_strdup(allocator
, tp
->name
);
2521 } /* ipxnet_name_lookup */
2525 parse_vlan_line(char *line
, vlan_t
*vlan
)
2530 if ((cp
= strchr(line
, '#')))
2533 if ((cp
= strtok(line
, " \t\n")) == NULL
)
2536 if (sscanf(cp
, "%" SCNu16
, &id
) == 1) {
2543 if ((cp
= strtok(NULL
, "\t\n")) == NULL
)
2546 (void) g_strlcpy(vlan
->name
, cp
, MAXVLANNAMELEN
);
2550 } /* parse_vlan_line */
2552 static FILE *vlan_p
;
2555 set_vlanent(char *path
)
2560 vlan_p
= ws_fopen(path
, "r");
2577 char buf
[MAX_LINELEN
];
2582 while (fgetline(buf
, sizeof(buf
), vlan_p
) >= 0) {
2583 if (parse_vlan_line(buf
, &vlan
) == 0) {
2593 get_vlannamebyid(uint16_t id
)
2597 set_vlanent(g_pvlan_path
);
2599 while (((vlan
= get_vlanent()) != NULL
) && (id
!= vlan
->id
) ) ;
2608 } /* get_vlannamebyid */
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 */
2630 vlan_name_lookup_cleanup(void)
2633 vlan_hash_table
= NULL
;
2634 g_free(g_pvlan_path
);
2635 g_pvlan_path
= NULL
;
2639 vlan_name_lookup(const unsigned id
)
2644 tp
= (hashvlan_t
*)wmem_map_lookup(vlan_hash_table
, GUINT_TO_POINTER(id
));
2646 tp
= wmem_new(addr_resolv_scope
, hashvlan_t
);
2647 wmem_map_insert(vlan_hash_table
, GUINT_TO_POINTER(id
), tp
);
2652 /* fill in a new entry */
2656 if ( (vlan
= get_vlannamebyid(id
)) == NULL
) {
2658 snprintf(tp
->name
, MAXVLANNAMELEN
, "<%u>", id
);
2661 (void) g_strlcpy(tp
->name
, vlan
->name
, MAXVLANNAMELEN
);
2666 } /* vlan_name_lookup */
2670 read_hosts_file (const char *hostspath
, bool store_entries
)
2673 char line
[MAX_LINELEN
];
2677 ws_in6_addr ip6_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
)
2688 while (fgetline(line
, sizeof(line
), hf
) >= 0) {
2689 if ((cp
= strchr(line
, '#')))
2692 if ((cp
= strtok(line
, " \t")) == NULL
)
2693 continue; /* no tokens in the line */
2695 if (ws_inet_pton6(cp
, &host_addr
.ip6_addr
)) {
2698 } else if (ws_inet_pton4(cp
, &host_addr
.ip4_addr
)) {
2705 if ((cp
= strtok(NULL
, " \t")) == NULL
)
2706 continue; /* no host name */
2709 if (store_entries
) {
2711 add_ipv6_name(&host_addr
.ip6_addr
, cp
, true);
2713 add_ipv4_name(host_addr
.ip4_addr
, cp
, true);
2719 return entry_found
? true : false;
2720 } /* read_hosts_file */
2723 add_hosts_file (const char *hosts_file
)
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)
2740 g_ptr_array_add(extra_hosts_files
, wmem_strdup(addr_resolv_scope
, hosts_file
));
2741 return read_hosts_file (hosts_file
, false);
2747 add_ip_name_from_string (const char *addr
, const char *name
)
2751 ws_in6_addr ip6_addr
;
2754 resolved_name_t
*resolved_entry
;
2756 if (ws_inet_pton6(addr
, &host_addr
.ip6_addr
)) {
2758 } else if (ws_inet_pton4(addr
, &host_addr
.ip4_addr
)) {
2765 resolved_entry
= (resolved_name_t
*)wmem_map_lookup(manually_resolved_ipv6_list
, &host_addr
.ip6_addr
);
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
);
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
);
2783 resolved_entry
= (resolved_name_t
*)wmem_map_lookup(manually_resolved_ipv4_list
, GUINT_TO_POINTER(host_addr
.ip4_addr
));
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
);
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
);
2800 } /* add_ip_name_from_string */
2802 extern resolved_name_t
* get_edited_resolved_name(const char* 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
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
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
);
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.
2875 read_subnets_file (const char *subnetspath
)
2878 char line
[MAX_LINELEN
];
2880 uint32_t host_addr
; /* IPv4 ONLY */
2881 uint8_t mask_length
;
2883 if ((hf
= ws_fopen(subnetspath
, "r")) == NULL
)
2886 while (fgetline(line
, sizeof(line
), hf
) >= 0) {
2887 if ((cp
= strchr(line
, '#')))
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
, '/');
2900 *cp2
= '\0'; /* Cut token */
2903 /* Check if this is a valid IPv4 address */
2904 if (!str_to_ip(cp
, &host_addr
)) {
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
);
2920 } /* read_subnets_file */
2922 static subnet_entry_t
2923 subnet_lookup(const uint32_t addr
)
2925 subnet_entry_t subnet_entry
;
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) */
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
;
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
) {
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
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
;
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
;
2997 if (tp
->addr
== subnet_addr
) {
2998 return; /* XXX provide warning that an address was repeated? */
3004 new_tp
= wmem_new(addr_resolv_scope
, sub_net_hashipv4_t
);
3008 tp
= entry
->subnet_addresses
[hash_idx
] = wmem_new(addr_resolv_scope
, sub_net_hashipv4_t
);
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;
3018 subnet_name_lookup_init(void)
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';
3068 static hashss7pc_t
*
3069 host_lookup_ss7pc(const uint8_t ni
, const uint32_t pc
)
3071 hashss7pc_t
* volatile tp
;
3074 id
= (ni
<<24) + (pc
&0xffffff);
3076 tp
= (hashss7pc_t
*)wmem_map_lookup(ss7pc_hash_table
, GUINT_TO_POINTER(id
));
3078 tp
= new_ss7pc(ni
, pc
);
3079 wmem_map_insert(ss7pc_hash_table
, GUINT_TO_POINTER(id
), 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
);
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')
3101 /* Don't have name in file */
3102 if (tp
->name
[0] == '\0')
3105 if (!gbl_resolv_flags
.ss7pc_name
)
3112 add_ss7pc_name(const uint8_t ni
, uint32_t pc
, const char *name
)
3117 if (!name
|| name
[0] == '\0')
3120 id
= (ni
<<24) + (pc
&0xffffff);
3121 tp
= (hashss7pc_t
*)wmem_map_lookup(ss7pc_hash_table
, GUINT_TO_POINTER(id
));
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
);
3133 read_ss7pcs_file(const char *ss7pcspath
)
3136 char line
[MAX_LINELEN
];
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
)
3148 while (fgetline(line
, sizeof(line
), hf
) >= 0) {
3149 if ((cp
= strchr(line
, '#')))
3152 if ((cp
= strtok(line
, "-")) == NULL
)
3153 continue; /*no ni-pc separator*/
3154 if (!ws_strtou8(cp
, NULL
, &ni
))
3159 if ((cp
= strtok(NULL
, " \t")) == NULL
)
3160 continue; /* no tokens for pc and name */
3161 if (!ws_strtou32(cp
, NULL
, &pc
))
3166 if ((cp
= strtok(NULL
, " \t")) == NULL
)
3167 continue; /* no host name */
3170 add_ss7pc_name(ni
, pc
, cp
);
3174 return entry_found
? true : false;
3178 ss7pc_name_lookup_init(void)
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);
3196 /* SS7PC Name Resolution End*/
3200 * External Functions
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"
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)"),
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
,
3266 c_ares_set_dns_servers
,
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",
3273 "A table of IPv4 and IPv6 addresses of DNS servers to be used to resolve IP names and addresses",
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",
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",
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();
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;
3325 host_name_lookup_process(void) {
3326 struct timeval tv
= { 0, 0 };
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. */
3338 process_async_dns_queue();
3342 nfds
= ares_fds(ghba_chan
, &rfds
, &wfds
);
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 */
3347 fprintf(stderr
, "Warning: call to select() failed, error is %s\n", g_strerror(errno
));
3350 ares_process(ghba_chan
, &rfds
, &wfds
);
3353 /* Any new entries? */
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();
3368 async_dns_initialized
= false;
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
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
)
3393 tp
->flags
|= RESOLVED_ADDRESS_USED
;
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 /* -------------------------- */
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
)
3423 tp
->flags
|= RESOLVED_ADDRESS_USED
;
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 /* -------------------------- */
3442 add_ipv4_name(const unsigned addr
, const char *name
, bool static_entry
)
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')
3453 tp
= (hashipv4_t
*)wmem_map_lookup(ipv4_hash_table
, GUINT_TO_POINTER(addr
));
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;
3463 tp
->flags
|= STATIC_HOSTNAME
;
3465 tp
->flags
|= TRIED_RESOLVE_ADDRESS
|NAME_RESOLVED
;
3466 } /* add_ipv4_name */
3468 /* -------------------------- */
3470 add_ipv6_name(const ws_in6_addr
*addrp
, const char *name
, const bool static_entry
)
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')
3481 tp
= (hashipv6_t
*)wmem_map_lookup(ipv6_hash_table
, addrp
);
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;
3495 tp
->flags
|= STATIC_HOSTNAME
;
3497 tp
->flags
|= TRIED_RESOLVE_ADDRESS
|NAME_RESOLVED
;
3498 } /* add_ipv6_name */
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);
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);
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
);
3527 host_name_lookup_init(void)
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);
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);
3573 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
3574 if (ares_library_init(ARES_LIB_INIT_ALL
) == ARES_SUCCESS
) {
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
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();
3599 host_name_lookup_cleanup(void)
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();
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 */
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 */
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 */
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 */
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
);
3713 get_ether_name(const uint8_t *addr
)
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 */
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.
3734 get_ether_name_if_known(const uint8_t *addr
)
3738 /* Initialize ether structs if we're the first
3739 * ether-related function called */
3740 if (!gbl_resolv_flags
.mac_name
)
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
;
3752 /* Name was created */
3758 add_ether_byip(const unsigned ip
, const uint8_t *eth
)
3762 /* first check that IP address can be resolved */
3763 if (!gbl_resolv_flags
.network_name
)
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 */
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 */
3794 get_vlan_name(wmem_allocator_t
*allocator
, const uint16_t id
)
3797 if (!gbl_resolv_flags
.vlan_name
) {
3801 return wmem_strdup(allocator
, vlan_name_lookup(id
));
3803 } /* get_vlan_name */
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 */
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
));
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
;
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
) {
3852 } /* get_manuf_name_if_known */
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
));
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
;
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
;
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
;
3903 short_name
= ws_manuf_lookup(addr
, &long_name
, &mask
);
3904 if (short_name
!= NULL
) {
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]);
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]);
3915 ret
= wmem_strdup_printf(allocator
, "%s_%01x:%02x:%02x:%02x", short_name
, addr
[4] & 0x0F, addr
[5], addr
[6], addr
[7]);
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]);
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]);
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
);
3931 } /* eui64_to_display */
3933 #define GHI_TIMEOUT (250 * 1000)
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. */
3953 get_host_ipaddr(const char *host
, uint32_t *addrp
)
3955 struct timeval tv
= { 0, GHI_TIMEOUT
}, *tvp
;
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
3971 /* If we're not allowed to do name resolution, don't do name
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
) {
3982 if (!async_dns_initialized
|| name_resolve_concurrency
< 1) {
3985 ahe
.addr_size
= (int) sizeof (struct in_addr
);
3988 ares_gethostbyname(ghbn_chan
, host
, AF_INET
, c_ares_ghi_cb
, &ahe
);
3991 nfds
= ares_fds(ghbn_chan
, &rfds
, &wfds
);
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 */
3997 fprintf(stderr
, "Warning: call to select() failed, error is %s\n", g_strerror(errno
));
4000 ares_process(ghbn_chan
, &rfds
, &wfds
);
4002 ares_cancel(ghbn_chan
);
4003 if (ahe
.addr_size
== ahe
.copied
) {
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.
4018 get_host_ipaddr6(const char *host
, ws_in6_addr
*addrp
)
4020 struct timeval tv
= { 0, GHI_TIMEOUT
}, *tvp
;
4023 async_hostent_t ahe
;
4025 if (str_to_ip6(host
, addrp
))
4028 /* It's not a valid dotted-quad IP address; is it a valid
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
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
) {
4048 if (!async_dns_initialized
|| name_resolve_concurrency
< 1) {
4051 ahe
.addr_size
= (int) sizeof (ws_in6_addr
);
4054 ares_gethostbyname(ghbn_chan
, host
, AF_INET6
, c_ares_ghi_cb
, &ahe
);
4057 nfds
= ares_fds(ghbn_chan
, &rfds
, &wfds
);
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 */
4063 fprintf(stderr
, "Warning: call to select() failed, error is %s\n", g_strerror(errno
));
4066 ares_process(ghbn_chan
, &rfds
, &wfds
);
4068 ares_cancel(ghbn_chan
);
4069 if (ahe
.addr_size
== ahe
.copied
) {
4077 get_manuf_hashtable(void)
4079 return manuf_hashtable
;
4083 get_wka_hashtable(void)
4085 return wka_hashtable
;
4089 get_eth_hashtable(void)
4091 return eth_hashtable
;
4095 get_serv_port_hashtable(void)
4097 return serv_port_hashtable
;
4101 get_ipxnet_hash_table(void)
4103 return ipxnet_hash_table
;
4107 get_vlan_hash_table(void)
4109 return vlan_hash_table
;
4113 get_ipv4_hash_table(void)
4115 return ipv4_hash_table
;
4119 get_ipv6_hash_table(void)
4121 return ipv6_hash_table
;
4123 /* Initialize all the address resolution subsystems in this file */
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();
4133 initialize_enterprises();
4134 host_name_lookup_init();
4137 /* Clean up all the address resolution subsystems in this file */
4139 addr_resolv_cleanup(void)
4141 vlan_name_lookup_cleanup();
4142 service_name_lookup_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
;
4153 str_to_ip(const char *str
, void *dst
)
4155 return ws_inet_pton4(str
, (uint32_t *)dst
);
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
4170 str_to_eth(const char *str
, char *eth_bytes
)
4174 if (!parse_ether_address(str
, ð
, NULL
, false))
4177 memcpy(eth_bytes
, eth
.addr
, sizeof(eth
.addr
));
4182 * Editor modelines - https://www.wireshark.org/tools/modelines.html
4187 * indent-tabs-mode: nil
4190 * vi: set shiftwidth=4 tabstop=8 expandtab:
4191 * :indentSize=4:tabSize=8:noTabs=true: