Coverage Report

Created: 2026-10-24 08:16

/work/toxcore/network.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
 * Functions for the core networking.
8
 */
9
10
#include "network.h"
11
12
#include <assert.h>
13
#include <limits.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
18
#include "attributes.h"
19
#include "bin_pack.h"
20
#include "ccompat.h"
21
#include "logger.h"
22
#include "mem.h"
23
#include "net.h"
24
#include "net_log.h"
25
#include "net_profile.h"
26
#include "os_network.h"
27
#include "util.h"
28
29
static_assert(sizeof(IP4) == SIZE_IP4, "IP4 size must be 4");
30
31
// TODO(iphydf): Stop relying on this. We memcpy this struct (and IP4 above)
32
// into packets but really should be serialising it properly.
33
static_assert(sizeof(IP6) == SIZE_IP6, "IP6 size must be 16");
34
35
IP4 get_ip4_broadcast(void)
36
31
{
37
31
    return net_get_ip4_broadcast();
38
31
}
39
40
IP6 get_ip6_broadcast(void)
41
132
{
42
132
    return net_get_ip6_broadcast();
43
132
}
44
45
IP4 get_ip4_loopback(void)
46
155
{
47
155
    return net_get_ip4_loopback();
48
155
}
49
50
IP6 get_ip6_loopback(void)
51
3
{
52
3
    return net_get_ip6_loopback();
53
3
}
54
55
bool sock_valid(Socket sock)
56
2.38k
{
57
2.38k
    const Socket invalid_socket = net_invalid_socket();
58
2.38k
    return sock.value != invalid_socket.value;
59
2.38k
}
60
61
int net_send(const Network *ns, const Logger *log,
62
             Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port, Net_Profile *net_profile)
63
17.6k
{
64
17.6k
    const int res = ns_send(ns, sock, buf, len);
65
66
17.6k
    if (res > 0) {
67
17.0k
        netprof_record_packet(net_profile, buf[0], res, PACKET_DIRECTION_SEND);
68
17.0k
    }
69
70
17.6k
    net_log_data(log, "T=>", buf, len, ip_port, res);
71
17.6k
    return res;
72
17.6k
}
73
74
int net_recv(const Network *ns, const Logger *log,
75
             Socket sock, uint8_t *buf, size_t len, const IP_Port *ip_port)
76
33.3k
{
77
33.3k
    const int res = ns_recv(ns, sock, buf, len);
78
33.3k
    net_log_data(log, "=>T", buf, len, ip_port, res);
79
33.3k
    return res;
80
33.3k
}
81
82
int net_listen(const Network *ns, Socket sock, int backlog)
83
36
{
84
36
    return ns_listen(ns, sock, backlog);
85
36
}
86
87
Socket net_accept(const Network *ns, Socket sock)
88
90
{
89
90
    return ns_accept(ns, sock);
90
90
}
91
92
/** Close the socket. */
93
void kill_sock(const Network *ns, Socket sock)
94
2.12k
{
95
2.12k
    ns_close(ns, sock);
96
2.12k
}
97
98
bool set_socket_nonblock(const Network *ns, Socket sock)
99
2.21k
{
100
2.21k
    return net_set_socket_nonblock(ns, sock);
101
2.21k
}
102
103
bool set_socket_nosigpipe(const Network *ns, Socket sock)
104
2.17k
{
105
2.17k
    return net_set_socket_nosigpipe(ns, sock);
106
2.17k
}
107
108
bool set_socket_reuseaddr(const Network *ns, Socket sock)
109
34
{
110
34
    return net_set_socket_reuseaddr(ns, sock);
111
34
}
112
113
bool set_socket_dualstack(const Network *ns, Socket sock)
114
1.49k
{
115
1.49k
    return net_set_socket_dualstack(ns, sock);
116
1.49k
}
117
118
typedef struct Packet_Handler {
119
    packet_handler_cb *_Nullable function;
120
    void *_Nullable object;
121
} Packet_Handler;
122
123
struct Networking_Core {
124
    const Logger *_Nonnull log;
125
    const Memory *_Nonnull mem;
126
    Packet_Handler packethandlers[256];
127
    const Network *_Nonnull ns;
128
129
    Family family;
130
    uint16_t port;
131
    /* Our UDP socket. */
132
    Socket sock;
133
134
    Net_Profile *_Nullable udp_net_profile;
135
};
136
137
Family net_family(const Networking_Core *net)
138
2.69k
{
139
2.69k
    return net->family;
140
2.69k
}
141
142
uint16_t net_port(const Networking_Core *net)
143
113k
{
144
113k
    return net->port;
145
113k
}
146
147
/* Basic network functions:
148
 */
149
150
bool net_socket_family_compatible(const Networking_Core *net, const IP_Port *ip_port, bool log_warning)
151
833k
{
152
833k
    if (!net_family_is_ipv4(net->family) || net_family_is_ipv4(ip_port->ip.family)) {
153
832k
        return true;
154
832k
    }
155
546
    Ip_Ntoa ip_str;
156
546
    if (log_warning) {
157
3
        LOGGER_WARNING(net->log, "attempted to send message with network family %d (probably IPv6) on IPv4 socket (%s)",
158
3
                       ip_port->ip.family.value, net_ip_ntoa(&ip_port->ip, &ip_str));
159
543
    } else {
160
543
        LOGGER_TRACE(net->log, "attempted to send message with network family %d (probably IPv6) on IPv4 socket (%s)",
161
543
                     ip_port->ip.family.value, net_ip_ntoa(&ip_port->ip, &ip_str));
162
543
    }
163
546
    return false;
164
833k
}
165
166
int net_send_packet(const Networking_Core *net, const IP_Port *ip_port, Net_Packet packet)
167
561k
{
168
561k
    IP_Port ipp_copy = *ip_port;
169
170
561k
    if (net_family_is_unspec(ip_port->ip.family)) {
171
        // TODO(iphydf): Make this an error. Currently this fails sometimes when
172
        // called from DHT.c:do_ping_and_sendnode_requests.
173
4
        return -1;
174
4
    }
175
176
561k
    if (net_family_is_unspec(net->family)) { /* Socket not initialized */
177
        // TODO(iphydf): Make this an error. Currently, the onion client calls
178
        // this via DHT nodes requests.
179
2
        LOGGER_WARNING(net->log, "attempted to send message of length %u on uninitialised socket", packet.length);
180
2
        return -1;
181
2
    }
182
183
    /* socket TOX_AF_INET, but target IP NOT: can't send */
184
561k
    if (!net_socket_family_compatible(net, ip_port, true)) {
185
        // TODO(iphydf): Make this an error. Occasionally we try to send to an
186
        // all-zero ip_port.
187
3
        return -1;
188
3
    }
189
190
561k
    if (net_family_is_ipv4(ipp_copy.ip.family) && net_family_is_ipv6(net->family)) {
191
        /* must convert to IPV4-in-IPV6 address */
192
40.5k
        IP6 ip6;
193
194
        /* there should be a macro for this in a standards compliant
195
         * environment, not found */
196
40.5k
        ip6.uint32[0] = 0;
197
40.5k
        ip6.uint32[1] = 0;
198
40.5k
        ip6.uint32[2] = net_htonl(0xFFFF);
199
40.5k
        ip6.uint32[3] = ipp_copy.ip.ip.v4.uint32;
200
201
40.5k
        ipp_copy.ip.family = net_family_ipv6();
202
40.5k
        ipp_copy.ip.ip.v6 = ip6;
203
40.5k
    }
204
205
561k
    const long res = ns_sendto(net->ns, net->sock, packet.data, packet.length, &ipp_copy);
206
561k
    net_log_data(net->log, "O=>", packet.data, packet.length, ip_port, res);
207
208
561k
    assert(res <= INT_MAX);
209
210
560k
    if (res == packet.length && packet.data != nullptr) {
211
560k
        netprof_record_packet(net->udp_net_profile, packet.data[0], packet.length, PACKET_DIRECTION_SEND);
212
560k
    }
213
214
560k
    return (int)res;
215
561k
}
216
217
/**
218
 * Function to send packet(data) of length length to ip_port.
219
 *
220
 * @deprecated Use net_send_packet instead.
221
 */
