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

systemd / systemd / 23966986054

03 Apr 2026 09:22PM UTC coverage: 72.107% (-0.3%) from 72.362%
23966986054

push

github

daandemeyer
fd-util: Add missing assert()

1 of 1 new or added line in 1 file covered. (100.0%)

7891 existing lines in 120 files now uncovered.

318256 of 441368 relevant lines covered (72.11%)

1186882.96 hits per line

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

94.09
/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 <stdio.h>
6

7
#include "alloc-util.h"
8
#include "errno-util.h"
9
#include "hash-funcs.h"
10
#include "in-addr-util.h"
11
#include "logarithm.h"
12
#include "memory-util.h"
13
#include "parse-util.h"
14
#include "random-util.h"
15
#include "siphash24.h"
16
#include "stdio-util.h"
17
#include "string-util.h"
18

19
bool in4_addr_is_null(const struct in_addr *a) {
153,402✔
20
        assert(a);
153,402✔
21

22
        return a->s_addr == 0;
153,402✔
23
}
24

25
bool in6_addr_is_null(const struct in6_addr *a) {
103,016✔
26
        assert(a);
103,016✔
27

28
        return eqzero(a->s6_addr32);
103,016✔
29
}
30

31
int in_addr_is_null(int family, const union in_addr_union *u) {
175,176✔
32
        assert(u);
175,176✔
33

34
        if (family == AF_INET)
175,176✔
35
                return in4_addr_is_null(&u->in);
79,429✔
36

37
        if (family == AF_INET6)
95,747✔
38
                return in6_addr_is_null(&u->in6);
67,599✔
39

40
        return -EAFNOSUPPORT;
41
}
42

43
bool in4_addr_is_link_local(const struct in_addr *a) {
11,705✔
44
        assert(a);
11,705✔
45

46
        return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
11,705✔
47
}
48

49
bool in4_addr_is_link_local_dynamic(const struct in_addr *a) {
90✔
50
        assert(a);
90✔
51

52
        if (!in4_addr_is_link_local(a))
90✔
53
                return false;
54

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

63
bool in6_addr_is_link_local(const struct in6_addr *a) {
6,131✔
64
        assert(a);
6,131✔
65

66
        return (a->s6_addr32[0] & htobe32(0xffc00000)) == htobe32(0xfe800000);
6,131✔
67
}
68

69
int in_addr_is_link_local(int family, const union in_addr_union *u) {
6,467✔
70
        assert(u);
6,467✔
71

72
        if (family == AF_INET)
6,467✔
73
                return in4_addr_is_link_local(&u->in);
4,532✔
74

75
        if (family == AF_INET6)
1,935✔
76
                return in6_addr_is_link_local(&u->in6);
1,935✔
77

78
        return -EAFNOSUPPORT;
79
}
80

81
bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
2✔
82
        assert(a);
2✔
83

84
        /* ff02::1 */
85
        return be32toh(a->s6_addr32[0]) == UINT32_C(0xff020000) &&
2✔
86
                a->s6_addr32[1] == 0 &&
×
87
                a->s6_addr32[2] == 0 &&
2✔
88
                be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
×
89
}
90

91
bool in4_addr_is_multicast(const struct in_addr *a) {
15✔
92
        assert(a);
15✔
93

94
        return IN_MULTICAST(be32toh(a->s_addr));
15✔
95
}
96

97
bool in6_addr_is_multicast(const struct in6_addr *a) {
198✔
98
        assert(a);
198✔
99

100
        return a->s6_addr[0] == 0xff;
198✔
101
}
102

103
int in_addr_is_multicast(int family, const union in_addr_union *u) {
24✔
104
        assert(u);
24✔
105

106
        if (family == AF_INET)
24✔
107
                return in4_addr_is_multicast(&u->in);
15✔
108

109
        if (family == AF_INET6)
9✔
110
                return in6_addr_is_multicast(&u->in6);
9✔
111

112
        return -EAFNOSUPPORT;
113
}
114

115
bool in4_addr_is_local_multicast(const struct in_addr *a) {
2✔
116
        assert(a);
2✔
117

118
        return (be32toh(a->s_addr) & UINT32_C(0xffffff00)) == UINT32_C(0xe0000000);
2✔
119
}
120

121
bool in4_addr_is_localhost(const struct in_addr *a) {
27,792✔
122
        assert(a);
27,792✔
123

124
        /* All of 127.x.x.x is localhost. */
125
        return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
27,792✔
126
}
127

