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