222
int sendpacket(const Networking_Core *net, const IP_Port *ip_port, const uint8_t *data, uint16_t length)
223
560k
{
224
560k
    const Net_Packet packet = {data, length};
225
560k
    return net_send_packet(net, ip_port, packet);
226
560k
}
227
228
/** @brief Function to receive data
229
 * ip and port of sender is put into ip_port.
230
 * Packet data is put into data.
231
 * Packet length is put into length.
232
 */
233
static int receivepacket(const Network *_Nonnull ns, const Logger *_Nonnull log, Socket sock, IP_Port *_Nonnull ip_port, uint8_t *_Nonnull data, uint32_t *_Nonnull length)
234
631k
{
235
631k
    memset(ip_port, 0, sizeof(IP_Port));
236
631k
    *length = 0;
237
238
631k
    const int fail_or_len = ns_recvfrom(ns, sock, data, MAX_UDP_PACKET_SIZE, ip_port);
239
240
631k
    if (fail_or_len < 0) {
241
102k
        const int error = net_error();
242
243
102k
        if (!net_should_ignore_recv_error(error)) {
244
4
            Net_Strerror error_str;
245
4
            LOGGER_ERROR(log, "unexpected error reading from socket: %u, %s", (unsigned int)error, net_strerror(error, &error_str));
246
4
        }
247
248
102k
        return -1; /* Nothing received. */
249
102k
    }
250
251
528k
    *length = (uint32_t)fail_or_len;
252
253
528k
    if (net_family_is_ipv6(ip_port->ip.family) && ipv6_ipv4_in_v6(&ip_port->ip.ip.v6)) {
254
40.1k
        ip_port->ip.family = net_family_ipv4();
255
40.1k
        ip_port->ip.ip.v4.uint32 = ip_port->ip.ip.v6.uint32[3];
256
40.1k
    }
257
258
528k
    net_log_data(log, "=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
259
260
528k
    return 0;
261
631k
}
262
263
void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_cb *cb, void *object)
264
121k
{
265
121k
    net->packethandlers[byte].function = cb;
266
121k
    net->packethandlers[byte].object = object;
267
121k
}
268
269
void networking_poll(const Networking_Core *net, void *userdata)
270
103k
{
271
103k
    if (net_family_is_unspec(net->family)) {
272
        /* Socket not initialized */
273
620
        return;
274
620
    }
275
276
102k
    IP_Port ip_port;
277
102k
    uint8_t data[MAX_UDP_PACKET_SIZE] = {0};
278
102k
    uint32_t length;
279
280
631k
    while (receivepacket(net->ns, net->log, net->sock, &ip_port, data, &length) != -1) {
281
528k
        if (length < 1) {
282
0
            continue;
283
0
        }
284
285
528k
        netprof_record_packet(net->udp_net_profile, data[0], length, PACKET_DIRECTION_RECV);
286
287
528k
        const Packet_Handler *const handler = &net->packethandlers[data[0]];
288
289
528k
        if (handler->function == nullptr) {
290
            // TODO(https://github.com/TokTok/c-toxcore/issues/1115): Make this
291
            // a warning or error again.
292
1.80k
            LOGGER_DEBUG(net->log, "[%02u] -- Packet has no handler", data[0]);
293
1.80k
            continue;
294
1.80k
        }
295
296
527k
        handler->function(handler->object, &ip_port, data, length, userdata);
297
527k
    }
298
102k
}
299
300
/** @brief Initialize networking.
301
 * Bind to ip and port.
302
 * ip must be in network order EX: 127.0.0.1 = (7F000001).
303
 * port is in host byte order (this means don't worry about it).
304
 *
305
 * @return Networking_Core object if no problems
306
 * @retval NULL if there are problems.
307
 *
308
 * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other.
309
 */
310
Networking_Core *new_networking_ex(
311
    const Logger *log, const Memory *mem, const Network *ns, const IP *ip,
312
    uint16_t port_from, uint16_t port_to, unsigned int *error)
