• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14766779411

30 Apr 2025 04:55PM UTC coverage: 72.225% (-0.06%) from 72.282%
14766779411

push

github

web-flow
wait-online: handle varlink connection errors while waiting for DNS (#37283)

Currently, if systemd-networkd-wait-online is started with --dns, and
systemd-resolved is not running, it will exit with an error right away.
Similarly, if systemd-resolved is restarted while waiting for DNS
configuration, systemd-networkd-wait-online will not attempt to
re-connect, and will potentially never see subsequent DNS
configurations.

Improve this by adding socket units for the systemd-resolved varlink
servers, and re-establish the connection in systemd-networkd-wait-online
when we receive `SD_VARLINK_ERROR_DISCONNECTED`.

8 of 16 new or added lines in 2 files covered. (50.0%)

5825 existing lines in 217 files now uncovered.

297168 of 411450 relevant lines covered (72.22%)

695892.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.83
/src/basic/in-addr-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <arpa/inet.h>
4
#include <endian.h>
5
#include <errno.h>
6
#include <net/if.h>
7
#include <stdint.h>
8
#include <stdio.h>
9
#include <stdlib.h>
10

11
#include "alloc-util.h"
12
#include "errno-util.h"
13
#include "in-addr-util.h"
14
#include "logarithm.h"
15
#include "macro.h"
16
#include "memory-util.h"
17
#include "parse-util.h"
18
#include "random-util.h"
19
#include "stdio-util.h"
20
#include "string-util.h"
21
#include "strxcpyx.h"
22

23
bool in4_addr_is_null(const struct in_addr *a) {
119,070✔
24
        assert(a);
119,070✔
25

26
        return a->s_addr == 0;
119,070✔
27
}
28

29
bool in6_addr_is_null(const struct in6_addr *a) {
70,752✔
30
        assert(a);
70,752✔
31

32
        return eqzero(a->in6_u.u6_addr32);
70,752✔
33
}
34

35
int in_addr_is_null(int family, const union in_addr_union *u) {
106,790✔
36
        assert(u);
106,790✔
37

38
        if (family == AF_INET)
106,790✔
39
                return in4_addr_is_null(&u->in);
50,970✔
40

41
        if (family == AF_INET6)
55,820✔
42
                return in6_addr_is_null(&u->in6);
38,761✔
43

44
        return -EAFNOSUPPORT;
45
}
46

47
bool in4_addr_is_link_local(const struct in_addr *a) {
8,567✔
48
        assert(a);
8,567✔
49

50
        return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
8,567✔
51
}
52

53
bool in4_addr_is_link_local_dynamic(const struct in_addr *a) {
89✔
54
        assert(a);
89✔
55

56
        if (!in4_addr_is_link_local(a))
89✔
57
                return false;
58

59
        /* 169.254.0.0/24 and 169.254.255.0/24 must not be used for the dynamic IPv4LL assignment.
60
         * See RFC 3927 Section 2.1:
61
         * The IPv4 prefix 169.254/16 is registered with the IANA for this purpose. The first 256 and last
62
         * 256 addresses in the 169.254/16 prefix are reserved for future use and MUST NOT be selected by a
63
         * host using this dynamic configuration mechanism. */
64
        return !IN_SET(be32toh(a->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U);
88✔
65
}
66

67
bool in6_addr_is_link_local(const struct in6_addr *a) {
5,305✔
68
        assert(a);
5,305✔
69

70
        return (a->in6_u.u6_addr32[0] & htobe32(0xffc00000)) == htobe32(0xfe800000);
5,305✔
71
}
72

73
int in_addr_is_link_local(int family, const union in_addr_union *u) {
4,286✔
74
        assert(u);
4,286✔
75

76
        if (family == AF_INET)
4,286✔
77
                return in4_addr_is_link_local(&u->in);
3,110✔
78

79
        if (family == AF_INET6)
1,176✔
80
                return in6_addr_is_link_local(&u->in6);
1,176✔
81

82
        return -EAFNOSUPPORT;
83
}
84

85
bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
2✔
86
        assert(a);
2✔
87

88
        /* ff02::1 */
89
        return be32toh(a->s6_addr32[0]) == UINT32_C(0xff020000) &&
2✔
UNCOV
90
                a->s6_addr32[1] == 0 &&
×
91
                a->s6_addr32[2] == 0 &&
2✔
UNCOV
92
                be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
×
93
}
94

95
bool in4_addr_is_multicast(const struct in_addr *a) {
15✔
96
        assert(a);
15✔
97

98
        return IN_MULTICAST(be32toh(a->s_addr));
15✔
99
}
100

101
bool in6_addr_is_multicast(const struct in6_addr *a) {
182✔
102
        assert(a);
182✔
103

104
        return a->in6_u.u6_addr8[0] == 0xff;
182✔
105
}
106

107
int in_addr_is_multicast(int family, const union in_addr_union *u) {
24✔
108
        assert(u);
24✔
109

110
        if (family == AF_INET)
24✔
111
                return in4_addr_is_multicast(&u->in);
15✔
112

113
        if (family == AF_INET6)
9✔
114
                return in6_addr_is_multicast(&u->in6);
9✔
115

116
        return -EAFNOSUPPORT;
117
}
118

119
bool in4_addr_is_local_multicast(const struct in_addr *a) {
2✔
120
        assert(a);
2✔
121

122
        return (be32toh(a->s_addr) & UINT32_C(0xffffff00)) == UINT32_C(0xe0000000);
2✔
123
}
124

125
bool in4_addr_is_localhost(const struct in_addr *a) {
18,299✔
126
        assert(a);
18,299✔
127

128
        /* All of 127.x.x.x is localhost. */
129
        return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
18,299✔
130
}
131

132
bool in4_addr_is_non_local(const struct in_addr *a) {
815✔
133
        /* Whether the address is not null and not localhost.
134
         *
135
         * As such, it is suitable to configure as DNS/NTP server from DHCP. */
136
        return !in4_addr_is_null(a) &&
1,630✔
137
               !in4_addr_is_localhost(a);
815✔
138
}
139

140
static bool in6_addr_is_loopback(const struct in6_addr *a) {
11,844✔
141
        return memcmp(a, &(struct in6_addr) IN6ADDR_LOOPBACK_INIT, sizeof(struct in6_addr)) == 0;
11,844✔
142
}
143

144
int in_addr_is_localhost(int family, const union in_addr_union *u) {
26,976✔
145
        assert(u);
26,976✔
146

147
        if (family == AF_INET)
26,976✔
148
                return in4_addr_is_localhost(&u->in);
15,132✔
149

150
        if (family == AF_INET6)
11,844✔
151
                return in6_addr_is_loopback(&u->in6);
11,844✔
152

153
        return -EAFNOSUPPORT;
154
}
155

156
int in_addr_is_localhost_one(int family, const union in_addr_union *u) {
×
UNCOV
157
        assert(u);
×
158

159
        if (family == AF_INET)
×
160
                /* 127.0.0.1 */
UNCOV
161
                return be32toh(u->in.s_addr) == UINT32_C(0x7F000001);
×
162

UNCOV
163
        if (family == AF_INET6)
×
UNCOV
164
                return in6_addr_is_loopback(&u->in6);
×
165

166
        return -EAFNOSUPPORT;
167
}
168

169
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
5✔
170
        return a->s6_addr32[0] == 0 &&
6✔
171
                a->s6_addr32[1] == 0 &&
5✔
172
                a->s6_addr32[2] == htobe32(UINT32_C(0x0000ffff));
1✔
173
}
174

