Coverage Report

Created: 2025-10-08 19:34

/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-2025 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
59
#define MAX_INTERFACES 16
46
47
struct Broadcast_Info {
48
    const Memory *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 *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 gateway = {0};
94
            IP subnet_mask = {0};
95
96
            if (addr_parse_ip(adapter->IpAddressList.IpMask.String, &subnet_mask)
97
                    && addr_parse_ip(adapter->GatewayList.IpAddress.String, &gateway)) {
98
                if (net_family_is_ipv4(gateway.family) && net_family_is_ipv4(subnet_mask.family)) {
99
                    IP *ip = &broadcast->ips[broadcast->count];
100
                    ip->family = net_family_ipv4();
101
                    const uint32_t gateway_ip = net_ntohl(gateway.ip.v4.uint32);
102
                    const uint32_t subnet_ip = net_ntohl(subnet_mask.ip.v4.uint32);
103
                    const uint32_t broadcast_ip = gateway_ip + ~subnet_ip - 1;
104
                    ip->ip.v4.uint32 = net_htonl(broadcast_ip);
105
                    ++broadcast->count;
106
107
                    if (broadcast->count >= MAX_INTERFACES) {
108
                        break;
109
                    }
110
                }
111
            }
112
113
            adapter = adapter->Next;
114
        }
115
    }
116
117
    if (adapter_info != nullptr) {
118
        mem_delete(mem, adapter_info);
119
    }
120
121
    return broadcast;
122
}
123
124
#elif !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && (defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__))
125
126
static bool ip4_is_local(const IP4 *_Nonnull ip4);
127
128
static Broadcast_Info *fetch_broadcast_info(const Memory *_Nonnull mem, const Network *_Nonnull ns)
129
35
{
130
35
    Broadcast_Info *broadcast = (Broadcast_Info *)mem_alloc(mem, sizeof(Broadcast_Info));
131
132
35
    if (broadcast == nullptr) {
133
2
        return nullptr;
134
2
    }
135
136
33
    broadcast->mem = mem;
137
138
    /* Not sure how many platforms this will run on,
139
     * so it's wrapped in `__linux__` for now.
140
     * Definitely won't work like this on Windows...
141
     */
142
33
    const Socket sock = net_socket(ns, net_family_ipv4(), TOX_SOCK_STREAM, 0);
143
144
33
    if (!sock_valid(sock)) {
145
2
        mem_delete(mem, broadcast);
146
2
        return nullptr;
147
2
    }
148
149
    /* Configure ifconf for the ioctl call. */
150
31
    struct ifreq i_faces[MAX_INTERFACES] = {{{0}}};
151
152
31
    struct ifconf ifc;
153
31
    ifc.ifc_buf = (char *)i_faces;
154
31
    ifc.ifc_len = sizeof(i_faces);
155
156
31
    if (ioctl(net_socket_to_native(sock), SIOCGIFCONF, &ifc) < 0) {
157
1
        kill_sock(ns, sock);
158
1
        mem_delete(mem, broadcast);
159
1
        return nullptr;
160
1
    }
161
162
    /* `ifc.ifc_len` is set by the `ioctl()` to the actual length used.
163
     * On usage of the complete array the call should be repeated with
164
     * a larger array, not done (640kB and 16 interfaces shall be
165
     * enough, for everybody!)
166
     */
167
30
    const int n = ifc.ifc_len / sizeof(struct ifreq);
168
169
90
    for (int i = 0; i < n; ++i) {
170
        /* there are interfaces with are incapable of broadcast
171
         * on Linux, `lo` has no broadcast address, but this function returns `>=0` */
172
60
        if (ioctl(net_socket_to_native(sock), SIOCGIFBRDADDR, &i_faces[i]) < 0) {
173
1
            continue;
174
1
        }
175
176
        /* moot check: only AF_INET returned (backwards compat.) */
177
59
        if (i_faces[i].ifr_broadaddr.sa_family != AF_INET) {
178
0
            continue;
179
0
        }
180
181
59
        const struct sockaddr_in *broadaddr4 = (const struct sockaddr_in *)(void *)&i_faces[i].ifr_broadaddr;
182
183
59
        if (broadcast->count >= MAX_INTERFACES) {
184
0
            break;
185
0
        }
186
187
59
        IP *ip = &broadcast->ips[broadcast->count];
188
59
        ip->family = net_family_ipv4();
189
59
        ip->ip.v4.uint32 = broadaddr4->sin_addr.s_addr;
190
191
        // if no broadcast address
192
59
        if (ip->ip.v4.uint32 == 0) {
193
7
            if (ioctl(net_socket_to_native(sock), SIOCGIFADDR, &i_faces[i]) < 0) {
194
0
                continue;
195
0
            }
196
197
7
            const struct sockaddr_in *addr4 = (const struct sockaddr_in *)(void *)&i_faces[i].ifr_addr;
198
199
200
7
            IP4 ip4_staging;
201
7
            ip4_staging.uint32 = addr4->sin_addr.s_addr;
202
203
7
            if (ip4_is_local(&ip4_staging)) {
204
                // this is 127.x.x.x
205
7
                ip->ip.v4.uint32 = ip4_staging.uint32;
206
7
            } else {
207
                // give up.
208
0
                continue;
209
0
            }
210
7
        }
211
212
59
        ++broadcast->count;
213
59
    }
214
215
30
    kill_sock(ns, sock);
216
217
30
    return broadcast;
218
31
}
219
220
#else // TODO(irungentoo): Other platforms?
221
222
static Broadcast_Info *fetch_broadcast_info(const Memory *_Nonnull mem, const Network *_Nonnull ns)
223
1.37k
{
224
1.37k
    Broadcast_Info *broadcast = (Broadcast_Info *)mem_alloc(mem, sizeof(Broadcast_Info));
225
226
1.37k
    if (broadcast == nullptr) {
227
0
        return nullptr;
228
0
    }
229
230
1.37k
    broadcast->mem = mem;
231
232
1.37k
    return broadcast;
233
1.37k
}
234
235
#endif /* platforms */
236
237
/** @brief Send packet to all IPv4 broadcast addresses
238
 *
239
 * @retval true if sent to at least one broadcast target.
240
 * @retval false on failure to find any valid broadcast target.
241
 */