313
2.01k
{
314
    /* If both from and to are 0, use default port range
315
     * If one is 0 and the other is non-0, use the non-0 value as only port
316
     * If from > to, swap
317
     */
318
2.01k
    if (port_from == 0 && port_to == 0) {
319
1.43k
        port_from = TOX_PORTRANGE_FROM;
320
1.43k
        port_to = TOX_PORTRANGE_TO;
321
1.43k
    } else if (port_from == 0 && port_to != 0) {
322
7
        port_from = port_to;
323
580
    } else if (port_from != 0 && port_to == 0) {
324
1
        port_to = port_from;
325
579
    } else if (port_from > port_to) {
326
4
        const uint16_t temp_port = port_from;
327
4
        port_from = port_to;
328
4
        port_to = temp_port;
329
4
    }
330
331
2.01k
    if (error != nullptr) {
332
1.81k
        *error = 2;
333
1.81k
    }
334
335
    /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */
336
2.01k
    if (!net_family_is_ipv4(ip->family) && !net_family_is_ipv6(ip->family)) {
337
2
        LOGGER_ERROR(log, "invalid address family: %u", ip->family.value);
338
2
        return nullptr;
339
2
    }
340
341
2.01k
    Networking_Core *temp = (Networking_Core *)mem_alloc(mem, sizeof(Networking_Core));
342
343
2.01k
    if (temp == nullptr) {
344
4
        return nullptr;
345
4
    }
346
347
2.01k
    Net_Profile *np = netprof_new(log, mem);
348
349
2.01k
    if (np == nullptr) {
350
4
        mem_delete(mem, temp);
351
4
        return nullptr;
352
4
    }
353
354
2.00k
    temp->udp_net_profile = np;
355
2.00k
    temp->ns = ns;
356
2.00k
    temp->log = log;
357
2.00k
    temp->mem = mem;
358
2.00k
    temp->family = ip->family;
359
2.00k
    temp->port = 0;
360
361
    /* Initialize our socket. */
362
    /* add log message what we're creating */
363
2.00k
    temp->sock = net_socket(ns, temp->family, TOX_SOCK_DGRAM, TOX_PROTO_UDP);
364
365
    /* Check for socket error. */
366
2.00k
    if (!sock_valid(temp->sock)) {
367
3
        const int neterror = net_error();
368
3
        Net_Strerror error_str;
369
3
        LOGGER_ERROR(log, "failed to get a socket?! %d, %s", neterror, net_strerror(neterror, &error_str));
370
3
        netprof_kill(mem, temp->udp_net_profile);
371
3
        mem_delete(mem, temp);
372
373
3
        if (error != nullptr) {
374
1
            *error = 1;
375
1
        }
376
377
3
        return nullptr;
378
3
    }
379
380
    /* Functions to increase the size of the send and receive UDP buffers.
381
     */
382
2.00k
    if (!net_set_socket_buffer_size(ns, temp->sock, 1024 * 1024 * 2)) {
383
3
        LOGGER_WARNING(log, "failed to set socket buffer size");
384
3
    }
385
386
    /* Enable broadcast on socket */
387
2.00k
    if (!net_set_socket_broadcast(ns, temp->sock)) {
388
3
        LOGGER_ERROR(log, "failed to set socket broadcast");
389
3
    }
390
391
    /* iOS UDP sockets are weird and apparently can SIGPIPE */
392
2.00k
    if (!set_socket_nosigpipe(ns, temp->sock)) {
393
0
        kill_networking(temp);
394
395
0
        if (error != nullptr) {
396
0
            *error = 1;
397
0
        }
398
399
0
        return nullptr;
400
0
    }
401
402
    /* Set socket nonblocking. */
403
2.00k
    if (!set_socket_nonblock(ns, temp->sock)) {
404
0
        kill_networking(temp);
405
406
0
        if (error != nullptr) {
407
0
            *error = 1;
408
0
        }
409
410
0
        return nullptr;
411
0
    }
412
413
    /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */
414
2.00k
    uint16_t *portptr = nullptr;
415
2.00k
    IP_Port addr;
416
2.00k
    ip_init(&addr.ip, net_family_is_ipv6(temp->family));
417
418
2.00k
    if (net_family_is_ipv4(temp->family) || net_family_is_ipv6(temp->family)) {
419
2.00k
        ip_copy(&addr.ip, ip);
420
2.00k
        addr.port = 0;
421
2.00k
        portptr = &addr.port;
422
2.00k
    } else {
423
0
        mem_delete(mem, temp);
424
0
        return nullptr;
425
0
    }
426
427
2.00k
    if (net_family_is_ipv6(ip->family)) {
428
1.47k
        const bool is_dualstack = set_socket_dualstack(ns, temp->sock);
429
430
1.47k
        if (is_dualstack) {
431
1.47k
            LOGGER_TRACE(log, "Dual-stack socket: enabled");
432
1.47k
        } else {
433
1
            LOGGER_ERROR(log, "Dual-stack socket failed to enable, won't be able to receive from/send to IPv4 addresses");
434
1
        }
435
436
1.47k
        if (!net_join_multicast(ns, temp->sock, ip->family)) {
437
30
            const int neterror = net_error();
438
30
            Net_Strerror error_str;
439
30
            LOGGER_INFO(log, "Failed to activate local multicast membership in FF02::1. (%d, %s)", neterror, net_strerror(neterror, &error_str));
440
1.44k
        } else {
441
1.44k
            const int neterror = net_error();
442
1.44k
            Net_Strerror error_str;
443
1.44k
            LOGGER_TRACE(log, "Local multicast group joined successfully. (%d, %s)", neterror, net_strerror(neterror, &error_str));
444
1.44k
        }
445
1.47k
    }
446
447
    /* A hanging program or a different user might block the standard port.
448
     * As long as it isn't a parameter coming from the commandline,
449
     * try a few ports after it, to see if we can find a "free" one.
450
     *
451
     * If we go on without binding, the first sendto() automatically binds to
452
     * a free port chosen by the system (i.e. anything from 1024 to 65535).
453
     *
454
     * Returning NULL after bind fails has both advantages and disadvantages:
455
     * advantage:
456
     *   we can rely on getting the port in the range 33445..33450, which
457
     *   enables us to tell joe user to open their firewall to a small range
458
     *
459
     * disadvantage:
460
     *   some clients might not test return of tox_new(), blindly assuming that
461
     *   it worked ok (which it did previously without a successful bind)
462
     */
463
2.00k
    uint16_t port_to_try = port_from;
464
2.00k
    *portptr = net_htons(port_to_try);
465
466
34.4k
    for (uint16_t tries = port_from; tries <= port_to; ++tries) {
467
34.4k
        const int res = ns_bind(ns, temp->sock, &addr);
468
469
34.4k
        if (res == 0) {
470
2.00k
            temp->port = *portptr;
471
472
2.00k
            Ip_Ntoa ip_str;
473
2.00k
            LOGGER_DEBUG(log, "Bound successfully to %s:%u", net_ip_ntoa(ip, &ip_str),
474
2.00k
                         net_ntohs(temp->port));
475
476
            /* errno isn't reset on success, only set on failure, the failed
477
             * binds with parallel clients yield a -EPERM to the outside if
478
             * errno isn't cleared here */
479
2.00k
            if (tries > 0) {
480
2.00k
                net_clear_error();
481
2.00k
            }
482
483
2.00k
            if (error != nullptr) {
484
1.81k
                *error = 0;
485
1.81k
            }
486
487
2.00k
            return temp;
488
2.00k
        }
489
490
32.4k
        ++port_to_try;
491
492
32.4k
        if (port_to_try > port_to) {
493
3
            port_to_try = port_from;
494
3
        }
495
496
32.4k
        *portptr = net_htons(port_to_try);
497
32.4k
    }
498
499
3
    Ip_Ntoa ip_str;
500
3
    const int neterror = net_error();
501
3
    Net_Strerror error_str;
502
3
    LOGGER_ERROR(log, "failed to bind socket: %d, %s IP: %s port_from: %u port_to: %u",
503
3
                 neterror, net_strerror(neterror, &error_str), net_ip_ntoa(ip, &ip_str), port_from, port_to);
504
3
    kill_networking(temp);
505
506
3
    if (error != nullptr) {
507
1
        *error = 1;
508
1
    }
509
510
3
    return nullptr;
511
2.00k
}
512
513
Networking_Core *new_networking_no_udp(const Logger *log, const Memory *mem, const Network *ns)
514
125
{
515
    /* this is the easiest way to completely disable UDP without changing too much code. */
516
125
    Networking_Core *net = (Networking_Core *)mem_alloc(mem, sizeof(Networking_Core));
517
518
125
    if (net == nullptr) {
519
1
        return nullptr;
520
1
    }
521
522
124
    net->ns = ns;
523
124
    net->log = log;
524
124
    net->mem = mem;
525
526
124
    return net;
527
125
}
528
529
/** Function to cleanup networking stuff (doesn't do much right now). */
530
void kill_networking(Networking_Core *net)
531
2.08k
{
532
2.08k
    if (net == nullptr) {
533
0
        return;
534
0
    }
535
536
2.08k
    if (!net_family_is_unspec(net->family)) {
537
        /* Socket is initialized, so we close it. */
538
1.96k
        kill_sock(net->ns, net->sock);
539
1.96k
    }
540
541
2.08k
    netprof_kill(net->mem, net->udp_net_profile);
542
2.08k
    mem_delete(net->mem, net);
543
2.08k
}
544
545
bool ip_equal(const IP *a, const IP *b)
546
243k
{
547
243k
    if (a == nullptr || b == nullptr) {
548
9
        return false;
549
9
    }
550
551
    /* same family */
552
243k
    if (a->family.value == b->family.value) {
553
243k
        if (net_family_is_ipv4(a->family) || net_family_is_tcp_ipv4(a->family)) {
554
243k
            return a->ip.v4.uint32 == b->ip.v4.uint32;
555
243k
        }
556
557
10
        if (net_family_is_ipv6(a->family) || net_family_is_tcp_ipv6(a->family)) {
558
6
            return a->ip.v6.uint64[0] == b->ip.v6.uint64[0] &&
559
6
                   a->ip.v6.uint64[1] == b->ip.v6.uint64[1];
560
6
        }
561
562
4
        return false;
563
10
    }
564
565
    /* different family: check on the IPv6 one if it is the IPv4 one embedded */
566
14
    if (net_family_is_ipv4(a->family) && net_family_is_ipv6(b->family)) {
567
6
        if (ipv6_ipv4_in_v6(&b->ip.v6)) {
568
3
            return a->ip.v4.uint32 == b->ip.v6.uint32[3];
569
3
        }
570
8
    } else if (net_family_is_ipv6(a->family) && net_family_is_ipv4(b->family)) {
571
0
        if (ipv6_ipv4_in_v6(&a->ip.v6)) {
572
0
            return a->ip.v6.uint32[3] == b->ip.v4.uint32;
573
0
        }
574
0
    }
575
576
11
    return false;
577
14
}
578
579
bool ipport_equal(const IP_Port *a, const IP_Port *b)
580
19.3M
{
581
19.3M
    if (a == nullptr || b == nullptr) {
582
0
        return false;
583
0
    }
584
585
19.3M
    if (a->port == 0 || (a->port != b->port)) {
586
19.0M
        return false;
587
19.0M
    }
588
589
231k
    return ip_equal(&a->ip, &b->ip);
590
19.3M
}
591
592
static int ip4_cmp(const IP4 *_Nonnull a, const IP4 *_Nonnull b)
593
139k
{
594
139k
    return cmp_uint(a->uint32, b->uint32);
595
139k
}
596
597
static int ip6_cmp(const IP6 *_Nonnull a, const IP6 *_Nonnull b)
598
2
{
599
2
    const int res = cmp_uint(a->uint64[0], b->uint64[0]);
600
2
    if (res != 0) {
601
1
        return res;
602
1
    }
603
1
    return cmp_uint(a->uint64[1], b->uint64[1]);
604
2
}
605
606
static int ip_cmp(const IP *_Nonnull a, const IP *_Nonnull b)
607
141k
{
608
141k
    const int res = cmp_uint(a->family.value, b->family.value);
609
141k
    if (res != 0) {
610
1.39k
        return res;
611
1.39k
    }
612
139k
    switch (a->family.value) {
613
1
        case TOX_AF_UNSPEC:
614
1
            return 0;
615
139k
        case TOX_AF_INET:
616
139k
        case TCP_INET:
617
139k
        case TOX_TCP_INET:
618
139k
            return ip4_cmp(&a->ip.v4, &b->ip.v4);
619
2
        case TOX_AF_INET6:
620
2
        case TCP_INET6:
621
2
        case TOX_TCP_INET6:
622
2
        case TCP_SERVER_FAMILY:  // these happen to be ipv6 according to TCP_server.c.
623
2
        case TCP_CLIENT_FAMILY:
624
2
            return ip6_cmp(&a->ip.v6, &b->ip.v6);
625
139k
    }
626
    // Invalid, we don't compare any further and consider them equal.
627
1
    return 0;
628
139k
}
629
630
int ipport_cmp_handler(const void *a, const void *b, size_t size)
631
141k
{
632
141k
    const IP_Port *ipp_a = (const IP_Port *)a;
633
141k
    const IP_Port *ipp_b = (const IP_Port *)b;
634
141k
    assert(size == sizeof(IP_Port));
635
636
141k
    const int ip_res = ip_cmp(&ipp_a->ip, &ipp_b->ip);
637
141k
    if (ip_res != 0) {
638
1.39k
        return ip_res;
639
1.39k
    }
640
641
139k
    return cmp_uint(ipp_a->port, ipp_b->port);
642
141k
}
643
644
static const IP empty_ip = {{0}};
645
646
/** nulls out ip */
647
void ip_reset(IP *ip)
648
73.2k
{
649
73.2k
    if (ip == nullptr) {
650
0
        return;
651
0
    }
652
653
73.2k
    *ip = empty_ip;
654
73.2k
}
655
656
static const IP_Port empty_ip_port = {{{0}}};
657
658
/** nulls out ip_port */
659
void ipport_reset(IP_Port *ipport)
660
444k
{
661
444k
    if (ipport == nullptr) {
662
0
        return;
663
0
    }
664
665
444k
    *ipport = empty_ip_port;
666
444k
}
667
668
/** nulls out ip, sets family according to flag */
669
void ip_init(IP *ip, bool ipv6enabled)
670
25.2k
{
671
25.2k
    if (ip == nullptr) {
672
0
        return;
673
0
    }
674
675
25.2k
    ip_reset(ip);
676
25.2k
    ip->family = ipv6enabled ? net_family_ipv6() : net_family_ipv4();
677
25.2k
}
678
679
/** checks if ip is valid */
680
bool ip_isset(const IP *ip)
681
1.60M
{
682
1.60M
    if (ip == nullptr) {
683
0
        return false;
684
0
    }
685
686
1.60M
    return !net_family_is_unspec(ip->family);
687
1.60M
}
688
689
/** checks if ip is valid */
690
bool ipport_isset(const IP_Port *ipport)
691
290k
{
692
290k
    if (ipport == nullptr) {
693
0
        return false;
694
0
    }
695
696
290k
    if (ipport->port == 0) {
697
58.8k
        return false;
698
58.8k
    }
699
700
231k
    return ip_isset(&ipport->ip);
701
290k
}
702
703
/** copies an ip structure (careful about direction) */
704
void ip_copy(IP *target, const IP *source)
705
2.02k
{
706
2.02k
    if (source == nullptr || target == nullptr) {
707
0
        return;
708
0
    }
709
710
2.02k
    *target = *source;
711
2.02k
}
712
713
/** copies an ip_port structure (careful about direction) */
714
void ipport_copy(IP_Port *target, const IP_Port *source)
715
5.87k
{
716
5.87k
    if (source == nullptr || target == nullptr) {
717
0
        return;
718
0
    }
719
720
    // Write to a temporary object first, so that padding bytes are
721
    // uninitialised and msan can catch mistakes in downstream code.
722
5.87k
    IP_Port tmp;
723
5.87k
    tmp.ip.family = source->ip.family;
724
5.87k
    tmp.ip.ip = source->ip.ip;
725
5.87k
    tmp.port = source->port;
726
727
5.87k
    *target = tmp;
728
5.87k
}
729
730
/** @brief Packs an IP structure.
731
 *
732
 * It's the caller's responsibility to make sure `is_ipv4` tells the truth. This
733
 * function is an implementation detail of @ref bin_pack_ip_port.
734
 *
735
 * @param is_ipv4 whether this IP is an IP4 or IP6.
736
 *
737
 * @retval true on success.
738
 */
