Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/addr_resolv.c
Line
Count
Source
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.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_H
60
# include <netinet/in.h>
61
#endif
62
63
#ifdef HAVE_NETDB_H
64
#include <netdb.h>
65
#endif
66
67
#ifdef HAVE_SYS_SOCKET_H
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
56
#define ENAME_HOSTS     "hosts"
100
84
#define ENAME_SUBNETS   "subnets"
101
84
#define ENAME_SUBNETS_V6 "subnetsipv6"
102
84
#define ENAME_ETHERS    "ethers"
103
84
#define ENAME_IPXNETS   "ipxnets"
104
84
#define ENAME_MANUF     "manuf"
105
28
#define ENAME_WKA       "wka"
106
84
#define ENAME_SERVICES  "services"
107
56
#define ENAME_VLANS     "vlans"
108
28
#define ENAME_SS7PCS    "ss7pcs"
109
84
#define ENAME_ENTERPRISES "enterprises"
110
28
#define ENAME_TACS      "tacs"
111
112
#define HASHETHSIZE      2048
113
0
#define HASHHOSTSIZE     2048
114
#define HASHIPXNETSIZE    256
115
1.46k
#define SUBNETLENGTHSIZE   32  /*1-32 inc.*/
116
5.41k
#define SUBNETLENGTHSIZE_V6 128 /*1-128 inc.*/
117
118
/* hash table used for IPv4 lookup */
119
120
0
#define HASH_IPV4_ADDRESS(addr) (g_htonl(addr) & (HASHHOSTSIZE - 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[MAXNAMELEN];
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[MAXNAMELEN];
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) & (HASHIPXNETSIZE - 1))
164
165
typedef struct hashipxnet {
166
    unsigned            addr;
167
    struct hashipxnet  *next;
168
    char                name[MAXNAMELEN];
169
} hashipxnet_t;
170
171
typedef struct hashvlan {
172
    unsigned            id;
173
/*    struct hashvlan     *next; */
174
    char                name[MAXVLANNAMELEN];
175
} hashvlan_t;
176
177
typedef struct ss7pc {
178
    uint32_t            id; /* 1st byte NI, 3 following bytes: Point Code */
179
    char                pc_addr[MAXNAMELEN];
180
    char                name[MAXNAMELEN];
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[MAXNAMELEN];
189
};
190
191
struct hasheui64 {
192
    uint8_t           flags;  /* (See above) */
193
    uint8_t           addr[EUI64_ADDR_LEN];
194
    char              hexaddr[EUI64_ADDR_LEN*3];
195
    char              resolved_name[MAXNAMELEN];
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[MAXNAMELEN];
208
    char              resolved_longname[MAXNAMELEN];
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[MAXNAMELEN];
216
    char              longname[MAXNAMELEN];
217
} ether_t;
218
219
/* internal ipxnet type */
220
typedef struct _ipxnet
221
{
222
    unsigned          addr;
223
    char              name[MAXNAMELEN];
224
} ipxnet_t;
225
226
/* internal vlan type */
227
typedef struct _vlan
228
{
229
    unsigned          id;
230
    char              name[MAXVLANNAMELEN];
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[SUBNETLENGTHSIZE]; /* Ordered array of entries */
274
static bool have_subnet_entry;
275
276
static subnet_length_entry_v6_t subnet_length_entries_v6[SUBNETLENGTHSIZE_V6]; /* IPv6 subnet entries */
277
static bool have_subnet_entry_v6;
278
279
static 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 static_entry);
284
static hasheui64_t *add_eui64_name(const uint8_t *addr, const char *name, 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
618
{
293
618
    int len = 16;
294
618
    const unsigned char *p = (const unsigned char *)key;
295
618
    unsigned h = 0;
296
618
    int i;
297
298
10.5k
    for ( i = 0; i < len; i++ ) {
299
9.88k
        h += p[i];
300
9.88k
        h += ( h << 10 );
301
9.88k
        h ^= ( h >> 6 );
302
9.88k
    }
303
304
618
    h += ( h << 3 );
305
618
    h ^= ( h >> 11 );
306
618
    h += ( h << 15 );
307
308
618
    return h;
309
618
}
310
311
unsigned
312
ws_ipv6_hash(const void* key)
313
0
{
314
#ifdef HAVE_XXHASH
315
    return wmem_strong_hash(key, 16);
316
#else
317
0
    return ipv6_oat_hash(key);
318
0
#endif
319
0
}
320
321
gboolean
322
ipv6_equal(const void *v1, const void *v2)
323
236
{
324
325
236
    if (memcmp(v1, v2, sizeof (ws_in6_addr)) == 0) {
326
233
        return true;
327
233
    }
328
329
3
    return false;
330
236
}
331
332
/*
333
 * Flag controlling what names to resolve.
334
 */
335
e_addr_resolve gbl_resolv_flags = {
336
    true,   /* mac_name */
337
    false,  /* network_name */
338
    false,  /* transport_name */
339
    true,   /* dns_pkt_addr_resolution */
340
    false,  /* handshake_sni_addr_resolution */
341
    true,   /* use_external_net_name_resolver */
342
    false,  /* vlan_name */
343
    false,  /* ss7 point code names */
344
    true,   /* maxmind_geoip */
345
    false,  /* 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 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_, 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            *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        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 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
0
UAT_CSTRING_CB_DEF(dnsserverlist_uats, ipaddr, struct dns_server_data)
431
0
UAT_DEC_CB_DEF(dnsserverlist_uats, tcp_port, struct dns_server_data)
Unexecuted instantiation: addr_resolv.c:dnsserverlist_uats_tcp_port_set_cb
Unexecuted instantiation: addr_resolv.c:dnsserverlist_uats_tcp_port_tostr_cb
432
0
UAT_DEC_CB_DEF(dnsserverlist_uats, udp_port, struct dns_server_data)
Unexecuted instantiation: addr_resolv.c:dnsserverlist_uats_udp_port_set_cb
Unexecuted instantiation: addr_resolv.c:dnsserverlist_uats_udp_port_tostr_cb
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
0
{
441
0
    struct dns_server_data *h = (struct dns_server_data*)data;
442
443
0
    g_free(h->ipaddr);
444
0
}
445
446
static void*
447
dns_server_copy_cb(void *dst_, const void *src_, size_t len _U_)
448
0
{
449
0
    const struct dns_server_data *src = (const struct dns_server_data *)src_;
450
0
    struct dns_server_data       *dst = (struct dns_server_data *)dst_;
451
452
0
    dst->ipaddr = g_strdup(src->ipaddr);
453
0
    dst->udp_port = src->udp_port;
454
0
    dst->tcp_port = src->tcp_port;
455
456
0
    return dst;
457
0
}
458
459
static bool
460
dnsserver_uat_fld_ip_chk_cb(void* r _U_, const char* ipaddr, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
461
0
{
462
    //Check for a valid IPv4 or IPv6 address.
463
0
    if (ipaddr && g_hostname_is_ip_address(ipaddr)) {
464
0
        *err = NULL;
465
0
        return true;
466
0
    }
467
468
0
    *err = ws_strdup_printf("No valid IP address given.");
469
0
    return false;
470
0
}
471
472
static bool
473
dnsserver_uat_fld_port_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
474
0
{
475
0
    if (!p || strlen(p) == 0u) {
476
        // This should be removed in favor of Decode As. Make it optional.
477
0
        *err = NULL;
478
0
        return true;
479
0
    }
480
481
0
    if (strcmp(p, "53") != 0){
482
0
        uint16_t port;
483
0
        if (!ws_strtou16(p, NULL, &port)) {
484
0
            *err = g_strdup("Invalid port given.");
485
0
            return false;
486
0
        }
487
0
    }
488
489
0
    *err = NULL;
490
0
    return true;
491
0
}
492
493
static void
494
0
c_ares_ghba_sync_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
495
0
    sync_dns_data_t *sdd = (sync_dns_data_t *)arg;
496
0
    char **p;
497
498
0
    if (status == ARES_SUCCESS) {
499
0
        for (p = he->h_addr_list; *p != NULL; p++) {
500
0
            switch(sdd->family) {
501
0
                case AF_INET:
502
0
                    add_ipv4_name(sdd->addr.ip4, he->h_name, false);
503
0
                    break;
504
0
                case AF_INET6:
505
0
                    add_ipv6_name(&sdd->addr.ip6, he->h_name, false);
506
0
                    break;
507
0
                default:
508
                    /* Throw an exception? */
509
0
                    break;
510
0
            }
511
0
        }
512
513
0
    }
514
515
    /*
516
     * Let our caller know that this is complete.
517
     */
518
0
    *sdd->completed = true;
519
520
    /*
521
     * Free the structure for this call.
522
     */
523
0
    g_free(sdd);
524
0
}
525
526
static void
527
0
wait_for_sync_resolv(bool *completed) {
528
0
    int nfds;
529
0
    fd_set rfds, wfds;
530
0
    struct timeval tv;
531
532
0
    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
0
        tv.tv_sec = 1;
555
0
        tv.tv_usec = 0;
556
557
0
        FD_ZERO(&rfds);
558
0
        FD_ZERO(&wfds);
559
0
        nfds = ares_fds(ghba_chan, &rfds, &wfds);
560
0
        if (nfds > 0) {
561
0
            if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
562
                /* If it's interrupted by a signal, no need to put out a message */
563
0
                if (errno != EINTR)
564
0
                    fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
565
0
                return;
566
0
            }
567
0
            ares_process(ghba_chan, &rfds, &wfds);
568
0
        }
569
0
    }
570
0
}
571
572
static void
573
process_async_dns_queue(void)
574
0
{
575
0
    wmem_list_frame_t* head;
576
0
    async_dns_queue_msg_t *caqm;
577
578
0
    if (async_dns_queue_head == NULL)
579
0
        return;
580
581
0
    if (!g_mutex_trylock(&async_dns_queue_mtx))
582
0
        return;
583
584
0
    head = wmem_list_head(async_dns_queue_head);
585
586
0
    while (head != NULL && async_dns_in_flight <= name_resolve_concurrency) {
587
0
        caqm = (async_dns_queue_msg_t *)wmem_list_frame_data(head);
588
0
        wmem_list_remove_frame(async_dns_queue_head, head);
589
0
        if (caqm->family == AF_INET) {
590
0
            ares_gethostbyaddr(ghba_chan, &caqm->addr.ip4, sizeof(uint32_t), AF_INET,
591
0
                    c_ares_ghba_cb, caqm);
592
0
            async_dns_in_flight++;
593
0
        } else if (caqm->family == AF_INET6) {
594
0
            ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(ws_in6_addr),
595
0
                    AF_INET6, c_ares_ghba_cb, caqm);
596
0
            async_dns_in_flight++;
597
0
        }
598
599
0
        head = wmem_list_head(async_dns_queue_head);
600
0
    }
601
602
0
    g_mutex_unlock(&async_dns_queue_mtx);
603
0
}
604
605
static void
606
wait_for_async_queue(void)
607
0
{
608
0
    struct timeval tv = { 0, 0 };
609
0
    int nfds;
610
0
    fd_set rfds, wfds;
611
612
0
    new_resolved_objects = false;
613
614
0
    if (!async_dns_initialized) {
615
0
        maxmind_db_lookup_process();
616
0
        return;
617
0
    }
618
619
0
    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
0
        process_async_dns_queue();
625
626
0
        FD_ZERO(&rfds);
627
0
        FD_ZERO(&wfds);
628
0
        nfds = ares_fds(ghba_chan, &rfds, &wfds);
629
0
        if (nfds == 0) {
630
            /* No more requests waiting for reply; we're done here. */
631
0
            break;
632
0
        }
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
0
        tv.tv_sec = 1;
639
0
        tv.tv_usec = 0;
640
641
0
        if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
642
            /* If it's interrupted by a signal, no need to put out a message */
643
0
            if (errno != EINTR)
644
0
                fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
645
0
            return;
646
0
        }
647
0
        ares_process(ghba_chan, &rfds, &wfds);
648
0
    }
649
650
0
    maxmind_db_lookup_process();
651
0
    return;
652
0
}
653
654
static void
655
sync_lookup_ip4(const uint32_t addr)
656
0
{
657
0
    bool completed = false;
658
0
    sync_dns_data_t *sdd;
659
660
0
    if (!async_dns_initialized) {
661
        /*
662
         * c-ares not initialized.  Bail out.
663
         */
664
0
        return;
665
0
    }
666
667
    /*
668
     * Start the request.
669
     */
670
0
    sdd = g_new(sync_dns_data_t, 1);
671
0
    sdd->family = AF_INET;
672
0
    sdd->addr.ip4 = addr;
673
0
    sdd->completed = &completed;
674
0
    ares_gethostbyaddr(ghba_chan, &addr, sizeof(uint32_t), AF_INET,
675
0
                       c_ares_ghba_sync_cb, sdd);
676
677
    /*
678
     * Now wait for it to finish.
679
     */
680
0
    wait_for_sync_resolv(&completed);
681
0
}
682
683
static void
684
sync_lookup_ip6(const ws_in6_addr *addrp)
685
0
{
686
0
    bool completed = false;
687
0
    sync_dns_data_t *sdd;
688
689
0
    if (!async_dns_initialized) {
690
        /*
691
         * c-ares not initialized.  Bail out.
692
         */
693
0
        return;
694
0
    }
695
696
    /*
697
     * Start the request.
698
     */
699
0
    sdd = g_new(sync_dns_data_t, 1);
700
0
    sdd->family = AF_INET6;
701
0
    memcpy(&sdd->addr.ip6, addrp, sizeof(sdd->addr.ip6));
702
0
    sdd->completed = &completed;
703
0
    ares_gethostbyaddr(ghba_chan, addrp, sizeof(ws_in6_addr), AF_INET6,
704
0
                       c_ares_ghba_sync_cb, sdd);
705
706
    /*
707
     * Now wait for it to finish.
708
     */
709
0
    wait_for_sync_resolv(&completed);
710
0
}
711
712
void
713
set_resolution_synchrony(bool synchronous)
714
0
{
715
0
    resolve_synchronously = synchronous;
716
0
    maxmind_db_set_synchrony(synchronous);
717
718
0
    if (synchronous) {
719
0
        wait_for_async_queue();
720
0
    }
721
0
}
722
723
static void
724
c_ares_set_dns_servers(void)
725
42
{
726
42
    if ((!async_dns_initialized) || (!use_custom_dns_server_list))
727
42
        return;
728
729
0
    if (ndnsservers == 0) {
730
        //clear the list of servers.  This may effectively disable name resolution
731
0
        ares_set_servers_ports(ghba_chan, NULL);
732
0
        ares_set_servers_ports(ghbn_chan, NULL);
733
0
    } else {
734
0
        struct ares_addr_port_node* servers = wmem_alloc_array(NULL, struct ares_addr_port_node, ndnsservers);
735
0
        ws_in4_addr ipv4addr;
736
0
        ws_in6_addr ipv6addr;
737
0
        bool invalid_IP_found = false;
738
0
        struct ares_addr_port_node* server;
739
0
        unsigned i;
740
0
        for (i = 0, server = servers; i < ndnsservers-1; i++, server++) {
741
0
            if (ws_inet_pton6(dnsserverlist_uats[i].ipaddr, &ipv6addr)) {
742
0
                server->family = AF_INET6;
743
0
                memcpy(&server->addr.addr6, &ipv6addr, 16);
744
0
            } else if (ws_inet_pton4(dnsserverlist_uats[i].ipaddr, &ipv4addr)) {
745
0
                server->family = AF_INET;
746
0
                memcpy(&server->addr.addr4, &ipv4addr, 4);
747
0
            } else {
748
                //This shouldn't happen, but just in case...
749
0
                invalid_IP_found = true;
750
0
                server->family = 0;
751
0
                memset(&server->addr.addr4, 0, 4);
752
0
                break;
753
0
            }
754
755
0
            server->udp_port = (int)dnsserverlist_uats[i].udp_port;
756
0
            server->tcp_port = (int)dnsserverlist_uats[i].tcp_port;
757
758
0
            server->next = (server+1);
759
0
        }
760
0
        if (!invalid_IP_found) {
761
0
            if (ws_inet_pton6(dnsserverlist_uats[i].ipaddr, &ipv6addr)) {
762
0
                server->family = AF_INET6;
763
0
                memcpy(&server->addr.addr6, &ipv6addr, 16);
764
0
            }
765
0
            else if (ws_inet_pton4(dnsserverlist_uats[i].ipaddr, &ipv4addr)) {
766
0
                server->family = AF_INET;
767
0
                memcpy(&server->addr.addr4, &ipv4addr, 4);
768
0
            } else {
769
                //This shouldn't happen, but just in case...
770
0
                server->family = 0;
771
0
                memset(&server->addr.addr4, 0, 4);
772
0
            }
773
0
        }
774
0
        server->udp_port = (int)dnsserverlist_uats[i].udp_port;
775
0
        server->tcp_port = (int)dnsserverlist_uats[i].tcp_port;
776
777
0
        server->next = NULL;
778
779
0
        ares_set_servers_ports(ghba_chan, servers);
780
0
        ares_set_servers_ports(ghbn_chan, servers);
781
0
        wmem_free(NULL, servers);
782
0
    }
783
0
}
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_LINELEN     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
0
{
798
0
    if (fgets(buf, size, fp)) {
799
0
        int len = (int)strcspn(buf, "\r\n");
800
0
        buf[len] = '\0';
801
0
        return len;
802
0
    }
803
0
    return -1;
804
805
0
} /* 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
0
{
816
0
    const serv_port_key_t *key = (const serv_port_key_t*)k;
817
0
    return key->port + (key->type << 16);
818
0
}
819
820
static gboolean serv_port_custom_equal(const void *k1, const void *k2)
821
0
{
822
0
    const serv_port_key_t *key1 = (const serv_port_key_t*)k1;
823
0
    const serv_port_key_t *key2 = (const serv_port_key_t*)k2;
824
825
0
    return (key1->port == key2->port) && (key1->type == key2->type);
826
0
}
827
828
static void
829
add_custom_service_name(port_type proto, const unsigned port, const char *service_name)
830
0
{
831
0
    char *name;
832
0
    serv_port_key_t *key, *orig_key;
833
834
0
    key = wmem_new(addr_resolv_scope, serv_port_key_t);
835
0
    key->port = (uint16_t)port;
836
0
    key->type = proto;
837
838
0
    if (wmem_map_lookup_extended(serv_port_custom_hashtable, key, (const void**)&orig_key, (void**)&name)) {
839
0
        wmem_free(addr_resolv_scope, orig_key);
840
0
        wmem_free(addr_resolv_scope, name);
841
0
    }
842
843
0
    name = wmem_strdup(addr_resolv_scope, service_name);
844
0
    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
0
}
849
850
static void
851
add_service_name(port_type proto, const unsigned port, const char *service_name)
852
0
{
853
0
    serv_port_key_t *key = wmem_new(addr_resolv_scope, serv_port_key_t);
854
0
    key->port = (uint16_t)port;
855
0
    key->type = proto;
856
857
0
    wmem_map_insert(serv_port_hashtable, key, (void*)service_name);
858
859
0
    new_resolved_objects = true;
860
0
}
861
862
static void
863
parse_service_line (char *line)
864
0
{
865
0
    char *cp;
866
0
    char *service;
867
0
    char *port;
868
0
    port_type proto;
869
0
    struct cb_serv_data cb_data;
870
0
    range_t *port_rng = NULL;
871
872
0
    if ((cp = strchr(line, '#')))
873
0
        *cp = '\0';
874
875
0
    if ((cp = strtok(line, " \t")) == NULL)
876
0
        return;
877
878
0
    service = cp;
879
880
0
    if ((cp = strtok(NULL, " \t")) == NULL)
881
0
        return;
882
883
0
    port = cp;
884
885
0
    if (strtok(cp, "/") == NULL)
886
0
        return;
887
888
0
    if (range_convert_str(NULL, &port_rng, port, UINT16_MAX) != CVT_NO_ERROR) {
889
0
        wmem_free (NULL, port_rng);
890
0
        return;
891
0
    }
892
893
0
    while ((cp = strtok(NULL, "/")) != NULL) {
894
0
        if (strcmp(cp, "tcp") == 0) {
895
0
            proto = PT_TCP;
896
0
        }
897
0
        else if (strcmp(cp, "udp") == 0) {
898
0
            proto = PT_UDP;
899
0
        }
900
0
        else if (strcmp(cp, "sctp") == 0) {
901
0
            proto = PT_SCTP;
902
0
        }
903
0
        else if (strcmp(cp, "dccp") == 0) {
904
0
            proto = PT_DCCP;
905
0
        }
906
0
        else {
907
0
            break;
908
0
        }
909
0
        cb_data.service = service;
910
0
        cb_data.proto = proto;
911
0
        range_foreach(port_rng, add_serv_port_cb, &cb_data);
912
0
    }
913
914
0
    wmem_free (NULL, port_rng);
915
0
} /* parse_service_line */
916
917
918
static void
919
add_serv_port_cb(const uint32_t port, void *ptr)
920
0
{
921
0
    struct cb_serv_data *cb_data = (struct cb_serv_data *)ptr;
922
923
0
    if ( port ) {
924
0
        add_custom_service_name(cb_data->proto, port, cb_data->service);
925
0
    }
926
0
}
927
928
929
static bool
930
parse_services_file(const char * path)
931
84
{
932
84
    FILE *serv_p;
933
84
    char    buf[MAX_LINELEN];
934
935
    /* services hash table initialization */
936
84
    serv_p = ws_fopen(path, "r");
937
938
84
    if (serv_p == NULL)
939
84
        return false;
940
941
0
    while (fgetline(buf, sizeof(buf), serv_p) >= 0) {
942
0
        parse_service_line(buf);
943
0
    }
944
945
0
    fclose(serv_p);
946
0
    return true;
947
84
}
948
949
/* -----------------
950
 * unsigned integer to ascii
951
 */