242
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)
243
198
{
244
198
    if (broadcast->count == 0) {
245
0
        return false;
246
0
    }
247
248
594
    for (uint32_t i = 0; i < broadcast->count; ++i) {
249
396
        IP_Port ip_port;
250
396
        ip_port.ip = broadcast->ips[i];
251
396
        ip_port.port = port;
252
396
        sendpacket(net, &ip_port, data, length);
253
396
    }
254
255
198
    return true;
256
198
}
257
258
/** Return the broadcast ip. */
259
static IP broadcast_ip(Family family_socket, Family family_broadcast)
260
198
{
261
198
    IP ip;
262
198
    ip_reset(&ip);
263
264
198
    if (net_family_is_ipv6(family_socket)) {
265
0
        if (net_family_is_ipv6(family_broadcast)) {
266
0
            ip.family = net_family_ipv6();
267
            /* `FF02::1` is - according to RFC 4291 - multicast all-nodes link-local */
268
            /* `FE80::*:` MUST be exact, for that we would need to look over all
269
             * interfaces and check in which status they are */
270
0
            ip.ip.v6.uint8[0] = 0xFF;
271
0
            ip.ip.v6.uint8[1] = 0x02;
272
0
            ip.ip.v6.uint8[15] = 0x01;
273
0
        } else if (net_family_is_ipv4(family_broadcast)) {
274
0
            ip.family = net_family_ipv6();
275
0
            ip.ip.v6 = get_ip6_broadcast();
276
0
        }
277
198
    } else if (net_family_is_ipv4(family_socket) && net_family_is_ipv4(family_broadcast)) {
278
198
        ip.family = net_family_ipv4();
279
198
        ip.ip.v4 = get_ip4_broadcast();
280
198
    }
281
282
198
    return ip;
283
198
}
284
285
static bool ip4_is_local(const IP4 *_Nonnull ip4)
286
4.69M
{
287
    /* Loopback. */
288
4.69M
    return ip4->uint8[0] == 127;
289
4.69M
}
290
291
/**
292
 * Is IP a local ip or not.
293
 */