128
bool in4_addr_is_non_local(const struct in_addr *a) {
1,092✔
129
        /* Whether the address is not null and not localhost.
130
         *
131
         * As such, it is suitable to configure as DNS/NTP server from DHCP. */
132
        return !in4_addr_is_null(a) &&
2,184✔
133
               !in4_addr_is_localhost(a);
1,092✔
134
}
135

136
static bool in6_addr_is_loopback(const struct in6_addr *a) {
19,226✔
137
        return memcmp(a, &(struct in6_addr) IN6ADDR_LOOPBACK_INIT, sizeof(struct in6_addr)) == 0;
19,226✔
138
}
139

140
int in_addr_is_localhost(int family, const union in_addr_union *u) {
42,726✔
141
        assert(u);
42,726✔
142

143
        if (family == AF_INET)
42,726✔
144
                return in4_addr_is_localhost(&u->in);
23,500✔
145

146
        if (family == AF_INET6)
19,226✔
147
                return in6_addr_is_loopback(&u->in6);
19,226✔
148

149
        return -EAFNOSUPPORT;
150
}
151

152
int in_addr_is_localhost_one(int family, const union in_addr_union *u) {
×
153
        assert(u);
×
154

155
        if (family == AF_INET)
×
156
                /* 127.0.0.1 */
157
                return be32toh(u->in.s_addr) == UINT32_C(0x7F000001);
×
158

159
        if (family == AF_INET6)
×
160
                return in6_addr_is_loopback(&u->in6);
×
161

162
        return -EAFNOSUPPORT;
163
}
164

165
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
5✔
166
        return a->s6_addr32[0] == 0 &&
6✔
167
                a->s6_addr32[1] == 0 &&
5✔
168
                a->s6_addr32[2] == htobe32(UINT32_C(0x0000ffff));
1✔
169
}
170

171
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
118,559✔
172
        assert(a);
118,559✔
173
        assert(b);
118,559✔
174

175
        return a->s_addr == b->s_addr;
118,559✔
176
}
177

178
bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b) {
15,778✔
179
        assert(a);
15,778✔
180
        assert(b);
15,778✔
181

182
        return memcmp(a, b, sizeof(struct in6_addr)) == 0;
15,778✔
183
}
184

185
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
120,598✔
186
        assert(a);
120,598✔
187
        assert(b);
120,598✔
188

189
        if (family == AF_INET)
120,598✔
190
                return in4_addr_equal(&a->in, &b->in);
110,138✔
191

192
        if (family == AF_INET6)
10,460✔
193
                return in6_addr_equal(&a->in6, &b->in6);
10,460✔
194

195
        return -EAFNOSUPPORT;
196
}
197

198
bool in4_addr_prefix_intersect(
849✔
199
                const struct in_addr *a,
200
                unsigned aprefixlen,
201
                const struct in_addr *b,
202
                unsigned bprefixlen) {
203

204
        assert(a);
849✔
205
        assert(b);
849✔
206

207
        unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in_addr) * 8));
849✔
208
        if (m == 0)
849✔
209
                return true; /* Let's return earlier, to avoid shift by 32. */
210

211
        uint32_t x = be32toh(a->s_addr ^ b->s_addr);
847✔
212
        uint32_t n = 0xFFFFFFFFUL << (32 - m);
847✔
213
        return (x & n) == 0;
847✔
214
}
215

216
bool in6_addr_prefix_intersect(
521✔
217
                const struct in6_addr *a,
218
                unsigned aprefixlen,
219
                const struct in6_addr *b,
220
                unsigned bprefixlen) {
221

222
        assert(a);
521✔
223
        assert(b);
521✔
224

225
        unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in6_addr) * 8));
521✔
226
        if (m == 0)
521✔
227
                return true;
228

229
        for (size_t i = 0; i < sizeof(struct in6_addr); i++) {
836✔
230
                uint8_t x = a->s6_addr[i] ^ b->s6_addr[i];
836✔
231
                uint8_t n = m < 8 ? (0xFF << (8 - m)) : 0xFF;
836✔
232
                if ((x & n) != 0)
836✔
233
                        return false;
234

235
                if (m <= 8)
336✔
236
                        break;
237

238
                m -= 8;
317✔
239
        }
240

241
        return true;
242
}
243