952
static char *
953
wmem_utoa(wmem_allocator_t *allocator, unsigned port)
954
89.6k
{
955
89.6k
    char *bp = (char *)wmem_alloc(allocator, MAXNAMELEN);
956
957
    /* XXX, uint32_to_str() ? */
958
89.6k
    uint32_to_str_buf(port, bp, MAXNAMELEN);
959
89.6k
    return bp;
960
89.6k
}
961
962
static const char *
963
_serv_name_lookup(port_type proto, unsigned port)
964
0
{
965
0
    const char* name = NULL;
966
0
    ws_services_proto_t p;
967
0
    ws_services_entry_t const *serv;
968
969
0
    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
0
    if (!wmem_map_lookup_extended(serv_port_hashtable, &custom_key, NULL, (void **)&name)) {
973
        /* Try the user custom table */
974
0
        name = wmem_map_lookup(serv_port_custom_hashtable, &custom_key);
975
976
0
        if (name == NULL) {
977
            /* now look in the global tables */
978
0
            bool valid_proto = true;
979
0
            switch(proto) {
980
0
                case PT_TCP: p = ws_tcp; break;
981
0
                case PT_UDP: p = ws_udp; break;
982
0
                case PT_SCTP: p = ws_sctp; break;
983
0
                case PT_DCCP: p = ws_dccp; break;
984
0
                default: valid_proto = false;
985
0
            }
986
0
            if (valid_proto) {
987
0
                serv = global_services_lookup(port, p);
988
0
                if (serv) {
989
0
                    name = serv->name;
990
0
                }
991
0
            }
992
0
        }
993
994
        /* Cache result (even if NULL, so we can know we have no result.) */
995
0
        add_service_name(proto, port, name);
996
0
    }
997
998
0
    return name;
999
0
}
1000
1001
const char *
1002
try_serv_name_lookup(port_type proto, unsigned port)
1003
0
{
1004
0
    return (proto == PT_NONE) ? NULL : _serv_name_lookup(proto, port);
1005
0
}
1006
1007
const char *
1008
serv_name_lookup(port_type proto, unsigned port)
1009
0
{
1010
0
    const char *name;
1011
1012
    /* first look for the name */
1013
0
    name = _serv_name_lookup(proto, port);
1014
0
    if (name != NULL)
1015
0
        return name;
1016
1017
    /* No resolved name. Do we have a cached numeric string? */
1018
0
    const serv_port_key_t key = { (uint16_t)port, PT_NONE };
1019
0
    name = (const char*)wmem_map_lookup(serv_port_hashtable, &key);
1020
    /* No name; create the numeric string. */
1021
0
    if (name == NULL) {
1022
0
        name = wmem_strdup_printf(addr_resolv_scope, "%u", port);
1023
0
        add_service_name(PT_NONE, port, name);
1024
0
    }
1025
1026
0
    return name;
1027
0
}
1028
1029
static void
1030
initialize_services(const char* app_env_var_prefix)
1031
28
{
1032
28
    ws_assert(serv_port_hashtable == NULL);
1033
28
    serv_port_hashtable = wmem_map_new(addr_resolv_scope, serv_port_custom_hash, serv_port_custom_equal);
1034
28
    ws_assert(serv_port_custom_hashtable == NULL);
1035
28
    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
28
    if (g_services_path == NULL) {
1039
28
        g_services_path = get_datafile_path(ENAME_SERVICES, app_env_var_prefix);
1040
28
    }
1041
28
    parse_services_file(g_services_path);
1042
1043
    /* Compute the pathname of the personal services file */
1044
28
    if (g_pservices_path == NULL) {
1045
        /* Check profile directory before personal configuration */
1046
28
        g_pservices_path = get_persconffile_path(ENAME_SERVICES, true, app_env_var_prefix);
1047
28
        if (!parse_services_file(g_pservices_path)) {
1048
28
            g_free(g_pservices_path);
1049
28
            g_pservices_path = get_persconffile_path(ENAME_SERVICES, false, app_env_var_prefix);
1050
28
            parse_services_file(g_pservices_path);
1051
28
        }
1052
28
    }
1053
28
}
1054
1055
static void
1056
service_name_lookup_cleanup(void)
1057
14
{
1058
14
    serv_port_hashtable = NULL;
1059
14
    serv_port_custom_hashtable = NULL;
1060
14
    g_free(g_services_path);
1061
14
    g_services_path = NULL;
1062
14
    g_free(g_pservices_path);
1063
14
    g_pservices_path = NULL;
1064
14
}
1065
1066
static void
1067
parse_enterprises_line (char *line)
1068
0
{
1069
0
    char *tok, *dec_str, *org_str;
1070
0
    uint32_t dec;
1071
0
    bool had_comment = false;
1072
1073
    /* Stop the line at any comment found */
1074
0
    if ((tok = strchr(line, '#'))) {
1075
0
        *tok = '\0';
1076
0
        had_comment = true;
1077
0
    }
1078
    /* Get enterprise number */
1079
0
    dec_str = strtok(line, " \t");
1080
0
    if (!dec_str)
1081
0
        return;
1082
    /* Get enterprise name */
1083
0
    org_str = strtok(NULL, ""); /* everything else */
1084
0
    if (org_str && had_comment) {
1085
        /* Only need to strip after (between name and where comment was) */
1086
0
        org_str = g_strchomp(org_str);
1087
0
    }
1088
0
    if (!org_str)
1089
0
        return;
1090
1091
    /* Add entry using number as key */
1092
0
    if (!ws_strtou32(dec_str, NULL, &dec))
1093
0
        return;
1094
0
    g_hash_table_insert(enterprises_hashtable, GUINT_TO_POINTER(dec), g_strdup(org_str));
1095
0
}
1096
1097
1098
static bool
1099
parse_enterprises_file(const char * path)
1100
56
{
1101
56
    FILE *fp;
1102
56
    char    buf[MAX_LINELEN];
1103
1104
56
    fp = ws_fopen(path, "r");
1105
56
    if (fp == NULL)
1106
56
        return false;
1107
1108
0
    while (fgetline(buf, sizeof(buf), fp) >= 0) {
1109
0
        parse_enterprises_line(buf);
1110
0
    }
1111
1112
0
    fclose(fp);
1113
0
    return true;
1114
56
}
1115
1116
static void
1117
initialize_enterprises(const char* app_env_var_prefix)
1118
28
{
1119
28
    ws_assert(enterprises_hashtable == NULL);
1120
28
    enterprises_hashtable = g_hash_table_new_full(NULL, NULL, NULL, g_free);
1121
1122
28
    if (g_enterprises_path == NULL) {
1123
28
        g_enterprises_path = get_datafile_path(ENAME_ENTERPRISES, app_env_var_prefix);
1124
28
    }
1125
28
    parse_enterprises_file(g_enterprises_path);
1126
1127
    /* Populate entries from profile or personal */
1128
28
    if (g_penterprises_path == NULL) {
1129
        /* Check profile directory before personal configuration */
1130
28
        g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES, true, app_env_var_prefix);
1131
28
        if (!file_exists(g_penterprises_path)) {
1132
28
            g_free(g_penterprises_path);
1133
28
            g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES, false, app_env_var_prefix);
1134
28
        }
1135
28
    }
1136
    /* Parse personal file (if present) */
1137
28
    parse_enterprises_file(g_penterprises_path);
1138
28
}
1139
1140
const char *
1141
try_enterprises_lookup(uint32_t value)
1142
1.29k
{
1143
    /* Trying extra entries first. N.B. This does allow entries to be overwritten and found.. */
1144
1.29k
    const char *name = (const char *)g_hash_table_lookup(enterprises_hashtable, GUINT_TO_POINTER(value));
1145
1.29k
    if (name)
1146
0
        return name;
1147
1148
1.29k
    return val_to_str_ext_const(value, &enterprise_val_ext, "Unknown");
1149
1.29k
}
1150
1151
const char *
1152
enterprises_lookup(uint32_t value, const char *unknown_str)
1153
1.22k
{
1154
1.22k
    const char *s;
1155
1156
1.22k
    s = try_enterprises_lookup(value);
1157
1.22k
    if (s != NULL)
1158
1.22k
        return s;
1159
0
    if (unknown_str != NULL)
1160
0
        return unknown_str;
1161
0
    return "<Unknown>";
1162
0
}
1163
1164
void
1165
enterprises_base_custom(char *buf, uint32_t value)
1166
0
{
1167
0
    const char *s;
1168
1169
0
    if ((s = try_enterprises_lookup(value)) == NULL)
1170
0
        s = ITEM_LABEL_UNKNOWN_STR;
1171
0
    snprintf(buf, ITEM_LABEL_LENGTH, "%s (%u)", s, value);
1172
0
}
1173
1174
static void
1175
enterprises_cleanup(void)
1176
14
{
1177
14
    ws_assert(enterprises_hashtable);
1178
14
    g_hash_table_destroy(enterprises_hashtable);
1179
14
    enterprises_hashtable = NULL;
1180
14
    g_free(g_enterprises_path);
1181
14
    g_enterprises_path = NULL;
1182
14
    g_free(g_penterprises_path);
1183
14
    g_penterprises_path = NULL;
1184
14
}
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
1190
fill_dummy_ip4(const unsigned addr, hashipv4_t* volatile tp)
1191
82
{
1192
82
    subnet_entry_t subnet_entry;
1193
1194
    /* return value : true if addr matches any subnet */
1195
82
    bool cidr_covered = false;
1196
1197
    /* Overwrite if we get async DNS reply */
1198
1199
    /* Do we have a subnet for this address? */
1200
82
    subnet_entry = subnet_lookup(addr);
1201
82
    if (0 != subnet_entry.mask) {
1202
        /* Print name, then '.' then IP address after subnet mask */
1203
0
        uint32_t host_addr;
1204
0
        char buffer[WS_INET_ADDRSTRLEN];
1205
0
        char* paddr;
1206
0
        size_t i;
1207
1208
0
        host_addr = addr & (~subnet_entry.mask);
1209
0
        ip_addr_to_str_buf(&host_addr, buffer, WS_INET_ADDRSTRLEN);
1210
0
        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
0
        i = subnet_entry.mask_length / 8;
1218
0
        while(*(paddr) != '\0' && i > 0) {
1219
0
            if (*(++paddr) == '.') {
1220
0
                --i;
1221
0
            }
1222
0
        }
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
0
        size_t subnet_entry_name_len;
1236
0
        subnet_entry_name_len = g_strlcpy(tp->name, subnet_entry.name, MAXDNSNAMELEN);
1237
0
        if (subnet_entry_name_len < MAXDNSNAMELEN)
1238
0
                g_strlcpy(tp->name + subnet_entry_name_len, paddr, MAXDNSNAMELEN - subnet_entry_name_len);
1239
1240
        /* Evaluate the subnet in CIDR notation
1241
         * Reuse buffers built above
1242
         */
1243
0
        uint32_t subnet_addr;
1244
0
        subnet_addr = addr & subnet_entry.mask;
1245
1246
0
        char buffer_subnet[WS_INET_ADDRSTRLEN];
1247
0
        ip_addr_to_str_buf(&subnet_addr, buffer_subnet, WS_INET_ADDRSTRLEN);
1248
1249
0
        char buffer_cidr[WS_INET_CIDRADDRSTRLEN];
1250
0
        snprintf(buffer_cidr, WS_INET_CIDRADDRSTRLEN, "%s%s%u", buffer_subnet, "/", (unsigned)subnet_entry.mask_length);
1251
1252
0
        snprintf(tp->cidr_addr, WS_INET_CIDRADDRSTRLEN, "%s%s%u", buffer_subnet, "/", (unsigned)subnet_entry.mask_length);
1253
0
        cidr_covered = true;
1254
82
    } else {
1255
        /* XXX: This means we end up printing "1.2.3.4 (1.2.3.4)" in many cases */
1256
82
        ip_addr_to_str_buf(&addr, tp->name, MAXDNSNAMELEN);
1257
1258
        /* IP does not belong to any known subnet, just indicate this IP without "/.32" */
1259
82
        ip_addr_to_str_buf(&addr, tp->cidr_addr, MAXDNSNAMELEN);
1260
82
    }
1261
82
    return cidr_covered;
1262
82
}
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
1
{
1274
1
    ws_in6_addr addr;
1275
1
    memcpy(addr.bytes, tp->addr, 16);
1276
1277
    /* Overwrite if we get async DNS reply */
1278
1
    subnet_entry_v6_t subnet_entry = subnet6_lookup(&addr);
1279
1
    if (subnet_entry.mask_length != 0) {
1280
0
        ws_in6_addr host_addr;
1281
0
        for (int i = 0; i < 16; i++)
1282
0
            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
0
        size_t first_host_group = subnet_entry.mask_length / 16;
1287
0
        wmem_strbuf_t *host_strbuf = wmem_strbuf_new_sized(addr_resolv_scope,
1288
0
                                                            WS_INET6_ADDRSTRLEN);
1289
0
        for (size_t g = first_host_group; g < 8; g++) {
1290
0
            if (g > first_host_group)
1291
0
                wmem_strbuf_append_c(host_strbuf, ':');
1292
0
            uint16_t grp = ((uint16_t)host_addr.bytes[g * 2] << 8)
1293
0
                           | host_addr.bytes[g * 2 + 1];
1294
0
            wmem_strbuf_append_printf(host_strbuf, "%x", (unsigned)grp);
1295
0
        }
1296
1297
        /* Assemble name: "subnetName:host_portion" */
1298
0
        wmem_strbuf_t *name_strbuf = wmem_strbuf_new_sized(addr_resolv_scope,
1299
0
                                                            MAXDNSNAMELEN);
1300
0
        wmem_strbuf_append(name_strbuf, subnet_entry.name);
1301
0
        if (wmem_strbuf_get_len(host_strbuf) > 0) {
1302
0
            wmem_strbuf_append_c(name_strbuf, ':');
1303
0
            wmem_strbuf_append(name_strbuf, wmem_strbuf_get_str(host_strbuf));
1304
0
        }
1305
0
        g_strlcpy(tp->name, wmem_strbuf_get_str(name_strbuf), MAXDNSNAMELEN);
1306
0
        wmem_strbuf_destroy(name_strbuf);
1307
0
        wmem_strbuf_destroy(host_strbuf);
1308
1309
        /* Build CIDR notation for cidr_addr */
1310
0
        ws_in6_addr net_addr;
1311
0
        for (int i = 0; i < 16; i++)
1312
0
            net_addr.bytes[i] = addr.bytes[i] & subnet_entry.mask[i];
1313
0
        char net_buf[WS_INET6_ADDRSTRLEN];
1314
0
        ip6_to_str_buf(&net_addr, net_buf, sizeof(net_buf));
1315
0
        wmem_strbuf_t *cidr_strbuf = wmem_strbuf_new_sized(addr_resolv_scope,
1316
0
                                                            WS_INET6_CIDRADDRSTRLEN);
1317
0
        wmem_strbuf_append_printf(cidr_strbuf, "%s/%zu", net_buf,
1318
0
                                  subnet_entry.mask_length);
1319
0
        g_strlcpy(tp->cidr_addr, wmem_strbuf_get_str(cidr_strbuf),
1320
0
                  WS_INET6_CIDRADDRSTRLEN);
1321
0
        wmem_strbuf_destroy(cidr_strbuf);
1322
1
    } else {
1323
1
        (void)g_strlcpy(tp->name, tp->ip6, MAXDNSNAMELEN);
1324
1
        (void)g_strlcpy(tp->cidr_addr, tp->ip6, WS_INET6_CIDRADDRSTRLEN);
1325
1
    }
1326
1
}
1327
1328
static void
1329
0
c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
1330
0
    async_dns_queue_msg_t *caqm = (async_dns_queue_msg_t *)arg;
1331
0
    char **p;
1332
1333
0
    if (!caqm) return;
1334
    /* XXX, what to do if async_dns_in_flight == 0? */
1335
0
    async_dns_in_flight--;
1336
1337
0
    if (status == ARES_SUCCESS) {
1338
0
        for (p = he->h_addr_list; *p != NULL; p++) {
1339
0
            switch(caqm->family) {
1340
0
                case AF_INET:
1341
0
                    add_ipv4_name(caqm->addr.ip4, he->h_name, false);
1342
0
                    break;
1343
0
                case AF_INET6:
1344
0
                    add_ipv6_name(&caqm->addr.ip6, he->h_name, false);
1345
0
                    break;
1346
0
                default:
1347
                    /* Throw an exception? */
1348
0
                    break;
1349
0
            }
1350
0
        }
1351
0
    }
1352
0
    wmem_free(addr_resolv_scope, caqm);
1353
0
}
1354
1355
/* --------------- */
1356
hashipv4_t *
1357
new_ipv4(const unsigned addr)
1358
143
{
1359
143
    hashipv4_t *tp = wmem_new(addr_resolv_scope, hashipv4_t);
1360
143
    tp->addr = addr;
1361
143
    tp->flags = 0;
1362
143
    tp->name[0] = '\0';
1363
143
    ip_addr_to_str_buf(&addr, tp->ip, sizeof(tp->ip));
1364
143
    return tp;
1365
143
}
1366
1367
static hashipv4_t *
1368
host_lookup(const unsigned addr)
1369
135
{
1370
135
    hashipv4_t * volatile tp;
1371
1372
135
    tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
1373
135
    if (tp == NULL) {
1374
        /*
1375
         * We don't already have an entry for this host name; create one,
1376
         * and then try to resolve it.
1377
         */
1378
82
        tp = new_ipv4(addr);
1379
82
        fill_dummy_ip4(addr, tp);
1380
82
        wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
1381
82
    } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
1382
0
        return tp;
1383
0
    }
1384
1385
    /*
1386
     * This hasn't been resolved yet, and we haven't tried to
1387
     * resolve it already.
1388
     */
1389
1390
135
    if (!gbl_resolv_flags.network_name)
1391
135
        return tp;
1392
1393
0
    if (gbl_resolv_flags.use_external_net_name_resolver) {
1394
0
        tp->flags |= TRIED_RESOLVE_ADDRESS;
1395
1396
0
        if (async_dns_initialized) {
1397
            /* c-ares is initialized, so we can use it */
1398
0
            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
0
                sync_lookup_ip4(addr);
1405
0
            } 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
0
                async_dns_queue_msg_t *caqm;
1412
1413
0
                caqm = wmem_new(addr_resolv_scope, async_dns_queue_msg_t);
1414
0
                caqm->family = AF_INET;
1415
0
                caqm->addr.ip4 = addr;
1416
0
                wmem_list_append(async_dns_queue_head, (void *) caqm);
1417
0
            }
1418
0
        }
1419
0
    }
1420
1421
0
    return tp;
