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 The FreeRADIUS server project
23 static const char rcsid[] =
26 #include <freeradius-devel/autoconf.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
42 #include <freeradius-devel/missing.h>
43 #include <freeradius-devel/libradius.h>
50 * Return an IP address in standard dot notation
54 const char *ip_ntoa(char *buffer, uint32_t ipaddr)
56 ipaddr = ntohl(ipaddr);
58 sprintf(buffer, "%d.%d.%d.%d",
59 (ipaddr >> 24) & 0xff,
60 (ipaddr >> 16) & 0xff,
68 * Like strncpy, but always adds \0
70 char *strNcpy(char *dest, const char *src, int n)
74 while ((n > 1) && (*src)) {
85 * Internal wrapper for locking, to minimize the number of ifdef's
87 * Lock an fd, prefer lockf() over flock()
89 int rad_lockfd(int fd, int lock_len)
91 #if defined(F_LOCK) && !defined(BSD)
92 return lockf(fd, F_LOCK, lock_len);
93 #elif defined(LOCK_EX)
94 return flock(fd, LOCK_EX);
101 fl.l_whence = SEEK_CUR;
102 return fcntl(fd, F_SETLKW, (void *)&fl);
107 * Internal wrapper for locking, to minimize the number of ifdef's
109 * Lock an fd, prefer lockf() over flock()
110 * Nonblocking version.
112 int rad_lockfd_nonblock(int fd, int lock_len)
114 #if defined(F_LOCK) && !defined(BSD)
115 return lockf(fd, F_TLOCK, lock_len);
116 #elif defined(LOCK_EX)
117 return flock(fd, LOCK_EX | LOCK_NB);
124 fl.l_whence = SEEK_CUR;
125 return fcntl(fd, F_SETLK, (void *)&fl);
130 * Internal wrapper for unlocking, to minimize the number of ifdef's
133 * Unlock an fd, prefer lockf() over flock()
135 int rad_unlockfd(int fd, int lock_len)
137 #if defined(F_LOCK) && !defined(BSD)
138 return lockf(fd, F_ULOCK, lock_len);
139 #elif defined(LOCK_EX)
140 return flock(fd, LOCK_UN);
147 fl.l_whence = SEEK_CUR;
148 return fcntl(fd, F_UNLCK, (void *)&fl);
153 * Return an interface-id in standard colon notation
155 char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid)
157 snprintf(buffer, size, "%x:%x:%x:%x",
158 (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
159 (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
165 * Return an interface-id from
166 * one supplied in standard colon notation.
168 uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid)
170 static const char xdigits[] = "0123456789abcdef";
172 int num_id = 0, val = 0, idx = 0;
174 for (p = ifid_str; ; ++p) {
175 if (*p == ':' || *p == '\0') {
180 * Drop 'val' into the array.
182 ifid[idx] = (val >> 8) & 0xff;
183 ifid[idx + 1] = val & 0xff;
186 * Must have all entries before
197 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
201 * Dumb version of 'scanf'
204 val |= (pch - xdigits);
212 #ifndef HAVE_INET_PTON
213 static int inet_pton4(const char *src, struct in_addr *dst)
219 static const char digits[] = "0123456789";
225 while (*p && ((off = strchr(digits, *p)) != NULL)) {
227 num += (off - digits);
229 if (num > 255) return 0;
236 * Not a digit, MUST be a dot, else we
248 * End of the string. At the fourth
249 * octet is OK, anything else is an
257 memcpy(dst, &tmp, sizeof(tmp));
263 * inet_pton6(src, dst)
264 * convert presentation level address to network order binary form.
266 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
268 * (1) does not touch `dst' unless it's returning 1.
269 * (2) :: in a full address is silently ignored.
271 * inspired by Mark Andrews.
276 inet_pton6(const char *src, unsigned char *dst)
278 static const char xdigits_l[] = "0123456789abcdef",
279 xdigits_u[] = "0123456789ABCDEF";
280 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
281 const char *xdigits, *curtok;
285 memset((tp = tmp), 0, IN6ADDRSZ);
286 endp = tp + IN6ADDRSZ;
288 /* Leading :: requires some special handling. */
295 while ((ch = *src++) != '\0') {
298 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
299 pch = strchr((xdigits = xdigits_u), ch);
302 val |= (pch - xdigits);
316 if (tp + INT16SZ > endp)
318 *tp++ = (u_char) (val >> 8) & 0xff;
319 *tp++ = (u_char) val & 0xff;
324 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
325 inet_pton4(curtok, tp) > 0) {
328 break; /* '\0' was seen by inet_pton4(). */
333 if (tp + INT16SZ > endp)
335 *tp++ = (u_char) (val >> 8) & 0xff;
336 *tp++ = (u_char) val & 0xff;
338 if (colonp != NULL) {
340 * Since some memmove()'s erroneously fail to handle
341 * overlapping regions, we'll do the shift by hand.
343 const int n = tp - colonp;
346 for (i = 1; i <= n; i++) {
347 endp[- i] = colonp[n - i];
354 /* bcopy(tmp, dst, IN6ADDRSZ); */
355 memcpy(dst, tmp, IN6ADDRSZ);
360 * Utility function, so that the rest of the server doesn't
361 * have ifdef's around IPv6 support
363 int inet_pton(int af, const char *src, void *dst)
366 return inet_pton4(src, dst);
369 if (af == AF_INET6) {
370 return inet_pton6(src, dst);
378 #ifndef HAVE_INET_NTOP
380 * Utility function, so that the rest of the server doesn't
381 * have ifdef's around IPv6 support
383 const char *inet_ntop(int af, const void *src, char *dst, size_t cnt)
386 const uint8_t *ipaddr = src;
388 if (cnt <= INET_ADDRSTRLEN) return NULL;
390 snprintf(dst, cnt, "%d.%d.%d.%d",
391 ipaddr[0], ipaddr[1],
392 ipaddr[2], ipaddr[3]);
397 * If the system doesn't define this, we define it
400 if (af == AF_INET6) {
401 const struct in6_addr *ipaddr = src;
403 if (cnt <= INET6_ADDRSTRLEN) return NULL;
405 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
406 (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
407 (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
408 (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
409 (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
410 (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
411 (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
412 (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
413 (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
417 return NULL; /* don't support IPv6 */
423 * Wrappers for IPv4/IPv6 host to IP address lookup.
424 * This API returns only one IP address, of the specified
425 * address family, or the first address (of whatever family),
426 * if AF_UNSPEC is used.
428 int ip_hton(const char *src, int af, lrad_ipaddr_t *dst)
431 struct addrinfo hints, *ai = NULL, *res = NULL;
433 memset(&hints, 0, sizeof(hints));
434 hints.ai_family = af;
436 if ((error = getaddrinfo(src, NULL, &hints, &res)) != 0) {
437 librad_log("ip_nton: %s", gai_strerror(error));
441 for (ai = res; ai; ai = ai->ai_next) {
442 if ((af == ai->ai_family) || (af == AF_UNSPEC))
447 librad_log("ip_hton failed to find requested information for host %.100s", src);
452 switch (ai->ai_family) {
456 &((struct sockaddr_in*)ai->ai_addr)->sin_addr,
457 sizeof(struct in_addr));
463 &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr,
464 sizeof(struct in6_addr));
467 /* Flow should never reach here */
470 librad_log("ip_hton found unusable information for host %.100s", src);
480 * Look IP addreses up, and print names (depending on DNS config)
482 const char *ip_ntoh(const lrad_ipaddr_t *src, char *dst, size_t cnt)
484 struct sockaddr_storage ss;
485 struct sockaddr_in *s4;
492 return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
496 memset(&ss, 0, sizeof(ss));
499 s4 = (struct sockaddr_in *)&ss;
500 len = sizeof(struct sockaddr_in);
501 s4->sin_family = AF_INET;
503 memcpy(&s4->sin_addr, &src->ipaddr.ip4addr, 4);
506 #ifdef HAVE_STRUCT_SOCKADDR_IN6
509 struct sockaddr_in6 *s6;
511 s6 = (struct sockaddr_in6 *)&ss;
512 len = sizeof(struct sockaddr_in6);
513 s6->sin6_family = AF_INET6;
514 s6->sin6_flowinfo = 0;
516 memcpy(&s6->sin6_addr, &src->ipaddr.ip6addr, 16);
525 if ((error = getnameinfo((struct sockaddr *)&ss, len, dst, cnt, NULL, 0,
526 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
527 librad_log("ip_ntoh: %s", gai_strerror(error));
534 static const char *hextab = "0123456789abcdef";
539 * We allow: hex == bin
541 int lrad_hex2bin(const char *hex, uint8_t *bin, int len)
546 for (i = 0; i < len; i++) {
547 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
548 !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
550 bin[i] = ((c1-hextab)<<4) + (c2-hextab);
560 * If the output buffer isn't long enough, we have a buffer overflow.
562 void lrad_bin2hex(const uint8_t *bin, char *hex, int len)
566 for (i = 0; i < len; i++) {
567 hex[0] = hextab[((*bin) >> 4) & 0x0f];
568 hex[1] = hextab[*bin & 0x0f];
578 * So we don't have ifdef's in the rest of the code
580 #ifndef HAVE_CLOSEFROM
581 int closefrom(int fd)
587 maxfd = sysconf(_SC_OPEN_MAX);
593 if (fd > maxfd) return 0;
596 * FIXME: return EINTR?
600 for (i = fd; i < maxfd; i++) {