]> git.proxmox.com Git - systemd.git/blob - src/basic/in-addr-util.c
New upstream version 249~rc1
[systemd.git] / src / basic / in-addr-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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 <stdio.h>
9 #include <stdlib.h>
10
11 #include "alloc-util.h"
12 #include "errno-util.h"
13 #include "in-addr-util.h"
14 #include "macro.h"
15 #include "parse-util.h"
16 #include "random-util.h"
17 #include "string-util.h"
18 #include "strxcpyx.h"
19 #include "util.h"
20
21 bool in4_addr_is_null(const struct in_addr *a) {
22 assert(a);
23
24 return a->s_addr == 0;
25 }
26
27 bool in6_addr_is_null(const struct in6_addr *a) {
28 assert(a);
29
30 return IN6_IS_ADDR_UNSPECIFIED(a);
31 }
32
33 int in_addr_is_null(int family, const union in_addr_union *u) {
34 assert(u);
35
36 if (family == AF_INET)
37 return in4_addr_is_null(&u->in);
38
39 if (family == AF_INET6)
40 return in6_addr_is_null(&u->in6);
41
42 return -EAFNOSUPPORT;
43 }
44
45 bool in4_addr_is_link_local(const struct in_addr *a) {
46 assert(a);
47
48 return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
49 }
50
51 bool in6_addr_is_link_local(const struct in6_addr *a) {
52 assert(a);
53
54 return IN6_IS_ADDR_LINKLOCAL(a); /* lgtm [cpp/potentially-dangerous-function] */
55 }
56
57 int in_addr_is_link_local(int family, const union in_addr_union *u) {
58 assert(u);
59
60 if (family == AF_INET)
61 return in4_addr_is_link_local(&u->in);
62
63 if (family == AF_INET6)
64 return in6_addr_is_link_local(&u->in6);
65
66 return -EAFNOSUPPORT;
67 }
68
69 bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
70 assert(a);
71
72 /* ff02::1 */
73 return be32toh(a->s6_addr32[0]) == UINT32_C(0xff020000) &&
74 a->s6_addr32[1] == 0 &&
75 a->s6_addr32[2] == 0 &&
76 be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
77 }
78
79 int in_addr_is_multicast(int family, const union in_addr_union *u) {
80 assert(u);
81
82 if (family == AF_INET)
83 return IN_MULTICAST(be32toh(u->in.s_addr));
84
85 if (family == AF_INET6)
86 return IN6_IS_ADDR_MULTICAST(&u->in6);
87
88 return -EAFNOSUPPORT;
89 }
90
91 bool in4_addr_is_local_multicast(const struct in_addr *a) {
92 assert(a);
93
94 return (be32toh(a->s_addr) & UINT32_C(0xffffff00)) == UINT32_C(0xe0000000);
95 }
96
97 bool in4_addr_is_localhost(const struct in_addr *a) {
98 assert(a);
99
100 /* All of 127.x.x.x is localhost. */
101 return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
102 }
103
104 bool in4_addr_is_non_local(const struct in_addr *a) {
105 /* Whether the address is not null and not localhost.
106 *
107 * As such, it is suitable to configure as DNS/NTP server from DHCP. */
108 return !in4_addr_is_null(a) &&
109 !in4_addr_is_localhost(a);
110 }
111
112 int in_addr_is_localhost(int family, const union in_addr_union *u) {
113 assert(u);
114
115 if (family == AF_INET)
116 return in4_addr_is_localhost(&u->in);
117
118 if (family == AF_INET6)
119 return IN6_IS_ADDR_LOOPBACK(&u->in6); /* lgtm [cpp/potentially-dangerous-function] */
120
121 return -EAFNOSUPPORT;
122 }
123
124 bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
125 return a->s6_addr32[0] == 0 &&
126 a->s6_addr32[1] == 0 &&
127 a->s6_addr32[2] == htobe32(UINT32_C(0x0000ffff));
128 }
129
130 bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
131 assert(a);
132 assert(b);
133
134 return a->s_addr == b->s_addr;
135 }
136
137 bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b) {
138 assert(a);
139 assert(b);
140
141 return IN6_ARE_ADDR_EQUAL(a, b);
142 }
143
144 int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
145 assert(a);
146 assert(b);
147
148 if (family == AF_INET)
149 return in4_addr_equal(&a->in, &b->in);
150
151 if (family == AF_INET6)
152 return in6_addr_equal(&a->in6, &b->in6);
153
154 return -EAFNOSUPPORT;
155 }
156
157 int in_addr_prefix_intersect(
158 int family,
159 const union in_addr_union *a,
160 unsigned aprefixlen,
161 const union in_addr_union *b,
162 unsigned bprefixlen) {
163
164 unsigned m;
165
166 assert(a);
167 assert(b);
168
169 /* Checks whether there are any addresses that are in both
170 * networks */
171
172 m = MIN(aprefixlen, bprefixlen);
173
174 if (family == AF_INET) {
175 uint32_t x, nm;
176
177 x = be32toh(a->in.s_addr ^ b->in.s_addr);
178 nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
179
180 return (x & nm) == 0;
181 }
182
183 if (family == AF_INET6) {
184 unsigned i;
185
186 if (m > 128)
187 m = 128;
188
189 for (i = 0; i < 16; i++) {
190 uint8_t x, nm;
191
192 x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
193
194 if (m < 8)
195 nm = 0xFF << (8 - m);
196 else
197 nm = 0xFF;
198
199 if ((x & nm) != 0)
200 return 0;
201
202 if (m > 8)
203 m -= 8;
204 else
205 m = 0;
206 }
207
208 return 1;
209 }
210
211 return -EAFNOSUPPORT;
212 }
213
214 int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
215 assert(u);
216
217 /* Increases the network part of an address by one. Returns 0 if that succeeds, or -ERANGE if
218 * this overflows. */
219
220 return in_addr_prefix_nth(family, u, prefixlen, 1);
221 }
222
223 /*
224 * Calculates the nth prefix of size prefixlen starting from the address denoted by u.
225 *
226 * On success 0 will be returned and the calculated prefix will be available in
227 * u. In case the calculation cannot be performed (invalid prefix length,
228 * overflows would occur) -ERANGE is returned. If the address family given isn't
229 * supported -EAFNOSUPPORT will be returned.
230 *
231 * Examples:
232 * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 0, writes 192.168.2.0 to u
233 * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 0, no data written
234 * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 24, 1), returns -ERANGE, no data written
235 * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 0, 1), returns -ERANGE, no data written
236 * - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 0, writes 2001:0db8:0000:ff00:: to u
237 */
238 int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth) {
239 assert(u);
240
241 if (prefixlen <= 0)
242 return -ERANGE;
243
244 if (family == AF_INET) {
245 uint32_t c, n, t;
246
247 if (prefixlen > 32)
248 return -ERANGE;
249
250 c = be32toh(u->in.s_addr);
251
252 t = nth << (32 - prefixlen);
253
254 /* Check for wrap */
255 if (c > UINT32_MAX - t)
256 return -ERANGE;
257
258 n = c + t;
259
260 n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen);
261 u->in.s_addr = htobe32(n);
262 return 0;
263 }
264
265 if (family == AF_INET6) {
266 bool overflow = false;
267
268 if (prefixlen > 128)
269 return -ERANGE;
270
271 for (unsigned i = 16; i > 0; i--) {
272 unsigned t, j = i - 1, p = j * 8;
273
274 if (p >= prefixlen) {
275 u->in6.s6_addr[j] = 0;
276 continue;
277 }
278
279 if (prefixlen - p < 8) {
280 u->in6.s6_addr[j] &= 0xff << (8 - (prefixlen - p));
281 t = u->in6.s6_addr[j] + ((nth & 0xff) << (8 - (prefixlen - p)));
282 nth >>= prefixlen - p;
283 } else {
284 t = u->in6.s6_addr[j] + (nth & 0xff) + overflow;
285 nth >>= 8;
286 }
287
288 overflow = t > UINT8_MAX;
289 u->in6.s6_addr[j] = (uint8_t) (t & 0xff);
290 }
291
292 if (overflow || nth != 0)
293 return -ERANGE;
294
295 return 0;
296 }
297
298 return -EAFNOSUPPORT;
299 }
300
301 int in_addr_random_prefix(
302 int family,
303 union in_addr_union *u,
304 unsigned prefixlen_fixed_part,
305 unsigned prefixlen) {
306
307 assert(u);
308
309 /* Random network part of an address by one. */
310
311 if (prefixlen <= 0)
312 return 0;
313
314 if (family == AF_INET) {
315 uint32_t c, n;
316
317 if (prefixlen_fixed_part > 32)
318 prefixlen_fixed_part = 32;
319 if (prefixlen > 32)
320 prefixlen = 32;
321 if (prefixlen_fixed_part >= prefixlen)
322 return -EINVAL;
323
324 c = be32toh(u->in.s_addr);
325 c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
326
327 random_bytes(&n, sizeof(n));
328 n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
329
330 u->in.s_addr = htobe32(n | c);
331 return 1;
332 }
333
334 if (family == AF_INET6) {
335 struct in6_addr n;
336 unsigned i, j;
337
338 if (prefixlen_fixed_part > 128)
339 prefixlen_fixed_part = 128;
340 if (prefixlen > 128)
341 prefixlen = 128;
342 if (prefixlen_fixed_part >= prefixlen)
343 return -EINVAL;
344
345 random_bytes(&n, sizeof(n));
346
347 for (i = 0; i < 16; i++) {
348 uint8_t mask_fixed_part = 0, mask = 0;
349
350 if (i < (prefixlen_fixed_part + 7) / 8) {
351 if (i < prefixlen_fixed_part / 8)
352 mask_fixed_part = 0xffu;
353 else {
354 j = prefixlen_fixed_part % 8;
355 mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
356 }
357 }
358
359 if (i < (prefixlen + 7) / 8) {
360 if (i < prefixlen / 8)
361 mask = 0xffu ^ mask_fixed_part;
362 else {
363 j = prefixlen % 8;
364 mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
365 }
366 }
367
368 u->in6.s6_addr[i] &= mask_fixed_part;
369 u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
370 }
371
372 return 1;
373 }
374
375 return -EAFNOSUPPORT;
376 }
377
378 int in_addr_prefix_range(
379 int family,
380 const union in_addr_union *in,
381 unsigned prefixlen,
382 union in_addr_union *ret_start,
383 union in_addr_union *ret_end) {
384
385 union in_addr_union start, end;
386 int r;
387
388 assert(in);
389
390 if (!IN_SET(family, AF_INET, AF_INET6))
391 return -EAFNOSUPPORT;
392
393 if (ret_start) {
394 start = *in;
395 r = in_addr_prefix_nth(family, &start, prefixlen, 0);
396 if (r < 0)
397 return r;
398 }
399
400 if (ret_end) {
401 end = *in;
402 r = in_addr_prefix_nth(family, &end, prefixlen, 1);
403 if (r < 0)
404 return r;
405 }
406
407 if (ret_start)
408 *ret_start = start;
409 if (ret_end)
410 *ret_end = end;
411
412 return 0;
413 }
414
415 int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
416 _cleanup_free_ char *x = NULL;
417 size_t l;
418
419 assert(u);
420 assert(ret);
421
422 if (family == AF_INET)
423 l = INET_ADDRSTRLEN;
424 else if (family == AF_INET6)
425 l = INET6_ADDRSTRLEN;
426 else
427 return -EAFNOSUPPORT;
428
429 x = new(char, l);
430 if (!x)
431 return -ENOMEM;
432
433 errno = 0;
434 if (!inet_ntop(family, u, x, l))
435 return errno_or_else(EINVAL);
436
437 *ret = TAKE_PTR(x);
438 return 0;
439 }
440
441 int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
442 _cleanup_free_ char *x = NULL;
443 char *p;
444 size_t l;
445
446 assert(u);
447 assert(ret);
448
449 if (family == AF_INET)
450 l = INET_ADDRSTRLEN + 3;
451 else if (family == AF_INET6)
452 l = INET6_ADDRSTRLEN + 4;
453 else
454 return -EAFNOSUPPORT;
455
456 if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
457 return -EINVAL;
458
459 x = new(char, l);
460 if (!x)
461 return -ENOMEM;
462
463 errno = 0;
464 if (!inet_ntop(family, u, x, l))
465 return errno_or_else(EINVAL);
466
467 p = x + strlen(x);
468 l -= strlen(x);
469 (void) strpcpyf(&p, l, "/%u", prefixlen);
470
471 *ret = TAKE_PTR(x);
472 return 0;
473 }
474
475 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) {
476 _cleanup_free_ char *ip_str = NULL, *x = NULL;
477 int r;
478
479 assert(IN_SET(family, AF_INET, AF_INET6));
480 assert(u);
481 assert(ret);
482
483 /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
484 * handle IPv6 link-local addresses. */
485
486 r = in_addr_to_string(family, u, &ip_str);
487 if (r < 0)
488 return r;
489
490 if (family == AF_INET6) {
491 r = in_addr_is_link_local(family, u);
492 if (r < 0)
493 return r;
494 if (r == 0)
495 ifindex = 0;
496 } else
497 ifindex = 0; /* For IPv4 address, ifindex is always ignored. */
498
499 if (port == 0 && ifindex == 0 && isempty(server_name)) {
500 *ret = TAKE_PTR(ip_str);
501 return 0;
502 }
503
504 const char *separator = isempty(server_name) ? "" : "#";
505 server_name = strempty(server_name);
506
507 if (port > 0) {
508 if (family == AF_INET6) {
509 if (ifindex > 0)
510 r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
511 else
512 r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
513 } else
514 r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
515 } else {
516 if (ifindex > 0)
517 r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name);
518 else {
519 x = strjoin(ip_str, separator, server_name);
520 r = x ? 0 : -ENOMEM;
521 }
522 }
523 if (r < 0)
524 return -ENOMEM;
525
526 *ret = TAKE_PTR(x);
527 return 0;
528 }
529
530 int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
531 union in_addr_union buffer;
532 assert(s);
533
534 if (!IN_SET(family, AF_INET, AF_INET6))
535 return -EAFNOSUPPORT;
536
537 errno = 0;
538 if (inet_pton(family, s, ret ?: &buffer) <= 0)
539 return errno_or_else(EINVAL);
540
541 return 0;
542 }
543
544 int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
545 int r;
546
547 assert(s);
548
549 r = in_addr_from_string(AF_INET, s, ret);
550 if (r >= 0) {
551 if (ret_family)
552 *ret_family = AF_INET;
553 return 0;
554 }
555
556 r = in_addr_from_string(AF_INET6, s, ret);
557 if (r >= 0) {
558 if (ret_family)
559 *ret_family = AF_INET6;
560 return 0;
561 }
562
563 return -EINVAL;
564 }
565
566 unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
567 assert(addr);
568
569 return 32U - u32ctz(be32toh(addr->s_addr));
570 }
571
572 struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
573 assert(addr);
574 assert(prefixlen <= 32);
575
576 /* Shifting beyond 32 is not defined, handle this specially. */
577 if (prefixlen == 0)
578 addr->s_addr = 0;
579 else
580 addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
581
582 return addr;
583 }
584
585 int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
586 uint8_t msb_octet = *(uint8_t*) addr;
587
588 /* addr may not be aligned, so make sure we only access it byte-wise */
589
590 assert(addr);
591 assert(prefixlen);
592
593 if (msb_octet < 128)
594 /* class A, leading bits: 0 */
595 *prefixlen = 8;
596 else if (msb_octet < 192)
597 /* class B, leading bits 10 */
598 *prefixlen = 16;
599 else if (msb_octet < 224)
600 /* class C, leading bits 110 */
601 *prefixlen = 24;
602 else
603 /* class D or E, no default prefixlen */
604 return -ERANGE;
605
606 return 0;
607 }
608
609 int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
610 unsigned char prefixlen;
611 int r;
612
613 assert(addr);
614 assert(mask);
615
616 r = in4_addr_default_prefixlen(addr, &prefixlen);
617 if (r < 0)
618 return r;
619
620 in4_addr_prefixlen_to_netmask(mask, prefixlen);
621 return 0;
622 }
623
624 int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
625 assert(addr);
626
627 if (family == AF_INET) {
628 struct in_addr mask;
629
630 if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
631 return -EINVAL;
632
633 addr->in.s_addr &= mask.s_addr;
634 return 0;
635 }
636
637 if (family == AF_INET6) {
638 unsigned i;
639
640 for (i = 0; i < 16; i++) {
641 uint8_t mask;
642
643 if (prefixlen >= 8) {
644 mask = 0xFF;
645 prefixlen -= 8;
646 } else {
647 mask = 0xFF << (8 - prefixlen);
648 prefixlen = 0;
649 }
650
651 addr->in6.s6_addr[i] &= mask;
652 }
653
654 return 0;
655 }
656
657 return -EAFNOSUPPORT;
658 }
659
660 int in_addr_prefix_covers(int family,
661 const union in_addr_union *prefix,
662 unsigned char prefixlen,
663 const union in_addr_union *address) {
664
665 union in_addr_union masked_prefix, masked_address;
666 int r;
667
668 assert(prefix);
669 assert(address);
670
671 masked_prefix = *prefix;
672 r = in_addr_mask(family, &masked_prefix, prefixlen);
673 if (r < 0)
674 return r;
675
676 masked_address = *address;
677 r = in_addr_mask(family, &masked_address, prefixlen);
678 if (r < 0)
679 return r;
680
681 return in_addr_equal(family, &masked_prefix, &masked_address);
682 }
683
684 int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
685 uint8_t u;
686 int r;
687
688 if (!IN_SET(family, AF_INET, AF_INET6))
689 return -EAFNOSUPPORT;
690
691 r = safe_atou8(p, &u);
692 if (r < 0)
693 return r;
694
695 if (u > FAMILY_ADDRESS_SIZE(family) * 8)
696 return -ERANGE;
697
698 *ret = u;
699 return 0;
700 }
701
702 int in_addr_prefix_from_string(
703 const char *p,
704 int family,
705 union in_addr_union *ret_prefix,
706 unsigned char *ret_prefixlen) {
707
708 _cleanup_free_ char *str = NULL;
709 union in_addr_union buffer;
710 const char *e, *l;
711 unsigned char k;
712 int r;
713
714 assert(p);
715
716 if (!IN_SET(family, AF_INET, AF_INET6))
717 return -EAFNOSUPPORT;
718
719 e = strchr(p, '/');
720 if (e) {
721 str = strndup(p, e - p);
722 if (!str)
723 return -ENOMEM;
724
725 l = str;
726 } else
727 l = p;
728
729 r = in_addr_from_string(family, l, &buffer);
730 if (r < 0)
731 return r;
732
733 if (e) {
734 r = in_addr_parse_prefixlen(family, e+1, &k);
735 if (r < 0)
736 return r;
737 } else
738 k = FAMILY_ADDRESS_SIZE(family) * 8;
739
740 if (ret_prefix)
741 *ret_prefix = buffer;
742 if (ret_prefixlen)
743 *ret_prefixlen = k;
744
745 return 0;
746 }
747
748 int in_addr_prefix_from_string_auto_internal(
749 const char *p,
750 InAddrPrefixLenMode mode,
751 int *ret_family,
752 union in_addr_union *ret_prefix,
753 unsigned char *ret_prefixlen) {
754
755 _cleanup_free_ char *str = NULL;
756 union in_addr_union buffer;
757 const char *e, *l;
758 unsigned char k;
759 int family, r;
760
761 assert(p);
762
763 e = strchr(p, '/');
764 if (e) {
765 str = strndup(p, e - p);
766 if (!str)
767 return -ENOMEM;
768
769 l = str;
770 } else
771 l = p;
772
773 r = in_addr_from_string_auto(l, &family, &buffer);
774 if (r < 0)
775 return r;
776
777 if (e) {
778 r = in_addr_parse_prefixlen(family, e+1, &k);
779 if (r < 0)
780 return r;
781 } else
782 switch (mode) {
783 case PREFIXLEN_FULL:
784 k = FAMILY_ADDRESS_SIZE(family) * 8;
785 break;
786 case PREFIXLEN_REFUSE:
787 return -ENOANO; /* To distinguish this error from others. */
788 case PREFIXLEN_LEGACY:
789 if (family == AF_INET) {
790 r = in4_addr_default_prefixlen(&buffer.in, &k);
791 if (r < 0)
792 return r;
793 } else
794 k = 0;
795 break;
796 default:
797 assert_not_reached("Invalid prefixlen mode");
798 }
799
800 if (ret_family)
801 *ret_family = family;
802 if (ret_prefix)
803 *ret_prefix = buffer;
804 if (ret_prefixlen)
805 *ret_prefixlen = k;
806
807 return 0;
808
809 }
810
811 static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
812 assert(a);
813 assert(state);
814
815 siphash24_compress(&a->family, sizeof(a->family), state);
816 siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
817 }
818
819 static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
820 int r;
821
822 assert(x);
823 assert(y);
824
825 r = CMP(x->family, y->family);
826 if (r != 0)
827 return r;
828
829 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
830 }
831
832 DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
833
834 static void in_addr_prefix_hash_func(const struct in_addr_prefix *a, struct siphash *state) {
835 assert(a);
836 assert(state);
837
838 siphash24_compress(&a->family, sizeof(a->family), state);
839 siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
840 siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
841 }
842
843 static int in_addr_prefix_compare_func(const struct in_addr_prefix *x, const struct in_addr_prefix *y) {
844 int r;
845
846 assert(x);
847 assert(y);
848
849 r = CMP(x->family, y->family);
850 if (r != 0)
851 return r;
852
853 r = CMP(x->prefixlen, y->prefixlen);
854 if (r != 0)
855 return r;
856
857 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
858 }
859
860 DEFINE_HASH_OPS(in_addr_prefix_hash_ops, struct in_addr_prefix, in_addr_prefix_hash_func, in_addr_prefix_compare_func);
861 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(in_addr_prefix_hash_ops_free, struct in_addr_prefix, in_addr_prefix_hash_func, in_addr_prefix_compare_func, free);
862
863 void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
864 assert(addr);
865 assert(state);
866
867 siphash24_compress(addr, sizeof(*addr), state);
868 }
869
870 int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
871 assert(a);
872 assert(b);
873
874 return memcmp(a, b, sizeof(*a));
875 }
876
877 DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);