294
bool ip_is_local(const IP *ip)
295
4.70M
{
296
4.70M
    if (net_family_is_ipv4(ip->family)) {
297
4.69M
        return ip4_is_local(&ip->ip.v4);
298
4.69M
    }
299
300
    /* embedded IPv4-in-IPv6 */
301
11.7k
    if (ipv6_ipv4_in_v6(&ip->ip.v6)) {
302
0
        IP4 ip4;
303
0
        ip4.uint32 = ip->ip.v6.uint32[3];
304
0
        return ip4_is_local(&ip4);
305
0
    }
306
307
    /* localhost in IPv6 (::1) */
308
11.7k
    return ip->ip.v6.uint64[0] == 0 && ip->ip.v6.uint32[2] == 0 && ip->ip.v6.uint32[3] == net_htonl(1);
309
11.7k
}
310
311
static bool ip4_is_lan(const IP4 *_Nonnull ip4)
312
116
{
313
    /* 10.0.0.0 to 10.255.255.255 range. */
314
116
    if (ip4->uint8[0] == 10) {
315
0
        return true;
316
0
    }
317
318
    /* 172.16.0.0 to 172.31.255.255 range. */
319
116
    if (ip4->uint8[0] == 172 && ip4->uint8[1] >= 16 && ip4->uint8[1] <= 31) {
320
108
        return true;
321
108
    }
322
323
    /* 192.168.0.0 to 192.168.255.255 range. */
324
8
    if (ip4->uint8[0] == 192 && ip4->uint8[1] == 168) {
325
0
        return true;
326
0
    }
327
328
    /* 169.254.1.0 to 169.254.254.255 range. */
329
8
    if (ip4->uint8[0] == 169 && ip4->uint8[1] == 254 && ip4->uint8[2] != 0
330
8
            && ip4->uint8[2] != 255) {
331
0
        return true;
332
0
    }
333
334
    /* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10)
335
     * (shared address space to stack another layer of NAT) */
336
8
    return (ip4->uint8[0] == 100) && ((ip4->uint8[1] & 0xC0) == 0x40);
337
8
}
338
339
bool ip_is_lan(const IP *ip)
340
4.70M
{
341
4.70M
    if (ip_is_local(ip)) {
342
4.69M
        return true;
343
4.69M
    }
344
345
11.7k
    if (net_family_is_ipv4(ip->family)) {
346
116
        return ip4_is_lan(&ip->ip.v4);
347
116
    }
348
349
11.6k
    if (net_family_is_ipv6(ip->family)) {
350
        /* autogenerated for each interface: `FE80::*` (up to `FEBF::*`)
351
         * `FF02::1` is - according to RFC 4291 - multicast all-nodes link-local */
352
0
        if (((ip->ip.v6.uint8[0] == 0xFF) && (ip->ip.v6.uint8[1] < 3) && (ip->ip.v6.uint8[15] == 1)) ||
353
0
                ((ip->ip.v6.uint8[0] == 0xFE) && ((ip->ip.v6.uint8[1] & 0xC0) == 0x80))) {
354
0
            return true;
355
0
        }
356
357
        /* embedded IPv4-in-IPv6 */
358
0
        if (ipv6_ipv4_in_v6(&ip->ip.v6)) {
359
0
            IP4 ip4;
360
0
            ip4.uint32 = ip->ip.v6.uint32[3];
361
0
            return ip4_is_lan(&ip4);
362
0
        }
363
0
    }
364
365
11.6k
    return false;
366
11.6k
}
367
368
bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk,
369
                        uint16_t port)
370
198
{
371
198
    if (broadcast == nullptr) {
372
0
        return false;
373
0
    }
374
375
198
    uint8_t data[CRYPTO_PUBLIC_KEY_SIZE + 1];
376
198
    data[0] = NET_PACKET_LAN_DISCOVERY;
377
198
    pk_copy(data + 1, dht_pk);
378
379
198
    send_broadcasts(net, broadcast, port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE);
380
381
198
    bool res = false;
382
198
    IP_Port ip_port;
383
198
    ip_port.port = port;
384
385
    /* IPv6 multicast */
386
198
    if (net_family_is_ipv6(net_family(net))) {
387
0
        ip_port.ip = broadcast_ip(net_family_ipv6(), net_family_ipv6());
388
389
0
        if (ip_isset(&ip_port.ip) && sendpacket(net, &ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) {
390
0
            res = true;
391
0
        }
392
0
    }
393
394
    /* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is IPv6 */
395
198
    ip_port.ip = broadcast_ip(net_family(net), net_family_ipv4());
396
397
198
    if (ip_isset(&ip_port.ip) && sendpacket(net, &ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) {
398
198
        res = true;
399
198
    }
400
401
198
    return res;
402
198
}
403
404
Broadcast_Info *lan_discovery_init(const Memory *mem, const Network *ns)
405
1.41k
{
406
1.41k
    return fetch_broadcast_info(mem, ns);
407
1.41k
}
408
409
void lan_discovery_kill(Broadcast_Info *broadcast)
410
1.90k
{
411
1.90k
    if (broadcast == nullptr) {
412
503
        return;
413
503
    }
414
415
1.40k
    mem_delete(broadcast->mem, broadcast);
416
1.40k
}