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);
170 uint64_t ret[2], *o = ret;
173 if (prefix > 128) prefix = 128;
176 if (prefix == 128)
return *ipaddr;
180 addr = (uint64_t)ipaddr->s6_addr[i] |
181 ((uint64_t)ipaddr->s6_addr[i + 1] << 8) |
182 ((uint64_t)ipaddr->s6_addr[i + 2] << 16) |
183 ((uint64_t)ipaddr->s6_addr[i + 3] << 24) |
184 ((uint64_t)ipaddr->s6_addr[i + 4] << 32) |
185 ((uint64_t)ipaddr->s6_addr[i + 5] << 40) |
186 ((uint64_t)ipaddr->s6_addr[i + 6] << 48) |
187 ((uint64_t)ipaddr->s6_addr[i + 7] << 56);
188 *o++ = 0xffffffffffffffffULL & addr;
196 addr = (uint64_t)ipaddr->s6_addr[i] |
197 ((uint64_t)ipaddr->s6_addr[i + 1] << 8) |
198 ((uint64_t)ipaddr->s6_addr[i + 2] << 16) |
199 ((uint64_t)ipaddr->s6_addr[i + 3] << 24) |
200 ((uint64_t)ipaddr->s6_addr[i + 4] << 32) |
201 ((uint64_t)ipaddr->s6_addr[i + 5] << 40) |
202 ((uint64_t)ipaddr->s6_addr[i + 6] << 48) |
203 ((uint64_t)ipaddr->s6_addr[i + 7] << 56);
204 *o = htonll(~((uint64_t)(0x0000000000000001ULL << (64 - prefix)) - 1)) & addr;
209 return *(
struct in6_addr *) &ret;
257 struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
264 #ifdef HAVE_STRUCT_SOCKADDR_IN6
265 if (af == AF_UNSPEC) {
268 for (p =
hostname; *p !=
'\0'; p++) {
279 if (af == AF_UNSPEC) af = AF_INET;
283 "hostname lookups are disabled",
hostname);
293 memset(&hints, 0,
sizeof(hints));
299 hints.ai_family = AF_UNSPEC;
301 hints.ai_family = af;
324 for (ai = res; ai; ai = ai->ai_next) {
325 if ((af == ai->ai_family) || (af == AF_UNSPEC))
break;
326 if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
331 fr_strerror_printf(
"Failed resolving \"%s\": No records matching requested address family returned",
357 struct sockaddr_storage ss;
370 if ((error =
getnameinfo((
struct sockaddr *)&ss, salen,
out, outlen, NULL, 0,
371 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
392 if ((*p <
'0') || (*p >
'9'))
return -1;
396 while ((*p >=
'0') && (*p <=
'9')) {
401 if (octet > 255)
return -1;
440 for (shift = 24; shift >= 0; shift -= 8) {
442 if (length <= 0)
return -1;
444 addr |= octet << shift;
450 if (!*p || (*p ==
'/'))
break;
455 if (*p !=
'.')
return -1;
459 out->s_addr = htonl(addr);
493 memset(
out, 0,
sizeof(*
out));
516 p = strchr(
value,
'/');
528 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
529 out->addr.v4.s_addr = htonl(INADDR_ANY);
538 out->addr.v4.s_addr = htonl(strtoul(
value, NULL, 0));
540 }
else if (!resolve) {
541 unsigned int a, b, c, d;
547 num = sscanf(
value,
"%u.%u.%u.%u%c", &a, &b, &c, &d, &rest);
548 if ((num == 0) || (num == 5) ||
549 (a > 255) || (b > 255) || (c > 255) || (d > 255)) {
554 out->addr.v4.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
564 if ((
size_t)(p -
value) >= INET_ADDRSTRLEN) {
591 mask = strtoul(p + 1, &eptr, 10);
597 if (eptr[0] !=
'\0') {
599 "got garbage after mask length \"%s\"",
value, eptr);
603 if (mask_bits && (
mask < 32)) {
642 memset(
out, 0,
sizeof(*
out));
666 p = strchr(
value,
'/');
674 p = strchr(
value,
'%');
675 if (p) *(p++) =
'\0';
680 if ((
value[0] ==
'*') && (
value[1] ==
'\0')) {
681 out->addr.v6 = (
struct in6_addr)IN6ADDR_ANY_INIT;
682 }
else if (!resolve) {
692 if (!p || !*p)
return 0;
697 prefix = strtoul(p, &eptr, 10);
698 if (prefix > UINT32_MAX) {
702 if (eptr[0] !=
'\0') {
704 "got garbage after numerical scope value \"%s\"", p, eptr);
711 if ((p -
value) >= INET6_ADDRSTRLEN) {
733 if (ret < 0)
return -1;
736 prefix = strtoul(p + 1, &eptr, 10);
741 if (eptr[0] !=
'\0') {
743 "got garbage after mask length \"%s\"",
value, eptr);
747 if (
mask && (prefix < 128)) {
748 struct in6_addr addr;
751 memcpy(
out->addr.v6.s6_addr, addr.s6_addr,
sizeof(
out->addr.v6.s6_addr));
796 for (i = 0; i < len; i++) {
825 if (
value[i] ==
':') {
834 if (
value[i] ==
'.') {
843 if (
value[i] ==
'/') {
859 if (!ipv4 && !ipv6) {
940 char const *p =
value, *q;
951 if (!(q = memchr(p + 1,
']', len - 1))) {
972 q = memchr(p,
':', len);
985 if (len > (
size_t) ((q +
sizeof(
buffer)) -
value)) {
994 port = strtoul(
buffer, &end, 10);
995 if (*end !=
'\0')
goto error;
997 if ((port > UINT16_MAX) || (port == 0)) {
1030 if ((addr->
af == AF_INET) || (addr->
scope_id == 0))
return out;
1034 #ifdef WITH_IFINDEX_NAME_RESOLUTION
1041 len =
snprintf(p, outlen - (p -
out),
"%%%s", ifname);
1044 (p -
out) + len, outlen);
1056 (p -
out) + len, outlen);
1085 (p -
out) + len, outlen);
1115 static char const xdigits[] =
"0123456789abcdef";
1116 char const *p, *pch;
1117 int num_id = 0, val = 0, idx = 0;
1119 for (p = ifid_str; ; ++p) {
1120 if (*p ==
':' || *p ==
'\0') {
1127 out[idx] = (val >> 8) & 0xff;
1128 out[idx + 1] = val & 0xff;
1142 }
else if ((pch = strchr(xdigits, tolower((
uint8_t) *p))) != NULL) {
1149 val |= (pch - xdigits);
1169 struct ifreq if_req;
1172 memset(&if_req, 0,
sizeof(if_req));
1173 memset(
out, 0,
sizeof(*
out));
1178 if_req.ifr_addr.sa_family = af;
1179 strlcpy(if_req.ifr_name,
name,
sizeof(if_req.ifr_name));
1181 fd = socket(AF_INET, SOCK_DGRAM, 0);
1188 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1200 (
struct sockaddr_storage *)&if_req.ifr_addr,
1201 sizeof(if_req.ifr_addr)) < 0)
goto error;
1216 #ifdef WITH_IFINDEX_NAME_RESOLUTION
1225 char *fr_ifname_from_ifindex(
char out[
static IFNAMSIZ],
int ifindex)
1227 #ifdef HAVE_IF_INDEXTONAME
1228 if (!if_indextoname(ifindex,
out)) {
1233 struct ifreq if_req;
1236 memset(&if_req, 0,
sizeof(if_req));
1237 if_req.ifr_ifindex = ifindex;
1239 fd = socket(AF_INET, SOCK_DGRAM, 0);
1253 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1264 #ifdef WITH_IFINDEX_IPADDR_RESOLUTION
1280 int fr_ipaddr_from_ifindex(
fr_ipaddr_t *
out,
int fd,
int af,
int ifindex)
1282 struct ifreq if_req;
1285 memset(&if_req, 0,
sizeof(if_req));
1286 memset(
out, 0,
sizeof(*
out));
1289 if_req.ifr_ifindex = ifindex;
1296 if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1300 #elif defined(HAVE_IF_INDEXTONAME)
1301 if (!if_indextoname(ifindex, if_req.ifr_name)) {
1306 # error Need SIOCGIFNAME or if_indextoname
1313 if_req.ifr_addr.sa_family = af;
1315 if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1328 (
struct sockaddr_storage *)&if_req.ifr_addr,
1329 sizeof(if_req.ifr_addr)) < 0)
return -1;
1360 len = ((a->
prefix + 7) & -8) >> 3;
1363 ret = memcmp(&a->
addr.v4, &b->
addr.v4, len);
1366 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1369 ret = memcmp(&a->
addr.v6, &b->
addr.v6, len);
1395 memset(sa, 0,
sizeof(*sa));
1397 if (ipaddr->
af == AF_INET) {
1398 struct sockaddr_in s4;
1400 *salen =
sizeof(s4);
1402 memset(&s4, 0,
sizeof(s4));
1403 s4.sin_family = AF_INET;
1404 s4.sin_addr = ipaddr->
addr.v4;
1405 s4.sin_port = htons(port);
1406 memset(sa, 0,
sizeof(*sa));
1407 memcpy(sa, &s4,
sizeof(s4));
1409 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1410 }
else if (ipaddr->
af == AF_INET6) {
1411 struct sockaddr_in6 s6;
1413 *salen =
sizeof(s6);
1415 memset(&s6, 0,
sizeof(s6));
1416 s6.sin6_family = AF_INET6;
1417 s6.sin6_addr = ipaddr->
addr.v6;
1418 s6.sin6_port = htons(port);
1419 s6.sin6_scope_id = ipaddr->
scope_id;
1420 memset(sa, 0,
sizeof(*sa));
1421 memcpy(sa, &s6,
sizeof(s6));
1442 struct sockaddr_storage
const *sa, socklen_t salen)
1444 memset(ipaddr, 0,
sizeof(*ipaddr));
1446 if (sa->ss_family == AF_INET) {
1447 struct sockaddr_in s4;
1449 if (salen <
sizeof(s4)) {
1454 memcpy(&s4, sa,
sizeof(s4));
1455 ipaddr->
af = AF_INET;
1457 ipaddr->
addr.v4 = s4.sin_addr;
1458 if (port) *port = ntohs(s4.sin_port);
1461 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1462 }
else if (sa->ss_family == AF_INET6) {
1463 struct sockaddr_in6 s6;
1465 if (salen <
sizeof(s6)) {
1470 memcpy(&s6, sa,
sizeof(s6));
1471 ipaddr->
af = AF_INET6;
1473 ipaddr->
addr.v6 = s6.sin6_addr;
1474 if (port) *port = ntohs(s6.sin6_port);
1475 ipaddr->
scope_id = s6.sin6_scope_id;
1488 struct ifaddrs *list = NULL;
1499 if (getifaddrs(&list) < 0)
return;
1501 for (i = list; i != NULL; i = i->ifa_next) {
1504 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1507 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1521 ipaddr->
scope_id = if_nametoindex(i->ifa_name);
1532 struct ifaddrs *list = NULL;
1534 char *
interface = NULL;
1539 if (getifaddrs(&list) < 0)
return NULL;
1541 for (i = list; i != NULL; i = i->ifa_next) {
1545 if (!i->ifa_addr || !i->ifa_name || (ipaddr->
af != i->ifa_addr->sa_family))
continue;
1548 (
struct sockaddr_storage *)i->ifa_addr,
sizeof(
struct sockaddr_in6));
1563 interface = talloc_strdup(ctx, i->ifa_name);
1575 struct ifaddrs *list = NULL;
1579 if (getifaddrs(&list) < 0)
return -1;
1581 for (i = list; i != NULL; i = i->ifa_next) {
1583 struct sockaddr_storage sa;
1585 if (!i->ifa_addr || !i->ifa_name || ((af != AF_UNSPEC) && (af != i->ifa_addr->sa_family)))
continue;
1586 if (strcmp(i->ifa_name, interface) != 0)
continue;
1588 memcpy(&sa, i->ifa_addr,
sizeof(
struct sockaddr_in6));
1615 #define AF_LINK AF_PACKET
1620 struct ifaddrs *list = NULL;
1624 if (getifaddrs(&list) < 0)
return -1;
1626 for (i = list; i != NULL; i = i->ifa_next) {
1627 if (!i->ifa_addr || !i->ifa_name || (i->ifa_addr->sa_family !=
AF_LINK))
continue;
1628 if (strcmp(i->ifa_name, interface) != 0)
continue;
1630 #if defined(__linux__) || defined(__EMSCRIPTEN__)
1632 struct sockaddr_ll *ll;
1634 ll = (
struct sockaddr_ll *) i->ifa_addr;
1635 if ((ll->sll_hatype != 1) || (ll->sll_halen != 6))
continue;
1637 memcpy(ethernet->
addr, ll->sll_addr, 6);
1641 struct sockaddr_dl *ll;
1643 ll = (
struct sockaddr_dl *) i->ifa_addr;
1644 if (ll->sdl_alen != 6)
continue;
1646 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.
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.
union fr_ipaddr_t::@130 addr
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)
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