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 >= htonl((
uint32_t) 0xe0000000)) &&
102 (ipaddr->
addr.v4.s_addr < htonl((
uint32_t) 0xf0000000)))
return 1;
103#ifdef HAVE_STRUCT_SOCKADDR_IN6
104 }
else if (ipaddr->
af == AF_INET6) {
106 if (IN6_IS_ADDR_MULTICAST(
UNCONST(
struct in6_addr *, &(ipaddr->
addr.v6)))) {
129 switch (ipaddr->
af) {
131 return (ipaddr->
prefix < 32);
134 return (ipaddr->
prefix < 128);
152 if (prefix > 32) prefix = 32;
155 if (prefix == 32)
return *ipaddr;
157 if (prefix == 0) ret = 0;
158 else ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
160 return (*(
struct in_addr *)&ret);
172 uint64_t ret[2], *o = ret;
175 if (prefix > 128) prefix = 128;
178 if (prefix == 128)
return *ipaddr;
182 addr = (uint64_t)ipaddr->s6_addr[i] |
183 ((uint64_t)ipaddr->s6_addr[i + 1] << 8) |
184 ((uint64_t)ipaddr->s6_addr[i + 2] << 16) |
185 ((uint64_t)ipaddr->s6_addr[i + 3] << 24) |
186 ((uint64_t)ipaddr->s6_addr[i + 4] << 32) |
187 ((uint64_t)ipaddr->s6_addr[i + 5] << 40) |
188 ((uint64_t)ipaddr->s6_addr[i + 6] << 48) |
189 ((uint64_t)ipaddr->s6_addr[i + 7] << 56);
190 *o++ = 0xffffffffffffffffULL & addr;
198 addr = (uint64_t)ipaddr->s6_addr[i] |
199 ((uint64_t)ipaddr->s6_addr[i + 1] << 8) |
200 ((uint64_t)ipaddr->s6_addr[i + 2] << 16) |
201 ((uint64_t)ipaddr->s6_addr[i + 3] << 24) |
202 ((uint64_t)ipaddr->s6_addr[i + 4] << 32) |
203 ((uint64_t)ipaddr->s6_addr[i + 5] << 40) |
204 ((uint64_t)ipaddr->s6_addr[i + 6] << 48) |
205 ((uint64_t)ipaddr->s6_addr[i + 7] << 56);
206 *o = htonll(~((uint64_t)(0x0000000000000001ULL << (64 - prefix)) - 1)) & addr;
211 return *(
struct in6_addr *) &ret;
259 struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
266#ifdef HAVE_STRUCT_SOCKADDR_IN6
267 if (af == AF_UNSPEC) {
270 for (p = hostname; *p !=
'\0'; p++) {
281 if (af == AF_UNSPEC) af = AF_INET;
285 "hostname lookups are disabled", hostname);
289 out->prefix = (af == AF_INET) ? 32 : 128;
295 memset(&hints, 0,
sizeof(hints));
301 hints.ai_family = AF_UNSPEC;
303 hints.ai_family = af;
306 if ((ret =
getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
326 for (ai = res; ai; ai = ai->ai_next) {
327 if ((af == ai->ai_family) || (af == AF_UNSPEC))
break;
328 if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
333 fr_strerror_printf(
"Failed resolving \"%s\": No records matching requested address family returned",
359 struct sockaddr_storage ss;
372 if ((error =
getnameinfo((
struct sockaddr *)&ss, salen,
out, outlen, NULL, 0,
373 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
394 if ((*p <
'0') || (*p >
'9'))
return -1;
398 while ((*p >=
'0') && (*p <=
'9')) {
403 if (octet > 255)
return -1;
442 for (shift = 24; shift >= 0; shift -= 8) {
444 if (length <= 0)
return -1;
446 addr |= octet << shift;
452 if (!*p || (*p ==
'/'))
break;
457 if (*p !=
'.')
return -1;
461 out->s_addr = htonl(addr);
495 memset(
out, 0,
sizeof(*
out));
520 p = strchr(
value,
'/');
532 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
533 out->addr.v4.s_addr = htonl(INADDR_ANY);
542 out->addr.v4.s_addr = htonl(strtoul(
value, NULL, 0));
544 }
else if (!resolve) {
545 unsigned int a, b, c, d;
551 num = sscanf(
value,
"%u.%u.%u.%u%c", &a, &b, &c, &d, &rest);
552 if ((num == 0) || (num == 5) ||
553 (a > 255) || (b > 255) || (c > 255) || (d > 255)) {
558 out->addr.v4.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
568 if ((
size_t)(p -
value) >= INET_ADDRSTRLEN) {
595 mask = strtoul(p + 1, &eptr, 10);
601 if (eptr[0] !=
'\0') {
603 "got garbage after mask length \"%s\"",
value, eptr);
607 if (mask_bits && (
mask < 32)) {
646 memset(
out, 0,
sizeof(*
out));
670 p = strchr(
value,
'/');
678 p = strchr(
value,
'%');
679 if (p) *(p++) =
'\0';
684 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
685 out->addr.v6 = (
struct in6_addr)IN6ADDR_ANY_INIT;
686 }
else if (!resolve) {
696 if (!p || !*p)
return 0;
701 prefix = strtoul(p, &eptr, 10);
702 if (prefix > UINT32_MAX) {
706 if (eptr[0] !=
'\0') {
708 "got garbage after numerical scope value \"%s\"", p, eptr);
712 out->scope_id = prefix;
717 if ((p -
value) >= INET6_ADDRSTRLEN) {
739 if (ret < 0)
return -1;
742 prefix = strtoul(p + 1, &eptr, 10);
747 if (eptr[0] !=
'\0') {
749 "got garbage after mask length \"%s\"",
value, eptr);
753 if (
mask && (prefix < 128)) {
754 struct in6_addr addr;
757 memcpy(
out->addr.v6.s6_addr, addr.s6_addr,
sizeof(
out->addr.v6.s6_addr));
787 bool hostname =
true;
804 for (i = 0; i < len; i++) {
833 if (
value[i] ==
':') {
842 if (
value[i] ==
'.') {
851 if (
value[i] ==
'/') {
867 if (!ipv4 && !ipv6) {
892 if (ipv6 && !hostname) {
948 char const *p =
value, *q;
959 if (!(q = memchr(p + 1,
']', len - 1))) {
980 q = memchr(p,
':', len);
993 if (len > (
size_t) ((q +
sizeof(
buffer)) -
value)) {
1002 port = strtoul(
buffer, &end, 10);
1003 if (*end !=
'\0')
goto error;
1005 if ((port > UINT16_MAX) || (port == 0)) {
1038 if ((addr->
af == AF_INET) || (addr->
scope_id == 0))
return out;
1042#ifdef WITH_IFINDEX_NAME_RESOLUTION
1049 len =
snprintf(p, outlen - (p -
out),
"%%%s", ifname);
1052 (p -
out) + len, outlen);
1064 (p -
out) + len, outlen);
1093 (p -
out) + len, outlen);
1123 static char const xdigits[] =
"0123456789abcdef";
1124 char const *p, *pch;
1125 int num_id = 0, val = 0, idx = 0;
1127 for (p = ifid_str; ; ++p) {
1128 if (*p ==
':' || *p ==
'\0') {
1135 out[idx] = (val >> 8) & 0xff;
1136 out[idx + 1] = val & 0xff;
1150 }
else if ((pch = strchr(xdigits, tolower((
uint8_t) *p))) != NULL) {
1157 val |= (pch - xdigits);
1177 struct ifreq if_req;
1180 memset(&if_req, 0,
sizeof(if_req));
1181 memset(
out, 0,
sizeof(*
out));
1186 if_req.ifr_addr.sa_family = af;
1187 strlcpy(if_req.ifr_name,
name,
sizeof(if_req.ifr_name));
1189 fd = socket(AF_INET, SOCK_DGRAM, 0);
1194 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1208 (
struct sockaddr_storage *)&if_req.ifr_addr,
1209 sizeof(if_req.ifr_addr)) < 0)
goto error;
1224#ifdef WITH_IFINDEX_NAME_RESOLUTION
1233char *fr_ifname_from_ifindex(
char out[
static IFNAMSIZ],
int ifindex)
1235#ifdef HAVE_IF_INDEXTONAME
1236 if (!if_indextoname(ifindex,
out)) {
1241 struct ifreq if_req;
1244 memset(&if_req, 0,
sizeof(if_req));
1245 if_req.ifr_ifindex = ifindex;
1247 fd = socket(AF_INET, SOCK_DGRAM, 0);
1261 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1272#ifdef WITH_IFINDEX_IPADDR_RESOLUTION
1288int fr_ipaddr_from_ifindex(
fr_ipaddr_t *
out,
int fd,
int af,
int ifindex)
1290 struct ifreq if_req;
1293 memset(&if_req, 0,
sizeof(if_req));
1294 memset(
out, 0,
sizeof(*
out));
1297 if_req.ifr_ifindex = ifindex;
1304 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1308#elif defined(HAVE_IF_INDEXTONAME)
1309 if (!if_indextoname(ifindex, if_req.ifr_name)) {
1314# error Need SIOCGIFNAME or if_indextoname
1321 if_req.ifr_addr.sa_family = af;
1323 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1336 (
struct sockaddr_storage *)&if_req.ifr_addr,
1337 sizeof(if_req.ifr_addr)) < 0)
return -1;
1368 len = ((a->
prefix + 7) & -8) >> 3;
1371 ret = memcmp(&a->
addr.v4, &b->
addr.v4, len);
1374#ifdef HAVE_STRUCT_SOCKADDR_IN6
1377 ret = memcmp(&a->
addr.v6, &b->
addr.v6, len);
1403 memset(sa, 0,
sizeof(*sa));
1405 if (ipaddr->
af == AF_INET) {
1406 struct sockaddr_in s4;
1408 *salen =
sizeof(s4);
1410 memset(&s4, 0,
sizeof(s4));
1411 s4.sin_family = AF_INET;
1412 s4.sin_addr = ipaddr->
addr.v4;
1413 s4.sin_port = htons(port);
1414 memset(sa, 0,
sizeof(*sa));
1415 memcpy(sa, &s4,
sizeof(s4));
1417#ifdef HAVE_STRUCT_SOCKADDR_IN6
1418 }
else if (ipaddr->
af == AF_INET6) {
1419 struct sockaddr_in6 s6;
1421 *salen =
sizeof(s6);
1423 memset(&s6, 0,
sizeof(s6));
1424 s6.sin6_family = AF_INET6;
1425 s6.sin6_addr = ipaddr->
addr.v6;
1426 s6.sin6_port = htons(port);
1427 s6.sin6_scope_id = ipaddr->
scope_id;
1428 memset(sa, 0,
sizeof(*sa));
1429 memcpy(sa, &s6,
sizeof(s6));
1450 struct sockaddr_storage
const *sa, socklen_t salen)
1452 memset(ipaddr, 0,
sizeof(*ipaddr));
1454 if (sa->ss_family == AF_INET) {
1455 struct sockaddr_in s4;
1457 if (salen <
sizeof(s4)) {
1462 memcpy(&s4, sa,
sizeof(s4));
1463 ipaddr->
af = AF_INET;
1465 ipaddr->
addr.v4 = s4.sin_addr;
1466 if (port) *port = ntohs(s4.sin_port);
1469#ifdef HAVE_STRUCT_SOCKADDR_IN6
1470 }
else if (sa->ss_family == AF_INET6) {
1471 struct sockaddr_in6 s6;
1473 if (salen <
sizeof(s6)) {
1478 memcpy(&s6, sa,
sizeof(s6));
1479 ipaddr->
af = AF_INET6;
1481 ipaddr->
addr.v6 = s6.sin6_addr;
1482 if (port) *port = ntohs(s6.sin6_port);
1483 ipaddr->
scope_id = s6.sin6_scope_id;
1496 struct ifaddrs *list = NULL;
1507 if (getifaddrs(&list) < 0)
return;
1509 for (i = list; i != NULL; i = i->ifa_next) {
1512 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1515 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1529 ipaddr->
scope_id = if_nametoindex(i->ifa_name);
1540 struct ifaddrs *list = NULL;
1542 char *
interface = NULL;
1547 if (getifaddrs(&list) < 0)
return NULL;
1549 for (i = list; i != NULL; i = i->ifa_next) {
1553 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1556 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1583 struct ifaddrs *list = NULL;
1587 if (getifaddrs(&list) < 0)
return -1;
1589 for (i = list; i != NULL; i = i->ifa_next) {
1591 struct sockaddr_storage sa;
1593 if (!i->ifa_addr || !i->ifa_name || ((af != AF_UNSPEC) && (af != i->ifa_addr->sa_family)))
continue;
1594 if (strcmp(i->ifa_name, interface) != 0)
continue;
1596 memcpy(&sa, i->ifa_addr,
sizeof(
struct sockaddr_in6));
1623#define AF_LINK AF_PACKET
1628 struct ifaddrs *list = NULL;
1632 if (getifaddrs(&list) < 0)
return -1;
1634 for (i = list; i != NULL; i = i->ifa_next) {
1635 if (!i->ifa_addr || !i->ifa_name || (i->ifa_addr->sa_family !=
AF_LINK))
continue;
1636 if (strcmp(i->ifa_name, interface) != 0)
continue;
1638#if defined(__linux__) || defined(__EMSCRIPTEN__)
1640 struct sockaddr_ll *ll;
1642 ll = (
struct sockaddr_ll *) i->ifa_addr;
1643 if ((ll->sll_hatype != 1) || (ll->sll_halen != 6))
continue;
1645 memcpy(ethernet->
addr, ll->sll_addr, 6);
1649 struct sockaddr_dl *ll;
1651 ll = (
struct sockaddr_dl *) i->ifa_addr;
1652 if (ll->sdl_alen != 6)
continue;
1654 memcpy(ethernet->
addr, LLADDR(ll), 6);
1670 ret =
CMP(a->ss_family, b->ss_family);
1671 if (ret != 0)
return ret;
1673 switch (a->ss_family) {
1675 ret =
CMP(((
struct sockaddr_in
const *)a)->sin_port, ((
struct sockaddr_in
const *)b)->sin_port);
1676 if (ret != 0)
return ret;
1678 ret = memcmp(&((
struct sockaddr_in
const *)a)->sin_addr,
1679 &((
struct sockaddr_in
const *)b)->sin_addr,
1680 sizeof(((
struct sockaddr_in
const *)a)->sin_addr));
1684 ret =
CMP(((
struct sockaddr_in6
const *)a)->sin6_port, ((
struct sockaddr_in6
const *)b)->sin6_port);
1685 if (ret != 0)
return ret;
1691 ret =
CMP(((
struct sockaddr_in6
const *)a)->sin6_scope_id, ((
struct sockaddr_in6
const *)b)->sin6_scope_id);
1692 if (ret != 0)
return ret;
1694 ret = memcmp(&((
struct sockaddr_in6
const *)a)->sin6_addr,
1695 &((
struct sockaddr_in6
const *)b)->sin6_addr,
1696 sizeof(((
struct sockaddr_in6
const *)a)->sin6_addr));
1700 ret = strcmp(((
struct sockaddr_un
const *)a)->sun_path,
1701 ((
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