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;
37 * Return an IP address in standard dot notation
41 const char *ip_ntoa(char *buffer, uint32_t ipaddr)
43 ipaddr = ntohl(ipaddr);
45 sprintf(buffer, "%d.%d.%d.%d",
46 (ipaddr >> 24) & 0xff,
47 (ipaddr >> 16) & 0xff,
56 * Internal wrapper for locking, to minimize the number of ifdef's
58 * Lock an fd, prefer lockf() over flock()
60 int rad_lockfd(int fd, int lock_len)
63 return lockf(fd, F_LOCK, lock_len);
64 #elif defined(LOCK_EX)
65 lock_len = lock_len; /* -Wunused */
66 return flock(fd, LOCK_EX);
73 fl.l_whence = SEEK_CUR;
74 return fcntl(fd, F_SETLKW, (void *)&fl);
79 * Internal wrapper for locking, to minimize the number of ifdef's
81 * Lock an fd, prefer lockf() over flock()
82 * Nonblocking version.
84 int rad_lockfd_nonblock(int fd, int lock_len)
86 #if defined(F_LOCK) && !defined(BSD)
87 return lockf(fd, F_TLOCK, lock_len);
88 #elif defined(LOCK_EX)
89 lock_len = lock_len; /* -Wunused */
90 return flock(fd, LOCK_EX | LOCK_NB);
97 fl.l_whence = SEEK_CUR;
98 return fcntl(fd, F_SETLK, (void *)&fl);
103 * Internal wrapper for unlocking, to minimize the number of ifdef's
106 * Unlock an fd, prefer lockf() over flock()
108 int rad_unlockfd(int fd, int lock_len)
110 #if defined(F_LOCK) && !defined(BSD)
111 return lockf(fd, F_ULOCK, lock_len);
112 #elif defined(LOCK_EX)
113 lock_len = lock_len; /* -Wunused */
114 return flock(fd, LOCK_UN);
121 fl.l_whence = SEEK_CUR;
122 return fcntl(fd, F_UNLCK, (void *)&fl);
127 * Return an interface-id in standard colon notation
129 char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid)
131 snprintf(buffer, size, "%x:%x:%x:%x",
132 (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
133 (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
139 * Return an interface-id from
140 * one supplied in standard colon notation.
142 uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid)
144 static const char xdigits[] = "0123456789abcdef";
146 int num_id = 0, val = 0, idx = 0;
148 for (p = ifid_str; ; ++p) {
149 if (*p == ':' || *p == '\0') {
154 * Drop 'val' into the array.
156 ifid[idx] = (val >> 8) & 0xff;
157 ifid[idx + 1] = val & 0xff;
160 * Must have all entries before
171 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
175 * Dumb version of 'scanf'
178 val |= (pch - xdigits);
186 #ifndef HAVE_INET_PTON
187 static int inet_pton4(const char *src, struct in_addr *dst)
193 static const char digits[] = "0123456789";
199 while (*p && ((off = strchr(digits, *p)) != NULL)) {
201 num += (off - digits);
203 if (num > 255) return 0;
210 * Not a digit, MUST be a dot, else we
222 * End of the string. At the fourth
223 * octet is OK, anything else is an
231 memcpy(dst, &tmp, sizeof(tmp));
236 #ifdef HAVE_STRUCT_SOCKADDR_IN6
238 * inet_pton6(src, dst)
239 * convert presentation level address to network order binary form.
241 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
243 * (1) does not touch `dst' unless it's returning 1.
244 * (2) :: in a full address is silently ignored.
246 * inspired by Mark Andrews.
251 inet_pton6(const char *src, unsigned char *dst)
253 static const char xdigits_l[] = "0123456789abcdef",
254 xdigits_u[] = "0123456789ABCDEF";
255 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
256 const char *xdigits, *curtok;
260 memset((tp = tmp), 0, IN6ADDRSZ);
261 endp = tp + IN6ADDRSZ;
263 /* Leading :: requires some special handling. */
270 while ((ch = *src++) != '\0') {
273 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
274 pch = strchr((xdigits = xdigits_u), ch);
277 val |= (pch - xdigits);
291 if (tp + INT16SZ > endp)
293 *tp++ = (u_char) (val >> 8) & 0xff;
294 *tp++ = (u_char) val & 0xff;
299 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
300 inet_pton4(curtok, (struct in_addr *) tp) > 0) {
303 break; /* '\0' was seen by inet_pton4(). */
308 if (tp + INT16SZ > endp)
310 *tp++ = (u_char) (val >> 8) & 0xff;
311 *tp++ = (u_char) val & 0xff;
313 if (colonp != NULL) {
315 * Since some memmove()'s erroneously fail to handle
316 * overlapping regions, we'll do the shift by hand.
318 const int n = tp - colonp;
321 for (i = 1; i <= n; i++) {
322 endp[- i] = colonp[n - i];
329 /* bcopy(tmp, dst, IN6ADDRSZ); */
330 memcpy(dst, tmp, IN6ADDRSZ);
336 * Utility function, so that the rest of the server doesn't
337 * have ifdef's around IPv6 support
339 int inet_pton(int af, const char *src, void *dst)
342 return inet_pton4(src, dst);
344 #ifdef HAVE_STRUCT_SOCKADDR_IN6
346 if (af == AF_INET6) {
347 return inet_pton6(src, dst);
356 #ifndef HAVE_INET_NTOP
358 * Utility function, so that the rest of the server doesn't
359 * have ifdef's around IPv6 support
361 const char *inet_ntop(int af, const void *src, char *dst, size_t cnt)
364 const uint8_t *ipaddr = src;
366 if (cnt <= INET_ADDRSTRLEN) return NULL;
368 snprintf(dst, cnt, "%d.%d.%d.%d",
369 ipaddr[0], ipaddr[1],
370 ipaddr[2], ipaddr[3]);
375 * If the system doesn't define this, we define it
378 if (af == AF_INET6) {
379 const struct in6_addr *ipaddr = src;
381 if (cnt <= INET6_ADDRSTRLEN) return NULL;
383 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
384 (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
385 (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
386 (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
387 (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
388 (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
389 (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
390 (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
391 (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
395 return NULL; /* don't support IPv6 */
401 * Wrappers for IPv4/IPv6 host to IP address lookup.
402 * This API returns only one IP address, of the specified
403 * address family, or the first address (of whatever family),
404 * if AF_UNSPEC is used.
406 int ip_hton(const char *src, int af, fr_ipaddr_t *dst)
409 struct addrinfo hints, *ai = NULL, *res = NULL;
411 memset(&hints, 0, sizeof(hints));
412 hints.ai_family = af;
414 if ((rcode = getaddrinfo(src, NULL, &hints, &res)) != 0) {
415 fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
419 for (ai = res; ai; ai = ai->ai_next) {
420 if ((af == ai->ai_family) || (af == AF_UNSPEC))
425 fr_strerror_printf("ip_hton failed to find requested information for host %.100s", src);
430 rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
431 ai->ai_addrlen, dst, NULL);
433 if (!rcode) return -1;
439 * Look IP addreses up, and print names (depending on DNS config)
441 const char *ip_ntoh(const fr_ipaddr_t *src, char *dst, size_t cnt)
443 struct sockaddr_storage ss;
450 if (!fr_dns_lookups) {
451 return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
454 if (!fr_ipaddr2sockaddr(src, 0, &ss, &salen)) {
458 if ((error = getnameinfo((struct sockaddr *)&ss, salen, dst, cnt, NULL, 0,
459 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
460 fr_strerror_printf("ip_ntoh: %s", gai_strerror(error));
467 static const char *hextab = "0123456789abcdef";
472 * We allow: hex == bin
474 size_t fr_hex2bin(const char *hex, uint8_t *bin, size_t len)
479 for (i = 0; i < len; i++) {
480 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
481 !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
483 bin[i] = ((c1-hextab)<<4) + (c2-hextab);
493 * If the output buffer isn't long enough, we have a buffer overflow.
495 void fr_bin2hex(const uint8_t *bin, char *hex, size_t len)
499 for (i = 0; i < len; i++) {
500 hex[0] = hextab[((*bin) >> 4) & 0x0f];
501 hex[1] = hextab[*bin & 0x0f];
511 * So we don't have ifdef's in the rest of the code
513 #ifndef HAVE_CLOSEFROM
514 int closefrom(int fd)
520 maxfd = sysconf(_SC_OPEN_MAX);
526 if (fd > maxfd) return 0;
529 * FIXME: return EINTR?
533 for (i = fd; i < maxfd; i++) {
541 int fr_ipaddr_cmp(const fr_ipaddr_t *a, const fr_ipaddr_t *b)
543 if (a->af < b->af) return -1;
544 if (a->af > b->af) return +1;
548 return memcmp(&a->ipaddr.ip4addr,
550 sizeof(a->ipaddr.ip4addr));
553 #ifdef HAVE_STRUCT_SOCKADDR_IN6
555 if (a->scope < b->scope) return -1;
556 if (a->scope > b->scope) return +1;
558 return memcmp(&a->ipaddr.ip6addr,
560 sizeof(a->ipaddr.ip6addr));
571 int fr_ipaddr2sockaddr(const fr_ipaddr_t *ipaddr, int port,
572 struct sockaddr_storage *sa, socklen_t *salen)
574 if (ipaddr->af == AF_INET) {
575 struct sockaddr_in s4;
579 memset(&s4, 0, sizeof(s4));
580 s4.sin_family = AF_INET;
581 s4.sin_addr = ipaddr->ipaddr.ip4addr;
582 s4.sin_port = htons(port);
583 memset(sa, 0, sizeof(*sa));
584 memcpy(sa, &s4, sizeof(s4));
586 #ifdef HAVE_STRUCT_SOCKADDR_IN6
587 } else if (ipaddr->af == AF_INET6) {
588 struct sockaddr_in6 s6;
592 memset(&s6, 0, sizeof(s6));
593 s6.sin6_family = AF_INET6;
594 s6.sin6_addr = ipaddr->ipaddr.ip6addr;
595 s6.sin6_port = htons(port);
596 s6.sin6_scope_id = ipaddr->scope;
597 memset(sa, 0, sizeof(*sa));
598 memcpy(sa, &s6, sizeof(s6));
608 int fr_sockaddr2ipaddr(const struct sockaddr_storage *sa, socklen_t salen,
609 fr_ipaddr_t *ipaddr, int *port)
611 if (sa->ss_family == AF_INET) {
612 struct sockaddr_in s4;
614 if (salen < sizeof(s4)) {
615 fr_strerror_printf("IPv4 address is too small");
619 memcpy(&s4, sa, sizeof(s4));
620 ipaddr->af = AF_INET;
621 ipaddr->ipaddr.ip4addr = s4.sin_addr;
622 if (port) *port = ntohs(s4.sin_port);
624 #ifdef HAVE_STRUCT_SOCKADDR_IN6
625 } else if (sa->ss_family == AF_INET6) {
626 struct sockaddr_in6 s6;
628 if (salen < sizeof(s6)) {
629 fr_strerror_printf("IPv6 address is too small");
633 memcpy(&s6, sa, sizeof(s6));
634 ipaddr->af = AF_INET6;
635 ipaddr->ipaddr.ip6addr = s6.sin6_addr;
636 if (port) *port = ntohs(s6.sin6_port);
637 ipaddr->scope = s6.sin6_scope_id;
641 fr_strerror_printf("Unsupported address famility %d",