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>
31#include <net/if_arp.h>
37#if defined(HAVE_LINUX_IF_PACKET_H)
38# include <linux/if_packet.h>
39# include <linux/if_ether.h>
43#elif defined(HAVE_NET_IF_DL_H)
44# include <net/if_dl.h>
48#elif defined(HAVE_NETPACKET_PACKET_H)
49# include <netpacket/packet.h>
66 if (ipaddr->
af == AF_INET) {
67 if (ipaddr->
addr.v4.s_addr == htonl(INADDR_ANY)) {
71#ifdef HAVE_STRUCT_SOCKADDR_IN6
72 }
else if (ipaddr->
af == AF_INET6) {
74 if (IN6_IS_ADDR_UNSPECIFIED(
UNCONST(
struct in6_addr *, &(ipaddr->
addr.v6)))) {
97 if (ipaddr->
af == AF_INET) {
101 if ((ipaddr->
addr.v4.s_addr >= 3758096384) && (ipaddr->
addr.v4.s_addr <= 4026531839))
return 1;
102#ifdef HAVE_STRUCT_SOCKADDR_IN6
103 }
else if (ipaddr->
af == AF_INET6) {
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);
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));
517 p = strchr(
value,
'/');
529 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
530 out->addr.v4.s_addr = htonl(INADDR_ANY);
539 out->addr.v4.s_addr = htonl(strtoul(
value, NULL, 0));
541 }
else if (!resolve) {
542 unsigned int a, b, c, d;
548 num = sscanf(
value,
"%u.%u.%u.%u%c", &a, &b, &c, &d, &rest);
549 if ((num == 0) || (num == 5) ||
550 (a > 255) || (b > 255) || (c > 255) || (d > 255)) {
555 out->addr.v4.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
565 if ((
size_t)(p -
value) >= INET_ADDRSTRLEN) {
592 mask = strtoul(p + 1, &eptr, 10);
598 if (eptr[0] !=
'\0') {
600 "got garbage after mask length \"%s\"",
value, eptr);
604 if (mask_bits && (
mask < 32)) {
643 memset(
out, 0,
sizeof(*
out));
667 p = strchr(
value,
'/');
675 p = strchr(
value,
'%');
676 if (p) *(p++) =
'\0';
681 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
682 out->addr.v6 = (
struct in6_addr)IN6ADDR_ANY_INIT;
683 }
else if (!resolve) {
693 if (!p || !*p)
return 0;
698 prefix = strtoul(p, &eptr, 10);
699 if (prefix > UINT32_MAX) {
703 if (eptr[0] !=
'\0') {
705 "got garbage after numerical scope value \"%s\"", p, eptr);
712 if ((p -
value) >= INET6_ADDRSTRLEN) {
734 if (ret < 0)
return -1;
737 prefix = strtoul(p + 1, &eptr, 10);
742 if (eptr[0] !=
'\0') {
744 "got garbage after mask length \"%s\"",
value, eptr);
748 if (
mask && (prefix < 128)) {
749 struct in6_addr addr;
752 memcpy(
out->addr.v6.s6_addr, addr.s6_addr,
sizeof(
out->addr.v6.s6_addr));
782 bool hostname =
true;
797 for (i = 0; i < len; i++) {
826 if (
value[i] ==
':') {
835 if (
value[i] ==
'.') {
844 if (
value[i] ==
'/') {
860 if (!ipv4 && !ipv6) {
885 if (ipv6 && !hostname) {
941 char const *p =
value, *q;
952 if (!(q = memchr(p + 1,
']', len - 1))) {
973 q = memchr(p,
':', len);
986 if (len > (
size_t) ((q +
sizeof(
buffer)) -
value)) {
995 port = strtoul(
buffer, &end, 10);
996 if (*end !=
'\0')
goto error;
998 if ((port > UINT16_MAX) || (port == 0)) {
1031 if ((addr->
af == AF_INET) || (addr->
scope_id == 0))
return out;
1035#ifdef WITH_IFINDEX_NAME_RESOLUTION
1042 len =
snprintf(p, outlen - (p -
out),
"%%%s", ifname);
1045 (p -
out) + len, outlen);
1057 (p -
out) + len, outlen);
1086 (p -
out) + len, outlen);
1116 static char const xdigits[] =
"0123456789abcdef";
1117 char const *p, *pch;
1118 int num_id = 0, val = 0, idx = 0;
1120 for (p = ifid_str; ; ++p) {
1121 if (*p ==
':' || *p ==
'\0') {
1128 out[idx] = (val >> 8) & 0xff;
1129 out[idx + 1] = val & 0xff;
1143 }
else if ((pch = strchr(xdigits, tolower((
uint8_t) *p))) != NULL) {
1150 val |= (pch - xdigits);
1170 struct ifreq if_req;
1173 memset(&if_req, 0,
sizeof(if_req));
1174 memset(
out, 0,
sizeof(*
out));
1179 if_req.ifr_addr.sa_family = af;
1180 strlcpy(if_req.ifr_name,
name,
sizeof(if_req.ifr_name));
1182 fd = socket(AF_INET, SOCK_DGRAM, 0);
1189 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1201 (
struct sockaddr_storage *)&if_req.ifr_addr,
1202 sizeof(if_req.ifr_addr)) < 0)
goto error;
1217#ifdef WITH_IFINDEX_NAME_RESOLUTION
1226char *fr_ifname_from_ifindex(
char out[
static IFNAMSIZ],
int ifindex)
1228#ifdef HAVE_IF_INDEXTONAME
1229 if (!if_indextoname(ifindex,
out)) {
1234 struct ifreq if_req;
1237 memset(&if_req, 0,
sizeof(if_req));
1238 if_req.ifr_ifindex = ifindex;
1240 fd = socket(AF_INET, SOCK_DGRAM, 0);
1254 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1265#ifdef WITH_IFINDEX_IPADDR_RESOLUTION
1281int fr_ipaddr_from_ifindex(
fr_ipaddr_t *
out,
int fd,
int af,
int ifindex)
1283 struct ifreq if_req;
1286 memset(&if_req, 0,
sizeof(if_req));
1287 memset(
out, 0,
sizeof(*
out));
1290 if_req.ifr_ifindex = ifindex;
1297 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1301#elif defined(HAVE_IF_INDEXTONAME)
1302 if (!if_indextoname(ifindex, if_req.ifr_name)) {
1307# error Need SIOCGIFNAME or if_indextoname
1314 if_req.ifr_addr.sa_family = af;
1316 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1329 (
struct sockaddr_storage *)&if_req.ifr_addr,
1330 sizeof(if_req.ifr_addr)) < 0)
return -1;
1361 len = ((a->
prefix + 7) & -8) >> 3;
1364 ret = memcmp(&a->
addr.v4, &b->
addr.v4, len);
1367#ifdef HAVE_STRUCT_SOCKADDR_IN6
1370 ret = memcmp(&a->
addr.v6, &b->
addr.v6, len);
1396 memset(sa, 0,
sizeof(*sa));
1398 if (ipaddr->
af == AF_INET) {
1399 struct sockaddr_in s4;
1401 *salen =
sizeof(s4);
1403 memset(&s4, 0,
sizeof(s4));
1404 s4.sin_family = AF_INET;
1405 s4.sin_addr = ipaddr->
addr.v4;
1406 s4.sin_port = htons(port);
1407 memset(sa, 0,
sizeof(*sa));
1408 memcpy(sa, &s4,
sizeof(s4));
1410#ifdef HAVE_STRUCT_SOCKADDR_IN6
1411 }
else if (ipaddr->
af == AF_INET6) {
1412 struct sockaddr_in6 s6;
1414 *salen =
sizeof(s6);
1416 memset(&s6, 0,
sizeof(s6));
1417 s6.sin6_family = AF_INET6;
1418 s6.sin6_addr = ipaddr->
addr.v6;
1419 s6.sin6_port = htons(port);
1420 s6.sin6_scope_id = ipaddr->
scope_id;
1421 memset(sa, 0,
sizeof(*sa));
1422 memcpy(sa, &s6,
sizeof(s6));
1443 struct sockaddr_storage
const *sa, socklen_t salen)
1445 memset(ipaddr, 0,
sizeof(*ipaddr));
1447 if (sa->ss_family == AF_INET) {
1448 struct sockaddr_in s4;
1450 if (salen <
sizeof(s4)) {
1455 memcpy(&s4, sa,
sizeof(s4));
1456 ipaddr->
af = AF_INET;
1458 ipaddr->
addr.v4 = s4.sin_addr;
1459 if (port) *port = ntohs(s4.sin_port);
1462#ifdef HAVE_STRUCT_SOCKADDR_IN6
1463 }
else if (sa->ss_family == AF_INET6) {
1464 struct sockaddr_in6 s6;
1466 if (salen <
sizeof(s6)) {
1471 memcpy(&s6, sa,
sizeof(s6));
1472 ipaddr->
af = AF_INET6;
1474 ipaddr->
addr.v6 = s6.sin6_addr;
1475 if (port) *port = ntohs(s6.sin6_port);
1476 ipaddr->
scope_id = s6.sin6_scope_id;
1489 struct ifaddrs *list = NULL;
1500 if (getifaddrs(&list) < 0)
return;
1502 for (i = list; i != NULL; i = i->ifa_next) {
1505 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1508 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1522 ipaddr->
scope_id = if_nametoindex(i->ifa_name);
1533 struct ifaddrs *list = NULL;
1535 char *
interface = NULL;
1540 if (getifaddrs(&list) < 0)
return NULL;
1542 for (i = list; i != NULL; i = i->ifa_next) {
1546 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1549 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1564 interface = talloc_strdup(ctx, i->ifa_name);
1576 struct ifaddrs *list = NULL;
1580 if (getifaddrs(&list) < 0)
return -1;
1582 for (i = list; i != NULL; i = i->ifa_next) {
1584 struct sockaddr_storage sa;
1586 if (!i->ifa_addr || !i->ifa_name || ((af != AF_UNSPEC) && (af != i->ifa_addr->sa_family)))
continue;
1587 if (strcmp(i->ifa_name, interface) != 0)
continue;
1589 memcpy(&sa, i->ifa_addr,
sizeof(
struct sockaddr_in6));
1616#define AF_LINK AF_PACKET
1621 struct ifaddrs *list = NULL;
1625 if (getifaddrs(&list) < 0)
return -1;
1627 for (i = list; i != NULL; i = i->ifa_next) {
1628 if (!i->ifa_addr || !i->ifa_name || (i->ifa_addr->sa_family !=
AF_LINK))
continue;
1629 if (strcmp(i->ifa_name, interface) != 0)
continue;
1631#if defined(__linux__) || defined(__EMSCRIPTEN__)
1633 struct sockaddr_ll *ll;
1635 ll = (
struct sockaddr_ll *) i->ifa_addr;
1636 if ((ll->sll_hatype != 1) || (ll->sll_halen != 6))
continue;
1638 memcpy(ethernet->
addr, ll->sll_addr, 6);
1642 struct sockaddr_dl *ll;
1644 ll = (
struct sockaddr_dl *) i->ifa_addr;
1645 if (ll->sdl_alen != 6)
continue;
1647 memcpy(ethernet->
addr, LLADDR(ll), 6);
1663 ret =
CMP(a->ss_family, b->ss_family);
1664 if (ret != 0)
return 0;
1666 switch (a->ss_family) {
1668 ret =
CMP(((
struct sockaddr_in
const *)a)->sin_port, ((
struct sockaddr_in
const *)b)->sin_port);
1669 if (ret != 0)
return ret;
1671 ret = memcmp(&((
struct sockaddr_in
const *)a)->sin_addr,
1672 &((
struct sockaddr_in
const *)b)->sin_addr,
1673 sizeof(((
struct sockaddr_in
const *)a)->sin_addr));
1677 ret =
CMP(((
struct sockaddr_in6
const *)a)->sin6_port, ((
struct sockaddr_in6
const *)b)->sin6_port);
1678 if (ret != 0)
return ret;
1684 ret =
CMP(((
struct sockaddr_in6
const *)a)->sin6_scope_id, ((
struct sockaddr_in6
const *)b)->sin6_scope_id);
1685 if (ret != 0)
return ret;
1687 ret = memcmp(&((
struct sockaddr_in6
const *)a)->sin6_addr,
1688 &((
struct sockaddr_in6
const *)b)->sin6_addr,
1689 sizeof(((
struct sockaddr_in6
const *)a)->sin6_addr));
1693 ret = strcmp(((
struct sockaddr_un
const *)a)->sun_path,
1694 ((
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::@135 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 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