1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <arpa/inet.h>
28 #include "alloc-util.h"
29 #include "in-addr-util.h"
31 #include "parse-util.h"
34 bool in4_addr_is_null(const struct in_addr
*a
) {
37 return a
->s_addr
== 0;
40 int in_addr_is_null(int family
, const union in_addr_union
*u
) {
43 if (family
== AF_INET
)
44 return in4_addr_is_null(&u
->in
);
46 if (family
== AF_INET6
)
47 return IN6_IS_ADDR_UNSPECIFIED(&u
->in6
);
52 bool in4_addr_is_link_local(const struct in_addr
*a
) {
55 return (be32toh(a
->s_addr
) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
58 int in_addr_is_link_local(int family
, const union in_addr_union
*u
) {
61 if (family
== AF_INET
)
62 return in4_addr_is_link_local(&u
->in
);
64 if (family
== AF_INET6
)
65 return IN6_IS_ADDR_LINKLOCAL(&u
->in6
);
70 int in_addr_is_multicast(int family
, const union in_addr_union
*u
) {
73 if (family
== AF_INET
)
74 return IN_MULTICAST(be32toh(u
->in
.s_addr
));
76 if (family
== AF_INET6
)
77 return IN6_IS_ADDR_MULTICAST(&u
->in6
);
82 bool in4_addr_is_localhost(const struct in_addr
*a
) {
85 /* All of 127.x.x.x is localhost. */
86 return (be32toh(a
->s_addr
) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
89 int in_addr_is_localhost(int family
, const union in_addr_union
*u
) {
92 if (family
== AF_INET
)
93 return in4_addr_is_localhost(&u
->in
);
95 if (family
== AF_INET6
)
96 return IN6_IS_ADDR_LOOPBACK(&u
->in6
);
101 int in_addr_equal(int family
, const union in_addr_union
*a
, const union in_addr_union
*b
) {
105 if (family
== AF_INET
)
106 return a
->in
.s_addr
== b
->in
.s_addr
;
108 if (family
== AF_INET6
)
110 a
->in6
.s6_addr32
[0] == b
->in6
.s6_addr32
[0] &&
111 a
->in6
.s6_addr32
[1] == b
->in6
.s6_addr32
[1] &&
112 a
->in6
.s6_addr32
[2] == b
->in6
.s6_addr32
[2] &&
113 a
->in6
.s6_addr32
[3] == b
->in6
.s6_addr32
[3];
115 return -EAFNOSUPPORT
;
118 int in_addr_prefix_intersect(
120 const union in_addr_union
*a
,
122 const union in_addr_union
*b
,
123 unsigned bprefixlen
) {
130 /* Checks whether there are any addresses that are in both
133 m
= MIN(aprefixlen
, bprefixlen
);
135 if (family
== AF_INET
) {
138 x
= be32toh(a
->in
.s_addr
^ b
->in
.s_addr
);
139 nm
= (m
== 0) ? 0 : 0xFFFFFFFFUL
<< (32 - m
);
141 return (x
& nm
) == 0;
144 if (family
== AF_INET6
) {
150 for (i
= 0; i
< 16; i
++) {
153 x
= a
->in6
.s6_addr
[i
] ^ b
->in6
.s6_addr
[i
];
156 nm
= 0xFF << (8 - m
);
172 return -EAFNOSUPPORT
;
175 int in_addr_prefix_next(int family
, union in_addr_union
*u
, unsigned prefixlen
) {
178 /* Increases the network part of an address by one. Returns
179 * positive it that succeeds, or 0 if this overflows. */
184 if (family
== AF_INET
) {
190 c
= be32toh(u
->in
.s_addr
);
191 n
= c
+ (1UL << (32 - prefixlen
));
194 n
&= 0xFFFFFFFFUL
<< (32 - prefixlen
);
196 u
->in
.s_addr
= htobe32(n
);
200 if (family
== AF_INET6
) {
201 struct in6_addr add
= {}, result
;
202 uint8_t overflow
= 0;
208 /* First calculate what we have to add */
209 add
.s6_addr
[(prefixlen
-1) / 8] = 1 << (7 - (prefixlen
-1) % 8);
211 for (i
= 16; i
> 0; i
--) {
214 result
.s6_addr
[j
] = u
->in6
.s6_addr
[j
] + add
.s6_addr
[j
] + overflow
;
215 overflow
= (result
.s6_addr
[j
] < u
->in6
.s6_addr
[j
]);
225 return -EAFNOSUPPORT
;
228 int in_addr_to_string(int family
, const union in_addr_union
*u
, char **ret
) {
235 if (family
== AF_INET
)
237 else if (family
== AF_INET6
)
238 l
= INET6_ADDRSTRLEN
;
240 return -EAFNOSUPPORT
;
247 if (!inet_ntop(family
, u
, x
, l
)) {
249 return errno
> 0 ? -errno
: -EINVAL
;
256 int in_addr_ifindex_to_string(int family
, const union in_addr_union
*u
, int ifindex
, char **ret
) {
264 /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
265 * handle IPv6 link-local addresses. */
267 if (family
!= AF_INET6
)
272 r
= in_addr_is_link_local(family
, u
);
278 l
= INET6_ADDRSTRLEN
+ 1 + DECIMAL_STR_MAX(ifindex
) + 1;
284 if (!inet_ntop(family
, u
, x
, l
)) {
286 return errno
> 0 ? -errno
: -EINVAL
;
289 sprintf(strchr(x
, 0), "%%%i", ifindex
);
295 return in_addr_to_string(family
, u
, ret
);
298 int in_addr_from_string(int family
, const char *s
, union in_addr_union
*ret
) {
299 union in_addr_union buffer
;
302 if (!IN_SET(family
, AF_INET
, AF_INET6
))
303 return -EAFNOSUPPORT
;
306 if (inet_pton(family
, s
, ret
?: &buffer
) <= 0)
307 return errno
> 0 ? -errno
: -EINVAL
;
312 int in_addr_from_string_auto(const char *s
, int *ret_family
, union in_addr_union
*ret
) {
317 r
= in_addr_from_string(AF_INET
, s
, ret
);
320 *ret_family
= AF_INET
;
324 r
= in_addr_from_string(AF_INET6
, s
, ret
);
327 *ret_family
= AF_INET6
;
334 int in_addr_ifindex_from_string_auto(const char *s
, int *family
, union in_addr_union
*ret
, int *ifindex
) {
342 /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
343 * if one is found. */
345 suffix
= strchr(s
, '%');
349 /* If we shall return the interface index, try to parse it */
350 r
= parse_ifindex(suffix
+ 1, &ifi
);
354 u
= if_nametoindex(suffix
+ 1);
362 s
= strndupa(s
, suffix
- s
);
365 r
= in_addr_from_string_auto(s
, family
, ret
);
375 unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr
*addr
) {
378 return 32 - u32ctz(be32toh(addr
->s_addr
));
381 struct in_addr
* in4_addr_prefixlen_to_netmask(struct in_addr
*addr
, unsigned char prefixlen
) {
383 assert(prefixlen
<= 32);
385 /* Shifting beyond 32 is not defined, handle this specially. */
389 addr
->s_addr
= htobe32((0xffffffff << (32 - prefixlen
)) & 0xffffffff);
394 int in4_addr_default_prefixlen(const struct in_addr
*addr
, unsigned char *prefixlen
) {
395 uint8_t msb_octet
= *(uint8_t*) addr
;
397 /* addr may not be aligned, so make sure we only access it byte-wise */
403 /* class A, leading bits: 0 */
405 else if (msb_octet
< 192)
406 /* class B, leading bits 10 */
408 else if (msb_octet
< 224)
409 /* class C, leading bits 110 */
412 /* class D or E, no default prefixlen */
418 int in4_addr_default_subnet_mask(const struct in_addr
*addr
, struct in_addr
*mask
) {
419 unsigned char prefixlen
;
425 r
= in4_addr_default_prefixlen(addr
, &prefixlen
);
429 in4_addr_prefixlen_to_netmask(mask
, prefixlen
);
433 int in_addr_mask(int family
, union in_addr_union
*addr
, unsigned char prefixlen
) {
436 if (family
== AF_INET
) {
439 if (!in4_addr_prefixlen_to_netmask(&mask
, prefixlen
))
442 addr
->in
.s_addr
&= mask
.s_addr
;
446 if (family
== AF_INET6
) {
449 for (i
= 0; i
< 16; i
++) {
452 if (prefixlen
>= 8) {
456 mask
= 0xFF << (8 - prefixlen
);
460 addr
->in6
.s6_addr
[i
] &= mask
;
466 return -EAFNOSUPPORT
;
469 int in_addr_prefix_covers(int family
,
470 const union in_addr_union
*prefix
,
471 unsigned char prefixlen
,
472 const union in_addr_union
*address
) {
474 union in_addr_union masked_prefix
, masked_address
;
480 masked_prefix
= *prefix
;
481 r
= in_addr_mask(family
, &masked_prefix
, prefixlen
);
485 masked_address
= *address
;
486 r
= in_addr_mask(family
, &masked_address
, prefixlen
);
490 return in_addr_equal(family
, &masked_prefix
, &masked_address
);
493 int in_addr_parse_prefixlen(int family
, const char *p
, unsigned char *ret
) {
497 if (!IN_SET(family
, AF_INET
, AF_INET6
))
498 return -EAFNOSUPPORT
;
500 r
= safe_atou8(p
, &u
);
504 if (u
> FAMILY_ADDRESS_SIZE(family
) * 8)
511 int in_addr_prefix_from_string(
514 union in_addr_union
*ret_prefix
,
515 unsigned char *ret_prefixlen
) {
517 union in_addr_union buffer
;
524 if (!IN_SET(family
, AF_INET
, AF_INET6
))
525 return -EAFNOSUPPORT
;
529 l
= strndupa(p
, e
- p
);
533 r
= in_addr_from_string(family
, l
, &buffer
);
538 r
= in_addr_parse_prefixlen(family
, e
+1, &k
);
542 k
= FAMILY_ADDRESS_SIZE(family
) * 8;
545 *ret_prefix
= buffer
;
552 int in_addr_prefix_from_string_auto(
555 union in_addr_union
*ret_prefix
,
556 unsigned char *ret_prefixlen
) {
558 union in_addr_union buffer
;
567 l
= strndupa(p
, e
- p
);
571 r
= in_addr_from_string_auto(l
, &family
, &buffer
);
576 r
= in_addr_parse_prefixlen(family
, e
+1, &k
);
580 k
= FAMILY_ADDRESS_SIZE(family
) * 8;
583 *ret_family
= family
;
585 *ret_prefix
= buffer
;