244
int in_addr_prefix_intersect(
1,339✔
245
                int family,
246
                const union in_addr_union *a,
247
                unsigned aprefixlen,
248
                const union in_addr_union *b,
249
                unsigned bprefixlen) {
250

251
        assert(a);
1,339✔
252
        assert(b);
1,339✔
253

254
        /* Checks whether there are any addresses that are in both networks. */
255

256
        if (family == AF_INET)
1,339✔
257
                return in4_addr_prefix_intersect(&a->in, aprefixlen, &b->in, bprefixlen);
849✔
258

259
        if (family == AF_INET6)
490✔
260
                return in6_addr_prefix_intersect(&a->in6, aprefixlen, &b->in6, bprefixlen);
490✔
261

262
        return -EAFNOSUPPORT;
263
}
264

265
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
15✔
266
        assert(u);
15✔
267

268
        /* Increases the network part of an address by one. Returns 0 if that succeeds, or -ERANGE if
269
         * this overflows. */
270

271
        return in_addr_prefix_nth(family, u, prefixlen, 1);
15✔
272
}
273

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

292
        if (prefixlen <= 0)
140✔
293
                return -ERANGE;
294

295
        if (family == AF_INET) {
138✔
296
                uint32_t c, n, t;
19✔
297

298
                if (prefixlen > 32)
19✔
299
                        return -ERANGE;
300

301
                c = be32toh(u->in.s_addr);
19✔
302

303
                t = nth << (32 - prefixlen);
19✔
304

305
                /* Check for wrap */
306
                if (c > UINT32_MAX - t)
19✔
307
                        return -ERANGE;
308

309
                n = c + t;
16✔
310

311
                n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen);
16✔
312
                u->in.s_addr = htobe32(n);
16✔
313
                return 0;
16✔
314
        }
315

316
        if (family == AF_INET6) {
119✔
317
                bool overflow = false;
119✔
318

319
                if (prefixlen > 128)
119✔
320
                        return -ERANGE;
321

322
                for (unsigned i = 16; i > 0; i--) {
2,023✔
323
                        unsigned t, j = i - 1, p = j * 8;
1,904✔
324

325
                        if (p >= prefixlen) {
1,904✔
326
                                u->in6.s6_addr[j] = 0;
905✔
327
                                continue;
905✔
328
                        }
329

330
                        if (prefixlen - p < 8) {
999✔
331
                                u->in6.s6_addr[j] &= 0xff << (8 - (prefixlen - p));
10✔
332
                                t = u->in6.s6_addr[j] + ((nth & 0xff) << (8 - (prefixlen - p)));
10✔
333
                                nth >>= prefixlen - p;
10✔
334
                        } else {
335
                                t = u->in6.s6_addr[j] + (nth & 0xff) + overflow;
989✔
336
                                nth >>= 8;
989✔
337
                        }
338

339
                        overflow = t > UINT8_MAX;
999✔
340
                        u->in6.s6_addr[j] = (uint8_t) (t & 0xff);
999✔
341
                }
342

343
                if (overflow || nth != 0)
119✔
344
                        return -ERANGE;
345

346
                return 0;
115✔
347
        }
348

349
        return -EAFNOSUPPORT;
350
}
351

352
int in_addr_random_prefix(
43✔
353
                int family,
354
                union in_addr_union *u,
355
                unsigned prefixlen_fixed_part,
356
                unsigned prefixlen) {
357

358
        assert(u);
43✔
359

360
        /* Random network part of an address by one. */
361

362
        if (prefixlen <= 0)
43✔
363
                return 0;
364

365
        if (family == AF_INET) {
43✔
366
                uint32_t c, n;
24✔
367

368
                if (prefixlen_fixed_part > 32)
24✔
369
                        prefixlen_fixed_part = 32;
×
370
                if (prefixlen > 32)
24✔
371
                        prefixlen = 32;
×
372
                if (prefixlen_fixed_part >= prefixlen)
24✔
373
                        return -EINVAL;
24✔
374

375
                c = be32toh(u->in.s_addr);
24✔
376
                c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
24✔
377

378
                random_bytes(&n, sizeof(n));
24✔
379
                n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
24✔
380

381
                u->in.s_addr = htobe32(n | c);
24✔
382
                return 1;
24✔
383
        }
384

385
        if (family == AF_INET6) {
19✔
386
                struct in6_addr n;
19✔
387
                unsigned i, j;
19✔
388

389
                if (prefixlen_fixed_part > 128)
19✔
390
                        prefixlen_fixed_part = 128;
×
391
                if (prefixlen > 128)
19✔
392
                        prefixlen = 128;
×
393
                if (prefixlen_fixed_part >= prefixlen)
19✔
394
                        return -EINVAL;
19✔
395

396
                random_bytes(&n, sizeof(n));
19✔
397

398
                for (i = 0; i < 16; i++) {
323✔
399
                        uint8_t mask_fixed_part = 0, mask = 0;
304✔
400

401
                        if (i < (prefixlen_fixed_part + 7) / 8) {
304✔
402
                                if (i < prefixlen_fixed_part / 8)
20✔
403
                                        mask_fixed_part = 0xffu;
404
                                else {
405
                                        j = prefixlen_fixed_part % 8;
×
406
                                        mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
×
407
                                }
408
                        }
409

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

419
                        u->in6.s6_addr[i] &= mask_fixed_part;
304✔
420
                        u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
304✔
421
                }
422

423
                return 1;
424
        }
425

426
        return -EAFNOSUPPORT;
427
}
428

