diff --git a/Makefile.am b/Makefile.am index 6ded5cf32a..b6e559ef0c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -67,7 +67,7 @@ test: check-spaces: ./contrib/checkSpace.pl -C \ src/common/*.h \ - src/common/[^asO]*.c \ + src/common/[^asO]*.c src/common/address.c \ src/or/[^et]*.[ch] src/or/t*.c src/or/eventdns_tor.h check-docs: diff --git a/src/common/address.c b/src/common/address.c index e52c789f31..b698eba7a3 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -7,12 +7,8 @@ const char address_c_id[] = "$Id$"; /** - * \file compat.c - * \brief Wrappers to make calls more portable. This code defines - * functions such as tor_malloc, tor_snprintf, get/set various data types, - * renaming, setting socket options, switching user IDs. It is basically - * where the non-portable items are conditionally included depending on - * the platform. + * \file address.c + * \brief DOCDOC **/ /* This is required on rh7 to make strptime not complain. @@ -102,21 +98,30 @@ const char address_c_id[] = #include #endif -/** DOCDOC */ +/** Convert the tor_addr_t in a, with port in port, into a + * socklen object in *sa_out of object size len. If not enough + * room is free, or on error, return -1. Else return the length of the + * sockaddr. */ socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port, - struct sockaddr *sa_out) + struct sockaddr *sa_out, + socklen_t len) { if (a->family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in *)sa_out; + struct sockaddr_in *sin; + if (len < sizeof(struct sockaddr_in)) + return -1; + sin = (struct sockaddr_in *)sa_out; sin->sin_family = AF_INET; sin->sin_port = port; sin->sin_addr.s_addr = a->addr.in_addr.s_addr; return sizeof(struct sockaddr_in); } else if (a->family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_out; - tor_assert(a->family == AF_INET6); + struct sockaddr_in6 *sin6; + if (len < sizeof(struct sockaddr_in6)) + return -1; + sin6 = (struct sockaddr_in6 *)sa_out; memset(sin6, 0, sizeof(struct sockaddr_in6)); sin6->sin6_family = AF_INET6; sin6->sin6_port = port; @@ -127,11 +132,14 @@ tor_addr_to_sockaddr(const tor_addr_t *a, } } -/** DOCDOC */ +/** Set the tor_addr_t in a to contain the socket address contained in + * sa. */ void tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa) { - memset(&a, 0, sizeof(tor_addr_t)); + tor_assert(a); + tor_assert(sa); + memset(a, 0, sizeof(tor_addr_t)); if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *) sa; a->family = AF_INET; @@ -140,6 +148,8 @@ tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa) struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; a->family = AF_INET6; memcpy(&a->addr.in6_addr, &sin6->sin6_addr, sizeof(struct in6_addr)); + } else { + a->family = AF_UNSPEC; } } @@ -161,7 +171,7 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr) struct in6_addr iaddr6; tor_assert(name); tor_assert(addr); - tor_assert(family == AF_INET || family == AF_UNSPEC); + tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC); memset(addr, 0, sizeof(addr)); /* Clear the extraneous fields. */ if (!*name) { /* Empty address is an error. */ @@ -340,18 +350,20 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, int len, int decorate) case AF_INET: if (len<3) return NULL; - if (decorate) - ptr = tor_inet_ntop(AF_INET, &addr->addr.in_addr, dest+1, len-2); - else ptr = tor_inet_ntop(AF_INET, &addr->addr.in_addr, dest, len); + break; + case AF_INET6: + if (decorate) + ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest+1, len-2); + else + ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest, len); if (ptr && decorate) { *dest = '['; memcpy(dest+strlen(dest), "]", 2); + tor_assert(ptr == dest+1); + ptr = dest; } break; - case AF_INET6: - ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest, len); - break; default: return NULL; } @@ -683,12 +695,24 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, case AF_INET: { uint32_t a1 = ntohl(addr1->addr.in_addr.s_addr); uint32_t a2 = ntohl(addr2->addr.in_addr.s_addr); + a1 >>= (32-mbits); + a2 >>= (32-mbits); return (a1 < a2) ? -1 : (a1 == a2) ? 0 : 1; } case AF_INET6: { - uint32_t *a1 = S6_ADDR32(addr1->addr.in6_addr); - uint32_t *a2 = S6_ADDR32(addr2->addr.in6_addr); - return memcmp(a1, a2, 16); + uint8_t *a1 = addr1->addr.in6_addr.s6_addr; + uint8_t *a2 = addr2->addr.in6_addr.s6_addr; + const int bytes = mbits >> 3; + const int leftover_bits = mbits & 7; + if (bytes && (r = memcmp(a1, a2, bytes))) { + return r; + } else if (leftover_bits) { + uint8_t b1 = a1[bytes] >> (8-leftover_bits); + uint8_t b2 = a2[bytes] >> (8-leftover_bits); + return (b1 < b2) ? -1 : (b1 == b2) ? 0 : 1; + } else { + return 0; + } } default: tor_fragile_assert(); @@ -706,6 +730,7 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, v_family[0] = tor_addr_family(addr1); v_family[1] = tor_addr_family(addr2); + /* All UNSPEC addresses are equal; they are unequal to all other addresses.*/ if (v_family[0] == AF_UNSPEC) { if (v_family[1] == AF_UNSPEC) return 0; @@ -785,7 +810,6 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, } - /** Return a hash code based on the address addr */ unsigned int tor_addr_hash(const tor_addr_t *addr) @@ -825,7 +849,6 @@ tor_addr_from_str(tor_addr_t *addr, const char *src) return tor_addr_parse_mask_ports(src, addr, NULL, NULL, NULL); } - /** Set *addr to the IP address (if any) of whatever interface * connects to the internet. This address should only be used in checking * whether our address has changed. Return 0 on success, -1 on failure. @@ -991,7 +1014,7 @@ addr_mask_get_bits(uint32_t mask) } /** Compare two addresses a1 and a2 for equality under a - * etmask of mbits bits. Return -1, 0, or 1. + * netmask of mbits bits. Return -1, 0, or 1. * * XXXX_IP6 Temporary function to allow masks as bitcounts everywhere. This * will be replaced with an IPv6-aware version as soon as 32-bit addresses are @@ -1184,7 +1207,6 @@ tor_dup_ip(uint32_t addr) return tor_strdup(buf); } - /** * Set *addr to the host-order IPv4 address (if any) of whatever * interface connects to the internet. This address should only be used in @@ -1202,3 +1224,4 @@ get_interface_address(int severity, uint32_t *addr) *addr = tor_addr_to_ipv4h(&local_addr); return r; } + diff --git a/src/common/address.h b/src/common/address.h index fd4b7879e8..b079f69451 100644 --- a/src/common/address.h +++ b/src/common/address.h @@ -37,8 +37,9 @@ static INLINE uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a); static INLINE sa_family_t tor_addr_family(const tor_addr_t *a); static INLINE const struct in_addr *tor_addr_to_in(const tor_addr_t *a); static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a); +static INLINE int tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u); socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port, - struct sockaddr *sa_out); + struct sockaddr *sa_out, socklen_t len); void tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa); static INLINE const struct in6_addr * @@ -47,6 +48,7 @@ tor_addr_to_in6(const tor_addr_t *a) return a->family == AF_INET6 ? &a->addr.in6_addr : NULL; } +#define tor_addr_to_in6_addr8(x) tor_addr_to_in6(x)->s6_addr #define tor_addr_to_in6_addr16(x) S6_ADDR16(*tor_addr_to_in6(x)) #define tor_addr_to_in6_addr32(x) S6_ADDR32(*tor_addr_to_in6(x)) @@ -75,6 +77,11 @@ tor_addr_to_in(const tor_addr_t *a) { return a->family == AF_INET ? &a->addr.in_addr : NULL; } +static INLINE int +tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u) +{ + return a->family == AF_INET ? (tor_addr_to_ipv4h(a) == u) : 0; +} #define TOR_ADDR_BUF_LEN 48 /* [ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255] */ diff --git a/src/or/test.c b/src/or/test.c index 18a22d3f4d..a3aa9906fe 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -1316,10 +1316,59 @@ test_util_ip6_helpers(void) uint16_t port1, port2; maskbits_t mask; const char *p1; + struct sockaddr_storage sa_storage; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; // struct in_addr b1, b2; /* Test tor_inet_ntop and tor_inet_pton: IPv6 */ + /* ==== Converting to and from sockaddr_t. */ + sin = (struct sockaddr_in *)&sa_storage; + sin->sin_family = AF_INET; + sin->sin_port = 9090; + sin->sin_addr.s_addr = htonl(0x7f7f0102); /*127.127.1.2*/ + tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin); + test_eq(tor_addr_family(&t1), AF_INET); + test_eq(tor_addr_to_ipv4h(&t1), 0x7f7f0102); + + memset(&sa_storage, 0, sizeof(sa_storage)); + test_eq(sizeof(struct sockaddr_in), + tor_addr_to_sockaddr(&t1, 1234, (struct sockaddr *)&sa_storage, + sizeof(sa_storage))); + test_eq(1234, sin->sin_port); + test_eq(0x7f7f0102, ntohl(sin->sin_addr.s_addr)); + + memset(&sa_storage, 0, sizeof(sa_storage)); + sin6 = (struct sockaddr_in6 *)&sa_storage; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 7070; + sin6->sin6_addr.s6_addr[0] = 128; + tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6); + test_eq(tor_addr_family(&t1), AF_INET6); + p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0); + test_streq(p1, "8000::"); + + memset(&sa_storage, 0, sizeof(sa_storage)); + test_eq(sizeof(struct sockaddr_in6), + tor_addr_to_sockaddr(&t1, 9999, (struct sockaddr *)&sa_storage, + sizeof(sa_storage))); + test_eq(AF_INET6, sin6->sin6_family); + test_eq(9999, sin6->sin6_port); + test_eq(0x80000000, ntohl(S6_ADDR32(sin6->sin6_addr)[0])); + + /* ==== tor_addr_lookup: static cases. (Can't test dns without knowing we + * have a good resolver. */ + test_eq(0, tor_addr_lookup("127.128.129.130", AF_UNSPEC, &t1)); + test_eq(AF_INET, tor_addr_family(&t1)); + test_eq(tor_addr_to_ipv4h(&t1), 0x7f808182); + + test_eq(0, tor_addr_lookup("9000::5", AF_UNSPEC, &t1)); + test_eq(AF_INET6, tor_addr_family(&t1)); + test_eq(0x90, tor_addr_to_in6_addr8(&t1)[0]); + test_assert(tor_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14)); + test_eq(0x05, tor_addr_to_in6_addr8(&t1)[15]); + /* === Test pton: valid af_inet6 */ /* Simple, valid parsing. */ r = tor_inet_pton(AF_INET6, @@ -1436,6 +1485,7 @@ test_util_ip6_helpers(void) test_internal_ip("::ffff:169.254.0.0", 0); test_internal_ip("::ffff:169.254.255.255", 0); test_external_ip("::ffff:169.255.0.0", 0); + test_assert(is_internal_IP(0x7f000001, 0)); /* tor_addr_compare(tor_addr_t x2) */ test_addr_compare("ffff::", ==, "ffff::0"); @@ -1456,6 +1506,14 @@ test_util_ip6_helpers(void) test_addr_compare_masked("0::2:2:1", <, "0::8000:2:1", 81); test_addr_compare_masked("0::2:2:1", ==, "0::8000:2:1", 80); + /* Test decorated addr_to_string. */ + test_eq(AF_INET6, tor_addr_from_str(&t1, "[123:45:6789::5005:11]")); + p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1); + test_streq(p1, "[123:45:6789::5005:11]"); + test_eq(AF_INET, tor_addr_from_str(&t1, "18.0.0.1")); + p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1); + test_streq(p1, "18.0.0.1"); + /* test tor_addr_parse_mask_ports */ test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6, 0, 0, 0, 0x0000000f, 17, 47, 95);