739
static bool bin_pack_ip(Bin_Pack *_Nonnull bp, const IP *_Nonnull ip, bool is_ipv4)
740
1.03M
{
741
1.03M
    if (is_ipv4) {
742
1.03M
        return bin_pack_bin_b(bp, ip->ip.v4.uint8, SIZE_IP4);
743
1.03M
    } else {
744
1.86k
        return bin_pack_bin_b(bp, ip->ip.v6.uint8, SIZE_IP6);
745
1.86k
    }
746
1.03M
}
747
748
/** @brief Packs an IP_Port structure.
749
 *
750
 * @retval true on success.
751
 */
752
bool bin_pack_ip_port(Bin_Pack *bp, const Logger *logger, const IP_Port *ip_port)
753
1.03M
{
754
1.03M
    bool is_ipv4;
755
1.03M
    uint8_t family;
756
757
1.03M
    if (net_family_is_ipv4(ip_port->ip.family)) {
758
        // TODO(irungentoo): use functions to convert endianness
759
1.02M
        is_ipv4 = true;
760
1.02M
        family = TOX_AF_INET;
761
1.02M
    } else if (net_family_is_tcp_ipv4(ip_port->ip.family)) {
762
8.79k
        is_ipv4 = true;
763
8.79k
        family = TOX_TCP_INET;
764
8.79k
    } else if (net_family_is_ipv6(ip_port->ip.family)) {
765
1.24k
        is_ipv4 = false;
766
1.24k
        family = TOX_AF_INET6;
767
1.24k
    } else if (net_family_is_tcp_ipv6(ip_port->ip.family)) {
768
640
        is_ipv4 = false;
769
640
        family = TOX_TCP_INET6;
770
640
    } else {
771
364
        Ip_Ntoa ip_str;
772
        // TODO(iphydf): Find out why we're trying to pack invalid IPs, stop
773
        // doing that, and turn this into an error.
774
364
        LOGGER_TRACE(logger, "cannot pack invalid IP: %s", net_ip_ntoa(&ip_port->ip, &ip_str));
775
364
        return false;
776
364
    }
777
778
1.03M
    return bin_pack_u08_b(bp, family)
779
1.03M
           && bin_pack_ip(bp, &ip_port->ip, is_ipv4)
780
1.03M
           && bin_pack_u16_b(bp, net_ntohs(ip_port->port));
781
1.03M
}
782
783
static bool bin_pack_ip_port_handler(const void *_Nonnull obj, const Logger *_Nonnull logger, Bin_Pack *_Nonnull bp)
784
158k
{
785
158k
    const IP_Port *ip_port = (const IP_Port *)obj;
786
158k
    return bin_pack_ip_port(bp, logger, ip_port);
787
158k
}
788
789
int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_Port *ip_port)
790
79.3k
{
791
79.3k
    const uint32_t size = bin_pack_obj_size(bin_pack_ip_port_handler, ip_port, logger);
792
793
79.3k
    if (size > length) {
794
0
        return -1;
795
0
    }
796
797
79.3k
    if (!bin_pack_obj(bin_pack_ip_port_handler, ip_port, logger, data, length)) {
798
0
        return -1;
799
0
    }
800
801
79.3k
    assert(size < INT_MAX);
802
79.3k
    return (int)size;
803
79.3k
}
804
805
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled)
806
445k
{
807
445k
    if (data == nullptr || length == 0 || ip_port == nullptr) {
808
3
        return -1;
809
3
    }
810
811
445k
    bool is_ipv4;
812
445k
    Family host_family;
813
814
445k
    if (data[0] == TOX_AF_INET) {
815
441k
        is_ipv4 = true;
816
441k
        host_family = net_family_ipv4();
817
441k
    } else if (data[0] == TOX_TCP_INET) {
818
1.41k
        if (!tcp_enabled) {
819
177
            return -1;
820
177
        }
821
822
1.23k
        is_ipv4 = true;
823
1.23k
        host_family = net_family_tcp_ipv4();
824
2.96k
    } else if (data[0] == TOX_AF_INET6) {
825
1.71k
        is_ipv4 = false;
826
1.71k
        host_family = net_family_ipv6();
827
1.71k
    } else if (data[0] == TOX_TCP_INET6) {
828
466
        if (!tcp_enabled) {
829
78
            return -1;
830
78
        }
831
832
388
        is_ipv4 = false;
833
388
        host_family = net_family_tcp_ipv6();
834
775
    } else {
835
775
        return -1;
836
775
    }
837
838
444k
    ipport_reset(ip_port);
839
840
444k
    if (is_ipv4) {
841
442k
        const uint32_t size = 1 + SIZE_IP4 + sizeof(uint16_t);
842
843
442k
        if (size > length) {
844
143
            return -1;
845
143
        }
846
847
442k
        ip_port->ip.family = host_family;
848
442k
        memcpy(ip_port->ip.ip.v4.uint8, data + 1, SIZE_IP4);
849
442k
        memcpy(&ip_port->port, data + 1 + SIZE_IP4, sizeof(uint16_t));
850
442k
        return size;
851
442k
    } else {
852
2.11k
        const uint32_t size = 1 + SIZE_IP6 + sizeof(uint16_t);
853
854
2.11k
        if (size > length) {
855
205
            return -1;
856
205
        }
857
858
1.91k
        ip_port->ip.family = host_family;
859
1.91k
        memcpy(ip_port->ip.ip.v6.uint8, data + 1, SIZE_IP6);
860
1.91k
        memcpy(&ip_port->port, data + 1 + SIZE_IP6, sizeof(uint16_t));
861
1.91k
        return size;
862
2.11k
    }
863
444k
}
864
865
const char *net_ip_ntoa(const IP *ip, Ip_Ntoa *ip_str)
866
1.60M
{
867
1.60M
    assert(ip_str != nullptr);
868
869
1.60M
    ip_str->ip_is_valid = false;
870
871
1.60M
    if (ip == nullptr) {
872
0
        snprintf(ip_str->buf, sizeof(ip_str->buf), "(IP invalid: NULL)");
873
0
        ip_str->length = (uint16_t)strlen(ip_str->buf);
874
0
        return ip_str->buf;
875
0
    }
876
877
1.60M
    if (!ip_parse_addr(ip, ip_str->buf, sizeof(ip_str->buf))) {
878
25.9k
        snprintf(ip_str->buf, sizeof(ip_str->buf), "(IP invalid, family %u)", ip->family.value);
879
25.9k
        ip_str->length = (uint16_t)strlen(ip_str->buf);
880
25.9k
        return ip_str->buf;
881
25.9k
    }
882
883
    /* brute force protection against lacking termination */
884
1.57M
    ip_str->buf[sizeof(ip_str->buf) - 1] = '\0';
885
1.57M
    ip_str->length = (uint16_t)strlen(ip_str->buf);
886
1.57M
    ip_str->ip_is_valid = true;
887
888
1.57M
    return ip_str->buf;
889
1.60M
}
890
891
bool ip_parse_addr(const IP *ip, char *address, size_t length)
892
1.60M
{
893
1.60M
    if (address == nullptr || ip == nullptr) {
894
0
        return false;
895
0
    }
896
897
1.60M
    if (net_family_is_ipv4(ip->family) || net_family_is_tcp_ipv4(ip->family)) {
898
1.57M
        return net_inet_ntop4(&ip->ip.v4, address, length) != nullptr;
899
1.57M
    }
900
901
27.8k
    if (net_family_is_ipv6(ip->family) || net_family_is_tcp_ipv6(ip->family)) {
902
1.73k
        return net_inet_ntop6(&ip->ip.v6, address, length) != nullptr;
903
1.73k
    }
904
905
26.1k
    return false;
906
27.8k
}
907
908
bool addr_parse_ip(const char *address, IP *to)
909
28.6k
{
910
28.6k
    if (address == nullptr || to == nullptr) {
911
0
        return false;
912
0
    }
913
914
28.6k
    if (net_inet_pton4(address, &to->ip.v4) == 1) {
915
28.6k
        to->family = net_family_ipv4();
916
28.6k
        return true;
917
28.6k
    }
918
919
13
    if (net_inet_pton6(address, &to->ip.v6) == 1) {
920
0
        to->family = net_family_ipv6();
921
0
        return true;
922
0
    }
923
924
13
    return false;
925
13
}
926
927
/** addr_resolve return values */
928
0
#define TOX_ADDR_RESOLVE_INET  1
929
0
#define TOX_ADDR_RESOLVE_INET6 2
930
931
/**
932
 * Uses getaddrinfo to resolve an address into an IP address.
933
 *
934
 * Uses the first IPv4/IPv6 addresses returned by getaddrinfo.
935
 *
936
 * @param address a hostname (or something parseable to an IP address)
937
 * @param to to.family MUST be initialized, either set to a specific IP version
938
 *   (TOX_AF_INET/TOX_AF_INET6) or to the unspecified TOX_AF_UNSPEC (0), if both
939
 *   IP versions are acceptable
940
 * @param extra can be NULL and is only set in special circumstances, see returns
941
 *
942
 * Returns in `*to` a valid IPAny (v4/v6),
943
 * prefers v6 if `ip.family` was TOX_AF_UNSPEC and both available
944
 * Returns in `*extra` an IPv4 address, if family was TOX_AF_UNSPEC and `*to` is TOX_AF_INET6
945
 *
946
 * @return false on failure, true on success.
947
 */