429
int in_addr_prefix_range(
52✔
430
                int family,
431
                const union in_addr_union *in,
432
                unsigned prefixlen,
433
                union in_addr_union *ret_start,
434
                union in_addr_union *ret_end) {
435

436
        union in_addr_union start, end;
52✔
437
        int r;
52✔
438

439
        assert(in);
52✔
440

441
        if (!IN_SET(family, AF_INET, AF_INET6))
52✔
442
                return -EAFNOSUPPORT;
52✔
443

444
        if (ret_start) {
52✔
445
                start = *in;
52✔
446
                r = in_addr_prefix_nth(family, &start, prefixlen, 0);
52✔
447
                if (r < 0)
52✔
448
                        return r;
449
        }
450

451
        if (ret_end) {
52✔
452
                end = *in;
52✔
453
                r = in_addr_prefix_nth(family, &end, prefixlen, 1);
52✔
454
                if (r < 0)
52✔
455
                        return r;
456
        }
457

458
        if (ret_start)
52✔
459
                *ret_start = start;
52✔
460
        if (ret_end)
52✔
461
                *ret_end = end;
52✔
462

463
        return 0;
464
}
465

466
int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
10,620✔
467
        _cleanup_free_ char *x = NULL;
10,620✔
468
        size_t l;
10,620✔
469

470
        assert(u);
10,620✔
471
        assert(ret);
10,620✔
472

473
        if (family == AF_INET)
10,620✔
474
                l = INET_ADDRSTRLEN;
475
        else if (family == AF_INET6)
1,624✔
476
                l = INET6_ADDRSTRLEN;
477
        else
478
                return -EAFNOSUPPORT;
479

480
        x = new(char, l);
10,620✔
481
        if (!x)
10,620✔
482
                return -ENOMEM;
483

484
        errno = 0;
10,620✔
485
        if (!typesafe_inet_ntop(family, u, x, l))
10,620✔
486
                return errno_or_else(EINVAL);
×
487

488
        *ret = TAKE_PTR(x);
10,620✔
489
        return 0;
10,620✔
490
}
491

492
const char* typesafe_inet_ntop(int family, const union in_addr_union *a, char *buf, size_t len) {
481,155✔
493
        return inet_ntop(family, a, buf, len);
481,155✔
494
}
495

496
const char* typesafe_inet_ntop4(const struct in_addr *a, char *buf, size_t len) {
7,740✔
497
        return inet_ntop(AF_INET, a, buf, len);
7,740✔
498
}
499

500
const char* typesafe_inet_ntop6(const struct in6_addr *a, char *buf, size_t len) {
880✔
501
        return inet_ntop(AF_INET6, a, buf, len);
880✔
502
}
503

504
int in_addr_prefix_to_string(
415,895✔
505
                int family,
506
                const union in_addr_union *u,
507
                unsigned prefixlen,
508
                char *buf,
509
                size_t buf_len) {
510

511
        assert(u);
415,895✔
512
        assert(buf);
415,895✔
513

514
        if (!IN_SET(family, AF_INET, AF_INET6))
415,895✔
515
                return -EAFNOSUPPORT;
516

517
        errno = 0;
415,895✔
518
        if (!typesafe_inet_ntop(family, u, buf, buf_len))
415,895✔
519
                return errno_or_else(ENOSPC);
×
520

521
        size_t l = strlen(buf);
415,895✔
522
        if (!snprintf_ok(buf + l, buf_len - l, "/%u", prefixlen))
415,895✔
523
                return -ENOSPC;
×
524
        return 0;
525
}
526