175
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
117,337✔
176
        assert(a);
117,337✔
177
        assert(b);
117,337✔
178

179
        return a->s_addr == b->s_addr;
117,337✔
180
}
181

182
bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b) {
14,022✔
183
        assert(a);
14,022✔
184
        assert(b);
14,022✔
185

186
        return memcmp(a, b, sizeof(struct in6_addr)) == 0;
14,022✔
187
}
188

189
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
118,201✔
190
        assert(a);
118,201✔
191
        assert(b);
118,201✔
192

193
        if (family == AF_INET)
118,201✔
194
                return in4_addr_equal(&a->in, &b->in);
109,188✔
195

196
        if (family == AF_INET6)
9,013✔
197
                return in6_addr_equal(&a->in6, &b->in6);
9,013✔
198

199
        return -EAFNOSUPPORT;
200
}
201

202
bool in4_addr_prefix_intersect(
824✔
203
                const struct in_addr *a,
204
                unsigned aprefixlen,
205
                const struct in_addr *b,
206
                unsigned bprefixlen) {
207

208
        assert(a);
824✔
209
        assert(b);
824✔
210

211
        unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in_addr) * 8));
824✔
212
        if (m == 0)
824✔
213
                return true; /* Let's return earlier, to avoid shift by 32. */
214

215
        uint32_t x = be32toh(a->s_addr ^ b->s_addr);
822✔
216
        uint32_t n = 0xFFFFFFFFUL << (32 - m);
822✔
217
        return (x & n) == 0;
822✔
218
}
219

220
bool in6_addr_prefix_intersect(
521✔
221
                const struct in6_addr *a,
222
                unsigned aprefixlen,
223
                const struct in6_addr *b,
224
                unsigned bprefixlen) {
225

226
        assert(a);
521✔
227
        assert(b);
521✔
228

229
        unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in6_addr) * 8));
