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>
31 #define FR_PUT_LE16(a, val)\
33 a[1] = ((uint16_t) (val)) >> 8;\
34 a[0] = ((uint16_t) (val)) & 0xff;\
38 # define PTHREAD_MUTEX_LOCK pthread_mutex_lock
39 # define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
41 # define PTHREAD_MUTEX_LOCK(_x)
42 # define PTHREAD_MUTEX_UNLOCK(_x)
45 bool fr_dns_lookups = false; /* IP -> hostname lookups? */
46 bool fr_hostname_lookups = true; /* hostname -> IP lookups? */
47 int fr_debug_flag = 0;
49 static char const *months[] = {
50 "jan", "feb", "mar", "apr", "may", "jun",
51 "jul", "aug", "sep", "oct", "nov", "dec" };
53 fr_thread_local_setup(char *, fr_inet_ntop_buffer); /* macro */
55 typedef struct fr_talloc_link {
60 /** Sets a signal handler using sigaction if available, else signal
62 * @param sig to set handler for.
63 * @param func handler to set.
65 int fr_set_signal(int sig, sig_t func)
70 memset(&act, 0, sizeof(act));
72 sigemptyset(&act.sa_mask);
73 act.sa_handler = func;
75 if (sigaction(sig, &act, NULL) < 0) {
76 fr_strerror_printf("Failed setting signal %i handler via sigaction(): %s", sig, fr_syserror(errno));
80 if (signal(sig, func) < 0) {
81 fr_strerror_printf("Failed setting signal %i handler via signal(): %s", sig, fr_syserror(errno));
88 static int _fr_trigger_talloc_ctx_free(fr_talloc_link_t *trigger)
90 if (trigger->armed) talloc_free(trigger->child);
95 static int _fr_disarm_talloc_ctx_free(bool **armed)
101 /** Link a parent and a child context, so the child is freed before the parent
103 * @note This is not thread safe. Do not free parent before threads are joined, do not call from a child thread.
104 * @note It's OK to free the child before threads are joined, but this will leak memory until the parent is freed.
106 * @param parent who's fate the child should share.
107 * @param child bound to parent's lifecycle.
108 * @return 0 on success -1 on failure.
110 int fr_link_talloc_ctx_free(TALLOC_CTX *parent, TALLOC_CTX *child)
112 fr_talloc_link_t *trigger;
115 trigger = talloc(parent, fr_talloc_link_t);
116 if (!trigger) return -1;
118 disarm = talloc(child, bool *);
120 talloc_free(trigger);
124 trigger->child = child;
125 trigger->armed = true;
126 *disarm = &trigger->armed;
128 talloc_set_destructor(trigger, _fr_trigger_talloc_ctx_free);
129 talloc_set_destructor(disarm, _fr_disarm_talloc_ctx_free);
135 * Explicitly cleanup the memory allocated to the error inet_ntop
138 static void _fr_inet_ntop_free(void *arg)
143 /** Wrapper around inet_ntop, prints IPv4/IPv6 addresses
145 * inet_ntop requires the caller pass in a buffer for the address.
146 * This would be annoying and cumbersome, seeing as quite often the ASCII
147 * address is only used for logging output.
149 * So as with lib/log.c use TLS to allocate thread specific buffers, and
150 * write the IP address there instead.
152 * @param af address family, either AF_INET or AF_INET6.
153 * @param src pointer to network address structure.
154 * @return NULL on error, else pointer to ASCII buffer containing text version of address.
156 char const *fr_inet_ntop(int af, void const *src)
164 buffer = fr_thread_local_init(fr_inet_ntop_buffer, _fr_inet_ntop_free);
169 * malloc is thread safe, talloc is not
171 buffer = malloc(sizeof(char) * INET6_ADDRSTRLEN);
173 fr_perror("Failed allocating memory for inet_ntop buffer");
177 ret = fr_thread_local_set(fr_inet_ntop_buffer, buffer);
179 fr_perror("Failed setting up TLS for inet_ntop buffer: %s", fr_syserror(ret));
186 return inet_ntop(af, src, buffer, INET6_ADDRSTRLEN);
190 * Return an IP address in standard dot notation
194 char const *ip_ntoa(char *buffer, uint32_t ipaddr)
196 ipaddr = ntohl(ipaddr);
198 sprintf(buffer, "%d.%d.%d.%d",
199 (ipaddr >> 24) & 0xff,
200 (ipaddr >> 16) & 0xff,
201 (ipaddr >> 8) & 0xff,
206 /** Parse an IPv4 address or IPv4 prefix in presentation format (and others)
208 * @param out Where to write the ip address value.
209 * @param value to parse, may be dotted quad [+ prefix], or integer, or octal number, or '*' (INADDR_ANY).
210 * @param inlen Length of value, if value is \0 terminated inlen may be -1.
211 * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
212 * @param fallback to IPv4 resolution if no A records can be found.
213 * @return 0 if ip address was parsed successfully, else -1 on error.
215 int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback)
221 /* Dotted quad + / + [0-9]{1,2} */
222 char buffer[INET_ADDRSTRLEN + 3];
225 * Copy to intermediary buffer if we were given a length
228 if (inlen >= (ssize_t)sizeof(buffer)) {
229 fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
232 memcpy(buffer, value, inlen);
233 buffer[inlen] = '\0';
236 p = strchr(value, '/');
238 * 192.0.2.2 is parsed as if it was /32
242 * Allow '*' as the wildcard address usually 0.0.0.0
244 if ((value[0] == '*') && (value[1] == '\0')) {
245 out->ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
247 * Convert things which are obviously integers to IP addresses
249 * We assume the number is the bigendian representation of the
252 } else if (is_integer(value) || ((value[0] == '0') && (value[1] == 'x'))) {
253 out->ipaddr.ip4addr.s_addr = htonl(strtoul(value, NULL, 0));
254 } else if (!resolve) {
255 if (inet_pton(AF_INET, value, &(out->ipaddr.ip4addr.s_addr)) <= 0) {
256 fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value);
259 } else if (ip_hton(out, AF_INET, value, fallback) < 0) return -1;
268 * Otherwise parse the prefix
270 if ((size_t)(p - value) >= INET_ADDRSTRLEN) {
271 fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
276 * Copy the IP portion into a temporary buffer if we haven't already.
278 if (inlen < 0) memcpy(buffer, value, p - value);
279 buffer[p - value] = '\0';
282 if (inet_pton(AF_INET, buffer, &(out->ipaddr.ip4addr.s_addr)) <= 0) {
283 fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value);
286 } else if (ip_hton(out, AF_INET, buffer, fallback) < 0) return -1;
288 prefix = strtoul(p + 1, &eptr, 10);
290 fr_strerror_printf("Invalid IPv4 mask length \"%s\". Should be between 0-32", p);
293 if (eptr[0] != '\0') {
294 fr_strerror_printf("Failed to parse IPv4 address string \"%s\", "
295 "got garbage after mask length \"%s\"", value, eptr);
300 out->ipaddr.ip4addr = fr_inaddr_mask(&(out->ipaddr.ip4addr), prefix);
303 out->prefix = (uint8_t) prefix;
309 /** Parse an IPv6 address or IPv6 prefix in presentation format (and others)
311 * @param out Where to write the ip address value.
312 * @param value to parse.
313 * @param inlen Length of value, if value is \0 terminated inlen may be -1.
314 * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
315 * @param fallback to IPv4 resolution if no AAAA records can be found.
316 * @return 0 if ip address was parsed successfully, else -1 on error.
318 int fr_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback)
324 /* IPv6 + / + [0-9]{1,3} */
325 char buffer[INET6_ADDRSTRLEN + 4];
328 * Copy to intermediary buffer if we were given a length
331 if (inlen >= (ssize_t)sizeof(buffer)) {
332 fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
335 memcpy(buffer, value, inlen);
336 buffer[inlen] = '\0';
339 p = strchr(value, '/');
342 * Allow '*' as the wildcard address
344 if ((value[0] == '*') && (value[1] == '\0')) {
345 memset(&out->ipaddr.ip6addr.s6_addr, 0, sizeof(out->ipaddr.ip6addr.s6_addr));
346 } else if (!resolve) {
347 if (inet_pton(AF_INET6, value, &(out->ipaddr.ip6addr.s6_addr)) <= 0) {
348 fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
351 } else if (ip_hton(out, AF_INET6, value, fallback) < 0) return -1;
359 if ((p - value) >= INET6_ADDRSTRLEN) {
360 fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
365 * Copy string to temporary buffer if we didn't do it earlier
367 if (inlen < 0) memcpy(buffer, value, p - value);
368 buffer[p - value] = '\0';
371 if (inet_pton(AF_INET6, buffer, &(out->ipaddr.ip6addr.s6_addr)) <= 0) {
372 fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
375 } else if (ip_hton(out, AF_INET6, buffer, fallback) < 0) return -1;
377 prefix = strtoul(p + 1, &eptr, 10);
379 fr_strerror_printf("Invalid IPv6 mask length \"%s\". Should be between 0-128", p);
382 if (eptr[0] != '\0') {
383 fr_strerror_printf("Failed to parse IPv6 address string \"%s\", "
384 "got garbage after mask length \"%s\"", value, eptr);
389 struct in6_addr addr;
391 addr = fr_in6addr_mask(&(out->ipaddr.ip6addr), prefix);
392 memcpy(&(out->ipaddr.ip6addr.s6_addr), &addr, sizeof(addr));
395 out->prefix = (uint8_t) prefix;
401 /** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser.
403 * @param out Where to write the ip address value.
404 * @param value to parse.
405 * @param inlen Length of value, if value is \0 terminated inlen may be -1.
406 * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
407 * @return 0 if ip address was parsed successfully, else -1 on error.
409 int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve)
413 len = (inlen < 0) ? strlen(value) : inlen;
414 for (i = 0; i < len; i++) switch (value[i]) {
416 * Chars illegal in domain names and IPv4 addresses.
417 * Must be v6 and cannot be a domain.
422 return fr_pton6(out, value, inlen, false, false);
425 * Chars which don't really tell us anything
433 * Outside the range of IPv4 chars, must be a domain
434 * Use A record in preference to AAAA record.
436 if ((value[i] < '0') || (value[i] > '9')) {
437 if (!resolve) return -1;
438 return fr_pton4(out, value, inlen, true, true);
444 * All chars were in the IPv4 set [0-9/.], must be an IPv4
447 return fr_pton4(out, value, inlen, false, false);
450 int fr_ntop(char *out, size_t outlen, fr_ipaddr_t *addr)
452 char buffer[INET6_ADDRSTRLEN];
454 if (inet_ntop(addr->af, &(addr->ipaddr), buffer, sizeof(buffer)) == NULL) return -1;
456 return snprintf(out, outlen, "%s/%i", buffer, addr->prefix);
460 * Internal wrapper for locking, to minimize the number of ifdef's
464 int rad_lockfd(int fd, int lock_len)
473 fl.l_whence = SEEK_CUR;
475 return fcntl(fd, F_SETLKW, (void *)&fl);
477 #error "missing definition for F_WRLCK, all file locks will fail"
484 * Internal wrapper for locking, to minimize the number of ifdef's
486 * Lock an fd, prefer lockf() over flock()
487 * Nonblocking version.
489 int rad_lockfd_nonblock(int fd, int lock_len)
498 fl.l_whence = SEEK_CUR;
500 return fcntl(fd, F_SETLK, (void *)&fl);
502 #error "missing definition for F_WRLCK, all file locks will fail"
509 * Internal wrapper for unlocking, to minimize the number of ifdef's
512 * Unlock an fd, prefer lockf() over flock()
514 int rad_unlockfd(int fd, int lock_len)
523 fl.l_whence = SEEK_CUR;
525 return fcntl(fd, F_UNLCK, (void *)&fl);
527 #error "missing definition for F_WRLCK, all file locks will fail"
534 * Return an interface-id in standard colon notation
536 char *ifid_ntoa(char *buffer, size_t size, uint8_t const *ifid)
538 snprintf(buffer, size, "%x:%x:%x:%x",
539 (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
540 (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
546 * Return an interface-id from
547 * one supplied in standard colon notation.
549 uint8_t *ifid_aton(char const *ifid_str, uint8_t *ifid)
551 static char const xdigits[] = "0123456789abcdef";
553 int num_id = 0, val = 0, idx = 0;
555 for (p = ifid_str; ; ++p) {
556 if (*p == ':' || *p == '\0') {
561 * Drop 'val' into the array.
563 ifid[idx] = (val >> 8) & 0xff;
564 ifid[idx + 1] = val & 0xff;
567 * Must have all entries before
578 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
582 * Dumb version of 'scanf'
585 val |= (pch - xdigits);
593 #ifndef HAVE_INET_PTON
594 static int inet_pton4(char const *src, struct in_addr *dst)
600 static char const digits[] = "0123456789";
606 while (*p && ((off = strchr(digits, *p)) != NULL)) {
608 num += (off - digits);
610 if (num > 255) return 0;
617 * Not a digit, MUST be a dot, else we
629 * End of the string. At the fourth
630 * octet is OK, anything else is an
638 memcpy(dst, &tmp, sizeof(tmp));
643 #ifdef HAVE_STRUCT_SOCKADDR_IN6
645 * inet_pton6(src, dst)
646 * convert presentation level address to network order binary form.
648 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
650 * (1) does not touch `dst' unless it's returning 1.
651 * (2) :: in a full address is silently ignored.
653 * inspired by Mark Andrews.
657 static int inet_pton6(char const *src, unsigned char *dst)
659 static char const xdigits_l[] = "0123456789abcdef",
660 xdigits_u[] = "0123456789ABCDEF";
661 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
662 char const *xdigits, *curtok;
666 memset((tp = tmp), 0, IN6ADDRSZ);
667 endp = tp + IN6ADDRSZ;
669 /* Leading :: requires some special handling. */
676 while ((ch = *src++) != '\0') {
679 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
680 pch = strchr((xdigits = xdigits_u), ch);
683 val |= (pch - xdigits);
697 if (tp + INT16SZ > endp)
699 *tp++ = (u_char) (val >> 8) & 0xff;
700 *tp++ = (u_char) val & 0xff;
705 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
706 inet_pton4(curtok, (struct in_addr *) tp) > 0) {
709 break; /* '\0' was seen by inet_pton4(). */
714 if (tp + INT16SZ > endp)
716 *tp++ = (u_char) (val >> 8) & 0xff;
717 *tp++ = (u_char) val & 0xff;
719 if (colonp != NULL) {
721 * Since some memmove()'s erroneously fail to handle
722 * overlapping regions, we'll do the shift by hand.
724 int const n = tp - colonp;
727 for (i = 1; i <= n; i++) {
728 endp[- i] = colonp[n - i];
735 /* bcopy(tmp, dst, IN6ADDRSZ); */
736 memcpy(dst, tmp, IN6ADDRSZ);
742 * Utility function, so that the rest of the server doesn't
743 * have ifdef's around IPv6 support
745 int inet_pton(int af, char const *src, void *dst)
748 return inet_pton4(src, dst);
750 #ifdef HAVE_STRUCT_SOCKADDR_IN6
752 if (af == AF_INET6) {
753 return inet_pton6(src, dst);
761 #ifndef HAVE_INET_NTOP
763 * Utility function, so that the rest of the server doesn't
764 * have ifdef's around IPv6 support
766 char const *inet_ntop(int af, void const *src, char *dst, size_t cnt)
769 uint8_t const *ipaddr = src;
771 if (cnt <= INET_ADDRSTRLEN) return NULL;
773 snprintf(dst, cnt, "%d.%d.%d.%d",
774 ipaddr[0], ipaddr[1],
775 ipaddr[2], ipaddr[3]);
780 * If the system doesn't define this, we define it
783 if (af == AF_INET6) {
784 struct in6_addr const *ipaddr = src;
786 if (cnt <= INET6_ADDRSTRLEN) return NULL;
788 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
789 (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
790 (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
791 (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
792 (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
793 (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
794 (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
795 (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
796 (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
800 return NULL; /* don't support IPv6 */
804 /** Wrappers for IPv4/IPv6 host to IP address lookup
806 * This function returns only one IP address, of the specified address family,
807 * or the first address (of whatever family), if AF_UNSPEC is used.
809 * If fallback is specified and af is AF_INET, but no AF_INET records were
810 * found and a record for AF_INET6 exists that record will be returned.
812 * If fallback is specified and af is AF_INET6, and a record with AF_INET4 exists
813 * that record will be returned instead.
815 * @param out Where to write result.
816 * @param af To search for in preference.
817 * @param hostname to search for.
818 * @param fallback to the other adress family, if no records matching af, found.
819 * @return 0 on success, else -1 on failure.
821 int ip_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
824 struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
826 if (!fr_hostname_lookups) {
827 #ifdef HAVE_STRUCT_SOCKADDR_IN6
828 if (af == AF_UNSPEC) {
831 for (p = hostname; *p != '\0'; p++) {
842 if (af == AF_UNSPEC) af = AF_INET;
844 if (!inet_pton(af, hostname, &(out->ipaddr))) {
852 memset(&hints, 0, sizeof(hints));
853 hints.ai_family = af;
857 * Avoid malloc for IP addresses. This helps us debug
858 * memory errors when using talloc.
862 * If it's all numeric, avoid getaddrinfo()
864 if (inet_pton(af, hostname, &out->ipaddr.ip4addr) == 1) {
870 if ((rcode = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
871 fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
875 for (ai = res; ai; ai = ai->ai_next) {
876 if ((af == ai->ai_family) || (af == AF_UNSPEC)) break;
877 if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
882 fr_strerror_printf("ip_hton failed to find requested information for host %.100s", hostname);
887 rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
888 ai->ai_addrlen, out, NULL);
890 if (!rcode) return -1;
896 * Look IP addresses up, and print names (depending on DNS config)
898 char const *ip_ntoh(fr_ipaddr_t const *src, char *dst, size_t cnt)
900 struct sockaddr_storage ss;
907 if (!fr_dns_lookups) {
908 return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
911 if (!fr_ipaddr2sockaddr(src, 0, &ss, &salen)) {
915 if ((error = getnameinfo((struct sockaddr *)&ss, salen, dst, cnt, NULL, 0,
916 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
917 fr_strerror_printf("ip_ntoh: %s", gai_strerror(error));
923 /** Mask off a portion of an IPv4 address
925 * @param ipaddr to mask.
926 * @param prefix Number of contiguous bits to mask.
927 * @return an ipv6 address with the host portion zeroed out.
929 struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
944 else ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
945 return (*(struct in_addr *)&ret);
948 /** Mask off a portion of an IPv6 address
950 * @param ipaddr to mask.
951 * @param prefix Number of contiguous bits to mask.
952 * @return an ipv6 address with the host portion zeroed out.
954 struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
956 uint64_t const *p = (uint64_t const *) ipaddr;
957 uint64_t ret[2], *o = ret;
970 *o++ = 0xffffffffffffffffULL & *p++;
975 *o = htonll(~((0x0000000000000001ULL << (64 - prefix)) - 1)) & *p;
977 return *(struct in6_addr *) &ret;
980 /** Zeroes out the host portion of an fr_ipaddr_t
982 * @param[in,out] addr to mask
983 * @param[in] prefix Length of the network portion.
985 void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
990 addr->ipaddr.ip4addr = fr_inaddr_mask(&addr->ipaddr.ip4addr, prefix);
994 addr->ipaddr.ip6addr = fr_in6addr_mask(&addr->ipaddr.ip6addr, prefix);
1000 addr->prefix = prefix;
1003 static char const hextab[] = "0123456789abcdef";
1005 /** Convert hex strings to binary data
1007 * @param bin Buffer to write output to.
1008 * @param outlen length of output buffer (or length of input string / 2).
1009 * @param hex input string.
1010 * @param inlen length of the input string
1011 * @return length of data written to buffer.
1013 size_t fr_hex2bin(uint8_t *bin, size_t outlen, char const *hex, size_t inlen)
1020 * Smartly truncate output, caller should check number of bytes
1024 if (len > outlen) len = outlen;
1026 for (i = 0; i < len; i++) {
1027 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), sizeof(hextab))) ||
1028 !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), sizeof(hextab))))
1030 bin[i] = ((c1-hextab)<<4) + (c2-hextab);
1036 /** Convert binary data to a hex string
1038 * Ascii encoded hex string will not be prefixed with '0x'
1040 * @warning If the output buffer isn't long enough, we have a buffer overflow.
1042 * @param[out] hex Buffer to write hex output.
1043 * @param[in] bin input.
1044 * @param[in] inlen of bin input.
1045 * @return length of data written to buffer.
1047 size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
1051 for (i = 0; i < inlen; i++) {
1052 hex[0] = hextab[((*bin) >> 4) & 0x0f];
1053 hex[1] = hextab[*bin & 0x0f];
1062 /** Convert binary data to a hex string
1064 * Ascii encoded hex string will not be prefixed with '0x'
1066 * @param[in] ctx to alloc buffer in.
1067 * @param[in] bin input.
1068 * @param[in] inlen of bin input.
1069 * @return length of data written to buffer.
1071 char *fr_abin2hex(TALLOC_CTX *ctx, uint8_t const *bin, size_t inlen)
1075 buff = talloc_array(ctx, char, (inlen << 2));
1076 if (!buff) return NULL;
1078 fr_bin2hex(buff, bin, inlen);
1083 /** Consume the integer (or hex) portion of a value string
1085 * @param value string to parse.
1086 * @param end pointer to the first non numeric char.
1087 * @return integer value.
1089 uint32_t fr_strtoul(char const *value, char **end)
1091 if ((value[0] == '0') && (value[1] == 'x')) {
1092 return strtoul(value, end, 16);
1095 return strtoul(value, end, 10);
1098 /** Check whether the string is all whitespace
1100 * @return true if the entirety of the string is whitespace, else false.
1102 bool is_whitespace(char const *value)
1105 if (!isspace(*value)) return false;
1111 /** Check whether the string is all numbers
1113 * @return true if the entirety of the string is are numebrs, else false.
1115 bool is_integer(char const *value)
1118 if (!isdigit(*value)) return false;
1124 /** Check whether the string is allzeros
1126 * @return true if the entirety of the string is are numebrs, else false.
1128 bool is_zero(char const *value)
1131 if (*value != '0') return false;
1138 * So we don't have ifdef's in the rest of the code
1140 #ifndef HAVE_CLOSEFROM
1141 int closefrom(int fd)
1147 maxfd = sysconf(_SC_OPEN_MAX);
1153 if (fd > maxfd) return 0;
1156 * FIXME: return EINTR?
1160 for (i = fd; i < maxfd; i++) {
1168 int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
1170 if (a->af < b->af) return -1;
1171 if (a->af > b->af) return +1;
1173 if (a->prefix < b->prefix) return -1;
1174 if (a->prefix > b->prefix) return +1;
1178 return memcmp(&a->ipaddr.ip4addr,
1180 sizeof(a->ipaddr.ip4addr));
1183 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1185 if (a->scope < b->scope) return -1;
1186 if (a->scope > b->scope) return +1;
1188 return memcmp(&a->ipaddr.ip6addr,
1190 sizeof(a->ipaddr.ip6addr));
1201 int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port,
1202 struct sockaddr_storage *sa, socklen_t *salen)
1204 memset(sa, 0, sizeof(*sa));
1206 if (ipaddr->af == AF_INET) {
1207 struct sockaddr_in s4;
1209 *salen = sizeof(s4);
1211 memset(&s4, 0, sizeof(s4));
1212 s4.sin_family = AF_INET;
1213 s4.sin_addr = ipaddr->ipaddr.ip4addr;
1214 s4.sin_port = htons(port);
1215 memset(sa, 0, sizeof(*sa));
1216 memcpy(sa, &s4, sizeof(s4));
1218 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1219 } else if (ipaddr->af == AF_INET6) {
1220 struct sockaddr_in6 s6;
1222 *salen = sizeof(s6);
1224 memset(&s6, 0, sizeof(s6));
1225 s6.sin6_family = AF_INET6;
1226 s6.sin6_addr = ipaddr->ipaddr.ip6addr;
1227 s6.sin6_port = htons(port);
1228 s6.sin6_scope_id = ipaddr->scope;
1229 memset(sa, 0, sizeof(*sa));
1230 memcpy(sa, &s6, sizeof(s6));
1240 int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
1241 fr_ipaddr_t *ipaddr, uint16_t *port)
1243 memset(ipaddr, 0, sizeof(*ipaddr));
1245 if (sa->ss_family == AF_INET) {
1246 struct sockaddr_in s4;
1248 if (salen < sizeof(s4)) {
1249 fr_strerror_printf("IPv4 address is too small");
1253 memcpy(&s4, sa, sizeof(s4));
1254 ipaddr->af = AF_INET;
1255 ipaddr->prefix = 32;
1256 ipaddr->ipaddr.ip4addr = s4.sin_addr;
1257 if (port) *port = ntohs(s4.sin_port);
1259 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1260 } else if (sa->ss_family == AF_INET6) {
1261 struct sockaddr_in6 s6;
1263 if (salen < sizeof(s6)) {
1264 fr_strerror_printf("IPv6 address is too small");
1268 memcpy(&s6, sa, sizeof(s6));
1269 ipaddr->af = AF_INET6;
1270 ipaddr->prefix = 128;
1271 ipaddr->ipaddr.ip6addr = s6.sin6_addr;
1272 if (port) *port = ntohs(s6.sin6_port);
1273 ipaddr->scope = s6.sin6_scope_id;
1277 fr_strerror_printf("Unsupported address famility %d",
1285 /** Convert UTF8 string to UCS2 encoding
1287 * @note Borrowed from src/crypto/ms_funcs.c of wpa_supplicant project (http://hostap.epitest.fi/wpa_supplicant/)
1289 * @param[out] out Where to write the ucs2 string.
1290 * @param[in] outlen Size of output buffer.
1291 * @param[in] in UTF8 string to convert.
1292 * @param[in] inlen length of UTF8 string.
1293 * @return the size of the UCS2 string written to the output buffer (in bytes).
1295 ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen)
1298 uint8_t *start = out;
1300 for (i = 0; i < inlen; i++) {
1304 if ((size_t)(out - start) >= outlen) {
1305 /* input too long */
1309 /* One-byte encoding */
1311 FR_PUT_LE16(out, c);
1314 } else if ((i == (inlen - 1)) || ((size_t)(out - start) >= (outlen - 1))) {
1315 /* Incomplete surrogate */
1320 /* Two-byte encoding */
1321 if ((c & 0xe0) == 0xc0) {
1322 FR_PUT_LE16(out, ((c & 0x1f) << 6) | (c2 & 0x3f));
1326 if ((i == inlen) || ((size_t)(out - start) >= (outlen - 1))) {
1327 /* Incomplete surrogate */
1331 /* Three-byte encoding */
1333 FR_PUT_LE16(out, ((c & 0xf) << 12) | ((c2 & 0x3f) << 6) | (c3 & 0x3f));
1340 /** Write 128bit unsigned integer to buffer
1342 * @author Alexey Frunze
1344 * @param out where to write result to.
1345 * @param outlen size of out.
1346 * @param num 128 bit integer.
1348 size_t fr_prints_uint128(char *out, size_t outlen, uint128_t const num)
1350 char buff[128 / 3 + 1 + 1];
1354 #ifdef RADIUS_LITTLE_ENDIAN
1362 memset(buff, '0', sizeof(buff) - 1);
1363 buff[sizeof(buff) - 1] = '\0';
1365 memcpy(n, &num, sizeof(n));
1367 for (i = 0; i < 128; i++) {
1371 carry = (n[h] >= 0x8000000000000000);
1373 // Shift n[] left, doubling it
1374 n[h] = ((n[h] << 1) & 0xffffffffffffffff) + (n[l] >= 0x8000000000000000);
1375 n[l] = ((n[l] << 1) & 0xffffffffffffffff);
1377 // Add s[] to itself in decimal, doubling it
1378 for (j = sizeof(buff) - 2; j >= 0; j--) {
1379 buff[j] += buff[j] - '0' + carry;
1380 carry = (buff[j] > '9');
1387 while ((*p == '0') && (p < &buff[sizeof(buff) - 2])) {
1391 return strlcpy(out, p, outlen);
1395 * Sort of strtok/strsep function.
1397 static char *mystrtok(char **ptr, char const *sep)
1405 while (**ptr && strchr(sep, **ptr)) {
1413 while (**ptr && strchr(sep, **ptr) == NULL) {
1423 /** Convert string in various formats to a time_t
1425 * @param date_str input date string.
1426 * @param date time_t to write result to.
1427 * @return 0 on success or -1 on error.
1429 int fr_get_time(char const *date_str, time_t *date)
1433 struct tm *tm, s_tm;
1440 * Test for unix timestamp date
1442 *date = strtoul(date_str, &tail, 10);
1443 if (*tail == '\0') {
1448 memset(tm, 0, sizeof(*tm));
1449 tm->tm_isdst = -1; /* don't know, and don't care about DST */
1451 strlcpy(buf, date_str, sizeof(buf));
1454 f[0] = mystrtok(&p, " \t");
1455 f[1] = mystrtok(&p, " \t");
1456 f[2] = mystrtok(&p, " \t");
1457 f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
1458 if (!f[0] || !f[1] || !f[2]) return -1;
1461 * The time has a colon, where nothing else does.
1462 * So if we find it, bubble it to the back of the list.
1465 for (i = 0; i < 3; i++) {
1466 if (strchr(f[i], ':')) {
1476 * The month is text, which allows us to find it easily.
1479 for (i = 0; i < 3; i++) {
1480 if (isalpha( (int) *f[i])) {
1482 * Bubble the month to the front of the list
1488 for (i = 0; i < 12; i++) {
1489 if (strncasecmp(months[i], f[0], 3) == 0) {
1497 /* month not found? */
1498 if (tm->tm_mon == 12) return -1;
1501 * The year may be in f[1], or in f[2]
1503 tm->tm_year = atoi(f[1]);
1504 tm->tm_mday = atoi(f[2]);
1506 if (tm->tm_year >= 1900) {
1507 tm->tm_year -= 1900;
1511 * We can't use 2-digit years any more, they make it
1512 * impossible to tell what's the day, and what's the year.
1514 if (tm->tm_mday < 1900) return -1;
1517 * Swap the year and the day.
1520 tm->tm_year = tm->tm_mday - 1900;
1525 * If the day is out of range, die.
1527 if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
1532 * There may be %H:%M:%S. Parse it in a hacky way.
1535 f[0] = f[3]; /* HH */
1536 f[1] = strchr(f[0], ':'); /* find : separator */
1537 if (!f[1]) return -1;
1539 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
1541 f[2] = strchr(f[1], ':'); /* find : separator */
1543 *(f[2]++) = '\0'; /* nuke it, and point to SS */
1544 tm->tm_sec = atoi(f[2]);
1545 } /* else leave it as zero */
1547 tm->tm_hour = atoi(f[0]);
1548 tm->tm_min = atoi(f[1]);
1552 * Returns -1 on error.
1555 if (t == (time_t) -1) return -1;
1562 /** Compares two pointers
1564 * @param a first pointer to compare.
1565 * @param b second pointer to compare.
1566 * @return -1 if a < b, +1 if b > a, or 0 if both equal.
1568 int8_t fr_pointer_cmp(void const *a, void const *b)
1570 if (a < b) return -1;
1571 if (a == b) return 0;
1576 static int _quick_partition(void const *to_sort[], int min, int max, fr_cmp_t cmp) {
1577 void const *pivot = to_sort[min];
1583 do ++i; while((cmp(to_sort[i], pivot) <= 0) && i <= max);
1584 do --j; while(cmp(to_sort[j], pivot) > 0);
1589 to_sort[i] = to_sort[j];
1594 to_sort[min] = to_sort[j];
1600 /** Quick sort an array of pointers using a comparator
1602 * @param to_sort array of pointers to sort.
1603 * @param min_idx the lowest index (usually 0).
1604 * @param max_idx the highest index (usually length of array - 1).
1605 * @param cmp the comparison function to use to sort the array elements.
1607 void fr_quick_sort(void const *to_sort[], int min_idx, int max_idx, fr_cmp_t cmp)
1611 if (min_idx >= max_idx) return;
1613 part = _quick_partition(to_sort, min_idx, max_idx, cmp);
1614 fr_quick_sort(to_sort, min_idx, part - 1, cmp);
1615 fr_quick_sort(to_sort, part + 1, max_idx, cmp);
1619 void fr_talloc_verify_cb(UNUSED const void *ptr, UNUSED int depth,
1620 UNUSED int max_depth, UNUSED int is_ref,
1621 UNUSED void *private_data)