527
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,839✔
528
        _cleanup_free_ char *ip_str = NULL, *x = NULL;
1,839✔
529
        int r;
1,839✔
530

531
        assert(IN_SET(family, AF_INET, AF_INET6));
1,839✔
532
        assert(u);
1,839✔
533
        assert(ret);
1,839✔
534

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

538
        r = in_addr_to_string(family, u, &ip_str);
1,839✔
539
        if (r < 0)
1,839✔
540
                return r;
541

542
        if (family == AF_INET6) {
1,839✔
543
                r = in_addr_is_link_local(family, u);
807✔
544
                if (r < 0)
807✔
545
                        return r;
546
                if (r == 0)
807✔
547
                        ifindex = 0;
751✔
548
        } else
549
                ifindex = 0; /* For IPv4 address, ifindex is always ignored. */
550

551
        if (port == 0 && ifindex == 0 && isempty(server_name)) {
1,839✔
552
                *ret = TAKE_PTR(ip_str);
1,472✔
553
                return 0;
1,472✔
554
        }
555

556
        const char *separator = isempty(server_name) ? "" : "#";
367✔
557
        server_name = strempty(server_name);
367✔
558

559
        if (port > 0) {
367✔
560
                if (family == AF_INET6) {
26✔
561
                        if (ifindex > 0)
16✔
562
                                x = asprintf_safe("[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
10✔
563
                        else
564
                                x = asprintf_safe("[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
6✔
565
                } else
566
                        x = asprintf_safe("%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
10✔
567
        } else {
568
                if (ifindex > 0)
341✔
569
                        x = asprintf_safe("%s%%%i%s%s", ip_str, ifindex, separator, server_name);
31✔
570
                else
571
                        x = strjoin(ip_str, separator, server_name);
310✔
572
        }
573
        if (!x)
367✔
574
                return -ENOMEM;
575

576
        *ret = TAKE_PTR(x);
367✔
577
        return 0;
367✔
578
}
579

580
int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
216,358✔
581
        union in_addr_union buffer;
216,358✔
582
        assert(s);
216,358✔
583

584
        if (!IN_SET(family, AF_INET, AF_INET6))
216,358✔
585
                return -EAFNOSUPPORT;
216,358✔
586

587
        errno = 0;
216,358✔
588
        if (inet_pton(family, s, ret ?: &buffer) <= 0)
216,983✔
589
                return errno_or_else(EINVAL);
69,667✔
590

591
        return 0;
592
}
593

594
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
140,879✔
595
        int r;
140,879✔
596

597
        assert(s);
140,879✔
598

599
        r = in_addr_from_string(AF_INET, s, ret);
140,879✔
600
        if (r >= 0) {
140,879✔
601
                if (ret_family)
72,970✔
602
                        *ret_family = AF_INET;
72,659✔
603
                return 0;
72,970✔
604
        }
605

606
        r = in_addr_from_string(AF_INET6, s, ret);
67,909✔
607
        if (r >= 0) {
67,909✔
608
                if (ret_family)
67,651✔
609
                        *ret_family = AF_INET6;
67,635✔
610
                return 0;
67,651✔
611
        }
612

613
        return -EINVAL;
614
}
615

616
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
404✔
617
        assert(addr);
404✔
618

619
        return 32U - u32ctz(be32toh(addr->s_addr));
404✔
620
}
621

622
/* Calculate an IPv4 netmask from prefix length, for example /8 -> 255.0.0.0. */
623
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
187,025✔
624
        assert(addr);
187,025✔
625
        assert(prefixlen <= 32);
187,025✔
626

627
        /* Shifting beyond 32 is not defined, handle this specially. */
628
        if (prefixlen == 0)
187,025✔
629
                addr->s_addr = 0;
2,170✔
630
        else
631
                addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
184,855✔
632

633
        return addr;
187,025✔
634
}
635