948
static bool addr_resolve(const Network *_Nonnull ns, const Memory *_Nonnull mem, const char *_Nonnull address, IP *_Nonnull to, IP *_Nullable extra)
949
71
{
950
71
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
951
71
    if ((true)) {
952
71
        return false;
953
71
    }
954
0
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
955
956
0
    if (address == nullptr || to == nullptr) {
957
0
        return false;
958
0
    }
959
960
0
    const int family = to->family.value;
961
962
0
    IP_Port *addrs = nullptr;
963
0
    const int rc = ns_getaddrinfo(ns, mem, address, family, 0, &addrs);
964
965
    // Lookup failed / empty.
966
0
    if (rc <= 0) {
967
0
        return false;
968
0
    }
969
970
0
    assert(addrs != nullptr);
971
972
0
    IP ip4;
973
0
    ip_init(&ip4, false); // ipv6enabled = false
974
0
    IP ip6;
975
0
    ip_init(&ip6, true); // ipv6enabled = true
976
977
0
    int result = 0;
978
0
    bool done = false;
979
980
0
    for (int i = 0; i < rc && !done; ++i) {
981
0
        if (net_family_is_ipv4(addrs[i].ip.family)) {
982
0
            if (addrs[i].ip.family.value == to->family.value) { /* AF_INET requested, done */
983
0
                ip_copy(to, &addrs[i].ip);
984
0
                result = TOX_ADDR_RESOLVE_INET;
985
0
                done = true;
986
0
            } else if ((result & TOX_ADDR_RESOLVE_INET) == 0) { /* AF_UNSPEC requested, store away */
987
0
                ip_copy(&ip4, &addrs[i].ip);
988
0
                result |= TOX_ADDR_RESOLVE_INET;
989
0
            }
990
0
        } else if (net_family_is_ipv6(addrs[i].ip.family)) {
991
0
            if (addrs[i].ip.family.value == to->family.value) { /* AF_INET6 requested, done */
992
0
                ip_copy(to, &addrs[i].ip);
993
0
                result = TOX_ADDR_RESOLVE_INET6;
994
0
                done = true;
995
0
            } else if ((result & TOX_ADDR_RESOLVE_INET6) == 0) { /* AF_UNSPEC requested, store away */
996
0
                ip_copy(&ip6, &addrs[i].ip);
997
0
                result |= TOX_ADDR_RESOLVE_INET6;
998
0
            }
999
0
        }
1000
0
    }
1001
1002
0
    if (family == TOX_AF_UNSPEC) {
1003
0
        if ((result & TOX_ADDR_RESOLVE_INET6) != 0) {
1004
0
            ip_copy(to, &ip6);
1005
1006
0
            if ((result & TOX_ADDR_RESOLVE_INET) != 0 && (extra != nullptr)) {
1007
0
                ip_copy(extra, &ip4);
1008
0
            }
1009
0
        } else if ((result & TOX_ADDR_RESOLVE_INET) != 0) {
1010
0
            ip_copy(to, &ip4);
1011
0
        } else {
1012
0
            result = 0;
1013
0
        }
1014
0
    }
1015
1016
0
    ns_freeaddrinfo(ns, mem, addrs);
1017
0
    return result != 0;
1018
0
}
1019
1020
bool addr_resolve_or_parse_ip(const Network *ns, const Memory *mem, const char *address, IP *to, IP *extra, bool dns_enabled)
1021
84
{
1022
84
    if (dns_enabled && addr_resolve(ns, mem, address, to, extra)) {
1023
13
        return true;
1024
13
    }
1025
1026
71
    return addr_parse_ip(address, to);
1027
84
}
1028
1029
const char *net_err_connect_to_string(Net_Err_Connect err)
1030
0
{
1031
0
    switch (err) {
1032
0
        case NET_ERR_CONNECT_OK:
1033
0
            return "NET_ERR_CONNECT_OK";
1034
0
        case NET_ERR_CONNECT_INVALID_FAMILY:
1035
0
            return "NET_ERR_CONNECT_INVALID_FAMILY";
1036
0
        case NET_ERR_CONNECT_FAILED:
1037
0
            return "NET_ERR_CONNECT_FAILED";
1038
0
    }
1039
1040
0
    return "<invalid Net_Err_Connect>";
1041
0
}
1042
1043
bool net_connect(const Network *ns, const Memory *mem, const Logger *log, Socket sock, const IP_Port *ip_port, Net_Err_Connect *err)
1044
22
{
1045
22
    if (!(net_family_is_ipv4(ip_port->ip.family) || net_family_is_ipv6(ip_port->ip.family))) {
1046
0
        Ip_Ntoa ip_str;
1047
0
        LOGGER_ERROR(log, "cannot connect to %s:%d which is neither IPv4 nor IPv6",
1048
0
                     net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port));
1049
0
        *err = NET_ERR_CONNECT_INVALID_FAMILY;
1050
0
        return false;
1051
0
    }
