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