]>
Commit | Line | Data |
---|---|---|
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 | 22 | bool 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 |
28 | bool in6_addr_is_null(const struct in6_addr *a) { |
29 | assert(a); | |
30 | ||
31 | return IN6_IS_ADDR_UNSPECIFIED(a); | |
32 | } | |
33 | ||
af93291c | 34 | int 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 |
46 | bool 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 |
52 | bool 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 |
66 | bool 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 |
72 | int 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 |
84 | bool 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 |
94 | bool in4_addr_is_multicast(const struct in_addr *a) { |
95 | assert(a); | |
96 | ||
97 | return IN_MULTICAST(be32toh(a->s_addr)); | |
98 | } | |
99 | ||
100 | bool in6_addr_is_multicast(const struct in6_addr *a) { | |
101 | assert(a); | |
102 | ||
103 | return IN6_IS_ADDR_MULTICAST(a); | |
104 | } | |
105 | ||
85257f48 SS |
106 | int 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 |
118 | bool 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 |
124 | bool 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 |
131 | bool 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 |
139 | int 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 |
151 | int 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 |
164 | bool 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 |
170 | bool 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 |
177 | bool 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 | 184 | int 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 |
197 | bool 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 |
215 | bool 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 |
243 | int 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 | 264 | int 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 | */ |
288 | int 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 |
351 | int 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 |
428 | int 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 | 465 | int 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 |
491 | int 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 |
514 | int 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 | 569 | int 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 | 583 | int 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 | 605 | unsigned 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 | 612 | struct 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::. */ |
626 | struct 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::. */ | |
651 | int 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 | 666 | int 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 | 690 | int 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 |
705 | int 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 |
717 | int 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 | ||
740 | int 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 | 753 | int 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 | 781 | int 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 | 809 | int 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 |
829 | int 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 | 847 | int 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 | 893 | int 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 |
948 | void 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 | 955 | void 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 | 963 | int 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 |
976 | DEFINE_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 | ||
982 | DEFINE_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 | 989 | void 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 | 996 | int 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 |
1003 | DEFINE_HASH_OPS( |
1004 | in6_addr_hash_ops, | |
1005 | struct in6_addr, | |
1006 | in6_addr_hash_func, | |
1007 | in6_addr_compare_func); | |
1008 | ||
f1cb8933 YW |
1009 | DEFINE_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); |