1052
1053
22
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1054
22
    if ((true)) {
1055
22
        *err = NET_ERR_CONNECT_OK;
1056
22
        return true;
1057
22
    }
1058
0
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
1059
1060
0
    Ip_Ntoa ip_str;
1061
0
    LOGGER_DEBUG(log, "connecting socket %d to %s:%d",
1062
0
                 net_socket_to_native(sock), net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port));
1063
0
    net_clear_error();
1064
1065
0
    if (ns_connect(ns, sock, ip_port) == -1) {
1066
0
        const int error = net_error();
1067
1068
        // Non-blocking socket: "Operation in progress" means it's connecting.
1069
0
        if (!net_should_ignore_connect_error(error)) {
1070
0
            Net_Strerror error_str;
1071
0
            LOGGER_WARNING(log, "failed to connect to %s:%d: %d (%s)",
1072
0
                           net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), error, net_strerror(error, &error_str));
1073
0
            *err = NET_ERR_CONNECT_FAILED;
1074
0
            return false;
1075
0
        }
1076
0
    }
1077
1078
0
    *err = NET_ERR_CONNECT_OK;
1079
0
    return true;
1080
0
}
1081
1082
int32_t net_getipport(const Network *ns, const Memory *mem, const char *node, IP_Port **res, int tox_type, bool dns_enabled)
1083
28.5k
{
1084
28.5k
    assert(node != nullptr);
1085
1086
    // Try parsing as IP address first.
1087
28.5k
    IP_Port parsed = {{{0}}};
1088
    // Initialise to nullptr. In error paths, at least we initialise the out
1089
    // parameter.
1090
28.5k
    *res = nullptr;
1091
1092
28.5k
    if (addr_parse_ip(node, &parsed.ip)) {
1093
28.5k
        IP_Port *tmp = (IP_Port *)mem_alloc(mem, sizeof(IP_Port));
1094
1095
28.5k
        if (tmp == nullptr) {
1096
13
            return -1;
1097
13
        }
1098
1099
28.5k
        tmp[0] = parsed;
1100
28.5k
        *res = tmp;
1101
28.5k
        return 1;
1102
28.5k
    }
1103
1104
26
    if (!dns_enabled) {
1105
0
        return -1;
1106
0
    }
1107
1108
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1109
0
    if ((true)) {
1110
0
        IP_Port *ip_port = (IP_Port *)mem_alloc(mem, sizeof(IP_Port));
1111
0
        if (ip_port == nullptr) {
1112
0
            abort();
1113
0
        }
1114
0
        ip_port->ip.ip.v4.uint32 = net_htonl(0x7F000003); // 127.0.0.3
1115
0
        ip_port->ip.family = net_family_ipv4();
1116
1117
0
        *res = ip_port;
1118
0
        return 1;
1119
0
    }
1120
0
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
1121
1122
26
    int type = tox_type;
1123
    // ugly
1124
26
    if (tox_type == -1) {
1125
0
        type = 0;
1126
0
    }
1127
1128
    // It's not an IP address, so now we try doing a DNS lookup.
1129
26
    IP_Port *addrs = nullptr;
1130
26
    const int rc = ns_getaddrinfo(ns, mem, node, TOX_AF_UNSPEC, type, &addrs);
1131
1132
    // Lookup failed / empty.
1133
26
    if (rc <= 0) {
1134
0
        return -1;
1135
0
    }
1136
1137
26
    assert(addrs != nullptr);
1138
1139
5
    *res = addrs;
1140
5
    return rc;
1141
26
}
net_getipport
Line
Count
Source
1083
60
{
1084
60
    assert(node != nullptr);
1085
1086
    // Try parsing as IP address first.
1087
60
    IP_Port parsed = {{{0}}};
1088
    // Initialise to nullptr. In error paths, at least we initialise the out
1089
    // parameter.
1090
60
    *res = nullptr;
1091
1092
60
    if (addr_parse_ip(node, &parsed.ip)) {
1093
60
        IP_Port *tmp = (IP_Port *)mem_alloc(mem, sizeof(IP_Port));
1094
1095
60
        if (tmp == nullptr) {
1096
13
            return -1;
1097
13
        }
1098
1099
47
        tmp[0] = parsed;
1100
47
        *res = tmp;
1101
47
        return 1;
1102
60
    }
1103
1104
0
    if (!dns_enabled) {
1105
0
        return -1;
1106
0
    }
1107
1108
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1109
0
    if ((true)) {
1110
0
        IP_Port *ip_port = (IP_Port *)mem_alloc(mem, sizeof(IP_Port));
1111
0
        if (ip_port == nullptr) {
1112
0
            abort();
1113
0
        }
1114
0
        ip_port->ip.ip.v4.uint32 = net_htonl(0x7F000003); // 127.0.0.3
1115
0
        ip_port->ip.family = net_family_ipv4();
1116
1117
0
        *res = ip_port;
1118
0
        return 1;
1119
0
    }
1120
0
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
1121
1122
0
    int type = tox_type;
1123
    // ugly
1124
0
    if (tox_type == -1) {
1125
0
        type = 0;
1126
0
    }
1127
1128
    // It's not an IP address, so now we try doing a DNS lookup.
1129
0
    IP_Port *addrs = nullptr;
1130
0
    const int rc = ns_getaddrinfo(ns, mem, node, TOX_AF_UNSPEC, type, &addrs);
1131
1132
    // Lookup failed / empty.
1133
0
    if (rc <= 0) {
1134
0
        return -1;
1135
0
    }
1136
1137
0
    assert(addrs != nullptr);
1138
1139
0
    *res = addrs;
1140
0
    return rc;
1141
0
}
net_getipport
Line
Count
Source
1083
28.5k
{
1084
28.5k
    assert(node != nullptr);
1085
1086
    // Try parsing as IP address first.
1087
28.5k
    IP_Port parsed = {{{0}}};
1088
    // Initialise to nullptr. In error paths, at least we initialise the out
1089
    // parameter.
1090
28.5k
    *res = nullptr;
1091
1092
28.5k
    if (addr_parse_ip(node, &parsed.ip)) {
1093
28.4k
        IP_Port *tmp = (IP_Port *)mem_alloc(mem, sizeof(IP_Port));
1094
1095
28.4k
        if (tmp == nullptr) {
1096
0
            return -1;
1097
0
        }
1098
1099
28.4k
        tmp[0] = parsed;
1100
28.4k
        *res = tmp;
1101
28.4k
        return 1;
1102
28.4k
    }
1103
1104
26
    if (!dns_enabled) {
1105
0
        return -1;
1106
0
    }
1107
1108
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1109
    if ((true)) {
1110
        IP_Port *ip_port = (IP_Port *)mem_alloc(mem, sizeof(IP_Port));
1111
        if (ip_port == nullptr) {
1112
            abort();
1113
        }
1114
        ip_port->ip.ip.v4.uint32 = net_htonl(0x7F000003); // 127.0.0.3
1115
        ip_port->ip.family = net_family_ipv4();
1116
1117
        *res = ip_port;
1118
        return 1;
1119
    }
1120
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
1121
1122
26
    int type = tox_type;
1123
    // ugly
1124
26
    if (tox_type == -1) {
1125
0
        type = 0;
1126
0
    }
1127
1128
    // It's not an IP address, so now we try doing a DNS lookup.
1129
26
    IP_Port *addrs = nullptr;
1130
26
    const int rc = ns_getaddrinfo(ns, mem, node, TOX_AF_UNSPEC, type, &addrs);
1131
1132
    // Lookup failed / empty.
1133
26
    if (rc <= 0) {
1134
0
        return -1;
1135
0
    }
1136
1137
26
    assert(addrs != nullptr);
1138
1139
5
    *res = addrs;
1140
5
    return rc;
1141
26
}
1142
1143
void net_freeipport(const Memory *mem, IP_Port *ip_ports)
1144
28.5k
{
1145
28.5k
    mem_delete(mem, ip_ports);
1146
28.5k
}
1147
1148
bool bind_to_port(const Network *ns, Socket sock, Family family, uint16_t port)
1149
36
{
1150
36
    IP_Port addr;
1151
36
    ip_init(&addr.ip, net_family_is_ipv6(family));
1152
36
    addr.ip.family = family;
1153
1154
36
    if (net_family_is_ipv4(family)) {
1155
19
        addr.ip.ip.v4.uint32 = 0;
1156
19
    } else {
1157
17
        memset(addr.ip.ip.v6.uint8, 0, 16);
1158
17
    }
1159
1160
36
    addr.port = net_htons(port);
1161
1162
36
    return ns_bind(ns, sock, &addr) == 0;
1163
36
}
1164
1165
Socket net_socket(const Network *ns, Family domain, int type, int protocol)
1166
2.18k
{
1167
2.18k
    return ns_socket(ns, domain.value, type, protocol);
1168
2.18k
}
1169
1170
uint16_t net_socket_data_recv_buffer(const Network *ns, Socket sock)
1171
77.1k
{
1172
77.1k
    const int count = ns_recvbuf(ns, sock);
1173
77.1k
    return (uint16_t)max_s32(0, min_s32(count, UINT16_MAX));
1174
77.1k
}
1175
1176
bool ipv6_ipv4_in_v6(const IP6 *a)
1177
113k
{
1178
113k
    return a->uint64[0] == 0 && a->uint32[2] == net_htonl(0xffff);
1179
113k
}
1180
1181
const Net_Profile *net_get_net_profile(const Networking_Core *net)
1182
2
{
1183
2
    if (net == nullptr) {
1184
0
        return nullptr;
1185
0
    }
1186
1187
2
    return net->udp_net_profile;
1188
2
}