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