]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
3b653205 LP |
2 | |
3 | #include <arpa/inet.h> | |
11c3a366 | 4 | #include <endian.h> |
ca78ad1d | 5 | #include <stdio.h> |
3b653205 | 6 | |
b5efdb8a | 7 | #include "alloc-util.h" |
66855de7 | 8 | #include "errno-util.h" |
0c15577a | 9 | #include "hash-funcs.h" |
3b653205 | 10 | #include "in-addr-util.h" |
3ae6b3bf | 11 | #include "logarithm.h" |
d559f463 | 12 | #include "memory-util.h" |
2817157b | 13 | #include "parse-util.h" |
c5236acd | 14 | #include "random-util.h" |
0c15577a | 15 | #include "siphash24.h" |
c71384a9 | 16 | #include "stdio-util.h" |
a723fb85 | 17 | #include "string-util.h" |
3b653205 | 18 | |
34380032 | 19 | bool in4_addr_is_null(const struct in_addr *a) { |
fdedbe26 | 20 | assert(a); |
34380032 | 21 | |
fdedbe26 | 22 | return a->s_addr == 0; |
34380032 LP |
23 | } |
24 | ||
7653dcc3 YW |
25 | bool in6_addr_is_null(const struct in6_addr *a) { |
26 | assert(a); | |
27 | ||
a8a39e23 | 28 | return eqzero(a->s6_addr32); |
7653dcc3 YW |
29 | } |
30 | ||
af93291c | 31 | int in_addr_is_null(int family, const union in_addr_union *u) { |
3b653205 LP |
32 | assert(u); |
33 | ||
34 | if (family == AF_INET) | |
34380032 | 35 | return in4_addr_is_null(&u->in); |
3b653205 LP |
36 | |
37 | if (family == AF_INET6) | |
7653dcc3 | 38 | return in6_addr_is_null(&u->in6); |
3b653205 LP |
39 | |
40 | return -EAFNOSUPPORT; | |
41 | } | |
42 | ||
fdedbe26 LP |
43 | bool in4_addr_is_link_local(const struct in_addr *a) { |
44 | assert(a); | |
45 | ||
46 | return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); | |
47 | } | |
48 | ||
d3efcd2d YW |
49 | bool in4_addr_is_link_local_dynamic(const struct in_addr *a) { |
50 | assert(a); | |
51 | ||
52 | if (!in4_addr_is_link_local(a)) | |
53 | return false; | |
54 | ||
55 | /* 169.254.0.0/24 and 169.254.255.0/24 must not be used for the dynamic IPv4LL assignment. | |
56 | * See RFC 3927 Section 2.1: | |
57 | * The IPv4 prefix 169.254/16 is registered with the IANA for this purpose. The first 256 and last | |
58 | * 256 addresses in the 169.254/16 prefix are reserved for future use and MUST NOT be selected by a | |
59 | * host using this dynamic configuration mechanism. */ | |
60 | return !IN_SET(be32toh(a->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); | |
61 | } | |
62 | ||
1235befa YW |
63 | bool in6_addr_is_link_local(const struct in6_addr *a) { |
64 | assert(a); | |
65 | ||
a8a39e23 | 66 | return (a->s6_addr32[0] & htobe32(0xffc00000)) == htobe32(0xfe800000); |
1235befa YW |
67 | } |
68 | ||
af93291c LP |
69 | int in_addr_is_link_local(int family, const union in_addr_union *u) { |
70 | assert(u); | |
71 | ||
72 | if (family == AF_INET) | |
fdedbe26 | 73 | return in4_addr_is_link_local(&u->in); |
af93291c LP |
74 | |
75 | if (family == AF_INET6) | |
1235befa | 76 | return in6_addr_is_link_local(&u->in6); |
af93291c LP |
77 | |
78 | return -EAFNOSUPPORT; | |
79 | } | |
3b653205 | 80 | |
5643cfc0 YW |
81 | bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) { |
82 | assert(a); | |
83 | ||
84 | /* ff02::1 */ | |
85 | return be32toh(a->s6_addr32[0]) == UINT32_C(0xff020000) && | |
86 | a->s6_addr32[1] == 0 && | |
87 | a->s6_addr32[2] == 0 && | |
88 | be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001); | |
89 | } | |
90 | ||
c7f46150 YW |
91 | bool in4_addr_is_multicast(const struct in_addr *a) { |
92 | assert(a); | |
93 | ||
94 | return IN_MULTICAST(be32toh(a->s_addr)); | |
95 | } | |
96 | ||
97 | bool in6_addr_is_multicast(const struct in6_addr *a) { | |
98 | assert(a); | |
99 | ||
a8a39e23 | 100 | return a->s6_addr[0] == 0xff; |
c7f46150 YW |
101 | } |
102 | ||
85257f48 SS |
103 | int in_addr_is_multicast(int family, const union in_addr_union *u) { |
104 | assert(u); | |
105 | ||
106 | if (family == AF_INET) | |
c7f46150 | 107 | return in4_addr_is_multicast(&u->in); |
85257f48 SS |
108 | |
109 | if (family == AF_INET6) | |
c7f46150 | 110 | return in6_addr_is_multicast(&u->in6); |
85257f48 SS |
111 | |
112 | return -EAFNOSUPPORT; | |
113 | } | |
114 | ||
ccea2448 YW |
115 | bool in4_addr_is_local_multicast(const struct in_addr *a) { |
116 | assert(a); | |
117 | ||
118 | return (be32toh(a->s_addr) & UINT32_C(0xffffff00)) == UINT32_C(0xe0000000); | |
119 | } | |
120 | ||
fdedbe26 LP |
121 | bool in4_addr_is_localhost(const struct in_addr *a) { |
122 | assert(a); | |
123 | ||
124 | /* All of 127.x.x.x is localhost. */ | |
125 | return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24; | |
126 | } | |
127 | ||
072320ea TH |
128 | bool in4_addr_is_non_local(const struct in_addr *a) { |
129 | /* Whether the address is not null and not localhost. | |
130 | * | |
131 | * As such, it is suitable to configure as DNS/NTP server from DHCP. */ | |
132 | return !in4_addr_is_null(a) && | |
133 | !in4_addr_is_localhost(a); | |
134 | } | |
135 | ||
d559f463 DDM |
136 | static bool in6_addr_is_loopback(const struct in6_addr *a) { |
137 | return memcmp(a, &(struct in6_addr) IN6ADDR_LOOPBACK_INIT, sizeof(struct in6_addr)) == 0; | |
138 | } | |
139 | ||
d830ebbd LP |
140 | int in_addr_is_localhost(int family, const union in_addr_union *u) { |
141 | assert(u); | |
142 | ||
143 | if (family == AF_INET) | |
fdedbe26 | 144 | return in4_addr_is_localhost(&u->in); |
d830ebbd | 145 | |
db15affc | 146 | if (family == AF_INET6) |
d559f463 | 147 | return in6_addr_is_loopback(&u->in6); |
d830ebbd LP |
148 | |
149 | return -EAFNOSUPPORT; | |
150 | } | |
151 | ||
b69bfa43 YW |
152 | int in_addr_is_localhost_one(int family, const union in_addr_union *u) { |
153 | assert(u); | |
154 | ||
155 | if (family == AF_INET) | |
156 | /* 127.0.0.1 */ | |
157 | return be32toh(u->in.s_addr) == UINT32_C(0x7F000001); | |
158 | ||
159 | if (family == AF_INET6) | |
d559f463 | 160 | return in6_addr_is_loopback(&u->in6); |
b69bfa43 YW |
161 | |
162 | return -EAFNOSUPPORT; | |
163 | } | |
164 | ||
c3e96088 YW |
165 | bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) { |
166 | return a->s6_addr32[0] == 0 && | |
167 | a->s6_addr32[1] == 0 && | |
168 | a->s6_addr32[2] == htobe32(UINT32_C(0x0000ffff)); | |
169 | } | |
170 | ||
9a897e22 YW |
171 | bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) { |
172 | assert(a); | |
173 | assert(b); | |
174 | ||
175 | return a->s_addr == b->s_addr; | |
176 | } | |
177 | ||
fa550434 YW |
178 | bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b) { |
179 | assert(a); | |
180 | assert(b); | |
181 | ||
d559f463 | 182 | return memcmp(a, b, sizeof(struct in6_addr)) == 0; |
fa550434 YW |
183 | } |
184 | ||
623a4c97 | 185 | int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) { |
3b653205 LP |
186 | assert(a); |
187 | assert(b); | |
188 | ||
189 | if (family == AF_INET) | |
9a897e22 | 190 | return in4_addr_equal(&a->in, &b->in); |
3b653205 LP |
191 | |
192 | if (family == AF_INET6) | |
fa550434 | 193 | return in6_addr_equal(&a->in6, &b->in6); |
3b653205 LP |
194 | |
195 | return -EAFNOSUPPORT; | |
196 | } | |
197 | ||
21ae0b4b YW |
198 | bool in4_addr_prefix_intersect( |
199 | const struct in_addr *a, | |
3b653205 | 200 | unsigned aprefixlen, |
21ae0b4b | 201 | const struct in_addr *b, |
3b653205 LP |
202 | unsigned bprefixlen) { |
203 | ||
3b653205 LP |
204 | assert(a); |
205 | assert(b); | |
206 | ||
21ae0b4b YW |
207 | unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in_addr) * 8)); |
208 | if (m == 0) | |
209 | return true; /* Let's return earlier, to avoid shift by 32. */ | |
3b653205 | 210 | |
21ae0b4b YW |
211 | uint32_t x = be32toh(a->s_addr ^ b->s_addr); |
212 | uint32_t n = 0xFFFFFFFFUL << (32 - m); | |
213 | return (x & n) == 0; | |
214 | } | |
3b653205 | 215 | |
21ae0b4b YW |
216 | bool in6_addr_prefix_intersect( |
217 | const struct in6_addr *a, | |
218 | unsigned aprefixlen, | |
219 | const struct in6_addr *b, | |
220 | unsigned bprefixlen) { | |
3b653205 | 221 | |
21ae0b4b YW |
222 | assert(a); |
223 | assert(b); | |
3b653205 | 224 | |
21ae0b4b YW |
225 | unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in6_addr) * 8)); |
226 | if (m == 0) | |
227 | return true; | |
3b653205 | 228 | |
21ae0b4b YW |
229 | for (size_t i = 0; i < sizeof(struct in6_addr); i++) { |
230 | uint8_t x = a->s6_addr[i] ^ b->s6_addr[i]; | |
231 | uint8_t n = m < 8 ? (0xFF << (8 - m)) : 0xFF; | |
232 | if ((x & n) != 0) | |
233 | return false; | |
3b653205 | 234 | |
21ae0b4b YW |
235 | if (m <= 8) |
236 | break; | |
3b653205 | 237 | |
21ae0b4b YW |
238 | m -= 8; |
239 | } | |
3b653205 | 240 | |
21ae0b4b YW |
241 | return true; |
242 | } | |
3b653205 | 243 | |
21ae0b4b YW |
244 | int in_addr_prefix_intersect( |
245 | int family, | |
246 | const union in_addr_union *a, | |
247 | unsigned aprefixlen, | |
248 | const union in_addr_union *b, | |
249 | unsigned bprefixlen) { | |
3b653205 | 250 | |
21ae0b4b YW |
251 | assert(a); |
252 | assert(b); | |
3b653205 | 253 | |
21ae0b4b | 254 | /* Checks whether there are any addresses that are in both networks. */ |
3b653205 | 255 | |
21ae0b4b YW |
256 | if (family == AF_INET) |
257 | return in4_addr_prefix_intersect(&a->in, aprefixlen, &b->in, bprefixlen); | |
258 | ||
259 | if (family == AF_INET6) | |
260 | return in6_addr_prefix_intersect(&a->in6, aprefixlen, &b->in6, bprefixlen); | |
3b653205 LP |
261 | |
262 | return -EAFNOSUPPORT; | |
263 | } | |
264 | ||
0dd25fb9 | 265 | int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) { |
3b653205 LP |
266 | assert(u); |
267 | ||
518b6da5 YW |
268 | /* Increases the network part of an address by one. Returns 0 if that succeeds, or -ERANGE if |
269 | * this overflows. */ | |
3b653205 | 270 | |
171f625b | 271 | return in_addr_prefix_nth(family, u, prefixlen, 1); |
c5236acd YW |
272 | } |
273 | ||
863b99cd AR |
274 | /* |
275 | * Calculates the nth prefix of size prefixlen starting from the address denoted by u. | |
276 | * | |
518b6da5 | 277 | * On success 0 will be returned and the calculated prefix will be available in |
9164338b | 278 | * u. In case the calculation cannot be performed (invalid prefix length, |
863b99cd AR |
279 | * overflows would occur) -ERANGE is returned. If the address family given isn't |
280 | * supported -EAFNOSUPPORT will be returned. | |
281 | * | |
863b99cd | 282 | * Examples: |
518b6da5 YW |
283 | * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 0, writes 192.168.2.0 to u |
284 | * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 0, no data written | |
863b99cd AR |
285 | * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 24, 1), returns -ERANGE, no data written |
286 | * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 0, 1), returns -ERANGE, no data written | |
518b6da5 | 287 | * - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 0, writes 2001:0db8:0000:ff00:: to u |
863b99cd AR |
288 | */ |
289 | int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth) { | |
290 | assert(u); | |
291 | ||
292 | if (prefixlen <= 0) | |
293 | return -ERANGE; | |
294 | ||
863b99cd AR |
295 | if (family == AF_INET) { |
296 | uint32_t c, n, t; | |
7b6b05cf | 297 | |
863b99cd | 298 | if (prefixlen > 32) |
7b6b05cf | 299 | return -ERANGE; |
863b99cd AR |
300 | |
301 | c = be32toh(u->in.s_addr); | |
302 | ||
303 | t = nth << (32 - prefixlen); | |
304 | ||
305 | /* Check for wrap */ | |
306 | if (c > UINT32_MAX - t) | |
307 | return -ERANGE; | |
308 | ||
309 | n = c + t; | |
310 | ||
311 | n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen); | |
312 | u->in.s_addr = htobe32(n); | |
518b6da5 | 313 | return 0; |
863b99cd AR |
314 | } |
315 | ||
316 | if (family == AF_INET6) { | |
9164338b | 317 | bool overflow = false; |
863b99cd AR |
318 | |
319 | if (prefixlen > 128) | |
7b6b05cf | 320 | return -ERANGE; |
863b99cd | 321 | |
863b99cd | 322 | for (unsigned i = 16; i > 0; i--) { |
9164338b YW |
323 | unsigned t, j = i - 1, p = j * 8; |
324 | ||
325 | if (p >= prefixlen) { | |
326 | u->in6.s6_addr[j] = 0; | |
327 | continue; | |
328 | } | |
329 | ||
330 | if (prefixlen - p < 8) { | |
331 | u->in6.s6_addr[j] &= 0xff << (8 - (prefixlen - p)); | |
332 | t = u->in6.s6_addr[j] + ((nth & 0xff) << (8 - (prefixlen - p))); | |
333 | nth >>= prefixlen - p; | |
334 | } else { | |
335 | t = u->in6.s6_addr[j] + (nth & 0xff) + overflow; | |
336 | nth >>= 8; | |
337 | } | |
338 | ||
339 | overflow = t > UINT8_MAX; | |
340 | u->in6.s6_addr[j] = (uint8_t) (t & 0xff); | |
863b99cd AR |
341 | } |
342 | ||
9164338b | 343 | if (overflow || nth != 0) |
863b99cd AR |
344 | return -ERANGE; |
345 | ||
518b6da5 | 346 | return 0; |
863b99cd AR |
347 | } |
348 | ||
349 | return -EAFNOSUPPORT; | |
350 | } | |
351 | ||
c5236acd YW |
352 | int in_addr_random_prefix( |
353 | int family, | |
354 | union in_addr_union *u, | |
355 | unsigned prefixlen_fixed_part, | |
356 | unsigned prefixlen) { | |
357 | ||
358 | assert(u); | |
359 | ||
360 | /* Random network part of an address by one. */ | |
361 | ||
362 | if (prefixlen <= 0) | |
363 | return 0; | |
364 | ||
365 | if (family == AF_INET) { | |
366 | uint32_t c, n; | |
367 | ||
368 | if (prefixlen_fixed_part > 32) | |
369 | prefixlen_fixed_part = 32; | |
370 | if (prefixlen > 32) | |
371 | prefixlen = 32; | |
372 | if (prefixlen_fixed_part >= prefixlen) | |
373 | return -EINVAL; | |
374 | ||
375 | c = be32toh(u->in.s_addr); | |
376 | c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part); | |
377 | ||
378 | random_bytes(&n, sizeof(n)); | |
379 | n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen); | |
380 | ||
381 | u->in.s_addr = htobe32(n | c); | |
382 | return 1; | |
383 | } | |
384 | ||
385 | if (family == AF_INET6) { | |
386 | struct in6_addr n; | |
387 | unsigned i, j; | |
388 | ||
389 | if (prefixlen_fixed_part > 128) | |
390 | prefixlen_fixed_part = 128; | |
391 | if (prefixlen > 128) | |
392 | prefixlen = 128; | |
393 | if (prefixlen_fixed_part >= prefixlen) | |
394 | return -EINVAL; | |
395 | ||
396 | random_bytes(&n, sizeof(n)); | |
397 | ||
398 | for (i = 0; i < 16; i++) { | |
399 | uint8_t mask_fixed_part = 0, mask = 0; | |
400 | ||
401 | if (i < (prefixlen_fixed_part + 7) / 8) { | |
402 | if (i < prefixlen_fixed_part / 8) | |
403 | mask_fixed_part = 0xffu; | |
404 | else { | |
405 | j = prefixlen_fixed_part % 8; | |
406 | mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j); | |
407 | } | |
408 | } | |
409 | ||
410 | if (i < (prefixlen + 7) / 8) { | |
411 | if (i < prefixlen / 8) | |
412 | mask = 0xffu ^ mask_fixed_part; | |
413 | else { | |
414 | j = prefixlen % 8; | |
415 | mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part; | |
416 | } | |
417 | } | |
418 | ||
419 | u->in6.s6_addr[i] &= mask_fixed_part; | |
420 | u->in6.s6_addr[i] |= n.s6_addr[i] & mask; | |
421 | } | |
422 | ||
423 | return 1; | |
424 | } | |
3b653205 LP |
425 | |
426 | return -EAFNOSUPPORT; | |
427 | } | |
428 | ||
1534c579 YW |
429 | int in_addr_prefix_range( |
430 | int family, | |
431 | const union in_addr_union *in, | |
432 | unsigned prefixlen, | |
433 | union in_addr_union *ret_start, | |
434 | union in_addr_union *ret_end) { | |
435 | ||
436 | union in_addr_union start, end; | |
437 | int r; | |
438 | ||
439 | assert(in); | |
440 | ||
441 | if (!IN_SET(family, AF_INET, AF_INET6)) | |
442 | return -EAFNOSUPPORT; | |
443 | ||
444 | if (ret_start) { | |
445 | start = *in; | |
446 | r = in_addr_prefix_nth(family, &start, prefixlen, 0); | |
447 | if (r < 0) | |
448 | return r; | |
449 | } | |
450 | ||
451 | if (ret_end) { | |
452 | end = *in; | |
453 | r = in_addr_prefix_nth(family, &end, prefixlen, 1); | |
454 | if (r < 0) | |
455 | return r; | |
456 | } | |
457 | ||
458 | if (ret_start) | |
459 | *ret_start = start; | |
460 | if (ret_end) | |
461 | *ret_end = end; | |
462 | ||
463 | return 0; | |
464 | } | |
465 | ||
0dd25fb9 | 466 | int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { |
81260be1 | 467 | _cleanup_free_ char *x = NULL; |
3b653205 LP |
468 | size_t l; |
469 | ||
470 | assert(u); | |
471 | assert(ret); | |
472 | ||
473 | if (family == AF_INET) | |
474 | l = INET_ADDRSTRLEN; | |
475 | else if (family == AF_INET6) | |
476 | l = INET6_ADDRSTRLEN; | |
477 | else | |
478 | return -EAFNOSUPPORT; | |
479 | ||
480 | x = new(char, l); | |
481 | if (!x) | |
482 | return -ENOMEM; | |
483 | ||
484 | errno = 0; | |
84dbb3fd | 485 | if (!typesafe_inet_ntop(family, u, x, l)) |
66855de7 | 486 | return errno_or_else(EINVAL); |
3b653205 | 487 | |
81260be1 | 488 | *ret = TAKE_PTR(x); |
3b653205 LP |
489 | return 0; |
490 | } | |
491 | ||
0c15577a DDM |
492 | const char* typesafe_inet_ntop(int family, const union in_addr_union *a, char *buf, size_t len) { |
493 | return inet_ntop(family, a, buf, len); | |
494 | } | |
495 | ||
496 | const char* typesafe_inet_ntop4(const struct in_addr *a, char *buf, size_t len) { | |
497 | return inet_ntop(AF_INET, a, buf, len); | |
498 | } | |
499 | ||
500 | const char* typesafe_inet_ntop6(const struct in6_addr *a, char *buf, size_t len) { | |
501 | return inet_ntop(AF_INET6, a, buf, len); | |
502 | } | |
503 | ||
c71384a9 ZJS |
504 | int in_addr_prefix_to_string( |
505 | int family, | |
506 | const union in_addr_union *u, | |
507 | unsigned prefixlen, | |
508 | char *buf, | |
509 | size_t buf_len) { | |
d9143dac YW |
510 | |
511 | assert(u); | |
c71384a9 | 512 | assert(buf); |
d9143dac | 513 | |
c71384a9 | 514 | if (!IN_SET(family, AF_INET, AF_INET6)) |
d9143dac YW |
515 | return -EAFNOSUPPORT; |
516 | ||
d9143dac | 517 | errno = 0; |
c71384a9 ZJS |
518 | if (!typesafe_inet_ntop(family, u, buf, buf_len)) |
519 | return errno_or_else(ENOSPC); | |
d9143dac | 520 | |
c71384a9 ZJS |
521 | size_t l = strlen(buf); |
522 | if (!snprintf_ok(buf + l, buf_len - l, "/%u", prefixlen)) | |
523 | return -ENOSPC; | |
d9143dac YW |
524 | return 0; |
525 | } | |
526 | ||
a723fb85 YW |
527 | 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) { |
528 | _cleanup_free_ char *ip_str = NULL, *x = NULL; | |
529 | int r; | |
530 | ||
531 | assert(IN_SET(family, AF_INET, AF_INET6)); | |
532 | assert(u); | |
533 | assert(ret); | |
534 | ||
535 | /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly | |
536 | * handle IPv6 link-local addresses. */ | |
537 | ||
538 | r = in_addr_to_string(family, u, &ip_str); | |
539 | if (r < 0) | |
540 | return r; | |
541 | ||
542 | if (family == AF_INET6) { | |
543 | r = in_addr_is_link_local(family, u); | |
544 | if (r < 0) | |
545 | return r; | |
546 | if (r == 0) | |
547 | ifindex = 0; | |
548 | } else | |
549 | ifindex = 0; /* For IPv4 address, ifindex is always ignored. */ | |
550 | ||
551 | if (port == 0 && ifindex == 0 && isempty(server_name)) { | |
552 | *ret = TAKE_PTR(ip_str); | |
553 | return 0; | |
554 | } | |
555 | ||
556 | const char *separator = isempty(server_name) ? "" : "#"; | |
557 | server_name = strempty(server_name); | |
558 | ||
559 | if (port > 0) { | |
560 | if (family == AF_INET6) { | |
561 | if (ifindex > 0) | |
562 | r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name); | |
563 | else | |
564 | r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name); | |
565 | } else | |
566 | r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name); | |
567 | } else { | |
568 | if (ifindex > 0) | |
569 | r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name); | |
570 | else { | |
571 | x = strjoin(ip_str, separator, server_name); | |
572 | r = x ? 0 : -ENOMEM; | |
573 | } | |
574 | } | |
575 | if (r < 0) | |
576 | return -ENOMEM; | |
577 | ||
578 | *ret = TAKE_PTR(x); | |
579 | return 0; | |
580 | } | |
581 | ||
0dd25fb9 | 582 | int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { |
fd18634d | 583 | union in_addr_union buffer; |
3b653205 | 584 | assert(s); |
3b653205 LP |
585 | |
586 | if (!IN_SET(family, AF_INET, AF_INET6)) | |
587 | return -EAFNOSUPPORT; | |
588 | ||
589 | errno = 0; | |
fd18634d | 590 | if (inet_pton(family, s, ret ?: &buffer) <= 0) |
66855de7 | 591 | return errno_or_else(EINVAL); |
3b653205 LP |
592 | |
593 | return 0; | |
594 | } | |
74b2466e | 595 | |
4e2d5273 | 596 | int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) { |
74b2466e LP |
597 | int r; |
598 | ||
599 | assert(s); | |
74b2466e LP |
600 | |
601 | r = in_addr_from_string(AF_INET, s, ret); | |
602 | if (r >= 0) { | |
4e2d5273 LP |
603 | if (ret_family) |
604 | *ret_family = AF_INET; | |
74b2466e LP |
605 | return 0; |
606 | } | |
607 | ||
608 | r = in_addr_from_string(AF_INET6, s, ret); | |
609 | if (r >= 0) { | |
4e2d5273 LP |
610 | if (ret_family) |
611 | *ret_family = AF_INET6; | |
74b2466e LP |
612 | return 0; |
613 | } | |
614 | ||
615 | return -EINVAL; | |
616 | } | |
44e7b949 | 617 | |
5a941f5f | 618 | unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) { |
44e7b949 LP |
619 | assert(addr); |
620 | ||
1a359852 | 621 | return 32U - u32ctz(be32toh(addr->s_addr)); |
44e7b949 | 622 | } |
df40eee8 | 623 | |
3f36b9ed | 624 | /* Calculate an IPv4 netmask from prefix length, for example /8 -> 255.0.0.0. */ |
5a941f5f | 625 | struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) { |
76917807 LP |
626 | assert(addr); |
627 | assert(prefixlen <= 32); | |
628 | ||
629 | /* Shifting beyond 32 is not defined, handle this specially. */ | |
630 | if (prefixlen == 0) | |
631 | addr->s_addr = 0; | |
632 | else | |
633 | addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff); | |
634 | ||
635 | return addr; | |
636 | } | |
637 | ||
3f36b9ed TM |
638 | /* Calculate an IPv6 netmask from prefix length, for example /16 -> ffff::. */ |
639 | struct in6_addr* in6_addr_prefixlen_to_netmask(struct in6_addr *addr, unsigned char prefixlen) { | |
640 | assert(addr); | |
641 | assert(prefixlen <= 128); | |
642 | ||
643 | for (unsigned i = 0; i < 16; i++) { | |
644 | uint8_t mask; | |
645 | ||
646 | if (prefixlen >= 8) { | |
647 | mask = 0xFF; | |
648 | prefixlen -= 8; | |
649 | } else if (prefixlen > 0) { | |
650 | mask = 0xFF << (8 - prefixlen); | |
651 | prefixlen = 0; | |
652 | } else { | |
653 | assert(prefixlen == 0); | |
654 | mask = 0; | |
655 | } | |
656 | ||
657 | addr->s6_addr[i] = mask; | |
658 | } | |
659 | ||
660 | return addr; | |
661 | } | |
662 | ||
663 | /* Calculate an IPv4 or IPv6 netmask from prefix length, for example /8 -> 255.0.0.0 or /16 -> ffff::. */ | |
664 | int in_addr_prefixlen_to_netmask(int family, union in_addr_union *addr, unsigned char prefixlen) { | |
665 | assert(addr); | |
666 | ||
667 | switch (family) { | |
668 | case AF_INET: | |
669 | in4_addr_prefixlen_to_netmask(&addr->in, prefixlen); | |
670 | return 0; | |
671 | case AF_INET6: | |
672 | in6_addr_prefixlen_to_netmask(&addr->in6, prefixlen); | |
673 | return 0; | |
674 | default: | |
675 | return -EAFNOSUPPORT; | |
676 | } | |
677 | } | |
678 | ||
5a941f5f | 679 | int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) { |
1caa12d0 TG |
680 | uint8_t msb_octet = *(uint8_t*) addr; |
681 | ||
682 | /* addr may not be aligned, so make sure we only access it byte-wise */ | |
df40eee8 TG |
683 | |
684 | assert(addr); | |
df40eee8 TG |
685 | assert(prefixlen); |
686 | ||
1caa12d0 | 687 | if (msb_octet < 128) |
df40eee8 TG |
688 | /* class A, leading bits: 0 */ |
689 | *prefixlen = 8; | |
1caa12d0 | 690 | else if (msb_octet < 192) |
df40eee8 TG |
691 | /* class B, leading bits 10 */ |
692 | *prefixlen = 16; | |
1caa12d0 | 693 | else if (msb_octet < 224) |
df40eee8 TG |
694 | /* class C, leading bits 110 */ |
695 | *prefixlen = 24; | |
696 | else | |
697 | /* class D or E, no default prefixlen */ | |
698 | return -ERANGE; | |
699 | ||
700 | return 0; | |
701 | } | |
702 | ||
5a941f5f | 703 | int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) { |
df40eee8 TG |
704 | unsigned char prefixlen; |
705 | int r; | |
706 | ||
707 | assert(addr); | |
708 | assert(mask); | |
709 | ||
5a941f5f | 710 | r = in4_addr_default_prefixlen(addr, &prefixlen); |
df40eee8 TG |
711 | if (r < 0) |
712 | return r; | |
713 | ||
5a941f5f | 714 | in4_addr_prefixlen_to_netmask(mask, prefixlen); |
df40eee8 TG |
715 | return 0; |
716 | } | |
5a8bcb67 | 717 | |
333f7d89 YW |
718 | int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen) { |
719 | struct in_addr mask; | |
5a8bcb67 | 720 | |
333f7d89 | 721 | assert(addr); |
5a8bcb67 | 722 | |
333f7d89 YW |
723 | if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen)) |
724 | return -EINVAL; | |
5a8bcb67 | 725 | |
333f7d89 YW |
726 | addr->s_addr &= mask.s_addr; |
727 | return 0; | |
728 | } | |
5a8bcb67 | 729 | |
333f7d89 YW |
730 | int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen) { |
731 | unsigned i; | |
5a8bcb67 | 732 | |
333f7d89 YW |
733 | for (i = 0; i < 16; i++) { |
734 | uint8_t mask; | |
5a8bcb67 | 735 | |
333f7d89 YW |
736 | if (prefixlen >= 8) { |
737 | mask = 0xFF; | |
738 | prefixlen -= 8; | |
6df860f3 | 739 | } else if (prefixlen > 0) { |
333f7d89 YW |
740 | mask = 0xFF << (8 - prefixlen); |
741 | prefixlen = 0; | |
6df860f3 YW |
742 | } else { |
743 | assert(prefixlen == 0); | |
744 | mask = 0; | |
5a8bcb67 LP |
745 | } |
746 | ||
333f7d89 | 747 | addr->s6_addr[i] &= mask; |
5a8bcb67 LP |
748 | } |
749 | ||
333f7d89 YW |
750 | return 0; |
751 | } | |
752 | ||
753 | int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) { | |
754 | assert(addr); | |
755 | ||
756 | switch (family) { | |
757 | case AF_INET: | |
758 | return in4_addr_mask(&addr->in, prefixlen); | |
759 | case AF_INET6: | |
760 | return in6_addr_mask(&addr->in6, prefixlen); | |
761 | default: | |
762 | return -EAFNOSUPPORT; | |
763 | } | |
5a8bcb67 | 764 | } |
f7bf1abe | 765 | |
45e76094 | 766 | int in4_addr_prefix_covers_full( |
e174b43f YW |
767 | const struct in_addr *prefix, |
768 | unsigned char prefixlen, | |
45e76094 YW |
769 | const struct in_addr *address, |
770 | unsigned char address_prefixlen) { | |
1274b6c6 | 771 | |
e174b43f | 772 | struct in_addr masked_prefix, masked_address; |
1274b6c6 LP |
773 | int r; |
774 | ||
775 | assert(prefix); | |
776 | assert(address); | |
777 | ||
45e76094 YW |
778 | if (prefixlen > address_prefixlen) |
779 | return false; | |
780 | ||
1274b6c6 | 781 | masked_prefix = *prefix; |
e174b43f | 782 | r = in4_addr_mask(&masked_prefix, prefixlen); |
1274b6c6 LP |
783 | if (r < 0) |
784 | return r; | |
785 | ||
786 | masked_address = *address; | |
e174b43f | 787 | r = in4_addr_mask(&masked_address, prefixlen); |
1274b6c6 LP |
788 | if (r < 0) |
789 | return r; | |
790 | ||
e174b43f YW |
791 | return in4_addr_equal(&masked_prefix, &masked_address); |
792 | } | |
793 | ||
45e76094 | 794 | int in6_addr_prefix_covers_full( |
e174b43f YW |
795 | const struct in6_addr *prefix, |
796 | unsigned char prefixlen, | |
45e76094 YW |
797 | const struct in6_addr *address, |
798 | unsigned char address_prefixlen) { | |
e174b43f YW |
799 | |
800 | struct in6_addr masked_prefix, masked_address; | |
801 | int r; | |
802 | ||
803 | assert(prefix); | |
804 | assert(address); | |
805 | ||
45e76094 YW |
806 | if (prefixlen > address_prefixlen) |
807 | return false; | |
808 | ||
e174b43f YW |
809 | masked_prefix = *prefix; |
810 | r = in6_addr_mask(&masked_prefix, prefixlen); | |
811 | if (r < 0) | |
812 | return r; | |
813 | ||
814 | masked_address = *address; | |
815 | r = in6_addr_mask(&masked_address, prefixlen); | |
816 | if (r < 0) | |
817 | return r; | |
818 | ||
819 | return in6_addr_equal(&masked_prefix, &masked_address); | |
820 | } | |
821 | ||
45e76094 | 822 | int in_addr_prefix_covers_full( |
e174b43f YW |
823 | int family, |
824 | const union in_addr_union *prefix, | |
825 | unsigned char prefixlen, | |
45e76094 YW |
826 | const union in_addr_union *address, |
827 | unsigned char address_prefixlen) { | |
e174b43f YW |
828 | |
829 | assert(prefix); | |
830 | assert(address); | |
831 | ||
832 | switch (family) { | |
833 | case AF_INET: | |
45e76094 | 834 | return in4_addr_prefix_covers_full(&prefix->in, prefixlen, &address->in, address_prefixlen); |
e174b43f | 835 | case AF_INET6: |
45e76094 | 836 | return in6_addr_prefix_covers_full(&prefix->in6, prefixlen, &address->in6, address_prefixlen); |
e174b43f YW |
837 | default: |
838 | return -EAFNOSUPPORT; | |
839 | } | |
1274b6c6 LP |
840 | } |
841 | ||
f4912f3a LP |
842 | int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) { |
843 | uint8_t u; | |
844 | int r; | |
845 | ||
846 | if (!IN_SET(family, AF_INET, AF_INET6)) | |
847 | return -EAFNOSUPPORT; | |
848 | ||
849 | r = safe_atou8(p, &u); | |
850 | if (r < 0) | |
851 | return r; | |
852 | ||
853 | if (u > FAMILY_ADDRESS_SIZE(family) * 8) | |
854 | return -ERANGE; | |
855 | ||
856 | *ret = u; | |
857 | return 0; | |
858 | } | |
859 | ||
9e0fdc21 | 860 | int in_addr_prefix_from_string( |
f4912f3a LP |
861 | const char *p, |
862 | int family, | |
863 | union in_addr_union *ret_prefix, | |
864 | unsigned char *ret_prefixlen) { | |
865 | ||
67944f5c | 866 | _cleanup_free_ char *str = NULL; |
f7bf1abe SS |
867 | union in_addr_union buffer; |
868 | const char *e, *l; | |
f4912f3a | 869 | unsigned char k; |
f7bf1abe SS |
870 | int r; |
871 | ||
872 | assert(p); | |
873 | ||
874 | if (!IN_SET(family, AF_INET, AF_INET6)) | |
875 | return -EAFNOSUPPORT; | |
876 | ||
877 | e = strchr(p, '/'); | |
67944f5c YW |
878 | if (e) { |
879 | str = strndup(p, e - p); | |
880 | if (!str) | |
881 | return -ENOMEM; | |
882 | ||
883 | l = str; | |
884 | } else | |
f7bf1abe SS |
885 | l = p; |
886 | ||
887 | r = in_addr_from_string(family, l, &buffer); | |
888 | if (r < 0) | |
889 | return r; | |
890 | ||
f7bf1abe | 891 | if (e) { |
f4912f3a | 892 | r = in_addr_parse_prefixlen(family, e+1, &k); |
f7bf1abe SS |
893 | if (r < 0) |
894 | return r; | |
f4912f3a LP |
895 | } else |
896 | k = FAMILY_ADDRESS_SIZE(family) * 8; | |
f7bf1abe | 897 | |
f4912f3a LP |
898 | if (ret_prefix) |
899 | *ret_prefix = buffer; | |
900 | if (ret_prefixlen) | |
901 | *ret_prefixlen = k; | |
f7bf1abe | 902 | |
f4912f3a LP |
903 | return 0; |
904 | } | |
f7bf1abe | 905 | |
c1316cd0 | 906 | int in_addr_prefix_from_string_auto_full( |
f4912f3a | 907 | const char *p, |
9e0fdc21 | 908 | InAddrPrefixLenMode mode, |
f4912f3a LP |
909 | int *ret_family, |
910 | union in_addr_union *ret_prefix, | |
911 | unsigned char *ret_prefixlen) { | |
912 | ||
67944f5c | 913 | _cleanup_free_ char *str = NULL; |
f4912f3a LP |
914 | union in_addr_union buffer; |
915 | const char *e, *l; | |
916 | unsigned char k; | |
917 | int family, r; | |
918 | ||
919 | assert(p); | |
920 | ||
921 | e = strchr(p, '/'); | |
67944f5c YW |
922 | if (e) { |
923 | str = strndup(p, e - p); | |
924 | if (!str) | |
925 | return -ENOMEM; | |
926 | ||
927 | l = str; | |
928 | } else | |
f4912f3a LP |
929 | l = p; |
930 | ||
931 | r = in_addr_from_string_auto(l, &family, &buffer); | |
932 | if (r < 0) | |
933 | return r; | |
934 | ||
935 | if (e) { | |
936 | r = in_addr_parse_prefixlen(family, e+1, &k); | |
937 | if (r < 0) | |
a4798d4e | 938 | return r; |
f4912f3a | 939 | } else |
9e0fdc21 YW |
940 | switch (mode) { |
941 | case PREFIXLEN_FULL: | |
942 | k = FAMILY_ADDRESS_SIZE(family) * 8; | |
943 | break; | |
944 | case PREFIXLEN_REFUSE: | |
945 | return -ENOANO; /* To distinguish this error from others. */ | |
9e0fdc21 | 946 | default: |
04499a70 | 947 | assert_not_reached(); |
9e0fdc21 | 948 | } |
f4912f3a LP |
949 | |
950 | if (ret_family) | |
951 | *ret_family = family; | |
952 | if (ret_prefix) | |
953 | *ret_prefix = buffer; | |
954 | if (ret_prefixlen) | |
955 | *ret_prefixlen = k; | |
f7bf1abe SS |
956 | |
957 | return 0; | |
958 | } | |
6c39e026 | 959 | |
c01a5c05 YW |
960 | void in_addr_hash_func(const union in_addr_union *u, int family, struct siphash *state) { |
961 | assert(u); | |
962 | assert(state); | |
963 | ||
964 | siphash24_compress(u->bytes, FAMILY_ADDRESS_SIZE(family), state); | |
965 | } | |
966 | ||
4596c836 | 967 | void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) { |
93e44aa9 YW |
968 | assert(a); |
969 | assert(state); | |
970 | ||
c01a5c05 YW |
971 | siphash24_compress_typesafe(a->family, state); |
972 | in_addr_hash_func(&a->address, a->family, state); | |
6c39e026 YW |
973 | } |
974 | ||
4596c836 | 975 | int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) { |
a0edd02e | 976 | int r; |
6c39e026 | 977 | |
93e44aa9 YW |
978 | assert(x); |
979 | assert(y); | |
980 | ||
a0edd02e FB |
981 | r = CMP(x->family, y->family); |
982 | if (r != 0) | |
983 | return r; | |
6c39e026 | 984 | |
23577246 | 985 | return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family)); |
6c39e026 YW |
986 | } |
987 | ||
4596c836 YW |
988 | DEFINE_HASH_OPS( |
989 | in_addr_data_hash_ops, | |
990 | struct in_addr_data, | |
991 | in_addr_data_hash_func, | |
992 | in_addr_data_compare_func); | |
993 | ||
994 | DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( | |
995 | in_addr_data_hash_ops_free, | |
996 | struct in_addr_data, | |
997 | in_addr_data_hash_func, | |
998 | in_addr_data_compare_func, | |
999 | free); | |
2968913e | 1000 | |
badd4928 | 1001 | void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) { |
2968913e | 1002 | assert(addr); |
93e44aa9 | 1003 | assert(state); |
2968913e | 1004 | |
c01a5c05 | 1005 | siphash24_compress_typesafe(*addr, state); |
2968913e YW |
1006 | } |
1007 | ||
badd4928 | 1008 | int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) { |
93e44aa9 YW |
1009 | assert(a); |
1010 | assert(b); | |
1011 | ||
2968913e YW |
1012 | return memcmp(a, b, sizeof(*a)); |
1013 | } | |
1014 | ||
4596c836 YW |
1015 | DEFINE_HASH_OPS( |
1016 | in6_addr_hash_ops, | |
1017 | struct in6_addr, | |
1018 | in6_addr_hash_func, | |
1019 | in6_addr_compare_func); | |
1020 | ||
f1cb8933 YW |
1021 | DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( |
1022 | in6_addr_hash_ops_free, | |
1023 | struct in6_addr, | |
1024 | in6_addr_hash_func, | |
1025 | in6_addr_compare_func, | |
1026 | free); |