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