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>
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 >= 3758096384) && (ipaddr->
addr.v4.s_addr <= 4026531839))
return 1;
101 #ifdef HAVE_STRUCT_SOCKADDR_IN6
102 }
else if (ipaddr->
af == AF_INET6) {
104 if (IN6_IS_ADDR_MULTICAST(
UNCONST(
struct in6_addr *, &(ipaddr->
addr.v6)))) {
127 switch (ipaddr->
af) {
129 return (ipaddr->
prefix < 32);
132 return (ipaddr->
prefix < 128);
150 if (prefix > 32) prefix = 32;
153 if (prefix == 32)
return *ipaddr;
155 if (prefix == 0) ret = 0;
156 else ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
158 return (*(
struct in_addr *)&ret);
169 uint64_t
const *p = (uint64_t
const *) ipaddr;
171 uint64_t ret[2], *o = ret;
173 if (prefix > 128) prefix = 128;
176 if (prefix == 128)
return *ipaddr;
180 memcpy(&addr, p,
sizeof(addr));
181 *o++ = 0xffffffffffffffffULL & addr;
189 memcpy(&addr, p,
sizeof(addr));
190 *o = htonll(~((uint64_t)(0x0000000000000001ULL << (64 - prefix)) - 1)) & addr;
195 return *(
struct in6_addr *) &ret;
243 struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
250 #ifdef HAVE_STRUCT_SOCKADDR_IN6
251 if (af == AF_UNSPEC) {
254 for (p =
hostname; *p !=
'\0'; p++) {
265 if (af == AF_UNSPEC) af = AF_INET;
269 "hostname lookups are disabled",
hostname);
279 memset(&hints, 0,
sizeof(hints));
285 hints.ai_family = AF_UNSPEC;
287 hints.ai_family = af;
310 for (ai = res; ai; ai = ai->ai_next) {
311 if ((af == ai->ai_family) || (af == AF_UNSPEC))
break;
312 if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
317 fr_strerror_printf(
"Failed resolving \"%s\": No records matching requested address family returned",
343 struct sockaddr_storage ss;
356 if ((error =
getnameinfo((
struct sockaddr *)&ss, salen,
out, outlen, NULL, 0,
357 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
378 if ((*p <
'0') || (*p >
'9'))
return -1;
382 while ((*p >=
'0') && (*p <=
'9')) {
387 if (octet > 255)
return -1;
426 for (shift = 24; shift >= 0; shift -= 8) {
428 if (length <= 0)
return -1;
430 addr |= octet << shift;
436 if (!*p || (*p ==
'/'))
break;
441 if (*p !=
'.')
return -1;
445 out->s_addr = htonl(addr);
479 memset(
out, 0,
sizeof(*
out));
502 p = strchr(
value,
'/');
514 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
515 out->addr.v4.s_addr = htonl(INADDR_ANY);
524 out->addr.v4.s_addr = htonl(strtoul(
value, NULL, 0));
526 }
else if (!resolve) {
527 unsigned int a, b, c, d;
533 num = sscanf(
value,
"%u.%u.%u.%u%c", &a, &b, &c, &d, &rest);
534 if ((num == 0) || (num == 5) ||
535 (a > 255) || (b > 255) || (c > 255) || (d > 255)) {
540 out->addr.v4.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
550 if ((
size_t)(p -
value) >= INET_ADDRSTRLEN) {
577 mask = strtoul(p + 1, &eptr, 10);
583 if (eptr[0] !=
'\0') {
585 "got garbage after mask length \"%s\"",
value, eptr);
589 if (mask_bits && (
mask < 32)) {
628 memset(
out, 0,
sizeof(*
out));
652 p = strchr(
value,
'/');
660 p = strchr(
value,
'%');
661 if (p) *(p++) =
'\0';
666 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
667 out->addr.v6 = (
struct in6_addr)IN6ADDR_ANY_INIT;
668 }
else if (!resolve) {
678 if (!p || !*p)
return 0;
683 prefix = strtoul(p, &eptr, 10);
684 if (prefix > UINT32_MAX) {
688 if (eptr[0] !=
'\0') {
690 "got garbage after numerical scope value \"%s\"", p, eptr);
697 if ((p -
value) >= INET6_ADDRSTRLEN) {
719 if (ret < 0)
return -1;
722 prefix = strtoul(p + 1, &eptr, 10);
727 if (eptr[0] !=
'\0') {
729 "got garbage after mask length \"%s\"",
value, eptr);
733 if (
mask && (prefix < 128)) {
734 struct in6_addr addr;
737 memcpy(
out->addr.v6.s6_addr, addr.s6_addr,
sizeof(
out->addr.v6.s6_addr));
782 for (i = 0; i < len; i++) {
811 if (
value[i] ==
':') {
820 if (
value[i] ==
'.') {
829 if (
value[i] ==
'/') {
845 if (!ipv4 && !ipv6) {
926 char const *p =
value, *q;
937 if (!(q = memchr(p + 1,
']', len - 1))) {
958 q = memchr(p,
':', len);
971 if (len > (
size_t) ((q +
sizeof(
buffer)) -
value)) {
980 port = strtoul(
buffer, &end, 10);
981 if (*end !=
'\0')
goto error;
983 if ((port > UINT16_MAX) || (port == 0)) {
1016 if ((addr->
af == AF_INET) || (addr->
scope_id == 0))
return out;
1020 #ifdef WITH_IFINDEX_NAME_RESOLUTION
1027 len =
snprintf(p, outlen - (p -
out),
"%%%s", ifname);
1030 (p -
out) + len, outlen);
1042 (p -
out) + len, outlen);
1071 (p -
out) + len, outlen);
1101 static char const xdigits[] =
"0123456789abcdef";
1102 char const *p, *pch;
1103 int num_id = 0, val = 0, idx = 0;
1105 for (p = ifid_str; ; ++p) {
1106 if (*p ==
':' || *p ==
'\0') {
1113 out[idx] = (val >> 8) & 0xff;
1114 out[idx + 1] = val & 0xff;
1128 }
else if ((pch = strchr(xdigits, tolower((
uint8_t) *p))) != NULL) {
1135 val |= (pch - xdigits);
1155 struct ifreq if_req;
1158 memset(&if_req, 0,
sizeof(if_req));
1159 memset(
out, 0,
sizeof(*
out));
1164 if_req.ifr_addr.sa_family = af;
1165 strlcpy(if_req.ifr_name,
name,
sizeof(if_req.ifr_name));
1167 fd = socket(AF_INET, SOCK_DGRAM, 0);
1174 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1186 (
struct sockaddr_storage *)&if_req.ifr_addr,
1187 sizeof(if_req.ifr_addr)) < 0)
goto error;
1202 #ifdef WITH_IFINDEX_NAME_RESOLUTION
1211 char *fr_ifname_from_ifindex(
char out[
static IFNAMSIZ],
int ifindex)
1213 #ifdef HAVE_IF_INDEXTONAME
1214 if (!if_indextoname(ifindex,
out)) {
1219 struct ifreq if_req;
1222 memset(&if_req, 0,
sizeof(if_req));
1223 if_req.ifr_ifindex = ifindex;
1225 fd = socket(AF_INET, SOCK_DGRAM, 0);
1239 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1250 #ifdef WITH_IFINDEX_IPADDR_RESOLUTION
1266 int fr_ipaddr_from_ifindex(
fr_ipaddr_t *
out,
int fd,
int af,
int ifindex)
1268 struct ifreq if_req;
1271 memset(&if_req, 0,
sizeof(if_req));
1272 memset(
out, 0,
sizeof(*
out));
1275 if_req.ifr_ifindex = ifindex;
1282 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1286 #elif defined(HAVE_IF_INDEXTONAME)
1287 if (!if_indextoname(ifindex, if_req.ifr_name)) {
1292 # error Need SIOCGIFNAME or if_indextoname
1299 if_req.ifr_addr.sa_family = af;
1301 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1314 (
struct sockaddr_storage *)&if_req.ifr_addr,
1315 sizeof(if_req.ifr_addr)) < 0)
return -1;
1346 len = ((a->
prefix + 7) & -8) >> 3;
1349 ret = memcmp(&a->
addr.v4, &b->
addr.v4, len);
1352 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1355 ret = memcmp(&a->
addr.v6, &b->
addr.v6, len);
1381 memset(sa, 0,
sizeof(*sa));
1383 if (ipaddr->
af == AF_INET) {
1384 struct sockaddr_in s4;
1386 *salen =
sizeof(s4);
1388 memset(&s4, 0,
sizeof(s4));
1389 s4.sin_family = AF_INET;
1390 s4.sin_addr = ipaddr->
addr.v4;
1391 s4.sin_port = htons(port);
1392 memset(sa, 0,
sizeof(*sa));
1393 memcpy(sa, &s4,
sizeof(s4));
1395 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1396 }
else if (ipaddr->
af == AF_INET6) {
1397 struct sockaddr_in6 s6;
1399 *salen =
sizeof(s6);
1401 memset(&s6, 0,
sizeof(s6));
1402 s6.sin6_family = AF_INET6;
1403 s6.sin6_addr = ipaddr->
addr.v6;
1404 s6.sin6_port = htons(port);
1405 s6.sin6_scope_id = ipaddr->
scope_id;
1406 memset(sa, 0,
sizeof(*sa));
1407 memcpy(sa, &s6,
sizeof(s6));
1428 struct sockaddr_storage
const *sa, socklen_t salen)
1430 memset(ipaddr, 0,
sizeof(*ipaddr));
1432 if (sa->ss_family == AF_INET) {
1433 struct sockaddr_in s4;
1435 if (salen <
sizeof(s4)) {
1440 memcpy(&s4, sa,
sizeof(s4));
1441 ipaddr->
af = AF_INET;
1443 ipaddr->
addr.v4 = s4.sin_addr;
1444 if (port) *port = ntohs(s4.sin_port);
1447 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1448 }
else if (sa->ss_family == AF_INET6) {
1449 struct sockaddr_in6 s6;
1451 if (salen <
sizeof(s6)) {
1456 memcpy(&s6, sa,
sizeof(s6));
1457 ipaddr->
af = AF_INET6;
1459 ipaddr->
addr.v6 = s6.sin6_addr;
1460 if (port) *port = ntohs(s6.sin6_port);
1461 ipaddr->
scope_id = s6.sin6_scope_id;
1474 struct ifaddrs *list = NULL;
1485 if (getifaddrs(&list) < 0)
return;
1487 for (i = list; i != NULL; i = i->ifa_next) {
1490 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1493 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1507 ipaddr->
scope_id = if_nametoindex(i->ifa_name);
1518 struct ifaddrs *list = NULL;
1520 char *
interface = NULL;
1525 if (getifaddrs(&list) < 0)
return NULL;
1527 for (i = list; i != NULL; i = i->ifa_next) {
1531 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1534 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1549 interface = talloc_strdup(ctx, i->ifa_name);
1561 struct ifaddrs *list = NULL;
1565 if (getifaddrs(&list) < 0)
return -1;
1567 for (i = list; i != NULL; i = i->ifa_next) {
1569 struct sockaddr_storage sa;
1571 if (!i->ifa_addr || !i->ifa_name || ((af != AF_UNSPEC) && (af != i->ifa_addr->sa_family)))
continue;
1572 if (strcmp(i->ifa_name, interface) != 0)
continue;
1574 memcpy(&sa, i->ifa_addr,
sizeof(
struct sockaddr_in6));
1601 #define AF_LINK AF_PACKET
1606 struct ifaddrs *list = NULL;
1610 if (getifaddrs(&list) < 0)
return -1;
1612 for (i = list; i != NULL; i = i->ifa_next) {
1613 if (!i->ifa_addr || !i->ifa_name || (i->ifa_addr->sa_family !=
AF_LINK))
continue;
1614 if (strcmp(i->ifa_name, interface) != 0)
continue;
1616 #if defined(__linux__) || defined(__EMSCRIPTEN__)
1618 struct sockaddr_ll *ll;
1620 ll = (
struct sockaddr_ll *) i->ifa_addr;
1621 if ((ll->sll_hatype != 1) || (ll->sll_halen != 6))
continue;
1623 memcpy(ethernet->
addr, ll->sll_addr, 6);
1627 struct sockaddr_dl *ll;
1629 ll = (
struct sockaddr_dl *) i->ifa_addr;
1630 if (ll->sdl_alen != 6)
continue;
1632 memcpy(ethernet->
addr, LLADDR(ll), 6);
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)
void freeaddrinfo(struct addrinfo *ai)
char const * gai_strerror(int ecode)
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)
char * fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
Print an interface-id in standard colon notation.
int fr_ipaddr_is_prefix(fr_ipaddr_t const *ipaddr)
Determine if an address is a prefix.
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_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)
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.
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.
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)
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
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.
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_ntop(char out[static FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print the address portion of a fr_ipaddr_t.
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.
char * fr_ipaddr_to_interface(TALLOC_CTX *ctx, fr_ipaddr_t *ipaddr)
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.
union fr_ipaddr_t::@121 addr
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.
#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
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
if(!subtype_vp) goto fail
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