### Bug Summary

File: | builds/wireshark/wireshark/epan/addr_resolv.c
Warning: | line 4041, column 46 An undefined value may be read from 'errno'

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