#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/libradius.h>
#include <ctype.h>
#include <sys/file.h>
#include <fcntl.h>
int fr_dns_lookups = 0;
int fr_debug_flag = 0;
const char *ip_ntoa(char *buffer, uint32_t ipaddr)
{
ipaddr = ntohl(ipaddr);
sprintf(buffer, "%d.%d.%d.%d",
(ipaddr >> 24) & 0xff,
(ipaddr >> 16) & 0xff,
(ipaddr >> 8) & 0xff,
(ipaddr ) & 0xff);
return buffer;
}
#undef F_LOCK
int rad_lockfd(int fd, int lock_len)
{
#if defined(F_LOCK)
return lockf(fd, F_LOCK, lock_len);
#elif defined(LOCK_EX)
lock_len = lock_len;
return flock(fd, LOCK_EX);
#elif defined(F_WRLCK)
struct flock fl;
fl.l_start = 0;
fl.l_len = lock_len;
fl.l_pid = getpid();
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_CUR;
return fcntl(fd, F_SETLKW, (void *)&fl);
#else
return -1;
#endif
}
int rad_lockfd_nonblock(int fd, int lock_len)
{
#if defined(F_LOCK) && !defined(BSD)
return lockf(fd, F_TLOCK, lock_len);
#elif defined(LOCK_EX)
lock_len = lock_len;
return flock(fd, LOCK_EX | LOCK_NB);
#elif defined(F_WRLCK)
struct flock fl;
fl.l_start = 0;
fl.l_len = lock_len;
fl.l_pid = getpid();
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_CUR;
return fcntl(fd, F_SETLK, (void *)&fl);
#else
return -1;
#endif
}
int rad_unlockfd(int fd, int lock_len)
{
#if defined(F_LOCK) && !defined(BSD)
return lockf(fd, F_ULOCK, lock_len);
#elif defined(LOCK_EX)
lock_len = lock_len;
return flock(fd, LOCK_UN);
#elif defined(F_WRLCK)
struct flock fl;
fl.l_start = 0;
fl.l_len = lock_len;
fl.l_pid = getpid();
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_CUR;
return fcntl(fd, F_UNLCK, (void *)&fl);
#else
return -1;
#endif
}
char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid)
{
snprintf(buffer, size, "%x:%x:%x:%x",
(ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
(ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
return buffer;
}
uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid)
{
static const char xdigits[] = "0123456789abcdef";
const char *p, *pch;
int num_id = 0, val = 0, idx = 0;
for (p = ifid_str; ; ++p) {
if (*p == ':' || *p == '\0') {
if (num_id <= 0)
return NULL;
ifid[idx] = (val >> 8) & 0xff;
ifid[idx + 1] = val & 0xff;
if (*p == '\0') {
if (idx != 6)
return NULL;
break;
}
val = 0;
num_id = 0;
if ((idx += 2) > 6)
return NULL;
} else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
if (++num_id > 4)
return NULL;
val <<= 4;
val |= (pch - xdigits);
} else
return NULL;
}
return ifid;
}
#ifndef HAVE_INET_PTON
static int inet_pton4(const char *src, struct in_addr *dst)
{
int octet;
unsigned int num;
const char *p, *off;
uint8_t tmp[4];
static const char digits[] = "0123456789";
octet = 0;
p = src;
while (1) {
num = 0;
while (*p && ((off = strchr(digits, *p)) != NULL)) {
num *= 10;
num += (off - digits);
if (num > 255) return 0;
p++;
}
if (!*p) break;
if (*p != '.') {
return 0;
}
tmp[octet++] = num;
p++;
}
if (octet != 3) {
return 0;
}
tmp[3] = num;
memcpy(dst, &tmp, sizeof(tmp));
return 1;
}
#ifdef HAVE_STRUCT_SOCKADDR_IN6
static int
inet_pton6(const char *src, unsigned char *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit;
u_int val;
memset((tp = tmp), 0, IN6ADDRSZ);
endp = tp + IN6ADDRSZ;
colonp = NULL;
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
saw_xdigit = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return (0);
saw_xdigit = 1;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
return (0);
colonp = tp;
continue;
}
if (tp + INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
saw_xdigit = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
inet_pton4(curtok, (struct in_addr *) tp) > 0) {
tp += INADDRSZ;
saw_xdigit = 0;
break;
}
return (0);
}
if (saw_xdigit) {
if (tp + INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
}
if (colonp != NULL) {
const int n = tp - colonp;
int i;
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return (0);
memcpy(dst, tmp, IN6ADDRSZ);
return (1);
}
#endif
int inet_pton(int af, const char *src, void *dst)
{
if (af == AF_INET) {
return inet_pton4(src, dst);
}
#ifdef HAVE_STRUCT_SOCKADDR_IN6
if (af == AF_INET6) {
return inet_pton6(src, dst);
}
#endif
return -1;
}
#endif
#ifndef HAVE_INET_NTOP
const char *inet_ntop(int af, const void *src, char *dst, size_t cnt)
{
if (af == AF_INET) {
const uint8_t *ipaddr = src;
if (cnt <= INET_ADDRSTRLEN) return NULL;
snprintf(dst, cnt, "%d.%d.%d.%d",
ipaddr[0], ipaddr[1],
ipaddr[2], ipaddr[3]);
return dst;
}
if (af == AF_INET6) {
const struct in6_addr *ipaddr = src;
if (cnt <= INET6_ADDRSTRLEN) return NULL;
snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
(ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
(ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
(ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
(ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
(ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
(ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
(ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
(ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
return dst;
}
return NULL;
}
#endif
int ip_hton(const char *src, int af, fr_ipaddr_t *dst)
{
int rcode;
struct addrinfo hints, *ai = NULL, *res = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
if ((rcode = getaddrinfo(src, NULL, &hints, &res)) != 0) {
fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
return -1;
}
for (ai = res; ai; ai = ai->ai_next) {
if ((af == ai->ai_family) || (af == AF_UNSPEC))
break;
}
if (!ai) {
fr_strerror_printf("ip_hton failed to find requested information for host %.100s", src);
freeaddrinfo(ai);
return -1;
}
rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
ai->ai_addrlen, dst, NULL);
freeaddrinfo(ai);
if (!rcode) return -1;
return 0;
}
const char *ip_ntoh(const fr_ipaddr_t *src, char *dst, size_t cnt)
{
struct sockaddr_storage ss;
int error;
socklen_t salen;
if (!fr_dns_lookups) {
return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
}
if (!fr_ipaddr2sockaddr(src, 0, &ss, &salen)) {
return NULL;
}
if ((error = getnameinfo((struct sockaddr *)&ss, salen, dst, cnt, NULL, 0,
NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
fr_strerror_printf("ip_ntoh: %s", gai_strerror(error));
return NULL;
}
return dst;
}
static const char *hextab = "0123456789abcdef";
size_t fr_hex2bin(const char *hex, uint8_t *bin, size_t len)
{
size_t i;
char *c1, *c2;
for (i = 0; i < len; i++) {
if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
!(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
break;
bin[i] = ((c1-hextab)<<4) + (c2-hextab);
}
return i;
}
void fr_bin2hex(const uint8_t *bin, char *hex, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
hex[0] = hextab[((*bin) >> 4) & 0x0f];
hex[1] = hextab[*bin & 0x0f];
hex += 2;
bin++;
}
*hex = '\0';
return;
}
#ifndef HAVE_CLOSEFROM
int closefrom(int fd)
{
int i;
int maxfd = 256;
#ifdef _SC_OPEN_MAX
maxfd = sysconf(_SC_OPEN_MAX);
if (maxfd < 0) {
maxfd = 256;
}
#endif
if (fd > maxfd) return 0;
for (i = fd; i < maxfd; i++) {
close(i);
}
return 0;
}
#endif
int fr_ipaddr_cmp(const fr_ipaddr_t *a, const fr_ipaddr_t *b)
{
if (a->af < b->af) return -1;
if (a->af > b->af) return +1;
switch (a->af) {
case AF_INET:
return memcmp(&a->ipaddr.ip4addr,
&b->ipaddr.ip4addr,
sizeof(a->ipaddr.ip4addr));
break;
#ifdef HAVE_STRUCT_SOCKADDR_IN6
case AF_INET6:
if (a->scope < b->scope) return -1;
if (a->scope > b->scope) return +1;
return memcmp(&a->ipaddr.ip6addr,
&b->ipaddr.ip6addr,
sizeof(a->ipaddr.ip6addr));
break;
#endif
default:
break;
}
return -1;
}
int fr_ipaddr2sockaddr(const fr_ipaddr_t *ipaddr, int port,
struct sockaddr_storage *sa, socklen_t *salen)
{
if (ipaddr->af == AF_INET) {
struct sockaddr_in s4;
*salen = sizeof(s4);
memset(&s4, 0, sizeof(s4));
s4.sin_family = AF_INET;
s4.sin_addr = ipaddr->ipaddr.ip4addr;
s4.sin_port = htons(port);
memset(sa, 0, sizeof(*sa));
memcpy(sa, &s4, sizeof(s4));
#ifdef HAVE_STRUCT_SOCKADDR_IN6
} else if (ipaddr->af == AF_INET6) {
struct sockaddr_in6 s6;
*salen = sizeof(s6);
memset(&s6, 0, sizeof(s6));
s6.sin6_family = AF_INET6;
s6.sin6_addr = ipaddr->ipaddr.ip6addr;
s6.sin6_port = htons(port);
s6.sin6_scope_id = ipaddr->scope;
memset(sa, 0, sizeof(*sa));
memcpy(sa, &s6, sizeof(s6));
#endif
} else {
return 0;
}
return 1;
}
int fr_sockaddr2ipaddr(const struct sockaddr_storage *sa, socklen_t salen,
fr_ipaddr_t *ipaddr, int *port)
{
if (sa->ss_family == AF_INET) {
struct sockaddr_in s4;
if (salen < sizeof(s4)) {
fr_strerror_printf("IPv4 address is too small");
return 0;
}
memcpy(&s4, sa, sizeof(s4));
ipaddr->af = AF_INET;
ipaddr->ipaddr.ip4addr = s4.sin_addr;
if (port) *port = ntohs(s4.sin_port);
#ifdef HAVE_STRUCT_SOCKADDR_IN6
} else if (sa->ss_family == AF_INET6) {
struct sockaddr_in6 s6;
if (salen < sizeof(s6)) {
fr_strerror_printf("IPv6 address is too small");
return 0;
}
memcpy(&s6, sa, sizeof(s6));
ipaddr->af = AF_INET6;
ipaddr->ipaddr.ip6addr = s6.sin6_addr;
if (port) *port = ntohs(s6.sin6_port);
ipaddr->scope = s6.sin6_scope_id;
#endif
} else {
fr_strerror_printf("Unsupported address famility %d",
sa->ss_family);
return 0;
}
return 1;
}