636
/* Calculate an IPv6 netmask from prefix length, for example /16 -> ffff::. */
637
struct in6_addr* in6_addr_prefixlen_to_netmask(struct in6_addr *addr, unsigned char prefixlen) {
165✔
638
        assert(addr);
165✔
639
        assert(prefixlen <= 128);
165✔
640

641
        for (unsigned i = 0; i < 16; i++) {
2,805✔
642
                uint8_t mask;
2,640✔
643

644
                if (prefixlen >= 8) {
2,640✔
645
                        mask = 0xFF;
1,264✔
646
                        prefixlen -= 8;
1,264✔
647
                } else if (prefixlen > 0) {
1,376✔
648
                        mask = 0xFF << (8 - prefixlen);
112✔
649
                        prefixlen = 0;
112✔
650
                } else {
651
                        assert(prefixlen == 0);
652
                        mask = 0;
653
                }
654

655
                addr->s6_addr[i] = mask;
2,640✔
656
        }
657

658
        return addr;
165✔
659
}
660

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

665
        switch (family) {
226✔
666
        case AF_INET:
61✔
667
                in4_addr_prefixlen_to_netmask(&addr->in, prefixlen);
61✔
668
                return 0;
61✔
669
        case AF_INET6:
165✔
670
                in6_addr_prefixlen_to_netmask(&addr->in6, prefixlen);
165✔
671
                return 0;
165✔
672
        default:
673
                return -EAFNOSUPPORT;
674
        }
675
}
676

677
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
32✔
678
        uint8_t msb_octet = *(uint8_t*) addr;
32✔
679

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

682
        assert(addr);
32✔
683
        assert(prefixlen);
32✔
684

685
        if (msb_octet < 128)
32✔
686
                /* class A, leading bits: 0 */
687
                *prefixlen = 8;
16✔
688
        else if (msb_octet < 192)
16✔
689
                /* class B, leading bits 10 */
690
                *prefixlen = 16;
×
691
        else if (msb_octet < 224)
16✔
692
                /* class C, leading bits 110 */
693
                *prefixlen = 24;
16✔
694
        else
695
                /* class D or E, no default prefixlen */
696
                return -ERANGE;
697

698
        return 0;
699
}
700

701
int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
×
702
        unsigned char prefixlen;
×
703
        int r;
×
704

705
        assert(addr);
×
706
        assert(mask);
×
707

708
        r = in4_addr_default_prefixlen(addr, &prefixlen);
×
709
        if (r < 0)
×
710
                return r;
×
711

712
        in4_addr_prefixlen_to_netmask(mask, prefixlen);
×
713
        return 0;
714
}
715

716
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen) {
186,930✔
717
        struct in_addr mask;
186,930✔
718

719
        assert(addr);
186,930✔
720

721
        if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
186,930✔
722
                return -EINVAL;
186,930✔
723

724
        addr->s_addr &= mask.s_addr;
186,930✔
725
        return 0;
186,930✔
726
}
727

728
int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen) {
141,276✔
729
        unsigned i;
141,276✔
730

731
        for (i = 0; i < 16; i++) {
2,401,692✔
732
                uint8_t mask;
2,260,416✔
733

734
                if (prefixlen >= 8) {
2,260,416✔
735
                        mask = 0xFF;
415,172✔
736
                        prefixlen -= 8;
415,172✔
737
                } else if (prefixlen > 0) {
1,845,244✔
738
                        mask = 0xFF << (8 - prefixlen);
270✔
739
                        prefixlen = 0;
270✔
740
                } else {
741
                        assert(prefixlen == 0);
742
                        mask = 0;
743
                }
744

745
                addr->s6_addr[i] &= mask;
2,260,416✔
746
        }
747

748
        return 0;
141,276✔
749
}
750

751
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
267,880✔
752
        assert(addr);
267,880✔
753

754
        switch (family) {
267,880✔
755
        case AF_INET:
133,938✔
756
                return in4_addr_mask(&addr->in, prefixlen);
133,938✔
757
        case AF_INET6:
133,942✔
758
                return in6_addr_mask(&addr->in6, prefixlen);
133,942✔
759
        default:
760
                return -EAFNOSUPPORT;
761
        }
762
}
763