1422
1423
135
} /* host_lookup */
1424
1425
/* --------------- */
1426
static hashipv6_t *
1427
new_ipv6(const ws_in6_addr *addr)
1428
194
{
1429
194
    hashipv6_t *tp = wmem_new(addr_resolv_scope, hashipv6_t);
1430
194
    memcpy(tp->addr, addr->bytes, sizeof tp->addr);
1431
194
    tp->flags = 0;
1432
194
    tp->name[0] = '\0';
1433
194
    ip6_to_str_buf(addr, tp->ip6, sizeof(tp->ip6));
1434
194
    return tp;
1435
194
}
1436
1437
/* ------------------------------------ */
1438
static hashipv6_t *
1439
host_lookup6(const ws_in6_addr *addr)
1440
1
{
1441
1
    hashipv6_t * volatile tp;
1442
1443
1
    tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addr);
1444
1
    if (tp == NULL) {
1445
        /*
1446
         * We don't already have an entry for this host name; create one,
1447
         * and then try to resolve it.
1448
         */
1449
1
        ws_in6_addr *addr_key;
1450
1451
1
        addr_key = wmem_new(addr_resolv_scope, ws_in6_addr);
1452
1
        tp = new_ipv6(addr);
1453
1
        memcpy(addr_key, addr, 16);
1454
1
        fill_dummy_ip6(tp);
1455
1
        wmem_map_insert(ipv6_hash_table, addr_key, tp);
1456
1
    } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
1457
0
        return tp;
1458
0
    }
1459
1460
    /*
1461
     * This hasn't been resolved yet, and we haven't tried to
1462
     * resolve it already.
1463
     */
1464
1465
1
    if (!gbl_resolv_flags.network_name)
1466
1
        return tp;
1467
1468
0
    if (gbl_resolv_flags.use_external_net_name_resolver) {
1469
0
        tp->flags |= TRIED_RESOLVE_ADDRESS;
1470
1471
0
        if (async_dns_initialized) {
1472
            /* c-ares is initialized, so we can use it */
1473
0
            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
0
                sync_lookup_ip6(addr);
1480
0
            } 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
0
                async_dns_queue_msg_t *caqm;
1487
1488
0
                caqm = wmem_new(addr_resolv_scope, async_dns_queue_msg_t);
1489
0
                caqm->family = AF_INET6;
1490
0
                memcpy(&caqm->addr.ip6, addr, sizeof(caqm->addr.ip6));
1491
0
                wmem_list_append(async_dns_queue_head, (void *) caqm);
1492
0
            }
1493
0
        }
1494
0
    }
1495
1496
0
    return tp;
1497
1498
1
} /* 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
1531
parse_ether_address_fast(const unsigned char *cp, ether_t *eth, unsigned int *mask,
1532
        const bool accept_mask)
1533
0
{
1534
    /* XXX copied from strutil.c */
1535
    /* a map from ASCII hex chars to their value */
1536
0
    static const int8_t str_to_nibble[256] = {
1537
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1538
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1539
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1540
0
         0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
1541
0
        -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1542
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1543
0
        -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1544
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1545
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1546
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1547
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1548
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1549
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1550
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1551
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
1552
0
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1553
0
    };
1554
0
    const uint8_t *str_to_nibble_usg = (const uint8_t *)str_to_nibble;
1555
1556
0
    unsigned char sep = cp[2];
1557
0
    if ((sep != ':' && sep != '-') || cp[5] != sep) {
1558
        /* Unexpected separators. */
1559
0
        return false;
1560
0
    }
1561
1562
    /* N.B. store octet values in an int to detect invalid (-1) entries */
1563
0
    int num0 = (str_to_nibble_usg[cp[0]] << 4) | (int8_t)str_to_nibble_usg[cp[1]];
1564
0
    int num1 = (str_to_nibble_usg[cp[3]] << 4) | (int8_t)str_to_nibble_usg[cp[4]];
1565
0
    int num2 = (str_to_nibble_usg[cp[6]] << 4) | (int8_t)str_to_nibble_usg[cp[7]];
1566
1567
0
    if ((num0 | num1 | num2) & 0x100) {
1568
        /* Not hexadecimal numbers. */
1569
0
        return false;
1570
0
    }
1571
1572
0
    eth->addr[0] = (uint8_t)num0;
1573
0
    eth->addr[1] = (uint8_t)num1;
1574
0
    eth->addr[2] = (uint8_t)num2;
1575
1576
0
    if (cp[8] == '\0' && accept_mask) {
1577
        /* Indicate that this is a manufacturer ID (0 is not allowed as a mask). */
1578
0
        *mask = 0;
1579
0
        return true;
1580
0
    } else if (cp[8] != sep || !accept_mask) {
1581
        /* Format not handled by this fast path. */
1582
0
        return false;
1583
0
    }
1584
1585
    /* N.B. store octet values in an int to detect invalid (-1) entries */
1586
0
    int num3 = (str_to_nibble_usg[cp[9]]  << 4) | (int8_t)str_to_nibble_usg[cp[10]];
1587
0
    int num4 = (str_to_nibble_usg[cp[12]] << 4) | (int8_t)str_to_nibble_usg[cp[13]];
1588
0
    int num5 = (str_to_nibble_usg[cp[15]] << 4) | (int8_t)str_to_nibble_usg[cp[16]];
1589
1590
0
    if (((num3 | num4 | num5) & 0x100) || cp[11] != sep || cp[14] != sep)  {
1591
        /* Not hexadecimal numbers or invalid separators. */
1592
0
        return false;
1593
0
    }
1594
1595
0
    eth->addr[3] = (uint8_t)num3;
1596
0
    eth->addr[4] = (uint8_t)num4;
1597
0
    eth->addr[5] = (uint8_t)num5;
1598
0
    if (cp[17] == '\0') {
1599
        /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1600
0
        *mask = 48;
1601
0
        return true;
1602
0
    } else if (cp[17] != '/' || cp[20] != '\0') {
1603
        /* Format not handled by this fast path. */
1604
0
        return false;
1605
0
    }
1606
1607
0
    int m1 = cp[18];
1608
0
    int m2 = cp[19];
1609
0
    if (m1 == '3' && m2 == '6') {   /* Mask /36 */
1610
0
        eth->addr[4] &= 0xf0;
1611
0
        eth->addr[5] = 0;
1612
0
        *mask = 36;
1613
0
        return true;
1614
0
    }
1615
0
    if (m1 == '2' && m2 == '8') {   /* Mask /28 */
1616
0
        eth->addr[3] &= 0xf0;
1617
0
        eth->addr[4] = 0;
1618
0
        eth->addr[5] = 0;
1619
0
        *mask = 28;
1620
0
        return true;
1621
0
    }
1622
    /* Unsupported mask */
1623
0
    return false;
1624
0
}
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
1633
parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
1634
        const bool accept_mask)
1635
0
{
1636
0
    int i;
1637
0
    unsigned long num;
1638
0
    char *p;
1639
0
    char sep = '\0';
1640
1641
0
    for (i = 0; i < EUI64_ADDR_LEN; i++) {
1642
        /* Get a hex number, 1 or 2 digits, no sign characters allowed. */
1643
0
        if (!g_ascii_isxdigit(*cp))
1644
0
            return false;
1645
0
        num = strtoul(cp, &p, 16);
1646
0
        if (p == cp)
1647
0
            return false; /* failed */
1648
0
        if (num > 0xFF)
1649
0
            return false; /* not a valid octet */
1650
0
        eth->addr[i] = (uint8_t) num;
1651
0
        cp = p;     /* skip past the number */
1652
1653
        /* OK, what character terminated the octet? */
1654
0
        if (*cp == '/') {
1655
            /* "/" - this has a mask. */
1656
0
            if (!accept_mask) {
1657
                /* Entries with masks are not allowed in this file. */
1658
0
                return false;
1659
0
            }
1660
0
            cp++; /* skip past the '/' to get to the mask */
1661
0
            if (!g_ascii_isdigit(*cp))
1662
0
                return false;   /* no sign allowed */
1663
0
            num = strtoul(cp, &p, 10);
1664
0
            if (p == cp)
1665
0
                return false;   /* failed */
1666
0
            cp = p;   /* skip past the number */
1667
0
            if (*cp != '\0' && !g_ascii_isspace(*cp))
1668
0
                return false;   /* bogus terminator */
1669
0
            if (num == 0 || num >= 48)
1670
0
                return false;   /* bogus mask */
1671
            /* Mask out the bits not covered by the mask */
1672
0
            *mask = (int)num;
1673
0
            for (i = 0; num >= 8; i++, num -= 8)
1674
0
                ;   /* skip octets entirely covered by the mask */
1675
            /* Mask out the first masked octet */
1676
0
            eth->addr[i] &= (0xFF << (8 - num));
1677
0
            i++;
1678
            /* Mask out completely-masked-out octets */
1679
0
            for (; i < 6; i++)
1680
0
                eth->addr[i] = 0;
1681
0
            return true;
1682
0
        }
1683
0
        if (*cp == '\0') {
1684
            /* We're at the end of the address, and there's no mask. */
1685
0
            if (i == 2) {
1686
                /* We got 3 bytes, so this is a manufacturer ID. */
1687
0
                if (!accept_mask) {
1688
                    /* Manufacturer IDs are not allowed in this file */
1689
0
                    return false;
1690
0
                }
1691
                /* Indicate that this is a manufacturer ID (0 is not allowed
1692
                   as a mask). */
1693
0
                *mask = 0;
1694
0
                return true;
1695
0
            }
1696
1697
0
            if (i == 5) {
1698
                /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
1699
0
                if (mask) {
1700
0
                    *mask = 48;
1701
0
                }
1702
0
                return true;
1703
0
            }
1704
1705
0
            if (i == 7) {
1706
                /* We got 8 bytes, so this is a EUI-64 address (64 is not allowed as a mask). */
1707
0
                if (mask) {
1708
0
                    *mask = 64;
1709
0
                }
1710
0
                return true;
1711
0
            }
1712
1713
            /* We didn't get 3 or 6 or 8 bytes, and there's no mask; this is
1714
               illegal. */
1715
0
            return false;
1716
0
        } else {
1717
0
            if (sep == '\0') {
1718
                /* We don't know the separator used in this number; it can either
1719
                   be ':', '-', or '.'. */
1720
0
                if (*cp != ':' && *cp != '-' && *cp != '.')
1721
0
                    return false;
1722
0
                sep = *cp;  /* subsequent separators must be the same */
1723
0
            } else {
1724
                /* It has to be the same as the first separator */
1725
0
                if (*cp != sep)
1726
0
                    return false;
1727
0
            }
1728
0
        }
1729
0
        cp++;
1730
0
    }
1731
1732
0
    return true;
1733
0
}
1734
1735
static int
1736
parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
1737
        const bool accept_mask)
1738
0
{
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
0
    char *cp;
1747
1748
0
    line = g_strstrip(line);
1749
0
    if (line[0] == '\0' || line[0] == '#')
1750
0
        return -1;
1751
1752
0
    if ((cp = strchr(line, '#'))) {
1753
0
        *cp = '\0';
1754
0
        g_strchomp(line);
1755
0
    }
1756
1757
0
    if ((cp = strtok(line, " \t")) == NULL)
1758
0
        return -1;
1759
1760
    /* First try to match the common format for the large ethers file. */
1761
0
    if (!parse_ether_address_fast((const uint8_t*)cp, eth, mask, accept_mask)) {
1762
        /* Fallback for the well-known addresses (wka) file. */
1763
0
        if (!parse_ether_address(cp, eth, mask, accept_mask))
1764
0
            return -1;
1765
0
    }
1766
1767
0
    if ((cp = strtok(NULL, " \t")) == NULL)
1768
0
        return -1;
1769
1770
0
    (void) g_strlcpy(eth->name, cp, MAXNAMELEN);
1771
1772
0
    if ((cp = strtok(NULL, "\t")) != NULL)
1773
0
    {
1774
0
        (void) g_strlcpy(eth->longname, cp, MAXNAMELEN);
1775
0
    } else {
1776
        /* Make the long name the short name */
1777
0
        (void) g_strlcpy(eth->longname, eth->name, MAXNAMELEN);
1778
0
    }
1779
1780
0
    return 0;
1781
1782
0
} /* parse_ether_line */
1783
1784
static FILE *eth_p;
1785
1786
static void
1787
set_ethent(char *path)
1788
56
{
1789
56
    if (eth_p)
1790
0
        rewind(eth_p);
1791
56
    else
1792
56
        eth_p = ws_fopen(path, "r");
1793
56
}
1794
1795
static void
1796
end_ethent(void)
1797
56
{
1798
56
    if (eth_p) {
1799
0
        fclose(eth_p);
1800
0
        eth_p = NULL;
1801
0
    }
1802
56
}
1803
1804
static ether_t *
1805
get_ethent(unsigned int *mask, const bool accept_mask)
1806
56
{
1807
1808
56
    static ether_t eth;
1809
56
    char    buf[MAX_LINELEN];
1810
1811
56
    if (eth_p == NULL)
1812
56
        return NULL;
1813
1814
0
    while (fgetline(buf, sizeof(buf), eth_p) >= 0) {
1815
0
        if (parse_ether_line(buf, &eth, mask, accept_mask) == 0) {
1816
0
            return &eth;
1817
0
        }
1818
0
    }
1819
1820
0
    return NULL;
1821
1822
0
} /* get_ethent */
1823
1824
static hashmanuf_t *
1825
manuf_hash_new_entry(const uint8_t *addr, const char* name, const char* longname)
1826
8.26k
{
1827
8.26k
    unsigned manuf_key;
1828
8.26k
    hashmanuf_t *manuf_value;
1829
8.26k
    char *endp;
1830
8.26k
    size_t attempted_size;
1831
1832
    /* manuf needs only the 3 most significant octets of the ethernet address */
1833
8.26k
    manuf_key = (addr[0] << 16) + (addr[1] << 8) + addr[2];
1834
8.26k
    manuf_value = wmem_new(addr_resolv_scope, hashmanuf_t);
1835
1836
8.26k
    memcpy(manuf_value->addr, addr, 3);
1837
8.26k
    if (name != NULL) {
1838
1.03k
        (void) g_strlcpy(manuf_value->resolved_name, name, MAXNAMELEN);
1839
1.03k
        manuf_value->flags = NAME_RESOLVED;
1840
1.03k
        if (longname != NULL) {
1841
1.03k
            attempted_size = g_strlcpy(manuf_value->resolved_longname, longname, MAXNAMELEN);
1842
1.03k
            if (attempted_size >= MAXNAMELEN) {
1843
1
                ws_utf8_truncate(manuf_value->resolved_longname, MAXNAMELEN - 1);
1844
1
            }
1845
1.03k
        }
1846
0
        else {
1847
0
            (void) g_strlcpy(manuf_value->resolved_longname, name, MAXNAMELEN);
1848
0
        }
1849
1.03k
    }
1850
7.23k
    else {
1851
7.23k
        manuf_value->flags = 0;
1852
7.23k
        manuf_value->resolved_name[0] = '\0';
1853
7.23k
        manuf_value->resolved_longname[0] = '\0';
1854
7.23k
    }
1855
    /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
1856
8.26k
    endp = bytes_to_hexstr_punct(manuf_value->hexaddr, addr, sizeof(manuf_value->addr), ':');
1857
8.26k
    *endp = '\0';
1858
1859
8.26k
    wmem_map_insert(manuf_hashtable, GUINT_TO_POINTER(manuf_key), manuf_value);
1860
8.26k
    return manuf_value;
1861
8.26k
}
1862
1863
static hashwka_t*
1864
wka_hash_new_entry(const uint8_t *addr, char* name)
1865
0
{
1866
0
    uint8_t *wka_key;
1867
0
    hashwka_t *wka_value;
1868
1869
0
    wka_key = (uint8_t *)wmem_alloc(addr_resolv_scope, 6);
1870
0
    memcpy(wka_key, addr, 6);
1871
1872
0
    wka_value = (hashwka_t*)wmem_new(addr_resolv_scope, hashwka_t);
1873
0
    wka_value->flags = NAME_RESOLVED;
1874
0
    wka_value->name = wmem_strdup(addr_resolv_scope, name);
1875
1876
0
    wmem_map_insert(wka_hashtable, wka_key, wka_value);
1877
0
    return wka_value;
1878
0
}
1879
1880
static void
1881
add_manuf_name(const uint8_t *addr, unsigned int mask, char *name, char *longname)
1882
0
{
1883
0
    switch (mask)
1884
0
    {
1885
0
    case 0:
1886
0
        {
1887
        /* This is a manufacturer ID; add it to the manufacturer ID hash table */
1888
0
        hashmanuf_t *entry = manuf_hash_new_entry(addr, name, longname);
1889
0
        entry->flags |= STATIC_HOSTNAME;
1890
0
        break;
1891
0
        }
1892
0
    case 48:
1893
0
        {
1894
        /* This is a well-known MAC address; add it to the Ethernet hash table */
1895
0
        add_eth_name(addr, name, true);
1896
0
        break;
1897
0
        }
1898
0
    default:
1899
0
        {
1900
        /* This is a range of well-known addresses; add it to the well-known-address table */
1901
0
        hashwka_t *entry = wka_hash_new_entry(addr, name);
1902
0
        entry->flags |= STATIC_HOSTNAME;
1903
0
        break;
1904
0
        }
1905
0
    }
1906
0
} /* 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_)
1924
67.8k
{
1925
67.8k
    uint32_t      manuf_key;
1926
67.8k
    uint8_t      oct;
1927
67.8k
    hashmanuf_t  *manuf_value;
1928
1929
67.8k
    ws_return_val_if(size < 3, NULL);
1930
1931
    /* manuf needs only the 3 most significant octets of the ethernet address */
1932
67.8k
    manuf_key = addr[0];
1933
67.8k
    manuf_key = manuf_key<<8;
1934
67.8k
    oct = addr[1];
1935
67.8k
    manuf_key = manuf_key | oct;
1936
67.8k
    manuf_key = manuf_key<<8;
1937
67.8k
    oct = addr[2];
1938
67.8k
    manuf_key = manuf_key | oct;
1939
1940
1941
    /* first try to find a "perfect match" */
1942
67.8k
    manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, GUINT_TO_POINTER(manuf_key));
1943
67.8k
    if (manuf_value != NULL) {
1944
58.0k
        manuf_value->flags |= TRIED_RESOLVE_ADDRESS;
1945
58.0k
        return manuf_value;
1946
58.0k
    }
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
9.72k
    if ((manuf_key & 0x00010000) != 0) {
1954
4.96k
        manuf_key &= 0x00FEFFFF;
1955
4.96k
        manuf_value = (hashmanuf_t*)wmem_map_lookup(manuf_hashtable, GUINT_TO_POINTER(manuf_key));
1956
4.96k
        if (manuf_value != NULL) {
1957
1.46k
            manuf_value->flags |= TRIED_RESOLVE_ADDRESS;
1958
1.46k
            return manuf_value;
1959
1.46k
        }
1960
4.96k
    }
1961
1962
    /* Try the global manuf tables. */
1963
8.26k
    const char *short_name, *long_name;
1964
    /* We can't insert a 28 or 36 bit entry into the used hash table. */
1965
8.26k
    short_name = ws_manuf_lookup_oui24(addr, &long_name);
1966
8.26k
    if (short_name != NULL) {
1967
        /* Found it */
1968
1.03k
        manuf_value = manuf_hash_new_entry(addr, short_name, long_name);
1969
7.23k
    } else {
1970
        /* Add the address as a hex string */
1971
7.23k
        manuf_value = manuf_hash_new_entry(addr, NULL, NULL);
1972
7.23k
    }
1973
1974
8.26k
    manuf_value->flags |= TRIED_RESOLVE_ADDRESS;
1975
8.26k
    return manuf_value;
