The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
inet.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2 of the
4 * License as published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14 */
15
16/** Functions for parsing, printing, masking and retrieving IP addresses
17 *
18 * @file src/lib/util/inet.c
19 *
20 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
21 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22 */
23#include <freeradius-devel/util/inet.h>
24#include <freeradius-devel/util/misc.h>
25#include <freeradius-devel/util/strerror.h>
26#include <freeradius-devel/util/syserror.h>
27#include <freeradius-devel/util/value.h>
28
29#include <stdlib.h>
30#include <ifaddrs.h>
31#include <net/if_arp.h>
32#include <sys/un.h>
33
34/*
35 * Linux
36 */
37#if defined(HAVE_LINUX_IF_PACKET_H)
38# include <linux/if_packet.h>
39# include <linux/if_ether.h>
40/*
41 * Apple, *BSD
42 */
43#elif defined(HAVE_NET_IF_DL_H)
44# include <net/if_dl.h> /* Needed for struct sockaddr_ll def */
45/*
46 * emscripten/musl
47 */
48#elif defined(HAVE_NETPACKET_PACKET_H)
49# include <netpacket/packet.h> /* Needed for struct sockaddr_ll def */
50#endif
51
52bool fr_reverse_lookups = false; //!< IP -> hostname lookups?
53bool fr_hostname_lookups = true; //!< hostname -> IP lookups?
54
55/** Determine if an address is the INADDR_ANY address for its address family
56 *
57 * @param ipaddr to check.
58 * @return
59 * - 0 if it's not.
60 * - 1 if it is.
61 * - -1 on error.
62 */
64{
65
66 if (ipaddr->af == AF_INET) {
67 if (ipaddr->addr.v4.s_addr == htonl(INADDR_ANY)) {
68 return 1;
69 }
70
71#ifdef HAVE_STRUCT_SOCKADDR_IN6
72 } else if (ipaddr->af == AF_INET6) {
73 /* Unconst for emscripten/musl */
74 if (IN6_IS_ADDR_UNSPECIFIED(UNCONST(struct in6_addr *, &(ipaddr->addr.v6)))) {
75 return 1;
76 }
77#endif
78
79 } else {
80 fr_strerror_const("Unknown address family");
81 return -1;
82 }
83
84 return 0;
85}
86
87/** Determine if an address is a multicast address
88 *
89 * @param ipaddr to check.
90 * @return
91 * - 0 if it's not.
92 * - 1 if it is.
93 * - -1 on error.
94 */
96{
97 if (ipaddr->af == AF_INET) {
98 /*
99 * 224.0.0.0 (3758096384) - 239.255.255.255 (4026531839)
100 */
101 if ((ipaddr->addr.v4.s_addr >= 3758096384) && (ipaddr->addr.v4.s_addr <= 4026531839)) return 1;
102#ifdef HAVE_STRUCT_SOCKADDR_IN6
103 } else if (ipaddr->af == AF_INET6) {
104 /* Unconst for emscripten/musl */
105 if (IN6_IS_ADDR_MULTICAST(UNCONST(struct in6_addr *, &(ipaddr->addr.v6)))) {
106 return 1;
107 }
108#endif
109
110 } else {
111 fr_strerror_const("Unknown address family");
112 return -1;
113 }
114
115 return 0;
116}
117
118/** Determine if an address is a prefix
119 *
120 * @param ipaddr to check.
121 * @return
122 * - 0 if it's not.
123 * - 1 if it is.
124 * - -1 on error.
125 */
127{
128 switch (ipaddr->af) {
129 case AF_INET:
130 return (ipaddr->prefix < 32);
131
132 case AF_INET6:
133 return (ipaddr->prefix < 128);
134
135 default:
136 fr_strerror_const("Unknown address family");
137 return -1;
138 }
139}
140
141/** Mask off a portion of an IPv4 address
142 *
143 * @param ipaddr to mask.
144 * @param prefix Number of contiguous bits to mask.
145 * @return an ipv4 address with the host portion zeroed out.
146 */
147static struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
148{
149 uint32_t ret;
150
151 if (prefix > 32) prefix = 32;
152
153 /* Short circuit */
154 if (prefix == 32) return *ipaddr;
155
156 if (prefix == 0) ret = 0;
157 else ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
158
159 return (*(struct in_addr *)&ret);
160}
161
162/** Mask off a portion of an IPv6 address
163 *
164 * @param ipaddr to mask.
165 * @param prefix Number of contiguous bits to mask.
166 * @return an ipv6 address with the host portion zeroed out.
167 */
168static struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
169{
170 uint64_t addr; /* Needed for alignment */
171 uint64_t ret[2], *o = ret;
172 uint8_t i = 0;
173
174 if (prefix > 128) prefix = 128;
175
176 /* Short circuit */
177 if (prefix == 128) return *ipaddr;
178
179 if (prefix >= 64) {
180 prefix -= 64;
181 addr = (uint64_t)ipaddr->s6_addr[i] |
182 ((uint64_t)ipaddr->s6_addr[i + 1] << 8) |
183 ((uint64_t)ipaddr->s6_addr[i + 2] << 16) |
184 ((uint64_t)ipaddr->s6_addr[i + 3] << 24) |
185 ((uint64_t)ipaddr->s6_addr[i + 4] << 32) |
186 ((uint64_t)ipaddr->s6_addr[i + 5] << 40) |
187 ((uint64_t)ipaddr->s6_addr[i + 6] << 48) |
188 ((uint64_t)ipaddr->s6_addr[i + 7] << 56);
189 *o++ = 0xffffffffffffffffULL & addr; /* lhs portion masked */
190 i += 8;
191 } else {
192 ret[1] = 0; /* rhs portion zeroed */
193 }
194
195 /* Max left shift is 63 else we get overflow */
196 if (prefix > 0) {
197 addr = (uint64_t)ipaddr->s6_addr[i] |
198 ((uint64_t)ipaddr->s6_addr[i + 1] << 8) |
199 ((uint64_t)ipaddr->s6_addr[i + 2] << 16) |
200 ((uint64_t)ipaddr->s6_addr[i + 3] << 24) |
201 ((uint64_t)ipaddr->s6_addr[i + 4] << 32) |
202 ((uint64_t)ipaddr->s6_addr[i + 5] << 40) |
203 ((uint64_t)ipaddr->s6_addr[i + 6] << 48) |
204 ((uint64_t)ipaddr->s6_addr[i + 7] << 56);
205 *o = htonll(~((uint64_t)(0x0000000000000001ULL << (64 - prefix)) - 1)) & addr;
206 } else {
207 *o = 0;
208 }
209
210 return *(struct in6_addr *) &ret;
211}
212
213/** Zeroes out the host portion of an fr_ipaddr_t
214 *
215 * @param[in,out] addr to mask
216 * @param[in] prefix Length of the network portion.
217 */
219{
220
221 switch (addr->af) {
222 case AF_INET:
223 addr->addr.v4 = fr_inaddr_mask(&addr->addr.v4, prefix);
224 break;
225
226 case AF_INET6:
227 addr->addr.v6 = fr_in6addr_mask(&addr->addr.v6, prefix);
228 break;
229
230 default:
231 return;
232 }
233 addr->prefix = prefix;
234}
235
236/** Wrappers for IPv4/IPv6 host to IP address lookup
237 *
238 * This function returns only one IP address, of the specified address family,
239 * or the first address (of whatever family), if AF_UNSPEC is used.
240 *
241 * If fallback is specified and af is AF_INET, but not AF_INET records were
242 * found and a record for AF_INET6 exists that record will be returned.
243 *
244 * If fallback is specified and af is AF_INET6, and a record with AF_INET4 exists
245 * that record will be returned inserted.
246 *
247 * @param[out] out Where to write result.
248 * @param[in] af To search for in preference.
249 * @param[in] hostname to search for.
250 * @param[in] fallback to the other address family, if no records matching af, found.
251 * @return
252 * - 0 on success.
253 * - -1 on failure.
254 */
255int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
256{
257 int ret;
258 struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
259
260 /*
261 * Avoid alloc for IP addresses. This helps us debug
262 * memory errors when using talloc.
263 */
264 if (!fr_hostname_lookups) {
265#ifdef HAVE_STRUCT_SOCKADDR_IN6
266 if (af == AF_UNSPEC) {
267 char const *p;
268
269 for (p = hostname; *p != '\0'; p++) {
270 if ((*p == ':') ||
271 (*p == '[') ||
272 (*p == ']')) {
273 af = AF_INET6;
274 break;
275 }
276 }
277 }
278#endif
279
280 if (af == AF_UNSPEC) af = AF_INET;
281
282 if (inet_pton(af, hostname, &(out->addr)) == 0) {
283 fr_strerror_printf("\"%s\" is not a valid IP address and "
284 "hostname lookups are disabled", hostname);
285 return -1;
286 }
287 out->af = af;
288 out->prefix = 32;
289 out->scope_id = 0;
290
291 return 0;
292 }
293
294 memset(&hints, 0, sizeof(hints));
295
296 /*
297 * If we're falling back we need both IPv4 and IPv6 records
298 */
299 if (fallback) {
300 hints.ai_family = AF_UNSPEC;
301 } else {
302 hints.ai_family = af;
303 }
304
305 if ((ret = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
306 switch (af) {
307 default:
308 case AF_UNSPEC:
309 fr_strerror_printf("Failed resolving \"%s\" to IP address: %s",
310 hostname, gai_strerror(ret));
311 return -1;
312
313 case AF_INET:
314 fr_strerror_printf("Failed resolving \"%s\" to IPv4 address: %s",
315 hostname, gai_strerror(ret));
316 return -1;
317
318 case AF_INET6:
319 fr_strerror_printf("Failed resolving \"%s\" to IPv6 address: %s",
320 hostname, gai_strerror(ret));
321 return -1;
322 }
323 }
324
325 for (ai = res; ai; ai = ai->ai_next) {
326 if ((af == ai->ai_family) || (af == AF_UNSPEC)) break;
327 if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
328 }
329
330 if (!ai) ai = alt;
331 if (!ai) {
332 fr_strerror_printf("Failed resolving \"%s\": No records matching requested address family returned",
333 hostname);
334 freeaddrinfo(res);
335 return -1;
336 }
337
338 ret = fr_ipaddr_from_sockaddr(out, NULL, (struct sockaddr_storage *)ai->ai_addr, ai->ai_addrlen);
339 freeaddrinfo(res);
340 if (ret < 0) {
341 fr_strerror_const("Failed converting sockaddr to ipaddr");
342 return -1;
343 }
344
345 return 0;
346}
347
348/** Perform reverse resolution of an IP address
349 *
350 * Attempt to resolve an IP address to a DNS record (if dns lookups are enabled).
351 *
352 * @param[in] src address to resolve.
353 * @param[out] out Where to write the resulting hostname.
354 * @param[in] outlen length of the output buffer.
355 */
356char const *fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
357{
358 struct sockaddr_storage ss;
359 int error;
360 socklen_t salen;
361
362 /*
363 * No DNS lookups
364 */
365 if (!fr_reverse_lookups) {
366 return inet_ntop(src->af, &(src->addr), out, outlen);
367 }
368
369 if (fr_ipaddr_to_sockaddr(&ss, &salen, src, 0) < 0) return NULL;
370
371 if ((error = getnameinfo((struct sockaddr *)&ss, salen, out, outlen, NULL, 0,
372 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
373 fr_strerror_printf("fr_inet_ntoh: %s", gai_strerror(error));
374 return NULL;
375 }
376 return out;
377}
378
379
380/** Parse a single octet of an IPv4 address string
381 *
382 * @param[out] out Where to write integer.
383 * @param[in] str to parse.
384 * @return
385 * - >= 0 on success (number of bytes parsed of in).
386 * - < 0 on error.
387 */
388static int ip_octet_from_str(uint32_t *out, char const *str)
389{
390 uint32_t octet;
391 char const *p = str;
392
393 if ((*p < '0') || (*p > '9')) return -1;
394
395 octet = 0;
396
397 while ((*p >= '0') && (*p <= '9')) {
398 octet *= 10;
399 octet += *p - '0';
400 p++;
401
402 if (octet > 255) return -1;
403 }
404
405 *out = octet;
406 return p - str;
407}
408
409/** Parses the network portion of an IPv4 prefix into an in_addr
410 *
411 * @note output is in network order.
412 *
413 * Parses address strings in dotted quad notation.
414 * Unlike inet_pton allows octets to be omitted, in which case their value is considered to be 0.
415 * Unlike inet_aton treats integers as representing the highest octet of an IPv4 address, and
416 * limits them to 255.
417 *
418 * Examples of acceptable strings:
419 * - 192.168.0.0
420 * - 192.168.0.0/24
421 * - 192.168/16
422 * - 192
423 * - 192/8
424 *
425 * @param[out] out Where to write parsed address.
426 * @param[in] str to parse.
427 * @return
428 * - >= 0 on success (number of bytes parsed of in).
429 * - < 0 on error.
430 */
431static int ip_prefix_addr_from_str(struct in_addr *out, char const *str)
432{
433 int shift, length;
434 uint32_t octet;
435 uint32_t addr;
436 char const *p = str;
437
438 addr = 0;
439 out->s_addr = 0;
440
441 for (shift = 24; shift >= 0; shift -= 8) {
442 length = ip_octet_from_str(&octet, p);
443 if (length <= 0) return -1;
444
445 addr |= octet << shift;
446 p += length;
447
448 /*
449 * EOS or / means we're done.
450 */
451 if (!*p || (*p == '/')) break;
452
453 /*
454 * We require dots between octets.
455 */
456 if (*p != '.') return -1;
457 p++;
458 }
459
460 out->s_addr = htonl(addr);
461 return p - str;
462}
463
464/** Parse an IPv4 address or IPv4 prefix in presentation format (and others)
465 *
466 * @param[out] out Where to write the ip address value.
467 * @param[in] value to parse, may be:
468 * - dotted quad [+ prefix]
469 * - integer
470 * - octal number
471 * - '*' (INADDR_ANY)
472 * - FQDN if resolve is true.
473 * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
474 * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
475 * @param[in] fallback to IPv6 resolution if no A records can be found.
476 * @param[in] mask_bits If true, set address bits to zero.
477 * @return
478 * - 0 if ip address was parsed successfully.
479 * - -1 on failure.
480 */
481int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask_bits)
482{
483 char *p;
484 unsigned int mask;
485 char const *end;
486 char *eptr;
487 char buffer[256]; /* As per RFC1035 */
488 int ret;
489
490 /*
491 * Zero out output so we don't have invalid fields
492 * like scope_id hanging around with garbage values.
493 */
494 memset(out, 0, sizeof(*out));
495
496 end = value + inlen;
497 while ((value < end) && isspace((uint8_t) *value)) value++;
498 if (value == end) {
499 fr_strerror_const("Empty IPv4 address string is invalid");
500 return -1;
501 }
502 inlen = end - value;
503
504 /*
505 * Copy to intermediary buffer if we were given a length
506 */
507 if (inlen >= 0) {
508 if (inlen >= (ssize_t)sizeof(buffer)) {
509 fr_strerror_printf("Invalid IPv4 address string \"%pV\"", fr_box_strvalue_len(value, inlen));
510 return -1;
511 }
512 memcpy(buffer, value, inlen);
513 buffer[inlen] = '\0';
514 value = buffer;
515 }
516
517 p = strchr(value, '/');
518
519 /*
520 * 192.0.2.2 is parsed as if it was /32
521 */
522 if (!p) {
523 out->prefix = 32;
524 out->af = AF_INET;
525
526 /*
527 * Allow '*' as the wildcard address usually 0.0.0.0
528 */
529 if ((value[0] == '*') && (value[1] == '\0')) {
530 out->addr.v4.s_addr = htonl(INADDR_ANY);
531
532 /*
533 * Convert things which are obviously integers to IP addresses
534 *
535 * We assume the number is the bigendian representation of the
536 * IP address.
537 */
538 } else if (is_integer(value) || ((value[0] == '0') && (value[1] == 'x'))) {
539 out->addr.v4.s_addr = htonl(strtoul(value, NULL, 0));
540
541 } else if (!resolve) {
542 unsigned int a, b, c, d;
543 int num;
544 char rest;
545
546 a = b = c = d = 0;
547
548 num = sscanf(value, "%u.%u.%u.%u%c", &a, &b, &c, &d, &rest);
549 if ((num == 0) || (num == 5) ||
550 (a > 255) || (b > 255) || (c > 255) || (d > 255)) {
551 fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value);
552 return -1;
553 }
554
555 out->addr.v4.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
556
557 } else if (fr_inet_hton(out, AF_INET, value, fallback) < 0) return -1;
558
559 return 0;
560 }
561
562 /*
563 * Otherwise parse the prefix
564 */
565 if ((size_t)(p - value) >= INET_ADDRSTRLEN) {
566 fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
567 return -1;
568 }
569
570 /*
571 * Copy the IP portion into a temporary buffer if we haven't already.
572 */
573 if (inlen < 0) memcpy(buffer, value, p - value);
574
575 /*
576 * We need a special function here, as inet_pton doesn't like
577 * address strings with octets omitted, and inet_aton treats
578 * 127 as an integer value, and sets the lowest octet of the
579 * prefix to 127 instead of the highest.
580 *
581 * @todo we should allow hostnames to be parsed as prefixes.
582 */
583 buffer[p - value] = '\0';
584 ret = ip_prefix_addr_from_str(&out->addr.v4, buffer);
585 buffer[p - value] = '/'; /* Set back to '/' to produce proper errors */
586
587 if (ret <= 0) {
588 fr_strerror_printf("Failed to parse IPv4 prefix string \"%s\"", value);
589 return -1;
590 }
591
592 mask = strtoul(p + 1, &eptr, 10);
593 if (mask > 32) {
594 fr_strerror_printf("Invalid IPv4 mask length \"%s\". Should be between 0-32", p);
595 return -1;
596 }
597
598 if (eptr[0] != '\0') {
599 fr_strerror_printf("Failed to parse IPv4 prefix string \"%s\", "
600 "got garbage after mask length \"%s\"", value, eptr);
601 return -1;
602 }
603
604 if (mask_bits && (mask < 32)) {
605 out->addr.v4 = fr_inaddr_mask(&out->addr.v4, mask);
606 }
607
608 out->prefix = (uint8_t) mask;
609 out->af = AF_INET;
610
611 return 0;
612}
613
614/** Parse an IPv6 address or IPv6 prefix in presentation format (and others)
615 *
616 * @param[out] out Where to write the ip address value.
617 * @param[in] value to parse, may be:
618 * - IPv6 hexits [+ prefix].
619 * - '*' wildcard.
620 * - FQDN if resolve is true.
621 * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
622 * @param[in] resolve If true and value doesn't look like an IP address,
623 * try and resolve value as a hostname.
624 * @param[in] fallback to IPv4 resolution if no AAAA records can be found.
625 * @param[in] mask If true, set address bits to zero.
626 * @return
627 * - 0 if ip address was parsed successfully.
628 * - -1 on failure.
629 */
630int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
631{
632 char *p;
633 char const *end;
634 unsigned int prefix;
635 char *eptr;
636 char buffer[256]; /* As per RFC1035 */
637 int ret;
638
639 /*
640 * Zero out output so we don't have fields
641 * like scope_id hanging around with garbage values.
642 */
643 memset(out, 0, sizeof(*out));
644
645 if (inlen < 0) inlen = strlen(value);
646
647 end = value + inlen;
648 while ((value < end) && isspace((uint8_t) *value)) value++;
649 if (value == end) {
650 fr_strerror_const("Empty IPv6 address string is invalid");
651 return -1;
652 }
653 inlen = end - value; /* always >0 due to the above check for value==end */
654
655 /*
656 * Copy to intermediary buffer.
657 */
658 if (inlen >= (ssize_t)sizeof(buffer)) {
659 fr_strerror_printf("Invalid IPv6 address string \"%pV\"", fr_box_strvalue_len(value, inlen));
660 return -1;
661 }
662
663 memcpy(buffer, value, inlen);
664 buffer[inlen] = '\0';
665 value = buffer;
666
667 p = strchr(value, '/');
668 if (!p) {
669 out->prefix = 128;
670 out->af = AF_INET6;
671
672 /*
673 * Allow scopes for non-prefix values.
674 */
675 p = strchr(value, '%');
676 if (p) *(p++) = '\0';
677
678 /*
679 * Allow '*' as the wildcard address
680 */
681 if ((value[0] == '*') && (value[1] == '\0')) {
682 out->addr.v6 = (struct in6_addr)IN6ADDR_ANY_INIT;
683 } else if (!resolve) {
684 if (inet_pton(AF_INET6, value, out->addr.v6.s6_addr) <= 0) {
685 fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
686 return -1;
687 }
688 } else if (fr_inet_hton(out, AF_INET6, value, fallback) < 0) return -1;
689
690 /*
691 * No scope, or just '%'. That's fine.
692 */
693 if (!p || !*p) return 0;
694
695 /*
696 * Parse scope.
697 */
698 prefix = strtoul(p, &eptr, 10);
699 if (prefix > UINT32_MAX) {
700 fr_strerror_printf("Invalid scope ID \"%s\". Should be between 0-2^32-1", p);
701 return -1;
702 }
703 if (eptr[0] != '\0') {
704 fr_strerror_printf("Failed to parse scope \"%s\", "
705 "got garbage after numerical scope value \"%s\"", p, eptr);
706 return -1;
707 }
708
709 return 0;
710 }
711
712 if ((p - value) >= INET6_ADDRSTRLEN) {
713 fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
714 return -1;
715 }
716
717 /*
718 * Copy string to temporary buffer if we didn't do it earlier
719 */
720 if (inlen < 0) memcpy(buffer, value, p - value);
721
722 if (!resolve) {
723 buffer[p - value] = '\0';
724 ret = inet_pton(AF_INET6, buffer, out->addr.v6.s6_addr);
725 buffer[p - value] = '/';
726 if (ret <= 0) {
727 fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
728 return -1;
729 }
730 } else {
731 buffer[p - value] = '\0';
732 ret = fr_inet_hton(out, AF_INET6, buffer, fallback);
733 buffer[p - value] = '/';
734 if (ret < 0) return -1;
735 }
736
737 prefix = strtoul(p + 1, &eptr, 10);
738 if (prefix > 128) {
739 fr_strerror_printf("Invalid IPv6 mask length \"%s\". Should be between 0-128", p);
740 return -1;
741 }
742 if (eptr[0] != '\0') {
743 fr_strerror_printf("Failed to parse IPv6 address string \"%s\", "
744 "got garbage after mask length \"%s\"", value, eptr);
745 return -1;
746 }
747
748 if (mask && (prefix < 128)) {
749 struct in6_addr addr;
750
751 addr = fr_in6addr_mask(&out->addr.v6, prefix);
752 memcpy(out->addr.v6.s6_addr, addr.s6_addr, sizeof(out->addr.v6.s6_addr));
753 }
754
755 out->af = AF_INET6;
756 out->prefix = (uint8_t) prefix;
757
758 return 0;
759}
760
761/** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser
762 *
763 * @param[out] out Where to write the ip address value.
764 * @param[in] value to parse.
765 * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
766 * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value
767 * as a hostname.
768 * @param[in] af If the address type is not obvious from the format, and resolve is true,
769 * the DNS record (A or AAAA) we require. Also controls which parser we pass
770 * the address to if we have no idea what it is.
771 * - AF_UNSPEC - Use the server default IP family.
772 * - AF_INET - Treat value as an IPv4 address.
773 * - AF_INET6 - Treat value as in IPv6 address.
774 * @param[in] mask If true, set address bits to zero.
775 * @return
776 * - 0 if ip address was parsed successfully.
777 * - -1 on failure.
778 */
779int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
780{
781 size_t len, i;
782 bool hostname = true;
783 bool ipv4 = true;
784 bool ipv6 = true;
785 char const *end;
786
787 end = value + inlen;
788 while ((value < end) && isspace((uint8_t) *value)) value++;
789 if (value == end) {
790 fr_strerror_const("Empty IPv4 address string is invalid");
791 return -1;
792 }
793 inlen = end - value;
794
795 len = (inlen >= 0) ? (size_t)inlen : strlen(value);
796
797 for (i = 0; i < len; i++) {
798 /*
799 * These are valid for IPv4, IPv6, and host names.
800 */
801 if ((value[i] >= '0') && (value[i] <= '9')) {
802 continue;
803 }
804
805 /*
806 * These are invalid for IPv4, but OK for IPv6
807 * and host names.
808 */
809 if ((value[i] >= 'a') && (value[i] <= 'f')) {
810 ipv4 = false;
811 continue;
812 }
813
814 /*
815 * These are invalid for IPv4, but OK for IPv6
816 * and host names.
817 */
818 if ((value[i] >= 'A') && (value[i] <= 'F')) {
819 ipv4 = false;
820 continue;
821 }
822
823 /*
824 * This is only valid for IPv6 addresses.
825 */
826 if (value[i] == ':') {
827 ipv4 = false;
828 hostname = false;
829 continue;
830 }
831
832 /*
833 * Valid for IPv4 and host names, not for IPv6.
834 */
835 if (value[i] == '.') {
836 ipv6 = false;
837 continue;
838 }
839
840 /*
841 * Netmasks are allowed by us, and MUST come at
842 * the end of the address.
843 */
844 if (value[i] == '/') {
845 break;
846 }
847
848 /*
849 * Any characters other than what are checked for
850 * above can't be IPv4 or IPv6 addresses.
851 */
852 ipv4 = false;
853 ipv6 = false;
854 }
855
856 /*
857 * It's not an IPv4 or IPv6 address. It MUST be a host
858 * name.
859 */
860 if (!ipv4 && !ipv6) {
861 /*
862 * Not an IPv4 or IPv6 address, and we weren't
863 * asked to do DNS resolution, we can't do it.
864 */
865 if (!resolve) {
866 fr_strerror_const("Not IPv4/6 address, and asked not to resolve");
867 return -1;
868 }
869
870 /*
871 * It's not a hostname, either, so bail out
872 * early.
873 */
874 if (!hostname) {
875 fr_strerror_const("Invalid address");
876 return -1;
877 }
878 }
879
880 /*
881 * The name has a ':' in it. Therefore it must be an
882 * IPv6 address. Error out if the caller specified IPv4.
883 * Otherwise, force IPv6.
884 */
885 if (ipv6 && !hostname) {
886 if (af == AF_INET) {
887 fr_strerror_const("Invalid address");
888 return -1;
889 }
890
891 af = AF_INET6;
892 }
893
894 /*
895 * Use whatever the caller specified, OR what we
896 * insinuated above from looking at the name string.
897 */
898 switch (af) {
899 case AF_UNSPEC:
900 return fr_inet_pton4(out, value, inlen, resolve, true, mask);
901
902 case AF_INET:
903 return fr_inet_pton4(out, value, inlen, resolve, false, mask);
904
905 case AF_INET6:
906 return fr_inet_pton6(out, value, inlen, resolve, false, mask);
907
908 default:
909 break;
910 }
911
912 /*
913 * No idea what it is...
914 */
915 fr_strerror_printf("Invalid address family %d", af);
916 return -1;
917}
918
919/** Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
920 *
921 * @param[out] out Where to write the ip address value.
922 * @param[out] port_out Where to write the port (0 if no port found).
923 * @param[in] value to parse.
924 * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
925 * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value
926 * as a hostname.
927 * @param[in] af If the address type is not obvious from the format, and resolve is true,
928 * the DNS record (A or AAAA) we require. Also controls which parser we pass
929 * the address to if we have no idea what it is.
930 * - AF_UNSPEC - Use the server default IP family.
931 * - AF_INET - Treat value as an IPv4 address.
932 * - AF_INET6 - Treat value as in IPv6 address.
933 * @param[in] mask If true, set address bits to zero.
934 * @return
935 * - 0 if ip address was parsed successfully.
936 * - -1 on failure.
937 */
938int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value,
939 ssize_t inlen, int af, bool resolve, bool mask)
940{
941 char const *p = value, *q;
942 char *end;
943 unsigned long port;
944 char buffer[6];
945 size_t len;
946
947 *port_out = 0;
948
949 len = (inlen >= 0) ? (size_t)inlen : strlen(value);
950
951 if (*p == '[') {
952 if (!(q = memchr(p + 1, ']', len - 1))) {
953 fr_strerror_const("Missing closing ']' for IPv6 address");
954 return -1;
955 }
956
957 /*
958 * inet_pton doesn't like the address being wrapped in []
959 */
960 if (fr_inet_pton6(out, p + 1, (q - p) - 1, false, false, mask) < 0) return -1;
961
962 if (q[1] == ':') {
963 q++;
964 goto do_port;
965 }
966
967 return 0;
968 }
969
970 /*
971 * Host, IPv4 or IPv6 with no port
972 */
973 q = memchr(p, ':', len);
974 if (!q) return fr_inet_pton(out, p, len, af, resolve, mask);
975
976 /*
977 * IPv4 or host, with port
978 */
979 if (fr_inet_pton(out, p, (q - p), af, resolve, mask) < 0) return -1;
980do_port:
981 /*
982 * Valid ports are a maximum of 5 digits, so if the
983 * input length indicates there are more than 5 chars
984 * after the ':' then there's an issue.
985 */
986 if (len > (size_t) ((q + sizeof(buffer)) - value)) {
987 error:
988 fr_strerror_const("IP string contains trailing garbage after port delimiter");
989 return -1;
990 }
991
992 p = q + 1; /* Move to first digit */
993
994 strlcpy(buffer, p, (len - (p - value)) + 1);
995 port = strtoul(buffer, &end, 10);
996 if (*end != '\0') goto error; /* Trailing garbage after integer */
997
998 if ((port > UINT16_MAX) || (port == 0)) {
999 fr_strerror_printf("Port %lu outside valid port range 1-" STRINGIFY(UINT16_MAX), port);
1000 return -1;
1001 }
1002 *port_out = port;
1003
1004 return 0;
1005}
1006
1007/** Print the address portion of a #fr_ipaddr_t
1008 *
1009 * @note Includes the textual scope_id name (eth0, en0 etc...) if supported.
1010 *
1011 * @param[out] out Where to write the resulting IP string.
1012 * Should be at least FR_IPADDR_STRLEN bytes.
1013 * @param[in] outlen of output buffer.
1014 * @param[in] addr to convert to presentation format.
1015 * @return
1016 * - NULL on error (use fr_syserror(errno)).
1017 * - a pointer to out on success.
1018 */
1019char *fr_inet_ntop(char out[static FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
1020{
1021 char *p;
1022 size_t len;
1023
1024 out[0] = '\0';
1025
1026 if (inet_ntop(addr->af, &addr->addr, out, outlen) == NULL) {
1027 fr_strerror_printf("%s", fr_syserror(errno));
1028 return NULL;
1029 }
1030
1031 if ((addr->af == AF_INET) || (addr->scope_id == 0)) return out;
1032
1033 p = out + strlen(out);
1034
1035#ifdef WITH_IFINDEX_NAME_RESOLUTION
1036 {
1037 char buffer[IFNAMSIZ];
1038 char *ifname;
1039
1040 ifname = fr_ifname_from_ifindex(buffer, addr->scope_id);
1041 if (ifname) {
1042 len = snprintf(p, outlen - (p - out), "%%%s", ifname);
1043 if (is_truncated(len + (p - out), outlen)) {
1044 fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
1045 (p - out) + len, outlen);
1046 return NULL;
1047 }
1048 return out;
1049 }
1050
1051 }
1052#endif
1053
1054 len = snprintf(p, outlen - (p - out), "%%%u", addr->scope_id);
1055 if (is_truncated(len + (p - out), outlen)) {
1056 fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
1057 (p - out) + len, outlen);
1058 return NULL;
1059 }
1060
1061 return out;
1062}
1063
1064/** Print a #fr_ipaddr_t as a CIDR style network prefix
1065 *
1066 * @param[out] out Where to write the resulting prefix string.
1067 * Should be at least FR_IPADDR_PREFIX_STRLEN bytes.
1068 * @param[in] outlen of output buffer.
1069 * @param[in] addr to convert to presentation format.
1070 * @return
1071 * - NULL on error (use fr_syserror(errno)).
1072 * - a pointer to out on success.
1073 */
1074char *fr_inet_ntop_prefix(char out[static FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
1075{
1076 char *p;
1077 size_t len;
1078
1079 if (fr_inet_ntop(out, outlen, addr) == NULL) return NULL;
1080
1081 p = out + strlen(out);
1082
1083 len = snprintf(p, outlen - (p - out), "/%i", addr->prefix);
1084 if (is_truncated(len + (p - out), outlen)) {
1085 fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
1086 (p - out) + len, outlen);
1087 return NULL;
1088 }
1089
1090 return out;
1091}
1092
1093/** Print an interface-id in standard colon notation
1094 *
1095 * @param[out] out Where to write the resulting interface-id string.
1096 * @param[in] outlen of output buffer.
1097 * @param[in] ifid to print.
1098 * @return a pointer to out.
1099 */
1100char *fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
1101{
1102 snprintf(out, outlen, "%x:%x:%x:%x",
1103 fr_nbo_to_uint16(ifid), fr_nbo_to_uint16(ifid + 2),
1104 fr_nbo_to_uint16(ifid + 4), fr_nbo_to_uint16(ifid + 6));
1105 return out;
1106}
1107
1108/** Convert interface-id in colon notation to 8 byte binary form
1109 *
1110 * @param[out] out Where to write the binary interface-id.
1111 * @param[in] ifid_str to parse.
1112 * @return a pointer to out.
1113 */
1114uint8_t *fr_inet_ifid_pton(uint8_t out[static 8], char const *ifid_str)
1115{
1116 static char const xdigits[] = "0123456789abcdef";
1117 char const *p, *pch;
1118 int num_id = 0, val = 0, idx = 0;
1119
1120 for (p = ifid_str; ; ++p) {
1121 if (*p == ':' || *p == '\0') {
1122 if (num_id <= 0)
1123 return NULL;
1124
1125 /*
1126 * Drop 'val' into the array.
1127 */
1128 out[idx] = (val >> 8) & 0xff;
1129 out[idx + 1] = val & 0xff;
1130 if (*p == '\0') {
1131 /*
1132 * Must have all entries before
1133 * end of the string.
1134 */
1135 if (idx != 6)
1136 return NULL;
1137 break;
1138 }
1139 val = 0;
1140 num_id = 0;
1141 if ((idx += 2) > 6)
1142 return NULL;
1143 } else if ((pch = strchr(xdigits, tolower((uint8_t) *p))) != NULL) {
1144 if (++num_id > 4)
1145 return NULL;
1146 /*
1147 * Dumb version of 'scanf'
1148 */
1149 val <<= 4;
1150 val |= (pch - xdigits);
1151 } else
1152 return NULL;
1153 }
1154 return out;
1155}
1156
1157#ifdef SIOCGIFADDR
1158/** Retrieve the primary IP address associated with an interface
1159 *
1160 * @param[out] out The primary IP address associated with the named interface.
1161 * @param[in] af of IP address to retrieve (AF_INET or AF_INET6).
1162 * @param[in] name of interface.
1163 * @return
1164 * - 0 on success.
1165 * - -1 on failure.
1166 */
1167int fr_ipaddr_from_ifname(fr_ipaddr_t *out, int af, char const *name)
1168{
1169 int fd;
1170 struct ifreq if_req;
1171 fr_ipaddr_t ipaddr;
1172
1173 memset(&if_req, 0, sizeof(if_req));
1174 memset(out, 0, sizeof(*out));
1175
1176 /*
1177 * Set the interface we're resolving, and the address family.
1178 */
1179 if_req.ifr_addr.sa_family = af;
1180 strlcpy(if_req.ifr_name, name, sizeof(if_req.ifr_name));
1181
1182 fd = socket(AF_INET, SOCK_DGRAM, 0);
1183 if (fd < 0) {
1184 fr_strerror_printf("Failed opening temporary socket for SIOCGIFADDR: %s", fr_syserror(errno));
1185 error:
1186 close(fd);
1187 return -1;
1188 }
1189 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1190 fr_strerror_printf("Failed determining address for interface %s: %s", name, fr_syserror(errno));
1191 goto error;
1192 }
1193
1194 /*
1195 * There's nothing in the ifreq struct that gives us the length
1196 * of the sockaddr struct, so we just use sizeof here.
1197 * sockaddr2ipaddr uses the address family anyway, so we should
1198 * be OK.
1199 */
1200 if (fr_ipaddr_from_sockaddr(&ipaddr, NULL,
1201 (struct sockaddr_storage *)&if_req.ifr_addr,
1202 sizeof(if_req.ifr_addr)) < 0) goto error;
1203 *out = ipaddr;
1204
1205 close(fd);
1206
1207 return 0;
1208}
1209#else
1211{
1212 fr_strerror_printf("No support for SIOCGIFADDR, can't determine IP address of %s", name);
1213 return -1;
1214}
1215#endif
1216
1217#ifdef WITH_IFINDEX_NAME_RESOLUTION
1218/** Resolve ifindex to interface name
1219 *
1220 * @param[out] out Buffer to use to store the name, must be at least IFNAMSIZ bytes.
1221 * @param[in] ifindex to resolve to name.
1222 * @return
1223 * - NULL on error.
1224 * - a pointer to out on success.
1225 */
1226char *fr_ifname_from_ifindex(char out[static IFNAMSIZ], int ifindex)
1227{
1228#ifdef HAVE_IF_INDEXTONAME
1229 if (!if_indextoname(ifindex, out)) {
1230 fr_strerror_printf("Failed resolving interface index %i to name", ifindex);
1231 return NULL;
1232 }
1233#else
1234 struct ifreq if_req;
1235 int fd;
1236
1237 memset(&if_req, 0, sizeof(if_req));
1238 if_req.ifr_ifindex = ifindex;
1239
1240 fd = socket(AF_INET, SOCK_DGRAM, 0);
1241 if (fd < 0) {
1242 fr_strerror_printf("Failed opening temporary socket for SIOCGIFADDR: %s", fr_syserror(errno));
1243 error:
1244 close(fd);
1245 return NULL;
1246 }
1247
1248 /*
1249 * First we resolve the interface index to the interface name
1250 * Which is pretty inefficient, but it seems the only way to
1251 * identify interfaces for SIOCG* operations is with the interface
1252 * name.
1253 */
1254 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1255 fr_strerror_printf("Failed resolving interface index %i to name: %s", ifindex, fr_syserror(errno));
1256 goto error;
1257 }
1258 strlcpy(out, if_req.ifr_name, IFNAMSIZ);
1259 close(fd);
1260#endif
1261 return out;
1262}
1263#endif
1264
1265#ifdef WITH_IFINDEX_IPADDR_RESOLUTION
1266/** Returns the primary IP address for a given interface index
1267 *
1268 * @note Intended to be used with udpfromto (recvfromto) to retrieve the
1269 * source IP address to use when responding to broadcast packets.
1270 *
1271 * @note Will likely be quite slow due to the number of system calls.
1272 *
1273 * @param[out] out Where to write the primary IP address.
1274 * @param[in] fd File descriptor of any datagram or raw socket.
1275 * @param[in] af to get interface for.
1276 * @param[in] ifindex of interface to get IP address for.
1277 * @return
1278 * - 0 on success.
1279 * - -1 on failure.
1280 */
1281int fr_ipaddr_from_ifindex(fr_ipaddr_t *out, int fd, int af, int ifindex)
1282{
1283 struct ifreq if_req;
1284 fr_ipaddr_t ipaddr;
1285
1286 memset(&if_req, 0, sizeof(if_req));
1287 memset(out, 0, sizeof(*out));
1288
1289#ifdef SIOCGIFNAME
1290 if_req.ifr_ifindex = ifindex;
1291 /*
1292 * First we resolve the interface index to the interface name
1293 * Which is pretty inefficient, but it seems the only way to
1294 * identify interfaces for SIOCG* operations is with the interface
1295 * name.
1296 */
1297 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1298 fr_strerror_printf("Failed resolving interface index %i to name: %s", ifindex, fr_syserror(errno));
1299 return -1;
1300 }
1301#elif defined(HAVE_IF_INDEXTONAME)
1302 if (!if_indextoname(ifindex, if_req.ifr_name)) {
1303 fr_strerror_printf("Failed resolving interface index %i to name", ifindex);
1304 return -1;
1305 }
1306#else
1307# error Need SIOCGIFNAME or if_indextoname
1308#endif
1309
1310 /*
1311 * Name should now be present in if_req, so we just need to
1312 * set the address family.
1313 */
1314 if_req.ifr_addr.sa_family = af;
1315
1316 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1317 fr_strerror_printf("Failed determining address for interface %s: %s",
1318 if_req.ifr_name, fr_syserror(errno));
1319 return -1;
1320 }
1321
1322 /*
1323 * There's nothing in the ifreq struct that gives us the length
1324 * of the sockaddr struct, so we just use sizeof here.
1325 * sockaddr2ipaddr uses the address family anyway, so we should
1326 * be OK.
1327 */
1328 if (fr_ipaddr_from_sockaddr(&ipaddr, NULL,
1329 (struct sockaddr_storage *)&if_req.ifr_addr,
1330 sizeof(if_req.ifr_addr)) < 0) return -1;
1331 *out = ipaddr;
1332
1333 return 0;
1334}
1335#endif
1336
1337/** Compare two ip addresses
1338 *
1339 * @param[in] a First ip to compare.
1340 * @param[in] b Second ip to compare.
1341 * @return
1342 * - 1 if a > b
1343 * - 0 if a == b
1344 * - -1 if a < b
1345 * - -2 on error.
1346 */
1347int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
1348{
1349 int ret;
1350 size_t len;
1351
1352 CMP_RETURN(a, b, af);
1353 CMP_RETURN(a, b, prefix);
1354
1355 /*
1356 * We only care about prefix bytes.
1357 *
1358 * Host bytes should be masked on ingestion
1359 * for prefix types.
1360 */
1361 len = ((a->prefix + 7) & -8) >> 3;
1362 switch (a->af) {
1363 case AF_INET:
1364 ret = memcmp(&a->addr.v4, &b->addr.v4, len);
1365 return CMP(ret, 0);
1366
1367#ifdef HAVE_STRUCT_SOCKADDR_IN6
1368 case AF_INET6:
1369 CMP_RETURN(a, b, scope_id);
1370 ret = memcmp(&a->addr.v6, &b->addr.v6, len);
1371 return CMP(ret, 0);
1372#endif
1373
1374 default:
1375 fr_strerror_printf("Invalid address family %d", a->af);
1376 return -2;
1377 }
1378}
1379
1380/** Convert our internal ip address representation to a sockaddr
1381 *
1382 * @param[out] sa where to write out the sockaddr,
1383 * must be large enough to hold
1384 * sizeof(s6).
1385 * @param[out] salen Length of the sockaddr struct.
1386 * @param[in] ipaddr IP address to convert.
1387 * @param[in] port Port to convert.
1388
1389 * @return
1390 * - 0 on success.
1391 * - -1 on failure.
1392 */
1393int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen,
1394 fr_ipaddr_t const *ipaddr, uint16_t port)
1395{
1396 memset(sa, 0, sizeof(*sa));
1397
1398 if (ipaddr->af == AF_INET) {
1399 struct sockaddr_in s4;
1400
1401 *salen = sizeof(s4);
1402
1403 memset(&s4, 0, sizeof(s4));
1404 s4.sin_family = AF_INET;
1405 s4.sin_addr = ipaddr->addr.v4;
1406 s4.sin_port = htons(port);
1407 memset(sa, 0, sizeof(*sa));
1408 memcpy(sa, &s4, sizeof(s4));
1409
1410#ifdef HAVE_STRUCT_SOCKADDR_IN6
1411 } else if (ipaddr->af == AF_INET6) {
1412 struct sockaddr_in6 s6;
1413
1414 *salen = sizeof(s6);
1415
1416 memset(&s6, 0, sizeof(s6));
1417 s6.sin6_family = AF_INET6;
1418 s6.sin6_addr = ipaddr->addr.v6;
1419 s6.sin6_port = htons(port);
1420 s6.sin6_scope_id = ipaddr->scope_id;
1421 memset(sa, 0, sizeof(*sa));
1422 memcpy(sa, &s6, sizeof(s6));
1423#endif
1424 } else {
1425 fr_strerror_printf("Unsupported address family %d", ipaddr->af);
1426 return -1;
1427 }
1428
1429 return 0;
1430}
1431
1432/** Convert sockaddr to our internal ip address representation
1433 *
1434 * @param[out] ipaddr Where to write the ipaddr.
1435 * @param[out] port Where to write the port.
1436 * @param[in] sa struct to convert.
1437 * @param[in] salen Length of the sockaddr struct.
1438 * @return
1439 * - 0 on success.
1440 * - -1 on failure.
1441 */
1443 struct sockaddr_storage const *sa, socklen_t salen)
1444{
1445 memset(ipaddr, 0, sizeof(*ipaddr));
1446
1447 if (sa->ss_family == AF_INET) {
1448 struct sockaddr_in s4;
1449
1450 if (salen < sizeof(s4)) {
1451 fr_strerror_const("IPv4 address is too small");
1452 return 0;
1453 }
1454
1455 memcpy(&s4, sa, sizeof(s4));
1456 ipaddr->af = AF_INET;
1457 ipaddr->prefix = 32;
1458 ipaddr->addr.v4 = s4.sin_addr;
1459 if (port) *port = ntohs(s4.sin_port);
1460 ipaddr->scope_id = 0;
1461
1462#ifdef HAVE_STRUCT_SOCKADDR_IN6
1463 } else if (sa->ss_family == AF_INET6) {
1464 struct sockaddr_in6 s6;
1465
1466 if (salen < sizeof(s6)) {
1467 fr_strerror_const("IPv6 address is too small");
1468 return 0;
1469 }
1470
1471 memcpy(&s6, sa, sizeof(s6));
1472 ipaddr->af = AF_INET6;
1473 ipaddr->prefix = 128;
1474 ipaddr->addr.v6 = s6.sin6_addr;
1475 if (port) *port = ntohs(s6.sin6_port);
1476 ipaddr->scope_id = s6.sin6_scope_id;
1477#endif
1478
1479 } else {
1480 fr_strerror_printf("Unsupported address family %d", sa->ss_family);
1481 return -1;
1482 }
1483
1484 return 0;
1485}
1486
1488{
1489 struct ifaddrs *list = NULL;
1490 struct ifaddrs *i;
1491
1492 /*
1493 * This should be set already for IPv6. We should only need to do this for IPv4.
1494 */
1495 if (ipaddr->scope_id != 0) return;
1496
1497 /*
1498 * Bind manually to an IP used by the named interface.
1499 */
1500 if (getifaddrs(&list) < 0) return;
1501
1502 for (i = list; i != NULL; i = i->ifa_next) {
1504
1505 if (!i->ifa_addr || !i->ifa_name || (ipaddr->af != i->ifa_addr->sa_family)) continue;
1506
1508 (struct sockaddr_storage *)i->ifa_addr, sizeof(struct sockaddr_in6));
1509 my_ipaddr.scope_id = 0;
1510
1511 /*
1512 * my_ipaddr will have a scope_id, but the input
1513 * ipaddr won't have one. We therefore set the
1514 * local one to zero, so that we can do correct
1515 * IP address comparisons.
1516 *
1517 * If the comparison succeeds, then we return
1518 * both the interface name, and we update the
1519 * input ipaddr with the correct scope_id.
1520 */
1521 if (fr_ipaddr_cmp(ipaddr, &my_ipaddr) == 0) {
1522 ipaddr->scope_id = if_nametoindex(i->ifa_name);
1523 break;
1524 }
1525 }
1526
1527 freeifaddrs(list);
1528}
1529
1530
1531char *fr_ipaddr_to_interface(TALLOC_CTX *ctx, fr_ipaddr_t *ipaddr)
1532{
1533 struct ifaddrs *list = NULL;
1534 struct ifaddrs *i;
1535 char *interface = NULL;
1536
1537 /*
1538 * Bind manually to an IP used by the named interface.
1539 */
1540 if (getifaddrs(&list) < 0) return NULL;
1541
1542 for (i = list; i != NULL; i = i->ifa_next) {
1543 int scope_id;
1545
1546 if (!i->ifa_addr || !i->ifa_name || (ipaddr->af != i->ifa_addr->sa_family)) continue;
1547
1549 (struct sockaddr_storage *)i->ifa_addr, sizeof(struct sockaddr_in6));
1550
1551 /*
1552 * my_ipaddr will have a scope_id, but the input
1553 * ipaddr won't have one. We therefore set the
1554 * local one to zero, so that we can do correct
1555 * IP address comparisons.
1556 *
1557 * If the comparison succeeds, then we return
1558 * both the interface name, and we update the
1559 * input ipaddr with the correct scope_id.
1560 */
1561 scope_id = my_ipaddr.scope_id;
1562 my_ipaddr.scope_id = 0;
1563 if (fr_ipaddr_cmp(ipaddr, &my_ipaddr) == 0) {
1564 interface = talloc_strdup(ctx, i->ifa_name);
1565 ipaddr->scope_id = scope_id;
1566 break;
1567 }
1568 }
1569
1570 freeifaddrs(list);
1571 return interface;
1572}
1573
1574int fr_interface_to_ipaddr(char const *interface, fr_ipaddr_t *ipaddr, int af, bool link_local)
1575{
1576 struct ifaddrs *list = NULL;
1577 struct ifaddrs *i;
1578 int ret = -1;
1579
1580 if (getifaddrs(&list) < 0) return -1;
1581
1582 for (i = list; i != NULL; i = i->ifa_next) {
1584 struct sockaddr_storage sa;
1585
1586 if (!i->ifa_addr || !i->ifa_name || ((af != AF_UNSPEC) && (af != i->ifa_addr->sa_family))) continue;
1587 if (strcmp(i->ifa_name, interface) != 0) continue;
1588
1589 memcpy(&sa, i->ifa_addr, sizeof(struct sockaddr_in6)); /* ifa->ifa_addr may not be aligned properly */
1590
1591 fr_ipaddr_from_sockaddr(&my_ipaddr, NULL, &sa, sizeof(struct sockaddr_in6));
1592
1593 /*
1594 * If they ask for a link local address, then give
1595 * it to them.
1596 */
1597 if (link_local) {
1598 if (my_ipaddr.af != AF_INET6) continue;
1599 if (!IN6_IS_ADDR_LINKLOCAL(&my_ipaddr.addr.v6)) continue;
1600 }
1601
1602 *ipaddr = my_ipaddr;
1603 ret = 0;
1604 break;
1605 }
1606
1607 freeifaddrs(list);
1608 return ret;
1609}
1610
1611/*
1612 * AF_PACKET on Linux
1613 * AF_LINK on BSD
1614 */
1615#ifndef AF_LINK
1616#define AF_LINK AF_PACKET
1617#endif
1618
1619int fr_interface_to_ethernet(char const *interface, fr_ethernet_t *ethernet)
1620{
1621 struct ifaddrs *list = NULL;
1622 struct ifaddrs *i;
1623 int ret = -1;
1624
1625 if (getifaddrs(&list) < 0) return -1;
1626
1627 for (i = list; i != NULL; i = i->ifa_next) {
1628 if (!i->ifa_addr || !i->ifa_name || (i->ifa_addr->sa_family != AF_LINK)) continue;
1629 if (strcmp(i->ifa_name, interface) != 0) continue;
1630
1631#if defined(__linux__) || defined(__EMSCRIPTEN__)
1632 {
1633 struct sockaddr_ll *ll;
1634
1635 ll = (struct sockaddr_ll *) i->ifa_addr;
1636 if ((ll->sll_hatype != 1) || (ll->sll_halen != 6)) continue;
1637
1638 memcpy(ethernet->addr, ll->sll_addr, 6);
1639 }
1640#else
1641 {
1642 struct sockaddr_dl *ll;
1643
1644 ll = (struct sockaddr_dl *) i->ifa_addr;
1645 if (ll->sdl_alen != 6) continue;
1646
1647 memcpy(ethernet->addr, LLADDR(ll), 6);
1648 }
1649#endif
1650 ret = 0;
1651 break;
1652 }
1653
1654 freeifaddrs(list);
1655 return ret;
1656}
1657
1658
1659int8_t fr_sockaddr_cmp(struct sockaddr_storage const *a, struct sockaddr_storage const *b)
1660{
1661 int ret;
1662
1663 ret = CMP(a->ss_family, b->ss_family);
1664 if (ret != 0) return 0;
1665
1666 switch (a->ss_family) {
1667 case AF_INET:
1668 ret = CMP(((struct sockaddr_in const *)a)->sin_port, ((struct sockaddr_in const *)b)->sin_port);
1669 if (ret != 0) return ret;
1670
1671 ret = memcmp(&((struct sockaddr_in const *)a)->sin_addr,
1672 &((struct sockaddr_in const *)b)->sin_addr,
1673 sizeof(((struct sockaddr_in const *)a)->sin_addr));
1674 return CMP(ret, 0);
1675
1676 case AF_INET6:
1677 ret = CMP(((struct sockaddr_in6 const *)a)->sin6_port, ((struct sockaddr_in6 const *)b)->sin6_port);
1678 if (ret != 0) return ret;
1679
1680 /*
1681 * @todo - flow info?
1682 */
1683
1684 ret = CMP(((struct sockaddr_in6 const *)a)->sin6_scope_id, ((struct sockaddr_in6 const *)b)->sin6_scope_id);
1685 if (ret != 0) return ret;
1686
1687 ret = memcmp(&((struct sockaddr_in6 const *)a)->sin6_addr,
1688 &((struct sockaddr_in6 const *)b)->sin6_addr,
1689 sizeof(((struct sockaddr_in6 const *)a)->sin6_addr));
1690 return CMP(ret, 0);
1691
1692 case AF_LOCAL:
1693 ret = strcmp(((struct sockaddr_un const *)a)->sun_path,
1694 ((struct sockaddr_un const *)b)->sun_path);
1695 return CMP(ret, 0);
1696
1697 default:
1698 fr_assert(0);
1699 return 0;
1700 }
1701}
static int const char char buffer[256]
Definition acutest.h:576
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define STRINGIFY(x)
Definition build.h:197
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition build.h:121
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define UNUSED
Definition build.h:317
Test enumeration values.
Definition dict_test.h:92
int getaddrinfo(char const *hostname, char const *servname, struct addrinfo const *hints, struct addrinfo **res)
char const * gai_strerror(int ecode)
void freeaddrinfo(struct addrinfo *ai)
int getnameinfo(struct sockaddr const *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, unsigned int flags)
int fr_interface_to_ipaddr(char const *interface, fr_ipaddr_t *ipaddr, int af, bool link_local)
Definition inet.c:1574
int fr_ipaddr_is_prefix(fr_ipaddr_t const *ipaddr)
Determine if an address is a prefix.
Definition inet.c:126
int fr_ipaddr_is_multicast(fr_ipaddr_t const *ipaddr)
Determine if an address is a multicast address.
Definition inet.c:95
void fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr)
Definition inet.c:1487
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
Definition inet.c:356
char * fr_inet_ntop_prefix(char out[static FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print a fr_ipaddr_t as a CIDR style network prefix.
Definition inet.c:1074
int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv6 address or IPv6 prefix in presentation format (and others)
Definition inet.c:630
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
Definition inet.c:255
static int ip_octet_from_str(uint32_t *out, char const *str)
Parse a single octet of an IPv4 address string.
Definition inet.c:388
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
Definition inet.c:1442
int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask_bits)
Parse an IPv4 address or IPv4 prefix in presentation format (and others)
Definition inet.c:481
int8_t fr_sockaddr_cmp(struct sockaddr_storage const *a, struct sockaddr_storage const *b)
Definition inet.c:1659
bool fr_hostname_lookups
hostname -> IP lookups?
Definition inet.c:53
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser.
Definition inet.c:779
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
Definition inet.c:938
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition inet.c:63
char * fr_inet_ntop(char out[static FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print the address portion of a fr_ipaddr_t.
Definition inet.c:1019
#define AF_LINK
Definition inet.c:1616
char * fr_ipaddr_to_interface(TALLOC_CTX *ctx, fr_ipaddr_t *ipaddr)
Definition inet.c:1531
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
Definition inet.c:1393
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1347
static struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
Mask off a portion of an IPv6 address.
Definition inet.c:168
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
Definition inet.c:218
int fr_interface_to_ethernet(char const *interface, fr_ethernet_t *ethernet)
Definition inet.c:1619
char * fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
Print an interface-id in standard colon notation.
Definition inet.c:1100
uint8_t * fr_inet_ifid_pton(uint8_t out[static 8], char const *ifid_str)
Convert interface-id in colon notation to 8 byte binary form.
Definition inet.c:1114
int fr_ipaddr_from_ifname(UNUSED fr_ipaddr_t *out, UNUSED int af, char const *name)
Definition inet.c:1210
static int ip_prefix_addr_from_str(struct in_addr *out, char const *str)
Parses the network portion of an IPv4 prefix into an in_addr.
Definition inet.c:431
bool fr_reverse_lookups
IP -> hostname lookups?
Definition inet.c:52
static struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
Mask off a portion of an IPv4 address.
Definition inet.c:147
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition inet.h:69
#define FR_IPADDR_STRLEN
Like INET6_ADDRSTRLEN but includes space for the textual Zone ID.
Definition inet.h:89
int af
Address family.
Definition inet.h:64
uint32_t scope_id
A host may have multiple link-local interfaces the scope ID allows the application to specify which o...
Definition inet.h:70
uint8_t addr[6]
Ethernet address.
Definition inet.h:46
union fr_ipaddr_t::@135 addr
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
Definition inet.h:93
Struct to represent an ethernet address.
Definition inet.h:45
IPv4/6 prefix.
unsigned short uint16_t
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
static bool is_integer(char const *value)
Check whether the string is all numbers.
Definition misc.h:109
int inet_pton(int af, char const *src, void *dst)
Definition missing.c:427
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition missing.c:443
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
#define is_truncated(_ret, _max)
Definition print.h:48
#define fr_assert(_expr)
Definition rad_assert.h:38
static fr_ipaddr_t my_ipaddr
static uint32_t mask
Definition rbmonkey.c:39
static char const * name
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
close(uq->fd)
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_box_strvalue_len(_val, _len)
Definition value.h:305
static size_t char fr_sbuff_t size_t inlen
Definition value.h:1020
static size_t char ** out
Definition value.h:1020