diff options
Diffstat (limited to 'src/lib/net/address.c')
-rw-r--r-- | src/lib/net/address.c | 117 |
1 files changed, 95 insertions, 22 deletions
diff --git a/src/lib/net/address.c b/src/lib/net/address.c index d623cdd131..6d46f9b955 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -97,7 +97,7 @@ * work correctly. Bail out here if we've found a platform where AF_UNSPEC * isn't 0. */ #if AF_UNSPEC != 0 -#error We rely on AF_UNSPEC being 0. Let us know about your platform, please! +#error "We rely on AF_UNSPEC being 0. Yours isn't. Please tell us more!" #endif CTASSERT(AF_UNSPEC == 0); @@ -608,7 +608,8 @@ tor_addr_parse_mask_ports(const char *s, family = AF_INET; tor_addr_from_ipv4h(addr_out, 0); } else if (flags & TAPMP_STAR_IPV6_ONLY) { - static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + static uint8_t nil_bytes[16] = + { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; family = AF_INET6; tor_addr_from_ipv6_bytes(addr_out, nil_bytes); } else { @@ -629,7 +630,7 @@ tor_addr_parse_mask_ports(const char *s, tor_addr_from_ipv4h(addr_out, 0); any_flag = 1; } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) { - static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + static uint8_t nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; family = AF_INET6; tor_addr_from_ipv6_bytes(addr_out, nil_bytes); any_flag = 1; @@ -817,8 +818,12 @@ tor_addr_is_loopback(const tor_addr_t *addr) /* Is addr valid? * Checks that addr is non-NULL and not tor_addr_is_null(). - * If for_listening is true, IPv4 addr 0.0.0.0 is allowed. - * It means "bind to all addresses on the local machine". */ + * If for_listening is true, all IPv4 and IPv6 addresses are valid, including + * 0.0.0.0 (for IPv4) and :: (for IPv6). When listening, these addresses mean + * "bind to all addresses on the local machine". + * Otherwise, 0.0.0.0 and :: are invalid, because they are null addresses. + * All unspecified and unix addresses are invalid, regardless of for_listening. + */ int tor_addr_is_valid(const tor_addr_t *addr, int for_listening) { @@ -827,10 +832,11 @@ tor_addr_is_valid(const tor_addr_t *addr, int for_listening) return 0; } - /* Only allow IPv4 0.0.0.0 for_listening. */ - if (for_listening && addr->family == AF_INET - && tor_addr_to_ipv4h(addr) == 0) { - return 1; + /* Allow all IPv4 and IPv6 addresses, when for_listening is true */ + if (for_listening) { + if (addr->family == AF_INET || addr->family == AF_INET6) { + return 1; + } } /* Otherwise, the address is valid if it's not tor_addr_is_null() */ @@ -882,7 +888,7 @@ tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr) /** Set <b>dest</b> to equal the IPv6 address in the 16 bytes at * <b>ipv6_bytes</b>. */ void -tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes) +tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *ipv6_bytes) { tor_assert(dest); tor_assert(ipv6_bytes); @@ -895,7 +901,21 @@ tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes) void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6) { - tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr); + tor_addr_from_ipv6_bytes(dest, in6->s6_addr); +} + +/** Set the 16 bytes at <b>dest</b> to equal the IPv6 address <b>src</b>. + * <b>src</b> must be an IPv6 address, if it is not, log a warning, and clear + * <b>dest</b>. */ +void +tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src) +{ + tor_assert(dest); + tor_assert(src); + memset(dest, 0, 16); + IF_BUG_ONCE(src->family != AF_INET6) + return; + memcpy(dest, src->addr.in6_addr.s6_addr, 16); } /** Copy a tor_addr_t from <b>src</b> to <b>dest</b>. @@ -1169,25 +1189,67 @@ fmt_addr_impl(const tor_addr_t *addr, int decorate) const char * fmt_addrport(const tor_addr_t *addr, uint16_t port) { - /* Add space for a colon and up to 5 digits. */ - static char buf[TOR_ADDR_BUF_LEN + 6]; + static char buf[TOR_ADDRPORT_BUF_LEN]; tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port); return buf; } /** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4 * addresses. Also not thread-safe, also clobbers its return buffer on - * repeated calls. */ + * repeated calls. Clean internal buffer and return empty string on failure. */ const char * fmt_addr32(uint32_t addr) { static char buf[INET_NTOA_BUF_LEN]; struct in_addr in; + int success; + in.s_addr = htonl(addr); - tor_inet_ntoa(&in, buf, sizeof(buf)); + + success = tor_inet_ntoa(&in, buf, sizeof(buf)); + tor_assertf_nonfatal(success >= 0, + "Failed to convert IP 0x%08X (HBO) to string", addr); + + IF_BUG_ONCE(success < 0) { + memset(buf, 0, INET_NTOA_BUF_LEN); + } + return buf; } +/** Return a string representing the family of <b>addr</b>. + * + * This string is a string constant, and must not be freed. + * This function is thread-safe. + */ +const char * +fmt_addr_family(const tor_addr_t *addr) +{ + static int default_bug_once = 0; + + IF_BUG_ONCE(!addr) + return "NULL pointer"; + + switch (tor_addr_family(addr)) { + case AF_INET6: + return "IPv6"; + case AF_INET: + return "IPv4"; + case AF_UNIX: + return "UNIX socket"; + case AF_UNSPEC: + return "unspecified"; + default: + if (!default_bug_once) { + log_warn(LD_BUG, "Called with unknown address family %d", + (int)tor_addr_family(addr)); + default_bug_once = 1; + } + return "unknown"; + } + //return "(unreachable code)"; +} + /** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string * may be an IPv4 address, or an IPv6 address surrounded by square brackets. * @@ -1412,10 +1474,10 @@ ifconf_free_ifc_buf(struct ifconf *ifc) * into smartlist of <b>tor_addr_t</b> structures. */ STATIC smartlist_t * -ifreq_to_smartlist(char *buf, size_t buflen) +ifreq_to_smartlist(const uint8_t *buf, size_t buflen) { smartlist_t *result = smartlist_new(); - char *end = buf + buflen; + const uint8_t *end = buf + buflen; /* These acrobatics are due to alignment issues which trigger * undefined behaviour traps on OSX. */ @@ -1489,7 +1551,7 @@ get_interface_addresses_ioctl(int severity, sa_family_t family) /* Ensure we have least IFREQ_SIZE bytes unused at the end. Otherwise, we * don't know if we got everything during ioctl. */ } while (mult * IFREQ_SIZE - ifc.ifc_len <= IFREQ_SIZE); - result = ifreq_to_smartlist(ifc.ifc_buf, ifc.ifc_len); + result = ifreq_to_smartlist((const uint8_t *)ifc.ifc_buf, ifc.ifc_len); done: if (fd >= 0) @@ -1642,11 +1704,15 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) * Ideally, we want the default route, see #12377 for details */ SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { tor_addr_copy(addr, a); + const bool is_internal = tor_addr_is_internal(a, 0); rv = 0; + log_debug(LD_NET, "Found %s interface address '%s'", + (is_internal ? "internal" : "external"), fmt_addr(addr)); + /* If we found a non-internal address, declare success. Otherwise, * keep looking. */ - if (!tor_addr_is_internal(a, 0)) + if (!is_internal) break; } SMARTLIST_FOREACH_END(a); @@ -1943,17 +2009,24 @@ parse_port_range(const char *port, uint16_t *port_min_out, } /** Given a host-order <b>addr</b>, call tor_inet_ntop() on it - * and return a strdup of the resulting address. + * and return a strdup of the resulting address. Return NULL if + * tor_inet_ntop() fails. */ char * tor_dup_ip(uint32_t addr) { + const char *ip_str; char buf[TOR_ADDR_BUF_LEN]; struct in_addr in; in.s_addr = htonl(addr); - tor_inet_ntop(AF_INET, &in, buf, sizeof(buf)); - return tor_strdup(buf); + ip_str = tor_inet_ntop(AF_INET, &in, buf, sizeof(buf)); + + tor_assertf_nonfatal(ip_str, "Failed to duplicate IP %08X", addr); + if (ip_str) + return tor_strdup(buf); + + return NULL; } /** |