1976
1977
9.72k
} /* manuf_name_lookup */
1978
1979
static char *
1980
wka_name_lookup(const uint8_t *addr, const unsigned int mask)
1981
477k
{
1982
477k
    uint8_t    masked_addr[6];
1983
477k
    unsigned   num;
1984
477k
    int        i;
1985
477k
    hashwka_t *value;
1986
1987
477k
    if (wka_hashtable == NULL) {
1988
0
        return NULL;
1989
0
    }
1990
    /* Get the part of the address covered by the mask. */
1991
1.78M
    for (i = 0, num = mask; num >= 8; i++, num -= 8)
1992
1.30M
        masked_addr[i] = addr[i];   /* copy octets entirely covered by the mask */
1993
    /* Mask out the first masked octet */
1994
477k
    masked_addr[i] = addr[i] & (0xFF << (8 - num));
1995
477k
    i++;
1996
    /* Zero out completely-masked-out octets */
1997
1.56M
    for (; i < 6; i++)
1998
1.08M
        masked_addr[i] = 0;
1999
2000
477k
    value = (hashwka_t*)wmem_map_lookup(wka_hashtable, masked_addr);
2001
2002
477k
    if (value) {
2003
0
        value->flags |= TRIED_RESOLVE_ADDRESS;
2004
0
        return value->name;
2005
0
    }
2006
2007
477k
    return NULL;
2008
2009
477k
} /* wka_name_lookup */
2010
2011
unsigned get_hash_ether_status(hashether_t* ether)
2012
0
{
2013
0
    return ether->flags;
2014
0
}
2015
2016
bool get_hash_ether_used(hashether_t* ether)
2017
0
{
2018
0
    return ((ether->flags & TRIED_OR_RESOLVED_MASK) == TRIED_OR_RESOLVED_MASK);
2019
0
}
2020
2021
char* get_hash_ether_hexaddr(hashether_t* ether)
2022
0
{
2023
0
    return ether->hexaddr;
2024
0
}
2025
2026
char* get_hash_ether_resolved_name(hashether_t* ether)
2027
0
{
2028
0
    return ether->resolved_name;
2029
0
}
2030
2031
bool get_hash_wka_used(hashwka_t* wka)
2032
0
{
2033
0
    return ((wka->flags & TRIED_OR_RESOLVED_MASK) == TRIED_OR_RESOLVED_MASK);
2034
0
}
2035
2036
char* get_hash_wka_resolved_name(hashwka_t* wka)
2037
0
{
2038
0
    return wka->name;
2039
0
}
2040
2041
static unsigned
2042
eth_addr_hash(const void *key)
2043
84.7k
{
2044
84.7k
    return wmem_strong_hash((const uint8_t *)key, 6);
2045
84.7k
}
2046
2047
static gboolean
2048
eth_addr_cmp(const void *a, const void *b)
2049
62.0k
{
2050
62.0k
    return (memcmp(a, b, 6) == 0);
2051
62.0k
}
2052
2053
static unsigned
2054
eui64_addr_hash(const void *key)
2055
4.14k
{
2056
4.14k
    return wmem_strong_hash((const uint8_t *)key, EUI64_ADDR_LEN);
2057
4.14k
}
2058
2059
static gboolean
2060
eui64_addr_cmp(const void *a, const void *b)
2061
2.42k
{
2062
2.42k
    return (memcmp(a, b, EUI64_ADDR_LEN) == 0);
2063
2.42k
}
2064
2065
static void
2066
initialize_ethers(const char* app_env_var_prefix)
2067
28
{
2068
28
    ether_t *eth;
2069
28
    unsigned mask = 0;
2070
2071
    /* hash table initialization */
2072
28
    ws_assert(wka_hashtable == NULL);
2073
28
    wka_hashtable   = wmem_map_new(addr_resolv_scope, eth_addr_hash, eth_addr_cmp);
2074
28
    ws_assert(manuf_hashtable == NULL);
2075
28
    manuf_hashtable = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
2076
28
    ws_assert(eth_hashtable == NULL);
2077
28
    eth_hashtable   = wmem_map_new(addr_resolv_scope, eth_addr_hash, eth_addr_cmp);
2078
28
    ws_assert(eui64_hashtable == NULL);
2079
28
    eui64_hashtable = wmem_map_new(addr_resolv_scope, eui64_addr_hash, eui64_addr_cmp);
2080
2081
    /* Compute the pathname of the ethers file. */
2082
28
    if (g_ethers_path == NULL) {
2083
28
        g_ethers_path = g_build_filename(get_systemfile_dir(app_env_var_prefix), ENAME_ETHERS, NULL);
2084
28
    }
2085
2086
    /* Compute the pathname of the personal ethers file. */
2087
28
    if (g_pethers_path == NULL) {
2088
        /* Check profile directory before personal configuration */
2089
28
        g_pethers_path = get_persconffile_path(ENAME_ETHERS, true, app_env_var_prefix);
2090
28
        if (!file_exists(g_pethers_path)) {
2091
28
            g_free(g_pethers_path);
2092
28
            g_pethers_path = get_persconffile_path(ENAME_ETHERS, false, app_env_var_prefix);
2093
28
        }
2094
28
    }
2095
2096
    /* Compute the pathname of the global manuf file */
2097
28
    if (g_manuf_path == NULL)
2098
28
        g_manuf_path = get_datafile_path(ENAME_MANUF, app_env_var_prefix);
2099
    /* Read it and initialize the hash table */
2100
28
    if (file_exists(g_manuf_path)) {
2101
0
        set_ethent(g_manuf_path);
2102
0
        while ((eth = get_ethent(&mask, true))) {
2103
0
            add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2104
0
        }
2105
0
        end_ethent();
2106
0
    }
2107
2108
    /* Compute the pathname of the personal manuf file */
2109
28
    if (g_pmanuf_path == NULL) {
2110
        /* Check profile directory before personal configuration */
2111
28
        g_pmanuf_path = get_persconffile_path(ENAME_MANUF, true, app_env_var_prefix);
2112
28
        if (!file_exists(g_pmanuf_path)) {
2113
28
            g_free(g_pmanuf_path);
2114
28
            g_pmanuf_path = get_persconffile_path(ENAME_MANUF, false, app_env_var_prefix);
2115
28
        }
2116
28
    }
2117
    /* Read it and initialize the hash table */
2118
28
    if (file_exists(g_pmanuf_path)) {
2119
0
        set_ethent(g_pmanuf_path);
2120
0
        while ((eth = get_ethent(&mask, true))) {
2121
0
            add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2122
0
        }
2123
0
        end_ethent();
2124
0
    }
2125
2126
    /* Compute the pathname of the wka file */
2127
28
    if (g_wka_path == NULL)
2128
28
        g_wka_path = get_datafile_path(ENAME_WKA, app_env_var_prefix);
2129
2130
    /* Read it and initialize the hash table */
2131
28
    set_ethent(g_wka_path);
2132
28
    while ((eth = get_ethent(&mask, true))) {
2133
0
        add_manuf_name(eth->addr, mask, eth->name, eth->longname);
2134
0
    }
2135
28
    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
28
    set_ethent(g_ethers_path);
2147
28
    while ((eth = get_ethent(&mask, false))) {
2148
0
        if (mask == 48) {
2149
0
            add_eth_name(eth->addr, eth->name, true);
2150
0
        } else if (mask == 64) {
2151
0
            add_eui64_name(eth->addr, eth->name, true);
2152
0
        }
2153
0
    }
2154
28
    end_ethent();
2155
2156
28
    if (file_exists(g_pethers_path)) {
2157
0
        set_ethent(g_pethers_path);
2158
0
        while ((eth = get_ethent(&mask, false))) {
2159
0
            if (mask == 48) {
2160
0
                add_eth_name(eth->addr, eth->name, true);
2161
0
            } else if (mask == 64) {
2162
0
                add_eui64_name(eth->addr, eth->name, true);
2163
0
            }
2164
0
        }
2165
0
        end_ethent();
2166
0
    }
2167
2168
28
} /* initialize_ethers */
2169
2170
static void
2171
ethers_cleanup(void)
2172
14
{
2173
14
    wka_hashtable = NULL;
2174
14
    manuf_hashtable = NULL;
2175
14
    eth_hashtable = NULL;
2176
14
    eui64_hashtable = NULL;
2177
14
    g_free(g_ethers_path);
2178
14
    g_ethers_path = NULL;
2179
14
    g_free(g_pethers_path);
2180
14
    g_pethers_path = NULL;
2181
14
    g_free(g_manuf_path);
2182
14
    g_manuf_path = NULL;
2183
14
    g_free(g_pmanuf_path);
2184
14
    g_pmanuf_path = NULL;
2185
14
    g_free(g_wka_path);
2186
14
    g_wka_path = NULL;
2187
14
}
2188
2189
static void
2190
eth_resolved_name_fill(hashether_t *tp, const char *name, unsigned mask, const uint8_t *addr)
2191
142
{
2192
142
    switch (mask) {
2193
0
        case 24:
2194
0
            snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
2195
0
                    name, addr[3], addr[4], addr[5]);
2196
0
            break;
2197
131
        case 28:
2198
131
            snprintf(tp->resolved_name, MAXNAMELEN, "%s_%01x:%02x:%02x",
2199
131
                    name, addr[3] & 0x0F, addr[4], addr[5]);
2200
131
            break;
2201
11
        case 36:
2202
11
            snprintf(tp->resolved_name, MAXNAMELEN, "%s_%01x:%02x",
2203
11
                    name, addr[4] & 0x0F, addr[5]);
2204
11
            break;
2205
0
        default: // Future-proof generic algorithm
2206
0
        {
2207
0
            unsigned bytes = mask / 8;
2208
0
            unsigned bitmask = mask % 8;
2209
2210
0
            int pos = snprintf(tp->resolved_name, MAXNAMELEN, "%s", name);
2211
0
            if (pos >= MAXNAMELEN) return;
2212
2213
0
            if (bytes < 6) {
2214
0
                pos += snprintf(tp->resolved_name + pos, MAXNAMELEN - pos,
2215
0
                    bitmask >= 4 ? "_%01x" : "_%02x",
2216
0
                    addr[bytes] & (0xFF >> bitmask));
2217
0
                bytes++;
2218
0
            }
2219
2220
0
            while (bytes < 6) {
2221
0
                if (pos >= MAXNAMELEN) return;
2222
0
                pos += snprintf(tp->resolved_name + pos, MAXNAMELEN - pos, ":%02x",
2223
0
                    addr[bytes]);
2224
0
                bytes++;
2225
0
            }
2226
0
        }
2227
142
    }
2228
142
}
2229
2230
/* Resolve ethernet address */
2231
static hashether_t *
2232
11.3k
eth_addr_resolve(hashether_t *tp) {
2233
11.3k
    hashmanuf_t *manuf_value;
2234
11.3k
    const uint8_t *addr = tp->addr;
2235
11.3k
    size_t addr_size = sizeof(tp->addr);
2236
2237
11.3k
    if (!(tp->flags & NAME_RESOLVED)) {
2238
11.3k
        unsigned      mask;
2239
11.3k
        char         *name;
2240
11.3k
        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
11.3k
        mask = 7;
2245
90.6k
        do {
2246
            /* Only the topmost 5 bytes participate fully */
2247
90.6k
            if ((name = wka_name_lookup(addr, mask+40)) != NULL) {
2248
0
                snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x",
2249
0
                        name, addr[5] & (0xFF >> mask));
2250
0
                tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2251
0
                return tp;
2252
0
            }
2253
90.6k
        } while (mask--);
2254
2255
11.3k
        mask = 7;
2256
90.6k
        do {
2257
            /* Only the topmost 4 bytes participate fully */
2258
90.6k
            if ((name = wka_name_lookup(addr, mask+32)) != NULL) {
2259
0
                snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x",
2260
0
                        name, addr[4] & (0xFF >> mask), addr[5]);
2261
0
                tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2262
0
                return tp;
2263
0
            }
2264
90.6k
        } while (mask--);
2265
2266
11.3k
        mask = 7;
2267
90.6k
        do {
2268
            /* Only the topmost 3 bytes participate fully */
2269
90.6k
            if ((name = wka_name_lookup(addr, mask+24)) != NULL) {
2270
0
                snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
2271
0
                        name, addr[3] & (0xFF >> mask), addr[4], addr[5]);
2272
0
                tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2273
0
                return tp;
2274
0
            }
2275
90.6k
        } while (mask--);
2276
2277
        /* Now try looking in the manufacturer table. */
2278
11.3k
        manuf_value = manuf_name_lookup(addr, addr_size);
2279
11.3k
        if ((manuf_value != NULL) && ((manuf_value->flags & NAME_RESOLVED) == NAME_RESOLVED)) {
2280
2.38k
            snprintf(tp->resolved_name, MAXNAMELEN, "%.*s_%02x:%02x:%02x",
2281
2.38k
                    MAXNAMELEN - 10, manuf_value->resolved_name, addr[3], addr[4], addr[5]);
2282
2.38k
            tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2283
2.38k
            return tp;
2284
2.38k
        }
2285
2286
        /* Now try looking for it in the well-known-address
2287
           tables for well-known address ranges larger than 2^24. */
2288
8.95k
        mask = 7;
2289
71.6k
        do {
2290
            /* Only the topmost 2 bytes participate fully */
2291
71.6k
            if ((name = wka_name_lookup(addr, mask+16)) != NULL) {
2292
0
                snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x",
2293
0
                        name, addr[2] & (0xFF >> mask), addr[3], addr[4],
2294
0
                        addr[5]);
2295
0
                tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2296
0
                return tp;
2297
0
            }
2298
71.6k
        } while (mask--);
2299
2300
8.95k
        mask = 7;
2301
71.6k
        do {
2302
            /* Only the topmost byte participates fully */
2303
71.6k
            if ((name = wka_name_lookup(addr, mask+8)) != NULL) {
2304
0
                snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
2305
0
                        name, addr[1] & (0xFF >> mask), addr[2], addr[3],
2306
0
                        addr[4], addr[5]);
2307
0
                tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2308
0
                return tp;
2309
0
            }
2310
71.6k
        } while (mask--);
2311
2312
8.95k
        mask = 7;
2313
62.6k
        do {
2314
            /* Not even the topmost byte participates fully */
2315
62.6k
            if ((name = wka_name_lookup(addr, mask)) != NULL) {
2316
0
                snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
2317
0
                        name, addr[0] & (0xFF >> mask), addr[1], addr[2],
2318
0
                        addr[3], addr[4], addr[5]);
2319
0
                tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2320
0
                return tp;
2321
0
            }
2322
62.6k
        } 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
8.95k
        const char *short_name, *long_name;
2329
8.95k
        short_name = ws_manuf_lookup(addr, &long_name, &mask);
2330
8.95k
        if (short_name != NULL) {
2331
142
            if (mask == 24) {
2332
                /* This shouldn't happen as it should be handled above,
2333
                 * but it doesn't hurt.
2334
                 */
2335
0
                manuf_hash_new_entry(addr, short_name, long_name);
2336
0
            }
2337
142
            eth_resolved_name_fill(tp, short_name, mask, addr);
2338
142
            tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2339
142
            return tp;
2340
142
        }
2341
        /* No match whatsoever. */
2342
8.80k
        set_address(&ether_addr, AT_ETHER, 6, addr);
2343
8.80k
        address_to_str_buf(&ether_addr, tp->resolved_name, MAXNAMELEN);
2344
8.80k
        return tp;
2345
8.95k
    }
2346
0
    return tp;
2347
11.3k
} /* eth_addr_resolve */
2348
2349
static hashether_t *
2350
eth_hash_new_entry(const uint8_t *addr, const bool resolve)
2351
11.3k
{
2352
11.3k
    hashether_t *tp;
2353
11.3k
    char *endp;
2354
2355
11.3k
    tp = wmem_new(addr_resolv_scope, hashether_t);
2356
11.3k
    memcpy(tp->addr, addr, sizeof(tp->addr));
2357
11.3k
    tp->flags = 0;
2358
    /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
2359
11.3k
    endp = bytes_to_hexstr_punct(tp->hexaddr, addr, sizeof(tp->addr), ':');
2360
11.3k
    *endp = '\0';
2361
11.3k
    tp->resolved_name[0] = '\0';
2362
2363
11.3k
    if (resolve)
2364
11.3k
        eth_addr_resolve(tp);
2365
2366
11.3k
    wmem_map_insert(eth_hashtable, tp->addr, tp);
2367
2368
11.3k
    return tp;
2369
11.3k
} /* eth_hash_new_entry */
2370
2371
static hashether_t *
2372
add_eth_name(const uint8_t *addr, const char *name, bool static_entry)
2373
0
{
2374
0
    hashether_t *tp;
2375
2376
0
    tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
2377
2378
0
    if (tp == NULL) {
2379
0
        tp = eth_hash_new_entry(addr, false);
2380
0
    }
2381
2382
0
    if (strcmp(tp->resolved_name, name) != 0 && (static_entry || !(tp->flags & STATIC_HOSTNAME))) {
2383
0
        (void) g_strlcpy(tp->resolved_name, name, MAXNAMELEN);
2384
0
        tp->flags |= NAME_RESOLVED;
2385
0
        if (static_entry) {
2386
0
            tp->flags |= STATIC_HOSTNAME;
2387
0
        }
2388
0
        new_resolved_objects = true;
2389
0
    }
2390
2391
0
    return tp;
2392
0
} /* add_eth_name */
2393
2394
static hashether_t *
2395
eth_name_lookup(const uint8_t *addr, const bool resolve)
2396
73.4k
{
2397
73.4k
    hashether_t  *tp;
2398
2399
73.4k
    tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
2400
2401
73.4k
    if (tp == NULL) {
2402
11.3k
        tp = eth_hash_new_entry(addr, resolve);
2403
62.0k
    } else {
2404
62.0k
        if (resolve && !(tp->flags & TRIED_OR_RESOLVED_MASK)) {
2405
0
            eth_addr_resolve(tp); /* Found but needs to be resolved */
2406
0
        }
2407
62.0k
    }
2408
73.4k
    if (resolve) {
2409
73.4k
        tp->flags |= TRIED_RESOLVE_ADDRESS;
2410
73.4k
    }
2411
2412
73.4k
    return tp;
2413
2414
73.4k
} /* 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
1
{
2419
1
    switch (mask) {
2420
0
        case 24:
2421
0
            snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
2422
0
                    name, addr[3], addr[4], addr[5], addr[6], addr[7]);
2423
0
            break;
2424
1
        case 28:
2425
1
            snprintf(tp->resolved_name, MAXNAMELEN, "%s_%01x:%02x:%02x:%02x:%02x",
2426
1
                    name, addr[3] & 0x0F, addr[4], addr[5], addr[6], addr[7]);
2427
1
            break;
2428
0
        case 36:
2429
0
            snprintf(tp->resolved_name, MAXNAMELEN, "%s_%01x:%02x:%02x:%02x",
2430
0
                    name, addr[4] & 0x0F, addr[5], addr[6], addr[7]);
2431
0
            break;
2432
0
        default: // Future-proof generic algorithm
2433
0
        {
2434
0
            unsigned bytes = mask / 8;
2435
0
            unsigned bitmask = mask % 8;
2436
2437
0
            int pos = snprintf(tp->resolved_name, MAXNAMELEN, "%s", name);
2438
0
            if (pos >= MAXNAMELEN) return;
2439
2440
0
            if (bytes < EUI64_ADDR_LEN) {
2441
0
                pos += snprintf(tp->resolved_name + pos, MAXNAMELEN - pos,
2442
0
                    bitmask >= 4 ? "_%01x" : "_%02x",
2443
0
                    addr[bytes] & (0xFF >> bitmask));
2444
0
                bytes++;
2445
0
            }
2446
2447
0
            while (bytes < EUI64_ADDR_LEN) {
2448
0
                if (pos >= MAXNAMELEN) return;
2449
0
                pos += snprintf(tp->resolved_name + pos, MAXNAMELEN - pos, ":%02x",
2450
0
                    addr[bytes]);
2451
0
                bytes++;
2452
0
            }
2453
0
        }
2454
1
    }
2455
1
}
2456
2457
/* Resolve EUI-64 address */
2458
static hasheui64_t *
2459
eui64_addr_resolve(hasheui64_t *tp)
2460
862
{
2461
862
    hashmanuf_t *manuf_value;
2462
862
    const uint8_t *addr = tp->addr;
2463
862
    size_t addr_size = sizeof(tp->addr);
2464
2465
862
    if (!(tp->flags & NAME_RESOLVED)) {
2466
862
        unsigned      mask;
2467
862
        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
862
        manuf_value = manuf_name_lookup(addr, addr_size);
2473
862
        if ((manuf_value != NULL) && ((manuf_value->flags & NAME_RESOLVED) == NAME_RESOLVED)) {
2474
94
            snprintf(tp->resolved_name, MAXNAMELEN, "%.*s_%02x:%02x:%02x:%02x:%02x",
2475
94
                    MAXNAMELEN - 16, manuf_value->resolved_name, addr[3], addr[4], addr[5], addr[6], addr[7]);
2476
94
            tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2477
94
            return tp;
2478
94
        }
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
768
        const char *short_name, *long_name;
2485
768
        short_name = ws_manuf_lookup(addr, &long_name, &mask);
2486
768
        if (short_name != NULL) {
2487
1
            if (mask == 24) {
2488
                /* This shouldn't happen as it should be handled above,
2489
                 * but it doesn't hurt.
2490
                 */
2491
0
                manuf_hash_new_entry(addr, short_name, long_name);
2492
0
            }
2493
1
            eui64_resolved_name_fill(tp, short_name, mask, addr);
2494
1
            tp->flags |= NAME_RESOLVED | NAME_RESOLVED_PREFIX;
2495
1
            return tp;
2496
1
        }
2497
        /* No match whatsoever. */
2498
767
        set_address(&eui64_addr, AT_EUI64, 8, addr);
2499
767
        address_to_str_buf(&eui64_addr, tp->resolved_name, MAXNAMELEN);
2500
767
        return tp;
2501
768
    }
2502
2503
0
    return tp;
2504
862
} /* eui64_addr_resolve */
2505
2506
static hasheui64_t *
2507
eui64_hash_new_entry(const uint8_t *addr, const bool resolve)
2508
862
{
2509
862
    hasheui64_t *tp;
2510
862
    char *endp;
2511
2512
862
    tp = wmem_new(addr_resolv_scope, hasheui64_t);
2513
862
    memcpy(tp->addr, addr, sizeof(tp->addr));
2514
862
    tp->flags = 0;
2515
    /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
2516
862
    endp = bytes_to_hexstr_punct(tp->hexaddr, addr, sizeof(tp->addr), ':');
2517
862
    *endp = '\0';
2518
862
    tp->resolved_name[0] = '\0';
2519
2520
862
    if (resolve)
2521
862
        eui64_addr_resolve(tp);
2522
2523
862
    wmem_map_insert(eui64_hashtable, tp->addr, tp);
2524
2525
862
    return tp;
2526
862
} /* eui64_hash_new_entry */
2527
2528
static hasheui64_t *
2529
add_eui64_name(const uint8_t *addr, const char *name, bool static_entry)
2530
0
{
2531
0
    hasheui64_t *tp;
2532
2533
0
    tp = (hasheui64_t *)wmem_map_lookup(eui64_hashtable, addr);
2534
2535
0
    if (tp == NULL) {
2536
0
        tp = eui64_hash_new_entry(addr, false);
2537
0
    }
2538
2539
0
    if (strcmp(tp->resolved_name, name) != 0 && (static_entry || !(tp->flags & STATIC_HOSTNAME))) {
2540
0
        (void) g_strlcpy(tp->resolved_name, name, MAXNAMELEN);
2541
0
        tp->flags |= NAME_RESOLVED;
2542
0
        if (static_entry) {
2543
0
            tp->flags |= STATIC_HOSTNAME;
2544
0
        }
2545
0
        new_resolved_objects = true;
2546
0
    }
2547
2548
0
    return tp;
2549
0
} /* add_eui64_name */
2550
2551
static hasheui64_t *
2552
eui64_name_lookup(const uint8_t *addr, const bool resolve)
2553
3.28k
{
2554
3.28k
    hasheui64_t  *tp;
2555
2556
3.28k
    tp = (hasheui64_t *)wmem_map_lookup(eui64_hashtable, addr);
2557
2558
3.28k
    if (tp == NULL) {
2559
862
        tp = eui64_hash_new_entry(addr, resolve);
2560
2.42k
    } else {
2561
2.42k
        if (resolve && !(tp->flags & TRIED_OR_RESOLVED_MASK)) {
2562
0
            eui64_addr_resolve(tp); /* Found but needs to be resolved */
2563
0
        }
2564
2.42k
    }
2565
3.28k
    if (resolve) {
2566
3.28k
        tp->flags |= TRIED_RESOLVE_ADDRESS;
2567
3.28k
    }
2568
2569
3.28k
    return tp;
2570
2571
3.28k
} /* eui64_name_lookup */
2572
2573
/* IPXNETS */
2574
static int
2575
parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
2576
0
{
2577
    /*
2578
     *  We allow three address separators (':', '-', and '.'),
2579
     *  as well as no separators
2580
     */
2581
2582
0
    char      *cp;
2583
0
    uint32_t  a, a0, a1, a2, a3;
2584
0
    bool      found_single_number = false;
2585
2586
0
    if ((cp = strchr(line, '#')))
2587
0
        *cp = '\0';
2588
2589
0
    if ((cp = strtok(line, " \t\n")) == NULL)
2590
0
        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
0
    if (sscanf(cp, "%x:%x:%x:%x", &a0, &a1, &a2, &a3) != 4) {
2597
0
        if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
2598
0
            if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
2599
0
                if (sscanf(cp, "%x", &a) == 1) {
2600
0
                    found_single_number = true;
2601
0
                }
2602
0
                else {
2603
0
                    return -1;
2604
0
                }
2605
0
            }
2606
0
        }