764
int in4_addr_prefix_covers_full(
3,220✔
765
                const struct in_addr *prefix,
766
                unsigned char prefixlen,
767
                const struct in_addr *address,
768
                unsigned char address_prefixlen) {
769

770
        struct in_addr masked_prefix, masked_address;
3,220✔
771
        int r;
3,220✔
772

773
        assert(prefix);
3,220✔
774
        assert(address);
3,220✔
775

776
        if (prefixlen > address_prefixlen)
3,220✔
777
                return false;
3,220✔
778

779
        masked_prefix = *prefix;
2,692✔
780
        r = in4_addr_mask(&masked_prefix, prefixlen);
2,692✔
781
        if (r < 0)
2,692✔
782
                return r;
783

784
        masked_address = *address;
2,692✔
785
        r = in4_addr_mask(&masked_address, prefixlen);
2,692✔
786
        if (r < 0)
2,692✔
787
                return r;
788

789
        return in4_addr_equal(&masked_prefix, &masked_address);
2,692✔
790
}
791

792
int in6_addr_prefix_covers_full(
3,420✔
793
                const struct in6_addr *prefix,
794
                unsigned char prefixlen,
795
                const struct in6_addr *address,
796
                unsigned char address_prefixlen) {
797

798
        struct in6_addr masked_prefix, masked_address;
3,420✔
799
        int r;
3,420✔
800

801
        assert(prefix);
3,420✔
802
        assert(address);
3,420✔
803

804
        if (prefixlen > address_prefixlen)
3,420✔
805
                return false;
3,420✔
806

807
        masked_prefix = *prefix;
3,420✔
808
        r = in6_addr_mask(&masked_prefix, prefixlen);
3,420✔
809
        if (r < 0)
3,420✔
810
                return r;
811

812
        masked_address = *address;
3,420✔
813
        r = in6_addr_mask(&masked_address, prefixlen);
3,420✔
814
        if (r < 0)
3,420✔
815
                return r;
816

817
        return in6_addr_equal(&masked_prefix, &masked_address);
3,420✔
818
}
819

820
int in_addr_prefix_covers_full(
6,345✔
821
                int family,
822
                const union in_addr_union *prefix,
823
                unsigned char prefixlen,
824
                const union in_addr_union *address,
825
                unsigned char address_prefixlen) {
826

827
        assert(prefix);
6,345✔
828
        assert(address);
6,345✔
829

830
        switch (family) {
6,345✔
831
        case AF_INET:
2,996✔
832
                return in4_addr_prefix_covers_full(&prefix->in, prefixlen, &address->in, address_prefixlen);
2,996✔
833
        case AF_INET6:
3,349✔
834
                return in6_addr_prefix_covers_full(&prefix->in6, prefixlen, &address->in6, address_prefixlen);
3,349✔
835
        default:
836
                return -EAFNOSUPPORT;
837
        }
838
}
839

840
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
140,864✔
841
        uint8_t u;
140,864✔
842
        int r;
140,864✔
843

844
        assert(ret);
140,864✔
845

846
        if (!IN_SET(family, AF_INET, AF_INET6))
140,864✔
847
                return -EAFNOSUPPORT;
140,864✔
848

849
        r = safe_atou8(p, &u);
140,864✔
850
        if (r < 0)
140,864✔
851
                return r;
852

853
        if (u > FAMILY_ADDRESS_SIZE(family) * 8)
140,860✔
854
                return -ERANGE;
855

856
        *ret = u;
140,856✔
857
        return 0;
140,856✔
858
}
859

860
int in_addr_prefix_from_string(
1,439✔
861
                const char *p,
862
                int family,
863
                union in_addr_union *ret_prefix,
864
                unsigned char *ret_prefixlen) {
865

866
        _cleanup_free_ char *str = NULL;
1,439✔
867
        union in_addr_union buffer;
1,439✔
868
        const char *e, *l;
1,439✔
869
        unsigned char k;
1,439✔
870
        int r;
1,439✔
871

872
        assert(p);
1,439✔
873

874
        if (!IN_SET(family, AF_INET, AF_INET6))
1,439✔
875
                return -EAFNOSUPPORT;
876

877
        e = strchr(p, '/');
1,439✔
878
        if (e) {
1,439✔
879
                str = strndup(p, e - p);
1,423✔
880
                if (!str)
1,423✔
881
                        return -ENOMEM;
882

883
                l = str;
884
        } else
885
                l = p;
886

887
        r = in_addr_from_string(family, l, &buffer);
1,439✔
888
        if (r < 0)
1,439✔
889
                return r;
890

891
        if (e) {
1,431✔
892
                r = in_addr_parse_prefixlen(family, e+1, &k);
1,418✔
893
                if (r < 0)
1,418✔
894
                        return r;
895
        } else
896
                k = FAMILY_ADDRESS_SIZE(family) * 8;
13✔
897

898
        if (ret_prefix)
1,427✔
899
                *ret_prefix = buffer;
1,427✔
900
        if (ret_prefixlen)
1,427✔
901
                *ret_prefixlen = k;
1,427✔
902

903
        return 0;
904
}
905