521✔
230
        if (m == 0)
521✔
231
                return true;
232

233
        for (size_t i = 0; i < sizeof(struct in6_addr); i++) {
844✔
234
                uint8_t x = a->s6_addr[i] ^ b->s6_addr[i];
844✔
235
                uint8_t n = m < 8 ? (0xFF << (8 - m)) : 0xFF;
844✔
236
                if ((x & n) != 0)
844✔
237
                        return false;
238

239
                if (m <= 8)
344✔
240
                        break;
241

242
                m -= 8;
325✔
243
        }
244

245
        return true;
246
}
247

248
int in_addr_prefix_intersect(
1,312✔
249
                int family,
250
                const union in_addr_union *a,
251
                unsigned aprefixlen,
252
                const union in_addr_union *b,
253
                unsigned bprefixlen) {
254

255
        assert(a);
1,312✔
256
        assert(b);
1,312✔
257

258
        /* Checks whether there are any addresses that are in both networks. */
259

260
        if (family == AF_INET)
1,312✔
261
                return in4_addr_prefix_intersect(&a->in, aprefixlen, &b->in, bprefixlen);
824✔
262

263
        if (family == AF_INET6)
488✔
264
                return in6_addr_prefix_intersect(&a->in6, aprefixlen, &b->in6, bprefixlen);
488✔
265

266
        return -EAFNOSUPPORT;
267
}
268

269
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
15✔
270
        assert(u);
15✔
271

272
        /* Increases the network part of an address by one. Returns 0 if that succeeds, or -ERANGE if
273
         * this overflows. */
274

275
        return in_addr_prefix_nth(family, u, prefixlen, 1);
15✔
276
}
277

278
/*
279
 * Calculates the nth prefix of size prefixlen starting from the address denoted by u.
280
 *
281
 * On success 0 will be returned and the calculated prefix will be available in
282
 * u. In case the calculation cannot be performed (invalid prefix length,
283
 * overflows would occur) -ERANGE is returned. If the address family given isn't
284
 * supported -EAFNOSUPPORT will be returned.
285
 *
286
 * Examples:
287
 *   - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 0, writes 192.168.2.0 to u
288
 *   - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 0, no data written
289
 *   - in_addr_prefix_nth(AF_INET, 255.255.255.0, 24, 1), returns -ERANGE, no data written
290
 *   - in_addr_prefix_nth(AF_INET, 255.255.255.0, 0, 1), returns -ERANGE, no data written
291
 *   - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 0, writes 2001:0db8:0000:ff00:: to u
292
 */
293
int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth) {
138✔
294
        assert(u);
138✔
295

296
        if (prefixlen <= 0)
138✔
297
                return -ERANGE;
298

299
        if (family == AF_INET) {
136✔
300
                uint32_t c, n, t;
19✔
301

302
                if (prefixlen > 32)
19✔
303
                        return -ERANGE;
304

305
                c = be32toh(u->in.s_addr);
19✔
306

307
                t = nth << (32 - prefixlen);
19✔
308

309
                /* Check for wrap */
310
                if (c > UINT32_MAX - t)
19✔
311
                        return -ERANGE;
312

313
                n = c + t;
16✔
314

315
                n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen);
16✔
316
                u->in.s_addr = htobe32(n);
16✔
317
                return 0;
16✔
318
        }
319

320
        if (family == AF_INET6) {
117✔
321
                bool overflow = false;
117✔
322

323
                if (prefixlen > 128)
117✔
324
                        return -ERANGE;
325

326
                for (unsigned i = 16; i > 0; i--) {
1,989✔
327
                        unsigned t, j = i - 1, p = j * 8;
1,872✔
328

329
                        if (p >= prefixlen) {
1,872✔
330
                                u->in6.s6_addr[j] = 0;
893✔
331
                                continue;
893✔
332
                        }
333

334
                        if (prefixlen - p < 8) {
979✔
335
                                u->in6.s6_addr[j] &= 0xff << (8 - (prefixlen - p));
14✔
336
                                t = u->in6.s6_addr[j] + ((nth & 0xff) << (8 - (prefixlen - p)));
14✔
337
                                nth >>= prefixlen - p;
14✔
338
                        } else {
339
                                t = u->in6.s6_addr[j] + (nth & 0xff) + overflow;
965✔
340
                                nth >>= 8;
965✔
341
                        }
342

343
                        overflow = t > UINT8_MAX;
979✔
344
                        u->in6.s6_addr[j] = (uint8_t) (t & 0xff);
979✔
345
                }
346

347
                if (overflow || nth != 0)
117✔
348
                        return -ERANGE;
349

350
                return 0;
113✔
351
        }
