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
25 #include <freeradius-devel/libradius.h>
32 int fr_dns_lookups = 0;
33 int fr_debug_flag = 0;
36 static int fr_debugger_present = -1;
38 /** Stub callback to see if the SIGTRAP handler is overriden
40 * @param signum signal raised.
42 static void _sigtrap_handler(UNUSED int signum)
44 fr_debugger_present = 0;
45 signal(SIGTRAP, SIG_DFL);
48 /** Break in GDB (if were running under GDB)
50 * If the server is running under GDB this will raise a SIGTRAP which
51 * will pause the running process.
53 * If the server is not running under GDB then this will do nothing.
55 void fr_debug_break(void)
57 if (fr_debugger_present == -1) {
58 fr_debugger_present = 0;
59 signal(SIGTRAP, _sigtrap_handler);
61 } else if (fr_debugger_present == 1) {
67 * Return an IP address in standard dot notation
71 char const *ip_ntoa(char *buffer, uint32_t ipaddr)
73 ipaddr = ntohl(ipaddr);
75 sprintf(buffer, "%d.%d.%d.%d",
76 (ipaddr >> 24) & 0xff,
77 (ipaddr >> 16) & 0xff,
84 * Internal wrapper for locking, to minimize the number of ifdef's
88 int rad_lockfd(int fd, int lock_len)
97 fl.l_whence = SEEK_CUR;
99 return fcntl(fd, F_SETLKW, (void *)&fl);
101 #error "missing definition for F_WRLCK, all file locks will fail"
108 * Internal wrapper for locking, to minimize the number of ifdef's
110 * Lock an fd, prefer lockf() over flock()
111 * Nonblocking version.
113 int rad_lockfd_nonblock(int fd, int lock_len)
122 fl.l_whence = SEEK_CUR;
124 return fcntl(fd, F_SETLK, (void *)&fl);
126 #error "missing definition for F_WRLCK, all file locks will fail"
133 * Internal wrapper for unlocking, to minimize the number of ifdef's
136 * Unlock an fd, prefer lockf() over flock()
138 int rad_unlockfd(int fd, int lock_len)
147 fl.l_whence = SEEK_CUR;
149 return fcntl(fd, F_UNLCK, (void *)&fl);
151 #error "missing definition for F_WRLCK, all file locks will fail"
158 * Return an interface-id in standard colon notation
160 char *ifid_ntoa(char *buffer, size_t size, uint8_t const *ifid)
162 snprintf(buffer, size, "%x:%x:%x:%x",
163 (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
164 (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
170 * Return an interface-id from
171 * one supplied in standard colon notation.
173 uint8_t *ifid_aton(char const *ifid_str, uint8_t *ifid)
175 static char const xdigits[] = "0123456789abcdef";
177 int num_id = 0, val = 0, idx = 0;
179 for (p = ifid_str; ; ++p) {
180 if (*p == ':' || *p == '\0') {
185 * Drop 'val' into the array.
187 ifid[idx] = (val >> 8) & 0xff;
188 ifid[idx + 1] = val & 0xff;
191 * Must have all entries before
202 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
206 * Dumb version of 'scanf'
209 val |= (pch - xdigits);
217 #ifndef HAVE_INET_PTON
218 static int inet_pton4(char const *src, struct in_addr *dst)
224 static char const digits[] = "0123456789";
230 while (*p && ((off = strchr(digits, *p)) != NULL)) {
232 num += (off - digits);
234 if (num > 255) return 0;
241 * Not a digit, MUST be a dot, else we
253 * End of the string. At the fourth
254 * octet is OK, anything else is an
262 memcpy(dst, &tmp, sizeof(tmp));
267 #ifdef HAVE_STRUCT_SOCKADDR_IN6
269 * inet_pton6(src, dst)
270 * convert presentation level address to network order binary form.
272 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
274 * (1) does not touch `dst' unless it's returning 1.
275 * (2) :: in a full address is silently ignored.
277 * inspired by Mark Andrews.
282 inet_pton6(char const *src, unsigned char *dst)
284 static char const xdigits_l[] = "0123456789abcdef",
285 xdigits_u[] = "0123456789ABCDEF";
286 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
287 char const *xdigits, *curtok;
291 memset((tp = tmp), 0, IN6ADDRSZ);
292 endp = tp + IN6ADDRSZ;
294 /* Leading :: requires some special handling. */
301 while ((ch = *src++) != '\0') {
304 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
305 pch = strchr((xdigits = xdigits_u), ch);
308 val |= (pch - xdigits);
322 if (tp + INT16SZ > endp)
324 *tp++ = (u_char) (val >> 8) & 0xff;
325 *tp++ = (u_char) val & 0xff;
330 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
331 inet_pton4(curtok, (struct in_addr *) tp) > 0) {
334 break; /* '\0' was seen by inet_pton4(). */
339 if (tp + INT16SZ > endp)
341 *tp++ = (u_char) (val >> 8) & 0xff;
342 *tp++ = (u_char) val & 0xff;
344 if (colonp != NULL) {
346 * Since some memmove()'s erroneously fail to handle
347 * overlapping regions, we'll do the shift by hand.
349 int const n = tp - colonp;
352 for (i = 1; i <= n; i++) {
353 endp[- i] = colonp[n - i];
360 /* bcopy(tmp, dst, IN6ADDRSZ); */
361 memcpy(dst, tmp, IN6ADDRSZ);
367 * Utility function, so that the rest of the server doesn't
368 * have ifdef's around IPv6 support
370 int inet_pton(int af, char const *src, void *dst)
373 return inet_pton4(src, dst);
375 #ifdef HAVE_STRUCT_SOCKADDR_IN6
377 if (af == AF_INET6) {
378 return inet_pton6(src, dst);
387 #ifndef HAVE_INET_NTOP
389 * Utility function, so that the rest of the server doesn't
390 * have ifdef's around IPv6 support
392 char const *inet_ntop(int af, void const *src, char *dst, size_t cnt)
395 uint8_t const *ipaddr = src;
397 if (cnt <= INET_ADDRSTRLEN) return NULL;
399 snprintf(dst, cnt, "%d.%d.%d.%d",
400 ipaddr[0], ipaddr[1],
401 ipaddr[2], ipaddr[3]);
406 * If the system doesn't define this, we define it
409 if (af == AF_INET6) {
410 struct const in6_addr *ipaddr = src;
412 if (cnt <= INET6_ADDRSTRLEN) return NULL;
414 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
415 (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
416 (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
417 (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
418 (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
419 (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
420 (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
421 (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
422 (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
426 return NULL; /* don't support IPv6 */
432 * Wrappers for IPv4/IPv6 host to IP address lookup.
433 * This API returns only one IP address, of the specified
434 * address family, or the first address (of whatever family),
435 * if AF_UNSPEC is used.
437 int ip_hton(char const *src, int af, fr_ipaddr_t *dst)
440 struct addrinfo hints, *ai = NULL, *res = NULL;
442 memset(&hints, 0, sizeof(hints));
443 hints.ai_family = af;
445 if ((rcode = getaddrinfo(src, NULL, &hints, &res)) != 0) {
446 fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
450 for (ai = res; ai; ai = ai->ai_next) {
451 if ((af == ai->ai_family) || (af == AF_UNSPEC))
456 fr_strerror_printf("ip_hton failed to find requested information for host %.100s", src);
461 rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
462 ai->ai_addrlen, dst, NULL);
464 if (!rcode) return -1;
470 * Look IP addresses up, and print names (depending on DNS config)
472 char const *ip_ntoh(fr_ipaddr_t const *src, char *dst, size_t cnt)
474 struct sockaddr_storage ss;
481 if (!fr_dns_lookups) {
482 return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
485 if (!fr_ipaddr2sockaddr(src, 0, &ss, &salen)) {
489 if ((error = getnameinfo((struct sockaddr *)&ss, salen, dst, cnt, NULL, 0,
490 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
491 fr_strerror_printf("ip_ntoh: %s", gai_strerror(error));
498 static char const *hextab = "0123456789abcdef";
500 /** Convert hex strings to binary data
502 * @param bin Buffer to write output to.
503 * @param hex input string.
504 * @param outlen length of output buffer (or length of input string / 2).
505 * @return length of data written to buffer.
507 size_t fr_hex2bin(uint8_t *bin, char const *hex, size_t outlen)
512 for (i = 0; i < outlen; i++) {
513 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
514 !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
516 bin[i] = ((c1-hextab)<<4) + (c2-hextab);
523 /** Convert binary data to a hex string
525 * Ascii encoded hex string will not be prefixed with '0x'
527 * @warning If the output buffer isn't long enough, we have a buffer overflow.
529 * @param[out] hex Buffer to write hex output.
530 * @param[in] bin input.
531 * @param[in] inlen of bin input.
532 * @return length of data written to buffer.
534 size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
538 for (i = 0; i < inlen; i++) {
539 hex[0] = hextab[((*bin) >> 4) & 0x0f];
540 hex[1] = hextab[*bin & 0x0f];
551 * So we don't have ifdef's in the rest of the code
553 #ifndef HAVE_CLOSEFROM
554 int closefrom(int fd)
560 maxfd = sysconf(_SC_OPEN_MAX);
566 if (fd > maxfd) return 0;
569 * FIXME: return EINTR?
573 for (i = fd; i < maxfd; i++) {
581 int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
583 if (a->af < b->af) return -1;
584 if (a->af > b->af) return +1;
588 return memcmp(&a->ipaddr.ip4addr,
590 sizeof(a->ipaddr.ip4addr));
593 #ifdef HAVE_STRUCT_SOCKADDR_IN6
595 if (a->scope < b->scope) return -1;
596 if (a->scope > b->scope) return +1;
598 return memcmp(&a->ipaddr.ip6addr,
600 sizeof(a->ipaddr.ip6addr));
611 int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, int port,
612 struct sockaddr_storage *sa, socklen_t *salen)
614 if (ipaddr->af == AF_INET) {
615 struct sockaddr_in s4;
619 memset(&s4, 0, sizeof(s4));
620 s4.sin_family = AF_INET;
621 s4.sin_addr = ipaddr->ipaddr.ip4addr;
622 s4.sin_port = htons(port);
623 memset(sa, 0, sizeof(*sa));
624 memcpy(sa, &s4, sizeof(s4));
626 #ifdef HAVE_STRUCT_SOCKADDR_IN6
627 } else if (ipaddr->af == AF_INET6) {
628 struct sockaddr_in6 s6;
632 memset(&s6, 0, sizeof(s6));
633 s6.sin6_family = AF_INET6;
634 s6.sin6_addr = ipaddr->ipaddr.ip6addr;
635 s6.sin6_port = htons(port);
636 s6.sin6_scope_id = ipaddr->scope;
637 memset(sa, 0, sizeof(*sa));
638 memcpy(sa, &s6, sizeof(s6));
648 int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
649 fr_ipaddr_t *ipaddr, int *port)
651 if (sa->ss_family == AF_INET) {
652 struct sockaddr_in s4;
654 if (salen < sizeof(s4)) {
655 fr_strerror_printf("IPv4 address is too small");
659 memcpy(&s4, sa, sizeof(s4));
660 ipaddr->af = AF_INET;
661 ipaddr->ipaddr.ip4addr = s4.sin_addr;
662 if (port) *port = ntohs(s4.sin_port);
664 #ifdef HAVE_STRUCT_SOCKADDR_IN6
665 } else if (sa->ss_family == AF_INET6) {
666 struct sockaddr_in6 s6;
668 if (salen < sizeof(s6)) {
669 fr_strerror_printf("IPv6 address is too small");
673 memcpy(&s6, sa, sizeof(s6));
674 ipaddr->af = AF_INET6;
675 ipaddr->ipaddr.ip6addr = s6.sin6_addr;
676 if (port) *port = ntohs(s6.sin6_port);
677 ipaddr->scope = s6.sin6_scope_id;
681 fr_strerror_printf("Unsupported address famility %d",