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