2607
0
    }
2608
2609
0
    if ((cp = strtok(NULL, " \t\n")) == NULL)
2610
0
        return -1;
2611
2612
0
    if (found_single_number) {
2613
0
        ipxnet->addr = a;
2614
0
    }
2615
0
    else {
2616
0
        ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
2617
0
    }
2618
2619
0
    (void) g_strlcpy(ipxnet->name, cp, MAXNAMELEN);
2620
2621
0
    return 0;
2622
2623
0
} /* parse_ipxnets_line */
2624
2625
static FILE *ipxnet_p;
2626
2627
static void
2628
set_ipxnetent(char *path)
2629
0
{
2630
0
    if (ipxnet_p)
2631
0
        rewind(ipxnet_p);
2632
0
    else
2633
0
        ipxnet_p = ws_fopen(path, "r");
2634
0
}
2635
2636
static void
2637
end_ipxnetent(void)
2638
0
{
2639
0
    if (ipxnet_p) {
2640
0
        fclose(ipxnet_p);
2641
0
        ipxnet_p = NULL;
2642
0
    }
2643
0
}
2644
2645
static ipxnet_t *
2646
get_ipxnetent(void)
2647
0
{
2648
2649
0
    static ipxnet_t ipxnet;
2650
0
    char    buf[MAX_LINELEN];
2651
2652
0
    if (ipxnet_p == NULL)
2653
0
        return NULL;
2654
2655
0
    while (fgetline(buf, sizeof(buf), ipxnet_p) >= 0) {
2656
0
        if (parse_ipxnets_line(buf, &ipxnet) == 0) {
2657
0
            return &ipxnet;
2658
0
        }
2659
0
    }
2660
2661
0
    return NULL;
2662
2663
0
} /* get_ipxnetent */
2664
2665
static ipxnet_t *
2666
get_ipxnetbyaddr(uint32_t addr)
2667
0
{
2668
0
    ipxnet_t *ipxnet;
2669
2670
0
    set_ipxnetent(g_ipxnets_path);
2671
2672
0
    while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) ) ;
2673
2674
0
    if (ipxnet == NULL) {
2675
0
        end_ipxnetent();
2676
2677
0
        set_ipxnetent(g_pipxnets_path);
2678
2679
0
        while (((ipxnet = get_ipxnetent()) != NULL) && (addr != ipxnet->addr) )
2680
0
            ;
2681
2682
0
        end_ipxnetent();
2683
0
    }
2684
2685
0
    return ipxnet;
2686
2687
0
} /* get_ipxnetbyaddr */
2688
2689
static void
2690
initialize_ipxnets(const char* app_env_var_prefix)
2691
28
{
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
28
    if (g_ipxnets_path == NULL) {
2700
28
        g_ipxnets_path = wmem_strdup_printf(addr_resolv_scope, "%s" G_DIR_SEPARATOR_S "%s",
2701
28
                get_systemfile_dir(app_env_var_prefix), ENAME_IPXNETS);
2702
28
    }
2703
2704
    /* Set g_pipxnets_path here, but don't actually do anything
2705
     * with it. It's used in get_ipxnetbyaddr().
2706
     */
2707
28
    if (g_pipxnets_path == NULL) {
2708
        /* Check profile directory before personal configuration */
2709
28
        g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, true, app_env_var_prefix);
2710
28
        if (!file_exists(g_pipxnets_path)) {
2711
28
            g_free(g_pipxnets_path);
2712
28
            g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, false, app_env_var_prefix);
2713
28
        }
2714
28
    }
2715
2716
28
} /* initialize_ipxnets */
2717
2718
static void
2719
ipx_name_lookup_cleanup(void)
2720
14
{
2721
14
    g_ipxnets_path = NULL;
2722
14
    g_free(g_pipxnets_path);
2723
14
    g_pipxnets_path = NULL;
2724
14
}
2725
2726
static char *
2727
ipxnet_name_lookup(wmem_allocator_t *allocator, const unsigned addr)
2728
0
{
2729
0
    hashipxnet_t *tp;
2730
0
    ipxnet_t *ipxnet;
2731
2732
0
    tp = (hashipxnet_t *)wmem_map_lookup(ipxnet_hash_table, GUINT_TO_POINTER(addr));
2733
0
    if (tp == NULL) {
2734
0
        tp = wmem_new(addr_resolv_scope, hashipxnet_t);
2735
0
        wmem_map_insert(ipxnet_hash_table, GUINT_TO_POINTER(addr), tp);
2736
0
    } else {
2737
0
        return wmem_strdup(allocator, tp->name);
2738
0
    }
2739
2740
    /* fill in a new entry */
2741
2742
0
    tp->addr = addr;
2743
2744
0
    if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL) {
2745
        /* unknown name */
2746
0
        snprintf(tp->name, MAXNAMELEN, "%X", addr);
2747
2748
0
    } else {
2749
0
        (void) g_strlcpy(tp->name, ipxnet->name, MAXNAMELEN);
2750
0
    }
2751
2752
0
    return wmem_strdup(allocator, tp->name);
2753
2754
0
} /* ipxnet_name_lookup */
2755
2756
/* VLANS */
2757
static int
2758
parse_vlan_line(char *line, vlan_t *vlan)
2759
0
{
2760
0
    char      *cp;
2761
0
    uint16_t  id;
2762
2763
0
    if ((cp = strchr(line, '#')))
2764
0
        *cp = '\0';
2765
2766
0
    if ((cp = strtok(line, " \t\n")) == NULL)
2767
0
        return -1;
2768
2769
0
    if (sscanf(cp, "%" SCNu16, &id) == 1) {
2770
0
        vlan->id = id;
2771
0
    }
2772
0
    else {
2773
0
        return -1;
2774
0
    }
2775
2776
0
    if ((cp = strtok(NULL, "\t\n")) == NULL)
2777
0
        return -1;
2778
2779
0
    (void) g_strlcpy(vlan->name, cp, MAXVLANNAMELEN);
2780
2781
0
    return 0;
2782
2783
0
} /* parse_vlan_line */
2784
2785
static FILE *vlan_p;
2786
2787
static void
2788
set_vlanent(char *path)
2789
0
{
2790
0
    if (vlan_p)
2791
0
        rewind(vlan_p);
2792
0
    else
2793
0
        vlan_p = ws_fopen(path, "r");
2794
0
}
2795
2796
static void
2797
end_vlanent(void)
2798
14
{
2799
14
    if (vlan_p) {
2800
0
        fclose(vlan_p);
2801
0
        vlan_p = NULL;
2802
0
    }
2803
14
}
2804
2805
static vlan_t *
2806
get_vlanent(void)
2807
0
{
2808
2809
0
    static vlan_t vlan;
2810
0
    char    buf[MAX_LINELEN];
2811
2812
0
    if (vlan_p == NULL)
2813
0
        return NULL;
2814
2815
0
    while (fgetline(buf, sizeof(buf), vlan_p) >= 0) {
2816
0
        if (parse_vlan_line(buf, &vlan) == 0) {
2817
0
            return &vlan;
2818
0
        }
2819
0
    }
2820
2821
0
    return NULL;
2822
2823
0
} /* get_vlanent */
2824
2825
static vlan_t *
2826
get_vlannamebyid(uint16_t id)
2827
0
{
2828
0
    vlan_t *vlan;
2829
2830
0
    set_vlanent(g_pvlan_path);
2831
2832
0
    while (((vlan = get_vlanent()) != NULL) && (id != vlan->id) ) ;
2833
2834
0
    if (vlan == NULL) {
2835
0
        end_vlanent();
2836
2837
0
    }
2838
2839
0
    return vlan;
2840
2841
0
} /* get_vlannamebyid */
2842
2843
static void
2844
initialize_vlans(const char* app_env_var_prefix)
2845
28
{
2846
28
    ws_assert(vlan_hash_table == NULL);
2847
28
    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
28
    if (g_pvlan_path == NULL) {
2853
        /* Check profile directory before personal configuration */
2854
28
        g_pvlan_path = get_persconffile_path(ENAME_VLANS, true, app_env_var_prefix);
2855
28
        if (!file_exists(g_pvlan_path)) {
2856
28
            g_free(g_pvlan_path);
2857
28
            g_pvlan_path = get_persconffile_path(ENAME_VLANS, false, app_env_var_prefix);
2858
28
        }
2859
28
    }
2860
28
} /* initialize_vlans */
2861
2862
static void
2863
vlan_name_lookup_cleanup(void)
2864
14
{
2865
14
    end_vlanent();
2866
14
    vlan_hash_table = NULL;
2867
14
    g_free(g_pvlan_path);
2868
14
    g_pvlan_path = NULL;
2869
14
}
2870
2871
static const char *
2872
vlan_name_lookup(const unsigned id)
2873
0
{
2874
0
    hashvlan_t *tp;
2875
0
    vlan_t *vlan;
2876
2877
0
    tp = (hashvlan_t *)wmem_map_lookup(vlan_hash_table, GUINT_TO_POINTER(id));
2878
0
    if (tp == NULL) {
2879
0
        tp = wmem_new(addr_resolv_scope, hashvlan_t);
2880
0
        wmem_map_insert(vlan_hash_table, GUINT_TO_POINTER(id), tp);
2881
0
    } else {
2882
0
        return tp->name;
2883
0
    }
2884
2885
    /* fill in a new entry */
2886
2887
0
    tp->id = id;
2888
2889
0
    if ( (vlan = get_vlannamebyid(id)) == NULL) {
2890
        /* unknown name */
2891
0
        snprintf(tp->name, MAXVLANNAMELEN, "<%u>", id);
2892
2893
0
    } else {
2894
0
        (void) g_strlcpy(tp->name, vlan->name, MAXVLANNAMELEN);
2895
0
    }
2896
2897
0
    return tp->name;
2898
2899
0
} /* vlan_name_lookup */
2900
/* VLAN END */
2901
2902
static bool
2903
read_hosts_file (const char *hostspath, bool store_entries)
2904
56
{
2905
56
    FILE *hf;
2906
56
    char line[MAX_LINELEN];
2907
56
    char *cp;
2908
56
    union {
2909
56
        uint32_t ip4_addr;
2910
56
        ws_in6_addr ip6_addr;
2911
56
    } host_addr;
2912
56
    bool is_ipv6, entry_found = false;
2913
2914
    /*
2915
     *  See the hosts(4) or hosts(5) man page for hosts file format
2916
     *  (not available on all systems).
2917
     */
2918
56
    if ((hf = ws_fopen(hostspath, "r")) == NULL)
2919
56
        return false;
2920
2921
0
    while (fgetline(line, sizeof(line), hf) >= 0) {
2922
0
        if ((cp = strchr(line, '#')))
2923
0
            *cp = '\0';
2924
2925
0
        if ((cp = strtok(line, " \t")) == NULL)
2926
0
            continue; /* no tokens in the line */
2927
2928
0
        if (ws_inet_pton6(cp, &host_addr.ip6_addr)) {
2929
            /* Valid IPv6 */
2930
0
            is_ipv6 = true;
2931
0
        } else if (ws_inet_pton4(cp, &host_addr.ip4_addr)) {
2932
            /* Valid IPv4 */
2933
0
            is_ipv6 = false;
2934
0
        } else {
2935
0
            continue;
2936
0
        }
2937
2938
0
        if ((cp = strtok(NULL, " \t")) == NULL)
2939
0
            continue; /* no host name */
2940
2941
0
        entry_found = true;
2942
0
        if (store_entries) {
2943
0
            if (is_ipv6) {
2944
0
                add_ipv6_name(&host_addr.ip6_addr, cp, true);
2945
0
            } else {
2946
0
                add_ipv4_name(host_addr.ip4_addr, cp, true);
2947
0
            }
2948
0
        }
2949
0
    }
2950
2951
0
    fclose(hf);
2952
0
    return entry_found ? true : false;
2953
56
} /* read_hosts_file */
2954
2955
bool
2956
add_hosts_file (const char *hosts_file)
2957
0
{
2958
0
    bool found = false;
2959
0
    unsigned i;
2960
2961
0
    if (!hosts_file)
2962
0
        return false;
2963
2964
0
    if (!extra_hosts_files)
2965
0
        extra_hosts_files = g_ptr_array_new();
2966
2967
0
    for (i = 0; i < extra_hosts_files->len; i++) {
2968
0
        if (strcmp(hosts_file, (const char *) g_ptr_array_index(extra_hosts_files, i)) == 0)
2969
0
            found = true;
2970
0
    }
2971
2972
0
    if (!found) {
2973
0
        g_ptr_array_add(extra_hosts_files, wmem_strdup(wmem_epan_scope(), hosts_file));
2974
0
        return read_hosts_file (hosts_file, false);
2975
0
    }
2976
0
    return true;
2977
0
}
2978
2979
bool
2980
add_ip_name_from_string (const char *addr, const char *name)
2981
0
{
2982
0
    union {
2983
0
        uint32_t ip4_addr;
2984
0
        ws_in6_addr ip6_addr;
2985
0
    } host_addr;
2986
0
    bool is_ipv6;
2987
0
    resolved_name_t *resolved_entry;
2988
2989
0
    if (ws_inet_pton6(addr, &host_addr.ip6_addr)) {
2990
0
        is_ipv6 = true;
2991
0
    } else if (ws_inet_pton4(addr, &host_addr.ip4_addr)) {
2992
0
        is_ipv6 = false;
2993
0
    } else {
2994
0
        return false;
2995
0
    }
2996
2997
0
    if (is_ipv6) {
2998
0
        resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv6_list, &host_addr.ip6_addr);
2999
0
        if (resolved_entry)
3000
0
        {
3001
            // If we found a previous matching key (IP address), then just update the value (custom hostname);
3002
0
            (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN);
3003
0
        }
3004
0
        else
3005
0
        {
3006
            // Add a new mapping entry, if this IP address isn't already in the list.
3007
0
            ws_in6_addr* addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr);
3008
0
            memcpy(addr_key, &host_addr.ip6_addr, sizeof(ws_in6_addr));
3009
3010
0
            resolved_entry = wmem_new(wmem_epan_scope(), resolved_name_t);
3011
0
            (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN);
3012
3013
0
            wmem_map_insert(manually_resolved_ipv6_list, addr_key, resolved_entry);
3014
0
        }
3015
0
    } else {
3016
0
        resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv4_list, GUINT_TO_POINTER(host_addr.ip4_addr));
3017
0
        if (resolved_entry)
3018
0
        {
3019
            // If we found a previous matching key (IP address), then just update the value (custom hostname);
3020
0
            (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN);
3021
0
        }
3022
0
        else
3023
0
        {
3024
            // Add a new mapping entry, if this IP address isn't already in the list.
3025
0
            resolved_entry = wmem_new(wmem_epan_scope(), resolved_name_t);
3026
0
            (void) g_strlcpy(resolved_entry->name, name, MAXDNSNAMELEN);
3027
3028
0
            wmem_map_insert(manually_resolved_ipv4_list, GUINT_TO_POINTER(host_addr.ip4_addr), resolved_entry);
3029
0
        }
3030
0
    }
3031
3032
0
    return true;
3033
0
} /* add_ip_name_from_string */
3034
3035
extern resolved_name_t* get_edited_resolved_name(const char* addr)
3036
0
{
3037
0
    uint32_t ip4_addr;
3038
0
    ws_in6_addr ip6_addr;
3039
0
    resolved_name_t* resolved_entry = NULL;
3040
3041
0
    if (ws_inet_pton6(addr, &ip6_addr)) {
3042
0
        resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv6_list, &ip6_addr);
3043
0
    }
3044
0
    else if (ws_inet_pton4(addr, &ip4_addr)) {
3045
0
        resolved_entry = (resolved_name_t*)wmem_map_lookup(manually_resolved_ipv4_list, GUINT_TO_POINTER(ip4_addr));
3046
0
    }
