Coverage Report

Created: 2026-10-24 08:16

/work/toxcore/LAN_discovery.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2026 The TokTok team.
3
 * Copyright © 2013 Tox project.
4
 */
5
6
/**
7
 * LAN discovery implementation.
8
 */
9
#include "LAN_discovery.h"
10
11
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
12
// The mingw32/64 Windows library warns about including winsock2.h after
13
// windows.h even though with the above it's a valid thing to do. So, to make
14
// mingw32 headers happy, we include winsock2.h first.
15
#include <winsock2.h>
16
17
#include <windows.h>
18
#include <ws2tcpip.h>
19
20
#include <iphlpapi.h>
21
#endif /* WIN32 */
22
23
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
24
#include <netinet/in.h>
25
#include <sys/ioctl.h>
26
#include <sys/socket.h>
27
#include <sys/types.h>
28
#include <unistd.h>
29
#endif /* Linux/BSD */
30
31
#ifdef __linux__
32
#include <linux/if.h>
33
#endif /* Linux */
34
35
#if defined(__FreeBSD__) || defined(__DragonFly__)
36
#include <net/if.h>
37
#endif /* BSD */
38
39
#include "attributes.h"
40
#include "ccompat.h"
41
#include "crypto_core.h"
42
#include "mem.h"
43
#include "network.h"
44
45
15
#define MAX_INTERFACES 16
46
47
struct Broadcast_Info {
48
    const Memory *_Nonnull mem;
49
50
    uint32_t count;
51
    IP ips[MAX_INTERFACES];
52
};
53
54
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
55
56
static Broadcast_Info *_Nullable fetch_broadcast_info(const Memory *_Nonnull mem, const Network *_Nonnull ns)
57
{
58
    Broadcast_Info *broadcast = (Broadcast_Info *)mem_alloc(mem, sizeof(Broadcast_Info));
59
60
    if (broadcast == nullptr) {
61
        return nullptr;
62
    }
63
64
    broadcast->mem = mem;
65
66
    IP_ADAPTER_INFO *adapter_info = (IP_ADAPTER_INFO *)mem_balloc(mem, sizeof(IP_ADAPTER_INFO));
67
68
    if (adapter_info == nullptr) {
69
        mem_delete(mem, broadcast);
70
        return nullptr;
71
    }
72
73
    unsigned long out_buf_len = sizeof(IP_ADAPTER_INFO);
74
75
    if (GetAdaptersInfo(adapter_info, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
76
        mem_delete(mem, adapter_info);
77
        IP_ADAPTER_INFO *new_adapter_info = (IP_ADAPTER_INFO *)mem_balloc(mem, out_buf_len);
78
79
        if (new_adapter_info == nullptr) {
80
            mem_delete(mem, broadcast);
81
            return nullptr;
82
        }
83
84
        adapter_info = new_adapter_info;
85
    }
86
87
    const int ret = GetAdaptersInfo(adapter_info, &out_buf_len);
88
89
    if (ret == NO_ERROR) {
90
        IP_ADAPTER_INFO *adapter = adapter_info;
91
92
        while (adapter != nullptr) {
93
            IP if_ip = {0};
94
            IP subnet_mask = {0};
95
96
            if (addr_parse_ip(adapter->IpAddressList.IpMask.String, &subnet_mask)
97
                    && addr_parse_ip(adapter->IpAddressList.IpAddress.String, &if_ip)) {
98
                if (net_family_is_ipv4(if_ip.family) && net_family_is_ipv4(subnet_mask.family)) {
99
                    if (if_ip.ip.v4.uint32 != 0 && subnet_mask.ip.v4.uint32 != 0) {
100
                        IP *ip = &broadcast->ips[broadcast->count];
101
                        ip->family = net_family_ipv4();
102
                        ip->ip.v4.uint32 = if_ip.ip.v4.uint32 | ~subnet_mask.ip.v4.uint32;
103
                        ++broadcast->count;
104
105
                        if (broadcast->count >= MAX_INTERFACES) {
106
                            break;
107
                        }
108
                    }
109
                }
110
            }
111
112
            adapter = adapter->Next;
113
        }
114
    }
115
116
    if (adapter_info != nullptr) {
117
        mem_delete(mem, adapter_info);
118
    }
119
120
    return broadcast;
121
}
122
123
#elif !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && (defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__))
124
125
static bool ip4_is_local(const IP4 *_Nonnull ip4);
126
127
static Broadcast_Info *_Nullable fetch_broadcast_info(const Memory *_Nonnull mem, const Network *_Nonnull ns)
128
39
{
129
39
    Broadcast_Info *broadcast = (Broadcast_Info *)mem_alloc(mem, sizeof(Broadcast_Info));
130
131
39
    if (broadcast == nullptr) {
132
1
        return nullptr;
133
1
    }
134
135
38
    broadcast->mem = mem;
136
137
    /* Not sure how many platforms this will run on,
138
     * so it's wrapped in `__linux__` for now.
139
     * Definitely won't work like this on Windows...
140
     */
141
38
    const Socket sock = net_socket(ns, net_family_ipv4(), TOX_SOCK_STREAM, 0);
142
143
38
    if (!sock_valid(sock)) {
144
1
        mem_delete(mem, broadcast);
145
1
        return nullptr;
146
1
    }
147
148
    /* Configure ifconf for the ioctl call. */
149
37
    struct ifreq i_faces[MAX_INTERFACES] = {{{0}}};
150
151
37
    struct ifconf ifc;
152
37
    ifc.ifc_buf = (char *)i_faces;
153
37
    ifc.ifc_len = sizeof(i_faces);
154
155
37
    if (ioctl(net_socket_to_native(sock), SIOCGIFCONF, &ifc) < 0) {
156
29
        kill_sock(ns, sock);
157
29
        mem_delete(mem, broadcast);
158
29
        return nullptr;
159
29
    }
160
161
    /* `ifc.ifc_len` is set by the `ioctl()` to the actual length used.
162
     * On usage of the complete array the call should be repeated with
163
     * a larger array, not done (640kB and 16 interfaces shall be
164
     * enough, for everybody!)
165
     */
166
8
    const int n = ifc.ifc_len / sizeof(struct ifreq);
167
168
24
    for (int i = 0; i < n; ++i) {
169
        /* there are interfaces with are incapable of broadcast
170
         * on Linux, `lo` has no broadcast address, but this function returns `>=0` */
171
16
        if (ioctl(net_socket_to_native(sock), SIOCGIFBRDADDR, &i_faces[i]) < 0) {
172
1
            continue;
173
1
        }
174
175
        /* moot check: only AF_INET returned (backwards compat.) */
176
15
        if (i_faces[i].ifr_broadaddr.sa_family != AF_INET) {
177
0
            continue;
178
0
        }
179
180
15
        const struct sockaddr_in *broadaddr4 = (const struct sockaddr_in *)(void *)&i_faces[i].ifr_broadaddr;
181
182
15
        if (broadcast->count >= MAX_INTERFACES) {
183
0
            break;
184
0
        }
185
186
15
        IP *ip = &broadcast->ips[broadcast->count];
187
15
        ip->family = net_family_ipv4();
188
15
        ip->ip.v4.uint32 = broadaddr4->sin_addr.s_addr;
189
190
        // if no broadcast address
191
15
        if (ip->ip.v4.uint32 == 0) {
192
6
            if (ioctl(net_socket_to_native(sock), SIOCGIFADDR, &i_faces[i]) < 0) {
193
0
                continue;
194
0
            }
195
196
6
            const struct sockaddr_in *addr4 = (const struct sockaddr_in *)(void *)&i_faces[i].ifr_addr;
197
198
199
6
            IP4 ip4_staging;
200
6
            ip4_staging.uint32 = addr4->sin_addr.s_addr;
201
202
6
            if (ip4_is_local(&ip4_staging)) {
203
                // this is 127.x.x.x
204
6
                ip->ip.v4.uint32 = ip4_staging.uint32;
205
6
            } else {
206
                // give up.
207
0
                continue;
208
0
            }
209
6
        }
210
211
15
        ++broadcast->count;
212
15
    }
213
214
8
    kill_sock(ns, sock);
215
216
8
    return broadcast;
217
37
}
218
219
#else // TODO(irungentoo): Other platforms?
220
221
static Broadcast_Info *_Nullable fetch_broadcast_info(const Memory *_Nonnull mem, const Network *_Nonnull ns)
222
1.44k
{
223
1.44k
    Broadcast_Info *broadcast = (Broadcast_Info *)mem_alloc(mem, sizeof(Broadcast_Info));
224
225
1.44k
    if (broadcast == nullptr) {
226
13
        return nullptr;
227
13
    }
228
229
1.43k
    broadcast->mem = mem;
230
231
1.43k
    return broadcast;
232
1.44k
}
233
234
#endif /* platforms */
235
236
/** @brief Send packet to all IPv4 broadcast addresses
237
 *
238
 * @retval true if sent to at least one broadcast target.
239
 * @retval false on failure to find any valid broadcast target.
240
 */
241
static bool send_broadcasts(const Networking_Core *_Nonnull net, const Broadcast_Info *_Nonnull broadcast, uint16_t port, const uint8_t *_Nonnull data, uint16_t length)
242
198
{
243
198
    if (broadcast->count == 0) {
244
77
        return false;
245
77
    }
246
247
363
    for (uint32_t i = 0; i < broadcast->count; ++i) {
248
242
        IP_Port ip_port;
249
242
        ip_port.ip = broadcast->ips[i];
250
242
        ip_port.port = port;
251
242
        sendpacket(net, &ip_port, data, length);
252
242
    }
253
254
121
    return true;
255
198
}
256
257
/** Return the broadcast ip. */
258
static IP broadcast_ip(Family family_socket, Family family_broadcast)
259
330
{
260
330
    IP ip;
261
330
    ip_reset(&ip);
262
263
330
    if (net_family_is_ipv6(family_socket)) {
264
264
        if (net_family_is_ipv6(family_broadcast)) {
265
132
            ip.family = net_family_ipv6();
266
            /* `FF02::1` is - according to RFC 4291 - multicast all-nodes link-local */
267
            /* `FE80::*:` MUST be exact, for that we would need to look over all
268
             * interfaces and check in which status they are */
269
132
            ip.ip.v6.uint8[0] = 0xFF;
270
132
            ip.ip.v6.uint8[1] = 0x02;
271
132
            ip.ip.v6.uint8[15] = 0x01;
272
132
        } else if (net_family_is_ipv4(family_broadcast)) {
273
132
            ip.family = net_family_ipv6();
274
132
            ip.ip.v6 = get_ip6_broadcast();
275
132
        }
276
264
    } else if (net_family_is_ipv4(family_socket) && net_family_is_ipv4(family_broadcast)) {
277
22
        ip.family = net_family_ipv4();
278
22
        ip.ip.v4 = get_ip4_broadcast();
279
22
    }
280
281
330
    return ip;
282
330
}
283
284
static bool ip4_is_local(const IP4 *ip4)
285
3.28M
{
286
    /* Loopback. */
287
3.28M
    return ip4->uint8[0] == 127;
288
3.28M
}
289
290
/**
291
 * Is IP a local ip or not.
292
 */
293
bool ip_is_local(const IP *ip)
294
3.35M
{
295
3.35M
    if (net_family_is_ipv4(ip->family)) {
296
3.28M
        return ip4_is_local(&ip->ip.v4);
297
3.28M
    }
298
299
    /* embedded IPv4-in-IPv6 */
300
73.5k
    if (ipv6_ipv4_in_v6(&ip->ip.v6)) {
301
0
        IP4 ip4;
302
0
        ip4.uint32 = ip->ip.v6.uint32[3];
303
0
        return ip4_is_local(&ip4);
304
0
    }
305
306
    /* localhost in IPv6 (::1) */
307
73.5k
    return ip->ip.v6.uint64[0] == 0 && ip->ip.v6.uint32[2] == 0 && ip->ip.v6.uint32[3] == net_htonl(1);
308
73.5k
}
309
310
static bool ip4_is_lan(const IP4 *_Nonnull ip4)
311
265k
{
312
    /* 10.0.0.0 to 10.255.255.255 range. */
313
265k
    if (ip4->uint8[0] == 10) {
314
84
        return true;
315
84
    }
316
317
    /* 172.16.0.0 to 172.31.255.255 range. */
318
265k
    if (ip4->uint8[0] == 172 && ip4->uint8[1] >= 16 && ip4->uint8[1] <= 31) {
319
23.2k
        return true;
320
23.2k
    }
321
322
    /* 192.168.0.0 to 192.168.255.255 range. */
323
242k
    if (ip4->uint8[0] == 192 && ip4->uint8[1] == 168) {
324
0
        return true;
325
0
    }
326
327
    /* 169.254.1.0 to 169.254.254.255 range. */
328
242k
    if (ip4->uint8[0] == 169 && ip4->uint8[1] == 254 && ip4->uint8[2] != 0
329
242k
            && ip4->uint8[2] != 255) {
330
0
        return true;
331
0
    }
332
333
    /* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10)
334
     * (shared address space to stack another layer of NAT) */
335
242k
    return (ip4->uint8[0] == 100) && ((ip4->uint8[1] & 0xC0) == 0x40);
336
242k
}
337
338
bool ip_is_lan(const IP *ip)
339
3.35M
{
340
3.35M
    if (ip_is_local(ip)) {
341
3.01M
        return true;
342
3.01M
    }
343
344
339k
    if (net_family_is_ipv4(ip->family)) {
345
265k
        return ip4_is_lan(&ip->ip.v4);
346
265k
    }
347
348
73.3k
    if (net_family_is_ipv6(ip->family)) {
349
        /* autogenerated for each interface: `FE80::*` (up to `FEBF::*`)
350
         * `FF02::1` is - according to RFC 4291 - multicast all-nodes link-local */
351
0
        if (((ip->ip.v6.uint8[0] == 0xFF) && (ip->ip.v6.uint8[1] < 3) && (ip->ip.v6.uint8[15] == 1)) ||
352
0
                ((ip->ip.v6.uint8[0] == 0xFE) && ((ip->ip.v6.uint8[1] & 0xC0) == 0x80))) {
353
0
            return true;
354
0
        }
355
356
        /* embedded IPv4-in-IPv6 */
357
0
        if (ipv6_ipv4_in_v6(&ip->ip.v6)) {
358
0
            IP4 ip4;
359
0
            ip4.uint32 = ip->ip.v6.uint32[3];
360
0
            return ip4_is_lan(&ip4);
361
0
        }
362
0
    }
363
364
73.3k
    return false;
365
73.3k
}
366
367
bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk,
368
                        uint16_t port)
