2 * misc.c Various miscellaneous functions.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000,2006 The FreeRADIUS server project
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/libradius.h>
32 int fr_dns_lookups = 0;
33 int fr_debug_flag = 0;
36 * Return an IP address in standard dot notation
40 const char *ip_ntoa(char *buffer, uint32_t ipaddr)
42 ipaddr = ntohl(ipaddr);
44 sprintf(buffer, "%d.%d.%d.%d",
45 (ipaddr >> 24) & 0xff,
46 (ipaddr >> 16) & 0xff,
55 * Internal wrapper for locking, to minimize the number of ifdef's
57 * Lock an fd, prefer lockf() over flock()
59 int rad_lockfd(int fd, int lock_len)
62 return lockf(fd, F_LOCK, lock_len);
63 #elif defined(LOCK_EX)
64 lock_len = lock_len; /* -Wunused */
65 return flock(fd, LOCK_EX);
66 #elif defined(F_WRLCK)
72 fl.l_whence = SEEK_CUR;
73 return fcntl(fd, F_SETLKW, (void *)&fl);
80 * Internal wrapper for locking, to minimize the number of ifdef's
82 * Lock an fd, prefer lockf() over flock()
83 * Nonblocking version.
85 int rad_lockfd_nonblock(int fd, int lock_len)
87 #if defined(F_LOCK) && !defined(BSD)
88 return lockf(fd, F_TLOCK, lock_len);
89 #elif defined(LOCK_EX)
90 lock_len = lock_len; /* -Wunused */
91 return flock(fd, LOCK_EX | LOCK_NB);
92 #elif defined(F_WRLCK)
98 fl.l_whence = SEEK_CUR;
99 return fcntl(fd, F_SETLK, (void *)&fl);
106 * Internal wrapper for unlocking, to minimize the number of ifdef's
109 * Unlock an fd, prefer lockf() over flock()
111 int rad_unlockfd(int fd, int lock_len)
113 #if defined(F_LOCK) && !defined(BSD)
114 return lockf(fd, F_ULOCK, lock_len);
115 #elif defined(LOCK_EX)
116 lock_len = lock_len; /* -Wunused */
117 return flock(fd, LOCK_UN);
118 #elif defined(F_WRLCK)
124 fl.l_whence = SEEK_CUR;
125 return fcntl(fd, F_UNLCK, (void *)&fl);
132 * Return an interface-id in standard colon notation
134 char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid)
136 snprintf(buffer, size, "%x:%x:%x:%x",
137 (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
138 (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
144 * Return an interface-id from
145 * one supplied in standard colon notation.
147 uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid)
149 static const char xdigits[] = "0123456789abcdef";
151 int num_id = 0, val = 0, idx = 0;
153 for (p = ifid_str; ; ++p) {
154 if (*p == ':' || *p == '\0') {
159 * Drop 'val' into the array.
161 ifid[idx] = (val >> 8) & 0xff;
162 ifid[idx + 1] = val & 0xff;
165 * Must have all entries before
176 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
180 * Dumb version of 'scanf'
183 val |= (pch - xdigits);
191 #ifndef HAVE_INET_PTON
192 static int inet_pton4(const char *src, struct in_addr *dst)
198 static const char digits[] = "0123456789";
204 while (*p && ((off = strchr(digits, *p)) != NULL)) {
206 num += (off - digits);
208 if (num > 255) return 0;
215 * Not a digit, MUST be a dot, else we
227 * End of the string. At the fourth
228 * octet is OK, anything else is an
236 memcpy(dst, &tmp, sizeof(tmp));
241 #ifdef HAVE_STRUCT_SOCKADDR_IN6
243 * inet_pton6(src, dst)
244 * convert presentation level address to network order binary form.
246 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
248 * (1) does not touch `dst' unless it's returning 1.
249 * (2) :: in a full address is silently ignored.
251 * inspired by Mark Andrews.
256 inet_pton6(const char *src, unsigned char *dst)
258 static const char xdigits_l[] = "0123456789abcdef",
259 xdigits_u[] = "0123456789ABCDEF";
260 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
261 const char *xdigits, *curtok;
265 memset((tp = tmp), 0, IN6ADDRSZ);
266 endp = tp + IN6ADDRSZ;
268 /* Leading :: requires some special handling. */
275 while ((ch = *src++) != '\0') {
278 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
279 pch = strchr((xdigits = xdigits_u), ch);
282 val |= (pch - xdigits);
296 if (tp + INT16SZ > endp)
298 *tp++ = (u_char) (val >> 8) & 0xff;
299 *tp++ = (u_char) val & 0xff;
304 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
305 inet_pton4(curtok, (struct in_addr *) tp) > 0) {
308 break; /* '\0' was seen by inet_pton4(). */
313 if (tp + INT16SZ > endp)
315 *tp++ = (u_char) (val >> 8) & 0xff;
316 *tp++ = (u_char) val & 0xff;
318 if (colonp != NULL) {
320 * Since some memmove()'s erroneously fail to handle
321 * overlapping regions, we'll do the shift by hand.
323 const int n = tp - colonp;
326 for (i = 1; i <= n; i++) {
327 endp[- i] = colonp[n - i];
334 /* bcopy(tmp, dst, IN6ADDRSZ); */
335 memcpy(dst, tmp, IN6ADDRSZ);
341 * Utility function, so that the rest of the server doesn't
342 * have ifdef's around IPv6 support
344 int inet_pton(int af, const char *src, void *dst)
347 return inet_pton4(src, dst);
349 #ifdef HAVE_STRUCT_SOCKADDR_IN6
351 if (af == AF_INET6) {
352 return inet_pton6(src, dst);
361 #ifndef HAVE_INET_NTOP
363 * Utility function, so that the rest of the server doesn't
364 * have ifdef's around IPv6 support
366 const char *inet_ntop(int af, const void *src, char *dst, size_t cnt)
369 const uint8_t *ipaddr = src;
371 if (cnt <= INET_ADDRSTRLEN) return NULL;
373 snprintf(dst, cnt, "%d.%d.%d.%d",
374 ipaddr[0], ipaddr[1],
375 ipaddr[2], ipaddr[3]);
380 * If the system doesn't define this, we define it
383 if (af == AF_INET6) {
384 const struct in6_addr *ipaddr = src;
386 if (cnt <= INET6_ADDRSTRLEN) return NULL;
388 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
389 (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
390 (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
391 (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
392 (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
393 (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
394 (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
395 (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
396 (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
400 return NULL; /* don't support IPv6 */
406 * Wrappers for IPv4/IPv6 host to IP address lookup.
407 * This API returns only one IP address, of the specified
408 * address family, or the first address (of whatever family),
409 * if AF_UNSPEC is used.
411 int ip_hton(const char *src, int af, fr_ipaddr_t *dst)
414 struct addrinfo hints, *ai = NULL, *res = NULL;
416 memset(&hints, 0, sizeof(hints));
417 hints.ai_family = af;
419 if ((rcode = getaddrinfo(src, NULL, &hints, &res)) != 0) {
420 fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
424 for (ai = res; ai; ai = ai->ai_next) {
425 if ((af == ai->ai_family) || (af == AF_UNSPEC))
430 fr_strerror_printf("ip_hton failed to find requested information for host %.100s", src);
435 rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
436 ai->ai_addrlen, dst, NULL);
438 if (!rcode) return -1;
444 * Look IP addreses up, and print names (depending on DNS config)
446 const char *ip_ntoh(const fr_ipaddr_t *src, char *dst, size_t cnt)
448 struct sockaddr_storage ss;
455 if (!fr_dns_lookups) {
456 return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
459 if (!fr_ipaddr2sockaddr(src, 0, &ss, &salen)) {
463 if ((error = getnameinfo((struct sockaddr *)&ss, salen, dst, cnt, NULL, 0,
464 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
465 fr_strerror_printf("ip_ntoh: %s", gai_strerror(error));
472 static const char *hextab = "0123456789abcdef";
477 * We allow: hex == bin
479 size_t fr_hex2bin(const char *hex, uint8_t *bin, size_t len)
484 for (i = 0; i < len; i++) {
485 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
486 !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
488 bin[i] = ((c1-hextab)<<4) + (c2-hextab);
498 * If the output buffer isn't long enough, we have a buffer overflow.
500 void fr_bin2hex(const uint8_t *bin, char *hex, size_t len)
504 for (i = 0; i < len; i++) {
505 hex[0] = hextab[((*bin) >> 4) & 0x0f];
506 hex[1] = hextab[*bin & 0x0f];
516 * So we don't have ifdef's in the rest of the code
518 #ifndef HAVE_CLOSEFROM
519 int closefrom(int fd)
525 maxfd = sysconf(_SC_OPEN_MAX);
531 if (fd > maxfd) return 0;
534 * FIXME: return EINTR?
538 for (i = fd; i < maxfd; i++) {
546 int fr_ipaddr_cmp(const fr_ipaddr_t *a, const fr_ipaddr_t *b)
548 if (a->af < b->af) return -1;
549 if (a->af > b->af) return +1;
553 return memcmp(&a->ipaddr.ip4addr,
555 sizeof(a->ipaddr.ip4addr));
558 #ifdef HAVE_STRUCT_SOCKADDR_IN6
560 if (a->scope < b->scope) return -1;
561 if (a->scope > b->scope) return +1;
563 return memcmp(&a->ipaddr.ip6addr,
565 sizeof(a->ipaddr.ip6addr));
576 int fr_ipaddr2sockaddr(const fr_ipaddr_t *ipaddr, int port,
577 struct sockaddr_storage *sa, socklen_t *salen)
579 if (ipaddr->af == AF_INET) {
580 struct sockaddr_in s4;
584 memset(&s4, 0, sizeof(s4));
585 s4.sin_family = AF_INET;
586 s4.sin_addr = ipaddr->ipaddr.ip4addr;
587 s4.sin_port = htons(port);
588 memset(sa, 0, sizeof(*sa));
589 memcpy(sa, &s4, sizeof(s4));
591 #ifdef HAVE_STRUCT_SOCKADDR_IN6
592 } else if (ipaddr->af == AF_INET6) {
593 struct sockaddr_in6 s6;
597 memset(&s6, 0, sizeof(s6));
598 s6.sin6_family = AF_INET6;
599 s6.sin6_addr = ipaddr->ipaddr.ip6addr;
600 s6.sin6_port = htons(port);
601 s6.sin6_scope_id = ipaddr->scope;
602 memset(sa, 0, sizeof(*sa));
603 memcpy(sa, &s6, sizeof(s6));
613 int fr_sockaddr2ipaddr(const struct sockaddr_storage *sa, socklen_t salen,
614 fr_ipaddr_t *ipaddr, int *port)
616 if (sa->ss_family == AF_INET) {
617 struct sockaddr_in s4;
619 if (salen < sizeof(s4)) {
620 fr_strerror_printf("IPv4 address is too small");
624 memcpy(&s4, sa, sizeof(s4));
625 ipaddr->af = AF_INET;
626 ipaddr->ipaddr.ip4addr = s4.sin_addr;
627 if (port) *port = ntohs(s4.sin_port);
629 #ifdef HAVE_STRUCT_SOCKADDR_IN6
630 } else if (sa->ss_family == AF_INET6) {
631 struct sockaddr_in6 s6;
633 if (salen < sizeof(s6)) {
634 fr_strerror_printf("IPv6 address is too small");
638 memcpy(&s6, sa, sizeof(s6));
639 ipaddr->af = AF_INET6;
640 ipaddr->ipaddr.ip6addr = s6.sin6_addr;
641 if (port) *port = ntohs(s6.sin6_port);
642 ipaddr->scope = s6.sin6_scope_id;
646 fr_strerror_printf("Unsupported address famility %d",