Bug Summary

File:builds/wireshark/wireshark/epan/addr_resolv.c
Warning:line 799, column 9
Value of 'errno' was not checked and may be overwritten by function 'fgets'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name addr_resolv.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan -isystem /builds/wireshark/wireshark/build/epan -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /usr/include/lua5.4 -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D epan_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-04-23-100342-3640-1 -x c /builds/wireshark/wireshark/epan/addr_resolv.c
1/* addr_resolv.c
2 * Routines for network object lookup
3 *
4 * Laurent Deniel <[email protected]>
5 *
6 * Add option to resolv VLAN ID to describing name
7 * Uli Heilmeier, March 2016
8 *
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <[email protected]>
11 * Copyright 1998 Gerald Combs
12 *
13 * SPDX-License-Identifier: GPL-2.0-or-later
14 */
15
16#include "config.h"
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <errno(*__errno_location ()).h>
22
23#include <wsutil/strtoi.h>
24#include <wsutil/ws_assert.h>
25
26#include "iana-info.h"
27#include "manuf.h"
28
29/*
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).
33 *
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.
38 *
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.
43 *
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.)
51 *
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.
57 */
58
59#ifdef HAVE_NETINET_IN_H1
60# include <netinet/in.h>
61#endif
62
63#ifdef HAVE_NETDB_H1
64#include <netdb.h>
65#endif
66
67#ifdef HAVE_SYS_SOCKET_H1
68#include <sys/socket.h> /* needed to define AF_ values on UNIX */
69#endif
70
71#ifdef _WIN32
72#include <winsock2.h> /* needed to define AF_ values on Windows */
73#include <ws2tcpip.h>
74#endif
75
76#ifdef _WIN32
77# define socklen_t unsigned int
78#endif
79#include <ares.h>
80#include <ares_version.h>
81
82#include <glib.h>
83
84#include <epan/packet.h>
85#include "addr_resolv.h"
86#include "wsutil/filesystem.h"
87
88#include <wsutil/report_message.h>
89#include <wsutil/file_util.h>
90#include <wsutil/pint.h>
91#include <wsutil/inet_cidr.h>
92
93#include <epan/strutil.h>
94#include <epan/to_str.h>
95#include <epan/maxmind_db.h>
96#include <epan/prefs.h>
97#include <epan/uat.h>
98
99#define ENAME_HOSTS"hosts" "hosts"
100#define ENAME_SUBNETS"subnets" "subnets"
101#define ENAME_SUBNETS_V6"subnetIpv6" "subnetIpv6"
102#define ENAME_ETHERS"ethers" "ethers"
103#define ENAME_IPXNETS"ipxnets" "ipxnets"
104#define ENAME_MANUF"manuf" "manuf"
105#define ENAME_WKA"wka" "wka"
106#define ENAME_SERVICES"services" "services"
107#define ENAME_VLANS"vlans" "vlans"
108#define ENAME_SS7PCS"ss7pcs" "ss7pcs"
109#define ENAME_ENTERPRISES"enterprises" "enterprises"
110#define ENAME_TACS"tacs" "tacs"
111
112#define HASHETHSIZE2048 2048
113#define HASHHOSTSIZE2048 2048
114#define HASHIPXNETSIZE256 256
115#define SUBNETLENGTHSIZE32 32 /*1-32 inc.*/
116#define SUBNETLENGTHSIZE_V6128 128 /*1-128 inc.*/
117
118/* hash table used for IPv4 lookup */
119
120#define HASH_IPV4_ADDRESS(addr)((((((guint32) ( (((guint32) (addr) & (guint32) 0x000000ffU
) << 24) | (((guint32) (addr) & (guint32) 0x0000ff00U
) << 8) | (((guint32) (addr) & (guint32) 0x00ff0000U
) >> 8) | (((guint32) (addr) & (guint32) 0xff000000U
) >> 24)))))) & (2048 - 1))
(g_htonl(addr)(((((guint32) ( (((guint32) (addr) & (guint32) 0x000000ffU
) << 24) | (((guint32) (addr) & (guint32) 0x0000ff00U
) << 8) | (((guint32) (addr) & (guint32) 0x00ff0000U
) >> 8) | (((guint32) (addr) & (guint32) 0xff000000U
) >> 24))))))
& (HASHHOSTSIZE2048 - 1))
121
122
123typedef struct sub_net_hashipv4 {
124 unsigned addr;
125 /* XXX: No longer needed?*/
126 uint8_t flags; /* B0 dummy_entry, B1 resolve, B2 If the address is used in the trace */
127 struct sub_net_hashipv4 *next;
128 char name[MAXNAMELEN64];
129} sub_net_hashipv4_t;
130
131/* Array of entries of subnets of different lengths */
132typedef struct {
133 size_t mask_length; /*1-32*/
134 uint32_t mask; /* e.g. 255.255.255.*/
135 sub_net_hashipv4_t** subnet_addresses; /* Hash table of subnet addresses */
136} subnet_length_entry_t;
137
138
139/* IPv6 subnet lookup structures */
140typedef struct sub_net_hashipv6 {
141 uint8_t addr[16]; /* masked network address */
142 uint8_t flags;
143 struct sub_net_hashipv6 *next;
144 char name[MAXNAMELEN64];
145} sub_net_hashipv6_t;
146
147typedef struct {
148 size_t mask_length; /* 1-128 */
149 uint8_t mask[16]; /* byte mask */
150 sub_net_hashipv6_t **subnet_addresses; /* hash table */
151} subnet_length_entry_v6_t;
152
153typedef struct {
154 uint8_t mask[16];
155 size_t mask_length;
156 const char *name;
157} subnet_entry_v6_t;
158
159/* hash table used for IPX network lookup */
160
161/* XXX - check goodness of hash function */
162
163#define HASH_IPX_NET(net)((net) & (256 - 1)) ((net) & (HASHIPXNETSIZE256 - 1))
164
165typedef struct hashipxnet {
166 unsigned addr;
167 struct hashipxnet *next;
168 char name[MAXNAMELEN64];
169} hashipxnet_t;
170
171typedef struct hashvlan {
172 unsigned id;
173/* struct hashvlan *next; */
174 char name[MAXVLANNAMELEN128];
175} hashvlan_t;
176
177typedef struct ss7pc {
178 uint32_t id; /* 1st byte NI, 3 following bytes: Point Code */
179 char pc_addr[MAXNAMELEN64];
180 char name[MAXNAMELEN64];
181} hashss7pc_t;
182
183/* hash tables used for ethernet and manufacturer lookup */
184struct hashether {
185 uint8_t flags; /* (See above) */
186 uint8_t addr[6];
187 char hexaddr[6*3];
188 char resolved_name[MAXNAMELEN64];
189};
190
191struct hasheui64 {
192 uint8_t flags; /* (See above) */
193 uint8_t addr[EUI64_ADDR_LEN8];
194 char hexaddr[EUI64_ADDR_LEN8*3];
195 char resolved_name[MAXNAMELEN64];
196};
197
198struct hashwka {
199 uint8_t flags; /* (See above) */
200 char* name;
201};
202
203struct hashmanuf {
204 uint8_t flags; /* (See above) */
205 uint8_t addr[3];
206 char hexaddr[3*3];
207 char resolved_name[MAXNAMELEN64];
208 char resolved_longname[MAXNAMELEN64];
209};
210
211/* internal type used when reading ethers file (or wka, manuf) */
212typedef struct _ether
213{
214 uint8_t addr[8];
215 char name[MAXNAMELEN64];
216 char longname[MAXNAMELEN64];
217} ether_t;
218
219/* internal ipxnet type */
220typedef struct _ipxnet
221{
222 unsigned addr;
223 char name[MAXNAMELEN64];
224} ipxnet_t;
225
226/* internal vlan type */
227typedef struct _vlan
228{
229 unsigned id;
230 char name[MAXVLANNAMELEN128];
231} vlan_t;
232
233static wmem_allocator_t *addr_resolv_scope;
234
235// Maps unsigned -> hashipxnet_t*
236static wmem_map_t *ipxnet_hash_table;
237static wmem_map_t *ipv4_hash_table;
238static wmem_map_t *ipv6_hash_table;
239// Maps unsigned -> hashvlan_t*
240static wmem_map_t *vlan_hash_table;
241static wmem_map_t *ss7pc_hash_table;
242static wmem_map_t *tac_hash_table;
243
244// Maps IP address -> manually set hostname.
245static wmem_map_t *manually_resolved_ipv4_list;
246static wmem_map_t *manually_resolved_ipv6_list;
247
248static addrinfo_lists_t addrinfo_lists;
249
250struct cb_serv_data {
251 char *service;
252 port_type proto;
253};
254
255// Maps unsigned -> hashmanuf_t*
256// XXX: Note that hashmanuf_t* only accommodates 24-bit OUIs.
257// We might want to store vendor names from MA-M and MA-S to
258// present in the Resolved Addresses dialog.
259static wmem_map_t *manuf_hashtable;
260// Maps address -> hashwka_t*
261static wmem_map_t *wka_hashtable;
262// Maps address -> hashether_t*
263static wmem_map_t *eth_hashtable;
264// Maps address -> hasheui64_t*
265static wmem_map_t *eui64_hashtable;
266// Maps unsigned -> serv_port_t*
267static wmem_map_t *serv_port_hashtable;
268static wmem_map_t *serv_port_custom_hashtable;
269
270// Maps enterprise-id -> enterprise-desc (only used for user additions)
271static GHashTable *enterprises_hashtable;
272
273static subnet_length_entry_t subnet_length_entries[SUBNETLENGTHSIZE32]; /* Ordered array of entries */
274static bool_Bool have_subnet_entry;
275
276static subnet_length_entry_v6_t subnet_length_entries_v6[SUBNETLENGTHSIZE_V6128]; /* IPv6 subnet entries */
277static bool_Bool have_subnet_entry_v6;
278
279static bool_Bool new_resolved_objects;
280
281static GPtrArray* extra_hosts_files;
282
283static hashether_t *add_eth_name(const uint8_t *addr, const char *name, bool_Bool static_entry);
284static hasheui64_t *add_eui64_name(const uint8_t *addr, const char *name, bool_Bool static_entry);
285static void add_serv_port_cb(const uint32_t port, void *ptr);
286
287/* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
288 * One-at-a-Time hash
289 */
290unsigned
291ipv6_oat_hash(const void *key)
292{
293 int len = 16;
294 const unsigned char *p = (const unsigned char *)key;
295 unsigned h = 0;
296 int i;
297
298 for ( i = 0; i < len; i++ ) {
299 h += p[i];
300 h += ( h << 10 );
301 h ^= ( h >> 6 );
302 }
303
304 h += ( h << 3 );
305 h ^= ( h >> 11 );
306 h += ( h << 15 );
307
308 return h;
309}
310
311unsigned
312ws_ipv6_hash(const void* key)
313{
314#ifdef HAVE_XXHASH1
315 return wmem_strong_hash(key, 16);
316#else
317 return ipv6_oat_hash(key);
318#endif
319}
320
321gboolean
322ipv6_equal(const void *v1, const void *v2)
323{
324
325 if (memcmp(v1, v2, sizeof (ws_in6_addr)) == 0) {
326 return true1;
327 }
328
329 return false0;
330}
331
332/*
333 * Flag controlling what names to resolve.
334 */
335e_addr_resolve gbl_resolv_flags = {
336 true1, /* mac_name */
337 false0, /* network_name */
338 false0, /* transport_name */
339 true1, /* dns_pkt_addr_resolution */
340 false0, /* handshake_sni_addr_resolution */
341 true1, /* use_external_net_name_resolver */
342 false0, /* vlan_name */
343 false0, /* ss7 point code names */
344 true1, /* maxmind_geoip */
345 false0, /* tac_name */
346};
347
348/* XXX - ares_init_options(3) says:
349 * "The recommended concurrent query limit is about 32k queries"
350 */
351static unsigned name_resolve_concurrency = 500;
352static bool_Bool resolve_synchronously;
353
354/*
355 * Global variables (can be changed in GUI sections)
356 * XXX - they could be changed in GUI code, but there's currently no
357 * GUI code to change them.
358 */
359
360char *g_ethers_path; /* global ethers file */
361char *g_pethers_path; /* personal ethers file */
362char *g_wka_path; /* global well-known-addresses file */
363char *g_manuf_path; /* global manuf file */
364char *g_pmanuf_path; /* personal manuf file */
365char *g_ipxnets_path; /* global ipxnets file */
366char *g_pipxnets_path; /* personal ipxnets file */
367char *g_services_path; /* global services file */
368char *g_pservices_path; /* personal services file */
369char *g_pvlan_path; /* personal vlans file */
370char *g_ss7pcs_path; /* personal ss7pcs file */
371char *g_enterprises_path; /* global enterprises file */
372char *g_penterprises_path; /* personal enterprises file */
373 /* first resolving call */
374
375/*
376 * Submitted asynchronous queries trigger a callback (c_ares_ghba_cb()).
377 * Queries are added to c_ares_queue_head. During processing, queries are
378 * popped off the front of c_ares_queue_head and submitted using
379 * ares_gethostbyaddr().
380 * The callback processes the response, then frees the request.
381 */
382typedef struct _async_dns_queue_msg
383{
384 union {
385 uint32_t ip4;
386 ws_in6_addr ip6;
387 } addr;
388 int family;
389} async_dns_queue_msg_t;
390
391typedef struct _async_hostent {
392 int addr_size;
393 int copied;
394 void *addrp;
395} async_hostent_t;
396
397static void
398c_ares_ghba_cb(void *arg, int status, int timeouts _U___attribute__((unused)), struct hostent *he);
399
400/*
401 * Submitted synchronous queries trigger a callback (c_ares_ghba_sync_cb()).
402 * The callback processes the response, sets completed to true if
403 * completed is non-NULL, then frees the request.
404 */
405typedef struct _sync_dns_data
406{
407 union {
408 uint32_t ip4;
409 ws_in6_addr ip6;
410 } addr;
411 int family;
412 bool_Bool *completed;
413} sync_dns_data_t;
414
415static ares_channel ghba_chan; /* ares_gethostbyaddr -- Usually non-interactive, no timeout */
416static ares_channel ghbn_chan; /* ares_gethostbyname -- Usually interactive, timeout */
417
418static bool_Bool async_dns_initialized;
419static unsigned async_dns_in_flight;
420static wmem_list_t *async_dns_queue_head;
421static GMutex async_dns_queue_mtx;
422
423//UAT for providing a list of DNS servers to C-ARES for name resolution
424bool_Bool use_custom_dns_server_list;
425struct dns_server_data {
426 char *ipaddr;
427 uint32_t udp_port;
428 uint32_t tcp_port;
429};
430
431UAT_CSTRING_CB_DEF(dnsserverlist_uats, ipaddr, struct dns_server_data)static void dnsserverlist_uats_ipaddr_set_cb(void* rec, const
char* buf, unsigned len, const void* u1 __attribute__((unused
)), const void* u2 __attribute__((unused))) { char* new_buf =
g_strndup(buf,len); g_free((((struct dns_server_data*)rec)->
ipaddr)); (((struct dns_server_data*)rec)->ipaddr) = new_buf
; } static void dnsserverlist_uats_ipaddr_tostr_cb(void* rec,
char** out_ptr, unsigned* out_len, const void* u1 __attribute__
((unused)), const void* u2 __attribute__((unused))) { if (((struct
dns_server_data*)rec)->ipaddr ) { *out_ptr = g_strdup_inline
((((struct dns_server_data*)rec)->ipaddr)); *out_len = (unsigned
)strlen((((struct dns_server_data*)rec)->ipaddr)); } else {
*out_ptr = g_strdup_inline (""); *out_len = 0; } }
432UAT_DEC_CB_DEF(dnsserverlist_uats, tcp_port, struct dns_server_data)static void dnsserverlist_uats_tcp_port_set_cb(void* rec, const
char* buf, unsigned len, const void* u1 __attribute__((unused
)), const void* u2 __attribute__((unused))) { char* tmp_str =
g_strndup(buf,len); ws_strtou32(tmp_str, ((void*)0), &((
struct dns_server_data*)rec)->tcp_port); g_free(tmp_str); }
static void dnsserverlist_uats_tcp_port_tostr_cb(void* rec, char
** out_ptr, unsigned* out_len, const void* u1 __attribute__((
unused)), const void* u2 __attribute__((unused))) { *out_ptr =
wmem_strdup_printf(((void*)0), "%u",((struct dns_server_data
*)rec)->tcp_port); *out_len = (unsigned)strlen(*out_ptr); }
433UAT_DEC_CB_DEF(dnsserverlist_uats, udp_port, struct dns_server_data)static void dnsserverlist_uats_udp_port_set_cb(void* rec, const
char* buf, unsigned len, const void* u1 __attribute__((unused
)), const void* u2 __attribute__((unused))) { char* tmp_str =
g_strndup(buf,len); ws_strtou32(tmp_str, ((void*)0), &((
struct dns_server_data*)rec)->udp_port); g_free(tmp_str); }
static void dnsserverlist_uats_udp_port_tostr_cb(void* rec, char
** out_ptr, unsigned* out_len, const void* u1 __attribute__((
unused)), const void* u2 __attribute__((unused))) { *out_ptr =
wmem_strdup_printf(((void*)0), "%u",((struct dns_server_data
*)rec)->udp_port); *out_len = (unsigned)strlen(*out_ptr); }
434
435static uat_t *dnsserver_uat;
436static struct dns_server_data *dnsserverlist_uats;
437static unsigned ndnsservers;
438
439static void
440dns_server_free_cb(void *data)
441{
442 struct dns_server_data *h = (struct dns_server_data*)data;
443
444 g_free(h->ipaddr);
445}
446
447static void*
448dns_server_copy_cb(void *dst_, const void *src_, size_t len _U___attribute__((unused)))
449{
450 const struct dns_server_data *src = (const struct dns_server_data *)src_;
451 struct dns_server_data *dst = (struct dns_server_data *)dst_;
452
453 dst->ipaddr = g_strdup(src->ipaddr)g_strdup_inline (src->ipaddr);
454 dst->udp_port = src->udp_port;
455 dst->tcp_port = src->tcp_port;
456
457 return dst;
458}
459
460static bool_Bool
461dnsserver_uat_fld_ip_chk_cb(void* r _U___attribute__((unused)), const char* ipaddr, unsigned len _U___attribute__((unused)), const void* u1 _U___attribute__((unused)), const void* u2 _U___attribute__((unused)), char** err)
462{
463 //Check for a valid IPv4 or IPv6 address.
464 if (ipaddr && g_hostname_is_ip_address(ipaddr)) {
465 *err = NULL((void*)0);
466 return true1;
467 }
468
469 *err = ws_strdup_printf("No valid IP address given.")wmem_strdup_printf(((void*)0), "No valid IP address given.");
470 return false0;
471}
472
473static bool_Bool
474dnsserver_uat_fld_port_chk_cb(void* r _U___attribute__((unused)), const char* p, unsigned len _U___attribute__((unused)), const void* u1 _U___attribute__((unused)), const void* u2 _U___attribute__((unused)), char** err)
475{
476 if (!p || strlen(p) == 0u) {
477 // This should be removed in favor of Decode As. Make it optional.
478 *err = NULL((void*)0);
479 return true1;
480 }
481
482 if (strcmp(p, "53") != 0){
483 uint16_t port;
484 if (!ws_strtou16(p, NULL((void*)0), &port)) {
485 *err = g_strdup("Invalid port given.")g_strdup_inline ("Invalid port given.");
486 return false0;
487 }
488 }
489
490 *err = NULL((void*)0);
491 return true1;
492}
493
494static void
495c_ares_ghba_sync_cb(void *arg, int status, int timeouts _U___attribute__((unused)), struct hostent *he) {
496 sync_dns_data_t *sdd = (sync_dns_data_t *)arg;
497 char **p;
498
499 if (status == ARES_SUCCESS) {
500 for (p = he->h_addr_list; *p != NULL((void*)0); p++) {
501 switch(sdd->family) {
502 case AF_INET2:
503 add_ipv4_name(sdd->addr.ip4, he->h_name, false0);
504 break;
505 case AF_INET610:
506 add_ipv6_name(&sdd->addr.ip6, he->h_name, false0);
507 break;
508 default:
509 /* Throw an exception? */
510 break;
511 }
512 }
513
514 }
515
516 /*
517 * Let our caller know that this is complete.
518 */
519 *sdd->completed = true1;
520
521 /*
522 * Free the structure for this call.
523 */
524 g_free(sdd);
525}
526
527static void
528wait_for_sync_resolv(bool_Bool *completed) {
529 int nfds;
530 fd_set rfds, wfds;
531 struct timeval tv;
532
533 while (!*completed) {
534 /*
535 * Not yet resolved; wait for something to show up on the
536 * address-to-name C-ARES channel.
537 *
538 * To quote the source code for ares_timeout() as of C-ARES
539 * 1.12.0, "WARNING: Beware that this is linear in the number
540 * of outstanding requests! You are probably far better off
541 * just calling ares_process() once per second, rather than
542 * calling ares_timeout() to figure out when to next call
543 * ares_process().", although we should have only one request
544 * outstanding.
545 * As of C-ARES 1.20.0, the ares_timeout() function is now O(1),
546 * but we don't require that minimum version.
547 * https://github.com/c-ares/c-ares/commit/cf99c025cfb3e21295b59923876a31a68ea2cb4b
548 *
549 * And, yes, we have to reset it each time, as select(), in
550 * some OSes modifies the timeout to reflect the time remaining
551 * (e.g., Linux) and select() in other OSes doesn't (most if not
552 * all other UN*Xes, Windows?), so we can't rely on *either*
553 * behavior.
554 */
555 tv.tv_sec = 1;
556 tv.tv_usec = 0;
557
558 FD_ZERO(&rfds)do { unsigned int __i; fd_set *__arr = (&rfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
559 FD_ZERO(&wfds)do { unsigned int __i; fd_set *__arr = (&wfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
560 nfds = ares_fds(ghba_chan, &rfds, &wfds);
561 if (nfds > 0) {
562 if (select(nfds, &rfds, &wfds, NULL((void*)0), &tv) == -1) { /* call to select() failed */
563 /* If it's interrupted by a signal, no need to put out a message */
564 if (errno(*__errno_location ()) != EINTR4)
565 fprintf(stderrstderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno(*__errno_location ())));
566 return;
567 }
568 ares_process(ghba_chan, &rfds, &wfds);
569 }
570 }
571}
572
573static void
574process_async_dns_queue(void)
575{
576 wmem_list_frame_t* head;
577 async_dns_queue_msg_t *caqm;
578
579 if (async_dns_queue_head == NULL((void*)0))
580 return;
581
582 if (!g_mutex_trylock(&async_dns_queue_mtx))
583 return;
584
585 head = wmem_list_head(async_dns_queue_head);
586
587 while (head != NULL((void*)0) && async_dns_in_flight <= name_resolve_concurrency) {
588 caqm = (async_dns_queue_msg_t *)wmem_list_frame_data(head);
589 wmem_list_remove_frame(async_dns_queue_head, head);
590 if (caqm->family == AF_INET2) {
591 ares_gethostbyaddr(ghba_chan, &caqm->addr.ip4, sizeof(uint32_t), AF_INET2,
592 c_ares_ghba_cb, caqm);
593 async_dns_in_flight++;
594 } else if (caqm->family == AF_INET610) {
595 ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(ws_in6_addr),
596 AF_INET610, c_ares_ghba_cb, caqm);
597 async_dns_in_flight++;
598 }
599
600 head = wmem_list_head(async_dns_queue_head);
601 }
602
603 g_mutex_unlock(&async_dns_queue_mtx);
604}
605
606static void
607wait_for_async_queue(void)
608{
609 struct timeval tv = { 0, 0 };
610 int nfds;
611 fd_set rfds, wfds;
612
613 new_resolved_objects = false0;
614
615 if (!async_dns_initialized) {
616 maxmind_db_lookup_process();
617 return;
618 }
619
620 while (1) {
621 /* We're switching to synchronous lookups, so process anything in
622 * the asynchronous queue. There might be more in the queue than
623 * name_resolve_concurrency allows, so check each cycle.
624 */
625 process_async_dns_queue();
626
627 FD_ZERO(&rfds)do { unsigned int __i; fd_set *__arr = (&rfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
628 FD_ZERO(&wfds)do { unsigned int __i; fd_set *__arr = (&wfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
629 nfds = ares_fds(ghba_chan, &rfds, &wfds);
630 if (nfds == 0) {
631 /* No more requests waiting for reply; we're done here. */
632 break;
633 }
634
635 /* See comment in wait_for_sync_resolv() about ares_timeout() being
636 * O(N) in the number of outstanding requests until c-ares 1.20, and
637 * why we might as well just set a 1 second to select().
638 */
639 tv.tv_sec = 1;
640 tv.tv_usec = 0;
641
642 if (select(nfds, &rfds, &wfds, NULL((void*)0), &tv) == -1) { /* call to select() failed */
643 /* If it's interrupted by a signal, no need to put out a message */
644 if (errno(*__errno_location ()) != EINTR4)
645 fprintf(stderrstderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno(*__errno_location ())));
646 return;
647 }
648 ares_process(ghba_chan, &rfds, &wfds);
649 }
650
651 maxmind_db_lookup_process();
652 return;
653}
654
655static void
656sync_lookup_ip4(const uint32_t addr)
657{
658 bool_Bool completed = false0;
659 sync_dns_data_t *sdd;
660
661 if (!async_dns_initialized) {
662 /*
663 * c-ares not initialized. Bail out.
664 */
665 return;
666 }
667
668 /*
669 * Start the request.
670 */
671 sdd = g_new(sync_dns_data_t, 1)((sync_dns_data_t *) g_malloc_n ((1), sizeof (sync_dns_data_t
)))
;
672 sdd->family = AF_INET2;
673 sdd->addr.ip4 = addr;
674 sdd->completed = &completed;
675 ares_gethostbyaddr(ghba_chan, &addr, sizeof(uint32_t), AF_INET2,
676 c_ares_ghba_sync_cb, sdd);
677
678 /*
679 * Now wait for it to finish.
680 */
681 wait_for_sync_resolv(&completed);
682}
683
684static void
685sync_lookup_ip6(const ws_in6_addr *addrp)
686{
687 bool_Bool completed = false0;
688 sync_dns_data_t *sdd;
689
690 if (!async_dns_initialized) {
691 /*
692 * c-ares not initialized. Bail out.
693 */
694 return;
695 }
696
697 /*
698 * Start the request.
699 */
700 sdd = g_new(sync_dns_data_t, 1)((sync_dns_data_t *) g_malloc_n ((1), sizeof (sync_dns_data_t
)))
;
701 sdd->family = AF_INET610;
702 memcpy(&sdd->addr.ip6, addrp, sizeof(sdd->addr.ip6));
703 sdd->completed = &completed;
704 ares_gethostbyaddr(ghba_chan, addrp, sizeof(ws_in6_addr), AF_INET610,
705 c_ares_ghba_sync_cb, sdd);
706
707 /*
708 * Now wait for it to finish.
709 */
710 wait_for_sync_resolv(&completed);
711}
712
713void
714set_resolution_synchrony(bool_Bool synchronous)
715{
716 resolve_synchronously = synchronous;
717 maxmind_db_set_synchrony(synchronous);
718
719 if (synchronous) {
720 wait_for_async_queue();
721 }
722}
723
724static void
725c_ares_set_dns_servers(void)
726{
727 if ((!async_dns_initialized) || (!use_custom_dns_server_list))
728 return;
729
730 if (ndnsservers == 0) {
731 //clear the list of servers. This may effectively disable name resolution
732 ares_set_servers_ports(ghba_chan, NULL((void*)0));
733 ares_set_servers_ports(ghbn_chan, NULL((void*)0));
734 } else {
735 struct ares_addr_port_node* servers = wmem_alloc_array(NULL, struct ares_addr_port_node, ndnsservers)((struct ares_addr_port_node*)wmem_alloc((((void*)0)), (((((ndnsservers
)) <= 0) || ((size_t)sizeof(struct ares_addr_port_node) >
(9223372036854775807L / (size_t)((ndnsservers))))) ? 0 : (sizeof
(struct ares_addr_port_node) * ((ndnsservers))))))
;
736 ws_in4_addr ipv4addr;
737 ws_in6_addr ipv6addr;
738 bool_Bool invalid_IP_found = false0;
739 struct ares_addr_port_node* server;
740 unsigned i;
741 for (i = 0, server = servers; i < ndnsservers-1; i++, server++) {
742 if (ws_inet_pton6(dnsserverlist_uats[i].ipaddr, &ipv6addr)) {
743 server->family = AF_INET610;
744 memcpy(&server->addr.addr6, &ipv6addr, 16);
745 } else if (ws_inet_pton4(dnsserverlist_uats[i].ipaddr, &ipv4addr)) {
746 server->family = AF_INET2;
747 memcpy(&server->addr.addr4, &ipv4addr, 4);
748 } else {
749 //This shouldn't happen, but just in case...
750 invalid_IP_found = true1;
751 server->family = 0;
752 memset(&server->addr.addr4, 0, 4);
753 break;
754 }
755
756 server->udp_port = (int)dnsserverlist_uats[i].udp_port;
757 server->tcp_port = (int)dnsserverlist_uats[i].tcp_port;
758
759 server->next = (server+1);
760 }
761 if (!invalid_IP_found) {
762 if (ws_inet_pton6(dnsserverlist_uats[i].ipaddr, &ipv6addr)) {
763 server->family = AF_INET610;
764 memcpy(&server->addr.addr6, &ipv6addr, 16);
765 }
766 else if (ws_inet_pton4(dnsserverlist_uats[i].ipaddr, &ipv4addr)) {
767 server->family = AF_INET2;
768 memcpy(&server->addr.addr4, &ipv4addr, 4);
769 } else {
770 //This shouldn't happen, but just in case...
771 server->family = 0;
772 memset(&server->addr.addr4, 0, 4);
773 }
774 }
775 server->udp_port = (int)dnsserverlist_uats[i].udp_port;
776 server->tcp_port = (int)dnsserverlist_uats[i].tcp_port;
777
778 server->next = NULL((void*)0);
779
780 ares_set_servers_ports(ghba_chan, servers);
781 ares_set_servers_ports(ghbn_chan, servers);
782 wmem_free(NULL((void*)0), servers);
783 }
784}
785
786typedef struct {
787 uint32_t mask;
788 size_t mask_length;
789 const char* name; /* Shallow copy */
790} subnet_entry_t;
791
792/* Maximum supported line length of hosts, services, manuf, etc. */
793#define MAX_LINELEN1024 1024
794
795/** Read a line without trailing (CR)LF. Returns -1 on failure. */
796static int
797fgetline(char *buf, int size, FILE *fp)
798{
799 if (fgets(buf, size, fp)) {
15
Value of 'errno' was not checked and may be overwritten by function 'fgets'
800 int len = (int)strcspn(buf, "\r\n");
801 buf[len] = '\0';
802 return len;
803 }
804 return -1;
805
806} /* fgetline */
807
808
809/*
810 * Local function definitions
811 */
812static subnet_entry_t subnet_lookup(const uint32_t addr);
813static void subnet_entry_set(uint32_t subnet_addr, const uint8_t mask_length, const char* name);
814
815static unsigned serv_port_custom_hash(const void *k)
816{
817 const serv_port_key_t *key = (const serv_port_key_t*)k;
818 return key->port + (key->type << 16);
819}
820
821static gboolean serv_port_custom_equal(const void *k1, const void *k2)
822{
823 const serv_port_key_t *key1 = (const serv_port_key_t*)k1;
824 const serv_port_key_t *key2 = (const serv_port_key_t*)k2;
825
826 return (key1->port == key2->port) && (key1->type == key2->type);
827}
828
829static void
830add_custom_service_name(port_type proto, const unsigned port, const char *service_name)
831{
832 char *name;
833 serv_port_key_t *key, *orig_key;
834
835 key = wmem_new(addr_resolv_scope, serv_port_key_t)((serv_port_key_t*)wmem_alloc((addr_resolv_scope), sizeof(serv_port_key_t
)))
;
836 key->port = (uint16_t)port;
837 key->type = proto;
838
839 if (wmem_map_lookup_extended(serv_port_custom_hashtable, key, (const void**)&orig_key, (void**)&name)) {
840 wmem_free(addr_resolv_scope, orig_key);
841 wmem_free(addr_resolv_scope, name);
842 }
843
844 name = wmem_strdup(addr_resolv_scope, service_name);
845 wmem_map_insert(serv_port_custom_hashtable, key, name);
846
847 // A new custom entry is not a new resolved object.
848 // new_resolved_objects = true;
849}
850
851static void
852add_service_name(port_type proto, const unsigned port, const char *service_name)
853{
854 serv_port_key_t *key = wmem_new(addr_resolv_scope, serv_port_key_t)((serv_port_key_t*)wmem_alloc((addr_resolv_scope), sizeof(serv_port_key_t
)))
;
855 key->port = (uint16_t)port;
856 key->type = proto;
857
858 wmem_map_insert(serv_port_hashtable, key, (void*)service_name);
859
860 new_resolved_objects = true1;
861}
862
863static void
864parse_service_line (char *line)
865{
866 char *cp;
867 char *service;
868 char *port;
869 port_type proto;
870 struct cb_serv_data cb_data;
871 range_t *port_rng = NULL((void*)0);
872
873 if ((cp = strchr(line, '#')))
874 *cp = '\0';
875
876 if ((cp = strtok(line, " \t")) == NULL((void*)0))
877 return;
878
879 service = cp;
880
881 if ((cp = strtok(NULL((void*)0), " \t")) == NULL((void*)0))
882 return;
883
884 port = cp;
885
886 if (strtok(cp, "/") == NULL((void*)0))
887 return;
888
889 if (range_convert_str(NULL((void*)0), &port_rng, port, UINT16_MAX(65535)) != CVT_NO_ERROR) {
890 wmem_free (NULL((void*)0), port_rng);
891 return;
892 }
893
894 while ((cp = strtok(NULL((void*)0), "/")) != NULL((void*)0)) {
895 if (strcmp(cp, "tcp") == 0) {
896 proto = PT_TCP;
897 }
898 else if (strcmp(cp, "udp") == 0) {
899 proto = PT_UDP;
900 }
901 else if (strcmp(cp, "sctp") == 0) {
902 proto = PT_SCTP;
903 }
904 else if (strcmp(cp, "dccp") == 0) {
905 proto = PT_DCCP;
906 }
907 else {
908 break;
909 }
910 cb_data.service = service;
911 cb_data.proto = proto;
912 range_foreach(port_rng, add_serv_port_cb, &cb_data);
913 }
914
915 wmem_free (NULL((void*)0), port_rng);
916} /* parse_service_line */
917
918
919static void
920add_serv_port_cb(const uint32_t port, void *ptr)
921{
922 struct cb_serv_data *cb_data = (struct cb_serv_data *)ptr;
923
924 if ( port ) {
925 add_custom_service_name(cb_data->proto, port, cb_data->service);
926 }
927}
928
929
930static bool_Bool
931parse_services_file(const char * path)
932{
933 FILE *serv_p;
934 char buf[MAX_LINELEN1024];
935
936 /* services hash table initialization */
937 serv_p = ws_fopenfopen(path, "r");
938
939 if (serv_p == NULL((void*)0))
940 return false0;
941
942 while (fgetline(buf, sizeof(buf), serv_p) >= 0) {
943 parse_service_line(buf);
944 }
945
946 fclose(serv_p);
947 return true1;
948}
949
950/* -----------------
951 * unsigned integer to ascii
952 */
953static char *
954wmem_utoa(wmem_allocator_t *allocator, unsigned port)
955{
956 char *bp = (char *)wmem_alloc(allocator, MAXNAMELEN64);
957
958 /* XXX, uint32_to_str() ? */
959 uint32_to_str_buf(port, bp, MAXNAMELEN64);
960 return bp;
961}
962
963static const char *
964_serv_name_lookup(port_type proto, unsigned port)
965{
966 const char* name = NULL((void*)0);
967 ws_services_proto_t p;
968 ws_services_entry_t const *serv;
969
970 const serv_port_key_t custom_key = { (uint16_t)port, proto };
971 /* Look in the cache. Use an extended lookup so we can distinguish a port
972 * we already tried but had no name from one we haven't tried. */
973 if (!wmem_map_lookup_extended(serv_port_hashtable, &custom_key, NULL((void*)0), (void **)&name)) {
974 /* Try the user custom table */
975 name = wmem_map_lookup(serv_port_custom_hashtable, &custom_key);
976
977 if (name == NULL((void*)0)) {
978 /* now look in the global tables */
979 bool_Bool valid_proto = true1;
980 switch(proto) {
981 case PT_TCP: p = ws_tcp; break;
982 case PT_UDP: p = ws_udp; break;
983 case PT_SCTP: p = ws_sctp; break;
984 case PT_DCCP: p = ws_dccp; break;
985 default: valid_proto = false0;
986 }
987 if (valid_proto) {
988 serv = global_services_lookup(port, p);
989 if (serv) {
990 name = serv->name;
991 }
992 }
993 }
994
995 /* Cache result (even if NULL, so we can know we have no result.) */
996 add_service_name(proto, port, name);
997 }
998
999 return name;
1000}
1001
1002const char *
1003try_serv_name_lookup(port_type proto, unsigned port)
1004{
1005 return (proto == PT_NONE) ? NULL((void*)0) : _serv_name_lookup(proto, port);
1006}
1007
1008const char *
1009serv_name_lookup(port_type proto, unsigned port)
1010{
1011 const char *name;
1012
1013 /* first look for the name */
1014 name = _serv_name_lookup(proto, port);
1015 if (name != NULL((void*)0))
1016 return name;
1017
1018 /* No resolved name. Do we have a cached numeric string? */
1019 const serv_port_key_t key = { (uint16_t)port, PT_NONE };
1020 name = (const char*)wmem_map_lookup(serv_port_hashtable, &key);
1021 /* No name; create the numeric string. */
1022 if (name == NULL((void*)0)) {
1023 name = wmem_strdup_printf(addr_resolv_scope, "%u", port);
1024 add_service_name(PT_NONE, port, name);
1025 }
1026
1027 return name;
1028}
1029
1030static void
1031initialize_services(const char* app_env_var_prefix)
1032{
1033 ws_assert(serv_port_hashtable == NULL)do { if ((1) && !(serv_port_hashtable == ((void*)0)))
ws_log_fatal_full("", LOG_LEVEL_ERROR, "epan/addr_resolv.c",
1033, __func__, "assertion failed: %s", "serv_port_hashtable == ((void*)0)"
); } while (0)
;
1034 serv_port_hashtable = wmem_map_new(addr_resolv_scope, serv_port_custom_hash, serv_port_custom_equal);
1035 ws_assert(serv_port_custom_hashtable == NULL)do { if ((1) && !(serv_port_custom_hashtable == ((void
*)0))) ws_log_fatal_full("", LOG_LEVEL_ERROR, "epan/addr_resolv.c"
, 1035, __func__, "assertion failed: %s", "serv_port_custom_hashtable == ((void*)0)"
); } while (0)
;
1036 serv_port_custom_hashtable = wmem_map_new(addr_resolv_scope, serv_port_custom_hash, serv_port_custom_equal);
1037
1038 /* Compute the pathname of the global services file. */
1039 if (g_services_path == NULL((void*)0)) {
1040 g_services_path = get_datafile_path(ENAME_SERVICES"services", app_env_var_prefix);
1041 }
1042 parse_services_file(g_services_path);
1043
1044 /* Compute the pathname of the personal services file */
1045 if (g_pservices_path == NULL((void*)0)) {
1046 /* Check profile directory before personal configuration */
1047 g_pservices_path = get_persconffile_path(ENAME_SERVICES"services", true1, app_env_var_prefix);
1048 if (!parse_services_file(g_pservices_path)) {
1049 g_free(g_pservices_path);
1050 g_pservices_path = get_persconffile_path(ENAME_SERVICES"services", false0, app_env_var_prefix);
1051 parse_services_file(g_pservices_path);
1052 }
1053 }
1054}
1055
1056static void
1057service_name_lookup_cleanup(void)
1058{
1059 serv_port_hashtable = NULL((void*)0);
1060 serv_port_custom_hashtable = NULL((void*)0);
1061 g_free(g_services_path);
1062 g_services_path = NULL((void*)0);
1063 g_free(g_pservices_path);
1064 g_pservices_path = NULL((void*)0);
1065}
1066
1067static void
1068parse_enterprises_line (char *line)
1069{
1070 char *tok, *dec_str, *org_str;
1071 uint32_t dec;
1072 bool_Bool had_comment = false0;
1073
1074 /* Stop the line at any comment found */
1075 if ((tok = strchr(line, '#'))) {
1076 *tok = '\0';
1077 had_comment = true1;
1078 }
1079 /* Get enterprise number */
1080 dec_str = strtok(line, " \t");
1081 if (!dec_str)
1082 return;
1083 /* Get enterprise name */
1084 org_str = strtok(NULL((void*)0), ""); /* everything else */
1085 if (org_str && had_comment) {
1086 /* Only need to strip after (between name and where comment was) */
1087 org_str = g_strchomp(org_str);
1088 }
1089 if (!org_str)
1090 return;
1091
1092 /* Add entry using number as key */
1093 if (!ws_strtou32(dec_str, NULL((void*)0), &dec))
1094 return;
1095 g_hash_table_insert(enterprises_hashtable, GUINT_TO_POINTER(dec)((gpointer) (gulong) (dec)), g_strdup(org_str)g_strdup_inline (org_str));
1096}
1097
1098
1099static bool_Bool
1100parse_enterprises_file(const char * path)
1101{
1102 FILE *fp;
1103 char buf[MAX_LINELEN1024];
1104
1105 fp = ws_fopenfopen(path, "r");
1106 if (fp == NULL((void*)0))
1107 return false0;
1108
1109 while (fgetline(buf, sizeof(buf), fp) >= 0) {
1110 parse_enterprises_line(buf);
1111 }
1112
1113 fclose(fp);
1114 return true1;
1115}
1116
1117static void
1118initialize_enterprises(const char* app_env_var_prefix)
1119{
1120 ws_assert(enterprises_hashtable == NULL)do { if ((1) && !(enterprises_hashtable == ((void*)0)
)) ws_log_fatal_full("", LOG_LEVEL_ERROR, "epan/addr_resolv.c"
, 1120, __func__, "assertion failed: %s", "enterprises_hashtable == ((void*)0)"
); } while (0)
;
1121 enterprises_hashtable = g_hash_table_new_full(NULL((void*)0), NULL((void*)0), NULL((void*)0), g_free);
1122
1123 if (g_enterprises_path == NULL((void*)0)) {
1124 g_enterprises_path = get_datafile_path(ENAME_ENTERPRISES"enterprises", app_env_var_prefix);
1125 }
1126 parse_enterprises_file(g_enterprises_path);
1127
1128 /* Populate entries from profile or personal */
1129 if (g_penterprises_path == NULL((void*)0)) {
1130 /* Check profile directory before personal configuration */
1131 g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES"enterprises", true1, app_env_var_prefix);
1132 if (!file_exists(g_penterprises_path)) {
1133 g_free(g_penterprises_path);
1134 g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES"enterprises", false0, app_env_var_prefix);
1135 }
1136 }
1137 /* Parse personal file (if present) */
1138 parse_enterprises_file(g_penterprises_path);
1139}
1140
1141const char *
1142try_enterprises_lookup(uint32_t value)
1143{
1144 /* Trying extra entries first. N.B. This does allow entries to be overwritten and found.. */
1145 const char *name = (const char *)g_hash_table_lookup(enterprises_hashtable, GUINT_TO_POINTER(value)((gpointer) (gulong) (value)));
1146 if (name)
1147 return name;
1148
1149 return val_to_str_ext_const(value, &enterprise_val_ext, "Unknown");
1150}
1151
1152const char *
1153enterprises_lookup(uint32_t value, const char *unknown_str)
1154{
1155 const char *s;
1156
1157 s = try_enterprises_lookup(value);
1158 if (s != NULL((void*)0))
1159 return s;
1160 if (unknown_str != NULL((void*)0))
1161 return unknown_str;
1162 return "<Unknown>";
1163}
1164
1165void
1166enterprises_base_custom(char *buf, uint32_t value)
1167{
1168 const char *s;
1169
1170 if ((s = try_enterprises_lookup(value)) == NULL((void*)0))
1171 s = ITEM_LABEL_UNKNOWN_STR"Unknown";
1172 snprintf(buf, ITEM_LABEL_LENGTH240, "%s (%u)", s, value);
1173}
1174
1175static void
1176enterprises_cleanup(void)
1177{
1178 ws_assert(enterprises_hashtable)do { if ((1) && !(enterprises_hashtable)) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 1178, __func__, "assertion failed: %s"
, "enterprises_hashtable"); } while (0)
;
1179 g_hash_table_destroy(enterprises_hashtable);
1180 enterprises_hashtable = NULL((void*)0);
1181 g_free(g_enterprises_path);
1182 g_enterprises_path = NULL((void*)0);
1183 g_free(g_penterprises_path);
1184 g_penterprises_path = NULL((void*)0);
1185}
1186
1187/* Fill in an IP4 structure with info from subnets file or just with the
1188 * string form of the address.
1189 */
1190bool_Bool
1191fill_dummy_ip4(const unsigned addr, hashipv4_t* volatile tp)
1192{
1193 subnet_entry_t subnet_entry;
1194
1195 /* return value : true if addr matches any subnet */
1196 bool_Bool cidr_covered = false0;
1197
1198 /* Overwrite if we get async DNS reply */
1199
1200 /* Do we have a subnet for this address? */
1201 subnet_entry = subnet_lookup(addr);
1202 if (0 != subnet_entry.mask) {
1203 /* Print name, then '.' then IP address after subnet mask */
1204 uint32_t host_addr;
1205 char buffer[WS_INET_ADDRSTRLEN16];
1206 char* paddr;
1207 size_t i;
1208
1209 host_addr = addr & (~subnet_entry.mask);
1210 ip_addr_to_str_buf(&host_addr, buffer, WS_INET_ADDRSTRLEN16);
1211 paddr = buffer;
1212
1213 /* Skip to first octet that is not totally masked
1214 * If length of mask is 32, we chomp the whole address.
1215 * If the address string starts '.' (should not happen?),
1216 * we skip that '.'.
1217 */
1218 i = subnet_entry.mask_length / 8;
1219 while(*(paddr) != '\0' && i > 0) {
1220 if (*(++paddr) == '.') {
1221 --i;
1222 }
1223 }
1224
1225 /* There are more efficient ways to do this, but this is safe if we
1226 * trust snprintf and MAXDNSNAMELEN
1227 */
1228 snprintf(tp->name, MAXDNSNAMELEN256, "%s%s", subnet_entry.name, paddr);
1229
1230 /* Evaluate the subnet in CIDR notation
1231 * Reuse buffers built above
1232 */
1233 uint32_t subnet_addr;
1234 subnet_addr = addr & subnet_entry.mask;
1235
1236 char buffer_subnet[WS_INET_ADDRSTRLEN16];
1237 ip_addr_to_str_buf(&subnet_addr, buffer_subnet, WS_INET_ADDRSTRLEN16);
1238
1239 char buffer_cidr[WS_INET_CIDRADDRSTRLEN19];
1240 snprintf(buffer_cidr, WS_INET_CIDRADDRSTRLEN19, "%s%s%u", buffer_subnet, "/", (unsigned)subnet_entry.mask_length);
1241
1242 snprintf(tp->cidr_addr, WS_INET_CIDRADDRSTRLEN19, "%s%s%u", buffer_subnet, "/", (unsigned)subnet_entry.mask_length);
1243 cidr_covered = true1;
1244 } else {
1245 /* XXX: This means we end up printing "1.2.3.4 (1.2.3.4)" in many cases */
1246 ip_addr_to_str_buf(&addr, tp->name, MAXDNSNAMELEN256);
1247
1248 /* IP does not belong to any known subnet, just indicate this IP without "/.32" */
1249 ip_addr_to_str_buf(&addr, tp->cidr_addr, MAXDNSNAMELEN256);
1250 }
1251 return cidr_covered;
1252}
1253
1254
1255/* Forward declaration — defined later with the IPv6 subnet functions. */
1256static subnet_entry_v6_t subnet6_lookup(const ws_in6_addr *addr);
1257
1258/* Fill in an IP6 structure with info from subnetIpv6 file or the string form
1259 * of the address.
1260 */
1261static void
1262fill_dummy_ip6(hashipv6_t* volatile tp)
1263{
1264 ws_in6_addr addr;
1265 memcpy(addr.bytes, tp->addr, 16);
1266
1267 /* Overwrite if we get async DNS reply */
1268 subnet_entry_v6_t subnet_entry = subnet6_lookup(&addr);
1269 if (subnet_entry.mask_length != 0) {
1270 ws_in6_addr host_addr;
1271 for (int i = 0; i < 16; i++)
1272 host_addr.bytes[i] = addr.bytes[i] & ~subnet_entry.mask[i];
1273
1274 /* Build host-portion 16-bit groups directly from bytes — avoids
1275 * ambiguity from IPv6 '::' zero-compression in string scanning. */
1276 size_t first_host_group = subnet_entry.mask_length / 16;
1277 wmem_strbuf_t *host_strbuf = wmem_strbuf_new_sized(addr_resolv_scope,
1278 WS_INET6_ADDRSTRLEN46);
1279 for (size_t g = first_host_group; g < 8; g++) {
1280 if (g > first_host_group)
1281 wmem_strbuf_append_c(host_strbuf, ':');
1282 uint16_t grp = ((uint16_t)host_addr.bytes[g * 2] << 8)
1283 | host_addr.bytes[g * 2 + 1];
1284 wmem_strbuf_append_printf(host_strbuf, "%x", (unsigned)grp);
1285 }
1286
1287 /* Assemble name: "subnetName:host_portion" */
1288 wmem_strbuf_t *name_strbuf = wmem_strbuf_new_sized(addr_resolv_scope,
1289 MAXDNSNAMELEN256);
1290 wmem_strbuf_append(name_strbuf, subnet_entry.name);
1291 if (wmem_strbuf_get_len(host_strbuf) > 0) {
1292 wmem_strbuf_append_c(name_strbuf, ':');
1293 wmem_strbuf_append(name_strbuf, wmem_strbuf_get_str(host_strbuf));
1294 }
1295 g_strlcpy(tp->name, wmem_strbuf_get_str(name_strbuf), MAXDNSNAMELEN256);
1296 wmem_strbuf_destroy(name_strbuf);
1297 wmem_strbuf_destroy(host_strbuf);
1298
1299 /* Build CIDR notation for cidr_addr */
1300 ws_in6_addr net_addr;
1301 for (int i = 0; i < 16; i++)
1302 net_addr.bytes[i] = addr.bytes[i] & subnet_entry.mask[i];
1303 char net_buf[WS_INET6_ADDRSTRLEN46];
1304 ip6_to_str_buf(&net_addr, net_buf, sizeof(net_buf));
1305 wmem_strbuf_t *cidr_strbuf = wmem_strbuf_new_sized(addr_resolv_scope,
1306 WS_INET6_CIDRADDRSTRLEN50);
1307 wmem_strbuf_append_printf(cidr_strbuf, "%s/%zu", net_buf,
1308 subnet_entry.mask_length);
1309 g_strlcpy(tp->cidr_addr, wmem_strbuf_get_str(cidr_strbuf),
1310 WS_INET6_CIDRADDRSTRLEN50);
1311 wmem_strbuf_destroy(cidr_strbuf);
1312 } else {
1313 (void)g_strlcpy(tp->name, tp->ip6, MAXDNSNAMELEN256);
1314 (void)g_strlcpy(tp->cidr_addr, tp->ip6, WS_INET6_CIDRADDRSTRLEN50);
1315 }
1316}
1317
1318static void
1319c_ares_ghba_cb(void *arg, int status, int timeouts _U___attribute__((unused)), struct hostent *he) {
1320 async_dns_queue_msg_t *caqm = (async_dns_queue_msg_t *)arg;
1321 char **p;
1322
1323 if (!caqm) return;
1324 /* XXX, what to do if async_dns_in_flight == 0? */
1325 async_dns_in_flight--;
1326
1327 if (status == ARES_SUCCESS) {
1328 for (p = he->h_addr_list; *p != NULL((void*)0); p++) {
1329 switch(caqm->family) {
1330 case AF_INET2:
1331 add_ipv4_name(caqm->addr.ip4, he->h_name, false0);
1332 break;
1333 case AF_INET610:
1334 add_ipv6_name(&caqm->addr.ip6, he->h_name, false0);
1335 break;
1336 default:
1337 /* Throw an exception? */
1338 break;
1339 }
1340 }
1341 }
1342 wmem_free(addr_resolv_scope, caqm);
1343}
1344
1345/* --------------- */
1346hashipv4_t *
1347new_ipv4(const unsigned addr)
1348{
1349 hashipv4_t *tp = wmem_new(addr_resolv_scope, hashipv4_t)((hashipv4_t*)wmem_alloc((addr_resolv_scope), sizeof(hashipv4_t
)))
;
1350 tp->addr = addr;
1351 tp->flags = 0;
1352 tp->name[0] = '\0';
1353 ip_addr_to_str_buf(&addr, tp->ip, sizeof(tp->ip));
1354 return tp;
1355}
1356
1357static hashipv4_t *
1358host_lookup(const unsigned addr)
1359{
1360 hashipv4_t * volatile tp;
1361
1362 tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr)((gpointer) (gulong) (addr)));
1363 if (tp == NULL((void*)0)) {
1364 /*
1365 * We don't already have an entry for this host name; create one,
1366 * and then try to resolve it.
1367 */
1368 tp = new_ipv4(addr);
1369 fill_dummy_ip4(addr, tp);
1370 wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr)((gpointer) (gulong) (addr)), tp);
1371 } else if (tp->flags & TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1))) {
1372 return tp;
1373 }
1374
1375 /*
1376 * This hasn't been resolved yet, and we haven't tried to
1377 * resolve it already.
1378 */
1379
1380 if (!gbl_resolv_flags.network_name)
1381 return tp;
1382
1383 if (gbl_resolv_flags.use_external_net_name_resolver) {
1384 tp->flags |= TRIED_RESOLVE_ADDRESS(1U<<0);
1385
1386 if (async_dns_initialized) {
1387 /* c-ares is initialized, so we can use it */
1388 if (resolve_synchronously || name_resolve_concurrency == 0) {
1389 /*
1390 * Either all names are to be resolved synchronously or
1391 * the concurrency level is 0; do the resolution
1392 * synchronously.
1393 */
1394 sync_lookup_ip4(addr);
1395 } else {
1396 /*
1397 * Names are to be resolved asynchronously, and we
1398 * allow at least one asynchronous request in flight;
1399 * post an asynchronous request.
1400 */
1401 async_dns_queue_msg_t *caqm;
1402
1403 caqm = wmem_new(addr_resolv_scope, async_dns_queue_msg_t)((async_dns_queue_msg_t*)wmem_alloc((addr_resolv_scope), sizeof
(async_dns_queue_msg_t)))
;
1404 caqm->family = AF_INET2;
1405 caqm->addr.ip4 = addr;
1406 wmem_list_append(async_dns_queue_head, (void *) caqm);
1407 }
1408 }
1409 }
1410
1411 return tp;
1412
1413} /* host_lookup */
1414
1415/* --------------- */
1416static hashipv6_t *
1417new_ipv6(const ws_in6_addr *addr)
1418{
1419 hashipv6_t *tp = wmem_new(addr_resolv_scope, hashipv6_t)((hashipv6_t*)wmem_alloc((addr_resolv_scope), sizeof(hashipv6_t
)))
;
1420 memcpy(tp->addr, addr->bytes, sizeof tp->addr);
1421 tp->flags = 0;
1422 tp->name[0] = '\0';
1423 ip6_to_str_buf(addr, tp->ip6, sizeof(tp->ip6));
1424 return tp;
1425}
1426
1427/* ------------------------------------ */
1428static hashipv6_t *
1429host_lookup6(const ws_in6_addr *addr)
1430{
1431 hashipv6_t * volatile tp;
1432
1433 tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addr);
1434 if (tp == NULL((void*)0)) {
1435 /*
1436 * We don't already have an entry for this host name; create one,
1437 * and then try to resolve it.
1438 */
1439 ws_in6_addr *addr_key;
1440
1441 addr_key = wmem_new(addr_resolv_scope, ws_in6_addr)((ws_in6_addr*)wmem_alloc((addr_resolv_scope), sizeof(ws_in6_addr
)))
;
1442 tp = new_ipv6(addr);
1443 memcpy(addr_key, addr, 16);
1444 fill_dummy_ip6(tp);
1445 wmem_map_insert(ipv6_hash_table, addr_key, tp);
1446 } else if (tp->flags & TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1))) {
1447 return tp;
1448 }
1449
1450 /*
1451 * This hasn't been resolved yet, and we haven't tried to
1452 * resolve it already.
1453 */
1454
1455 if (!gbl_resolv_flags.network_name)
1456 return tp;
1457
1458 if (gbl_resolv_flags.use_external_net_name_resolver) {
1459 tp->flags |= TRIED_RESOLVE_ADDRESS(1U<<0);
1460
1461 if (async_dns_initialized) {
1462 /* c-ares is initialized, so we can use it */
1463 if (resolve_synchronously || name_resolve_concurrency == 0) {
1464 /*
1465 * Either all names are to be resolved synchronously or
1466 * the concurrency level is 0; do the resolution
1467 * synchronously.
1468 */
1469 sync_lookup_ip6(addr);
1470 } else {
1471 /*
1472 * Names are to be resolved asynchronously, and we
1473 * allow at least one asynchronous request in flight;
1474 * post an asynchronous request.
1475 */
1476 async_dns_queue_msg_t *caqm;
1477
1478 caqm = wmem_new(addr_resolv_scope, async_dns_queue_msg_t)((async_dns_queue_msg_t*)wmem_alloc((addr_resolv_scope), sizeof
(async_dns_queue_msg_t)))
;
1479 caqm->family = AF_INET610;
1480 memcpy(&caqm->addr.ip6, addr, sizeof(caqm->addr.ip6));
1481 wmem_list_append(async_dns_queue_head, (void *) caqm);
1482 }
1483 }
1484 }
1485
1486 return tp;
1487
1488} /* host_lookup6 */
1489
1490/*
1491 * Ethernet / manufacturer resolution
1492 *
1493 * The following functions implement ethernet address resolution and
1494 * ethers files parsing (see ethers(4)).
1495 *
1496 * The manuf file has the same format as ethers(4) except that names are
1497 * truncated to MAXMANUFLEN-1 (8) characters and that an address contains
1498 * only 3 bytes (instead of 6).
1499 *
1500 * Notes:
1501 *
1502 * I decide to not use the existing functions (see ethers(3) on some
1503 * operating systems) for the following reasons:
1504 * - performance gains (use of hash tables and some other enhancements),
1505 * - use of two ethers files (system-wide and per user),
1506 * - avoid the use of NIS maps,
1507 * - lack of these functions on some systems.
1508 *
1509 * So the following functions do _not_ behave as the standard ones.
1510 *
1511 * -- Laurent.
1512 */
1513
1514/*
1515 * Converts Ethernet addresses of the form aa:bb:cc or aa:bb:cc:dd:ee:ff/28.
1516 * '-' is also supported as a separator. The
1517 * octets must be exactly two hexadecimal characters and the mask must be either
1518 * 28 or 36. Pre-condition: cp MUST be at least 21 bytes.
1519 */
1520static bool_Bool
1521parse_ether_address_fast(const unsigned char *cp, ether_t *eth, unsigned int *mask,
1522 const bool_Bool accept_mask)
1523{
1524 /* XXX copied from strutil.c */
1525 /* a map from ASCII hex chars to their value */
1526 static const int8_t str_to_nibble[256] = {
1527 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1528 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1529 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1530 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
1531 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1532 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1533 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1534 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1535 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1536 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1537 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1538 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1539 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1540 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1541 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1542 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1543 };
1544 const uint8_t *str_to_nibble_usg = (const uint8_t *)str_to_nibble;
1545
1546 unsigned char sep = cp[2];
1547 if ((sep != ':' && sep != '-') || cp[5] != sep) {
1548 /* Unexpected separators. */
1549 return false0;
1550 }
1551
1552 /* N.B. store octet values in an int to detect invalid (-1) entries */
1553 int num0 = (str_to_nibble_usg[cp[0]] << 4) | (int8_t)str_to_nibble_usg[cp[1]];
1554 int num1 = (str_to_nibble_usg[cp[3]] << 4) | (int8_t)str_to_nibble_usg[cp[4]];
1555 int num2 = (str_to_nibble_usg[cp[6]] << 4) | (int8_t)str_to_nibble_usg[cp[7]];
1556
1557 if ((num0 | num1 | num2) & 0x100) {
1558 /* Not hexadecimal numbers. */
1559 return false0;
1560 }
1561
1562 eth->addr[0] = (uint8_t)num0;
1563 eth->addr[1] = (uint8_t)num1;
1564 eth->addr[2] = (uint8_t)num2;
1565
1566 if (cp[8] == '\0' && accept_mask) {
1567 /* Indicate that this is a manufacturer ID (0 is not allowed as a mask). */
1568 *mask = 0;
1569 return true1;
1570 } else if (cp[8] != sep || !accept_mask) {
1571 /* Format not handled by this fast path. */
1572 return false0;
1573 }
1574
1575 /* N.B. store octet values in an int to detect invalid (-1) entries */
1576 int num3 = (str_to_nibble_usg[cp[9]] << 4) | (int8_t)str_to_nibble_usg[cp[10]];
1577 int num4 = (str_to_nibble_usg[cp[12]] << 4) | (int8_t)str_to_nibble_usg[cp[13]];
1578 int num5 = (str_to_nibble_usg[cp[15]] << 4) | (int8_t)str_to_nibble_usg[cp[16]];
1579
1580 if (((num3 | num4 | num5) & 0x100) || cp[11] != sep || cp[14] != sep) {
1581 /* Not hexadecimal numbers or invalid separators. */
1582 return false0;
1583 }
1584
1585 eth->addr[3] = (uint8_t)num3;
1586 eth->addr[4] = (uint8_t)num4;
1587 eth->addr[5] = (uint8_t)num5;
1588 if (cp[17] == '\0') {
1589 /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1590 *mask = 48;
1591 return true1;
1592 } else if (cp[17] != '/' || cp[20] != '\0') {
1593 /* Format not handled by this fast path. */
1594 return false0;
1595 }
1596
1597 int m1 = cp[18];
1598 int m2 = cp[19];
1599 if (m1 == '3' && m2 == '6') { /* Mask /36 */
1600 eth->addr[4] &= 0xf0;
1601 eth->addr[5] = 0;
1602 *mask = 36;
1603 return true1;
1604 }
1605 if (m1 == '2' && m2 == '8') { /* Mask /28 */
1606 eth->addr[3] &= 0xf0;
1607 eth->addr[4] = 0;
1608 eth->addr[5] = 0;
1609 *mask = 28;
1610 return true1;
1611 }
1612 /* Unsupported mask */
1613 return false0;
1614}
1615
1616/*
1617 * If "accept_mask" is false, cp must point to an address that consists
1618 * of exactly 6 (EUI-48) or 8 (EUI-64) bytes.
1619 * If "accept_mask" is true, parse an up-to-6-byte sequence with an optional
1620 * mask.
1621 */
1622static bool_Bool
1623parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
1624 const bool_Bool accept_mask)
1625{
1626 int i;
1627 unsigned long num;
1628 char *p;
1629 char sep = '\0';
1630
1631 for (i = 0; i < EUI64_ADDR_LEN8; i++) {
1632 /* Get a hex number, 1 or 2 digits, no sign characters allowed. */
1633 if (!g_ascii_isxdigit(*cp)((g_ascii_table[(guchar) (*cp)] & G_ASCII_XDIGIT) != 0))
1634 return false0;
1635 num = strtoul(cp, &p, 16);
1636 if (p == cp)
1637 return false0; /* failed */
1638 if (num > 0xFF)
1639 return false0; /* not a valid octet */
1640 eth->addr[i] = (uint8_t) num;
1641 cp = p; /* skip past the number */
1642
1643 /* OK, what character terminated the octet? */
1644 if (*cp == '/') {
1645 /* "/" - this has a mask. */
1646 if (!accept_mask) {
1647 /* Entries with masks are not allowed in this file. */
1648 return false0;
1649 }
1650 cp++; /* skip past the '/' to get to the mask */
1651 if (!g_ascii_isdigit(*cp)((g_ascii_table[(guchar) (*cp)] & G_ASCII_DIGIT) != 0))
1652 return false0; /* no sign allowed */
1653 num = strtoul(cp, &p, 10);
1654 if (p == cp)
1655 return false0; /* failed */
1656 cp = p; /* skip past the number */
1657 if (*cp != '\0' && !g_ascii_isspace(*cp)((g_ascii_table[(guchar) (*cp)] & G_ASCII_SPACE) != 0))
1658 return false0; /* bogus terminator */
1659 if (num == 0 || num >= 48)
1660 return false0; /* bogus mask */
1661 /* Mask out the bits not covered by the mask */
1662 *mask = (int)num;
1663 for (i = 0; num >= 8; i++, num -= 8)
1664 ; /* skip octets entirely covered by the mask */
1665 /* Mask out the first masked octet */
1666 eth->addr[i] &= (0xFF << (8 - num));
1667 i++;
1668 /* Mask out completely-masked-out octets */
1669 for (; i < 6; i++)
1670 eth->addr[i] = 0;
1671 return true1;
1672 }
1673 if (*cp == '\0') {
1674 /* We're at the end of the address, and there's no mask. */
1675 if (i == 2) {
1676 /* We got 3 bytes, so this is a manufacturer ID. */
1677 if (!accept_mask) {
1678 /* Manufacturer IDs are not allowed in this file */
1679 return false0;
1680 }
1681 /* Indicate that this is a manufacturer ID (0 is not allowed
1682 as a mask). */
1683 *mask = 0;
1684 return true1;
1685 }
1686
1687 if (i == 5) {
1688 /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1689 if (mask) {
1690 *mask = 48;
1691 }
1692 return true1;
1693 }
1694
1695 if (i == 7) {
1696 /* We got 8 bytes, so this is a EUI-64 address (64 is not allowed as a mask). */
1697 if (mask) {
1698 *mask = 64;
1699 }
1700 return true1;
1701 }
1702
1703 /* We didn't get 3 or 6 or 8 bytes, and there's no mask; this is
1704 illegal. */
1705 return false0;
1706 } else {
1707 if (sep == '\0') {
1708 /* We don't know the separator used in this number; it can either
1709 be ':', '-', or '.'. */
1710 if (*cp != ':' && *cp != '-' && *cp != '.')
1711 return false0;
1712 sep = *cp; /* subsequent separators must be the same */
1713 } else {
1714 /* It has to be the same as the first separator */
1715 if (*cp != sep)
1716 return false0;
1717 }
1718 }
1719 cp++;
1720 }
1721
1722 return true1;
1723}
1724
1725static int
1726parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
1727 const bool_Bool accept_mask)
1728{
1729 /*
1730 * See the ethers(4) or ethers(5) man page for ethers file format
1731 * (not available on all systems).
1732 * We allow both ethernet address separators (':' and '-'),
1733 * as well as Wireshark's '.' separator.
1734 */
1735
1736 char *cp;
1737
1738 line = g_strstrip(line)g_strchomp (g_strchug (line));
1739 if (line[0] == '\0' || line[0] == '#')
1740 return -1;
1741
1742 if ((cp = strchr(line, '#'))) {
1743 *cp = '\0';
1744 g_strchomp(line);
1745 }
1746
1747 if ((cp = strtok(line, " \t")) == NULL((void*)0))
1748 return -1;
1749
1750 /* First try to match the common format for the large ethers file. */
1751 if (!parse_ether_address_fast((const uint8_t*)cp, eth, mask, accept_mask)) {
1752 /* Fallback for the well-known addresses (wka) file. */
1753 if (!parse_ether_address(cp, eth, mask, accept_mask))
1754 return -1;
1755 }
1756
1757 if ((cp = strtok(NULL((void*)0), " \t")) == NULL((void*)0))
1758 return -1;
1759
1760 (void) g_strlcpy(eth->name, cp, MAXNAMELEN64);
1761
1762 if ((cp = strtok(NULL((void*)0), "\t")) != NULL((void*)0))
1763 {
1764 (void) g_strlcpy(eth->longname, cp, MAXNAMELEN64);
1765 } else {
1766 /* Make the long name the short name */
1767 (void) g_strlcpy(eth->longname, eth->name, MAXNAMELEN64);
1768 }
1769
1770 return 0;
1771
1772} /* parse_ether_line */
1773
1774static FILE *eth_p;
1775
1776static void
1777set_ethent(char *path)
1778{
1779 if (eth_p)
1780 rewind(eth_p);
1781 else
1782 eth_p = ws_fopenfopen(path, "r");
1783}
1784
1785static void
1786end_ethent(void)
1787{
1788 if (eth_p) {
1789 fclose(eth_p);
1790 eth_p = NULL((void*)0);
1791 }
1792}
1793
1794static ether_t *
1795get_ethent(unsigned int *mask, const bool_Bool accept_mask)
1796{
1797
1798 static ether_t eth;
1799 char buf[MAX_LINELEN1024];
1800
1801 if (eth_p == NULL((void*)0))
1802 return NULL((void*)0);
1803
1804 while (fgetline(buf, sizeof(buf), eth_p) >= 0) {
1805 if (parse_ether_line(buf, &eth, mask, accept_mask) == 0) {
1806 return &eth;
1807 }
1808 }
1809
1810 return NULL((void*)0);
1811
1812} /* get_ethent */
1813
1814static hashmanuf_t *
1815manuf_hash_new_entry(const uint8_t *addr, const char* name, const char* longname)
1816{
1817 unsigned manuf_key;
1818 hashmanuf_t *manuf_value;
1819 char *endp;
1820
1821 /* manuf needs only the 3 most significant octets of the ethernet address */
1822 manuf_key = (addr[0] << 16) + (addr[1] << 8) + addr[2];
1823 manuf_value = wmem_new(addr_resolv_scope, hashmanuf_t)((hashmanuf_t*)wmem_alloc((addr_resolv_scope), sizeof(hashmanuf_t
)))
;
1824
1825 memcpy(manuf_value->addr, addr, 3);
1826 if (name != NULL((void*)0)) {
1827 (void) g_strlcpy(manuf_value->resolved_name, name, MAXNAMELEN64);
1828 manuf_value->flags = NAME_RESOLVED(1U<<1);
1829 if (longname != NULL((void*)0)) {
1830 (void) g_strlcpy(manuf_value->resolved_longname, longname, MAXNAMELEN64);
1831 }
1832 else {
1833 (void) g_strlcpy(manuf_value->resolved_longname, name, MAXNAMELEN64);
1834 }
1835 }
1836 else {
1837 manuf_value->flags = 0;
1838 manuf_value->resolved_name[0] = '\0';
1839 manuf_value->resolved_longname[0] = '\0';
1840 }
1841 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
1842 endp = bytes_to_hexstr_punct(manuf_value->hexaddr, addr, sizeof(manuf_value->addr), ':');
1843 *endp = '\0';
1844
1845 wmem_map_insert(manuf_hashtable, GUINT_TO_POINTER(manuf_key)((gpointer) (gulong) (manuf_key)), manuf_value);
1846 return manuf_value;
1847}
1848
1849static hashwka_t*
1850wka_hash_new_entry(const uint8_t *addr, char* name)
1851{
1852 uint8_t *wka_key;
1853 hashwka_t *wka_value;
1854
1855 wka_key = (uint8_t *)wmem_alloc(addr_resolv_scope, 6);
1856 memcpy(wka_key, addr, 6);
1857
1858 wka_value = (hashwka_t*)wmem_new(addr_resolv_scope, hashwka_t)((hashwka_t*)wmem_alloc((addr_resolv_scope), sizeof(hashwka_t
)))
;
1859 wka_value->flags = NAME_RESOLVED(1U<<1);
1860 wka_value->name = wmem_strdup(addr_resolv_scope, name);
1861
1862 wmem_map_insert(wka_hashtable, wka_key, wka_value);
1863 return wka_value;
1864}
1865
1866static void
1867add_manuf_name(const uint8_t *addr, unsigned int mask, char *name, char *longname)
1868{
1869 switch (mask)
1870 {
1871 case 0:
1872 {
1873 /* This is a manufacturer ID; add it to the manufacturer ID hash table */
1874 hashmanuf_t *entry = manuf_hash_new_entry(addr, name, longname);
1875 entry->flags |= STATIC_HOSTNAME(1U<<3);
1876 break;
1877 }
1878 case 48:
1879 {
1880 /* This is a well-known MAC address; add it to the Ethernet hash table */
1881 add_eth_name(addr, name, true1);
1882 break;
1883 }
1884 default:
1885 {
1886 /* This is a range of well-known addresses; add it to the well-known-address table */
1887 hashwka_t *entry = wka_hash_new_entry(addr, name);
1888 entry->flags |= STATIC_HOSTNAME(1U<<3);
1889 break;
1890 }
1891 }
1892} /* add_manuf_name */
1893
1894/* XXX: manuf_name_lookup returns a hashmanuf_t*, which cannot hold a 28 or
1895 * 36 bit MA-M or MA-S. So it returns those as unresolved. For EUI-48 and
1896 * EUI-64, MA-M and MA-S should be checked for separately in the global
1897 * tables.
1898 *
1899 * XXX - size_t is used only in a ws_return_val_if() that checks
1900 * whether the argument has at least 3 bytes; that's done only if
1901 * assertions are enabled, so it's used only if assertions are
1902 * enabled. This means that, if assertions aren't enabled, a
1903 * warning that the argument is unused will be issued by at least
1904 * some compilers, so we mark it as unused. Should we do that
1905 * check unconditionally, and just emit a warning if assertions
1906 * are enabled?
1907 */
1908static hashmanuf_t *
1909manuf_name_lookup(const uint8_t *addr, size_t size _U___attribute__((unused)))
1910{
1911 uint32_t manuf_key;
1912 uint8_t oct;
1913 hashmanuf_t *manuf_value;
1914
1915 ws_return_val_if(size < 3, NULL)do { if (1 && (size < 3)) { ws_log_full("InvalidArg"
, LOG_LEVEL_WARNING, "epan/addr_resolv.c", 1915, __func__, "invalid argument: %s"
, "size < 3"); return (((void*)0)); } } while (0)
;
1916
1917 /* manuf needs only the 3 most significant octets of the ethernet address */
1918 manuf_key = addr[0];
1919 manuf_key = manuf_key<<8;
1920 oct = addr[1];
1921 manuf_key = manuf_key | oct;
1922 manuf_key = manuf_key<<8;
1923 oct = addr[2];
1924 manuf_key = manuf_key | oct;
1925
1926
1927 /* first try to find a "perfect match" */
1928 manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, GUINT_TO_POINTER(manuf_key)((gpointer) (gulong) (manuf_key)));
1929 if (manuf_value != NULL((void*)0)) {
1930 manuf_value->flags |= TRIED_RESOLVE_ADDRESS(1U<<0);
1931 return manuf_value;
1932 }
1933
1934 /* Mask out the broadcast/multicast flag but not the locally
1935 * administered flag as locally administered means: not assigned
1936 * by the IEEE but the local administrator instead.
1937 * 0x01 multicast / broadcast bit
1938 * 0x02 locally administered bit */
1939 if ((manuf_key & 0x00010000) != 0) {
1940 manuf_key &= 0x00FEFFFF;
1941 manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, GUINT_TO_POINTER(manuf_key)((gpointer) (gulong) (manuf_key)));
1942 if (manuf_value != NULL((void*)0)) {
1943 manuf_value->flags |= TRIED_RESOLVE_ADDRESS(1U<<0);
1944 return manuf_value;
1945 }
1946 }
1947
1948 /* Try the global manuf tables. */
1949 const char *short_name, *long_name;
1950 /* We can't insert a 28 or 36 bit entry into the used hash table. */
1951 short_name = ws_manuf_lookup_oui24(addr, &long_name);
1952 if (short_name != NULL((void*)0)) {
1953 /* Found it */
1954 manuf_value = manuf_hash_new_entry(addr, short_name, long_name);
1955 } else {
1956 /* Add the address as a hex string */
1957 manuf_value = manuf_hash_new_entry(addr, NULL((void*)0), NULL((void*)0));
1958 }
1959
1960 manuf_value->flags |= TRIED_RESOLVE_ADDRESS(1U<<0);
1961 return manuf_value;
1962
1963} /* manuf_name_lookup */
1964
1965static char *
1966wka_name_lookup(const uint8_t *addr, const unsigned int mask)
1967{
1968 uint8_t masked_addr[6];
1969 unsigned num;
1970 int i;
1971 hashwka_t *value;
1972
1973 if (wka_hashtable == NULL((void*)0)) {
1974 return NULL((void*)0);
1975 }
1976 /* Get the part of the address covered by the mask. */
1977 for (i = 0, num = mask; num >= 8; i++, num -= 8)
1978 masked_addr[i] = addr[i]; /* copy octets entirely covered by the mask */
1979 /* Mask out the first masked octet */
1980 masked_addr[i] = addr[i] & (0xFF << (8 - num));
1981 i++;
1982 /* Zero out completely-masked-out octets */
1983 for (; i < 6; i++)
1984 masked_addr[i] = 0;
1985
1986 value = (hashwka_t*)wmem_map_lookup(wka_hashtable, masked_addr);
1987
1988 if (value) {
1989 value->flags |= TRIED_RESOLVE_ADDRESS(1U<<0);
1990 return value->name;
1991 }
1992
1993 return NULL((void*)0);
1994
1995} /* wka_name_lookup */
1996
1997unsigned get_hash_ether_status(hashether_t* ether)
1998{
1999 return ether->flags;
2000}
2001
2002bool_Bool get_hash_ether_used(hashether_t* ether)
2003{
2004 return ((ether->flags & TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1))) == TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1)));
2005}
2006
2007char* get_hash_ether_hexaddr(hashether_t* ether)
2008{
2009 return ether->hexaddr;
2010}
2011
2012char* get_hash_ether_resolved_name(hashether_t* ether)
2013{
2014 return ether->resolved_name;
2015}
2016
2017bool_Bool get_hash_wka_used(hashwka_t* wka)
2018{
2019 return ((wka->flags & TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1))) == TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1)));
2020}
2021
2022char* get_hash_wka_resolved_name(hashwka_t* wka)
2023{
2024 return wka->name;
2025}
2026
2027static unsigned
2028eth_addr_hash(const void *key)
2029{
2030 return wmem_strong_hash((const uint8_t *)key, 6);
2031}
2032
2033static gboolean
2034eth_addr_cmp(const void *a, const void *b)
2035{
2036 return (memcmp(a, b, 6) == 0);
2037}
2038
2039static unsigned
2040eui64_addr_hash(const void *key)
2041{
2042 return wmem_strong_hash((const uint8_t *)key, EUI64_ADDR_LEN8);
2043}
2044
2045static gboolean
2046eui64_addr_cmp(const void *a, const void *b)
2047{
2048 return (memcmp(a, b, EUI64_ADDR_LEN8) == 0);
2049}
2050
2051static void
2052initialize_ethers(const char* app_env_var_prefix)
2053{
2054 ether_t *eth;
2055 unsigned mask = 0;
2056
2057 /* hash table initialization */
2058 ws_assert(wka_hashtable == NULL)do { if ((1) && !(wka_hashtable == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 2058, __func__, "assertion failed: %s"
, "wka_hashtable == ((void*)0)"); } while (0)
;
2059 wka_hashtable = wmem_map_new(addr_resolv_scope, eth_addr_hash, eth_addr_cmp);
2060 ws_assert(manuf_hashtable == NULL)do { if ((1) && !(manuf_hashtable == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 2060, __func__, "assertion failed: %s"
, "manuf_hashtable == ((void*)0)"); } while (0)
;
2061 manuf_hashtable = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
2062 ws_assert(eth_hashtable == NULL)do { if ((1) && !(eth_hashtable == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 2062, __func__, "assertion failed: %s"
, "eth_hashtable == ((void*)0)"); } while (0)
;
2063 eth_hashtable = wmem_map_new(addr_resolv_scope, eth_addr_hash, eth_addr_cmp);
2064 ws_assert(eui64_hashtable == NULL)do { if ((1) && !(eui64_hashtable == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 2064, __func__, "assertion failed: %s"
, "eui64_hashtable == ((void*)0)"); } while (0)
;
2065 eui64_hashtable = wmem_map_new(addr_resolv_scope, eui64_addr_hash, eui64_addr_cmp);
2066
2067 /* Compute the pathname of the ethers file. */
2068 if (g_ethers_path == NULL((void*)0)) {
2069 g_ethers_path = g_build_filename(get_systemfile_dir(app_env_var_prefix), ENAME_ETHERS"ethers", NULL((void*)0));
2070 }
2071
2072 /* Compute the pathname of the personal ethers file. */
2073 if (g_pethers_path == NULL((void*)0)) {
2074 /* Check profile directory before personal configuration */
2075 g_pethers_path = get_persconffile_path(ENAME_ETHERS"ethers", true1, app_env_var_prefix);
2076 if (!file_exists(g_pethers_path)) {
2077 g_free(g_pethers_path);
2078 g_pethers_path = get_persconffile_path(ENAME_ETHERS"ethers", false0, app_env_var_prefix);
2079 }
2080 }
2081
2082 /* Compute the pathname of the global manuf file */
2083 if (g_manuf_path == NULL((void*)0))
2084 g_manuf_path = get_datafile_path(ENAME_MANUF"manuf", app_env_var_prefix);
2085 /* Read it and initialize the hash table */
2086 if (file_exists(g_manuf_path)) {
2087 set_ethent(g_manuf_path);
2088 while ((eth = get_ethent(&mask, true1))) {
2089 add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2090 }
2091 end_ethent();
2092 }
2093
2094 /* Compute the pathname of the personal manuf file */
2095 if (g_pmanuf_path == NULL((void*)0)) {
2096 /* Check profile directory before personal configuration */
2097 g_pmanuf_path = get_persconffile_path(ENAME_MANUF"manuf", true1, app_env_var_prefix);
2098 if (!file_exists(g_pmanuf_path)) {
2099 g_free(g_pmanuf_path);
2100 g_pmanuf_path = get_persconffile_path(ENAME_MANUF"manuf", false0, app_env_var_prefix);
2101 }
2102 }
2103 /* Read it and initialize the hash table */
2104 if (file_exists(g_pmanuf_path)) {
2105 set_ethent(g_pmanuf_path);
2106 while ((eth = get_ethent(&mask, true1))) {
2107 add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2108 }
2109 end_ethent();
2110 }
2111
2112 /* Compute the pathname of the wka file */
2113 if (g_wka_path == NULL((void*)0))
2114 g_wka_path = get_datafile_path(ENAME_WKA"wka", app_env_var_prefix);
2115
2116 /* Read it and initialize the hash table */
2117 set_ethent(g_wka_path);
2118 while ((eth = get_ethent(&mask, true1))) {
2119 add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2120 }
2121 end_ethent();
2122
2123 /* Look at the ethers files last. These are set as static names,
2124 * so they override earlier entries, and the ones we read last
2125 * take precedence. Order of precedence is personal ethers file,
2126 * global ethers file, wka file, personal manuf file, global manuf
2127 * file, and then non-static sources like ARP Eth -> IP hostname
2128 * discovery (if enabled), NRB entries (if wiretap adds support for
2129 * EUI-48 in NRBs), etc.
2130 * XXX: What _is_ the proper order of precedence, and should it
2131 * be configurable? (cf. #18075) */
2132 set_ethent(g_ethers_path);
2133 while ((eth = get_ethent(&mask, false0))) {
2134 if (mask == 48) {
2135 add_eth_name(eth->addr, eth->name, true1);
2136 } else if (mask == 64) {
2137 add_eui64_name(eth->addr, eth->name, true1);
2138 }
2139 }
2140 end_ethent();
2141
2142 if (file_exists(g_pethers_path)) {
2143 set_ethent(g_pethers_path);
2144 while ((eth = get_ethent(&mask, false0))) {
2145 if (mask == 48) {
2146 add_eth_name(eth->addr, eth->name, true1);
2147 } else if (mask == 64) {
2148 add_eui64_name(eth->addr, eth->name, true1);
2149 }
2150 }
2151 end_ethent();
2152 }
2153
2154} /* initialize_ethers */
2155
2156static void
2157ethers_cleanup(void)
2158{
2159 wka_hashtable = NULL((void*)0);
2160 manuf_hashtable = NULL((void*)0);
2161 eth_hashtable = NULL((void*)0);
2162 eui64_hashtable = NULL((void*)0);
2163 g_free(g_ethers_path);
2164 g_ethers_path = NULL((void*)0);
2165 g_free(g_pethers_path);
2166 g_pethers_path = NULL((void*)0);
2167 g_free(g_manuf_path);
2168 g_manuf_path = NULL((void*)0);
2169 g_free(g_pmanuf_path);
2170 g_pmanuf_path = NULL((void*)0);
2171 g_free(g_wka_path);
2172 g_wka_path = NULL((void*)0);
2173}
2174
2175static void
2176eth_resolved_name_fill(hashether_t *tp, const char *name, unsigned mask, const uint8_t *addr)
2177{
2178 switch (mask) {
2179 case 24:
2180 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%02x:%02x:%02x",
2181 name, addr[3], addr[4], addr[5]);
2182 break;
2183 case 28:
2184 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%01x:%02x:%02x",
2185 name, addr[3] & 0x0F, addr[4], addr[5]);
2186 break;
2187 case 36:
2188 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%01x:%02x",
2189 name, addr[4] & 0x0F, addr[5]);
2190 break;
2191 default: // Future-proof generic algorithm
2192 {
2193 unsigned bytes = mask / 8;
2194 unsigned bitmask = mask % 8;
2195
2196 int pos = snprintf(tp->resolved_name, MAXNAMELEN64, "%s", name);
2197 if (pos >= MAXNAMELEN64) return;
2198
2199 if (bytes < 6) {
2200 pos += snprintf(tp->resolved_name + pos, MAXNAMELEN64 - pos,
2201 bitmask >= 4 ? "_%01x" : "_%02x",
2202 addr[bytes] & (0xFF >> bitmask));
2203 bytes++;
2204 }
2205
2206 while (bytes < 6) {
2207 if (pos >= MAXNAMELEN64) return;
2208 pos += snprintf(tp->resolved_name + pos, MAXNAMELEN64 - pos, ":%02x",
2209 addr[bytes]);
2210 bytes++;
2211 }
2212 }
2213 }
2214}
2215
2216/* Resolve ethernet address */
2217static hashether_t *
2218eth_addr_resolve(hashether_t *tp) {
2219 hashmanuf_t *manuf_value;
2220 const uint8_t *addr = tp->addr;
2221 size_t addr_size = sizeof(tp->addr);
2222
2223 if (!(tp->flags & NAME_RESOLVED(1U<<1))) {
2224 unsigned mask;
2225 char *name;
2226 address ether_addr;
2227
2228 /* Unknown name. Try looking for it in the well-known-address
2229 tables for well-known address ranges smaller than 2^24. */
2230 mask = 7;
2231 do {
2232 /* Only the topmost 5 bytes participate fully */
2233 if ((name = wka_name_lookup(addr, mask+40)) != NULL((void*)0)) {
2234 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%02x",
2235 name, addr[5] & (0xFF >> mask));
2236 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2237 return tp;
2238 }
2239 } while (mask--);
2240
2241 mask = 7;
2242 do {
2243 /* Only the topmost 4 bytes participate fully */
2244 if ((name = wka_name_lookup(addr, mask+32)) != NULL((void*)0)) {
2245 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%02x:%02x",
2246 name, addr[4] & (0xFF >> mask), addr[5]);
2247 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2248 return tp;
2249 }
2250 } while (mask--);
2251
2252 mask = 7;
2253 do {
2254 /* Only the topmost 3 bytes participate fully */
2255 if ((name = wka_name_lookup(addr, mask+24)) != NULL((void*)0)) {
2256 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%02x:%02x:%02x",
2257 name, addr[3] & (0xFF >> mask), addr[4], addr[5]);
2258 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2259 return tp;
2260 }
2261 } while (mask--);
2262
2263 /* Now try looking in the manufacturer table. */
2264 manuf_value = manuf_name_lookup(addr, addr_size);
2265 if ((manuf_value != NULL((void*)0)) && ((manuf_value->flags & NAME_RESOLVED(1U<<1)) == NAME_RESOLVED(1U<<1))) {
2266 snprintf(tp->resolved_name, MAXNAMELEN64, "%.*s_%02x:%02x:%02x",
2267 MAXNAMELEN64 - 10, manuf_value->resolved_name, addr[3], addr[4], addr[5]);
2268 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2269 return tp;
2270 }
2271
2272 /* Now try looking for it in the well-known-address
2273 tables for well-known address ranges larger than 2^24. */
2274 mask = 7;
2275 do {
2276 /* Only the topmost 2 bytes participate fully */
2277 if ((name = wka_name_lookup(addr, mask+16)) != NULL((void*)0)) {
2278 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%02x:%02x:%02x:%02x",
2279 name, addr[2] & (0xFF >> mask), addr[3], addr[4],
2280 addr[5]);
2281 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2282 return tp;
2283 }
2284 } while (mask--);
2285
2286 mask = 7;
2287 do {
2288 /* Only the topmost byte participates fully */
2289 if ((name = wka_name_lookup(addr, mask+8)) != NULL((void*)0)) {
2290 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%02x:%02x:%02x:%02x:%02x",
2291 name, addr[1] & (0xFF >> mask), addr[2], addr[3],
2292 addr[4], addr[5]);
2293 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2294 return tp;
2295 }
2296 } while (mask--);
2297
2298 mask = 7;
2299 do {
2300 /* Not even the topmost byte participates fully */
2301 if ((name = wka_name_lookup(addr, mask)) != NULL((void*)0)) {
2302 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
2303 name, addr[0] & (0xFF >> mask), addr[1], addr[2],
2304 addr[3], addr[4], addr[5]);
2305 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2306 return tp;
2307 }
2308 } while (--mask); /* Work down to the last bit */
2309
2310 /* Now try looking in the global manuf data for a MA-M or MA-S
2311 * match. We do this last so that the other files override this
2312 * result.
2313 */
2314 const char *short_name, *long_name;
2315 short_name = ws_manuf_lookup(addr, &long_name, &mask);
2316 if (short_name != NULL((void*)0)) {
2317 if (mask == 24) {
2318 /* This shouldn't happen as it should be handled above,
2319 * but it doesn't hurt.
2320 */
2321 manuf_hash_new_entry(addr, short_name, long_name);
2322 }
2323 eth_resolved_name_fill(tp, short_name, mask, addr);
2324 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2325 return tp;
2326 }
2327 /* No match whatsoever. */
2328 set_address(&ether_addr, AT_ETHER, 6, addr);
2329 address_to_str_buf(&ether_addr, tp->resolved_name, MAXNAMELEN64);
2330 return tp;
2331 }
2332 return tp;
2333} /* eth_addr_resolve */
2334
2335static hashether_t *
2336eth_hash_new_entry(const uint8_t *addr, const bool_Bool resolve)
2337{
2338 hashether_t *tp;
2339 char *endp;
2340
2341 tp = wmem_new(addr_resolv_scope, hashether_t)((hashether_t*)wmem_alloc((addr_resolv_scope), sizeof(hashether_t
)))
;
2342 memcpy(tp->addr, addr, sizeof(tp->addr));
2343 tp->flags = 0;
2344 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
2345 endp = bytes_to_hexstr_punct(tp->hexaddr, addr, sizeof(tp->addr), ':');
2346 *endp = '\0';
2347 tp->resolved_name[0] = '\0';
2348
2349 if (resolve)
2350 eth_addr_resolve(tp);
2351
2352 wmem_map_insert(eth_hashtable, tp->addr, tp);
2353
2354 return tp;
2355} /* eth_hash_new_entry */
2356
2357static hashether_t *
2358add_eth_name(const uint8_t *addr, const char *name, bool_Bool static_entry)
2359{
2360 hashether_t *tp;
2361
2362 tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
2363
2364 if (tp == NULL((void*)0)) {
2365 tp = eth_hash_new_entry(addr, false0);
2366 }
2367
2368 if (strcmp(tp->resolved_name, name) != 0 && (static_entry || !(tp->flags & STATIC_HOSTNAME(1U<<3)))) {
2369 (void) g_strlcpy(tp->resolved_name, name, MAXNAMELEN64);
2370 tp->flags |= NAME_RESOLVED(1U<<1);
2371 if (static_entry) {
2372 tp->flags |= STATIC_HOSTNAME(1U<<3);
2373 }
2374 new_resolved_objects = true1;
2375 }
2376
2377 return tp;
2378} /* add_eth_name */
2379
2380static hashether_t *
2381eth_name_lookup(const uint8_t *addr, const bool_Bool resolve)
2382{
2383 hashether_t *tp;
2384
2385 tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
2386
2387 if (tp == NULL((void*)0)) {
2388 tp = eth_hash_new_entry(addr, resolve);
2389 } else {
2390 if (resolve && !(tp->flags & TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1)))) {
2391 eth_addr_resolve(tp); /* Found but needs to be resolved */
2392 }
2393 }
2394 if (resolve) {
2395 tp->flags |= TRIED_RESOLVE_ADDRESS(1U<<0);
2396 }
2397
2398 return tp;
2399
2400} /* eth_name_lookup */
2401
2402static void
2403eui64_resolved_name_fill(hasheui64_t *tp, const char *name, unsigned mask, const uint8_t *addr)
2404{
2405 switch (mask) {
2406 case 24:
2407 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%02x:%02x:%02x:%02x:%02x",
2408 name, addr[3], addr[4], addr[5], addr[6], addr[7]);
2409 break;
2410 case 28:
2411 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%01x:%02x:%02x:%02x:%02x",
2412 name, addr[3] & 0x0F, addr[4], addr[5], addr[6], addr[7]);
2413 break;
2414 case 36:
2415 snprintf(tp->resolved_name, MAXNAMELEN64, "%s_%01x:%02x:%02x:%02x",
2416 name, addr[4] & 0x0F, addr[5], addr[6], addr[7]);
2417 break;
2418 default: // Future-proof generic algorithm
2419 {
2420 unsigned bytes = mask / 8;
2421 unsigned bitmask = mask % 8;
2422
2423 int pos = snprintf(tp->resolved_name, MAXNAMELEN64, "%s", name);
2424 if (pos >= MAXNAMELEN64) return;
2425
2426 if (bytes < EUI64_ADDR_LEN8) {
2427 pos += snprintf(tp->resolved_name + pos, MAXNAMELEN64 - pos,
2428 bitmask >= 4 ? "_%01x" : "_%02x",
2429 addr[bytes] & (0xFF >> bitmask));
2430 bytes++;
2431 }
2432
2433 while (bytes < EUI64_ADDR_LEN8) {
2434 if (pos >= MAXNAMELEN64) return;
2435 pos += snprintf(tp->resolved_name + pos, MAXNAMELEN64 - pos, ":%02x",
2436 addr[bytes]);
2437 bytes++;
2438 }
2439 }
2440 }
2441}
2442
2443/* Resolve EUI-64 address */
2444static hasheui64_t *
2445eui64_addr_resolve(hasheui64_t *tp)
2446{
2447 hashmanuf_t *manuf_value;
2448 const uint8_t *addr = tp->addr;
2449 size_t addr_size = sizeof(tp->addr);
2450
2451 if (!(tp->flags & NAME_RESOLVED(1U<<1))) {
2452 unsigned mask;
2453 address eui64_addr;
2454 /* manuf_name_lookup returns a hashmanuf_t* that covers an entire /24,
2455 * so we can't properly use it for MA-M and MA-S. We do want to check
2456 * it first so it also covers the user-defined tables.
2457 */
2458 manuf_value = manuf_name_lookup(addr, addr_size);
2459 if ((manuf_value != NULL((void*)0)) && ((manuf_value->flags & NAME_RESOLVED(1U<<1)) == NAME_RESOLVED(1U<<1))) {
2460 snprintf(tp->resolved_name, MAXNAMELEN64, "%.*s_%02x:%02x:%02x:%02x:%02x",
2461 MAXNAMELEN64 - 16, manuf_value->resolved_name, addr[3], addr[4], addr[5], addr[6], addr[7]);
2462 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2463 return tp;
2464 }
2465
2466 /* Now try looking in the global manuf data for a MA-M or MA-S
2467 * match. We do this last so that the other files override this
2468 * result.
2469 */
2470 const char *short_name, *long_name;
2471 short_name = ws_manuf_lookup(addr, &long_name, &mask);
2472 if (short_name != NULL((void*)0)) {
2473 if (mask == 24) {
2474 /* This shouldn't happen as it should be handled above,
2475 * but it doesn't hurt.
2476 */
2477 manuf_hash_new_entry(addr, short_name, long_name);
2478 }
2479 eui64_resolved_name_fill(tp, short_name, mask, addr);
2480 tp->flags |= NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4);
2481 return tp;
2482 }
2483 /* No match whatsoever. */
2484 set_address(&eui64_addr, AT_EUI64, 8, addr);
2485 address_to_str_buf(&eui64_addr, tp->resolved_name, MAXNAMELEN64);
2486 return tp;
2487 }
2488
2489 return tp;
2490} /* eui64_addr_resolve */
2491
2492static hasheui64_t *
2493eui64_hash_new_entry(const uint8_t *addr, const bool_Bool resolve)
2494{
2495 hasheui64_t *tp;
2496 char *endp;
2497
2498 tp = wmem_new(addr_resolv_scope, hasheui64_t)((hasheui64_t*)wmem_alloc((addr_resolv_scope), sizeof(hasheui64_t
)))
;
2499 memcpy(tp->addr, addr, sizeof(tp->addr));
2500 tp->flags = 0;
2501 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
2502 endp = bytes_to_hexstr_punct(tp->hexaddr, addr, sizeof(tp->addr), ':');
2503 *endp = '\0';
2504 tp->resolved_name[0] = '\0';
2505
2506 if (resolve)
2507 eui64_addr_resolve(tp);
2508
2509 wmem_map_insert(eui64_hashtable, tp->addr, tp);
2510
2511 return tp;
2512} /* eui64_hash_new_entry */
2513
2514static hasheui64_t *
2515add_eui64_name(const uint8_t *addr, const char *name, bool_Bool static_entry)
2516{
2517 hasheui64_t *tp;
2518
2519 tp = (hasheui64_t *)wmem_map_lookup(eui64_hashtable, addr);
2520
2521 if (tp == NULL((void*)0)) {
2522 tp = eui64_hash_new_entry(addr, false0);
2523 }
2524
2525 if (strcmp(tp->resolved_name, name) != 0 && (static_entry || !(tp->flags & STATIC_HOSTNAME(1U<<3)))) {
2526 (void) g_strlcpy(tp->resolved_name, name, MAXNAMELEN64);
2527 tp->flags |= NAME_RESOLVED(1U<<1);
2528 if (static_entry) {
2529 tp->flags |= STATIC_HOSTNAME(1U<<3);
2530 }
2531 new_resolved_objects = true1;
2532 }
2533
2534 return tp;
2535} /* add_eui64_name */
2536
2537static hasheui64_t *
2538eui64_name_lookup(const uint8_t *addr, const bool_Bool resolve)
2539{
2540 hasheui64_t *tp;
2541
2542 tp = (hasheui64_t *)wmem_map_lookup(eui64_hashtable, addr);
2543
2544 if (tp == NULL((void*)0)) {
2545 tp = eui64_hash_new_entry(addr, resolve);
2546 } else {
2547 if (resolve && !(tp->flags & TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1)))) {
2548 eui64_addr_resolve(tp); /* Found but needs to be resolved */
2549 }
2550 }
2551 if (resolve) {
2552 tp->flags |= TRIED_RESOLVE_ADDRESS(1U<<0);
2553 }
2554
2555 return tp;
2556
2557} /* eui64_name_lookup */
2558
2559/* IPXNETS */
2560static int
2561parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
2562{
2563 /*
2564 * We allow three address separators (':', '-', and '.'),
2565 * as well as no separators
2566 */
2567
2568 char *cp;
2569 uint32_t a, a0, a1, a2, a3;
2570 bool_Bool found_single_number = false0;
2571
2572 if ((cp = strchr(line, '#')))
2573 *cp = '\0';
2574
2575 if ((cp = strtok(line, " \t\n")) == NULL((void*)0))
2576 return -1;
2577
2578 /* Either fill a0,a1,a2,a3 and found_single_number is false,
2579 * fill a and found_single_number is true,
2580 * or return -1
2581 */
2582 if (sscanf(cp, "%x:%x:%x:%x", &a0, &a1, &a2, &a3) != 4) {
2583 if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
2584 if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
2585 if (sscanf(cp, "%x", &a) == 1) {
2586 found_single_number = true1;
2587 }
2588 else {
2589 return -1;
2590 }
2591 }
2592 }
2593 }
2594
2595 if ((cp = strtok(NULL((void*)0), " \t\n")) == NULL((void*)0))
2596 return -1;
2597
2598 if (found_single_number) {
2599 ipxnet->addr = a;
2600 }
2601 else {
2602 ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
2603 }
2604
2605 (void) g_strlcpy(ipxnet->name, cp, MAXNAMELEN64);
2606
2607 return 0;
2608
2609} /* parse_ipxnets_line */
2610
2611static FILE *ipxnet_p;
2612
2613static void
2614set_ipxnetent(char *path)
2615{
2616 if (ipxnet_p)
8
Assuming 'ipxnet_p' is non-null
9
Taking true branch
2617 rewind(ipxnet_p);
10
After calling 'rewind' reading 'errno' is required to find out if the call has failed
2618 else
2619 ipxnet_p = ws_fopenfopen(path, "r");
2620}
2621
2622static void
2623end_ipxnetent(void)
2624{
2625 if (ipxnet_p) {
2626 fclose(ipxnet_p);
2627 ipxnet_p = NULL((void*)0);
2628 }
2629}
2630
2631static ipxnet_t *
2632get_ipxnetent(void)
2633{
2634
2635 static ipxnet_t ipxnet;
2636 char buf[MAX_LINELEN1024];
2637
2638 if (ipxnet_p
12.1
'ipxnet_p' is not equal to NULL
== NULL((void*)0))
13
Taking false branch
2639 return NULL((void*)0);
2640
2641 while (fgetline(buf, sizeof(buf), ipxnet_p) >= 0) {
14
Calling 'fgetline'
2642 if (parse_ipxnets_line(buf, &ipxnet) == 0) {
2643 return &ipxnet;
2644 }
2645 }
2646
2647 return NULL((void*)0);
2648
2649} /* get_ipxnetent */
2650
2651static ipxnet_t *
2652get_ipxnetbyaddr(uint32_t addr)
2653{
2654 ipxnet_t *ipxnet;
2655
2656 set_ipxnetent(g_ipxnets_path);
7
Calling 'set_ipxnetent'
11
Returning from 'set_ipxnetent'
2657
2658 while (((ipxnet = get_ipxnetent()) != NULL((void*)0)) && (addr != ipxnet->addr) ) ;
12
Calling 'get_ipxnetent'
2659
2660 if (ipxnet == NULL((void*)0)) {
2661 end_ipxnetent();
2662
2663 set_ipxnetent(g_pipxnets_path);
2664
2665 while (((ipxnet = get_ipxnetent()) != NULL((void*)0)) && (addr != ipxnet->addr) )
2666 ;
2667
2668 end_ipxnetent();
2669 }
2670
2671 return ipxnet;
2672
2673} /* get_ipxnetbyaddr */
2674
2675static void
2676initialize_ipxnets(const char* app_env_var_prefix)
2677{
2678 /* Compute the pathname of the ipxnets file.
2679 *
2680 * XXX - is there a notion of an "ipxnets file" in any flavor of
2681 * UNIX, or with any add-on Netware package for UNIX? If not,
2682 * should the UNIX version of the ipxnets file be in the datafile
2683 * directory as well?
2684 */
2685 if (g_ipxnets_path == NULL((void*)0)) {
2686 g_ipxnets_path = wmem_strdup_printf(addr_resolv_scope, "%s" G_DIR_SEPARATOR_S"/" "%s",
2687 get_systemfile_dir(app_env_var_prefix), ENAME_IPXNETS"ipxnets");
2688 }
2689
2690 /* Set g_pipxnets_path here, but don't actually do anything
2691 * with it. It's used in get_ipxnetbyaddr().
2692 */
2693 if (g_pipxnets_path == NULL((void*)0)) {
2694 /* Check profile directory before personal configuration */
2695 g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS"ipxnets", true1, app_env_var_prefix);
2696 if (!file_exists(g_pipxnets_path)) {
2697 g_free(g_pipxnets_path);
2698 g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS"ipxnets", false0, app_env_var_prefix);
2699 }
2700 }
2701
2702} /* initialize_ipxnets */
2703
2704static void
2705ipx_name_lookup_cleanup(void)
2706{
2707 g_ipxnets_path = NULL((void*)0);
2708 g_free(g_pipxnets_path);
2709 g_pipxnets_path = NULL((void*)0);
2710}
2711
2712static char *
2713ipxnet_name_lookup(wmem_allocator_t *allocator, const unsigned addr)
2714{
2715 hashipxnet_t *tp;
2716 ipxnet_t *ipxnet;
2717
2718 tp = (hashipxnet_t *)wmem_map_lookup(ipxnet_hash_table, GUINT_TO_POINTER(addr)((gpointer) (gulong) (addr)));
2719 if (tp == NULL((void*)0)) {
4
Assuming 'tp' is equal to NULL
5
Taking true branch
2720 tp = wmem_new(addr_resolv_scope, hashipxnet_t)((hashipxnet_t*)wmem_alloc((addr_resolv_scope), sizeof(hashipxnet_t
)))
;
2721 wmem_map_insert(ipxnet_hash_table, GUINT_TO_POINTER(addr)((gpointer) (gulong) (addr)), tp);
2722 } else {
2723 return wmem_strdup(allocator, tp->name);
2724 }
2725
2726 /* fill in a new entry */
2727
2728 tp->addr = addr;
2729
2730 if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL((void*)0)) {
6
Calling 'get_ipxnetbyaddr'
2731 /* unknown name */
2732 snprintf(tp->name, MAXNAMELEN64, "%X", addr);
2733
2734 } else {
2735 (void) g_strlcpy(tp->name, ipxnet->name, MAXNAMELEN64);
2736 }
2737
2738 return wmem_strdup(allocator, tp->name);
2739
2740} /* ipxnet_name_lookup */
2741
2742/* VLANS */
2743static int
2744parse_vlan_line(char *line, vlan_t *vlan)
2745{
2746 char *cp;
2747 uint16_t id;
2748
2749 if ((cp = strchr(line, '#')))
2750 *cp = '\0';
2751
2752 if ((cp = strtok(line, " \t\n")) == NULL((void*)0))
2753 return -1;
2754
2755 if (sscanf(cp, "%" SCNu16"hu", &id) == 1) {
2756 vlan->id = id;
2757 }
2758 else {
2759 return -1;
2760 }
2761
2762 if ((cp = strtok(NULL((void*)0), "\t\n")) == NULL((void*)0))
2763 return -1;
2764
2765 (void) g_strlcpy(vlan->name, cp, MAXVLANNAMELEN128);
2766
2767 return 0;
2768
2769} /* parse_vlan_line */
2770
2771static FILE *vlan_p;
2772
2773static void
2774set_vlanent(char *path)
2775{
2776 if (vlan_p)
2777 rewind(vlan_p);
2778 else
2779 vlan_p = ws_fopenfopen(path, "r");
2780}
2781
2782static void
2783end_vlanent(void)
2784{
2785 if (vlan_p) {
2786 fclose(vlan_p);
2787 vlan_p = NULL((void*)0);
2788 }
2789}
2790
2791static vlan_t *
2792get_vlanent(void)
2793{
2794
2795 static vlan_t vlan;
2796 char buf[MAX_LINELEN1024];
2797
2798 if (vlan_p == NULL((void*)0))
2799 return NULL((void*)0);
2800
2801 while (fgetline(buf, sizeof(buf), vlan_p) >= 0) {
2802 if (parse_vlan_line(buf, &vlan) == 0) {
2803 return &vlan;
2804 }
2805 }
2806
2807 return NULL((void*)0);
2808
2809} /* get_vlanent */
2810
2811static vlan_t *
2812get_vlannamebyid(uint16_t id)
2813{
2814 vlan_t *vlan;
2815
2816 set_vlanent(g_pvlan_path);
2817
2818 while (((vlan = get_vlanent()) != NULL((void*)0)) && (id != vlan->id) ) ;
2819
2820 if (vlan == NULL((void*)0)) {
2821 end_vlanent();
2822
2823 }
2824
2825 return vlan;
2826
2827} /* get_vlannamebyid */
2828
2829static void
2830initialize_vlans(const char* app_env_var_prefix)
2831{
2832 ws_assert(vlan_hash_table == NULL)do { if ((1) && !(vlan_hash_table == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 2832, __func__, "assertion failed: %s"
, "vlan_hash_table == ((void*)0)"); } while (0)
;
2833 vlan_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
2834
2835 /* Set g_pvlan_path here, but don't actually do anything
2836 * with it. It's used in get_vlannamebyid()
2837 */
2838 if (g_pvlan_path == NULL((void*)0)) {
2839 /* Check profile directory before personal configuration */
2840 g_pvlan_path = get_persconffile_path(ENAME_VLANS"vlans", true1, app_env_var_prefix);
2841 if (!file_exists(g_pvlan_path)) {
2842 g_free(g_pvlan_path);
2843 g_pvlan_path = get_persconffile_path(ENAME_VLANS"vlans", false0, app_env_var_prefix);
2844 }
2845 }
2846} /* initialize_vlans */
2847
2848static void
2849vlan_name_lookup_cleanup(void)
2850{
2851 end_vlanent();
2852 vlan_hash_table = NULL((void*)0);
2853 g_free(g_pvlan_path);
2854 g_pvlan_path = NULL((void*)0);
2855}
2856
2857static const char *
2858vlan_name_lookup(const unsigned id)
2859{
2860 hashvlan_t *tp;
2861 vlan_t *vlan;
2862
2863 tp = (hashvlan_t *)wmem_map_lookup(vlan_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)));
2864 if (tp == NULL((void*)0)) {
2865 tp = wmem_new(addr_resolv_scope, hashvlan_t)((hashvlan_t*)wmem_alloc((addr_resolv_scope), sizeof(hashvlan_t
)))
;
2866 wmem_map_insert(vlan_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)), tp);
2867 } else {
2868 return tp->name;
2869 }
2870
2871 /* fill in a new entry */
2872
2873 tp->id = id;
2874
2875 if ( (vlan = get_vlannamebyid(id)) == NULL((void*)0)) {
2876 /* unknown name */
2877 snprintf(tp->name, MAXVLANNAMELEN128, "<%u>", id);
2878
2879 } else {
2880 (void) g_strlcpy(tp->name, vlan->name, MAXVLANNAMELEN128);
2881 }
2882
2883 return tp->name;
2884
2885} /* vlan_name_lookup */
2886/* VLAN END */
2887
2888static bool_Bool
2889read_hosts_file (const char *hostspath, bool_Bool store_entries)
2890{
2891 FILE *hf;
2892 char line[MAX_LINELEN1024];
2893 char *cp;
2894 union {
2895 uint32_t ip4_addr;
2896 ws_in6_addr ip6_addr;
2897 } host_addr;
2898 bool_Bool is_ipv6, entry_found = false0;
2899
2900 /*
2901 * See the hosts(4) or hosts(5) man page for hosts file format
2902 * (not available on all systems).
2903 */
2904 if ((hf = ws_fopenfopen(hostspath, "r")) == NULL((void*)0))
2905 return false0;
2906
2907 while (fgetline(line, sizeof(line), hf) >= 0) {
2908 if ((cp = strchr(line, '#')))
2909 *cp = '\0';
2910
2911 if ((cp = strtok(line, " \t")) == NULL((void*)0))
2912 continue; /* no tokens in the line */
2913
2914 if (ws_inet_pton6(cp, &host_addr.ip6_addr)) {
2915 /* Valid IPv6 */
2916 is_ipv6 = true1;
2917 } else if (ws_inet_pton4(cp, &host_addr.ip4_addr)) {
2918 /* Valid IPv4 */
2919 is_ipv6 = false0;
2920 } else {
2921 continue;
2922 }
2923
2924 if ((cp = strtok(NULL((void*)0), " \t")) == NULL((void*)0))
2925 continue; /* no host name */
2926
2927 entry_found = true1;
2928 if (store_entries) {
2929 if (is_ipv6) {
2930 add_ipv6_name(&host_addr.ip6_addr, cp, true1);
2931 } else {
2932 add_ipv4_name(host_addr.ip4_addr, cp, true1);
2933 }
2934 }
2935 }
2936
2937 fclose(hf);
2938 return entry_found ? true1 : false0;
2939} /* read_hosts_file */
2940
2941bool_Bool
2942add_hosts_file (const char *hosts_file)
2943{
2944 bool_Bool found = false0;
2945 unsigned i;
2946
2947 if (!hosts_file)
2948 return false0;
2949
2950 if (!extra_hosts_files)
2951 extra_hosts_files = g_ptr_array_new();
2952
2953 for (i = 0; i < extra_hosts_files->len; i++) {
2954 if (strcmp(hosts_file, (const char *) g_ptr_array_index(extra_hosts_files, i)((extra_hosts_files)->pdata)[i]) == 0)
2955 found = true1;
2956 }
2957
2958 if (!found) {
2959 g_ptr_array_add(extra_hosts_files, wmem_strdup(wmem_epan_scope(), hosts_file));
2960 return read_hosts_file (hosts_file, false0);
2961 }
2962 return true1;
2963}
2964
2965bool_Bool
2966add_ip_name_from_string (const char *addr, const char *name)
2967{
2968 union {
2969 uint32_t ip4_addr;
2970 ws_in6_addr ip6_addr;
2971 } host_addr;
2972 bool_Bool is_ipv6;
2973 resolved_name_t *resolved_entry;
2974
2975 if (ws_inet_pton6(addr, &host_addr.ip6_addr)) {
2976 is_ipv6 = true1;
2977 } else if (ws_inet_pton4(addr, &host_addr.ip4_addr)) {
2978 is_ipv6 = false0;
2979 } else {
2980 return false0;
2981 }
2982
2983 if (is_ipv6) {
2984 resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv6_list, &host_addr.ip6_addr);
2985 if (resolved_entry)
2986 {
2987 // If we found a previous matching key (IP address), then just update the value (custom hostname);
2988 (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN256);
2989 }
2990 else
2991 {
2992 // Add a new mapping entry, if this IP address isn't already in the list.
2993 ws_in6_addr* addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr)((ws_in6_addr*)wmem_alloc((wmem_epan_scope()), sizeof(ws_in6_addr
)))
;
2994 memcpy(addr_key, &host_addr.ip6_addr, sizeof(ws_in6_addr));
2995
2996 resolved_entry = wmem_new(wmem_epan_scope(), resolved_name_t)((resolved_name_t*)wmem_alloc((wmem_epan_scope()), sizeof(resolved_name_t
)))
;
2997 (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN256);
2998
2999 wmem_map_insert(manually_resolved_ipv6_list, addr_key, resolved_entry);
3000 }
3001 } else {
3002 resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv4_list, GUINT_TO_POINTER(host_addr.ip4_addr)((gpointer) (gulong) (host_addr.ip4_addr)));
3003 if (resolved_entry)
3004 {
3005 // If we found a previous matching key (IP address), then just update the value (custom hostname);
3006 (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN256);
3007 }
3008 else
3009 {
3010 // Add a new mapping entry, if this IP address isn't already in the list.
3011 resolved_entry = wmem_new(wmem_epan_scope(), resolved_name_t)((resolved_name_t*)wmem_alloc((wmem_epan_scope()), sizeof(resolved_name_t
)))
;
3012 (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN256);
3013
3014 wmem_map_insert(manually_resolved_ipv4_list, GUINT_TO_POINTER(host_addr.ip4_addr)((gpointer) (gulong) (host_addr.ip4_addr)), resolved_entry);
3015 }
3016 }
3017
3018 return true1;
3019} /* add_ip_name_from_string */
3020
3021extern resolved_name_t* get_edited_resolved_name(const char* addr)
3022{
3023 uint32_t ip4_addr;
3024 ws_in6_addr ip6_addr;
3025 resolved_name_t* resolved_entry = NULL((void*)0);
3026
3027 if (ws_inet_pton6(addr, &ip6_addr)) {
3028 resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv6_list, &ip6_addr);
3029 }
3030 else if (ws_inet_pton4(addr, &ip4_addr)) {
3031 resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv4_list, GUINT_TO_POINTER(ip4_addr)((gpointer) (gulong) (ip4_addr)));
3032 }
3033
3034 return resolved_entry;
3035}
3036
3037/*
3038 * Add the resolved addresses that are in use to the list used to create the pcapng NRB
3039 */
3040static void
3041ipv4_hash_table_resolved_to_list(void *key _U___attribute__((unused)), void *value, void *user_data)
3042{
3043 addrinfo_lists_t *lists = (addrinfo_lists_t *)user_data;
3044 hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value;
3045
3046 if ((ipv4_hash_table_entry->flags & USED_AND_RESOLVED_MASK((1U<<1) | (1U<<2))) == USED_AND_RESOLVED_MASK((1U<<1) | (1U<<2))) {
3047 lists->ipv4_addr_list = g_list_prepend(lists->ipv4_addr_list, ipv4_hash_table_entry);
3048 }
3049}
3050
3051/*
3052 * Add the resolved addresses that are in use to the list used to create the pcapng NRB
3053 */
3054static void
3055ipv6_hash_table_resolved_to_list(void *key _U___attribute__((unused)), void *value, void *user_data)
3056{
3057 addrinfo_lists_t *lists = (addrinfo_lists_t *)user_data;
3058 hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value;
3059
3060 if ((ipv6_hash_table_entry->flags & USED_AND_RESOLVED_MASK((1U<<1) | (1U<<2))) == USED_AND_RESOLVED_MASK((1U<<1) | (1U<<2))) {
3061 lists->ipv6_addr_list = g_list_prepend(lists->ipv6_addr_list, ipv6_hash_table_entry);
3062 }
3063}
3064
3065addrinfo_lists_t *
3066get_addrinfo_list(void)
3067{
3068 if (ipv4_hash_table) {
3069 wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_resolved_to_list, &addrinfo_lists);
3070 }
3071
3072 if (ipv6_hash_table) {
3073 wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_resolved_to_list, &addrinfo_lists);
3074 }
3075
3076 return &addrinfo_lists;
3077}
3078
3079/* Read in a list of subnet definition - name pairs.
3080 * <line> = <comment> | <entry> | <whitespace>
3081 * <comment> = <whitespace>#<any>
3082 * <entry> = <subnet_definition> <whitespace> <subnet_name> [<comment>|<whitespace><any>]
3083 * <subnet_definition> = <ipv4_address> / <subnet_mask_length>
3084 * <ipv4_address> is a full address; it will be masked to get the subnet-ID.
3085 * <subnet_mask_length> is a decimal 1-31
3086 * <subnet_name> is a string containing no whitespace.
3087 * <whitespace> = (space | tab)+
3088 * Any malformed entries are ignored.
3089 * Any trailing data after the subnet_name is ignored.
3090 *
3091 * XXX Support IPv6
3092 */
3093static bool_Bool
3094read_subnets_file (const char *subnetspath)
3095{
3096 FILE *hf;
3097 char line[MAX_LINELEN1024];
3098 char *cp, *cp2;
3099 uint32_t host_addr; /* IPv4 ONLY */
3100 uint8_t mask_length;
3101
3102 if ((hf = ws_fopenfopen(subnetspath, "r")) == NULL((void*)0))
3103 return false0;
3104
3105 while (fgetline(line, sizeof(line), hf) >= 0) {
3106 if ((cp = strchr(line, '#')))
3107 *cp = '\0';
3108
3109 if ((cp = strtok(line, " \t")) == NULL((void*)0))
3110 continue; /* no tokens in the line */
3111
3112
3113 /* Expected format is <IP4 address>/<subnet length> */
3114 cp2 = strchr(cp, '/');
3115 if (NULL((void*)0) == cp2) {
3116 /* No length */
3117 continue;
3118 }
3119 *cp2 = '\0'; /* Cut token */
3120 ++cp2 ;
3121
3122 /* Check if this is a valid IPv4 address */
3123 if (!str_to_ip(cp, &host_addr)) {
3124 continue; /* no */
3125 }
3126
3127 if (!ws_strtou8(cp2, NULL((void*)0), &mask_length) || mask_length == 0 || mask_length > 32) {
3128 continue; /* invalid mask length */
3129 }
3130
3131 if ((cp = strtok(NULL((void*)0), " \t")) == NULL((void*)0))
3132 continue; /* no subnet name */
3133
3134 subnet_entry_set(host_addr, mask_length, cp);
3135 }
3136
3137 fclose(hf);
3138 return true1;
3139} /* read_subnets_file */
3140
3141static subnet_entry_t
3142subnet_lookup(const uint32_t addr)
3143{
3144 subnet_entry_t subnet_entry;
3145 uint32_t i;
3146
3147 /* Search mask lengths linearly, longest first */
3148
3149 i = SUBNETLENGTHSIZE32;
3150 while(have_subnet_entry && i > 0) {
3151 uint32_t masked_addr;
3152 subnet_length_entry_t* length_entry;
3153
3154 /* Note that we run from 31 (length 32) to 0 (length 1) */
3155 --i;
3156 ws_assert(i < SUBNETLENGTHSIZE)do { if ((1) && !(i < 32)) ws_log_fatal_full("", LOG_LEVEL_ERROR
, "epan/addr_resolv.c", 3156, __func__, "assertion failed: %s"
, "i < 32"); } while (0)
;
3157
3158
3159 length_entry = &subnet_length_entries[i];
3160
3161 if (NULL((void*)0) != length_entry->subnet_addresses) {
3162 sub_net_hashipv4_t * tp;
3163 uint32_t hash_idx;
3164
3165 masked_addr = addr & length_entry->mask;
3166 hash_idx = HASH_IPV4_ADDRESS(masked_addr)((((((guint32) ( (((guint32) (masked_addr) & (guint32) 0x000000ffU
) << 24) | (((guint32) (masked_addr) & (guint32) 0x0000ff00U
) << 8) | (((guint32) (masked_addr) & (guint32) 0x00ff0000U
) >> 8) | (((guint32) (masked_addr) & (guint32) 0xff000000U
) >> 24)))))) & (2048 - 1))
;
3167
3168 tp = length_entry->subnet_addresses[hash_idx];
3169 while(tp != NULL((void*)0) && tp->addr != masked_addr) {
3170 tp = tp->next;
3171 }
3172
3173 if (NULL((void*)0) != tp) {
3174 subnet_entry.mask = length_entry->mask;
3175 subnet_entry.mask_length = i + 1; /* Length is offset + 1 */
3176 subnet_entry.name = tp->name;
3177 return subnet_entry;
3178 }
3179 }
3180 }
3181
3182 subnet_entry.mask = 0;
3183 subnet_entry.mask_length = 0;
3184 subnet_entry.name = NULL((void*)0);
3185
3186 return subnet_entry;
3187}
3188
3189/* Add a subnet-definition - name pair to the set.
3190 * The definition is taken by masking the address passed in with the mask of the
3191 * given length.
3192 */
3193static void
3194subnet_entry_set(uint32_t subnet_addr, const uint8_t mask_length, const char* name)
3195{
3196 subnet_length_entry_t* entry;
3197 sub_net_hashipv4_t * tp;
3198 size_t hash_idx;
3199
3200 ws_assert(mask_length > 0 && mask_length <= 32)do { if ((1) && !(mask_length > 0 && mask_length
<= 32)) ws_log_fatal_full("", LOG_LEVEL_ERROR, "epan/addr_resolv.c"
, 3200, __func__, "assertion failed: %s", "mask_length > 0 && mask_length <= 32"
); } while (0)
;
3201
3202 entry = &subnet_length_entries[mask_length - 1];
3203
3204 subnet_addr &= entry->mask;
3205
3206 hash_idx = HASH_IPV4_ADDRESS(subnet_addr)((((((guint32) ( (((guint32) (subnet_addr) & (guint32) 0x000000ffU
) << 24) | (((guint32) (subnet_addr) & (guint32) 0x0000ff00U
) << 8) | (((guint32) (subnet_addr) & (guint32) 0x00ff0000U
) >> 8) | (((guint32) (subnet_addr) & (guint32) 0xff000000U
) >> 24)))))) & (2048 - 1))
;
3207
3208 if (NULL((void*)0) == entry->subnet_addresses) {
3209 entry->subnet_addresses = (sub_net_hashipv4_t**)wmem_alloc0(addr_resolv_scope, sizeof(sub_net_hashipv4_t*) * HASHHOSTSIZE2048);
3210 }
3211
3212 if (NULL((void*)0) != (tp = entry->subnet_addresses[hash_idx])) {
3213 sub_net_hashipv4_t * new_tp;
3214
3215 while (tp->next) {
3216 if (tp->addr == subnet_addr) {
3217 return; /* XXX provide warning that an address was repeated? */
3218 } else {
3219 tp = tp->next;
3220 }
3221 }
3222
3223 new_tp = wmem_new(addr_resolv_scope, sub_net_hashipv4_t)((sub_net_hashipv4_t*)wmem_alloc((addr_resolv_scope), sizeof(
sub_net_hashipv4_t)))
;
3224 tp->next = new_tp;
3225 tp = new_tp;
3226 } else {
3227 tp = entry->subnet_addresses[hash_idx] = wmem_new(addr_resolv_scope, sub_net_hashipv4_t)((sub_net_hashipv4_t*)wmem_alloc((addr_resolv_scope), sizeof(
sub_net_hashipv4_t)))
;
3228 }
3229
3230 tp->next = NULL((void*)0);
3231 tp->addr = subnet_addr;
3232 (void) g_strlcpy(tp->name, name, MAXNAMELEN64); /* This is longer than subnet names can actually be */
3233 have_subnet_entry = true1;
3234}
3235
3236static void
3237subnet_name_lookup_init(const char* app_env_var_prefix)
3238{
3239 char* subnetspath;
3240 uint32_t i;
3241
3242 for(i = 0; i < SUBNETLENGTHSIZE32; ++i) {
3243 uint32_t length = i + 1;
3244
3245 subnet_length_entries[i].subnet_addresses = NULL((void*)0);
3246 subnet_length_entries[i].mask_length = length;
3247 subnet_length_entries[i].mask = g_htonl(ws_ipv4_get_subnet_mask(length))(((((guint32) ( (((guint32) (ws_ipv4_get_subnet_mask(length))
& (guint32) 0x000000ffU) << 24) | (((guint32) (ws_ipv4_get_subnet_mask
(length)) & (guint32) 0x0000ff00U) << 8) | (((guint32
) (ws_ipv4_get_subnet_mask(length)) & (guint32) 0x00ff0000U
) >> 8) | (((guint32) (ws_ipv4_get_subnet_mask(length))
& (guint32) 0xff000000U) >> 24))))))
;
3248 }
3249
3250 /* Check profile directory before personal configuration */
3251 subnetspath = get_persconffile_path(ENAME_SUBNETS"subnets", true1, app_env_var_prefix);
3252 if (!read_subnets_file(subnetspath)) {
3253 if (errno(*__errno_location ()) != ENOENT2) {
3254 report_open_failure(subnetspath, errno(*__errno_location ()), false0);
3255 }
3256
3257 g_free(subnetspath);
3258 subnetspath = get_persconffile_path(ENAME_SUBNETS"subnets", false0, app_env_var_prefix);
3259 if (!read_subnets_file(subnetspath) && errno(*__errno_location ()) != ENOENT2) {
3260 report_open_failure(subnetspath, errno(*__errno_location ()), false0);
3261 }
3262 }
3263 g_free(subnetspath);
3264
3265 /*
3266 * Load the global subnets file, if we have one.
3267 */
3268 subnetspath = get_datafile_path(ENAME_SUBNETS"subnets", app_env_var_prefix);
3269 if (!read_subnets_file(subnetspath) && errno(*__errno_location ()) != ENOENT2) {
3270 report_open_failure(subnetspath, errno(*__errno_location ()), false0);
3271 }
3272 g_free(subnetspath);
3273}
3274
3275/* IPv6 Subnet Name Resolution */
3276
3277/* Compute a 16-byte subnet mask from a prefix length (1-128). */
3278static void
3279ipv6_get_subnet_mask(uint32_t mask_length, uint8_t mask[16])
3280{
3281 uint32_t full_bytes = mask_length / 8;
3282 uint32_t remaining = mask_length % 8;
3283 memset(mask, 0, 16);
3284 for (uint32_t i = 0; i < full_bytes; i++)
3285 mask[i] = 0xff;
3286 if (remaining > 0 && full_bytes < 16)
3287 mask[full_bytes] = (uint8_t)(0xff << (8 - remaining));
3288}
3289
3290static void
3291subnet6_entry_set(const ws_in6_addr *subnet_addr, const uint32_t mask_length,
3292 const char *name)
3293{
3294 subnet_length_entry_v6_t *entry;
3295 sub_net_hashipv6_t *tp;
3296 uint8_t masked[16];
3297 size_t hash_idx;
3298
3299 ws_assert(mask_length > 0 && mask_length <= 128)do { if ((1) && !(mask_length > 0 && mask_length
<= 128)) ws_log_fatal_full("", LOG_LEVEL_ERROR, "epan/addr_resolv.c"
, 3299, __func__, "assertion failed: %s", "mask_length > 0 && mask_length <= 128"
); } while (0)
;
3300 entry = &subnet_length_entries_v6[mask_length - 1];
3301
3302 for (int i = 0; i < 16; i++)
3303 masked[i] = subnet_addr->bytes[i] & entry->mask[i];
3304
3305 hash_idx = ipv6_oat_hash(masked) & (HASHHOSTSIZE2048 - 1);
3306
3307 if (entry->subnet_addresses == NULL((void*)0))
3308 entry->subnet_addresses = (sub_net_hashipv6_t **)wmem_alloc0(
3309 addr_resolv_scope, sizeof(sub_net_hashipv6_t *) * HASHHOSTSIZE2048);
3310
3311 if ((tp = entry->subnet_addresses[hash_idx]) != NULL((void*)0)) {
3312 sub_net_hashipv6_t *new_tp;
3313 while (tp->next) {
3314 if (memcmp(tp->addr, masked, 16) == 0)
3315 return; /* duplicate */
3316 tp = tp->next;
3317 }
3318 if (memcmp(tp->addr, masked, 16) == 0)
3319 return; /* duplicate at tail */
3320 new_tp = wmem_new(addr_resolv_scope, sub_net_hashipv6_t)((sub_net_hashipv6_t*)wmem_alloc((addr_resolv_scope), sizeof(
sub_net_hashipv6_t)))
;
3321 tp->next = new_tp;
3322 tp = new_tp;
3323 } else {
3324 tp = entry->subnet_addresses[hash_idx] =
3325 wmem_new(addr_resolv_scope, sub_net_hashipv6_t)((sub_net_hashipv6_t*)wmem_alloc((addr_resolv_scope), sizeof(
sub_net_hashipv6_t)))
;
3326 }
3327
3328 tp->next = NULL((void*)0);
3329 memcpy(tp->addr, masked, 16);
3330 (void)g_strlcpy(tp->name, name, MAXNAMELEN64);
3331 have_subnet_entry_v6 = true1;
3332}
3333
3334static subnet_entry_v6_t
3335subnet6_lookup(const ws_in6_addr *addr)
3336{
3337 subnet_entry_v6_t result;
3338 uint32_t i = SUBNETLENGTHSIZE_V6128;
3339
3340 while (have_subnet_entry_v6 && i > 0) {
3341 subnet_length_entry_v6_t *length_entry;
3342 uint8_t masked[16];
3343 size_t hash_idx;
3344 sub_net_hashipv6_t *tp;
3345
3346 --i;
3347 length_entry = &subnet_length_entries_v6[i];
3348
3349 if (length_entry->subnet_addresses == NULL((void*)0))
3350 continue;
3351
3352 for (int b = 0; b < 16; b++)
3353 masked[b] = addr->bytes[b] & length_entry->mask[b];
3354
3355 hash_idx = ipv6_oat_hash(masked) & (HASHHOSTSIZE2048 - 1);
3356 tp = length_entry->subnet_addresses[hash_idx];
3357
3358 while (tp != NULL((void*)0) && memcmp(tp->addr, masked, 16) != 0)
3359 tp = tp->next;
3360
3361 if (tp != NULL((void*)0)) {
3362 memcpy(result.mask, length_entry->mask, 16);
3363 result.mask_length = i + 1;
3364 result.name = tp->name;
3365 return result;
3366 }
3367 }
3368
3369 memset(result.mask, 0, 16);
3370 result.mask_length = 0;
3371 result.name = NULL((void*)0);
3372 return result;
3373}
3374
3375static bool_Bool
3376read_subnets_ipv6_file(const char *subnetspath)
3377{
3378 FILE *hf;
3379 char line[MAX_LINELEN1024];
3380 char *cp, *cp2;
3381 ws_in6_addr host_addr;
3382 uint32_t mask_length;
3383
3384 if ((hf = ws_fopenfopen(subnetspath, "r")) == NULL((void*)0))
3385 return false0;
3386
3387 while (fgetline(line, sizeof(line), hf) >= 0) {
3388 if ((cp = strchr(line, '#')))
3389 *cp = '\0';
3390
3391 if ((cp = strtok(line, " \t")) == NULL((void*)0))
3392 continue;
3393
3394 /* Expected format: <IPv6_address>/<prefix_length> */
3395 cp2 = strchr(cp, '/');
3396 if (cp2 == NULL((void*)0))
3397 continue;
3398 *cp2 = '\0';
3399 ++cp2;
3400
3401 if (!ws_inet_pton6(cp, &host_addr))
3402 continue;
3403
3404 if (!ws_strtou32(cp2, NULL((void*)0), &mask_length) || mask_length == 0 || mask_length > 128)
3405 continue;
3406
3407 if ((cp = strtok(NULL((void*)0), " \t")) == NULL((void*)0))
3408 continue;
3409
3410 subnet6_entry_set(&host_addr, mask_length, cp);
3411 }
3412
3413 fclose(hf);
3414 return true1;
3415}
3416
3417static void
3418subnet6_name_lookup_init(const char *app_env_var_prefix)
3419{
3420 char *subnetspath;
3421
3422 for (uint32_t i = 0; i < SUBNETLENGTHSIZE_V6128; ++i) {
3423 subnet_length_entries_v6[i].subnet_addresses = NULL((void*)0);
3424 subnet_length_entries_v6[i].mask_length = i + 1;
3425 ipv6_get_subnet_mask((uint32_t)(i + 1), subnet_length_entries_v6[i].mask);
3426 }
3427
3428 /* Check profile directory before personal configuration */
3429 subnetspath = get_persconffile_path(ENAME_SUBNETS_V6"subnetIpv6", true1, app_env_var_prefix);
3430 if (!read_subnets_ipv6_file(subnetspath)) {
3431 if (errno(*__errno_location ()) != ENOENT2)
3432 report_open_failure(subnetspath, errno(*__errno_location ()), false0);
3433 g_free(subnetspath);
3434 subnetspath = get_persconffile_path(ENAME_SUBNETS_V6"subnetIpv6", false0, app_env_var_prefix);
3435 if (!read_subnets_ipv6_file(subnetspath) && errno(*__errno_location ()) != ENOENT2)
3436 report_open_failure(subnetspath, errno(*__errno_location ()), false0);
3437 }
3438 g_free(subnetspath);
3439
3440 /*
3441 * Load the global IPv6 subnets file, if we have one.
3442 */
3443 subnetspath = get_datafile_path(ENAME_SUBNETS_V6"subnetIpv6", app_env_var_prefix);
3444 if (!read_subnets_ipv6_file(subnetspath) && errno(*__errno_location ()) != ENOENT2)
3445 report_open_failure(subnetspath, errno(*__errno_location ()), false0);
3446 g_free(subnetspath);
3447}
3448
3449/* SS7 PC Name Resolution Portion */
3450static hashss7pc_t *
3451new_ss7pc(const uint8_t ni, const uint32_t pc)
3452{
3453 hashss7pc_t *tp = wmem_new(addr_resolv_scope, hashss7pc_t)((hashss7pc_t*)wmem_alloc((addr_resolv_scope), sizeof(hashss7pc_t
)))
;
3454 tp->id = (ni<<24) + (pc&0xffffff);
3455 tp->pc_addr[0] = '\0';
3456 tp->name[0] = '\0';
3457
3458 return tp;
3459}
3460
3461static hashss7pc_t *
3462host_lookup_ss7pc(const uint8_t ni, const uint32_t pc)
3463{
3464 hashss7pc_t * volatile tp;
3465 uint32_t id;
3466
3467 id = (ni<<24) + (pc&0xffffff);
3468
3469 tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)));
3470 if (tp == NULL((void*)0)) {
3471 tp = new_ss7pc(ni, pc);
3472 wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)), tp);
3473 }
3474
3475 return tp;
3476}
3477
3478void fill_unresolved_ss7pc(const char * pc_addr, const uint8_t ni, const uint32_t pc)
3479{
3480 hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
3481
3482 (void) g_strlcpy(tp->pc_addr, pc_addr, MAXNAMELEN64);
3483}
3484
3485const char *
3486get_hostname_ss7pc(const uint8_t ni, const uint32_t pc)
3487{
3488 hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
3489
3490 /* never resolved yet*/
3491 if (tp->pc_addr[0] == '\0')
3492 return tp->pc_addr;
3493
3494 /* Don't have name in file */
3495 if (tp->name[0] == '\0')
3496 return tp->pc_addr;
3497
3498 if (!gbl_resolv_flags.ss7pc_name)
3499 return tp->pc_addr;
3500
3501 return tp->name;
3502}
3503
3504static void
3505add_ss7pc_name(const uint8_t ni, uint32_t pc, const char *name)
3506{
3507 hashss7pc_t *tp;
3508 uint32_t id;
3509
3510 if (!name || name[0] == '\0')
3511 return;
3512
3513 id = (ni<<24) + (pc&0xffffff);
3514 tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)));
3515 if (!tp) {
3516 tp = new_ss7pc(ni, pc);
3517 wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)), tp);
3518 }
3519
3520 if (g_ascii_strcasecmp(tp->name, name)) {
3521 (void) g_strlcpy(tp->name, name, MAXNAMELEN64);
3522 }
3523}
3524
3525static bool_Bool
3526read_ss7pcs_file(const char *ss7pcspath)
3527{
3528 FILE *hf;
3529 char line[MAX_LINELEN1024];
3530 char *cp;
3531 uint8_t ni;
3532 uint32_t pc;
3533 bool_Bool entry_found = false0;
3534
3535 /*
3536 * File format is Network Indicator (decimal)<dash>Point Code (Decimal)<tab/space>Hostname
3537 */
3538 if ((hf = ws_fopenfopen(ss7pcspath, "r")) == NULL((void*)0))
3539 return false0;
3540
3541 while (fgetline(line, sizeof(line), hf) >= 0) {
3542 if ((cp = strchr(line, '#')))
3543 *cp = '\0';
3544
3545 if ((cp = strtok(line, "-")) == NULL((void*)0))
3546 continue; /*no ni-pc separator*/
3547 if (!ws_strtou8(cp, NULL((void*)0), &ni))
3548 continue;
3549 if (ni > 3)
3550 continue;
3551
3552 if ((cp = strtok(NULL((void*)0), " \t")) == NULL((void*)0))
3553 continue; /* no tokens for pc and name */
3554 if (!ws_strtou32(cp, NULL((void*)0), &pc))
3555 continue;
3556 if (pc >> 24 > 0)
3557 continue;
3558
3559 if ((cp = strtok(NULL((void*)0), " \t")) == NULL((void*)0))
3560 continue; /* no host name */
3561
3562 entry_found = true1;
3563 add_ss7pc_name(ni, pc, cp);
3564 }
3565
3566 fclose(hf);
3567 return entry_found ? true1 : false0;
3568}
3569
3570static void
3571ss7pc_name_lookup_init(const char* app_env_var_prefix)
3572{
3573 char *ss7pcspath;
3574
3575 ws_assert(ss7pc_hash_table == NULL)do { if ((1) && !(ss7pc_hash_table == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 3575, __func__, "assertion failed: %s"
, "ss7pc_hash_table == ((void*)0)"); } while (0)
;
3576
3577 ss7pc_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
3578
3579 /*
3580 * Load the user's ss7pcs file
3581 */
3582 ss7pcspath = get_persconffile_path(ENAME_SS7PCS"ss7pcs", true1, app_env_var_prefix);
3583 if (!read_ss7pcs_file(ss7pcspath) && errno(*__errno_location ()) != ENOENT2) {
3584 report_open_failure(ss7pcspath, errno(*__errno_location ()), false0);
3585 }
3586 g_free(ss7pcspath);
3587}
3588
3589/* SS7PC Name Resolution End*/
3590
3591/* TACS */
3592static bool_Bool
3593read_tacs_file(const char *tacspath)
3594{
3595 FILE *hf;
3596 char line[MAX_LINELEN1024];
3597 char *cp;
3598 uint16_t id;
3599
3600 /*
3601 * File format is TAC(decimal)<tab/space>TACName (no spaces)
3602 */
3603 if ((hf = ws_fopenfopen(tacspath, "r")) == NULL((void*)0))
3604 return false0;
3605
3606 while (fgetline(line, sizeof(line), hf) >= 0) {
3607 if ((cp = strchr(line, '#')))
3608 *cp = '\0';
3609
3610 if ((cp = strtok(line, " \t")) == NULL((void*)0))
3611 continue;
3612
3613 if (sscanf(cp, "%" SCNu16"hu", &id) != 1) {
3614 continue;
3615 }
3616
3617 if ((cp = strtok(NULL((void*)0), " \t\n")) == NULL((void*)0))
3618 continue; /* no TAC name */
3619
3620 if (!wmem_map_lookup(tac_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)))) {
3621 char *buf = wmem_strdup(addr_resolv_scope, cp);
3622 wmem_map_insert(tac_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)), (void *)buf);
3623 }
3624 }
3625
3626 fclose(hf);
3627 return true1;
3628}
3629
3630static void
3631initialize_tacs(const char* app_env_var_prefix)
3632{
3633 char *tacspath;
3634 ws_assert(tac_hash_table == NULL)do { if ((1) && !(tac_hash_table == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 3634, __func__, "assertion failed: %s"
, "tac_hash_table == ((void*)0)"); } while (0)
;
3635 tac_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
3636
3637 tacspath = get_persconffile_path(ENAME_TACS"tacs", true1, app_env_var_prefix);
3638 if (!read_tacs_file(tacspath) && errno(*__errno_location ()) != ENOENT2) {
3639 report_open_failure(tacspath, errno(*__errno_location ()), false0);
3640 }
3641 g_free(tacspath);
3642}
3643
3644static void
3645tac_name_lookup_cleanup(void)
3646{
3647 tac_hash_table = NULL((void*)0);
3648}
3649
3650const char *
3651tac_name_lookup(const unsigned id)
3652{
3653 return (const char *)wmem_map_lookup(tac_hash_table, GUINT_TO_POINTER(id)((gpointer) (gulong) (id)));
3654}
3655/* TAC END */
3656
3657/*
3658 * External Functions
3659 */
3660
3661void
3662addr_resolve_pref_init(module_t *nameres)
3663{
3664 prefs_register_bool_preference(nameres, "mac_name",
3665 "Resolve MAC addresses",
3666 "Resolve Ethernet MAC addresses to host names from the preferences"
3667 " or system's Ethers file, or to a manufacturer based name.",
3668 &gbl_resolv_flags.mac_name);
3669
3670 prefs_register_bool_preference(nameres, "transport_name",
3671 "Resolve transport names",
3672 "Resolve TCP/UDP ports into service names",
3673 &gbl_resolv_flags.transport_name);
3674
3675 prefs_register_bool_preference(nameres, "network_name",
3676 "Resolve network (IP) addresses",
3677 "Resolve IPv4, IPv6, and IPX addresses into host names."
3678 " The next set of check boxes determines how name resolution should be performed."
3679 " If no other options are checked name resolution is made from Wireshark's host file"
3680 " and capture file name resolution blocks.",
3681 &gbl_resolv_flags.network_name);
3682
3683 prefs_register_bool_preference(nameres, "dns_pkt_addr_resolution",
3684 "Use captured DNS packet data for name resolution",
3685 "Use address/name pairs found in captured DNS packets for name resolution.",
3686 &gbl_resolv_flags.dns_pkt_addr_resolution);
3687
3688 prefs_register_bool_preference(nameres, "handshake_sni_addr_resolution",
3689 "Use SNI information from captured handshake packets",
3690 "Use the Server Name Indication found in TLS handshakes for name resolution.",
3691 &gbl_resolv_flags.handshake_sni_addr_resolution);
3692
3693 prefs_register_bool_preference(nameres, "use_external_name_resolver",
3694 "Use your system's DNS settings for name resolution",
3695 "Use your system's configured name resolver"
3696 " (usually DNS) to resolve network names."
3697 " Only applies when network name resolution"
3698 " is enabled.",
3699 &gbl_resolv_flags.use_external_net_name_resolver);
3700
3701 prefs_register_bool_preference(nameres, "use_custom_dns_servers",
3702 "Use a custom list of DNS servers for name resolution",
3703 "Use a DNS Servers list to resolve network names if true. If false, default information is used",
3704 &use_custom_dns_server_list);
3705
3706 static uat_field_t dns_server_uats_flds[] = {
3707 UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, ipaddr, "IP address", dnsserver_uat_fld_ip_chk_cb, "IPv4 or IPv6 address"){"ipaddr", "IP address", PT_TXTMOD_STRING,{ dnsserver_uat_fld_ip_chk_cb
,dnsserverlist_uats_ipaddr_set_cb,dnsserverlist_uats_ipaddr_tostr_cb
},{0,0,0},0,"IPv4 or IPv6 address",((void*)0)}
,
3708 UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, tcp_port, "TCP Port", dnsserver_uat_fld_port_chk_cb, "Port Number (TCP)"){"tcp_port", "TCP Port", PT_TXTMOD_STRING,{ dnsserver_uat_fld_port_chk_cb
,dnsserverlist_uats_tcp_port_set_cb,dnsserverlist_uats_tcp_port_tostr_cb
},{0,0,0},0,"Port Number (TCP)",((void*)0)}
,
3709 UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, udp_port, "UDP Port", dnsserver_uat_fld_port_chk_cb, "Port Number (UDP)"){"udp_port", "UDP Port", PT_TXTMOD_STRING,{ dnsserver_uat_fld_port_chk_cb
,dnsserverlist_uats_udp_port_set_cb,dnsserverlist_uats_udp_port_tostr_cb
},{0,0,0},0,"Port Number (UDP)",((void*)0)}
,
3710 UAT_END_FIELDS{((void*)0),((void*)0),PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,((void
*)0)}
3711 };
3712
3713 dnsserver_uat = uat_new("DNS Servers",
3714 sizeof(struct dns_server_data),
3715 "addr_resolve_dns_servers", /* filename */
3716 true1, /* from_profile */
3717 &dnsserverlist_uats, /* data_ptr */
3718 &ndnsservers, /* numitems_ptr */
3719 UAT_AFFECTS_DISSECTION0x00000001,
3720 NULL((void*)0),
3721 dns_server_copy_cb,
3722 NULL((void*)0),
3723 dns_server_free_cb,
3724 c_ares_set_dns_servers,
3725 NULL((void*)0),
3726 dns_server_uats_flds);
3727 static const char *dnsserver_uat_defaults[] = { NULL((void*)0), "53", "53" };
3728 uat_set_default_values(dnsserver_uat, dnsserver_uat_defaults);
3729 prefs_register_uat_preference(nameres, "dns_servers",
3730 "DNS Servers",
3731 "A table of IPv4 and IPv6 addresses of DNS servers to be used to resolve IP names and addresses",
3732 dnsserver_uat);
3733
3734 prefs_register_obsolete_preference(nameres, "concurrent_dns");
3735
3736 prefs_register_uint_preference(nameres, "name_resolve_concurrency",
3737 "Maximum concurrent requests",
3738 "The maximum number of DNS requests that may"
3739 " be active at any time. A large value (many"
3740 " thousands) might overload the network or make"
3741 " your DNS server behave badly.",
3742 10,
3743 &name_resolve_concurrency);
3744
3745 prefs_register_obsolete_preference(nameres, "hosts_file_handling");
3746
3747 prefs_register_bool_preference(nameres, "vlan_name",
3748 "Resolve VLAN IDs",
3749 "Resolve VLAN IDs to network names from the preferences \"vlans\" file."
3750 " Format of the file is: \"ID<Tab>Name\"."
3751 " One line per VLAN, e.g.: 1 Management",
3752 &gbl_resolv_flags.vlan_name);
3753
3754 prefs_register_bool_preference(nameres, "ss7_pc_name",
3755 "Resolve SS7 PCs",
3756 "Resolve SS7 Point Codes to node names from the profiles \"ss7pcs\" file."
3757 " Format of the file is: \"Network_Indicator<Dash>PC_Decimal<Tab>Name\"."
3758 " One line per Point Code, e.g.: 2-1234 MyPointCode1",
3759 &gbl_resolv_flags.ss7pc_name);
3760
3761 prefs_register_bool_preference(nameres, "tac_name",
3762 "Resolve TAC",
3763 "Resolve TAC to area names from the preferences \"tac\" file."
3764 " Format of the file is: \"TAC(decimail)<Tab/space>Name\"."
3765 " One line per TAC, e.g.: 30123 City1",
3766 &gbl_resolv_flags.tac_name);
3767
3768}
3769
3770void addr_resolve_pref_apply(void)
3771{
3772 c_ares_set_dns_servers();
3773 maxmind_db_pref_apply();
3774}
3775
3776void
3777disable_name_resolution(void) {
3778 gbl_resolv_flags.mac_name = false0;
3779 gbl_resolv_flags.network_name = false0;
3780 gbl_resolv_flags.transport_name = false0;
3781 gbl_resolv_flags.dns_pkt_addr_resolution = false0;
3782 gbl_resolv_flags.handshake_sni_addr_resolution = false0;
3783 gbl_resolv_flags.use_external_net_name_resolver = false0;
3784 gbl_resolv_flags.vlan_name = false0;
3785 gbl_resolv_flags.ss7pc_name = false0;
3786 gbl_resolv_flags.maxmind_geoip = false0;
3787 gbl_resolv_flags.tac_name = false0;
3788}
3789
3790bool_Bool
3791host_name_lookup_process(void) {
3792 struct timeval tv = { 0, 0 };
3793 int nfds;
3794 fd_set rfds, wfds;
3795 bool_Bool nro = new_resolved_objects;
3796
3797 new_resolved_objects = false0;
3798 nro |= maxmind_db_lookup_process();
3799
3800 if (!async_dns_initialized)
3801 /* c-ares not initialized. Bail out and cancel timers. */
3802 return nro;
3803
3804 process_async_dns_queue();
3805
3806 FD_ZERO(&rfds)do { unsigned int __i; fd_set *__arr = (&rfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
3807 FD_ZERO(&wfds)do { unsigned int __i; fd_set *__arr = (&wfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
3808 nfds = ares_fds(ghba_chan, &rfds, &wfds);
3809 if (nfds > 0) {
3810 if (select(nfds, &rfds, &wfds, NULL((void*)0), &tv) == -1) { /* call to select() failed */
3811 /* If it's interrupted by a signal, no need to put out a message */
3812 if (errno(*__errno_location ()) != EINTR4)
3813 fprintf(stderrstderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno(*__errno_location ())));
3814 return nro;
3815 }
3816 ares_process(ghba_chan, &rfds, &wfds);
3817 }
3818
3819 /* Any new entries? */
3820 return nro;
3821}
3822
3823static void
3824_host_name_lookup_cleanup(void) {
3825 async_dns_queue_head = NULL((void*)0);
3826
3827 if (async_dns_initialized) {
3828 ares_destroy(ghba_chan);
3829 ares_destroy(ghbn_chan);
3830 }
3831#ifdef CARES_HAVE_ARES_LIBRARY_INIT1
3832 ares_library_cleanup();
3833#endif
3834 async_dns_initialized = false0;
3835}
3836
3837const char *
3838get_hostname(const unsigned addr)
3839{
3840 /* XXX why do we call this if we're not resolving? To create hash entries?
3841 * Why? So that we can return a const char*?
3842 *
3843 * Note the returned string is in addr_resolv_scope, which has a similar
3844 * life to the global file scope (slightly larger, in that the resolved
3845 * addresses need to be available during dissector registration, e.g.
3846 * for RADIUS and enterprises), so if not copied it is possible to use
3847 * it after freeing.
3848 *
3849 * Should this be deprecated in favor of get_hostname_wmem so that
3850 * host name lookups don't increase persistent memory usage even when
3851 * hostname lookups are disabled? (An alternative would be to return
3852 * NULL when lookups are disabled, but callers don't expect that.)
3853 */
3854 hashipv4_t *tp = host_lookup(addr);
3855
3856 if (!gbl_resolv_flags.network_name)
3857 return tp->ip;
3858
3859 tp->flags |= RESOLVED_ADDRESS_USED(1U<<2);
3860
3861 return tp->name;
3862}
3863
3864char *
3865get_hostname_wmem(wmem_allocator_t *allocator, const unsigned addr)
3866{
3867 if (!gbl_resolv_flags.network_name)
3868 return ip_addr_to_str(allocator, &addr);
3869
3870 hashipv4_t *tp = host_lookup(addr);
3871
3872 tp->flags |= RESOLVED_ADDRESS_USED(1U<<2);
3873
3874 return wmem_strdup(allocator, tp->name);
3875}
3876/* -------------------------- */
3877
3878const char *
3879get_hostname6(const ws_in6_addr *addr)
3880{
3881 /* XXX why do we call this if we're not resolving? To create hash entries?
3882 * Why? The same comments as get_hostname above apply.
3883 */
3884 hashipv6_t *tp = host_lookup6(addr);
3885
3886 if (!gbl_resolv_flags.network_name)
3887 return tp->ip6;
3888
3889 tp->flags |= RESOLVED_ADDRESS_USED(1U<<2);
3890
3891 return tp->name;
3892}
3893
3894char *
3895get_hostname6_wmem(wmem_allocator_t *allocator, const ws_in6_addr *addr)
3896{
3897 if (!gbl_resolv_flags.network_name)
3898 return ip6_to_str(allocator, addr);
3899
3900 hashipv6_t *tp = host_lookup6(addr);
3901
3902 tp->flags |= RESOLVED_ADDRESS_USED(1U<<2);
3903
3904 return wmem_strdup(allocator, tp->name);
3905}
3906/* -------------------------- */
3907void
3908add_ipv4_name(const unsigned addr, const char *name, bool_Bool static_entry)
3909{
3910 hashipv4_t *tp;
3911
3912 /*
3913 * Don't add zero-length names; apparently, some resolvers will return
3914 * them if they get them from DNS.
3915 */
3916 if (!name || name[0] == '\0')
3917 return;
3918
3919 tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr)((gpointer) (gulong) (addr)));
3920 if (!tp) {
3921 tp = new_ipv4(addr);
3922 wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr)((gpointer) (gulong) (addr)), tp);
3923 }
3924
3925 if (g_ascii_strcasecmp(tp->name, name) && (static_entry || !(tp->flags & STATIC_HOSTNAME(1U<<3)))) {
3926 (void) g_strlcpy(tp->name, name, MAXDNSNAMELEN256);
3927 new_resolved_objects = true1;
3928 if (static_entry)
3929 tp->flags |= STATIC_HOSTNAME(1U<<3);
3930 }
3931 tp->flags |= TRIED_RESOLVE_ADDRESS(1U<<0)|NAME_RESOLVED(1U<<1);
3932} /* add_ipv4_name */
3933
3934/* -------------------------- */
3935void
3936add_ipv6_name(const ws_in6_addr *addrp, const char *name, const bool_Bool static_entry)
3937{
3938 hashipv6_t *tp;
3939
3940 /*
3941 * Don't add zero-length names; apparently, some resolvers will return
3942 * them if they get them from DNS.
3943 */
3944 if (!name || name[0] == '\0')
3945 return;
3946
3947 tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addrp);
3948 if (!tp) {
3949 ws_in6_addr *addr_key;
3950
3951 addr_key = wmem_new(addr_resolv_scope, ws_in6_addr)((ws_in6_addr*)wmem_alloc((addr_resolv_scope), sizeof(ws_in6_addr
)))
;
3952 tp = new_ipv6(addrp);
3953 memcpy(addr_key, addrp, 16);
3954 wmem_map_insert(ipv6_hash_table, addr_key, tp);
3955 }
3956
3957 if (g_ascii_strcasecmp(tp->name, name) && (static_entry || !(tp->flags & STATIC_HOSTNAME(1U<<3)))) {
3958 (void) g_strlcpy(tp->name, name, MAXDNSNAMELEN256);
3959 new_resolved_objects = true1;
3960 if (static_entry)
3961 tp->flags |= STATIC_HOSTNAME(1U<<3);
3962 }
3963 tp->flags |= TRIED_RESOLVE_ADDRESS(1U<<0)|NAME_RESOLVED(1U<<1);
3964} /* add_ipv6_name */
3965
3966static void
3967add_manually_resolved_ipv4(void *key, void *value, void *user_data _U___attribute__((unused)))
3968{
3969 resolved_name_t *resolved_ipv4_entry = (resolved_name_t*)value;
3970 add_ipv4_name(GPOINTER_TO_UINT(key)((guint) (gulong) (key)), resolved_ipv4_entry->name, true1);
3971}
3972
3973static void
3974add_manually_resolved_ipv6(void *key, void *value, void *user_data _U___attribute__((unused)))
3975{
3976 resolved_name_t *resolved_ipv6_entry = (resolved_name_t*)value;
3977 add_ipv6_name((ws_in6_addr*)key, resolved_ipv6_entry->name, true1);
3978}
3979
3980static void
3981add_manually_resolved(void)
3982{
3983 if (manually_resolved_ipv4_list) {
3984 wmem_map_foreach(manually_resolved_ipv4_list, add_manually_resolved_ipv4, NULL((void*)0));
3985 }
3986
3987 if (manually_resolved_ipv6_list) {
3988 wmem_map_foreach(manually_resolved_ipv6_list, add_manually_resolved_ipv6, NULL((void*)0));
3989 }
3990}
3991
3992static void
3993host_name_lookup_init(const char* app_env_var_prefix)
3994{
3995 char *hostspath;
3996 unsigned i;
3997
3998 ws_assert(ipxnet_hash_table == NULL)do { if ((1) && !(ipxnet_hash_table == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 3998, __func__, "assertion failed: %s"
, "ipxnet_hash_table == ((void*)0)"); } while (0)
;
3999 ipxnet_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
4000
4001 ws_assert(ipv4_hash_table == NULL)do { if ((1) && !(ipv4_hash_table == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 4001, __func__, "assertion failed: %s"
, "ipv4_hash_table == ((void*)0)"); } while (0)
;
4002 ipv4_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
4003
4004 ws_assert(ipv6_hash_table == NULL)do { if ((1) && !(ipv6_hash_table == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 4004, __func__, "assertion failed: %s"
, "ipv6_hash_table == ((void*)0)"); } while (0)
;
4005 ipv6_hash_table = wmem_map_new(addr_resolv_scope, ipv6_oat_hash, ipv6_equal);
4006
4007 ws_assert(async_dns_queue_head == NULL)do { if ((1) && !(async_dns_queue_head == ((void*)0))
) ws_log_fatal_full("", LOG_LEVEL_ERROR, "epan/addr_resolv.c"
, 4007, __func__, "assertion failed: %s", "async_dns_queue_head == ((void*)0)"
); } while (0)
;
4008 async_dns_queue_head = wmem_list_new(addr_resolv_scope);
4009
4010 /*
4011 * The manually resolved lists are the only address resolution maps
4012 * that are not reset by addr_resolv_cleanup(), because they are
4013 * the only ones that do not have entries from personal configuration
4014 * files that can change when changing configurations. All their
4015 * entries must also be in epan scope.
4016 */
4017 if (manually_resolved_ipv4_list == NULL((void*)0))
4018 manually_resolved_ipv4_list = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
4019
4020 if (manually_resolved_ipv6_list == NULL((void*)0))
4021 manually_resolved_ipv6_list = wmem_map_new(wmem_epan_scope(), ws_ipv6_hash, ipv6_equal);
4022
4023 /*
4024 * Load the global hosts file, if we have one.
4025 */
4026 hostspath = get_datafile_path(ENAME_HOSTS"hosts", app_env_var_prefix);
4027 if (!read_hosts_file(hostspath, true1) && errno(*__errno_location ()) != ENOENT2) {
4028 report_open_failure(hostspath, errno(*__errno_location ()), false0);
4029 }
4030 g_free(hostspath);
4031 /*
4032 * Load the user's hosts file no matter what, if they have one.
4033 */
4034 hostspath = get_persconffile_path(ENAME_HOSTS"hosts", true1, app_env_var_prefix);
4035 if (!read_hosts_file(hostspath, true1) && errno(*__errno_location ()) != ENOENT2) {
4036 report_open_failure(hostspath, errno(*__errno_location ()), false0);
4037 }
4038 g_free(hostspath);
4039#ifdef CARES_HAVE_ARES_LIBRARY_INIT1
4040 if (ares_library_init(ARES_LIB_INIT_ALL((1 << 0))) == ARES_SUCCESS) {
4041#endif
4042 /* XXX - Check which options we should set */
4043 if (ares_init_options(&ghba_chan, NULL((void*)0), 0) == ARES_SUCCESS && ares_init_options(&ghbn_chan, NULL((void*)0), 0) == ARES_SUCCESS) {
4044 async_dns_initialized = true1;
4045 c_ares_set_dns_servers();
4046 }
4047#ifdef CARES_HAVE_ARES_LIBRARY_INIT1
4048 }
4049#endif
4050
4051 if (extra_hosts_files) {
4052 for (i = 0; i < extra_hosts_files->len; i++) {
4053 read_hosts_file((const char *) g_ptr_array_index(extra_hosts_files, i)((extra_hosts_files)->pdata)[i], true1);
4054 }
4055 }
4056
4057 subnet_name_lookup_init(app_env_var_prefix);
4058 subnet6_name_lookup_init(app_env_var_prefix);
4059
4060 add_manually_resolved();
4061
4062 ss7pc_name_lookup_init(app_env_var_prefix);
4063}
4064
4065static void
4066host_name_lookup_cleanup(void)
4067{
4068 uint32_t i, j;
4069 sub_net_hashipv4_t *entry, *next_entry;
4070
4071 _host_name_lookup_cleanup();
4072
4073 ipxnet_hash_table = NULL((void*)0);
4074 ipv4_hash_table = NULL((void*)0);
4075 ipv6_hash_table = NULL((void*)0);
4076 ss7pc_hash_table = NULL((void*)0);
4077
4078 for(i = 0; i < SUBNETLENGTHSIZE32; ++i) {
4079 if (subnet_length_entries[i].subnet_addresses != NULL((void*)0)) {
4080 for (j = 0; j < HASHHOSTSIZE2048; j++) {
4081 for (entry = subnet_length_entries[i].subnet_addresses[j];
4082 entry != NULL((void*)0); entry = next_entry) {
4083 next_entry = entry->next;
4084 wmem_free(addr_resolv_scope, entry);
4085 }
4086 }
4087 wmem_free(addr_resolv_scope, subnet_length_entries[i].subnet_addresses);
4088 subnet_length_entries[i].subnet_addresses = NULL((void*)0);
4089 }
4090 }
4091
4092 have_subnet_entry = false0;
4093
4094 for(i = 0; i < SUBNETLENGTHSIZE_V6128; ++i) {
4095 sub_net_hashipv6_t *entry6, *next_entry6;
4096 if (subnet_length_entries_v6[i].subnet_addresses != NULL((void*)0)) {
4097 for (j = 0; j < HASHHOSTSIZE2048; j++) {
4098 for (entry6 = subnet_length_entries_v6[i].subnet_addresses[j];
4099 entry6 != NULL((void*)0); entry6 = next_entry6) {
4100 next_entry6 = entry6->next;
4101 wmem_free(addr_resolv_scope, entry6);
4102 }
4103 }
4104 wmem_free(addr_resolv_scope, subnet_length_entries_v6[i].subnet_addresses);
4105 subnet_length_entries_v6[i].subnet_addresses = NULL((void*)0);
4106 }
4107 }
4108 have_subnet_entry_v6 = false0;
4109
4110 new_resolved_objects = false0;
4111}
4112
4113
4114void host_name_lookup_reset(const char* app_env_var_prefix)
4115{
4116 addr_resolv_cleanup();
4117 addr_resolv_init(app_env_var_prefix);
4118}
4119
4120char *
4121udp_port_to_display(wmem_allocator_t *allocator, unsigned port)
4122{
4123
4124 if (!gbl_resolv_flags.transport_name) {
4125 return wmem_utoa(allocator, port);
4126 }
4127
4128 return wmem_strdup(allocator, serv_name_lookup(PT_UDP, port));
4129
4130} /* udp_port_to_display */
4131
4132char *
4133dccp_port_to_display(wmem_allocator_t *allocator, unsigned port)
4134{
4135
4136 if (!gbl_resolv_flags.transport_name) {
4137 return wmem_utoa(allocator, port);
4138 }
4139
4140 return wmem_strdup(allocator, serv_name_lookup(PT_DCCP, port));
4141
4142} /* dccp_port_to_display */
4143
4144char *
4145tcp_port_to_display(wmem_allocator_t *allocator, unsigned port)
4146{
4147
4148 if (!gbl_resolv_flags.transport_name) {
4149 return wmem_utoa(allocator, port);
4150 }
4151
4152 return wmem_strdup(allocator, serv_name_lookup(PT_TCP, port));
4153
4154} /* tcp_port_to_display */
4155
4156char *
4157sctp_port_to_display(wmem_allocator_t *allocator, unsigned port)
4158{
4159
4160 if (!gbl_resolv_flags.transport_name) {
4161 return wmem_utoa(allocator, port);
4162 }
4163
4164 return wmem_strdup(allocator, serv_name_lookup(PT_SCTP, port));
4165
4166} /* sctp_port_to_display */
4167
4168char *
4169port_with_resolution_to_str(wmem_allocator_t *scope, port_type proto, unsigned port)
4170{
4171 const char *port_str;
4172
4173 if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
4174 /* No name resolution support, just return port string */
4175 return wmem_strdup_printf(scope, "%u", port);
4176 }
4177 port_str = serv_name_lookup(proto, port);
4178 ws_assert(port_str)do { if ((1) && !(port_str)) ws_log_fatal_full("", LOG_LEVEL_ERROR
, "epan/addr_resolv.c", 4178, __func__, "assertion failed: %s"
, "port_str"); } while (0)
;
4179 return wmem_strdup_printf(scope, "%s (%u)", port_str, port);
4180}
4181
4182int
4183port_with_resolution_to_str_buf(char *buf, unsigned long buf_size, port_type proto, unsigned port)
4184{
4185 const char *port_str;
4186
4187 if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
4188 /* No name resolution support, just return port string */
4189 return snprintf(buf, buf_size, "%u", port);
4190 }
4191 port_str = serv_name_lookup(proto, port);
4192 ws_assert(port_str)do { if ((1) && !(port_str)) ws_log_fatal_full("", LOG_LEVEL_ERROR
, "epan/addr_resolv.c", 4192, __func__, "assertion failed: %s"
, "port_str"); } while (0)
;
4193 return snprintf(buf, buf_size, "%s (%u)", port_str, port);
4194}
4195
4196const char *
4197get_ether_name(const uint8_t *addr)
4198{
4199 hashether_t *tp;
4200 bool_Bool resolve = gbl_resolv_flags.mac_name;
4201
4202 tp = eth_name_lookup(addr, resolve);
4203
4204 return resolve ? tp->resolved_name : tp->hexaddr;
4205
4206} /* get_ether_name */
4207
4208const char *
4209tvb_get_ether_name(tvbuff_t *tvb, unsigned offset)
4210{
4211 return get_ether_name(tvb_get_ptr(tvb, offset, 6));
4212}
4213
4214/* Look for a (non-dummy) ether name in the hash, and return it if found.
4215 * If it's not found, simply return NULL.
4216 */
4217const char *
4218get_ether_name_if_known(const uint8_t *addr)
4219{
4220 hashether_t *tp;
4221
4222 /* Initialize ether structs if we're the first
4223 * ether-related function called */
4224 if (!gbl_resolv_flags.mac_name)
4225 return NULL((void*)0);
4226
4227 /* eth_name_lookup will create a (resolved) hash entry
4228 * if it doesn't exist, so it never returns NULL */
4229 tp = eth_name_lookup(addr, true1);
4230
4231 if ((tp->flags & (NAME_RESOLVED(1U<<1) | NAME_RESOLVED_PREFIX(1U<<4))) == NAME_RESOLVED(1U<<1)) {
4232 /* Name is from an exact match, not a prefix/OUI */
4233 return tp->resolved_name;
4234 }
4235 else {
4236 /* Name was created */
4237 return NULL((void*)0);
4238 }
4239}
4240
4241void
4242add_ether_byip(const unsigned ip, const uint8_t *eth)
4243{
4244 hashipv4_t *tp;
4245
4246 /* first check that IP address can be resolved */
4247 if (!gbl_resolv_flags.network_name)
4248 return;
4249
4250 tp = host_lookup(ip);
4251
4252 /*
4253 * Was this IP address resolved to a host name?
4254 */
4255 if (tp->flags & NAME_RESOLVED(1U<<1)) {
4256 /*
4257 * Yes, so add an entry in the ethers hashtable resolving
4258 * the MAC address to that name.
4259 */
4260 add_eth_name(eth, tp->name, false0);
4261 }
4262
4263} /* add_ether_byip */
4264
4265char *
4266get_ipxnet_name(wmem_allocator_t *allocator, const uint32_t addr)
4267{
4268
4269 if (!gbl_resolv_flags.network_name) {
1
Assuming field 'network_name' is true
2
Taking false branch
4270 return ipxnet_to_str_punct(allocator, addr, '\0');
4271 }
4272
4273 return ipxnet_name_lookup(allocator, addr);
3
Calling 'ipxnet_name_lookup'
4274
4275} /* get_ipxnet_name */
4276
4277char *
4278get_vlan_name(wmem_allocator_t *allocator, const uint16_t id)
4279{
4280
4281 if (!gbl_resolv_flags.vlan_name) {
4282 return NULL((void*)0);
4283 }
4284
4285 return wmem_strdup(allocator, vlan_name_lookup(id));
4286
4287} /* get_vlan_name */
4288
4289const char *
4290get_manuf_name(const uint8_t *addr, size_t size)
4291{
4292 hashmanuf_t *manuf_value;
4293
4294 ws_return_val_if(size < 3, NULL)do { if (1 && (size < 3)) { ws_log_full("InvalidArg"
, LOG_LEVEL_WARNING, "epan/addr_resolv.c", 4294, __func__, "invalid argument: %s"
, "size < 3"); return (((void*)0)); } } while (0)
;
4295
4296 manuf_value = manuf_name_lookup(addr, size);
4297 if (gbl_resolv_flags.mac_name && ((manuf_value->flags & NAME_RESOLVED(1U<<1)) == NAME_RESOLVED(1U<<1)))
4298 return manuf_value->resolved_name;
4299
4300 return manuf_value->hexaddr;
4301
4302} /* get_manuf_name */
4303
4304const char *
4305tvb_get_manuf_name(tvbuff_t *tvb, unsigned offset)
4306{
4307 uint8_t buf[3] = { 0 };
4308 tvb_memcpy(tvb, buf, offset, 3);
4309 return get_manuf_name(buf, sizeof(buf));
4310}
4311
4312const char *
4313get_manuf_name_if_known(const uint8_t *addr, size_t size)
4314{
4315 hashmanuf_t *manuf_value;
4316
4317 ws_return_val_if(size < 3, NULL)do { if (1 && (size < 3)) { ws_log_full("InvalidArg"
, LOG_LEVEL_WARNING, "epan/addr_resolv.c", 4317, __func__, "invalid argument: %s"
, "size < 3"); return (((void*)0)); } } while (0)
;
4318
4319 manuf_value = manuf_name_lookup(addr, size);
4320 if (manuf_value != NULL((void*)0) && ((manuf_value->flags & NAME_RESOLVED(1U<<1)) == NAME_RESOLVED(1U<<1))) {
4321 return manuf_value->resolved_longname;
4322 }
4323
4324 if (size >= 6) {
4325 /* Try the global manuf tables. */
4326 const char *short_name, *long_name;
4327 short_name = ws_manuf_lookup_str(addr, &long_name);
4328 if (short_name != NULL((void*)0)) {
4329 /* Found it */
4330 return long_name;
4331 }
4332 }
4333
4334 return NULL((void*)0);
4335
4336} /* get_manuf_name_if_known */
4337
4338const char *
4339uint_get_manuf_name_if_known(const uint32_t manuf_key)
4340{
4341 uint8_t addr[6] = { 0 };
4342 addr[0] = (manuf_key >> 16) & 0xFF;
4343 addr[1] = (manuf_key >> 8) & 0xFF;
4344 addr[2] = manuf_key & 0xFF;
4345
4346 return get_manuf_name_if_known(addr, sizeof(addr));
4347}
4348
4349const char *
4350tvb_get_manuf_name_if_known(tvbuff_t *tvb, unsigned offset)
4351{
4352 uint8_t buf[3] = { 0 };
4353 tvb_memcpy(tvb, buf, offset, 3);
4354 return get_manuf_name_if_known(buf, sizeof(buf));
4355}
4356
4357bool_Bool get_hash_manuf_used(hashmanuf_t* manuf)
4358{
4359 return ((manuf->flags & TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1))) == TRIED_OR_RESOLVED_MASK((1U<<0) | (1U<<1)));
4360}
4361
4362char* get_hash_manuf_resolved_name(hashmanuf_t* manuf)
4363{
4364 return manuf->resolved_longname;
4365}
4366
4367const char *
4368get_eui64_name(const uint8_t *addr)
4369{
4370 hasheui64_t *tp;
4371 bool_Bool resolve = gbl_resolv_flags.mac_name;
4372
4373 tp = eui64_name_lookup(addr, resolve);
4374
4375 return resolve ? tp->resolved_name : tp->hexaddr;
4376
4377} /* get_eui64_name */
4378
4379char *
4380eui64_to_display(wmem_allocator_t *allocator, const uint64_t addr_eui64)
4381{
4382 uint8_t addr[EUI64_ADDR_LEN8];
4383
4384 phtonu64(addr, addr_eui64);
4385
4386 const char *result = get_eui64_name(addr);
4387
4388 return wmem_strdup(allocator, result);
4389} /* eui64_to_display */
4390
4391#define GHI_TIMEOUT(250 * 1000) (250 * 1000)
4392static void
4393c_ares_ghi_cb(void *arg, int status, int timeouts _U___attribute__((unused)), struct hostent *hp) {
4394 /*
4395 * XXX - If we wanted to be really fancy we could cache results here and
4396 * look them up in get_host_ipaddr* below.
4397 *
4398 * XXX - This only gets the first host address if there's more than one.
4399 */
4400 async_hostent_t *ahp = (async_hostent_t *)arg;
4401 if (status == ARES_SUCCESS && hp && ahp && hp->h_length == ahp->addr_size) {
4402 memcpy(ahp->addrp, hp->h_addrh_addr_list[0], hp->h_length);
4403 ahp->copied = hp->h_length;
4404 }
4405}
4406
4407/* Translate a string, assumed either to be a dotted-quad IPv4 address or
4408 * a host name, to a numeric IPv4 address. Return true if we succeed and
4409 * set "*addrp" to that numeric IPv4 address; return false if we fail. */
4410bool_Bool
4411get_host_ipaddr(const char *host, uint32_t *addrp)
4412{
4413 struct timeval tv = { 0, GHI_TIMEOUT(250 * 1000) }, *tvp;
4414 int nfds;
4415 fd_set rfds, wfds;
4416 async_hostent_t ahe;
4417
4418 /*
4419 * XXX - are there places where this is used to translate something
4420 * that's *only* supposed to be an IPv4 address, and where it
4421 * *shouldn't* translate host names?
4422 */
4423 if (!ws_inet_pton4(host, addrp)) {
4424
4425 /* It's not a valid dotted-quad IP address; is it a valid
4426 * host name?
4427 */
4428
4429 /* If we're not allowed to do name resolution, don't do name
4430 * resolution...
4431 * XXX - What if we're allowed to do name resolution, and the name
4432 * is in a DNS packet we've dissected or in a Name Resolution Block,
4433 * or a user-entered manual name resolution?
4434 */
4435 if (!gbl_resolv_flags.network_name ||
4436 !gbl_resolv_flags.use_external_net_name_resolver) {
4437 return false0;
4438 }
4439
4440 if (!async_dns_initialized || name_resolve_concurrency < 1) {
4441 return false0;
4442 }
4443 ahe.addr_size = (int) sizeof (struct in_addr);
4444 ahe.copied = 0;
4445 ahe.addrp = addrp;
4446 ares_gethostbyname(ghbn_chan, host, AF_INET2, c_ares_ghi_cb, &ahe);
4447 FD_ZERO(&rfds)do { unsigned int __i; fd_set *__arr = (&rfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
4448 FD_ZERO(&wfds)do { unsigned int __i; fd_set *__arr = (&wfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
4449 nfds = ares_fds(ghbn_chan, &rfds, &wfds);
4450 if (nfds > 0) {
4451 tvp = ares_timeout(ghbn_chan, &tv, &tv);
4452 if (select(nfds, &rfds, &wfds, NULL((void*)0), tvp) == -1) { /* call to select() failed */
4453 /* If it's interrupted by a signal, no need to put out a message */
4454 if (errno(*__errno_location ()) != EINTR4)
4455 fprintf(stderrstderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno(*__errno_location ())));
4456 return false0;
4457 }
4458 ares_process(ghbn_chan, &rfds, &wfds);
4459 }
4460 ares_cancel(ghbn_chan);
4461 if (ahe.addr_size == ahe.copied) {
4462 return true1;
4463 }
4464 return false0;
4465 }
4466
4467 return true1;
4468}
4469
4470/*
4471 * Translate IPv6 numeric address or FQDN hostname into binary IPv6 address.
4472 * Return true if we succeed and set "*addrp" to that numeric IPv6 address;
4473 * return false if we fail.
4474 */
4475bool_Bool
4476get_host_ipaddr6(const char *host, ws_in6_addr *addrp)
4477{
4478 struct timeval tv = { 0, GHI_TIMEOUT(250 * 1000) }, *tvp;
4479 int nfds;
4480 fd_set rfds, wfds;
4481 async_hostent_t ahe;
4482
4483 if (str_to_ip6(host, addrp))
4484 return true1;
4485
4486 /* It's not a valid dotted-quad IP address; is it a valid
4487 * host name?
4488 *
4489 * XXX - are there places where this is used to translate something
4490 * that's *only* supposed to be an IPv6 address, and where it
4491 * *shouldn't* translate host names?
4492 */
4493
4494 /* If we're not allowed to do name resolution, don't do name
4495 * resolution...
4496 * XXX - What if we're allowed to do name resolution, and the name
4497 * is in a DNS packet we've dissected or in a Name Resolution Block,
4498 * or a user-entered manual name resolution?
4499 */
4500 if (!gbl_resolv_flags.network_name ||
4501 !gbl_resolv_flags.use_external_net_name_resolver) {
4502 return false0;
4503 }
4504
4505 /* try FQDN */
4506 if (!async_dns_initialized || name_resolve_concurrency < 1) {
4507 return false0;
4508 }
4509 ahe.addr_size = (int) sizeof (ws_in6_addr);
4510 ahe.copied = 0;
4511 ahe.addrp = addrp;
4512 ares_gethostbyname(ghbn_chan, host, AF_INET610, c_ares_ghi_cb, &ahe);
4513 FD_ZERO(&rfds)do { unsigned int __i; fd_set *__arr = (&rfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
4514 FD_ZERO(&wfds)do { unsigned int __i; fd_set *__arr = (&wfds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->__fds_bits)[__i] = 0; } while (0)
;
4515 nfds = ares_fds(ghbn_chan, &rfds, &wfds);
4516 if (nfds > 0) {
4517 tvp = ares_timeout(ghbn_chan, &tv, &tv);
4518 if (select(nfds, &rfds, &wfds, NULL((void*)0), tvp) == -1) { /* call to select() failed */
4519 /* If it's interrupted by a signal, no need to put out a message */
4520 if (errno(*__errno_location ()) != EINTR4)
4521 fprintf(stderrstderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno(*__errno_location ())));
4522 return false0;
4523 }
4524 ares_process(ghbn_chan, &rfds, &wfds);
4525 }
4526 ares_cancel(ghbn_chan);
4527 if (ahe.addr_size == ahe.copied) {
4528 return true1;
4529 }
4530
4531 return false0;
4532}
4533
4534wmem_map_t *
4535get_manuf_hashtable(void)
4536{
4537 return manuf_hashtable;
4538}
4539
4540wmem_map_t *
4541get_wka_hashtable(void)
4542{
4543 return wka_hashtable;
4544}
4545
4546wmem_map_t *
4547get_eth_hashtable(void)
4548{
4549 return eth_hashtable;
4550}
4551
4552wmem_map_t *
4553get_serv_port_hashtable(void)
4554{
4555 return serv_port_hashtable;
4556}
4557
4558wmem_map_t *
4559get_ipxnet_hash_table(void)
4560{
4561 return ipxnet_hash_table;
4562}
4563
4564wmem_map_t *
4565get_vlan_hash_table(void)
4566{
4567 return vlan_hash_table;
4568}
4569
4570wmem_map_t *
4571get_ipv4_hash_table(void)
4572{
4573 return ipv4_hash_table;
4574}
4575
4576wmem_map_t *
4577get_ipv6_hash_table(void)
4578{
4579 return ipv6_hash_table;
4580}
4581/* Initialize all the address resolution subsystems in this file */
4582void
4583addr_resolv_init(const char* app_env_var_prefix)
4584{
4585 ws_assert(addr_resolv_scope == NULL)do { if ((1) && !(addr_resolv_scope == ((void*)0))) ws_log_fatal_full
("", LOG_LEVEL_ERROR, "epan/addr_resolv.c", 4585, __func__, "assertion failed: %s"
, "addr_resolv_scope == ((void*)0)"); } while (0)
;
4586 addr_resolv_scope = wmem_allocator_new(WMEM_ALLOCATOR_BLOCK);
4587 initialize_services(app_env_var_prefix);
4588 initialize_ethers(app_env_var_prefix);
4589 initialize_ipxnets(app_env_var_prefix);
4590 initialize_vlans(app_env_var_prefix);
4591 initialize_enterprises(app_env_var_prefix);
4592 host_name_lookup_init(app_env_var_prefix);
4593 initialize_tacs(app_env_var_prefix);
4594}
4595
4596/* Clean up all the address resolution subsystems in this file */
4597void
4598addr_resolv_cleanup(void)
4599{
4600 vlan_name_lookup_cleanup();
4601 service_name_lookup_cleanup();
4602 ethers_cleanup();
4603 ipx_name_lookup_cleanup();
4604 enterprises_cleanup();
4605 host_name_lookup_cleanup();
4606 tac_name_lookup_cleanup();
4607
4608 wmem_destroy_allocator(addr_resolv_scope);
4609 addr_resolv_scope = NULL((void*)0);
4610}
4611
4612bool_Bool
4613str_to_ip(const char *str, void *dst)
4614{
4615 return ws_inet_pton4(str, (uint32_t *)dst);
4616}
4617
4618bool_Bool
4619str_to_ip6(const char *str, void *dst)
4620{
4621 return ws_inet_pton6(str, (ws_in6_addr *)dst);
4622}
4623
4624/*
4625 * convert a 0-terminated string that contains an ethernet address into
4626 * the corresponding sequence of 6 bytes
4627 * eth_bytes is a buffer >= 6 bytes that was allocated by the caller
4628 */
4629bool_Bool
4630str_to_eth(const char *str, uint8_t (*eth_bytes)[6])
4631{
4632 ether_t eth;
4633 unsigned mask;
4634
4635 if (!parse_ether_address(str, &eth, &mask, false0))
4636 return false0;
4637
4638 if (mask == 48) {
4639 memcpy(eth_bytes, eth.addr, 6);
4640 }
4641 return true1;
4642}
4643
4644/*
4645 * Editor modelines - https://www.wireshark.org/tools/modelines.html
4646 *
4647 * Local variables:
4648 * c-basic-offset: 4
4649 * tab-width: 8
4650 * indent-tabs-mode: nil
4651 * End:
4652 *
4653 * vi: set shiftwidth=4 tabstop=8 expandtab:
4654 * :indentSize=4:tabSize=8:noTabs=true:
4655 */