3047
3048
0
    return resolved_entry;
3049
0
}
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_, void *value, void *user_data)
3056
0
{
3057
0
    addrinfo_lists_t *lists = (addrinfo_lists_t *)user_data;
3058
0
    hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value;
3059
3060
0
    if ((ipv4_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
3061
0
        lists->ipv4_addr_list = g_list_prepend(lists->ipv4_addr_list, ipv4_hash_table_entry);
3062
0
    }
3063
0
}
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_, void *value, void *user_data)
3070
0
{
3071
0
    addrinfo_lists_t *lists = (addrinfo_lists_t *)user_data;
3072
0
    hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value;
3073
3074
0
    if ((ipv6_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
3075
0
        lists->ipv6_addr_list = g_list_prepend(lists->ipv6_addr_list, ipv6_hash_table_entry);
3076
0
    }
3077
0
}
3078
3079
addrinfo_lists_t *
3080
get_addrinfo_list(void)
3081
0
{
3082
0
    if (ipv4_hash_table) {
3083
0
        wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_resolved_to_list, &addrinfo_lists);
3084
0
    }
3085
3086
0
    if (ipv6_hash_table) {
3087
0
        wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_resolved_to_list, &addrinfo_lists);
3088
0
    }
3089
3090
0
    return &addrinfo_lists;
3091
0
}
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
3108
read_subnets_file (const char *subnetspath)
3109
84
{
3110
84
    FILE *hf;
3111
84
    char line[MAX_LINELEN];
3112
84
    char *cp, *cp2;
3113
84
    uint32_t host_addr; /* IPv4 ONLY */
3114
84
    uint8_t mask_length;
3115
3116
84
    if ((hf = ws_fopen(subnetspath, "r")) == NULL)
3117
84
        return false;
3118
3119
0
    while (fgetline(line, sizeof(line), hf) >= 0) {
3120
0
        if ((cp = strchr(line, '#')))
3121
0
            *cp = '\0';
3122
3123
0
        if ((cp = strtok(line, " \t")) == NULL)
3124
0
            continue; /* no tokens in the line */
3125
3126
3127
        /* Expected format is <IP4 address>/<subnet length> */
3128
0
        cp2 = strchr(cp, '/');
3129
0
        if (NULL == cp2) {
3130
            /* No length */
3131
0
            continue;
3132
0
        }
3133
0
        *cp2 = '\0'; /* Cut token */
3134
0
        ++cp2    ;
3135
3136
        /* Check if this is a valid IPv4 address */
3137
0
        if (!str_to_ip(cp, &host_addr)) {
3138
0
            continue; /* no */
3139
0
        }
3140
3141
0
        if (!ws_strtou8(cp2, NULL, &mask_length) || mask_length == 0 || mask_length > 32) {
3142
0
            continue; /* invalid mask length */
3143
0
        }
3144
3145
0
        if ((cp = strtok(NULL, " \t")) == NULL)
3146
0
            continue; /* no subnet name */
3147
3148
0
        subnet_entry_set(host_addr, mask_length, cp);
3149
0
    }
3150
3151
0
    fclose(hf);
3152
0
    return true;
3153
84
} /* read_subnets_file */
3154
3155
static subnet_entry_t
3156
subnet_lookup(const uint32_t addr)
3157
82
{
3158
82
    subnet_entry_t subnet_entry;
3159
82
    uint32_t i;
3160
3161
    /* Search mask lengths linearly, longest first */
3162
3163
82
    i = SUBNETLENGTHSIZE;
3164
82
    while(have_subnet_entry && i > 0) {
3165
0
        uint32_t masked_addr;
3166
0
        subnet_length_entry_t* length_entry;
3167
3168
        /* Note that we run from 31 (length 32)  to 0 (length 1)  */
3169
0
        --i;
3170
0
        ws_assert(i < SUBNETLENGTHSIZE);
3171
3172
3173
0
        length_entry = &subnet_length_entries[i];
3174
3175
0
        if (NULL != length_entry->subnet_addresses) {
3176
0
            sub_net_hashipv4_t * tp;
3177
0
            uint32_t hash_idx;
3178
3179
0
            masked_addr = addr & length_entry->mask;
3180
0
            hash_idx = HASH_IPV4_ADDRESS(masked_addr);
3181
3182
0
            tp = length_entry->subnet_addresses[hash_idx];
3183
0
            while(tp != NULL && tp->addr != masked_addr) {
3184
0
                tp = tp->next;
3185
0
            }
3186
3187
0
            if (NULL != tp) {
3188
0
                subnet_entry.mask = length_entry->mask;
3189
0
                subnet_entry.mask_length = i + 1; /* Length is offset + 1 */
3190
0
                subnet_entry.name = tp->name;
3191
0
                return subnet_entry;
3192
0
            }
3193
0
        }
3194
0
    }
3195
3196
82
    subnet_entry.mask = 0;
3197
82
    subnet_entry.mask_length = 0;
3198
82
    subnet_entry.name = NULL;
3199
3200
82
    return subnet_entry;
3201
82
}
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
0
{
3210
0
    subnet_length_entry_t* entry;
3211
0
    sub_net_hashipv4_t * tp;
3212
0
    size_t hash_idx;
3213
3214
0
    ws_assert(mask_length > 0 && mask_length <= 32);
3215
3216
0
    entry = &subnet_length_entries[mask_length - 1];
3217
3218
0
    subnet_addr &= entry->mask;
3219
3220
0
    hash_idx = HASH_IPV4_ADDRESS(subnet_addr);
3221
3222
0
    if (NULL == entry->subnet_addresses) {
3223
0
        entry->subnet_addresses = (sub_net_hashipv4_t**)wmem_alloc0(addr_resolv_scope, sizeof(sub_net_hashipv4_t*) * HASHHOSTSIZE);
3224
0
    }
3225
3226
0
    if (NULL != (tp = entry->subnet_addresses[hash_idx])) {
3227
0
        sub_net_hashipv4_t * new_tp;
3228
3229
0
        while (tp->next) {
3230
0
            if (tp->addr == subnet_addr) {
3231
0
                return; /* XXX provide warning that an address was repeated? */
3232
0
            } else {
3233
0
                tp = tp->next;
3234
0
            }
3235
0
        }
3236
3237
0
        new_tp = wmem_new(addr_resolv_scope, sub_net_hashipv4_t);
3238
0
        tp->next = new_tp;
3239
0
        tp = new_tp;
3240
0
    } else {
3241
0
        tp = entry->subnet_addresses[hash_idx] = wmem_new(addr_resolv_scope, sub_net_hashipv4_t);
3242
0
    }
3243
3244
0
    tp->next = NULL;
3245
0
    tp->addr = subnet_addr;
3246
0
    (void) g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
3247
0
    have_subnet_entry = true;
3248
0
}
3249
3250
static void
3251
subnet_name_lookup_init(const char* app_env_var_prefix)
3252
28
{
3253
28
    char* subnetspath;
3254
28
    uint32_t i;
3255
3256
924
    for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
3257
896
        uint32_t length = i + 1;
3258
3259
896
        subnet_length_entries[i].subnet_addresses  = NULL;
3260
896
        subnet_length_entries[i].mask_length  = length;
3261
896
        subnet_length_entries[i].mask = g_htonl(ws_ipv4_get_subnet_mask(length));
3262
896
    }
3263
3264
    /* Check profile directory before personal configuration */
3265
28
    subnetspath = get_persconffile_path(ENAME_SUBNETS, true, app_env_var_prefix);
3266
28
    if (!read_subnets_file(subnetspath)) {
3267
28
        if (errno != ENOENT) {
3268
0
            report_open_failure(subnetspath, errno, false);
3269
0
        }
3270
3271
28
        g_free(subnetspath);
3272
28
        subnetspath = get_persconffile_path(ENAME_SUBNETS, false, app_env_var_prefix);
3273
28
        if (!read_subnets_file(subnetspath) && errno != ENOENT) {
3274
0
            report_open_failure(subnetspath, errno, false);
3275
0
        }
3276
28
    }
3277
28
    g_free(subnetspath);
3278
3279
    /*
3280
     * Load the global subnets file, if we have one.
3281
     */
3282
28
    subnetspath = get_datafile_path(ENAME_SUBNETS, app_env_var_prefix);
3283
28
    if (!read_subnets_file(subnetspath) && errno != ENOENT) {
3284
0
        report_open_failure(subnetspath, errno, false);
3285
0
    }
3286
28
    g_free(subnetspath);
3287
28
}
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
3.58k
{
3295
3.58k
    uint32_t full_bytes = mask_length / 8;
3296
3.58k
    uint32_t remaining  = mask_length % 8;
3297
3.58k
    memset(mask, 0, 16);
3298
30.9k
    for (uint32_t i = 0; i < full_bytes; i++)
3299
27.3k
        mask[i] = 0xff;
3300
3.58k
    if (remaining > 0 && full_bytes < 16)
3301
3.13k
        mask[full_bytes] = (uint8_t)(0xff << (8 - remaining));
3302
3.58k
}
3303
3304
static void
3305
subnet6_entry_set(const ws_in6_addr *subnet_addr, const uint32_t mask_length,
3306
                  const char *name)
3307
0
{
3308
0
    subnet_length_entry_v6_t *entry;
3309
0
    sub_net_hashipv6_t *tp;
3310
0
    uint8_t masked[16];
3311
0
    size_t hash_idx;
3312
3313
0
    ws_assert(mask_length > 0 && mask_length <= 128);
3314
0
    entry = &subnet_length_entries_v6[mask_length - 1];
3315
3316
0
    for (int i = 0; i < 16; i++)
3317
0
        masked[i] = subnet_addr->bytes[i] & entry->mask[i];
3318
3319
0
    hash_idx = ipv6_oat_hash(masked) & (HASHHOSTSIZE - 1);
3320
3321
0
    if (entry->subnet_addresses == NULL)
3322
0
        entry->subnet_addresses = (sub_net_hashipv6_t **)wmem_alloc0(
3323
0
            addr_resolv_scope, sizeof(sub_net_hashipv6_t *) * HASHHOSTSIZE);
3324
3325
0
    if ((tp = entry->subnet_addresses[hash_idx]) != NULL) {
3326
0
        sub_net_hashipv6_t *new_tp;
3327
0
        while (tp->next) {
3328
0
            if (memcmp(tp->addr, masked, 16) == 0)
3329
0
                return; /* duplicate */
3330
0
            tp = tp->next;
3331
0
        }
3332
0
        if (memcmp(tp->addr, masked, 16) == 0)
3333
0
            return; /* duplicate at tail */
3334
0
        new_tp = wmem_new(addr_resolv_scope, sub_net_hashipv6_t);
3335
0
        tp->next = new_tp;
3336
0
        tp = new_tp;
3337
0
    } else {
3338
0
        tp = entry->subnet_addresses[hash_idx] =
3339
0
            wmem_new(addr_resolv_scope, sub_net_hashipv6_t);
3340
0
    }
3341
3342
0
    tp->next = NULL;
3343
0
    memcpy(tp->addr, masked, 16);
3344
0
    (void)g_strlcpy(tp->name, name, MAXNAMELEN);
3345
0
    have_subnet_entry_v6 = true;
3346
0
}
3347
3348
static subnet_entry_v6_t
3349
subnet6_lookup(const ws_in6_addr *addr)
3350
1
{
3351
1
    subnet_entry_v6_t result;
3352
1
    uint32_t i = SUBNETLENGTHSIZE_V6;
3353
3354
1
    while (have_subnet_entry_v6 && i > 0) {
3355
0
        subnet_length_entry_v6_t *length_entry;
3356
0
        uint8_t masked[16];
3357
0
        size_t hash_idx;
3358
0
        sub_net_hashipv6_t *tp;
3359
3360
0
        --i;
3361
0
        length_entry = &subnet_length_entries_v6[i];
3362
3363
0
        if (length_entry->subnet_addresses == NULL)
3364
0
            continue;
3365
3366
0
        for (int b = 0; b < 16; b++)
3367
0
            masked[b] = addr->bytes[b] & length_entry->mask[b];
3368
3369
0
        hash_idx = ipv6_oat_hash(masked) & (HASHHOSTSIZE - 1);
3370
0
        tp = length_entry->subnet_addresses[hash_idx];
3371
3372
0
        while (tp != NULL && memcmp(tp->addr, masked, 16) != 0)
3373
0
            tp = tp->next;
3374
3375
0
        if (tp != NULL) {
3376
0
            memcpy(result.mask, length_entry->mask, 16);
3377
0
            result.mask_length = i + 1;
3378
0
            result.name = tp->name;
3379
0
            return result;
3380
0
        }
3381
0
    }
3382
3383
1
    memset(result.mask, 0, 16);
3384
1
    result.mask_length = 0;
3385
1
    result.name = NULL;
3386
1
    return result;
3387
1
}
3388
3389
static bool
3390
read_subnets_ipv6_file(const char *subnetspath)
3391
84
{
3392
84
    FILE *hf;
3393
84
    char line[MAX_LINELEN];
3394
84
    char *cp, *cp2;
3395
84
    ws_in6_addr host_addr;
3396
84
    uint32_t mask_length;
3397
3398
84
    if ((hf = ws_fopen(subnetspath, "r")) == NULL)
3399
84
        return false;
3400
3401
0
    while (fgetline(line, sizeof(line), hf) >= 0) {
3402
0
        if ((cp = strchr(line, '#')))
3403
0
            *cp = '\0';
3404
3405
0
        if ((cp = strtok(line, " \t")) == NULL)
3406
0
            continue;
3407
3408
        /* Expected format: <IPv6_address>/<prefix_length> */
3409
0
        cp2 = strchr(cp, '/');
3410
0
        if (cp2 == NULL)
3411
0
            continue;
3412
0
        *cp2 = '\0';
3413
0
        ++cp2;
3414
3415
0
        if (!ws_inet_pton6(cp, &host_addr))
3416
0
            continue;
3417
3418
0
        if (!ws_strtou32(cp2, NULL, &mask_length) || mask_length == 0 || mask_length > 128)
3419
0
            continue;
3420
3421
0
        if ((cp = strtok(NULL, " \t")) == NULL)
3422
0
            continue;
3423
3424
0
        subnet6_entry_set(&host_addr, mask_length, cp);
3425
0
    }
3426
3427
0
    fclose(hf);
3428
0
    return true;
3429
84
}
3430
3431
static void
3432
subnet6_name_lookup_init(const char *app_env_var_prefix)
3433
28
{
3434
28
    char *subnetspath;
3435
3436
3.61k
    for (uint32_t i = 0; i < SUBNETLENGTHSIZE_V6; ++i) {
3437
3.58k
        subnet_length_entries_v6[i].subnet_addresses = NULL;
3438
3.58k
        subnet_length_entries_v6[i].mask_length = i + 1;
3439
3.58k
        ipv6_get_subnet_mask((uint32_t)(i + 1), subnet_length_entries_v6[i].mask);
3440
3.58k
    }
3441
3442
    /* Check profile directory before personal configuration */
3443
28
    subnetspath = get_persconffile_path(ENAME_SUBNETS_V6, true, app_env_var_prefix);
3444
28
    if (!read_subnets_ipv6_file(subnetspath)) {
3445
28
        if (errno != ENOENT)
3446
0
            report_open_failure(subnetspath, errno, false);
3447
28
        g_free(subnetspath);
3448
28
        subnetspath = get_persconffile_path(ENAME_SUBNETS_V6, false, app_env_var_prefix);
3449
28
        if (!read_subnets_ipv6_file(subnetspath) && errno != ENOENT)
3450
0
            report_open_failure(subnetspath, errno, false);
3451
28
    }
3452
28
    g_free(subnetspath);
3453
3454
    /*
3455
     * Load the global IPv6 subnets file, if we have one.
3456
     */
3457
28
    subnetspath = get_datafile_path(ENAME_SUBNETS_V6, app_env_var_prefix);
3458
28
    if (!read_subnets_ipv6_file(subnetspath) && errno != ENOENT)
3459
0
        report_open_failure(subnetspath, errno, false);
3460
28
    g_free(subnetspath);
3461
28
}
3462
3463
/* SS7 PC Name Resolution Portion */
3464
static hashss7pc_t *
3465
new_ss7pc(const uint8_t ni, const uint32_t pc)
3466
0
{
3467
0
    hashss7pc_t *tp = wmem_new(addr_resolv_scope, hashss7pc_t);
3468
0
    tp->id = (ni<<24) + (pc&0xffffff);
3469
0
    tp->pc_addr[0] = '\0';
3470
0
    tp->name[0] = '\0';
3471
3472
0
    return tp;
3473
0
}
3474
3475
static hashss7pc_t *
3476
host_lookup_ss7pc(const uint8_t ni, const uint32_t pc)
3477
0
{
3478
0
    hashss7pc_t * volatile tp;
3479
0
    uint32_t id;
3480
3481
0
    id = (ni<<24) + (pc&0xffffff);
3482
3483
0
    tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
3484
0
    if (tp == NULL) {
3485
0
        tp = new_ss7pc(ni, pc);
3486
0
        wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
3487
0
    }
3488
3489
0
    return tp;
3490
0
}
3491
3492
void fill_unresolved_ss7pc(const char * pc_addr, const uint8_t ni, const uint32_t pc)
3493
0
{
3494
0
    hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
3495
3496
0
    (void) g_strlcpy(tp->pc_addr, pc_addr, MAXNAMELEN);
3497
0
}
3498
3499
const char *
3500
get_hostname_ss7pc(const uint8_t ni, const uint32_t pc)
3501
0
{
3502
0
    hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
3503
3504
    /* never resolved yet*/
3505
0
    if (tp->pc_addr[0] == '\0')
3506
0
        return tp->pc_addr;
3507
3508
    /* Don't have name in file */
3509
0
    if (tp->name[0] == '\0')
3510
0
        return tp->pc_addr;
3511
3512
0
    if (!gbl_resolv_flags.ss7pc_name)
3513
0
        return tp->pc_addr;
3514
3515
0
    return tp->name;
3516
0
}
3517
3518
static void
3519
add_ss7pc_name(const uint8_t ni, uint32_t pc, const char *name)
3520
0
{
3521
0
    hashss7pc_t *tp;
3522
0
    uint32_t id;
3523
3524
0
    if (!name || name[0] == '\0')
3525
0
        return;
3526
3527
0
    id = (ni<<24) + (pc&0xffffff);
3528
0
    tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
3529
0
    if (!tp) {
3530
0
        tp = new_ss7pc(ni, pc);
3531
0
        wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
3532
0
    }
3533
3534
0
    if (g_ascii_strcasecmp(tp->name, name)) {
3535
0
        (void) g_strlcpy(tp->name, name, MAXNAMELEN);
3536
0
    }
3537
0
}
3538
3539
static bool
3540
read_ss7pcs_file(const char *ss7pcspath)
3541
28
{
3542
28
    FILE *hf;
3543
28
    char line[MAX_LINELEN];
3544
28
    char *cp;
3545
28
    uint8_t ni;
3546
28
    uint32_t pc;
3547
28
    bool entry_found = false;
3548
3549
    /*
3550
    *  File format is Network Indicator (decimal)<dash>Point Code (Decimal)<tab/space>Hostname
3551
    */
3552
28
    if ((hf = ws_fopen(ss7pcspath, "r")) == NULL)
3553
28
        return false;
3554
3555
0
    while (fgetline(line, sizeof(line), hf) >= 0) {
3556
0
        if ((cp = strchr(line, '#')))
3557
0
            *cp = '\0';
3558
3559
0
        if ((cp = strtok(line, "-")) == NULL)
3560
0
            continue; /*no ni-pc separator*/
3561
0
        if (!ws_strtou8(cp, NULL, &ni))
3562
0
            continue;
3563
0
        if (ni > 3)
3564
0
             continue;
3565
3566
0
        if ((cp = strtok(NULL, " \t")) == NULL)
3567
0
            continue; /* no tokens for pc and name */
3568
0
        if (!ws_strtou32(cp, NULL, &pc))
3569
0
            continue;
3570
0
        if (pc >> 24 > 0)
3571
0
            continue;
3572
3573
0
        if ((cp = strtok(NULL, " \t")) == NULL)
3574
0
            continue; /* no host name */
3575
3576
0
        entry_found = true;
3577
0
        add_ss7pc_name(ni, pc, cp);
3578
0
    }
3579
3580
0
    fclose(hf);
3581
0
    return entry_found ? true : false;
3582
28
}
3583
3584
static void
3585
ss7pc_name_lookup_init(const char* app_env_var_prefix)
3586
28
{
3587
28
    char *ss7pcspath;
3588
3589
28
    ws_assert(ss7pc_hash_table == NULL);
3590
3591
28
    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
28
    ss7pcspath = get_persconffile_path(ENAME_SS7PCS, true, app_env_var_prefix);
3597
28
    if (!read_ss7pcs_file(ss7pcspath) && errno != ENOENT) {
3598
0
        report_open_failure(ss7pcspath, errno, false);
3599
0
    }
3600
28
    g_free(ss7pcspath);
3601
28
}
3602
3603
/* SS7PC Name Resolution End*/
3604
3605
/* TACS */
3606
static bool
3607
read_tacs_file(const char *tacspath)
3608
28
{
3609
28
    FILE *hf;
3610
28
    char line[MAX_LINELEN];
3611
28
    char *cp;
3612
28
    uint16_t id;
3613
3614
    /*
3615
    *  File format is TAC(decimal)<tab/space>TACName (no spaces)
3616
    */
3617
28
    if ((hf = ws_fopen(tacspath, "r")) == NULL)
3618
28
        return false;
3619
3620
0
    while (fgetline(line, sizeof(line), hf) >= 0) {
3621
0
        if ((cp = strchr(line, '#')))
3622
0
            *cp = '\0';
3623
3624
0
        if ((cp = strtok(line, " \t")) == NULL)
3625
0
            continue;
3626
3627
0
        if (sscanf(cp, "%" SCNu16, &id) != 1) {
3628
0
            continue;
3629
0
        }
3630
3631
0
        if ((cp = strtok(NULL, " \t\n")) == NULL)
3632
0
            continue; /* no TAC name */
3633
3634
0
        if (!wmem_map_lookup(tac_hash_table, GUINT_TO_POINTER(id))) {
3635
0
            char *buf = wmem_strdup(addr_resolv_scope, cp);
3636
0
            wmem_map_insert(tac_hash_table, GUINT_TO_POINTER(id), (void *)buf);
3637
0
        }
3638
0
    }
3639
3640
0
    fclose(hf);
3641
0
    return true;
3642
28
}
3643
3644
static void
3645
initialize_tacs(const char* app_env_var_prefix)
3646
28
{
3647
28
    char *tacspath;
3648
28
    ws_assert(tac_hash_table == NULL);
3649
28
    tac_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
3650
3651
28
    tacspath = get_persconffile_path(ENAME_TACS, true, app_env_var_prefix);
3652
28
    if (!read_tacs_file(tacspath) && errno != ENOENT) {
3653
0
        report_open_failure(tacspath, errno, false);
3654
0
    }
3655
28
    g_free(tacspath);
3656
28
}
3657
3658
static void
3659
tac_name_lookup_cleanup(void)
3660
14
{
3661
14
    tac_hash_table = NULL;
3662
14
}
3663
3664
const char *
3665
tac_name_lookup(const unsigned id)
3666
0
{
3667
0
    return (const char *)wmem_map_lookup(tac_hash_table, GUINT_TO_POINTER(id));
3668
0
}
3669
/* TAC END */
3670
3671
/*
3672
 *  External Functions
3673
 */
