#include #include #include #include #include #include #include #include #include #include "triton.h" #include "utils.h" #include "memdebug.h" extern int urandom_fd; /* Convenient wrapper around inet_ntop() to print IPv6 addresses. * It stores a string representation of addr into buf, which must be at * least INET6_ADDRSTRLEN bytes long. * * Returns buf, which is guaranteed to contain a valid string even if an error * occured. */ char __export *u_ip6str(const struct in6_addr *addr, char *buf) { if (!inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN)) snprintf(buf, INET6_ADDRSTRLEN, "< ERROR! >"); return buf; } /* Convenient wrapper around inet_ntop() to print IPv4 addresses. * It stores a string representation of addr into buf, which must be at * least INET_ADDRSTRLEN bytes long. * * Returns buf, which is guaranteed to contain a valid string even if an error * occured. */ char __export *u_ip4str(const struct in_addr *addr, char *buf) { if (!inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN)) snprintf(buf, INET_ADDRSTRLEN, "< ERROR! >"); return buf; } void __export u_inet_ntoa(in_addr_t addr, char *str) { addr = ntohl(addr); sprintf(str, "%i.%i.%i.%i", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); } int __export u_readlong(long int *dst, const char *src, long int min, long int max) { char *src_stop = NULL; long int rv; if (dst == NULL || src == NULL || src[0] == '\0') return -1; errno = 0; rv = strtol(src, &src_stop, 0); if (errno != 0 || *src_stop != '\0' || rv < min || rv > max) { return -1; } else { *dst = rv; return 0; } } /* Parse spaces. * Returns the number of leading space characters in str. * This is a convenient function around strspn() which preserves the look and * feel of other u_parse_*() functions. */ size_t __export u_parse_spaces(const char *str) { return strspn(str, " "); } /* Parse end of string. * Reads a sequence of space characters, followed by the end-of-string * mark ('\0'). * Returns the number of characters parsed on success (that is, the number of * space characters plus one for '\0'). Beware that 'str + u_parse_endstr(str)' * points to the next byte after the end of the string in this case. * Returns 0 if parsing fails (that is, if unexpected characers are found * before the end of the string). */ size_t __export u_parse_endstr(const char *str) { const char *end; end = str + strspn(str, " "); if (*end != '\0') return 0; ++end; return end - str; } /* Parse an 8 bits unsigned integer in base 10. * Returns the number of bytes parsed on success. * Returns 0 if str doesn't start with a valid number or if this number doesn't * fit in 8 bits. */ size_t __export u_parse_u8(const char *str, uint8_t *val) { char *endptr; unsigned long ul; /* strtoul() handles leading signs (+/-) and white spaces. Make sure we * parse raw numbers. */ if (!isdigit(*str)) return 0; ul = strtoul(str, &endptr, 10); if (ul > UINT8_MAX) return 0; *val = ul; return endptr - str; } /* Parse a 16 bits unsigned integer in base 10. * Returns the number of bytes parsed on success. * Returns 0 if str doesn't start with a valid number or if this number doesn't * fit in 16 bits. */ size_t __export u_parse_u16(const char *str, uint16_t *val) { char *endptr; unsigned long ul; /* strtoul() handles leading signs (+/-) and white spaces. Make sure we * parse raw numbers. */ if (!isdigit(*str)) return 0; ul = strtoul(str, &endptr, 10); if (ul > UINT16_MAX) return 0; *val = ul; return endptr - str; } /* Parse a 32 bits unsigned integer in base 10. * Returns the number of bytes parsed on success. * Returns 0 if str doesn't start with a valid number or if this number doesn't * fit in 32 bits. */ size_t __export u_parse_u32(const char *str, uint32_t *val) { char *endptr; unsigned long ul; /* strtoul() handles leading signs (+/-) and white spaces. Make sure we * parse raw numbers. */ if (!isdigit(*str)) return 0; errno = 0; ul = strtoul(str, &endptr, 10); /* On platforms where unsigned longs are 32 bits wide, overflows would * return a valid UINT32_MAX value. So we need to check for ERANGE too. */ if (errno == ERANGE || ul > UINT32_MAX) return 0; *val = ul; return endptr - str; } /* Parse an IPv6 address (for example "2001:db8::1"). * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv6 * address. */ size_t __export u_parse_ip6addr(const char *str, struct in6_addr *addr) { char buf[INET6_ADDRSTRLEN]; size_t len; len = strspn(str, ":0123456789abcdef"); if (!len || len >= sizeof(buf)) return 0; memcpy(buf, str, len); buf[len] = '\0'; if (inet_pton(AF_INET6, buf, addr) != 1) return 0; return len; } /* Parse an IPv4 address in dotted-decimal format (for example "198.51.100.1"). * Other formats (hex "0xc6.0x33.0x64.0x1", octal "0306.063.0144.01", mixed * "0xc6.51.0144.1", non dotted-quad "198.51.25601"...) are rejected. * * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv4 * address. */ size_t __export u_parse_ip4addr(const char *str, struct in_addr *addr) { char buf[INET_ADDRSTRLEN]; size_t len; len = strspn(str, ".0123456789"); if (!len || len >= sizeof(buf)) return 0; memcpy(buf, str, len); buf[len] = '\0'; if (inet_pton(AF_INET, buf, addr) != 1) return 0; return len; } /* Parse an IPv6 network prefix in CIDR notation (for example "2001:db8::/32"). * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv6 * network prefix. */ size_t __export u_parse_ip6cidr(const char *str, struct in6_addr *netp, uint8_t *plen) { const char *ptr = str; size_t len; len = u_parse_ip6addr(ptr, netp); if (!len) return 0; ptr += len; if (*ptr != '/') return 0; len = u_parse_u8(++ptr, plen); if (!len) return 0; if (*plen > 128) return 0; ptr += len; return ptr - str; } /* Parse an IPv4 network prefix in CIDR notation (for example "192.0.2.0/24"). * The IP address must be in dotted-decimal format. * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv4 * network prefix. */ size_t __export u_parse_ip4cidr(const char *str, struct in_addr *netp, uint8_t *plen) { const char *ptr = str; size_t len; len = u_parse_ip4addr(ptr, netp); if (!len) return 0; ptr += len; if (*ptr != '/') return 0; len = u_parse_u8(++ptr, plen); if (!len) return 0; if (*plen > 32) return 0; ptr += len; return ptr - str; } /* Parse an IPv4 address range (for example "192.0.2.0-255"). * The IP address must be in dotted-decimal format. The number following '-' * is the upper bound of the address' least significant byte (the lower bound * is given by the address itself). The upper bound must be bigger or equal * than the lower bound. * * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv4 * address range. */ size_t __export u_parse_ip4range(const char *str, struct in_addr *base_ip, uint8_t *max) { const char *ptr = str; size_t len; len = u_parse_ip4addr(ptr, base_ip); if (!len) return 0; ptr += len; if (*ptr != '-') return 0; len = u_parse_u8(++ptr, max); if (!len) return 0; if (*max < (ntohl(base_ip->s_addr) & 0xff)) return 0; ptr += len; return ptr - str; } int __export u_randbuf(void *buf, size_t buf_len, int *err) { uint8_t *u8buf = buf; ssize_t rd_len; while (buf_len) { rd_len = read(urandom_fd, u8buf, buf_len); if (rd_len < 0) { if (errno == EINTR) rd_len = 0; else { if (err) *err = errno; return -1; } } else if (rd_len == 0) { if (err) *err = 0; return -1; } u8buf += rd_len; buf_len -= rd_len; } return 0; }