906
int in_addr_prefix_from_string_auto_full(
139,749✔
907
                const char *p,
908
                InAddrPrefixLenMode mode,
909
                int *ret_family,
910
                union in_addr_union *ret_prefix,
911
                unsigned char *ret_prefixlen) {
912

913
        _cleanup_free_ char *str = NULL;
139,749✔
914
        union in_addr_union buffer;
139,749✔
915
        const char *e, *l;
139,749✔
916
        unsigned char k;
139,749✔
917
        int family, r;
139,749✔
918

919
        assert(p);
139,749✔
920

921
        e = strchr(p, '/');
139,749✔
922
        if (e) {
139,749✔
923
                str = strndup(p, e - p);
139,450✔
924
                if (!str)
139,450✔
925
                        return -ENOMEM;
926

927
                l = str;
928
        } else
929
                l = p;
930

931
        r = in_addr_from_string_auto(l, &family, &buffer);
139,749✔
932
        if (r < 0)
139,749✔
933
                return r;
934

935
        if (e) {
139,718✔
936
                r = in_addr_parse_prefixlen(family, e+1, &k);
139,446✔
937
                if (r < 0)
139,446✔
938
                        return r;
939
        } else
940
                switch (mode) {
272✔
941
                case PREFIXLEN_FULL:
256✔
942
                        k = FAMILY_ADDRESS_SIZE(family) * 8;
256✔
943
                        break;
256✔
944
                case PREFIXLEN_REFUSE:
945
                        return -ENOANO; /* To distinguish this error from others. */
UNCOV
946
                default:
×
UNCOV
947
                        assert_not_reached();
×
948
                }
949

950
        if (ret_family)
139,698✔
951
                *ret_family = family;
139,698✔
952
        if (ret_prefix)
139,698✔
953
                *ret_prefix = buffer;
139,698✔
954
        if (ret_prefixlen)
139,698✔
955
                *ret_prefixlen = k;
139,698✔
956

957
        return 0;
958
}
959

960
void in_addr_hash_func(const union in_addr_union *u, int family, struct siphash *state) {
856,428✔
961
        assert(u);
856,428✔
962
        assert(state);
856,428✔
963

964
        siphash24_compress(u->bytes, FAMILY_ADDRESS_SIZE(family), state);
856,428✔
965
}
856,428✔
966

967
void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
735✔
968
        assert(a);
735✔
969
        assert(state);
735✔
970

971
        siphash24_compress_typesafe(a->family, state);
735✔
972
        in_addr_hash_func(&a->address, a->family, state);
735✔
973
}
735✔
974

975
int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
322✔
976
        int r;
322✔
977

978
        assert(x);
322✔
979
        assert(y);
322✔
980

981
        r = CMP(x->family, y->family);
322✔
982
        if (r != 0)
248✔
983
                return r;
84✔
984

985
        return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
238✔
986
}
987

988
DEFINE_HASH_OPS(
989
        in_addr_data_hash_ops,
990
        struct in_addr_data,
991
        in_addr_data_hash_func,
992
        in_addr_data_compare_func);
993

994
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
179✔
995
        in_addr_data_hash_ops_free,
996
        struct in_addr_data,
997
        in_addr_data_hash_func,
998
        in_addr_data_compare_func,
999
        free);
1000

1001
void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
461✔
1002
        assert(addr);
461✔
1003
        assert(state);
461✔
1004

1005
        siphash24_compress_typesafe(*addr, state);
461✔
1006
}
461✔
1007

1008
int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
161✔
1009
        assert(a);
161✔
1010
        assert(b);
161✔
1011

1012
        return memcmp(a, b, sizeof(*a));
161✔
1013
}
1014

1015
DEFINE_HASH_OPS(
1016
        in6_addr_hash_ops,
1017
        struct in6_addr,
1018
        in6_addr_hash_func,
1019
        in6_addr_compare_func);
1020

1021
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
5✔
1022
        in6_addr_hash_ops_free,
1023
        struct in6_addr,
1024
        in6_addr_hash_func,
1025
        in6_addr_compare_func,
1026
        free);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc