]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/in-addr-util.c
Merge pull request #14424 from poettering/watch-bus-name-rework
[thirdparty/systemd.git] / src / basic / in-addr-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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 "macro.h"
15 #include "parse-util.h"
16 #include "random-util.h"
17 #include "strxcpyx.h"
18 #include "util.h"
19
20 bool in4_addr_is_null(const struct in_addr *a) {
21 assert(a);
22
23 return a->s_addr == 0;
24 }
25
26 int in_addr_is_null(int family, const union in_addr_union *u) {
27 assert(u);
28
29 if (family == AF_INET)
30 return in4_addr_is_null(&u->in);
31
32 if (family == AF_INET6)
33 return IN6_IS_ADDR_UNSPECIFIED(&u->in6);
34
35 return -EAFNOSUPPORT;
36 }
37
38 bool in4_addr_is_link_local(const struct in_addr *a) {
39 assert(a);
40
41 return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
42 }
43
44 int in_addr_is_link_local(int family, const union in_addr_union *u) {
45 assert(u);
46
47 if (family == AF_INET)
48 return in4_addr_is_link_local(&u->in);
49
50 if (family == AF_INET6)
51 return IN6_IS_ADDR_LINKLOCAL(&u->in6);
52
53 return -EAFNOSUPPORT;
54 }
55
56 int in_addr_is_multicast(int family, const union in_addr_union *u) {
57 assert(u);
58
59 if (family == AF_INET)
60 return IN_MULTICAST(be32toh(u->in.s_addr));
61
62 if (family == AF_INET6)
63 return IN6_IS_ADDR_MULTICAST(&u->in6);
64
65 return -EAFNOSUPPORT;
66 }
67
68 bool in4_addr_is_localhost(const struct in_addr *a) {
69 assert(a);
70
71 /* All of 127.x.x.x is localhost. */
72 return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
73 }
74
75 bool in4_addr_is_non_local(const struct in_addr *a) {
76 /* Whether the address is not null and not localhost.
77 *
78 * As such, it is suitable to configure as DNS/NTP server from DHCP. */
79 return !in4_addr_is_null(a) &&
80 !in4_addr_is_localhost(a);
81 }
82
83 int in_addr_is_localhost(int family, const union in_addr_union *u) {
84 assert(u);
85
86 if (family == AF_INET)
87 return in4_addr_is_localhost(&u->in);
88
89 if (family == AF_INET6)
90 return IN6_IS_ADDR_LOOPBACK(&u->in6);
91
92 return -EAFNOSUPPORT;
93 }
94
95 bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
96 assert(a);
97 assert(b);
98
99 return a->s_addr == b->s_addr;
100 }
101
102 int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
103 assert(a);
104 assert(b);
105
106 if (family == AF_INET)
107 return in4_addr_equal(&a->in, &b->in);
108
109 if (family == AF_INET6)
110 return
111 a->in6.s6_addr32[0] == b->in6.s6_addr32[0] &&
112 a->in6.s6_addr32[1] == b->in6.s6_addr32[1] &&
113 a->in6.s6_addr32[2] == b->in6.s6_addr32[2] &&
114 a->in6.s6_addr32[3] == b->in6.s6_addr32[3];
115
116 return -EAFNOSUPPORT;
117 }
118
119 int in_addr_prefix_intersect(
120 int family,
121 const union in_addr_union *a,
122 unsigned aprefixlen,
123 const union in_addr_union *b,
124 unsigned bprefixlen) {
125
126 unsigned m;
127
128 assert(a);
129 assert(b);
130
131 /* Checks whether there are any addresses that are in both
132 * networks */
133
134 m = MIN(aprefixlen, bprefixlen);
135
136 if (family == AF_INET) {
137 uint32_t x, nm;
138
139 x = be32toh(a->in.s_addr ^ b->in.s_addr);
140 nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
141
142 return (x & nm) == 0;
143 }
144
145 if (family == AF_INET6) {
146 unsigned i;
147
148 if (m > 128)
149 m = 128;
150
151 for (i = 0; i < 16; i++) {
152 uint8_t x, nm;
153
154 x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
155
156 if (m < 8)
157 nm = 0xFF << (8 - m);
158 else
159 nm = 0xFF;
160
161 if ((x & nm) != 0)
162 return 0;
163
164 if (m > 8)
165 m -= 8;
166 else
167 m = 0;
168 }
169
170 return 1;
171 }
172
173 return -EAFNOSUPPORT;
174 }
175
176 int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
177 assert(u);
178
179 /* Increases the network part of an address by one. Returns
180 * positive it that succeeds, or 0 if this overflows. */
181
182 if (prefixlen <= 0)
183 return 0;
184
185 if (family == AF_INET) {
186 uint32_t c, n;
187
188 if (prefixlen > 32)
189 prefixlen = 32;
190
191 c = be32toh(u->in.s_addr);
192 n = c + (1UL << (32 - prefixlen));
193 if (n < c)
194 return 0;
195 n &= 0xFFFFFFFFUL << (32 - prefixlen);
196
197 u->in.s_addr = htobe32(n);
198 return 1;
199 }
200
201 if (family == AF_INET6) {
202 struct in6_addr add = {}, result;
203 uint8_t overflow = 0;
204 unsigned i;
205
206 if (prefixlen > 128)
207 prefixlen = 128;
208
209 /* First calculate what we have to add */
210 add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8);
211
212 for (i = 16; i > 0; i--) {
213 unsigned j = i - 1;
214
215 result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow;
216 overflow = (result.s6_addr[j] < u->in6.s6_addr[j]);
217 }
218
219 if (overflow)
220 return 0;
221
222 u->in6 = result;
223 return 1;
224 }
225
226 return -EAFNOSUPPORT;
227 }
228
229 int in_addr_random_prefix(
230 int family,
231 union in_addr_union *u,
232 unsigned prefixlen_fixed_part,
233 unsigned prefixlen) {
234
235 assert(u);
236
237 /* Random network part of an address by one. */
238
239 if (prefixlen <= 0)
240 return 0;
241
242 if (family == AF_INET) {
243 uint32_t c, n;
244
245 if (prefixlen_fixed_part > 32)
246 prefixlen_fixed_part = 32;
247 if (prefixlen > 32)
248 prefixlen = 32;
249 if (prefixlen_fixed_part >= prefixlen)
250 return -EINVAL;
251
252 c = be32toh(u->in.s_addr);
253 c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
254
255 random_bytes(&n, sizeof(n));
256 n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
257
258 u->in.s_addr = htobe32(n | c);
259 return 1;
260 }
261
262 if (family == AF_INET6) {
263 struct in6_addr n;
264 unsigned i, j;
265
266 if (prefixlen_fixed_part > 128)
267 prefixlen_fixed_part = 128;
268 if (prefixlen > 128)
269 prefixlen = 128;
270 if (prefixlen_fixed_part >= prefixlen)
271 return -EINVAL;
272
273 random_bytes(&n, sizeof(n));
274
275 for (i = 0; i < 16; i++) {
276 uint8_t mask_fixed_part = 0, mask = 0;
277
278 if (i < (prefixlen_fixed_part + 7) / 8) {
279 if (i < prefixlen_fixed_part / 8)
280 mask_fixed_part = 0xffu;
281 else {
282 j = prefixlen_fixed_part % 8;
283 mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
284 }
285 }
286
287 if (i < (prefixlen + 7) / 8) {
288 if (i < prefixlen / 8)
289 mask = 0xffu ^ mask_fixed_part;
290 else {
291 j = prefixlen % 8;
292 mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
293 }
294 }
295
296 u->in6.s6_addr[i] &= mask_fixed_part;
297 u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
298 }
299
300 return 1;
301 }
302
303 return -EAFNOSUPPORT;
304 }
305
306 int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
307 _cleanup_free_ char *x = NULL;
308 size_t l;
309
310 assert(u);
311 assert(ret);
312
313 if (family == AF_INET)
314 l = INET_ADDRSTRLEN;
315 else if (family == AF_INET6)
316 l = INET6_ADDRSTRLEN;
317 else
318 return -EAFNOSUPPORT;
319
320 x = new(char, l);
321 if (!x)
322 return -ENOMEM;
323
324 errno = 0;
325 if (!inet_ntop(family, u, x, l))
326 return errno_or_else(EINVAL);
327
328 *ret = TAKE_PTR(x);
329 return 0;
330 }
331
332 int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
333 _cleanup_free_ char *x = NULL;
334 char *p;
335 size_t l;
336
337 assert(u);
338 assert(ret);
339
340 if (family == AF_INET)
341 l = INET_ADDRSTRLEN + 3;
342 else if (family == AF_INET6)
343 l = INET6_ADDRSTRLEN + 4;
344 else
345 return -EAFNOSUPPORT;
346
347 if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
348 return -EINVAL;
349
350 x = new(char, l);
351 if (!x)
352 return -ENOMEM;
353
354 errno = 0;
355 if (!inet_ntop(family, u, x, l))
356 return errno_or_else(EINVAL);
357
358 p = x + strlen(x);
359 l -= strlen(x);
360 (void) strpcpyf(&p, l, "/%u", prefixlen);
361
362 *ret = TAKE_PTR(x);
363 return 0;
364 }
365
366 int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
367 _cleanup_free_ char *x = NULL;
368 size_t l;
369 int r;
370
371 assert(u);
372 assert(ret);
373
374 /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
375 * handle IPv6 link-local addresses. */
376
377 if (family != AF_INET6)
378 goto fallback;
379 if (ifindex <= 0)
380 goto fallback;
381
382 r = in_addr_is_link_local(family, u);
383 if (r < 0)
384 return r;
385 if (r == 0)
386 goto fallback;
387
388 l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1;
389 x = new(char, l);
390 if (!x)
391 return -ENOMEM;
392
393 errno = 0;
394 if (!inet_ntop(family, u, x, l))
395 return errno_or_else(EINVAL);
396
397 sprintf(strchr(x, 0), "%%%i", ifindex);
398
399 *ret = TAKE_PTR(x);
400 return 0;
401
402 fallback:
403 return in_addr_to_string(family, u, ret);
404 }
405
406 int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
407 union in_addr_union buffer;
408 assert(s);
409
410 if (!IN_SET(family, AF_INET, AF_INET6))
411 return -EAFNOSUPPORT;
412
413 errno = 0;
414 if (inet_pton(family, s, ret ?: &buffer) <= 0)
415 return errno_or_else(EINVAL);
416
417 return 0;
418 }
419
420 int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
421 int r;
422
423 assert(s);
424
425 r = in_addr_from_string(AF_INET, s, ret);
426 if (r >= 0) {
427 if (ret_family)
428 *ret_family = AF_INET;
429 return 0;
430 }
431
432 r = in_addr_from_string(AF_INET6, s, ret);
433 if (r >= 0) {
434 if (ret_family)
435 *ret_family = AF_INET6;
436 return 0;
437 }
438
439 return -EINVAL;
440 }
441
442 unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
443 assert(addr);
444
445 return 32U - u32ctz(be32toh(addr->s_addr));
446 }
447
448 struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
449 assert(addr);
450 assert(prefixlen <= 32);
451
452 /* Shifting beyond 32 is not defined, handle this specially. */
453 if (prefixlen == 0)
454 addr->s_addr = 0;
455 else
456 addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
457
458 return addr;
459 }
460
461 int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
462 uint8_t msb_octet = *(uint8_t*) addr;
463
464 /* addr may not be aligned, so make sure we only access it byte-wise */
465
466 assert(addr);
467 assert(prefixlen);
468
469 if (msb_octet < 128)
470 /* class A, leading bits: 0 */
471 *prefixlen = 8;
472 else if (msb_octet < 192)
473 /* class B, leading bits 10 */
474 *prefixlen = 16;
475 else if (msb_octet < 224)
476 /* class C, leading bits 110 */
477 *prefixlen = 24;
478 else
479 /* class D or E, no default prefixlen */
480 return -ERANGE;
481
482 return 0;
483 }
484
485 int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
486 unsigned char prefixlen;
487 int r;
488
489 assert(addr);
490 assert(mask);
491
492 r = in4_addr_default_prefixlen(addr, &prefixlen);
493 if (r < 0)
494 return r;
495
496 in4_addr_prefixlen_to_netmask(mask, prefixlen);
497 return 0;
498 }
499
500 int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
501 assert(addr);
502
503 if (family == AF_INET) {
504 struct in_addr mask;
505
506 if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
507 return -EINVAL;
508
509 addr->in.s_addr &= mask.s_addr;
510 return 0;
511 }
512
513 if (family == AF_INET6) {
514 unsigned i;
515
516 for (i = 0; i < 16; i++) {
517 uint8_t mask;
518
519 if (prefixlen >= 8) {
520 mask = 0xFF;
521 prefixlen -= 8;
522 } else {
523 mask = 0xFF << (8 - prefixlen);
524 prefixlen = 0;
525 }
526
527 addr->in6.s6_addr[i] &= mask;
528 }
529
530 return 0;
531 }
532
533 return -EAFNOSUPPORT;
534 }
535
536 int in_addr_prefix_covers(int family,
537 const union in_addr_union *prefix,
538 unsigned char prefixlen,
539 const union in_addr_union *address) {
540
541 union in_addr_union masked_prefix, masked_address;
542 int r;
543
544 assert(prefix);
545 assert(address);
546
547 masked_prefix = *prefix;
548 r = in_addr_mask(family, &masked_prefix, prefixlen);
549 if (r < 0)
550 return r;
551
552 masked_address = *address;
553 r = in_addr_mask(family, &masked_address, prefixlen);
554 if (r < 0)
555 return r;
556
557 return in_addr_equal(family, &masked_prefix, &masked_address);
558 }
559
560 int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
561 uint8_t u;
562 int r;
563
564 if (!IN_SET(family, AF_INET, AF_INET6))
565 return -EAFNOSUPPORT;
566
567 r = safe_atou8(p, &u);
568 if (r < 0)
569 return r;
570
571 if (u > FAMILY_ADDRESS_SIZE(family) * 8)
572 return -ERANGE;
573
574 *ret = u;
575 return 0;
576 }
577
578 int in_addr_prefix_from_string(
579 const char *p,
580 int family,
581 union in_addr_union *ret_prefix,
582 unsigned char *ret_prefixlen) {
583
584 _cleanup_free_ char *str = NULL;
585 union in_addr_union buffer;
586 const char *e, *l;
587 unsigned char k;
588 int r;
589
590 assert(p);
591
592 if (!IN_SET(family, AF_INET, AF_INET6))
593 return -EAFNOSUPPORT;
594
595 e = strchr(p, '/');
596 if (e) {
597 str = strndup(p, e - p);
598 if (!str)
599 return -ENOMEM;
600
601 l = str;
602 } else
603 l = p;
604
605 r = in_addr_from_string(family, l, &buffer);
606 if (r < 0)
607 return r;
608
609 if (e) {
610 r = in_addr_parse_prefixlen(family, e+1, &k);
611 if (r < 0)
612 return r;
613 } else
614 k = FAMILY_ADDRESS_SIZE(family) * 8;
615
616 if (ret_prefix)
617 *ret_prefix = buffer;
618 if (ret_prefixlen)
619 *ret_prefixlen = k;
620
621 return 0;
622 }
623
624 int in_addr_prefix_from_string_auto_internal(
625 const char *p,
626 InAddrPrefixLenMode mode,
627 int *ret_family,
628 union in_addr_union *ret_prefix,
629 unsigned char *ret_prefixlen) {
630
631 _cleanup_free_ char *str = NULL;
632 union in_addr_union buffer;
633 const char *e, *l;
634 unsigned char k;
635 int family, r;
636
637 assert(p);
638
639 e = strchr(p, '/');
640 if (e) {
641 str = strndup(p, e - p);
642 if (!str)
643 return -ENOMEM;
644
645 l = str;
646 } else
647 l = p;
648
649 r = in_addr_from_string_auto(l, &family, &buffer);
650 if (r < 0)
651 return r;
652
653 if (e) {
654 r = in_addr_parse_prefixlen(family, e+1, &k);
655 if (r < 0)
656 return r;
657 } else
658 switch (mode) {
659 case PREFIXLEN_FULL:
660 k = FAMILY_ADDRESS_SIZE(family) * 8;
661 break;
662 case PREFIXLEN_REFUSE:
663 return -ENOANO; /* To distinguish this error from others. */
664 case PREFIXLEN_LEGACY:
665 if (family == AF_INET) {
666 r = in4_addr_default_prefixlen(&buffer.in, &k);
667 if (r < 0)
668 return r;
669 } else
670 k = 0;
671 break;
672 default:
673 assert_not_reached("Invalid prefixlen mode");
674 }
675
676 if (ret_family)
677 *ret_family = family;
678 if (ret_prefix)
679 *ret_prefix = buffer;
680 if (ret_prefixlen)
681 *ret_prefixlen = k;
682
683 return 0;
684
685 }
686
687 static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
688 siphash24_compress(&a->family, sizeof(a->family), state);
689 siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
690 }
691
692 static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
693 int r;
694
695 r = CMP(x->family, y->family);
696 if (r != 0)
697 return r;
698
699 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
700 }
701
702 DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
703
704 static void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
705 assert(addr);
706
707 siphash24_compress(addr, sizeof(*addr), state);
708 }
709
710 static int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
711 return memcmp(a, b, sizeof(*a));
712 }
713
714 DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);