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>
30#include <net/if_arp.h>
36#if defined(HAVE_LINUX_IF_PACKET_H)
37# include <linux/if_packet.h>
38# include <linux/if_ether.h>
42#elif defined(HAVE_NET_IF_DL_H)
43# include <net/if_dl.h>
47#elif defined(HAVE_NETPACKET_PACKET_H)
48# include <netpacket/packet.h>
65 if (ipaddr->
af == AF_INET) {
66 if (ipaddr->
addr.v4.s_addr == htonl(INADDR_ANY)) {
70#ifdef HAVE_STRUCT_SOCKADDR_IN6
71 }
else if (ipaddr->
af == AF_INET6) {
73 if (IN6_IS_ADDR_UNSPECIFIED(
UNCONST(
struct in6_addr *, &(ipaddr->
addr.v6)))) {
96 if (ipaddr->
af == AF_INET) {
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) {
105 if (IN6_IS_ADDR_MULTICAST(
UNCONST(
struct in6_addr *, &(ipaddr->
addr.v6)))) {
128 switch (ipaddr->
af) {
130 return (ipaddr->
prefix < 32);
133 return (ipaddr->
prefix < 128);
151 if (prefix > 32) prefix = 32;
154 if (prefix == 32)
return *ipaddr;
156 if (prefix == 0) ret = 0;
157 else ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
159 return (*(
struct in_addr *)&ret);
171 uint64_t ret[2], *o = ret;
174 if (prefix > 128) prefix = 128;
177 if (prefix == 128)
return *ipaddr;
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;
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;
210 return *(
struct in6_addr *) &ret;
258 struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
265#ifdef HAVE_STRUCT_SOCKADDR_IN6
266 if (af == AF_UNSPEC) {
269 for (p = hostname; *p !=
'\0'; p++) {
280 if (af == AF_UNSPEC) af = AF_INET;
284 "hostname lookups are disabled", hostname);
288 out->prefix = (af == AF_INET) ? 32 : 128;
294 memset(&hints, 0,
sizeof(hints));
300 hints.ai_family = AF_UNSPEC;
302 hints.ai_family = af;
305 if ((ret =
getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
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;
332 fr_strerror_printf(
"Failed resolving \"%s\": No records matching requested address family returned",
358 struct sockaddr_storage ss;
371 if ((error =
getnameinfo((
struct sockaddr *)&ss, salen,
out, outlen, NULL, 0,
372 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
393 if ((*p <
'0') || (*p >
'9'))
return -1;
397 while ((*p >=
'0') && (*p <=
'9')) {
402 if (octet > 255)
return -1;
441 for (shift = 24; shift >= 0; shift -= 8) {
443 if (length <= 0)
return -1;
445 addr |= octet << shift;
451 if (!*p || (*p ==
'/'))
break;
456 if (*p !=
'.')
return -1;
460 out->s_addr = htonl(addr);
494 memset(
out, 0,
sizeof(*
out));
519 p = strchr(
value,
'/');
531 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
532 out->addr.v4.s_addr = htonl(INADDR_ANY);
541 out->addr.v4.s_addr = htonl(strtoul(
value, NULL, 0));
543 }
else if (!resolve) {
544 unsigned int a, b, c, d;
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)) {
557 out->addr.v4.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
567 if ((
size_t)(p -
value) >= INET_ADDRSTRLEN) {
594 mask = strtoul(p + 1, &eptr, 10);
600 if (eptr[0] !=
'\0') {
602 "got garbage after mask length \"%s\"",
value, eptr);
606 if (mask_bits && (
mask < 32)) {
645 memset(
out, 0,
sizeof(*
out));
669 p = strchr(
value,
'/');
677 p = strchr(
value,
'%');
678 if (p) *(p++) =
'\0';
683 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
684 out->addr.v6 = (
struct in6_addr)IN6ADDR_ANY_INIT;
685 }
else if (!resolve) {
695 if (!p || !*p)
return 0;
700 prefix = strtoul(p, &eptr, 10);
701 if (prefix > UINT32_MAX) {
705 if (eptr[0] !=
'\0') {
707 "got garbage after numerical scope value \"%s\"", p, eptr);
711 out->scope_id = prefix;
716 if ((p -
value) >= INET6_ADDRSTRLEN) {
738 if (ret < 0)
return -1;
741 prefix = strtoul(p + 1, &eptr, 10);
746 if (eptr[0] !=
'\0') {
748 "got garbage after mask length \"%s\"",
value, eptr);
752 if (
mask && (prefix < 128)) {
753 struct in6_addr addr;
756 memcpy(
out->addr.v6.s6_addr, addr.s6_addr,
sizeof(
out->addr.v6.s6_addr));
786 bool hostname =
true;
803 for (i = 0; i < len; i++) {
832 if (
value[i] ==
':') {
841 if (
value[i] ==
'.') {
850 if (
value[i] ==
'/') {
866 if (!ipv4 && !ipv6) {
891 if (ipv6 && !hostname) {
947 char const *p =
value, *q;
958 if (!(q = memchr(p + 1,
']', len - 1))) {
979 q = memchr(p,
':', len);
992 if (len > (
size_t) ((q +
sizeof(
buffer)) -
value)) {
1001 port = strtoul(
buffer, &end, 10);
1002 if (*end !=
'\0')
goto error;
1004 if ((port > UINT16_MAX) || (port == 0)) {
1037 if ((addr->
af == AF_INET) || (addr->
scope_id == 0))
return out;
1041#ifdef WITH_IFINDEX_NAME_RESOLUTION
1048 len =
snprintf(p, outlen - (p -
out),
"%%%s", ifname);
1051 (p -
out) + len, outlen);
1063 (p -
out) + len, outlen);
1092 (p -
out) + len, outlen);
1122 static char const xdigits[] =
"0123456789abcdef";
1123 char const *p, *pch;
1124 int num_id = 0, val = 0, idx = 0;
1126 for (p = ifid_str; ; ++p) {
1127 if (*p ==
':' || *p ==
'\0') {
1134 out[idx] = (val >> 8) & 0xff;
1135 out[idx + 1] = val & 0xff;
1149 }
else if ((pch = strchr(xdigits, tolower((
uint8_t) *p))) != NULL) {
1156 val |= (pch - xdigits);
1176 struct ifreq if_req;
1179 memset(&if_req, 0,
sizeof(if_req));
1180 memset(
out, 0,
sizeof(*
out));
1185 if_req.ifr_addr.sa_family = af;
1186 strlcpy(if_req.ifr_name,
name,
sizeof(if_req.ifr_name));
1188 fd = socket(AF_INET, SOCK_DGRAM, 0);
1193 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1207 (
struct sockaddr_storage *)&if_req.ifr_addr,
1208 sizeof(if_req.ifr_addr)) < 0)
goto error;
1223#ifdef WITH_IFINDEX_NAME_RESOLUTION
1232char *fr_ifname_from_ifindex(
char out[
static IFNAMSIZ],
int ifindex)
1234#ifdef HAVE_IF_INDEXTONAME
1235 if (!if_indextoname(ifindex,
out)) {
1240 struct ifreq if_req;
1243 memset(&if_req, 0,
sizeof(if_req));
1244 if_req.ifr_ifindex = ifindex;
1246 fd = socket(AF_INET, SOCK_DGRAM, 0);
1260 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1271#ifdef WITH_IFINDEX_IPADDR_RESOLUTION
1287int fr_ipaddr_from_ifindex(
fr_ipaddr_t *
out,
int fd,
int af,
int ifindex)
1289 struct ifreq if_req;
1292 memset(&if_req, 0,
sizeof(if_req));
1293 memset(
out, 0,
sizeof(*
out));
1296 if_req.ifr_ifindex = ifindex;
1303 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1307#elif defined(HAVE_IF_INDEXTONAME)
1308 if (!if_indextoname(ifindex, if_req.ifr_name)) {
1313# error Need SIOCGIFNAME or if_indextoname
1320 if_req.ifr_addr.sa_family = af;
1322 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1335 (
struct sockaddr_storage *)&if_req.ifr_addr,
1336 sizeof(if_req.ifr_addr)) < 0)
return -1;
1367 len = ((a->
prefix + 7) & -8) >> 3;
1370 ret = memcmp(&a->
addr.v4, &b->
addr.v4, len);
1373#ifdef HAVE_STRUCT_SOCKADDR_IN6
1376 ret = memcmp(&a->
addr.v6, &b->
addr.v6, len);
1402 memset(sa, 0,
sizeof(*sa));
1404 if (ipaddr->
af == AF_INET) {
1405 struct sockaddr_in s4;
1407 *salen =
sizeof(s4);
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));
1416#ifdef HAVE_STRUCT_SOCKADDR_IN6
1417 }
else if (ipaddr->
af == AF_INET6) {
1418 struct sockaddr_in6 s6;
1420 *salen =
sizeof(s6);
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));
1449 struct sockaddr_storage
const *sa, socklen_t salen)
1451 memset(ipaddr, 0,
sizeof(*ipaddr));
1453 if (sa->ss_family == AF_INET) {
1454 struct sockaddr_in s4;
1456 if (salen <
sizeof(s4)) {
1461 memcpy(&s4, sa,
sizeof(s4));
1462 ipaddr->
af = AF_INET;
1464 ipaddr->
addr.v4 = s4.sin_addr;
1465 if (port) *port = ntohs(s4.sin_port);
1468#ifdef HAVE_STRUCT_SOCKADDR_IN6
1469 }
else if (sa->ss_family == AF_INET6) {
1470 struct sockaddr_in6 s6;
1472 if (salen <
sizeof(s6)) {
1477 memcpy(&s6, sa,
sizeof(s6));
1478 ipaddr->
af = AF_INET6;
1480 ipaddr->
addr.v6 = s6.sin6_addr;
1481 if (port) *port = ntohs(s6.sin6_port);
1482 ipaddr->
scope_id = s6.sin6_scope_id;
1495 struct ifaddrs *list = NULL;
1506 if (getifaddrs(&list) < 0)
return;
1508 for (i = list; i != NULL; i = i->ifa_next) {
1511 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1514 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1528 ipaddr->
scope_id = if_nametoindex(i->ifa_name);
1539 struct ifaddrs *list = NULL;
1541 char *
interface = NULL;
1546 if (getifaddrs(&list) < 0)
return NULL;
1548 for (i = list; i != NULL; i = i->ifa_next) {
1552 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1555 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1582 struct ifaddrs *list = NULL;
1586 if (getifaddrs(&list) < 0)
return -1;
1588 for (i = list; i != NULL; i = i->ifa_next) {
1590 struct sockaddr_storage sa;
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;
1595 memcpy(&sa, i->ifa_addr,
sizeof(
struct sockaddr_in6));
1622#define AF_LINK AF_PACKET
1627 struct ifaddrs *list = NULL;
1631 if (getifaddrs(&list) < 0)
return -1;
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;
1637#if defined(__linux__) || defined(__EMSCRIPTEN__)
1639 struct sockaddr_ll *ll;
1641 ll = (
struct sockaddr_ll *) i->ifa_addr;
1642 if ((ll->sll_hatype != 1) || (ll->sll_halen != 6))
continue;
1644 memcpy(ethernet->
addr, ll->sll_addr, 6);
1648 struct sockaddr_dl *ll;
1650 ll = (
struct sockaddr_dl *) i->ifa_addr;
1651 if (ll->sdl_alen != 6)
continue;
1653 memcpy(ethernet->
addr, LLADDR(ll), 6);
1669 ret =
CMP(a->ss_family, b->ss_family);
1670 if (ret != 0)
return ret;
1672 switch (a->ss_family) {
1674 ret =
CMP(((
struct sockaddr_in
const *)a)->sin_port, ((
struct sockaddr_in
const *)b)->sin_port);
1675 if (ret != 0)
return ret;
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));
1683 ret =
CMP(((
struct sockaddr_in6
const *)a)->sin6_port, ((
struct sockaddr_in6
const *)b)->sin6_port);
1684 if (ret != 0)
return ret;
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;
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));
1699 ret = strcmp(((
struct sockaddr_un
const *)a)->sun_path,
1700 ((
struct sockaddr_un
const *)b)->sun_path);
static int const char char buffer[256]
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
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)
int fr_ipaddr_is_prefix(fr_ipaddr_t const *ipaddr)
Determine if an address is a prefix.
int fr_ipaddr_is_multicast(fr_ipaddr_t const *ipaddr)
Determine if an address is a multicast address.
void fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr)
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
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.
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)
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
static int ip_octet_from_str(uint32_t *out, char const *str)
Parse a single octet of an IPv4 address string.
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.
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)
int8_t fr_sockaddr_cmp(struct sockaddr_storage const *a, struct sockaddr_storage const *b)
bool fr_hostname_lookups
hostname -> IP lookups?
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.
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)
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
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.
char * fr_ipaddr_to_interface(TALLOC_CTX *ctx, fr_ipaddr_t *ipaddr)
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.
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
static struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
Mask off a portion of an IPv6 address.
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
int fr_interface_to_ethernet(char const *interface, fr_ethernet_t *ethernet)
char * fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
Print an interface-id in standard colon notation.
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.
int fr_ipaddr_from_ifname(UNUSED fr_ipaddr_t *out, UNUSED int af, char const *name)
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.
bool fr_reverse_lookups
IP -> hostname lookups?
static struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
Mask off a portion of an IPv4 address.
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
#define FR_IPADDR_STRLEN
Like INET6_ADDRSTRLEN but includes space for the textual Zone ID.
uint32_t scope_id
A host may have multiple link-local interfaces the scope ID allows the application to specify which o...
uint8_t addr[6]
Ethernet address.
union fr_ipaddr_t::@137 addr
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
Struct to represent an ethernet address.
static bool is_integer(char const *value)
Check whether the string is all numbers.
int inet_pton(int af, char const *src, void *dst)
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
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)
#define is_truncated(_ret, _max)
static fr_ipaddr_t my_ipaddr
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
size_t strlcpy(char *dst, char const *src, size_t siz)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define talloc_strdup(_ctx, _str)
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
#define fr_box_strvalue_len(_val, _len)
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out