352

353
        return -EAFNOSUPPORT;
354
}
355

356
int in_addr_random_prefix(
42✔
357
                int family,
358
                union in_addr_union *u,
359
                unsigned prefixlen_fixed_part,
360
                unsigned prefixlen) {
361

362
        assert(u);
42✔
363

364
        /* Random network part of an address by one. */
365

366
        if (prefixlen <= 0)
42✔
367
                return 0;
368

369
        if (family == AF_INET) {
42✔
370
                uint32_t c, n;
23✔
371

372
                if (prefixlen_fixed_part > 32)
23✔
UNCOV
373
                        prefixlen_fixed_part = 32;
×
374
                if (prefixlen > 32)
23✔
UNCOV
375
                        prefixlen = 32;
×
376
                if (prefixlen_fixed_part >= prefixlen)
23✔
377
                        return -EINVAL;
23✔
378

379
                c = be32toh(u->in.s_addr);
23✔
380
                c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
23✔
381

382
                random_bytes(&n, sizeof(n));
23✔
383
                n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
23✔
384

385
                u->in.s_addr = htobe32(n | c);
23✔
386
                return 1;
23✔
387
        }
388

389
        if (family == AF_INET6) {
19✔
390
                struct in6_addr n;
19✔
391
                unsigned i, j;
19✔
392

393
                if (prefixlen_fixed_part > 128)
19✔
UNCOV
394
                        prefixlen_fixed_part = 128;
×
395
                if (prefixlen > 128)
19✔
UNCOV
396
                        prefixlen = 128;
×
397
                if (prefixlen_fixed_part >= prefixlen)
19✔
398
                        return -EINVAL;
19✔
399

400
                random_bytes(&n, sizeof(n));
19✔
401

402
                for (i = 0; i < 16; i++) {
323✔
403
                        uint8_t mask_fixed_part = 0, mask = 0;
304✔
404

405
                        if (i < (prefixlen_fixed_part + 7) / 8) {
304✔
406
                                if (i < prefixlen_fixed_part / 8)
20✔
407
                                        mask_fixed_part = 0xffu;
408
                                else {
UNCOV
409
                                        j = prefixlen_fixed_part % 8;
×
UNCOV
410
                                        mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
×
411
                                }
412
                        }
413

414
                        if (i < (prefixlen + 7) / 8) {
304✔
415
                                if (i < prefixlen / 8)
178✔
416
                                        mask = 0xffu ^ mask_fixed_part;
162✔
417
                                else {
418
                                        j = prefixlen % 8;
16✔
419
                                        mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
16✔
420
                                }
421
                        }
422

423
                        u->in6.s6_addr[i] &= mask_fixed_part;
304✔
424
                        u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
304✔
425
                }
426

427
                return 1;
428
        }
429

430
        return -EAFNOSUPPORT;
431
}
432

433
int in_addr_prefix_range(
51✔
434
                int family,
435
                const union in_addr_union *in,
436
                unsigned prefixlen,
437
                union in_addr_union *ret_start,
438
                union in_addr_union *ret_end) {
439

440
        union in_addr_union start, end;
51✔
441
        int r;
51✔
442

443
        assert(in);
51✔
444

445
        if (!IN_SET(family, AF_INET, AF_INET6))
51✔
446
                return -EAFNOSUPPORT;
51✔
447

448
        if (ret_start) {
51✔
449
                start = *in;
51✔
450
                r = in_addr_prefix_nth(family, &start, prefixlen, 0);
51✔
451
                if (r < 0)
51✔
452
                        return r;
453
        }
454

455
        if (ret_end) {
51✔
456
                end = *in;
51✔
457
                r = in_addr_prefix_nth(family, &end, prefixlen, 1);
51✔
458
                if (r < 0)
51✔
459
                        return r;
460
        }
461

462
        if (ret_start)
51✔
463
                *ret_start = start;
51✔
464
        if (ret_end)
51✔
465
                *ret_end = end;
51✔
466

467
        return 0;
468
}
469

470
int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
9,630✔
471
        _cleanup_free_ char *x = NULL;
19,260✔
472
        size_t l;
9,630✔
473

474
        assert(u);
9,630✔
475
        assert(ret);
9,630✔
476

477
        if (family == AF_INET)
9,630✔
478
                l = INET_ADDRSTRLEN;
479
        else if (family == AF_INET6)
1,506✔
480
                l = INET6_ADDRSTRLEN;
481
        else
482
                return -EAFNOSUPPORT;
483

484
        x = new(char, l);
9,630✔
485
        if (!x)
9,630✔
486
                return -ENOMEM;
487

488
        errno = 0;
9,630✔
489
        if (!typesafe_inet_ntop(family, u, x, l))
9,630✔
UNCOV
490
                return errno_or_else(EINVAL);
×
491

492
        *ret = TAKE_PTR(x);
9,630✔
493
        return 0;
9,630✔
494
}
495

496
int in_addr_prefix_to_string(
414,564✔
497
                int family,
498
                const union in_addr_union *u,
499
                unsigned prefixlen,
500
                char *buf,
501
                size_t buf_len) {
502

503
        assert(u);
414,564✔
504
        assert(buf);
414,564✔
505

506
        if (!IN_SET(family, AF_INET, AF_INET6))
414,564✔
507
                return -EAFNOSUPPORT;
508

509
        errno = 0;
414,564✔
510
        if (!typesafe_inet_ntop(family, u, buf, buf_len))
414,564✔
UNCOV
511
                return errno_or_else(ENOSPC);
×
512

513
        size_t l = strlen(buf);
414,564✔
514
        if (!snprintf_ok(buf + l, buf_len - l, "/%u", prefixlen))
414,564✔
UNCOV
515
                return -ENOSPC;
×
516
        return 0;
517
}
518

519
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) {
1,813✔
520
        _cleanup_free_ char *ip_str = NULL, *x = NULL;
1,813✔
521
        int r;
1,813✔
522

523
        assert(IN_SET(family, AF_INET, AF_INET6));
1,813✔
524
        assert(u);
1,813✔
525
        assert(ret);
1,813✔
526

527
        /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
528
         * handle IPv6 link-local addresses. */
529

530
        r = in_addr_to_string(family, u, &ip_str);
1,813✔
531
        if (r < 0)
1,813✔
532
                return r;
533

534
        if (family == AF_INET6) {
1,813✔
535
                r = in_addr_is_link_local(family, u);
778✔
536
                if (r < 0)
778✔
537
                        return r;
538
                if (r == 0)
778✔
539
                        ifindex = 0;
725✔
540
        } else
541
                ifindex = 0; /* For IPv4 address, ifindex is always ignored. */
542

543
        if (port == 0 && ifindex == 0 && isempty(server_name)) {
1,813✔
544
                *ret = TAKE_PTR(ip_str);
1,445✔
545
                return 0;
1,445✔
546
        }
547

548
        const char *separator = isempty(server_name) ? "" : "#";
368✔
549
        server_name = strempty(server_name);
368✔
550

551
        if (port > 0) {
368✔
552
                if (family == AF_INET6) {
26✔
553
                        if (ifindex > 0)
16✔
554
                                r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
10✔
555
                        else
556
                                r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
6✔
557
                } else
558
                        r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
10✔
559
        } else {
560
                if (ifindex > 0)
342✔
561
                        r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name);
24✔
562
                else {
563
                        x = strjoin(ip_str, separator, server_name);
318✔
564
                        r = x ? 0 : -ENOMEM;
318✔
565
                }
566
        }
567
        if (r < 0)
50✔
UNCOV
568
                return -ENOMEM;
×
569

570
        *ret = TAKE_PTR(x);
368✔
571
        return 0;
368✔
572
}
573

574
int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
216,628✔
575
        union in_addr_union buffer;
216,628✔
576
        assert(s);
216,628✔
577

578
        if (!IN_SET(family, AF_INET, AF_INET6))
216,628✔
579
                return -EAFNOSUPPORT;
216,628✔
580

581
        errno = 0;
216,628✔
582
        if (inet_pton(family, s, ret ?: &buffer) <= 0)
217,833✔
583
                return errno_or_else(EINVAL);
71,450✔
584

585
        return 0;
586
}
587

588
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
140,225✔
589
        int r;
140,225✔
590

591
        assert(s);
140,225✔
592

593
        r = in_addr_from_string(AF_INET, s, ret);
140,225✔
594
        if (r >= 0) {
140,225✔
595
                if (ret_family)
72,009✔
596
                        *ret_family = AF_INET;
71,786✔
597
                return 0;
72,009✔
598
        }
599

600
        r = in_addr_from_string(AF_INET6, s, ret);
68,216✔
601
        if (r >= 0) {
68,216✔
602
                if (ret_family)
67,637✔
603
                        *ret_family = AF_INET6;
67,623✔
604
                return 0;
67,637✔
605
        }
606

607
        return -EINVAL;
608
}
609

610
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
342✔
611
        assert(addr);
342✔
612

613
        return 32U - u32ctz(be32toh(addr->s_addr));
342✔
614
}
615

616
/* Calculate an IPv4 netmask from prefix length, for example /8 -> 255.0.0.0. */
617
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
183,560✔
618
        assert(addr);
183,560✔
619
        assert(prefixlen <= 32);
183,560✔
620