3674
3675
void
3676
addr_resolve_pref_init(module_t *nameres)
3677
14
{
3678
14
    prefs_register_bool_preference(nameres, "mac_name",
3679
14
            "Resolve MAC addresses",
3680
14
            "Resolve Ethernet MAC addresses to host names from the preferences"
3681
14
            " or system's Ethers file, or to a manufacturer based name.",
3682
14
            &gbl_resolv_flags.mac_name);
3683
3684
14
    prefs_register_bool_preference(nameres, "transport_name",
3685
14
            "Resolve transport names",
3686
14
            "Resolve TCP/UDP ports into service names",
3687
14
            &gbl_resolv_flags.transport_name);
3688
3689
14
    prefs_register_bool_preference(nameres, "network_name",
3690
14
            "Resolve network (IP) addresses",
3691
14
            "Resolve IPv4, IPv6, and IPX addresses into host names."
3692
14
            " The next set of check boxes determines how name resolution should be performed."
3693
14
            " If no other options are checked name resolution is made from Wireshark's host, subnets or subnetsipv6 file"
3694
14
            " and capture file name resolution blocks.",
3695
14
            &gbl_resolv_flags.network_name);
3696
3697
14
    prefs_register_bool_preference(nameres, "dns_pkt_addr_resolution",
3698
14
            "Use captured DNS packet data for name resolution",
3699
14
            "Use address/name pairs found in captured DNS packets for name resolution.",
3700
14
            &gbl_resolv_flags.dns_pkt_addr_resolution);
3701
3702
14
    prefs_register_bool_preference(nameres, "handshake_sni_addr_resolution",
3703
14
            "Use SNI information from captured handshake packets",
3704
14
            "Use the Server Name Indication found in TLS handshakes for name resolution.",
3705
14
            &gbl_resolv_flags.handshake_sni_addr_resolution);
3706
3707
14
    prefs_register_bool_preference(nameres, "use_external_name_resolver",
3708
14
            "Use your system's DNS settings for name resolution",
3709
14
            "Use your system's configured name resolver"
3710
14
            " (usually DNS) to resolve network names."
3711
14
            " Only applies when network name resolution"
3712
14
            " is enabled.",
3713
14
            &gbl_resolv_flags.use_external_net_name_resolver);
3714
3715
14
    prefs_register_bool_preference(nameres, "use_custom_dns_servers",
3716
14
            "Use a custom list of DNS servers for name resolution",
3717
14
            "Use a DNS Servers list to resolve network names if true.  If false, default information is used",
3718
14
            &use_custom_dns_server_list);
3719
3720
14
    static uat_field_t dns_server_uats_flds[] = {
3721
14
        UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, ipaddr, "IP address", dnsserver_uat_fld_ip_chk_cb, "IPv4 or IPv6 address"),
3722
14
        UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, tcp_port, "TCP Port", dnsserver_uat_fld_port_chk_cb, "Port Number (TCP)"),
3723
14
        UAT_FLD_CSTRING_OTHER(dnsserverlist_uats, udp_port, "UDP Port", dnsserver_uat_fld_port_chk_cb, "Port Number (UDP)"),
3724
14
        UAT_END_FIELDS
3725
14
    };
3726
3727
14
    dnsserver_uat = uat_new("DNS Servers",
3728
14
        sizeof(struct dns_server_data),
3729
14
        "addr_resolve_dns_servers",        /* filename */
3730
14
        true,                       /* from_profile */
3731
14
        &dnsserverlist_uats,        /* data_ptr */
3732
14
        &ndnsservers,               /* numitems_ptr */
3733
14
        UAT_AFFECTS_DISSECTION,
3734
14
        NULL,
3735
14
        dns_server_copy_cb,
3736
14
        NULL,
3737
14
        dns_server_free_cb,
3738
14
        c_ares_set_dns_servers,
3739
14
        NULL,
3740
14
        dns_server_uats_flds);
3741
14
    static const char *dnsserver_uat_defaults[] = { NULL, "53", "53" };
3742
14
    uat_set_default_values(dnsserver_uat, dnsserver_uat_defaults);
3743
14
    prefs_register_uat_preference(nameres, "dns_servers",
3744
14
        "DNS Servers",
3745
14
        "A table of IPv4 and IPv6 addresses of DNS servers to be used to resolve IP names and addresses",
3746
14
        dnsserver_uat);
3747
3748
14
    prefs_register_obsolete_preference(nameres, "concurrent_dns");
3749
3750
14
    prefs_register_uint_preference(nameres, "name_resolve_concurrency",
3751
14
            "Maximum concurrent requests",
3752
14
            "The maximum number of DNS requests that may"
3753
14
            " be active at any time. A large value (many"
3754
14
            " thousands) might overload the network or make"
3755
14
            " your DNS server behave badly.",
3756
14
            10,
3757
14
            &name_resolve_concurrency);
3758
3759
14
    prefs_register_obsolete_preference(nameres, "hosts_file_handling");
3760
3761
14
    prefs_register_bool_preference(nameres, "vlan_name",
3762
14
            "Resolve VLAN IDs",
3763
14
            "Resolve VLAN IDs to network names from the preferences \"vlans\" file."
3764
14
            " Format of the file is: \"ID<Tab>Name\"."
3765
14
            " One line per VLAN, e.g.: 1 Management",
3766
14
            &gbl_resolv_flags.vlan_name);
3767
3768
14
    prefs_register_bool_preference(nameres, "ss7_pc_name",
3769
14
            "Resolve SS7 PCs",
3770
14
            "Resolve SS7 Point Codes to node names from the profiles \"ss7pcs\" file."
3771
14
            " Format of the file is: \"Network_Indicator<Dash>PC_Decimal<Tab>Name\"."
3772
14
            " One line per Point Code, e.g.: 2-1234 MyPointCode1",
3773
14
            &gbl_resolv_flags.ss7pc_name);
3774
3775
14
    prefs_register_bool_preference(nameres, "tac_name",
3776
14
            "Resolve TAC",
3777
14
            "Resolve TAC to area names from the preferences \"tac\" file."
3778
14
            " Format of the file is: \"TAC(decimail)<Tab/space>Name\"."
3779
14
            " One line per TAC, e.g.: 30123 City1",
3780
14
            &gbl_resolv_flags.tac_name);
3781
3782
14
}
3783
3784
void addr_resolve_pref_apply(void)
3785
0
{
3786
0
    c_ares_set_dns_servers();
3787
0
    maxmind_db_pref_apply();
3788
0
}
3789
3790
void
3791
0
disable_name_resolution(void) {
3792
0
    gbl_resolv_flags.mac_name                           = false;
3793
0
    gbl_resolv_flags.network_name                       = false;
3794
0
    gbl_resolv_flags.transport_name                     = false;
3795
0
    gbl_resolv_flags.dns_pkt_addr_resolution            = false;
3796
0
    gbl_resolv_flags.handshake_sni_addr_resolution      = false;
3797
0
    gbl_resolv_flags.use_external_net_name_resolver     = false;
3798
0
    gbl_resolv_flags.vlan_name                          = false;
3799
0
    gbl_resolv_flags.ss7pc_name                         = false;
3800
0
    gbl_resolv_flags.maxmind_geoip                      = false;
3801
0
    gbl_resolv_flags.tac_name                           = false;
3802
0
}
3803
3804
bool
3805
0
host_name_lookup_process(void) {
3806
0
    struct timeval tv = { 0, 0 };
3807
0
    int nfds;
3808
0
    fd_set rfds, wfds;
3809
0
    bool nro = new_resolved_objects;
3810
3811
0
    new_resolved_objects = false;
3812
0
    nro |= maxmind_db_lookup_process();
3813
3814
0
    if (!async_dns_initialized)
3815
        /* c-ares not initialized. Bail out and cancel timers. */
3816
0
        return nro;
3817
3818
0
    process_async_dns_queue();
3819
3820
0
    FD_ZERO(&rfds);
3821
0
    FD_ZERO(&wfds);
3822
0
    nfds = ares_fds(ghba_chan, &rfds, &wfds);
3823
0
    if (nfds > 0) {
3824
0
        if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) { /* call to select() failed */
3825
            /* If it's interrupted by a signal, no need to put out a message */
3826
0
            if (errno != EINTR)
3827
0
                fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
3828
0
            return nro;
3829
0
        }
3830
0
        ares_process(ghba_chan, &rfds, &wfds);
3831
0
    }
3832
3833
    /* Any new entries? */
3834
0
    return nro;
3835
0
}
3836
3837
static void
3838
14
_host_name_lookup_cleanup(void) {
3839
14
    async_dns_queue_head = NULL;
3840
3841
14
    if (async_dns_initialized) {
3842
14
        ares_destroy(ghba_chan);
3843
14
        ares_destroy(ghbn_chan);
3844
14
    }
3845
14
#ifdef CARES_HAVE_ARES_LIBRARY_INIT
3846
14
    ares_library_cleanup();
3847
14
#endif
3848
14
    async_dns_initialized = false;
3849
14
}
3850
3851
const char *
3852
get_hostname(const unsigned addr)
3853
135
{
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
135
    hashipv4_t *tp = host_lookup(addr);
3869
3870
135
    if (!gbl_resolv_flags.network_name)
3871
135
        return tp->ip;
3872
3873
0
    tp->flags |= RESOLVED_ADDRESS_USED;
3874
3875
0
    return tp->name;
3876
135
}
3877
3878
char *
3879
get_hostname_wmem(wmem_allocator_t *allocator, const unsigned addr)
3880
67.3k
{
3881
67.3k
    if (!gbl_resolv_flags.network_name)
3882
67.3k
        return ip_addr_to_str(allocator, &addr);
3883
3884
0
    hashipv4_t *tp = host_lookup(addr);
3885
3886
0
    tp->flags |= RESOLVED_ADDRESS_USED;
3887
3888
0
    return wmem_strdup(allocator, tp->name);
3889
67.3k
}
3890
/* -------------------------- */
3891
3892
const char *
3893
get_hostname6(const ws_in6_addr *addr)
3894
1
{
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
1
    hashipv6_t *tp = host_lookup6(addr);
3899
3900
1
    if (!gbl_resolv_flags.network_name)
3901
1
        return tp->ip6;
3902
3903
0
    tp->flags |= RESOLVED_ADDRESS_USED;
3904
3905
0
    return tp->name;
3906
1
}
3907
3908
char *
3909
get_hostname6_wmem(wmem_allocator_t *allocator, const ws_in6_addr *addr)
3910
28.4k
{
3911
28.4k
    if (!gbl_resolv_flags.network_name)
3912
28.4k
        return ip6_to_str(allocator, addr);
3913
3914
0
    hashipv6_t *tp = host_lookup6(addr);
3915
3916
0
    tp->flags |= RESOLVED_ADDRESS_USED;
3917
3918
0
    return wmem_strdup(allocator, tp->name);
3919
28.4k
}
3920
/* -------------------------- */
3921
void
3922
add_ipv4_name(const unsigned addr, const char *name, bool static_entry)
3923
422
{
3924
422
    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
422
    if (!name || name[0] == '\0')
3931
63
        return;
3932
3933
359
    tp = (hashipv4_t *)wmem_map_lookup(ipv4_hash_table, GUINT_TO_POINTER(addr));
3934
359
    if (!tp) {
3935
61
        tp = new_ipv4(addr);
3936
61
        wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
3937
61
    }
3938
3939
359
    if (g_ascii_strcasecmp(tp->name, name) && (static_entry || !(tp->flags & STATIC_HOSTNAME))) {
3940
173
        (void) g_strlcpy(tp->name, name, MAXDNSNAMELEN);
3941
173
        new_resolved_objects = true;
3942
173
        if (static_entry)
3943
0
            tp->flags |= STATIC_HOSTNAME;
3944
173
    }
3945
359
    tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
3946
359
} /* add_ipv4_name */
3947
3948
/* -------------------------- */
3949
void
3950
add_ipv6_name(const ws_in6_addr *addrp, const char *name, const bool static_entry)
3951
496
{
3952
496
    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
496
    if (!name || name[0] == '\0')
3959
70
        return;
3960
3961
426
    tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addrp);
3962
426
    if (!tp) {
3963
193
        ws_in6_addr *addr_key;
3964
3965
193
        addr_key = wmem_new(addr_resolv_scope, ws_in6_addr);
3966
193
        tp = new_ipv6(addrp);
3967
193
        memcpy(addr_key, addrp, 16);
3968
193
        wmem_map_insert(ipv6_hash_table, addr_key, tp);
3969
193
    }
3970
3971
426
    if (g_ascii_strcasecmp(tp->name, name) && (static_entry || !(tp->flags & STATIC_HOSTNAME))) {
3972
206
        (void) g_strlcpy(tp->name, name, MAXDNSNAMELEN);
3973
206
        new_resolved_objects = true;
3974
206
        if (static_entry)
3975
0
            tp->flags |= STATIC_HOSTNAME;
3976
206
    }
3977
426
    tp->flags |= TRIED_RESOLVE_ADDRESS|NAME_RESOLVED;
3978
426
} /* add_ipv6_name */
3979
3980
static void
3981
add_manually_resolved_ipv4(void *key, void *value, void *user_data _U_)
3982
0
{
3983
0
    resolved_name_t *resolved_ipv4_entry = (resolved_name_t*)value;
3984
0
    add_ipv4_name(GPOINTER_TO_UINT(key), resolved_ipv4_entry->name, true);
3985
0
}
3986
3987
static void
3988
add_manually_resolved_ipv6(void *key, void *value, void *user_data _U_)
3989
0
{
3990
0
    resolved_name_t *resolved_ipv6_entry = (resolved_name_t*)value;
3991
0
    add_ipv6_name((ws_in6_addr*)key, resolved_ipv6_entry->name, true);
3992
0
}
3993
3994
static void
3995
add_manually_resolved(void)
3996
28
{
3997
28
    if (manually_resolved_ipv4_list) {
3998
28
        wmem_map_foreach(manually_resolved_ipv4_list, add_manually_resolved_ipv4, NULL);
3999
28
    }
4000
4001
28
    if (manually_resolved_ipv6_list) {
4002
28
        wmem_map_foreach(manually_resolved_ipv6_list, add_manually_resolved_ipv6, NULL);
4003
28
    }
4004
28
}
4005
4006
static void
4007
host_name_lookup_init(const char* app_env_var_prefix)
4008
28
{
4009
28
    char *hostspath;
4010
28
    unsigned i;
4011
4012
28
    ws_assert(ipxnet_hash_table == NULL);
4013
28
    ipxnet_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
4014
4015
28
    ws_assert(ipv4_hash_table == NULL);
4016
28
    ipv4_hash_table = wmem_map_new(addr_resolv_scope, g_direct_hash, g_direct_equal);
4017
4018
28
    ws_assert(ipv6_hash_table == NULL);
4019
28
    ipv6_hash_table = wmem_map_new(addr_resolv_scope, ipv6_oat_hash, ipv6_equal);
4020
4021
28
    ws_assert(async_dns_queue_head == NULL);
4022
28
    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
28
    if (manually_resolved_ipv4_list == NULL)
4032
14
        manually_resolved_ipv4_list = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
4033
4034
28
    if (manually_resolved_ipv6_list == NULL)
4035
14
        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
28
    hostspath = get_datafile_path(ENAME_HOSTS, app_env_var_prefix);
4041
28
    if (!read_hosts_file(hostspath, true) && errno != ENOENT) {
4042
0
        report_open_failure(hostspath, errno, false);
4043
0
    }
4044
28
    g_free(hostspath);
4045
    /*
4046
     * Load the user's hosts file no matter what, if they have one.
4047
     */
4048
28
    hostspath = get_persconffile_path(ENAME_HOSTS, true, app_env_var_prefix);
4049
28
    if (!read_hosts_file(hostspath, true) && errno != ENOENT) {
4050
0
        report_open_failure(hostspath, errno, false);
4051
0
    }
4052
28
    g_free(hostspath);
4053
28
#ifdef CARES_HAVE_ARES_LIBRARY_INIT
4054
28
    if (ares_library_init(ARES_LIB_INIT_ALL) == ARES_SUCCESS) {
4055
28
#endif
4056
        /* XXX - Check which options we should set */
4057
28
        if (ares_init_options(&ghba_chan, NULL, 0) == ARES_SUCCESS && ares_init_options(&ghbn_chan, NULL, 0) == ARES_SUCCESS) {
4058
28
            async_dns_initialized = true;
4059
28
            c_ares_set_dns_servers();
4060
28
        }
4061
28
#ifdef CARES_HAVE_ARES_LIBRARY_INIT
4062
28
    }
4063
28
#endif
4064
4065
28
    if (extra_hosts_files) {
4066
0
        for (i = 0; i < extra_hosts_files->len; i++) {
4067
0
            read_hosts_file((const char *) g_ptr_array_index(extra_hosts_files, i), true);
4068
0
        }
4069
0
    }
4070
4071
28
    subnet_name_lookup_init(app_env_var_prefix);
4072
28
    subnet6_name_lookup_init(app_env_var_prefix);
4073
4074
28
    add_manually_resolved();
4075
4076
28
    ss7pc_name_lookup_init(app_env_var_prefix);
4077
28
}
4078
4079
static void
4080
host_name_lookup_cleanup(void)
4081
14
{
4082
14
    uint32_t i, j;
4083
14
    sub_net_hashipv4_t *entry, *next_entry;
4084
4085
14
    _host_name_lookup_cleanup();
4086
4087
14
    ipxnet_hash_table = NULL;
4088
14
    ipv4_hash_table = NULL;
4089
14
    ipv6_hash_table = NULL;
4090
14
    ss7pc_hash_table = NULL;
4091
4092
462
    for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
4093
448
        if (subnet_length_entries[i].subnet_addresses != NULL) {
4094
0
            for (j = 0; j < HASHHOSTSIZE; j++) {
4095
0
                for (entry = subnet_length_entries[i].subnet_addresses[j];
4096
0
                     entry != NULL; entry = next_entry) {
4097
0
                    next_entry = entry->next;
4098
0
                    wmem_free(addr_resolv_scope, entry);
4099
0
                }
4100
0
            }
4101
0
            wmem_free(addr_resolv_scope, subnet_length_entries[i].subnet_addresses);
4102
0
            subnet_length_entries[i].subnet_addresses = NULL;
4103
0
        }
4104
448
    }
