]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/in-addr-util.c
Merge pull request #33377 from yuwata/strbuf-cleanups
[thirdparty/systemd.git] / src / basic / in-addr-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
3b653205
LP
2
3#include <arpa/inet.h>
11c3a366
TA
4#include <endian.h>
5#include <errno.h>
2817157b 6#include <net/if.h>
11c3a366 7#include <stdint.h>
ca78ad1d 8#include <stdio.h>
11c3a366 9#include <stdlib.h>
3b653205 10
b5efdb8a 11#include "alloc-util.h"
66855de7 12#include "errno-util.h"
3b653205 13#include "in-addr-util.h"
3ae6b3bf 14#include "logarithm.h"
11c3a366 15#include "macro.h"
2817157b 16#include "parse-util.h"
c5236acd 17#include "random-util.h"
c71384a9 18#include "stdio-util.h"
a723fb85 19#include "string-util.h"
d9143dac 20#include "strxcpyx.h"
3b653205 21
34380032 22bool in4_addr_is_null(const struct in_addr *a) {
fdedbe26 23 assert(a);
34380032 24
fdedbe26 25 return a->s_addr == 0;
34380032
LP
26}
27
7653dcc3
YW
28bool in6_addr_is_null(const struct in6_addr *a) {
29 assert(a);
30
31 return IN6_IS_ADDR_UNSPECIFIED(a);
32}
33
af93291c 34int in_addr_is_null(int family, const union in_addr_union *u) {
3b653205
LP
35 assert(u);
36
37 if (family == AF_INET)
34380032 38 return in4_addr_is_null(&u->in);
3b653205
LP
39
40 if (family == AF_INET6)
7653dcc3 41 return in6_addr_is_null(&u->in6);
3b653205
LP
42
43 return -EAFNOSUPPORT;
44}
45
fdedbe26
LP
46bool in4_addr_is_link_local(const struct in_addr *a) {
47 assert(a);
48
49 return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
50}
51
d3efcd2d
YW
52bool in4_addr_is_link_local_dynamic(const struct in_addr *a) {
53 assert(a);
54
55 if (!in4_addr_is_link_local(a))
56 return false;
57
58 /* 169.254.0.0/24 and 169.254.255.0/24 must not be used for the dynamic IPv4LL assignment.
59 * See RFC 3927 Section 2.1:
60 * The IPv4 prefix 169.254/16 is registered with the IANA for this purpose. The first 256 and last
61 * 256 addresses in the 169.254/16 prefix are reserved for future use and MUST NOT be selected by a
62 * host using this dynamic configuration mechanism. */
63 return !IN_SET(be32toh(a->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U);
64}
65
1235befa
YW
66bool in6_addr_is_link_local(const struct in6_addr *a) {
67 assert(a);
68
f37508d5 69 return IN6_IS_ADDR_LINKLOCAL(a);
1235befa
YW
70}
71
af93291c
LP
72int in_addr_is_link_local(int family, const union in_addr_union *u) {
73 assert(u);
74
75 if (family == AF_INET)
fdedbe26 76 return in4_addr_is_link_local(&u->in);
af93291c
LP
77
78 if (family == AF_INET6)
1235befa 79 return in6_addr_is_link_local(&u->in6);
af93291c
LP
80
81 return -EAFNOSUPPORT;
82}
3b653205 83
5643cfc0
YW
84bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
85 assert(a);
86
87 /* ff02::1 */
88 return be32toh(a->s6_addr32[0]) == UINT32_C(0xff020000) &&
89 a->s6_addr32[1] == 0 &&
90 a->s6_addr32[2] == 0 &&
91 be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
92}
93
c7f46150
YW
94bool in4_addr_is_multicast(const struct in_addr *a) {
95 assert(a);
96
97 return IN_MULTICAST(be32toh(a->s_addr));
98}
99
100bool in6_addr_is_multicast(const struct in6_addr *a) {
101 assert(a);
102
103 return IN6_IS_ADDR_MULTICAST(a);
104}
105
85257f48
SS
106int in_addr_is_multicast(int family, const union in_addr_union *u) {
107 assert(u);
108
109 if (family == AF_INET)
c7f46150 110 return in4_addr_is_multicast(&u->in);
85257f48
SS
111
112 if (family == AF_INET6)
c7f46150 113 return in6_addr_is_multicast(&u->in6);
85257f48
SS
114
115 return -EAFNOSUPPORT;
116}
117
ccea2448
YW
118bool in4_addr_is_local_multicast(const struct in_addr *a) {
119 assert(a);
120
121 return (be32toh(a->s_addr) & UINT32_C(0xffffff00)) == UINT32_C(0xe0000000);
122}
123
fdedbe26
LP
124bool in4_addr_is_localhost(const struct in_addr *a) {
125 assert(a);
126
127 /* All of 127.x.x.x is localhost. */
128 return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
129}
130
072320ea
TH
131bool in4_addr_is_non_local(const struct in_addr *a) {
132 /* Whether the address is not null and not localhost.
133 *
134 * As such, it is suitable to configure as DNS/NTP server from DHCP. */
135 return !in4_addr_is_null(a) &&
136 !in4_addr_is_localhost(a);
137}
138
d830ebbd
LP
139int in_addr_is_localhost(int family, const union in_addr_union *u) {
140 assert(u);
141
142 if (family == AF_INET)
fdedbe26 143 return in4_addr_is_localhost(&u->in);
d830ebbd 144
db15affc 145 if (family == AF_INET6)
f37508d5 146 return IN6_IS_ADDR_LOOPBACK(&u->in6);
d830ebbd
LP
147
148 return -EAFNOSUPPORT;
149}
150
b69bfa43
YW
151int in_addr_is_localhost_one(int family, const union in_addr_union *u) {
152 assert(u);
153
154 if (family == AF_INET)
155 /* 127.0.0.1 */
156 return be32toh(u->in.s_addr) == UINT32_C(0x7F000001);
157
158 if (family == AF_INET6)
f37508d5 159 return IN6_IS_ADDR_LOOPBACK(&u->in6);
b69bfa43
YW
160
161 return -EAFNOSUPPORT;
162}
163
c3e96088
YW
164bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
165 return a->s6_addr32[0] == 0 &&
166 a->s6_addr32[1] == 0 &&
167 a->s6_addr32[2] == htobe32(UINT32_C(0x0000ffff));
168}
169
9a897e22
YW
170bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
171 assert(a);
172 assert(b);
173
174 return a->s_addr == b->s_addr;
175}
176
fa550434
YW
177bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b) {
178 assert(a);
179 assert(b);
180
181 return IN6_ARE_ADDR_EQUAL(a, b);
182}
183
623a4c97 184int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
3b653205
LP
185 assert(a);
186 assert(b);
187
188 if (family == AF_INET)
9a897e22 189 return in4_addr_equal(&a->in, &b->in);
3b653205
LP
190
191 if (family == AF_INET6)
fa550434 192 return in6_addr_equal(&a->in6, &b->in6);
3b653205
LP
193
194 return -EAFNOSUPPORT;
195}
196
21ae0b4b
YW
197bool in4_addr_prefix_intersect(
198 const struct in_addr *a,
3b653205 199 unsigned aprefixlen,
21ae0b4b 200 const struct in_addr *b,
3b653205
LP
201 unsigned bprefixlen) {
202
3b653205
LP
203 assert(a);
204 assert(b);
205
21ae0b4b
YW
206 unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in_addr) * 8));
207 if (m == 0)
208 return true; /* Let's return earlier, to avoid shift by 32. */
3b653205 209
21ae0b4b
YW
210 uint32_t x = be32toh(a->s_addr ^ b->s_addr);
211 uint32_t n = 0xFFFFFFFFUL << (32 - m);
212 return (x & n) == 0;
213}
3b653205 214
21ae0b4b
YW
215bool in6_addr_prefix_intersect(
216 const struct in6_addr *a,
217 unsigned aprefixlen,
218 const struct in6_addr *b,
219 unsigned bprefixlen) {
3b653205 220
21ae0b4b
YW
221 assert(a);
222 assert(b);
3b653205 223
21ae0b4b
YW
224 unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in6_addr) * 8));
225 if (m == 0)
226 return true;
3b653205 227
21ae0b4b
YW
228 for (size_t i = 0; i < sizeof(struct in6_addr); i++) {
229 uint8_t x = a->s6_addr[i] ^ b->s6_addr[i];
230 uint8_t n = m < 8 ? (0xFF << (8 - m)) : 0xFF;
231 if ((x & n) != 0)
232 return false;
3b653205 233
21ae0b4b
YW
234 if (m <= 8)
235 break;
3b653205 236
21ae0b4b
YW
237 m -= 8;
238 }
3b653205 239
21ae0b4b
YW
240 return true;
241}
3b653205 242
21ae0b4b
YW
243int in_addr_prefix_intersect(
244 int family,
245 const union in_addr_union *a,
246 unsigned aprefixlen,
247 const union in_addr_union *b,
248 unsigned bprefixlen) {
3b653205 249
21ae0b4b
YW
250 assert(a);
251 assert(b);
3b653205 252
21ae0b4b 253 /* Checks whether there are any addresses that are in both networks. */
3b653205 254
21ae0b4b
YW
255 if (family == AF_INET)
256 return in4_addr_prefix_intersect(&a->in, aprefixlen, &b->in, bprefixlen);
257
258 if (family == AF_INET6)
259 return in6_addr_prefix_intersect(&a->in6, aprefixlen, &b->in6, bprefixlen);
3b653205
LP
260
261 return -EAFNOSUPPORT;
262}
263
0dd25fb9 264int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
3b653205
LP
265 assert(u);
266
518b6da5
YW
267 /* Increases the network part of an address by one. Returns 0 if that succeeds, or -ERANGE if
268 * this overflows. */
3b653205 269
171f625b 270 return in_addr_prefix_nth(family, u, prefixlen, 1);
c5236acd
YW
271}
272
863b99cd
AR
273/*
274 * Calculates the nth prefix of size prefixlen starting from the address denoted by u.
275 *
518b6da5 276 * On success 0 will be returned and the calculated prefix will be available in
9164338b 277 * u. In case the calculation cannot be performed (invalid prefix length,
863b99cd
AR
278 * overflows would occur) -ERANGE is returned. If the address family given isn't
279 * supported -EAFNOSUPPORT will be returned.
280 *
863b99cd 281 * Examples:
518b6da5
YW
282 * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 0, writes 192.168.2.0 to u
283 * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 0, no data written
863b99cd
AR
284 * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 24, 1), returns -ERANGE, no data written
285 * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 0, 1), returns -ERANGE, no data written
518b6da5 286 * - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 0, writes 2001:0db8:0000:ff00:: to u
863b99cd
AR
287 */
288int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth) {
289 assert(u);
290
291 if (prefixlen <= 0)
292 return -ERANGE;
293
863b99cd
AR
294 if (family == AF_INET) {
295 uint32_t c, n, t;
7b6b05cf 296
863b99cd 297 if (prefixlen > 32)
7b6b05cf 298 return -ERANGE;
863b99cd
AR
299
300 c = be32toh(u->in.s_addr);
301
302 t = nth << (32 - prefixlen);
303
304 /* Check for wrap */
305 if (c > UINT32_MAX - t)
306 return -ERANGE;
307
308 n = c + t;
309
310 n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen);
311 u->in.s_addr = htobe32(n);
518b6da5 312 return 0;
863b99cd
AR
313 }
314
315 if (family == AF_INET6) {
9164338b 316 bool overflow = false;
863b99cd
AR
317
318 if (prefixlen > 128)
7b6b05cf 319 return -ERANGE;
863b99cd 320
863b99cd 321 for (unsigned i = 16; i > 0; i--) {
9164338b
YW
322 unsigned t, j = i - 1, p = j * 8;
323
324 if (p >= prefixlen) {
325 u->in6.s6_addr[j] = 0;
326 continue;
327 }
328
329 if (prefixlen - p < 8) {
330 u->in6.s6_addr[j] &= 0xff << (8 - (prefixlen - p));
331 t = u->in6.s6_addr[j] + ((nth & 0xff) << (8 - (prefixlen - p)));
332 nth >>= prefixlen - p;
333 } else {
334 t = u->in6.s6_addr[j] + (nth & 0xff) + overflow;
335 nth >>= 8;
336 }
337
338 overflow = t > UINT8_MAX;
339 u->in6.s6_addr[j] = (uint8_t) (t & 0xff);
863b99cd
AR
340 }
341
9164338b 342 if (overflow || nth != 0)
863b99cd
AR
343 return -ERANGE;
344
518b6da5 345 return 0;
863b99cd
AR
346 }
347
348 return -EAFNOSUPPORT;
349}
350
c5236acd
YW
351int in_addr_random_prefix(
352 int family,
353 union in_addr_union *u,
354 unsigned prefixlen_fixed_part,
355 unsigned prefixlen) {
356
357 assert(u);
358
359 /* Random network part of an address by one. */
360
361 if (prefixlen <= 0)
362 return 0;
363
364 if (family == AF_INET) {
365 uint32_t c, n;
366
367 if (prefixlen_fixed_part > 32)
368 prefixlen_fixed_part = 32;
369 if (prefixlen > 32)
370 prefixlen = 32;
371 if (prefixlen_fixed_part >= prefixlen)
372 return -EINVAL;
373
374 c = be32toh(u->in.s_addr);
375 c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
376
377 random_bytes(&n, sizeof(n));
378 n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
379
380 u->in.s_addr = htobe32(n | c);
381 return 1;
382 }
383
384 if (family == AF_INET6) {
385 struct in6_addr n;
386 unsigned i, j;
387
388 if (prefixlen_fixed_part > 128)
389 prefixlen_fixed_part = 128;
390 if (prefixlen > 128)
391 prefixlen = 128;
392 if (prefixlen_fixed_part >= prefixlen)
393 return -EINVAL;
394
395 random_bytes(&n, sizeof(n));
396
397 for (i = 0; i < 16; i++) {
398 uint8_t mask_fixed_part = 0, mask = 0;
399
400 if (i < (prefixlen_fixed_part + 7) / 8) {
401 if (i < prefixlen_fixed_part / 8)
402 mask_fixed_part = 0xffu;
403 else {
404 j = prefixlen_fixed_part % 8;
405 mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
406 }
407 }
408
409 if (i < (prefixlen + 7) / 8) {
410 if (i < prefixlen / 8)
411 mask = 0xffu ^ mask_fixed_part;
412 else {
413 j = prefixlen % 8;
414 mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
415 }
416 }
417
418 u->in6.s6_addr[i] &= mask_fixed_part;
419 u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
420 }
421
422 return 1;
423 }
3b653205
LP
424
425 return -EAFNOSUPPORT;
426}
427
1534c579
YW
428int in_addr_prefix_range(
429 int family,
430 const union in_addr_union *in,
431 unsigned prefixlen,
432 union in_addr_union *ret_start,
433 union in_addr_union *ret_end) {
434
435 union in_addr_union start, end;
436 int r;
437
438 assert(in);
439
440 if (!IN_SET(family, AF_INET, AF_INET6))
441 return -EAFNOSUPPORT;
442
443 if (ret_start) {
444 start = *in;
445 r = in_addr_prefix_nth(family, &start, prefixlen, 0);
446 if (r < 0)
447 return r;
448 }
449
450 if (ret_end) {
451 end = *in;
452 r = in_addr_prefix_nth(family, &end, prefixlen, 1);
453 if (r < 0)
454 return r;
455 }
456
457 if (ret_start)
458 *ret_start = start;
459 if (ret_end)
460 *ret_end = end;
461
462 return 0;
463}
464
0dd25fb9 465int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
81260be1 466 _cleanup_free_ char *x = NULL;
3b653205
LP
467 size_t l;
468
469 assert(u);
470 assert(ret);
471
472 if (family == AF_INET)
473 l = INET_ADDRSTRLEN;
474 else if (family == AF_INET6)
475 l = INET6_ADDRSTRLEN;
476 else
477 return -EAFNOSUPPORT;
478
479 x = new(char, l);
480 if (!x)
481 return -ENOMEM;
482
483 errno = 0;
84dbb3fd 484 if (!typesafe_inet_ntop(family, u, x, l))
66855de7 485 return errno_or_else(EINVAL);
3b653205 486
81260be1 487 *ret = TAKE_PTR(x);
3b653205
LP
488 return 0;
489}
490
c71384a9
ZJS
491int in_addr_prefix_to_string(
492 int family,
493 const union in_addr_union *u,
494 unsigned prefixlen,
495 char *buf,
496 size_t buf_len) {
d9143dac
YW
497
498 assert(u);
c71384a9 499 assert(buf);
d9143dac 500
c71384a9 501 if (!IN_SET(family, AF_INET, AF_INET6))
d9143dac
YW
502 return -EAFNOSUPPORT;
503
d9143dac 504 errno = 0;
c71384a9
ZJS
505 if (!typesafe_inet_ntop(family, u, buf, buf_len))
506 return errno_or_else(ENOSPC);
d9143dac 507
c71384a9
ZJS
508 size_t l = strlen(buf);
509 if (!snprintf_ok(buf + l, buf_len - l, "/%u", prefixlen))
510 return -ENOSPC;
d9143dac
YW
511 return 0;
512}
513
a723fb85
YW
514int 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) {
515 _cleanup_free_ char *ip_str = NULL, *x = NULL;
516 int r;
517
518 assert(IN_SET(family, AF_INET, AF_INET6));
519 assert(u);
520 assert(ret);
521
522 /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
523 * handle IPv6 link-local addresses. */
524
525 r = in_addr_to_string(family, u, &ip_str);
526 if (r < 0)
527 return r;
528
529 if (family == AF_INET6) {
530 r = in_addr_is_link_local(family, u);
531 if (r < 0)
532 return r;
533 if (r == 0)
534 ifindex = 0;
535 } else
536 ifindex = 0; /* For IPv4 address, ifindex is always ignored. */
537
538 if (port == 0 && ifindex == 0 && isempty(server_name)) {
539 *ret = TAKE_PTR(ip_str);
540 return 0;
541 }
542
543 const char *separator = isempty(server_name) ? "" : "#";
544 server_name = strempty(server_name);
545
546 if (port > 0) {
547 if (family == AF_INET6) {
548 if (ifindex > 0)
549 r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
550 else
551 r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
552 } else
553 r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
554 } else {
555 if (ifindex > 0)
556 r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name);
557 else {
558 x = strjoin(ip_str, separator, server_name);
559 r = x ? 0 : -ENOMEM;
560 }
561 }
562 if (r < 0)
563 return -ENOMEM;
564
565 *ret = TAKE_PTR(x);
566 return 0;
567}
568
0dd25fb9 569int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
fd18634d 570 union in_addr_union buffer;
3b653205 571 assert(s);
3b653205
LP
572
573 if (!IN_SET(family, AF_INET, AF_INET6))
574 return -EAFNOSUPPORT;
575
576 errno = 0;
fd18634d 577 if (inet_pton(family, s, ret ?: &buffer) <= 0)
66855de7 578 return errno_or_else(EINVAL);
3b653205
LP
579
580 return 0;
581}
74b2466e 582
4e2d5273 583int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
74b2466e
LP
584 int r;
585
586 assert(s);
74b2466e
LP
587
588 r = in_addr_from_string(AF_INET, s, ret);
589 if (r >= 0) {
4e2d5273
LP
590 if (ret_family)
591 *ret_family = AF_INET;
74b2466e
LP
592 return 0;
593 }
594
595 r = in_addr_from_string(AF_INET6, s, ret);
596 if (r >= 0) {
4e2d5273
LP
597 if (ret_family)
598 *ret_family = AF_INET6;
74b2466e
LP
599 return 0;
600 }
601
602 return -EINVAL;
603}
44e7b949 604
5a941f5f 605unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
44e7b949
LP
606 assert(addr);
607
1a359852 608 return 32U - u32ctz(be32toh(addr->s_addr));
44e7b949 609}
df40eee8 610
3f36b9ed 611/* Calculate an IPv4 netmask from prefix length, for example /8 -> 255.0.0.0. */
5a941f5f 612struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
76917807
LP
613 assert(addr);
614 assert(prefixlen <= 32);
615
616 /* Shifting beyond 32 is not defined, handle this specially. */
617 if (prefixlen == 0)
618 addr->s_addr = 0;
619 else
620 addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
621
622 return addr;
623}
624
3f36b9ed
TM
625/* Calculate an IPv6 netmask from prefix length, for example /16 -> ffff::. */
626struct in6_addr* in6_addr_prefixlen_to_netmask(struct in6_addr *addr, unsigned char prefixlen) {
627 assert(addr);
628 assert(prefixlen <= 128);
629
630 for (unsigned i = 0; i < 16; i++) {
631 uint8_t mask;
632
633 if (prefixlen >= 8) {
634 mask = 0xFF;
635 prefixlen -= 8;
636 } else if (prefixlen > 0) {
637 mask = 0xFF << (8 - prefixlen);
638 prefixlen = 0;
639 } else {
640 assert(prefixlen == 0);
641 mask = 0;
642 }
643
644 addr->s6_addr[i] = mask;
645 }
646
647 return addr;
648}
649
650/* Calculate an IPv4 or IPv6 netmask from prefix length, for example /8 -> 255.0.0.0 or /16 -> ffff::. */
651int in_addr_prefixlen_to_netmask(int family, union in_addr_union *addr, unsigned char prefixlen) {
652 assert(addr);
653
654 switch (family) {
655 case AF_INET:
656 in4_addr_prefixlen_to_netmask(&addr->in, prefixlen);
657 return 0;
658 case AF_INET6:
659 in6_addr_prefixlen_to_netmask(&addr->in6, prefixlen);
660 return 0;
661 default:
662 return -EAFNOSUPPORT;
663 }
664}
665
5a941f5f 666int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
1caa12d0
TG
667 uint8_t msb_octet = *(uint8_t*) addr;
668
669 /* addr may not be aligned, so make sure we only access it byte-wise */
df40eee8
TG
670
671 assert(addr);
df40eee8
TG
672 assert(prefixlen);
673
1caa12d0 674 if (msb_octet < 128)
df40eee8
TG
675 /* class A, leading bits: 0 */
676 *prefixlen = 8;
1caa12d0 677 else if (msb_octet < 192)
df40eee8
TG
678 /* class B, leading bits 10 */
679 *prefixlen = 16;
1caa12d0 680 else if (msb_octet < 224)
df40eee8
TG
681 /* class C, leading bits 110 */
682 *prefixlen = 24;
683 else
684 /* class D or E, no default prefixlen */
685 return -ERANGE;
686
687 return 0;
688}
689
5a941f5f 690int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
df40eee8
TG
691 unsigned char prefixlen;
692 int r;
693
694 assert(addr);
695 assert(mask);
696
5a941f5f 697 r = in4_addr_default_prefixlen(addr, &prefixlen);
df40eee8
TG
698 if (r < 0)
699 return r;
700
5a941f5f 701 in4_addr_prefixlen_to_netmask(mask, prefixlen);
df40eee8
TG
702 return 0;
703}
5a8bcb67 704
333f7d89
YW
705int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen) {
706 struct in_addr mask;
5a8bcb67 707
333f7d89 708 assert(addr);
5a8bcb67 709
333f7d89
YW
710 if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
711 return -EINVAL;
5a8bcb67 712
333f7d89
YW
713 addr->s_addr &= mask.s_addr;
714 return 0;
715}
5a8bcb67 716
333f7d89
YW
717int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen) {
718 unsigned i;
5a8bcb67 719
333f7d89
YW
720 for (i = 0; i < 16; i++) {
721 uint8_t mask;
5a8bcb67 722
333f7d89
YW
723 if (prefixlen >= 8) {
724 mask = 0xFF;
725 prefixlen -= 8;
6df860f3 726 } else if (prefixlen > 0) {
333f7d89
YW
727 mask = 0xFF << (8 - prefixlen);
728 prefixlen = 0;
6df860f3
YW
729 } else {
730 assert(prefixlen == 0);
731 mask = 0;
5a8bcb67
LP
732 }
733
333f7d89 734 addr->s6_addr[i] &= mask;
5a8bcb67
LP
735 }
736
333f7d89
YW
737 return 0;
738}
739
740int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
741 assert(addr);
742
743 switch (family) {
744 case AF_INET:
745 return in4_addr_mask(&addr->in, prefixlen);
746 case AF_INET6:
747 return in6_addr_mask(&addr->in6, prefixlen);
748 default:
749 return -EAFNOSUPPORT;
750 }
5a8bcb67 751}
f7bf1abe 752
45e76094 753int in4_addr_prefix_covers_full(
e174b43f
YW
754 const struct in_addr *prefix,
755 unsigned char prefixlen,
45e76094
YW
756 const struct in_addr *address,
757 unsigned char address_prefixlen) {
1274b6c6 758
e174b43f 759 struct in_addr masked_prefix, masked_address;
1274b6c6
LP
760 int r;
761
762 assert(prefix);
763 assert(address);
764
45e76094
YW
765 if (prefixlen > address_prefixlen)
766 return false;
767
1274b6c6 768 masked_prefix = *prefix;
e174b43f 769 r = in4_addr_mask(&masked_prefix, prefixlen);
1274b6c6
LP
770 if (r < 0)
771 return r;
772
773 masked_address = *address;
e174b43f 774 r = in4_addr_mask(&masked_address, prefixlen);
1274b6c6
LP
775 if (r < 0)
776 return r;
777
e174b43f
YW
778 return in4_addr_equal(&masked_prefix, &masked_address);
779}
780
45e76094 781int in6_addr_prefix_covers_full(
e174b43f
YW
782 const struct in6_addr *prefix,
783 unsigned char prefixlen,
45e76094
YW
784 const struct in6_addr *address,
785 unsigned char address_prefixlen) {
e174b43f
YW
786
787 struct in6_addr masked_prefix, masked_address;
788 int r;
789
790 assert(prefix);
791 assert(address);
792
45e76094
YW
793 if (prefixlen > address_prefixlen)
794 return false;
795
e174b43f
YW
796 masked_prefix = *prefix;
797 r = in6_addr_mask(&masked_prefix, prefixlen);
798 if (r < 0)
799 return r;
800
801 masked_address = *address;
802 r = in6_addr_mask(&masked_address, prefixlen);
803 if (r < 0)
804 return r;
805
806 return in6_addr_equal(&masked_prefix, &masked_address);
807}
808
45e76094 809int in_addr_prefix_covers_full(
e174b43f
YW
810 int family,
811 const union in_addr_union *prefix,
812 unsigned char prefixlen,
45e76094
YW
813 const union in_addr_union *address,
814 unsigned char address_prefixlen) {
e174b43f
YW
815
816 assert(prefix);
817 assert(address);
818
819 switch (family) {
820 case AF_INET:
45e76094 821 return in4_addr_prefix_covers_full(&prefix->in, prefixlen, &address->in, address_prefixlen);
e174b43f 822 case AF_INET6:
45e76094 823 return in6_addr_prefix_covers_full(&prefix->in6, prefixlen, &address->in6, address_prefixlen);
e174b43f
YW
824 default:
825 return -EAFNOSUPPORT;
826 }
1274b6c6
LP
827}
828
f4912f3a
LP
829int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
830 uint8_t u;
831 int r;
832
833 if (!IN_SET(family, AF_INET, AF_INET6))
834 return -EAFNOSUPPORT;
835
836 r = safe_atou8(p, &u);
837 if (r < 0)
838 return r;
839
840 if (u > FAMILY_ADDRESS_SIZE(family) * 8)
841 return -ERANGE;
842
843 *ret = u;
844 return 0;
845}
846
9e0fdc21 847int in_addr_prefix_from_string(
f4912f3a
LP
848 const char *p,
849 int family,
850 union in_addr_union *ret_prefix,
851 unsigned char *ret_prefixlen) {
852
67944f5c 853 _cleanup_free_ char *str = NULL;
f7bf1abe
SS
854 union in_addr_union buffer;
855 const char *e, *l;
f4912f3a 856 unsigned char k;
f7bf1abe
SS
857 int r;
858
859 assert(p);
860
861 if (!IN_SET(family, AF_INET, AF_INET6))
862 return -EAFNOSUPPORT;
863
864 e = strchr(p, '/');
67944f5c
YW
865 if (e) {
866 str = strndup(p, e - p);
867 if (!str)
868 return -ENOMEM;
869
870 l = str;
871 } else
f7bf1abe
SS
872 l = p;
873
874 r = in_addr_from_string(family, l, &buffer);
875 if (r < 0)
876 return r;
877
f7bf1abe 878 if (e) {
f4912f3a 879 r = in_addr_parse_prefixlen(family, e+1, &k);
f7bf1abe
SS
880 if (r < 0)
881 return r;
f4912f3a
LP
882 } else
883 k = FAMILY_ADDRESS_SIZE(family) * 8;
f7bf1abe 884
f4912f3a
LP
885 if (ret_prefix)
886 *ret_prefix = buffer;
887 if (ret_prefixlen)
888 *ret_prefixlen = k;
f7bf1abe 889
f4912f3a
LP
890 return 0;
891}
f7bf1abe 892
a4798d4e 893int in_addr_prefix_from_string_auto_internal(
f4912f3a 894 const char *p,
9e0fdc21 895 InAddrPrefixLenMode mode,
f4912f3a
LP
896 int *ret_family,
897 union in_addr_union *ret_prefix,
898 unsigned char *ret_prefixlen) {
899
67944f5c 900 _cleanup_free_ char *str = NULL;
f4912f3a
LP
901 union in_addr_union buffer;
902 const char *e, *l;
903 unsigned char k;
904 int family, r;
905
906 assert(p);
907
908 e = strchr(p, '/');
67944f5c
YW
909 if (e) {
910 str = strndup(p, e - p);
911 if (!str)
912 return -ENOMEM;
913
914 l = str;
915 } else
f4912f3a
LP
916 l = p;
917
918 r = in_addr_from_string_auto(l, &family, &buffer);
919 if (r < 0)
920 return r;
921
922 if (e) {
923 r = in_addr_parse_prefixlen(family, e+1, &k);
924 if (r < 0)
a4798d4e 925 return r;
f4912f3a 926 } else
9e0fdc21
YW
927 switch (mode) {
928 case PREFIXLEN_FULL:
929 k = FAMILY_ADDRESS_SIZE(family) * 8;
930 break;
931 case PREFIXLEN_REFUSE:
932 return -ENOANO; /* To distinguish this error from others. */
9e0fdc21 933 default:
04499a70 934 assert_not_reached();
9e0fdc21 935 }
f4912f3a
LP
936
937 if (ret_family)
938 *ret_family = family;
939 if (ret_prefix)
940 *ret_prefix = buffer;
941 if (ret_prefixlen)
942 *ret_prefixlen = k;
f7bf1abe
SS
943
944 return 0;
f4912f3a 945
f7bf1abe 946}
6c39e026 947
c01a5c05
YW
948void in_addr_hash_func(const union in_addr_union *u, int family, struct siphash *state) {
949 assert(u);
950 assert(state);
951
952 siphash24_compress(u->bytes, FAMILY_ADDRESS_SIZE(family), state);
953}
954
4596c836 955void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
93e44aa9
YW
956 assert(a);
957 assert(state);
958
c01a5c05
YW
959 siphash24_compress_typesafe(a->family, state);
960 in_addr_hash_func(&a->address, a->family, state);
6c39e026
YW
961}
962
4596c836 963int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
a0edd02e 964 int r;
6c39e026 965
93e44aa9
YW
966 assert(x);
967 assert(y);
968
a0edd02e
FB
969 r = CMP(x->family, y->family);
970 if (r != 0)
971 return r;
6c39e026 972
23577246 973 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
6c39e026
YW
974}
975
4596c836
YW
976DEFINE_HASH_OPS(
977 in_addr_data_hash_ops,
978 struct in_addr_data,
979 in_addr_data_hash_func,
980 in_addr_data_compare_func);
981
982DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
983 in_addr_data_hash_ops_free,
984 struct in_addr_data,
985 in_addr_data_hash_func,
986 in_addr_data_compare_func,
987 free);
2968913e 988
badd4928 989void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
2968913e 990 assert(addr);
93e44aa9 991 assert(state);
2968913e 992
c01a5c05 993 siphash24_compress_typesafe(*addr, state);
2968913e
YW
994}
995
badd4928 996int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
93e44aa9
YW
997 assert(a);
998 assert(b);
999
2968913e
YW
1000 return memcmp(a, b, sizeof(*a));
1001}
1002
4596c836
YW
1003DEFINE_HASH_OPS(
1004 in6_addr_hash_ops,
1005 struct in6_addr,
1006 in6_addr_hash_func,
1007 in6_addr_compare_func);
1008
f1cb8933
YW
1009DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1010 in6_addr_hash_ops_free,
1011 struct in6_addr,
1012 in6_addr_hash_func,
1013 in6_addr_compare_func,
1014 free);