621
        /* Shifting beyond 32 is not defined, handle this specially. */
622
        if (prefixlen == 0)
183,560✔
623
                addr->s_addr = 0;
2,026✔
624
        else
625
                addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
181,534✔
626

627
        return addr;
183,560✔
628
}
629

630
/* Calculate an IPv6 netmask from prefix length, for example /16 -> ffff::. */
631
struct in6_addr* in6_addr_prefixlen_to_netmask(struct in6_addr *addr, unsigned char prefixlen) {
165✔
632
        assert(addr);
165✔
633
        assert(prefixlen <= 128);
165✔
634

635
        for (unsigned i = 0; i < 16; i++) {
2,805✔
636
                uint8_t mask;
2,640✔
637

638
                if (prefixlen >= 8) {
2,640✔
639
                        mask = 0xFF;
1,264✔
640
                        prefixlen -= 8;
1,264✔
641
                } else if (prefixlen > 0) {
1,376✔
642
                        mask = 0xFF << (8 - prefixlen);
112✔
643
                        prefixlen = 0;
112✔
644
                } else {
645
                        assert(prefixlen == 0);
646
                        mask = 0;
647
                }
648

649
                addr->s6_addr[i] = mask;
2,640✔
650
        }
651

652
        return addr;
165✔
653
}
654

655
/* Calculate an IPv4 or IPv6 netmask from prefix length, for example /8 -> 255.0.0.0 or /16 -> ffff::. */
656
int in_addr_prefixlen_to_netmask(int family, union in_addr_union *addr, unsigned char prefixlen) {
226✔
657
        assert(addr);
226✔
658

659
        switch (family) {
226✔
660
        case AF_INET:
61✔
661
                in4_addr_prefixlen_to_netmask(&addr->in, prefixlen);
61✔
662
                return 0;
61✔
663
        case AF_INET6:
165✔
664
                in6_addr_prefixlen_to_netmask(&addr->in6, prefixlen);
165✔
665
                return 0;
165✔
666
        default:
667
                return -EAFNOSUPPORT;
668
        }
669
}
670

671
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
32✔
672
        uint8_t msb_octet = *(uint8_t*) addr;
32✔
673

674
        /* addr may not be aligned, so make sure we only access it byte-wise */
675

676
        assert(addr);
32✔
677
        assert(prefixlen);
32✔
678

679
        if (msb_octet < 128)
32✔
680
                /* class A, leading bits: 0 */
681
                *prefixlen = 8;
16✔
682
        else if (msb_octet < 192)
16✔
683
                /* class B, leading bits 10 */
UNCOV
684
                *prefixlen = 16;
×
685
        else if (msb_octet < 224)
16✔
686
                /* class C, leading bits 110 */
687
                *prefixlen = 24;
16✔
688
        else
689
                /* class D or E, no default prefixlen */
690
                return -ERANGE;
691

692
        return 0;
693
}
694

695
int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
×
UNCOV
696
        unsigned char prefixlen;
×
697
        int r;
×
698

699
        assert(addr);
×
UNCOV
700
        assert(mask);
×
701

UNCOV
702
        r = in4_addr_default_prefixlen(addr, &prefixlen);
×
UNCOV
703
        if (r < 0)
×
UNCOV
704
                return r;
×
705

UNCOV
706
        in4_addr_prefixlen_to_netmask(mask, prefixlen);
×
707
        return 0;
708
}
709

710
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen) {
183,467✔
711
        struct in_addr mask;
183,467✔
712

713
        assert(addr);
183,467✔
714

715
        if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
183,467✔
716
                return -EINVAL;
183,467✔
717

718
        addr->s_addr &= mask.s_addr;
183,467✔
719
        return 0;
183,467✔
720
}
721

722
int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen) {
140,614✔
723
        unsigned i;
140,614✔
724

725
        for (i = 0; i < 16; i++) {
2,390,438✔
726
                uint8_t mask;
2,249,824✔
727

728
                if (prefixlen >= 8) {
2,249,824✔
729
                        mask = 0xFF;
422,408✔
730
                        prefixlen -= 8;
422,408✔
731
                } else if (prefixlen > 0) {
1,827,416✔
732
                        mask = 0xFF << (8 - prefixlen);
270✔
733
                        prefixlen = 0;
270✔
734
                } else {
735
                        assert(prefixlen == 0);
736
                        mask = 0;
737
                }
738

739
                addr->s6_addr[i] &= mask;
2,249,824✔
740
        }
741

742
        return 0;
140,614✔
743
}
744

745
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
267,568✔
746
        assert(addr);
267,568✔
747