4105
4106
14
    have_subnet_entry = false;
4107
4108
1.80k
    for(i = 0; i < SUBNETLENGTHSIZE_V6; ++i) {
4109
1.79k
        sub_net_hashipv6_t *entry6, *next_entry6;
4110
1.79k
        if (subnet_length_entries_v6[i].subnet_addresses != NULL) {
4111
0
            for (j = 0; j < HASHHOSTSIZE; j++) {
4112
0
                for (entry6 = subnet_length_entries_v6[i].subnet_addresses[j];
4113
0
                     entry6 != NULL; entry6 = next_entry6) {
4114
0
                    next_entry6 = entry6->next;
4115
0
                    wmem_free(addr_resolv_scope, entry6);
4116
0
                }
4117
0
            }
4118
0
            wmem_free(addr_resolv_scope, subnet_length_entries_v6[i].subnet_addresses);
4119
0
            subnet_length_entries_v6[i].subnet_addresses = NULL;
4120
0
        }
4121
1.79k
    }
4122
14
    have_subnet_entry_v6 = false;
4123
4124
14
    new_resolved_objects = false;
4125
14
}
4126
4127
4128
void host_name_lookup_reset(const char* app_env_var_prefix)
4129
14
{
4130
14
    addr_resolv_cleanup();
4131
14
    addr_resolv_init(app_env_var_prefix);
4132
14
}
4133
4134
char *
4135
udp_port_to_display(wmem_allocator_t *allocator, unsigned port)
4136
26.5k
{
4137
4138
26.5k
    if (!gbl_resolv_flags.transport_name) {
4139
26.5k
        return wmem_utoa(allocator, port);
4140
26.5k
    }
4141
4142
0
    return wmem_strdup(allocator, serv_name_lookup(PT_UDP, port));
4143
4144
26.5k
} /* udp_port_to_display */
4145
4146
char *
4147
dccp_port_to_display(wmem_allocator_t *allocator, unsigned port)
4148
0
{
4149
4150
0
    if (!gbl_resolv_flags.transport_name) {
4151
0
        return wmem_utoa(allocator, port);
4152
0
    }
4153
4154
0
    return wmem_strdup(allocator, serv_name_lookup(PT_DCCP, port));
4155
4156
0
} /* dccp_port_to_display */
4157
4158
char *
4159
tcp_port_to_display(wmem_allocator_t *allocator, unsigned port)
4160
31.3k
{
4161
4162
31.3k
    if (!gbl_resolv_flags.transport_name) {
4163
31.3k
        return wmem_utoa(allocator, port);
4164
31.3k
    }
4165
4166
0
    return wmem_strdup(allocator, serv_name_lookup(PT_TCP, port));
4167
4168
31.3k
} /* tcp_port_to_display */
4169
4170
char *
4171
sctp_port_to_display(wmem_allocator_t *allocator, unsigned port)
4172
31.7k
{
4173
4174
31.7k
    if (!gbl_resolv_flags.transport_name) {
4175
31.7k
        return wmem_utoa(allocator, port);
4176
31.7k
    }
4177
4178
0
    return wmem_strdup(allocator, serv_name_lookup(PT_SCTP, port));
4179
4180
31.7k
} /* sctp_port_to_display */
4181
4182
char *
4183
port_with_resolution_to_str(wmem_allocator_t *scope, port_type proto, unsigned port)
4184
166k
{
4185
166k
    const char *port_str;
4186
4187
166k
    if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
4188
        /* No name resolution support, just return port string */
4189
166k
        return wmem_strdup_printf(scope, "%u", port);
4190
166k
    }
4191
0
    port_str = serv_name_lookup(proto, port);
4192
0
    ws_assert(port_str);
4193
0
    return wmem_strdup_printf(scope, "%s (%u)", port_str, port);
4194
166k
}
4195
4196
int
4197
port_with_resolution_to_str_buf(char *buf, unsigned long buf_size, port_type proto, unsigned port)
4198
0
{
4199
0
    const char *port_str;
4200
4201
0
    if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) {
4202
        /* No name resolution support, just return port string */
4203
0
        return snprintf(buf, buf_size, "%u", port);
4204
0
    }
4205
0
    port_str = serv_name_lookup(proto, port);
4206
0
    ws_assert(port_str);
4207
0
    return snprintf(buf, buf_size, "%s (%u)", port_str, port);
4208
0
}
4209
4210
const char *
4211
get_ether_name(const uint8_t *addr)
4212
72.5k
{
4213
72.5k
    hashether_t *tp;
4214
72.5k
    bool resolve = gbl_resolv_flags.mac_name;
4215
4216
72.5k
    tp = eth_name_lookup(addr, resolve);
4217
4218
72.5k
    return resolve ? tp->resolved_name : tp->hexaddr;
4219
4220
72.5k
} /* get_ether_name */
4221
4222
const char *
4223
tvb_get_ether_name(tvbuff_t *tvb, unsigned offset)
4224
0
{
4225
0
    return get_ether_name(tvb_get_ptr(tvb, offset, 6));
4226
0
}
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
819
{
4234
819
    hashether_t *tp;
4235
4236
    /* Initialize ether structs if we're the first
4237
     * ether-related function called */
4238
819
    if (!gbl_resolv_flags.mac_name)
4239
0
        return NULL;
4240
4241
    /* eth_name_lookup will create a (resolved) hash entry
4242
     * if it doesn't exist, so it never returns NULL */
4243
819
    tp = eth_name_lookup(addr, true);
4244
4245
819
    if ((tp->flags & (NAME_RESOLVED | NAME_RESOLVED_PREFIX)) == NAME_RESOLVED) {
4246
        /* Name is from an exact match, not a prefix/OUI */
4247
0
        return tp->resolved_name;
4248
0
    }
4249
819
    else {
4250
        /* Name was created */
4251
819
        return NULL;
4252
819
    }
4253
819
}
4254
4255
void
4256
add_ether_byip(const unsigned ip, const uint8_t *eth)
4257
0
{
4258
0
    hashipv4_t *tp;
4259
4260
    /* first check that IP address can be resolved */
4261
0
    if (!gbl_resolv_flags.network_name)
4262
0
        return;
4263
4264
0
    tp = host_lookup(ip);
4265
4266
    /*
4267
     * Was this IP address resolved to a host name?
4268
     */
4269
0
    if (tp->flags & NAME_RESOLVED) {
4270
        /*
4271
         * Yes, so add an entry in the ethers hashtable resolving
4272
         * the MAC address to that name.
4273
         */
4274
0
        add_eth_name(eth, tp->name, false);
4275
0
    }
4276
4277
0
} /* add_ether_byip */
4278
4279
char *
4280
get_ipxnet_name(wmem_allocator_t *allocator, const uint32_t addr)
4281
0
{
4282
4283
0
    if (!gbl_resolv_flags.network_name) {
4284
0
        return ipxnet_to_str_punct(allocator, addr, '\0');
4285
0
    }
4286
4287
0
    return ipxnet_name_lookup(allocator, addr);
4288
4289
0
} /* get_ipxnet_name */
4290
4291
char *
4292
get_vlan_name(wmem_allocator_t *allocator, const uint16_t id)
4293
0
{
4294
4295
0
    if (!gbl_resolv_flags.vlan_name) {
4296
0
        return NULL;
4297
0
    }
4298
4299
0
    return wmem_strdup(allocator, vlan_name_lookup(id));
4300
4301
0
} /* get_vlan_name */
4302
4303
const char *
4304
get_manuf_name(const uint8_t *addr, size_t size)
4305
4
{
4306
4
    hashmanuf_t *manuf_value;
4307
4308
4
    ws_return_val_if(size < 3, NULL);
4309
4310
4
    manuf_value = manuf_name_lookup(addr, size);
4311
4
    if (gbl_resolv_flags.mac_name && ((manuf_value->flags & NAME_RESOLVED) == NAME_RESOLVED))
4312
3
        return manuf_value->resolved_name;
4313
4314
1
    return manuf_value->hexaddr;
4315
4316
4
} /* get_manuf_name */
4317
4318
const char *
4319
tvb_get_manuf_name(tvbuff_t *tvb, unsigned offset)
4320
4
{
4321
4
    uint8_t buf[3] = { 0 };
4322
4
    tvb_memcpy(tvb, buf, offset, 3);
4323
4
    return get_manuf_name(buf, sizeof(buf));
4324
4
}
4325
4326
const char *
4327
get_manuf_name_if_known(const uint8_t *addr, size_t size)
4328
55.6k
{
4329
55.6k
    hashmanuf_t *manuf_value;
4330
4331
55.6k
    ws_return_val_if(size < 3, NULL);
4332
4333
55.6k
    manuf_value = manuf_name_lookup(addr, size);
4334
55.6k
    if (manuf_value != NULL && ((manuf_value->flags & NAME_RESOLVED) == NAME_RESOLVED)) {
4335
17.3k
        return manuf_value->resolved_longname;
4336
17.3k
    }
4337
4338
38.2k
    if (size >= 6) {
4339
        /* Try the global manuf tables. */
4340
38.1k
        const char *short_name, *long_name;
4341
38.1k
        short_name = ws_manuf_lookup_str(addr, &long_name);
4342
38.1k
        if (short_name != NULL) {
4343
            /* Found it */
4344
601
            return long_name;
4345
601
        }
4346
38.1k
    }
4347
4348
37.6k
    return NULL;
4349
4350
38.2k
} /* get_manuf_name_if_known */
4351
4352
const char *
4353
uint_get_manuf_name_if_known(const uint32_t manuf_key)
4354
1.85k
{
4355
1.85k
    uint8_t addr[6] = { 0 };
4356
1.85k
    addr[0] = (manuf_key >> 16) & 0xFF;
4357
1.85k
    addr[1] = (manuf_key >> 8) & 0xFF;
4358
1.85k
    addr[2] = manuf_key & 0xFF;
4359
4360
1.85k
    return get_manuf_name_if_known(addr, sizeof(addr));
4361
1.85k
}
4362
4363
const char *
4364
tvb_get_manuf_name_if_known(tvbuff_t *tvb, unsigned offset)
4365
120
{
4366
120
    uint8_t buf[3] = { 0 };
4367
120
    tvb_memcpy(tvb, buf, offset, 3);
4368
120
    return get_manuf_name_if_known(buf, sizeof(buf));
4369
120
}
4370
4371
bool get_hash_manuf_used(hashmanuf_t* manuf)
4372
0
{
4373
0
    return ((manuf->flags & TRIED_OR_RESOLVED_MASK) == TRIED_OR_RESOLVED_MASK);
4374
0
}
4375
4376
char* get_hash_manuf_resolved_name(hashmanuf_t* manuf)
4377
0
{
4378
0
    return manuf->resolved_longname;
4379
0
}
4380
4381
const char *
4382
get_eui64_name(const uint8_t *addr)
4383
3.28k
{
4384
3.28k
    hasheui64_t *tp;
4385
3.28k
    bool resolve = gbl_resolv_flags.mac_name;
4386
4387
3.28k
    tp = eui64_name_lookup(addr, resolve);
4388
4389
3.28k
    return resolve ? tp->resolved_name : tp->hexaddr;
4390
4391
3.28k
} /* get_eui64_name */
4392
4393
char *
4394
eui64_to_display(wmem_allocator_t *allocator, const uint64_t addr_eui64)
4395
3.01k
{
4396
3.01k
    uint8_t addr[EUI64_ADDR_LEN];
4397
4398
3.01k
    phtonu64(addr, addr_eui64);
4399
4400
3.01k
    const char *result = get_eui64_name(addr);
4401
4402
3.01k
    return wmem_strdup(allocator, result);
4403
3.01k
} /* eui64_to_display */
4404
4405
0
#define GHI_TIMEOUT (250 * 1000)
4406
static void
4407
0
c_ares_ghi_cb(void *arg, int status, int timeouts _U_, 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
0
    async_hostent_t *ahp = (async_hostent_t *)arg;
4415
0
    if (status == ARES_SUCCESS && hp && ahp && hp->h_length == ahp->addr_size) {
4416
0
        memcpy(ahp->addrp, hp->h_addr, hp->h_length);
4417
0
        ahp->copied = hp->h_length;
4418
0
    }
4419
0
}
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
4425
get_host_ipaddr(const char *host, uint32_t *addrp)
4426
0
{
4427
0
    struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
4428
0
    int nfds;
4429
0
    fd_set rfds, wfds;
4430
0
    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
0
    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
0
        if (!gbl_resolv_flags.network_name ||
4450
0
                !gbl_resolv_flags.use_external_net_name_resolver) {
4451
0
            return false;
4452
0
        }
4453
4454
0
        if (!async_dns_initialized || name_resolve_concurrency < 1) {
4455
0
            return false;
4456
0
        }
4457
0
        ahe.addr_size = (int) sizeof (struct in_addr);
4458
0
        ahe.copied = 0;
4459
0
        ahe.addrp = addrp;
4460
0
        ares_gethostbyname(ghbn_chan, host, AF_INET, c_ares_ghi_cb, &ahe);
4461
0
        FD_ZERO(&rfds);
4462
0
        FD_ZERO(&wfds);
4463
0
        nfds = ares_fds(ghbn_chan, &rfds, &wfds);
4464
0
        if (nfds > 0) {
4465
0
            tvp = ares_timeout(ghbn_chan, &tv, &tv);
4466
0
            if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
4467
                /* If it's interrupted by a signal, no need to put out a message */
4468
0
                if (errno != EINTR)
4469
0
                    fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
4470
0
                return false;
4471
0
            }
4472
0
            ares_process(ghbn_chan, &rfds, &wfds);
4473
0
        }
4474
0
        ares_cancel(ghbn_chan);
4475
0
        if (ahe.addr_size == ahe.copied) {
4476
0
            return true;
4477
0
        }
4478
0
        return false;
4479
0
    }
4480
4481
0
    return true;
4482
0
}
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
4490
get_host_ipaddr6(const char *host, ws_in6_addr *addrp)
4491
0
{
4492
0
    struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
4493
0
    int nfds;
4494
0
    fd_set rfds, wfds;
4495
0
    async_hostent_t ahe;
4496
4497
0
    if (str_to_ip6(host, addrp))
4498
0
        return true;
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
0
    if (!gbl_resolv_flags.network_name ||
4515
0
            !gbl_resolv_flags.use_external_net_name_resolver) {
4516
0
        return false;
4517
0
    }
4518
4519
    /* try FQDN */
4520
0
    if (!async_dns_initialized || name_resolve_concurrency < 1) {
4521
0
        return false;
4522
0
    }
4523
0
    ahe.addr_size = (int) sizeof (ws_in6_addr);
4524
0
    ahe.copied = 0;
4525
0
    ahe.addrp = addrp;
4526
0
    ares_gethostbyname(ghbn_chan, host, AF_INET6, c_ares_ghi_cb, &ahe);
4527
0
    FD_ZERO(&rfds);
4528
0
    FD_ZERO(&wfds);
4529
0
    nfds = ares_fds(ghbn_chan, &rfds, &wfds);
4530
0
    if (nfds > 0) {
4531
0
        tvp = ares_timeout(ghbn_chan, &tv, &tv);
4532
0
        if (select(nfds, &rfds, &wfds, NULL, tvp) == -1) { /* call to select() failed */
4533
            /* If it's interrupted by a signal, no need to put out a message */
4534
0
            if (errno != EINTR)
4535
0
                fprintf(stderr, "Warning: call to select() failed, error is %s\n", g_strerror(errno));
4536
0
            return false;
4537
0
        }
4538
0
        ares_process(ghbn_chan, &rfds, &wfds);
4539
0
    }
4540
0
    ares_cancel(ghbn_chan);
4541
0
    if (ahe.addr_size == ahe.copied) {
4542
0
        return true;
4543
0
    }
4544
4545
0
    return false;
4546
0
}
4547
4548
wmem_map_t *
4549
get_manuf_hashtable(void)
4550
0
{
4551
0
    return manuf_hashtable;
4552
0
}
4553
4554
wmem_map_t *
4555
get_wka_hashtable(void)
4556
0
{
4557
0
    return wka_hashtable;
4558
0
}
4559
4560
wmem_map_t *
4561
get_eth_hashtable(void)
4562
0
{
4563
0
    return eth_hashtable;
4564
0
}
4565
4566
wmem_map_t *
4567
get_serv_port_hashtable(void)
4568
0
{
4569
0
    return serv_port_hashtable;
4570
0
}
4571
4572
wmem_map_t *
4573
get_ipxnet_hash_table(void)
4574
0
{
4575
0
        return ipxnet_hash_table;
4576
0
}
4577
4578
wmem_map_t *
4579
get_vlan_hash_table(void)
4580
0
{
4581
0
        return vlan_hash_table;
4582
0
}
4583
4584
wmem_map_t *
4585
get_ipv4_hash_table(void)
4586
0
{
4587
0
        return ipv4_hash_table;
4588
0
}
4589
4590
wmem_map_t *
4591
get_ipv6_hash_table(void)
4592
0
{
4593
0
        return ipv6_hash_table;
4594
0
}
4595
/* Initialize all the address resolution subsystems in this file */
4596
void
4597
addr_resolv_init(const char* app_env_var_prefix)
4598
28
{
4599
28
    ws_assert(addr_resolv_scope == NULL);
4600
28
    addr_resolv_scope = wmem_allocator_new(WMEM_ALLOCATOR_BLOCK);
4601
28
    initialize_services(app_env_var_prefix);
4602
28
    initialize_ethers(app_env_var_prefix);
4603
28
    initialize_ipxnets(app_env_var_prefix);
4604
28
    initialize_vlans(app_env_var_prefix);
4605
28
    initialize_enterprises(app_env_var_prefix);
4606
28
    host_name_lookup_init(app_env_var_prefix);
4607
28
    initialize_tacs(app_env_var_prefix);
4608
28
}
4609
4610
/* Clean up all the address resolution subsystems in this file */
4611
void
4612
addr_resolv_cleanup(void)
4613
14
{
4614
14
    vlan_name_lookup_cleanup();
4615
14
    service_name_lookup_cleanup();
4616
14
    ethers_cleanup();
4617
14
    ipx_name_lookup_cleanup();
4618
14
    enterprises_cleanup();
4619
14
    host_name_lookup_cleanup();
4620
14
    tac_name_lookup_cleanup();
4621
4622
14
    wmem_destroy_allocator(addr_resolv_scope);
4623
14
    addr_resolv_scope = NULL;
4624
14
}
4625
4626
bool
4627
str_to_ip(const char *str, void *dst)
4628
388
{
4629
388
    return ws_inet_pton4(str, (uint32_t *)dst);
4630
388
}
4631
4632
bool
4633
str_to_ip6(const char *str, void *dst)
4634
17
{
4635
17
    return ws_inet_pton6(str, (ws_in6_addr *)dst);
4636
17
}
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
4644
str_to_eth(const char *str, uint8_t (*eth_bytes)[6])
4645
0
{
4646
0
    ether_t eth;
4647
0
    unsigned mask;
4648
4649
0
    if (!parse_ether_address(str, &eth, &mask, false))
4650
0
        return false;
4651
4652
0
    if (mask == 48) {
4653
0
        memcpy(eth_bytes, eth.addr, 6);
4654
0
    }
4655
    return true;
4656
0
}
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
 */