### Bug Summary

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

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
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-01-11-100356-3603-1 -x c /builds/wireshark/wireshark/epan/addr_resolv.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

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