748
        switch (family) {
267,568✔
749
        case AF_INET:
133,775✔
750
                return in4_addr_mask(&addr->in, prefixlen);
133,775✔
751
        case AF_INET6:
133,793✔
752
                return in6_addr_mask(&addr->in6, prefixlen);
133,793✔
753
        default:
754
                return -EAFNOSUPPORT;
755
        }
756
}
757

758
int in4_addr_prefix_covers_full(
3,277✔
759
                const struct in_addr *prefix,
760
                unsigned char prefixlen,
761
                const struct in_addr *address,
762
                unsigned char address_prefixlen) {
763

764
        struct in_addr masked_prefix, masked_address;
3,277✔
765
        int r;
3,277✔
766

767
        assert(prefix);
3,277✔
768
        assert(address);
3,277✔
769

770
        if (prefixlen > address_prefixlen)
3,277✔
771
                return false;
3,277✔
772

773
        masked_prefix = *prefix;
2,749✔
774
        r = in4_addr_mask(&masked_prefix, prefixlen);
2,749✔
775
        if (r < 0)
2,749✔
776
                return r;
777

778
        masked_address = *address;
2,749✔
779
        r = in4_addr_mask(&masked_address, prefixlen);
2,749✔
780
        if (r < 0)
2,749✔
781
                return r;
782

783
        return in4_addr_equal(&masked_prefix, &masked_address);
2,749✔
784
}
785

786
int in6_addr_prefix_covers_full(
3,181✔
787
                const struct in6_addr *prefix,
788
                unsigned char prefixlen,
789
                const struct in6_addr *address,
790
                unsigned char address_prefixlen) {
791

792
        struct in6_addr masked_prefix, masked_address;
3,181✔
793
        int r;
3,181✔
794

795
        assert(prefix);
3,181✔
796
        assert(address);
3,181✔
797

798
        if (prefixlen > address_prefixlen)
3,181✔
799
                return false;
3,181✔
800

801
        masked_prefix = *prefix;
3,181✔
802
        r = in6_addr_mask(&masked_prefix, prefixlen);
3,181✔
803
        if (r < 0)
3,181✔
804
                return r;
805

806
        masked_address = *address;
3,181✔
807
        r = in6_addr_mask(&masked_address, prefixlen);
3,181✔
808
        if (r < 0)
3,181✔
809
                return r;
810

811
        return in6_addr_equal(&masked_prefix, &masked_address);
3,181✔
812
}
813

814
int in_addr_prefix_covers_full(
6,188✔
815
                int family,
816
                const union in_addr_union *prefix,
817
                unsigned char prefixlen,
818
                const union in_addr_union *address,
819
                unsigned char address_prefixlen) {
820

821
        assert(prefix);
6,188✔
822
        assert(address);
6,188✔
823

824
        switch (family) {
6,188✔
825
        case AF_INET:
3,078✔
826
                return in4_addr_prefix_covers_full(&prefix->in, prefixlen, &address->in, address_prefixlen);
3,078✔
827
        case AF_INET6:
3,110✔
828
                return in6_addr_prefix_covers_full(&prefix->in6, prefixlen, &address->in6, address_prefixlen);
3,110✔
829
        default:
830
                return -EAFNOSUPPORT;
831
        }
832
}
833

834
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
140,056✔
835
        uint8_t u;
140,056✔
836
        int r;
140,056✔
837

838
        if (!IN_SET(family, AF_INET, AF_INET6))
140,056✔
839
                return -EAFNOSUPPORT;
140,056✔
840

841
        r = safe_atou8(p, &u);
140,056✔
842
        if (r < 0)
140,056✔
843
                return r;
844

845
        if (u > FAMILY_ADDRESS_SIZE(family) * 8)
140,052✔
846
                return -ERANGE;
847

848
        *ret = u;
140,048✔
849
        return 0;
140,048✔
850
}
851

852
int in_addr_prefix_from_string(
1,416✔
853
                const char *p,
854
                int family,
855
                union in_addr_union *ret_prefix,
856
                unsigned char *ret_prefixlen) {
857

858
        _cleanup_free_ char *str = NULL;
1,416✔
859
        union in_addr_union buffer;
1,416✔
860
        const char *e, *l;
1,416✔
861
        unsigned char k;
1,416✔
862
        int r;
1,416✔
863

864
        assert(p);
1,416✔
865

866
        if (!IN_SET(family, AF_INET, AF_INET6))
1,416✔
867
                return -EAFNOSUPPORT;
868

869
        e = strchr(p, '/');
1,416✔
870
        if (e) {
1,416✔
871
                str = strndup(p, e - p);
1,400✔
872
                if (!str)
1,400✔
873
                        return -ENOMEM;
874

875
                l = str;
876
        } else
877
                l = p;
878

879
        r = in_addr_from_string(family, l, &buffer);
1,416✔
880
        if (r < 0)
1,416✔
881
                return r;
882

883
        if (e) {
1,408✔
884
                r = in_addr_parse_prefixlen(family, e+1, &k);
1,395✔
885
                if (r < 0)
1,395✔
886
                        return r;
887
        } else
888
                k = FAMILY_ADDRESS_SIZE(family) * 8;
13✔
889

890
        if (ret_prefix)
1,404✔
891
                *ret_prefix = buffer;
1,404✔
892
        if (ret_prefixlen)
1,404✔
893
                *ret_prefixlen = k;
1,404✔
894

895
        return 0;
896
}
897