369
198
{
370
198
    if (broadcast == nullptr) {
371
0
        return false;
372
0
    }
373
374
198
    uint8_t data[CRYPTO_PUBLIC_KEY_SIZE + 1];
375
198
    data[0] = NET_PACKET_LAN_DISCOVERY;
376
198
    pk_copy(data + 1, dht_pk);
377
378
198
    send_broadcasts(net, broadcast, port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE);
379
380
198
    bool res = false;
381
198
    IP_Port ip_port;
382
198
    ip_port.port = port;
383
384
    /* IPv6 multicast */
385
198
    if (net_family_is_ipv6(net_family(net))) {
386
132
        ip_port.ip = broadcast_ip(net_family_ipv6(), net_family_ipv6());
387
388
132
        if (ip_isset(&ip_port.ip) && sendpacket(net, &ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) {
389
33
            res = true;
390
33
        }
391
132
    }
392
393
    /* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is IPv6 */
394
198
    ip_port.ip = broadcast_ip(net_family(net), net_family_ipv4());
395
396
198
    if (ip_isset(&ip_port.ip) && sendpacket(net, &ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) {
397
154
        res = true;
398
154
    }
399
400
198
    return res;
401
198
}
402
403
Broadcast_Info *lan_discovery_init(const Memory *mem, const Network *ns)
404
1.48k
{
405
1.48k
    return fetch_broadcast_info(mem, ns);
406
1.48k
}
407
408
void lan_discovery_kill(Broadcast_Info *broadcast)
409
1.83k
{
410
1.83k
    if (broadcast == nullptr) {
411
396
        return;
412
396
    }
413
414
1.44k
    mem_delete(broadcast->mem, broadcast);
415
1.44k
}