898
int in_addr_prefix_from_string_auto_full(
138,957✔
899
                const char *p,
900
                InAddrPrefixLenMode mode,
901
                int *ret_family,
902
                union in_addr_union *ret_prefix,
903
                unsigned char *ret_prefixlen) {
904

905
        _cleanup_free_ char *str = NULL;
138,957✔
906
        union in_addr_union buffer;
138,957✔
907
        const char *e, *l;
138,957✔
908
        unsigned char k;
138,957✔
909
        int family, r;
138,957✔
910

911
        assert(p);
138,957✔
912

913
        e = strchr(p, '/');
138,957✔
914
        if (e) {
138,957✔
915
                str = strndup(p, e - p);
138,665✔
916
                if (!str)
138,665✔
917
                        return -ENOMEM;
918

919
                l = str;
920
        } else
921
                l = p;
922

923
        r = in_addr_from_string_auto(l, &family, &buffer);
138,957✔
924
        if (r < 0)
138,957✔
925
                return r;
926

927
        if (e) {
138,926✔
928
                r = in_addr_parse_prefixlen(family, e+1, &k);
138,661✔
929
                if (r < 0)
138,661✔
930
                        return r;
931
        } else
932
                switch (mode) {
265✔
933
                case PREFIXLEN_FULL:
249✔
934
                        k = FAMILY_ADDRESS_SIZE(family) * 8;
249✔
935
                        break;
249✔
936
                case PREFIXLEN_REFUSE:
937
                        return -ENOANO; /* To distinguish this error from others. */
UNCOV
938
                default:
×
UNCOV
939
                        assert_not_reached();
×
940
                }
941

942
        if (ret_family)
138,906✔
943
                *ret_family = family;
138,906✔
944
        if (ret_prefix)
138,906✔
945
                *ret_prefix = buffer;
138,906✔
946
        if (ret_prefixlen)
138,906✔
947
                *ret_prefixlen = k;
138,906✔
948

949
        return 0;
950
}
951

952
void in_addr_hash_func(const union in_addr_union *u, int family, struct siphash *state) {
829,413✔
953
        assert(u);
829,413✔
954
        assert(state);
829,413✔
955

956
        siphash24_compress(u->bytes, FAMILY_ADDRESS_SIZE(family), state);
829,413✔
957
}
829,413✔
958

959
void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
125✔
960
        assert(a);
125✔
961
        assert(state);
125✔
962

963
        siphash24_compress_typesafe(a->family, state);
125✔
964
        in_addr_hash_func(&a->address, a->family, state);
125✔
965
}
125✔
966

967
int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
81✔
968
        int r;
81✔
969

970
        assert(x);
81✔
971
        assert(y);
81✔
972

973
        r = CMP(x->family, y->family);
81✔
974
        if (r != 0)
71✔
975
                return r;
14✔
976

977
        return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
67✔
978
}
979

980
DEFINE_HASH_OPS(
981
        in_addr_data_hash_ops,
982
        struct in_addr_data,
983
        in_addr_data_hash_func,
984
        in_addr_data_compare_func);
985

986
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
25✔
987
        in_addr_data_hash_ops_free,
988
        struct in_addr_data,
989
        in_addr_data_hash_func,
990
        in_addr_data_compare_func,
991
        free);
992

993
void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
446✔
994
        assert(addr);
446✔
995
        assert(state);
446✔
996

997
        siphash24_compress_typesafe(*addr, state);
446✔
998
}
446✔
999

1000
int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
161✔
1001
        assert(a);
161✔
1002
        assert(b);
161✔
1003

1004
        return memcmp(a, b, sizeof(*a));
161✔
1005
}
1006

1007
DEFINE_HASH_OPS(
1008
        in6_addr_hash_ops,
1009
        struct in6_addr,
1010
        in6_addr_hash_func,
1011
        in6_addr_compare_func);
1012

1013
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
5✔
1014
        in6_addr_hash_ops_free,
1015
        struct in6_addr,
1016
        in6_addr_hash_func,
1017
        in6_addr_compare_func,
1018
        free);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc