Esempio n. 1
0
File: geoip.c Progetto: majek/tor
/** Given an IP address, return a number representing the country to which
 * that address belongs, -1 for "No geoip information available", or 0 for
 * the 'unknown country'.  The return value will always be less than
 * geoip_get_n_countries().  To decode it, call geoip_get_country_name().
 */
int
geoip_get_country_by_addr(const tor_addr_t *addr)
{
  if (tor_addr_family(addr) == AF_INET) {
    return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr));
  } else if (tor_addr_family(addr) == AF_INET6) {
    return geoip_get_country_by_ipv6(tor_addr_to_in6(addr));
  } else {
    return -1;
  }
}
Esempio n. 2
0
/** Given an IP address, return a number representing the country to which
 * that address belongs, -1 for "No geoip information available", or 0 for
 * the 'unknown country'.  The return value will always be less than
 * geoip_get_n_countries().  To decode it, call geoip_get_country_name().
 */
int
geoip_get_country_by_addr(const tor_addr_t *addr)
{
  if (tor_addr_family(addr) != AF_INET) {
    /*XXXX IP6 support ipv6 geoip.*/
    return -1;
  }
  return geoip_get_country_by_ip(tor_addr_to_ipv4h(addr));
}
Esempio n. 3
0
/** Set *<b>out</b> to a newly allocated SOCKS4a resolve request with
 * <b>username</b> and <b>hostname</b> as provided.  Return the number
 * of bytes in the request. */
static ssize_t
build_socks_resolve_request(char **out,
                            const char *username,
                            const char *hostname,
                            int reverse,
                            int version)
{
  size_t len = 0;
  tor_assert(out);
  tor_assert(username);
  tor_assert(hostname);

  if (version == 4) {
    len = 8 + strlen(username) + 1 + strlen(hostname) + 1;
    *out = tor_malloc(len);
    (*out)[0] = 4;      /* SOCKS version 4 */
    (*out)[1] = '\xF0'; /* Command: resolve. */
    set_uint16((*out)+2, htons(0)); /* port: 0. */
    set_uint32((*out)+4, htonl(0x00000001u)); /* addr: 0.0.0.1 */
    memcpy((*out)+8, username, strlen(username)+1);
    memcpy((*out)+8+strlen(username)+1, hostname, strlen(hostname)+1);
  } else if (version == 5) {
    int is_ip_address;
    tor_addr_t addr;
    size_t addrlen;
    int ipv6;
    is_ip_address = tor_addr_parse(&addr, hostname) != -1;
    if (!is_ip_address && reverse) {
      log_err(LD_GENERAL, "Tried to do a reverse lookup on a non-IP!");
      return -1;
    }
    ipv6 = reverse && tor_addr_family(&addr) == AF_INET6;
    addrlen = reverse ? (ipv6 ? 16 : 4) : 1 + strlen(hostname);
    len = 6 + addrlen;
    *out = tor_malloc(len);
    (*out)[0] = 5; /* SOCKS version 5 */
    (*out)[1] = reverse ? '\xF1' : '\xF0'; /* RESOLVE_PTR or RESOLVE */
    (*out)[2] = 0; /* reserved. */
    if (reverse) {
      (*out)[3] = ipv6 ? 4 : 1;
      if (ipv6)
        memcpy((*out)+4, tor_addr_to_in6_addr8(&addr), 16);
      else
        set_uint32((*out)+4, tor_addr_to_ipv4n(&addr));
    } else {
      (*out)[3] = 3;
      (*out)[4] = (char)(uint8_t)(addrlen - 1);
      memcpy((*out)+5, hostname, addrlen - 1);
    }
    set_uint16((*out)+4+addrlen, 0); /* port */
  } else {
    tor_assert(0);
  }

  return len;
}
Esempio n. 4
0
File: geoip.c Progetto: majek/tor
/** Add an entry to a GeoIP table, mapping all IP addresses between <b>low</b>
 * and <b>high</b>, inclusive, to the 2-letter country code <b>country</b>. */
static void
geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high,
                const char *country)
{
  intptr_t idx;
  void *idxplus1_;

  if (tor_addr_family(low) != tor_addr_family(high))
    return;
  if (tor_addr_compare(high, low, CMP_EXACT) < 0)
    return;

  idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country);

  if (!idxplus1_) {
    geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t));
    strlcpy(c->countrycode, country, sizeof(c->countrycode));
    tor_strlower(c->countrycode);
    smartlist_add(geoip_countries, c);
    idx = smartlist_len(geoip_countries) - 1;
    strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1));
  } else {
    idx = ((uintptr_t)idxplus1_)-1;
  }
  {
    geoip_country_t *c = smartlist_get(geoip_countries, idx);
    tor_assert(!strcasecmp(c->countrycode, country));
  }

  if (tor_addr_family(low) == AF_INET) {
    geoip_ipv4_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv4_entry_t));
    ent->ip_low = tor_addr_to_ipv4h(low);
    ent->ip_high = tor_addr_to_ipv4h(high);
    ent->country = idx;
    smartlist_add(geoip_ipv4_entries, ent);
  } else if (tor_addr_family(low) == AF_INET6) {
    geoip_ipv6_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv6_entry_t));
    ent->ip_low = *tor_addr_to_in6(low);
    ent->ip_high = *tor_addr_to_in6(high);
    ent->country = idx;
    smartlist_add(geoip_ipv6_entries, ent);
  }
}
Esempio n. 5
0
/** Convert the tor_addr_t in <b>a</b>, with port in <b>port</b>, into a
 * sockaddr object in *<b>sa_out</b> of object size <b>len</b>.  If not enough
 * room is available in sa_out, or on error, return 0.  On success, return
 * the length of the sockaddr.
 *
 * Interface note: ordinarily, we return -1 for error.  We can't do that here,
 * since socklen_t is unsigned on some platforms.
 **/
socklen_t
tor_addr_to_sockaddr(const tor_addr_t *a,
                     uint16_t port,
                     struct sockaddr *sa_out,
                     socklen_t len)
{
  sa_family_t family = tor_addr_family(a);
  if (family == AF_INET) {
    struct sockaddr_in *sin;
    if (len < (int)sizeof(struct sockaddr_in))
      return 0;
    sin = (struct sockaddr_in *)sa_out;
    memset(sin, 0, sizeof(struct sockaddr_in));
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
    sin->sin_len = sizeof(struct sockaddr_in);
#endif
    sin->sin_family = AF_INET;
    sin->sin_port = htons(port);
    sin->sin_addr.s_addr = tor_addr_to_ipv4n(a);
    return sizeof(struct sockaddr_in);
  } else if (family == AF_INET6) {
    struct sockaddr_in6 *sin6;
    if (len < (int)sizeof(struct sockaddr_in6))
      return 0;
    sin6 = (struct sockaddr_in6 *)sa_out;
    memset(sin6, 0, sizeof(struct sockaddr_in6));
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
    sin6->sin6_len = sizeof(struct sockaddr_in6);
#endif
    sin6->sin6_family = AF_INET6;
    sin6->sin6_port = htons(port);
    memcpy(&sin6->sin6_addr, tor_addr_to_in6(a), sizeof(struct in6_addr));
    return sizeof(struct sockaddr_in6);
  } else {
    return 0;
  }
}
Esempio n. 6
0
File: onion.c Progetto: BwRy/Astoria
/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. */
static int
check_extend_cell(const extend_cell_t *cell)
{
  if (tor_digest_is_zero((const char*)cell->node_id))
    return -1;
  /* We don't currently allow EXTEND2 cells without an IPv4 address */
  if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC)
    return -1;
  if (cell->create_cell.cell_type == CELL_CREATE) {
    if (cell->cell_type != RELAY_COMMAND_EXTEND)
      return -1;
  } else if (cell->create_cell.cell_type == CELL_CREATE2) {
    if (cell->cell_type != RELAY_COMMAND_EXTEND2 &&
        cell->cell_type != RELAY_COMMAND_EXTEND)
      return -1;
  } else {
    /* In particular, no CREATE_FAST cells are allowed */
    return -1;
  }
  if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST)
    return -1;

  return check_create_cell(&cell->create_cell, 1);
}
Esempio n. 7
0
/** More tests for parsing different kinds of microdescriptors, and getting
 * invalid digests trackd from them. */
static void
test_md_parse(void *arg)
{
  (void) arg;
  char *mem_op_hex_tmp = NULL;
  smartlist_t *invalid = smartlist_new();

  smartlist_t *mds = microdescs_parse_from_string(MD_PARSE_TEST_DATA,
                                                  NULL, 1, SAVED_NOWHERE,
                                                  invalid);
  tt_int_op(smartlist_len(mds), OP_EQ, 11);
  tt_int_op(smartlist_len(invalid), OP_EQ, 4);

  test_memeq_hex(smartlist_get(invalid,0),
                 "5d76bf1c6614e885614a1e0ad074e1ab"
                 "4ea14655ebeefb1736a71b5ed8a15a51");
  test_memeq_hex(smartlist_get(invalid,1),
                 "2fde0ee3343669c2444cd9d53cbd39c6"
                 "a7d1fc0513513e840ca7f6e68864b36c");
  test_memeq_hex(smartlist_get(invalid,2),
                 "20d1576c5ab11bbcff0dedb1db4a3cfc"
                 "c8bc8dd839d8cbfef92d00a1a7d7b294");
  test_memeq_hex(smartlist_get(invalid,3),
                 "074770f394c73dbde7b44412e9692add"
                 "691a478d4727f9804b77646c95420a96");

  /* Spot-check the valid ones. */
  const microdesc_t *md = smartlist_get(mds, 5);
  test_memeq_hex(md->digest,
                 "54bb6d733ddeb375d2456c79ae103961"
                 "da0cae29620375ac4cf13d54da4d92b3");
  tt_int_op(md->last_listed, OP_EQ, 0);
  tt_int_op(md->saved_location, OP_EQ, SAVED_NOWHERE);
  tt_int_op(md->no_save, OP_EQ, 0);
  tt_uint_op(md->held_in_map, OP_EQ, 0);
  tt_uint_op(md->held_by_nodes, OP_EQ, 0);
  tt_assert(md->onion_curve25519_pkey);

  md = smartlist_get(mds, 6);
  test_memeq_hex(md->digest,
                 "53f740bd222ab37f19f604b1d3759aa6"
                 "5eff1fbce9ac254bd0fa50d4af9b1bae");
  tt_assert(! md->exit_policy);

  md = smartlist_get(mds, 8);
  test_memeq_hex(md->digest,
                 "a0a155562d8093d8fd0feb7b93b7226e"
                 "17f056c2142aab7a4ea8c5867a0376d5");
  tt_assert(md->onion_curve25519_pkey);

  md = smartlist_get(mds, 10);
  test_memeq_hex(md->digest,
                 "409ebd87d23925a2732bd467a92813c9"
                 "21ca378fcb9ca193d354c51550b6d5e9");
  tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
  tt_int_op(md->ipv6_orport, OP_EQ, 9090);

 done:
  SMARTLIST_FOREACH(mds, microdesc_t *, mdsc, microdesc_free(mdsc));
  smartlist_free(mds);
  SMARTLIST_FOREACH(invalid, char *, cp, tor_free(cp));
  smartlist_free(invalid);
  tor_free(mem_op_hex_tmp);
}
Esempio n. 8
0
/** Run unit tests for IPv6 encoding/decoding/manipulation functions. */
static void
test_addr_ip6_helpers(void)
{
  char buf[TOR_ADDR_BUF_LEN], bug[TOR_ADDR_BUF_LEN];
  char rbuf[REVERSE_LOOKUP_NAME_BUF_LEN];
  struct in6_addr a1, a2;
  tor_addr_t t1, t2;
  int r, i;
  uint16_t port1, port2;
  maskbits_t mask;
  const char *p1;
  struct sockaddr_storage sa_storage;
  struct sockaddr_in *sin;
  struct sockaddr_in6 *sin6;

  /* Test tor_inet_ntop and tor_inet_pton: IPv6 */
  {
    const char *ip = "2001::1234";
    const char *ip_ffff = "::ffff:192.168.1.2";

    /* good round trip */
    test_eq(tor_inet_pton(AF_INET6, ip, &a1), 1);
    test_eq_ptr(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), &buf);
    test_streq(buf, ip);

    /* good round trip - ::ffff:0:0 style */
    test_eq(tor_inet_pton(AF_INET6, ip_ffff, &a2), 1);
    test_eq_ptr(tor_inet_ntop(AF_INET6, &a2, buf, sizeof(buf)), &buf);
    test_streq(buf, ip_ffff);

    /* just long enough buffer (remember \0) */
    test_streq(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)+1), ip);
    test_streq(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)+1),
               ip_ffff);

    /* too short buffer (remember \0) */
    test_eq_ptr(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)), NULL);
    test_eq_ptr(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)), NULL);
  }

  /* ==== 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, NULL);
  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, ntohs(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 = htons(7070);
  sin6->sin6_addr.s6_addr[0] = 128;
  tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL);
  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, ntohs(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,
                    "0102:0304:0506:0708:090A:0B0C:0D0E:0F10", &a1);
  test_assert(r==1);
  for (i=0;i<16;++i) { test_eq(i+1, (int)a1.s6_addr[i]); }
  /* ipv4 ending. */
  test_pton6_same("0102:0304:0506:0708:090A:0B0C:0D0E:0F10",
                  "0102:0304:0506:0708:090A:0B0C:13.14.15.16");
  /* shortened words. */
  test_pton6_same("0001:0099:BEEF:0000:0123:FFFF:0001:0001",
                  "1:99:BEEF:0:0123:FFFF:1:1");
  /* zeros at the beginning */
  test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001",
                  "::9:c0a8:1:1");
  test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001",
                  "::9:c0a8:0.1.0.1");
  /* zeros in the middle. */
  test_pton6_same("fe80:0000:0000:0000:0202:1111:0001:0001",
                  "fe80::202:1111:1:1");
  /* zeros at the end. */
  test_pton6_same("1000:0001:0000:0007:0000:0000:0000:0000",
                  "1000:1:0:7::");

  /* === Test ntop: af_inet6 */
  test_ntop6_reduces("0:0:0:0:0:0:0:0", "::");

  test_ntop6_reduces("0001:0099:BEEF:0006:0123:FFFF:0001:0001",
                     "1:99:beef:6:123:ffff:1:1");

  //test_ntop6_reduces("0:0:0:0:0:0:c0a8:0101", "::192.168.1.1");
  test_ntop6_reduces("0:0:0:0:0:ffff:c0a8:0101", "::ffff:192.168.1.1");
  test_ntop6_reduces("002:0:0000:0:3::4", "2::3:0:0:4");
  test_ntop6_reduces("0:0::1:0:3", "::1:0:3");
  test_ntop6_reduces("008:0::0", "8::");
  test_ntop6_reduces("0:0:0:0:0:ffff::1", "::ffff:0.0.0.1");
  test_ntop6_reduces("abcd:0:0:0:0:0:7f00::", "abcd::7f00:0");
  test_ntop6_reduces("0000:0000:0000:0000:0009:C0A8:0001:0001",
                     "::9:c0a8:1:1");
  test_ntop6_reduces("fe80:0000:0000:0000:0202:1111:0001:0001",
                     "fe80::202:1111:1:1");
  test_ntop6_reduces("1000:0001:0000:0007:0000:0000:0000:0000",
                     "1000:1:0:7::");

  /* Bad af param */
  test_eq(tor_inet_pton(AF_UNSPEC, 0, 0), -1);

  /* === Test pton: invalid in6. */
  test_pton6_bad("foobar.");
  test_pton6_bad("-1::");
  test_pton6_bad("00001::");
  test_pton6_bad("10000::");
  test_pton6_bad("::10000");
  test_pton6_bad("55555::");
  test_pton6_bad("9:-60::");
  test_pton6_bad("9:+60::");
  test_pton6_bad("9|60::");
  test_pton6_bad("0x60::");
  test_pton6_bad("::0x60");
  test_pton6_bad("9:0x60::");
  test_pton6_bad("1:2:33333:4:0002:3::");
  test_pton6_bad("1:2:3333:4:fish:3::");
  test_pton6_bad("1:2:3:4:5:6:7:8:9");
  test_pton6_bad("1:2:3:4:5:6:7");
  test_pton6_bad("1:2:3:4:5:6:1.2.3.4.5");
  test_pton6_bad("1:2:3:4:5:6:1.2.3");
  test_pton6_bad("::1.2.3");
  test_pton6_bad("::1.2.3.4.5");
  test_pton6_bad("::ffff:0xff.0.0.0");
  test_pton6_bad("::ffff:ff.0.0.0");
  test_pton6_bad("::ffff:256.0.0.0");
  test_pton6_bad("::ffff:-1.0.0.0");
  test_pton6_bad("99");
  test_pton6_bad("");
  test_pton6_bad(".");
  test_pton6_bad(":");
  test_pton6_bad("1::2::3:4");
  test_pton6_bad("a:::b:c");
  test_pton6_bad(":::a:b:c");
  test_pton6_bad("a:b:c:::");

  /* test internal checking */
  test_external_ip("fbff:ffff::2:7", 0);
  test_internal_ip("fc01::2:7", 0);
  test_internal_ip("fc01::02:7", 0);
  test_internal_ip("fc01::002:7", 0);
  test_internal_ip("fc01::0002:7", 0);
  test_internal_ip("fdff:ffff::f:f", 0);
  test_external_ip("fe00::3:f", 0);

  test_external_ip("fe7f:ffff::2:7", 0);
  test_internal_ip("fe80::2:7", 0);
  test_internal_ip("febf:ffff::f:f", 0);

  test_internal_ip("fec0::2:7:7", 0);
  test_internal_ip("feff:ffff::e:7:7", 0);
  test_external_ip("ff00::e:7:7", 0);

  test_internal_ip("::", 0);
  test_internal_ip("::1", 0);
  test_internal_ip("::1", 1);
  test_internal_ip("::", 0);
  test_external_ip("::", 1);
  test_external_ip("::2", 0);
  test_external_ip("2001::", 0);
  test_external_ip("ffff::", 0);

  test_external_ip("::ffff:0.0.0.0", 1);
  test_internal_ip("::ffff:0.0.0.0", 0);
  test_internal_ip("::ffff:0.255.255.255", 0);
  test_external_ip("::ffff:1.0.0.0", 0);

  test_external_ip("::ffff:9.255.255.255", 0);
  test_internal_ip("::ffff:10.0.0.0", 0);
  test_internal_ip("::ffff:10.255.255.255", 0);
  test_external_ip("::ffff:11.0.0.0", 0);

  test_external_ip("::ffff:126.255.255.255", 0);
  test_internal_ip("::ffff:127.0.0.0", 0);
  test_internal_ip("::ffff:127.255.255.255", 0);
  test_external_ip("::ffff:128.0.0.0", 0);

  test_external_ip("::ffff:172.15.255.255", 0);
  test_internal_ip("::ffff:172.16.0.0", 0);
  test_internal_ip("::ffff:172.31.255.255", 0);
  test_external_ip("::ffff:172.32.0.0", 0);

  test_external_ip("::ffff:192.167.255.255", 0);
  test_internal_ip("::ffff:192.168.0.0", 0);
  test_internal_ip("::ffff:192.168.255.255", 0);
  test_external_ip("::ffff:192.169.0.0", 0);

  test_external_ip("::ffff:169.253.255.255", 0);
  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");
  test_addr_compare("0::3:2:1", <, "0::ffff:0.3.2.1");
  test_addr_compare("0::2:2:1", <, "0::ffff:0.3.2.1");
  test_addr_compare("0::ffff:0.3.2.1", >, "0::0:0:0");
  test_addr_compare("0::ffff:5.2.2.1", <, "::ffff:6.0.0.0"); /* XXXX wrong. */
  tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", &t1, NULL, NULL, NULL);
  tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
  test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0);
  tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", &t1, NULL, NULL, NULL);
  tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
  test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0);

  /* test compare_masked */
  test_addr_compare_masked("ffff::", ==, "ffff::0", 128);
  test_addr_compare_masked("ffff::", ==, "ffff::0", 64);
  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 undecorated tor_addr_to_str */
  test_eq(AF_INET6, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
  test_streq(p1, "123:45:6789::5005:11");
  test_eq(AF_INET, tor_addr_parse(&t1, "18.0.0.1"));
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
  test_streq(p1, "18.0.0.1");

  /* Test decorated tor_addr_to_str */
  test_eq(AF_INET6, tor_addr_parse(&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_parse(&t1, "18.0.0.1"));
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  test_streq(p1, "18.0.0.1");

  /* Test buffer bounds checking of tor_addr_to_str */
  test_eq(AF_INET6, tor_addr_parse(&t1, "::")); /* 2 + \0 */
  test_eq_ptr(tor_addr_to_str(buf, &t1, 2, 0), NULL); /* too short buf */
  test_streq(tor_addr_to_str(buf, &t1, 3, 0), "::");
  test_eq_ptr(tor_addr_to_str(buf, &t1, 4, 1), NULL); /* too short buf */
  test_streq(tor_addr_to_str(buf, &t1, 5, 1), "[::]");

  test_eq(AF_INET6, tor_addr_parse(&t1, "2000::1337")); /* 10 + \0 */
  test_eq_ptr(tor_addr_to_str(buf, &t1, 10, 0), NULL); /* too short buf */
  test_streq(tor_addr_to_str(buf, &t1, 11, 0), "2000::1337");
  test_eq_ptr(tor_addr_to_str(buf, &t1, 12, 1), NULL); /* too short buf */
  test_streq(tor_addr_to_str(buf, &t1, 13, 1), "[2000::1337]");

  test_eq(AF_INET, tor_addr_parse(&t1, "1.2.3.4")); /* 7 + \0 */
  test_eq_ptr(tor_addr_to_str(buf, &t1, 7, 0), NULL); /* too short buf */
  test_streq(tor_addr_to_str(buf, &t1, 8, 0), "1.2.3.4");

  test_eq(AF_INET, tor_addr_parse(&t1, "255.255.255.255")); /* 15 + \0 */
  test_eq_ptr(tor_addr_to_str(buf, &t1, 15, 0), NULL); /* too short buf */
  test_streq(tor_addr_to_str(buf, &t1, 16, 0), "255.255.255.255");
  test_eq_ptr(tor_addr_to_str(buf, &t1, 15, 1), NULL); /* too short buf */
  test_streq(tor_addr_to_str(buf, &t1, 16, 1), "255.255.255.255");

  t1.family = AF_UNSPEC;
  test_eq_ptr(tor_addr_to_str(buf, &t1, sizeof(buf), 0), NULL);

  /* Test tor_addr_parse_PTR_name */
  i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 0);
  test_eq(0, i);
  i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 1);
  test_eq(0, i);
  i = tor_addr_parse_PTR_name(&t1, "1.0.168.192.in-addr.arpa",
                                         AF_UNSPEC, 1);
  test_eq(1, i);
  test_eq(tor_addr_family(&t1), AF_INET);
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  test_streq(p1, "192.168.0.1");
  i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 0);
  test_eq(0, i);
  i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 1);
  test_eq(1, i);
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  test_streq(p1, "192.168.0.99");
  memset(&t1, 0, sizeof(t1));
  i = tor_addr_parse_PTR_name(&t1,
                                         "0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_UNSPEC, 0);
  test_eq(1, i);
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  test_streq(p1, "[9dee:effe:ebe1:beef:fedc:ba98:7654:3210]");
  /* Failing cases. */
  i = tor_addr_parse_PTR_name(&t1,
                                         "6.7.8.9.a.b.c.d.e.f."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_UNSPEC, 0);
  test_eq(i, -1);
  i = tor_addr_parse_PTR_name(&t1,
                                         "6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.f.0."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_UNSPEC, 0);
  test_eq(i, -1);
  i = tor_addr_parse_PTR_name(&t1,
                                         "6.7.8.9.a.b.c.d.e.f.X.0.0.0.0.9."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_UNSPEC, 0);
  test_eq(i, -1);
  i = tor_addr_parse_PTR_name(&t1, "32.1.1.in-addr.arpa",
                                         AF_UNSPEC, 0);
  test_eq(i, -1);
  i = tor_addr_parse_PTR_name(&t1, ".in-addr.arpa",
                                         AF_UNSPEC, 0);
  test_eq(i, -1);
  i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa",
                                         AF_UNSPEC, 0);
  test_eq(i, -1);
  i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa",
                                         AF_INET6, 0);
  test_eq(i, -1);
  i = tor_addr_parse_PTR_name(&t1,
                                         "6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.0."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_INET, 0);
  test_eq(i, -1);

  /* === Test tor_addr_to_PTR_name */

  /* Stage IPv4 addr */
  memset(&sa_storage, 0, sizeof(sa_storage));
  sin = (struct sockaddr_in *)&sa_storage;
  sin->sin_family = AF_INET;
  sin->sin_addr.s_addr = htonl(0x7f010203); /* 127.1.2.3 */
  tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL);

  /* Check IPv4 PTR - too short buffer */
  test_eq(tor_addr_to_PTR_name(rbuf, 1, &t1), -1);
  test_eq(tor_addr_to_PTR_name(rbuf,
                               strlen("3.2.1.127.in-addr.arpa") - 1,
                               &t1), -1);

  /* Check IPv4 PTR - valid addr */
  test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),
          strlen("3.2.1.127.in-addr.arpa"));
  test_streq(rbuf, "3.2.1.127.in-addr.arpa");

  /* Invalid addr family */
  t1.family = AF_UNSPEC;
  test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1), -1);

  /* Stage IPv6 addr */
  memset(&sa_storage, 0, sizeof(sa_storage));
  sin6 = (struct sockaddr_in6 *)&sa_storage;
  sin6->sin6_family = AF_INET6;
  sin6->sin6_addr.s6_addr[0] = 0x80; /* 8000::abcd */
  sin6->sin6_addr.s6_addr[14] = 0xab;
  sin6->sin6_addr.s6_addr[15] = 0xcd;

  tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL);

  {
    const char* addr_PTR = "d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0."
      "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.ip6.arpa";

    /* Check IPv6 PTR - too short buffer */
    test_eq(tor_addr_to_PTR_name(rbuf, 0, &t1), -1);
    test_eq(tor_addr_to_PTR_name(rbuf, strlen(addr_PTR) - 1, &t1), -1);

    /* Check IPv6 PTR - valid addr */
    test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),
            strlen(addr_PTR));
    test_streq(rbuf, addr_PTR);
  }

  /* test tor_addr_parse_mask_ports */
  test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6,
                             0, 0, 0, 0x0000000f, 17, 47, 95);
  test_streq(p1, "::f");
  //test_addr_parse("[::fefe:4.1.1.7/120]:999-1000");
  //test_addr_parse_check("::fefe:401:107", 120, 999, 1000);
  test_addr_mask_ports_parse("[::ffff:4.1.1.7]/120:443", AF_INET6,
                             0, 0, 0x0000ffff, 0x04010107, 120, 443, 443);
  test_streq(p1, "::ffff:4.1.1.7");
  test_addr_mask_ports_parse("[abcd:2::44a:0]:2-65000", AF_INET6,
                             0xabcd0002, 0, 0, 0x044a0000, 128, 2, 65000);

  test_streq(p1, "abcd:2::44a:0");
  r=tor_addr_parse_mask_ports("[fefef::]/112", &t1, NULL, NULL, NULL);
  test_assert(r == -1);
  r=tor_addr_parse_mask_ports("efef::/112", &t1, NULL, NULL, NULL);
  test_assert(r == -1);
  r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]", &t1, NULL, NULL, NULL);
  test_assert(r == -1);
  r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
  test_assert(r == -1);
  r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
  test_assert(r == -1);
  /* Test for V4-mapped address with mask < 96.  (arguably not valid) */
  r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]", &t1, &mask, NULL, NULL);
  test_assert(r == -1);
  r=tor_addr_parse_mask_ports("1.1.2.2/33", &t1, &mask, NULL, NULL);
  test_assert(r == -1);
  r=tor_addr_parse_mask_ports("1.1.2.2/31", &t1, &mask, NULL, NULL);
  test_assert(r == AF_INET);
  r=tor_addr_parse_mask_ports("[efef::]/112", &t1, &mask, &port1, &port2);
  test_assert(r == AF_INET6);
  test_assert(port1 == 1);
  test_assert(port2 == 65535);

  /* make sure inet address lengths >= max */
  test_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255"));
  test_assert(TOR_ADDR_BUF_LEN >=
              sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"));

  test_assert(sizeof(tor_addr_t) >= sizeof(struct in6_addr));

  /* get interface addresses */
  r = get_interface_address6(LOG_DEBUG, AF_INET, &t1);
  i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2);

  TT_BLATHER(("v4 address: %s (family=%d)", fmt_addr(&t1),
              tor_addr_family(&t1)));
  TT_BLATHER(("v6 address: %s (family=%d)", fmt_addr(&t2),
              tor_addr_family(&t2)));

 done:
  ;
}
Esempio n. 9
0
/** Parse the encoded introduction points in <b>intro_points_encoded</b> of
 * length <b>intro_points_encoded_size</b> and write the result to the
 * descriptor in <b>parsed</b>; return the number of successfully parsed
 * introduction points or -1 in case of a failure. */
int
rend_parse_introduction_points(rend_service_descriptor_t *parsed,
                               const char *intro_points_encoded,
                               size_t intro_points_encoded_size)
{
  const char *current_ipo, *end_of_intro_points;
  smartlist_t *tokens = NULL;
  directory_token_t *tok;
  rend_intro_point_t *intro;
  extend_info_t *info;
  int result, num_ok=1;
  memarea_t *area = NULL;
  tor_assert(parsed);
  /** Function may only be invoked once. */
  tor_assert(!parsed->intro_nodes);
  if (!intro_points_encoded || intro_points_encoded_size == 0) {
    log_warn(LD_REND, "Empty or zero size introduction point list");
    goto err;
  }
  /* Consider one intro point after the other. */
  current_ipo = intro_points_encoded;
  end_of_intro_points = intro_points_encoded + intro_points_encoded_size;
  tokens = smartlist_new();
  parsed->intro_nodes = smartlist_new();
  area = memarea_new();

  while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo,
                      "introduction-point ")) {
    /* Determine end of string. */
    const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo,
                                 "\nintroduction-point ");
    if (!eos)
      eos = end_of_intro_points;
    else
      eos = eos+1;
    tor_assert(eos <= intro_points_encoded+intro_points_encoded_size);
    /* Free tokens and clear token list. */
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
    smartlist_clear(tokens);
    memarea_clear(area);
    /* Tokenize string. */
    if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) {
      log_warn(LD_REND, "Error tokenizing introduction point");
      goto err;
    }
    /* Advance to next introduction point, if available. */
    current_ipo = eos;
    /* Check minimum allowed length of introduction point. */
    if (smartlist_len(tokens) < 5) {
      log_warn(LD_REND, "Impossibly short introduction point.");
      goto err;
    }
    /* Allocate new intro point and extend info. */
    intro = tor_malloc_zero(sizeof(rend_intro_point_t));
    info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
    /* Parse identifier. */
    tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
    if (base32_decode(info->identity_digest, DIGEST_LEN,
                      tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
      log_warn(LD_REND, "Identity digest contains illegal characters: %s",
               tok->args[0]);
      rend_intro_point_free(intro);
      goto err;
    }
    /* Write identifier to nickname. */
    info->nickname[0] = '$';
    base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
                  info->identity_digest, DIGEST_LEN);
    /* Parse IP address. */
    tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
    if (tor_addr_parse(&info->addr, tok->args[0])<0) {
      log_warn(LD_REND, "Could not parse introduction point address.");
      rend_intro_point_free(intro);
      goto err;
    }
    if (tor_addr_family(&info->addr) != AF_INET) {
      log_warn(LD_REND, "Introduction point address was not ipv4.");
      rend_intro_point_free(intro);
      goto err;
    }

    /* Parse onion port. */
    tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
    info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
                                           &num_ok,NULL);
    if (!info->port || !num_ok) {
      log_warn(LD_REND, "Introduction point onion port %s is invalid",
               escaped(tok->args[0]));
      rend_intro_point_free(intro);
      goto err;
    }
    /* Parse onion key. */
    tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
    if (!crypto_pk_public_exponent_ok(tok->key)) {
      log_warn(LD_REND,
               "Introduction point's onion key had invalid exponent.");
      rend_intro_point_free(intro);
      goto err;
    }
    info->onion_key = tok->key;
    tok->key = NULL; /* Prevent free */
    /* Parse service key. */
    tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
    if (!crypto_pk_public_exponent_ok(tok->key)) {
      log_warn(LD_REND,
               "Introduction point key had invalid exponent.");
      rend_intro_point_free(intro);
      goto err;
    }
    intro->intro_key = tok->key;
    tok->key = NULL; /* Prevent free */
    /* Add extend info to list of introduction points. */
    smartlist_add(parsed->intro_nodes, intro);
  }
  result = smartlist_len(parsed->intro_nodes);
  goto done;

 err:
  result = -1;

 done:
  /* Free tokens and clear token list. */
  if (tokens) {
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
    smartlist_free(tokens);
  }
  if (area)
    memarea_drop_all(area);

  return result;
}
Esempio n. 10
0
static void
test_virtaddrmap_persist(void *data)
{
  (void)data;
  const char *a, *b, *c;
  tor_addr_t addr;
  char *ones = NULL;

  addressmap_init();

  // Try a hostname.
  a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
                                          tor_strdup("foobar.baz"));
  tt_assert(a);
  tt_assert(!strcmpend(a, ".virtual"));

  // mock crypto_rand to repeat the same result twice; make sure we get
  // different outcomes.  (Because even though the odds for receiving the
  // same 80-bit address twice is only 1/2^40, it could still happen for
  // some user -- but running our test through 2^40 iterations isn't
  // reasonable.)
  canned_data = "1234567890" // the first call returns this.
                "1234567890" // the second call returns this.
                "abcdefghij"; // the third call returns this.
  canned_data_len = 30;
  MOCK(crypto_rand, crypto_canned);

  a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
                                          tor_strdup("quuxit.baz"));
  b = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
                                          tor_strdup("nescio.baz"));
  tt_assert(a);
  tt_assert(b);
  tt_str_op(a, OP_EQ, "gezdgnbvgy3tqojq.virtual");
  tt_str_op(b, OP_EQ, "mfrggzdfmztwq2lk.virtual");

  // Now try something to get us an ipv4 address
  UNMOCK(crypto_rand);
  tt_int_op(0,OP_EQ, parse_virtual_addr_network("192.168.0.0/16",
                                                AF_INET, 0, NULL));
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("foobar.baz"));
  tt_assert(a);
  tt_assert(!strcmpstart(a, "192.168."));
  tor_addr_parse(&addr, a);
  tt_int_op(AF_INET, OP_EQ, tor_addr_family(&addr));

  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("quuxit.baz"));
  tt_str_op(b, OP_NE, a);
  tt_assert(!strcmpstart(b, "192.168."));

  // Try some canned entropy and verify all the we discard duplicates,
  // addresses that end with 0, and addresses that end with 255.
  MOCK(crypto_rand, crypto_canned);
  canned_data = "\x01\x02\x03\x04" // okay
                "\x01\x02\x03\x04" // duplicate
                "\x03\x04\x00\x00" // bad ending 1
                "\x05\x05\x00\xff" // bad ending 2
                "\x05\x06\x07\xf0"; // okay
  canned_data_len = 20;
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("wumble.onion"));
  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("wumpus.onion"));
  tt_str_op(a, OP_EQ, "192.168.3.4");
  tt_str_op(b, OP_EQ, "192.168.7.240");

  // Now try IPv6!
  UNMOCK(crypto_rand);
  tt_int_op(0,OP_EQ, parse_virtual_addr_network("1010:F000::/20",
                                                AF_INET6, 0, NULL));
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                          tor_strdup("foobar.baz"));
  tt_assert(a);
  tt_assert(!strcmpstart(a, "[1010:f"));
  tor_addr_parse(&addr, a);
  tt_int_op(AF_INET6, OP_EQ, tor_addr_family(&addr));

  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                          tor_strdup("quuxit.baz"));
  tt_str_op(b, OP_NE, a);
  tt_assert(!strcmpstart(b, "[1010:f"));

  // Try IPv6 with canned entropy, to make sure we detect duplicates.
  MOCK(crypto_rand, crypto_canned);
  canned_data = "acanthopterygian" // okay
                "cinematographist" // okay
                "acanthopterygian" // duplicate
                "acanthopterygian" // duplicate
                "acanthopterygian" // duplicate
                "cinematographist" // duplicate
                "coadministration"; // okay
  canned_data_len = 16 * 7;
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                          tor_strdup("wuffle.baz"));
  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                          tor_strdup("gribble.baz"));
  c = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                      tor_strdup("surprisingly-legible.baz"));
  tt_str_op(a, OP_EQ, "[1010:f16e:7468:6f70:7465:7279:6769:616e]");
  tt_str_op(b, OP_EQ, "[1010:fe65:6d61:746f:6772:6170:6869:7374]");
  tt_str_op(c, OP_EQ, "[1010:f164:6d69:6e69:7374:7261:7469:6f6e]");

  // Try address exhaustion: make sure we can actually fail if we
  // get too many already-existing addresses.
  canned_data_len = 128*1024;
  canned_data = ones = tor_malloc(canned_data_len);
  memset(ones, 1, canned_data_len);
  // There is some chance this one will fail if a previous random
  // allocation gave out the address already.
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("might-work.onion"));
  if (a) {
    tt_str_op(a, OP_EQ, "192.168.1.1");
  }
  setup_capture_of_logs(LOG_WARN);
  // This one will definitely fail, since we've set up the RNG to hand
  // out "1" forever.
  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("wont-work.onion"));
  tt_assert(b == NULL);
  expect_single_log_msg_containing("Ran out of virtual addresses!");

 done:
  UNMOCK(crypto_rand);
  tor_free(ones);
  addressmap_free_all();
  teardown_capture_of_logs();
}
Esempio n. 11
0
/** Run unit tests for IPv6 encoding/decoding/manipulation functions. */
static void
test_addr_ip6_helpers(void *arg)
{
  char buf[TOR_ADDR_BUF_LEN], bug[TOR_ADDR_BUF_LEN];
  char rbuf[REVERSE_LOOKUP_NAME_BUF_LEN];
  struct in6_addr a1, a2;
  tor_addr_t t1, t2;
  int r, i;
  uint16_t port1, port2;
  maskbits_t mask;
  const char *p1;
  struct sockaddr_storage sa_storage;
  struct sockaddr_in *sin;
  struct sockaddr_in6 *sin6;

  /* Test tor_inet_ntop and tor_inet_pton: IPv6 */
  (void)arg;
  {
    const char *ip = "2001::1234";
    const char *ip_ffff = "::ffff:192.168.1.2";

    /* good round trip */
    tt_int_op(tor_inet_pton(AF_INET6, ip, &a1),OP_EQ, 1);
    tt_ptr_op(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)),OP_EQ, &buf);
    tt_str_op(buf,OP_EQ, ip);

    /* good round trip - ::ffff:0:0 style */
    tt_int_op(tor_inet_pton(AF_INET6, ip_ffff, &a2),OP_EQ, 1);
    tt_ptr_op(tor_inet_ntop(AF_INET6, &a2, buf, sizeof(buf)),OP_EQ, &buf);
    tt_str_op(buf,OP_EQ, ip_ffff);

    /* just long enough buffer (remember \0) */
    tt_str_op(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)+1),OP_EQ, ip);
    tt_str_op(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)+1),OP_EQ,
               ip_ffff);

    /* too short buffer (remember \0) */
    tt_ptr_op(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)),OP_EQ, NULL);
    tt_ptr_op(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)),OP_EQ, NULL);
  }

  /* ==== Converting to and from sockaddr_t. */
  sin = (struct sockaddr_in *)&sa_storage;
  sin->sin_family = AF_INET;
  sin->sin_port = htons(9090);
  sin->sin_addr.s_addr = htonl(0x7f7f0102); /*127.127.1.2*/
  tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, &port1);
  tt_int_op(tor_addr_family(&t1),OP_EQ, AF_INET);
  tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ, 0x7f7f0102);
  tt_int_op(port1, OP_EQ, 9090);

  memset(&sa_storage, 0, sizeof(sa_storage));
  tt_int_op(sizeof(struct sockaddr_in),OP_EQ,
          tor_addr_to_sockaddr(&t1, 1234, (struct sockaddr *)&sa_storage,
                               sizeof(sa_storage)));
  tt_int_op(1234,OP_EQ, ntohs(sin->sin_port));
  tt_int_op(0x7f7f0102,OP_EQ, 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 = htons(7070);
  sin6->sin6_addr.s6_addr[0] = 128;
  tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, &port1);
  tt_int_op(tor_addr_family(&t1),OP_EQ, AF_INET6);
  tt_int_op(port1, OP_EQ, 7070);
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
  tt_str_op(p1,OP_EQ, "8000::");

  memset(&sa_storage, 0, sizeof(sa_storage));
  tt_int_op(sizeof(struct sockaddr_in6),OP_EQ,
          tor_addr_to_sockaddr(&t1, 9999, (struct sockaddr *)&sa_storage,
                               sizeof(sa_storage)));
  tt_int_op(AF_INET6,OP_EQ, sin6->sin6_family);
  tt_int_op(9999,OP_EQ, ntohs(sin6->sin6_port));
  tt_int_op(0x80000000,OP_EQ, ntohl(S6_ADDR32(sin6->sin6_addr)[0]));

  /* ==== tor_addr_lookup: static cases.  (Can't test dns without knowing we
   * have a good resolver. */
  tt_int_op(0,OP_EQ, tor_addr_lookup("127.128.129.130", AF_UNSPEC, &t1));
  tt_int_op(AF_INET,OP_EQ, tor_addr_family(&t1));
  tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ, 0x7f808182);

  tt_int_op(0,OP_EQ, tor_addr_lookup("9000::5", AF_UNSPEC, &t1));
  tt_int_op(AF_INET6,OP_EQ, tor_addr_family(&t1));
  tt_int_op(0x90,OP_EQ, tor_addr_to_in6_addr8(&t1)[0]);
  tt_assert(tor_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14));
  tt_int_op(0x05,OP_EQ, tor_addr_to_in6_addr8(&t1)[15]);

  /* === Test pton: valid af_inet6 */
  /* Simple, valid parsing. */
  r = tor_inet_pton(AF_INET6,
                    "0102:0304:0506:0708:090A:0B0C:0D0E:0F10", &a1);
  tt_int_op(r, OP_EQ, 1);
  for (i=0;i<16;++i) { tt_int_op(i+1,OP_EQ, (int)a1.s6_addr[i]); }
  /* ipv4 ending. */
  test_pton6_same("0102:0304:0506:0708:090A:0B0C:0D0E:0F10",
                  "0102:0304:0506:0708:090A:0B0C:13.14.15.16");
  /* shortened words. */
  test_pton6_same("0001:0099:BEEF:0000:0123:FFFF:0001:0001",
                  "1:99:BEEF:0:0123:FFFF:1:1");
  /* zeros at the beginning */
  test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001",
                  "::9:c0a8:1:1");
  test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001",
                  "::9:c0a8:0.1.0.1");
  /* zeros in the middle. */
  test_pton6_same("fe80:0000:0000:0000:0202:1111:0001:0001",
                  "fe80::202:1111:1:1");
  /* zeros at the end. */
  test_pton6_same("1000:0001:0000:0007:0000:0000:0000:0000",
                  "1000:1:0:7::");

  /* === Test ntop: af_inet6 */
  test_ntop6_reduces("0:0:0:0:0:0:0:0", "::");

  test_ntop6_reduces("0001:0099:BEEF:0006:0123:FFFF:0001:0001",
                     "1:99:beef:6:123:ffff:1:1");

  //test_ntop6_reduces("0:0:0:0:0:0:c0a8:0101", "::192.168.1.1");
  test_ntop6_reduces("0:0:0:0:0:ffff:c0a8:0101", "::ffff:192.168.1.1");
  test_ntop6_reduces("0:0:0:0:0:0:c0a8:0101", "::192.168.1.1");
  test_ntop6_reduces("002:0:0000:0:3::4", "2::3:0:0:4");
  test_ntop6_reduces("0:0::1:0:3", "::1:0:3");
  test_ntop6_reduces("008:0::0", "8::");
  test_ntop6_reduces("0:0:0:0:0:ffff::1", "::ffff:0.0.0.1");
  test_ntop6_reduces("abcd:0:0:0:0:0:7f00::", "abcd::7f00:0");
  test_ntop6_reduces("0000:0000:0000:0000:0009:C0A8:0001:0001",
                     "::9:c0a8:1:1");
  test_ntop6_reduces("fe80:0000:0000:0000:0202:1111:0001:0001",
                     "fe80::202:1111:1:1");
  test_ntop6_reduces("1000:0001:0000:0007:0000:0000:0000:0000",
                     "1000:1:0:7::");

  /* Bad af param */
  tt_int_op(tor_inet_pton(AF_UNSPEC, 0, 0),OP_EQ, -1);

  /* === Test pton: invalid in6. */
  test_pton6_bad("foobar.");
  test_pton6_bad("-1::");
  test_pton6_bad("00001::");
  test_pton6_bad("10000::");
  test_pton6_bad("::10000");
  test_pton6_bad("55555::");
  test_pton6_bad("9:-60::");
  test_pton6_bad("9:+60::");
  test_pton6_bad("9|60::");
  test_pton6_bad("0x60::");
  test_pton6_bad("::0x60");
  test_pton6_bad("9:0x60::");
  test_pton6_bad("1:2:33333:4:0002:3::");
  test_pton6_bad("1:2:3333:4:fish:3::");
  test_pton6_bad("1:2:3:4:5:6:7:8:9");
  test_pton6_bad("1:2:3:4:5:6:7");
  test_pton6_bad("1:2:3:4:5:6:1.2.3.4.5");
  test_pton6_bad("1:2:3:4:5:6:1.2.3");
  test_pton6_bad("::1.2.3");
  test_pton6_bad("::1.2.3.4.5");
  test_pton6_bad("::ffff:0xff.0.0.0");
  test_pton6_bad("::ffff:ff.0.0.0");
  test_pton6_bad("::ffff:256.0.0.0");
  test_pton6_bad("::ffff:-1.0.0.0");
  test_pton6_bad("99");
  test_pton6_bad("");
  test_pton6_bad(".");
  test_pton6_bad(":");
  test_pton6_bad("1::2::3:4");
  test_pton6_bad("a:::b:c");
  test_pton6_bad(":::a:b:c");
  test_pton6_bad("a:b:c:::");
  test_pton6_bad("1.2.3.4");
  test_pton6_bad(":1.2.3.4");
  test_pton6_bad(".2.3.4");
  /* Regression tests for 22789. */
  test_pton6_bad("0xfoo");
  test_pton6_bad("0x88");
  test_pton6_bad("0xyxxy");
  test_pton6_bad("0XFOO");
  test_pton6_bad("0X88");
  test_pton6_bad("0XYXXY");
  test_pton6_bad("0x");
  test_pton6_bad("0X");

  /* test internal checking */
  test_external_ip("fbff:ffff::2:7", 0);
  test_internal_ip("fc01::2:7", 0);
  test_internal_ip("fc01::02:7", 0);
  test_internal_ip("fc01::002:7", 0);
  test_internal_ip("fc01::0002:7", 0);
  test_internal_ip("fdff:ffff::f:f", 0);
  test_external_ip("fe00::3:f", 0);

  test_external_ip("fe7f:ffff::2:7", 0);
  test_internal_ip("fe80::2:7", 0);
  test_internal_ip("febf:ffff::f:f", 0);

  test_internal_ip("fec0::2:7:7", 0);
  test_internal_ip("feff:ffff::e:7:7", 0);
  test_external_ip("ff00::e:7:7", 0);

  test_internal_ip("::", 0);
  test_internal_ip("::1", 0);
  test_internal_ip("::1", 1);
  test_internal_ip("::", 0);
  test_external_ip("::", 1);
  test_external_ip("::2", 0);
  test_external_ip("2001::", 0);
  test_external_ip("ffff::", 0);

  test_external_ip("::ffff:0.0.0.0", 1);
  test_internal_ip("::ffff:0.0.0.0", 0);
  test_internal_ip("::ffff:0.255.255.255", 0);
  test_external_ip("::ffff:1.0.0.0", 0);

  test_external_ip("::ffff:9.255.255.255", 0);
  test_internal_ip("::ffff:10.0.0.0", 0);
  test_internal_ip("::ffff:10.255.255.255", 0);
  test_external_ip("::ffff:11.0.0.0", 0);

  test_external_ip("::ffff:126.255.255.255", 0);
  test_internal_ip("::ffff:127.0.0.0", 0);
  test_internal_ip("::ffff:127.255.255.255", 0);
  test_external_ip("::ffff:128.0.0.0", 0);

  test_external_ip("::ffff:172.15.255.255", 0);
  test_internal_ip("::ffff:172.16.0.0", 0);
  test_internal_ip("::ffff:172.31.255.255", 0);
  test_external_ip("::ffff:172.32.0.0", 0);

  test_external_ip("::ffff:192.167.255.255", 0);
  test_internal_ip("::ffff:192.168.0.0", 0);
  test_internal_ip("::ffff:192.168.255.255", 0);
  test_external_ip("::ffff:192.169.0.0", 0);

  test_external_ip("::ffff:169.253.255.255", 0);
  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);

  /* tor_addr_compare(tor_addr_t x2) */
  test_addr_compare("ffff::", OP_EQ, "ffff::0");
  test_addr_compare("0::3:2:1", OP_LT, "0::ffff:0.3.2.1");
  test_addr_compare("0::2:2:1", OP_LT, "0::ffff:0.3.2.1");
  test_addr_compare("0::ffff:0.3.2.1", OP_GT, "0::0:0:0");
  test_addr_compare("0::ffff:5.2.2.1", OP_LT,
                    "::ffff:6.0.0.0"); /* XXXX wrong. */
  tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", 0, &t1, NULL, NULL, NULL);
  tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
  tt_int_op(tor_addr_compare(&t1, &t2, CMP_SEMANTIC), OP_EQ, 0);
  tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", 0, &t1, NULL, NULL, NULL);
  tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
  tt_int_op(tor_addr_compare(&t1, &t2, CMP_SEMANTIC), OP_LT, 0);

  /* test compare_masked */
  test_addr_compare_masked("ffff::", OP_EQ, "ffff::0", 128);
  test_addr_compare_masked("ffff::", OP_EQ, "ffff::0", 64);
  test_addr_compare_masked("0::2:2:1", OP_LT, "0::8000:2:1", 81);
  test_addr_compare_masked("0::2:2:1", OP_EQ, "0::8000:2:1", 80);

  /* Test undecorated tor_addr_to_str */
  tt_int_op(AF_INET6,OP_EQ, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
  tt_str_op(p1,OP_EQ, "123:45:6789::5005:11");
  tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&t1, "18.0.0.1"));
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
  tt_str_op(p1,OP_EQ, "18.0.0.1");

  /* Test decorated tor_addr_to_str */
  tt_int_op(AF_INET6,OP_EQ, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  tt_str_op(p1,OP_EQ, "[123:45:6789::5005:11]");
  tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&t1, "18.0.0.1"));
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  tt_str_op(p1,OP_EQ, "18.0.0.1");

  /* Test buffer bounds checking of tor_addr_to_str */
  tt_int_op(AF_INET6,OP_EQ, tor_addr_parse(&t1, "::")); /* 2 + \0 */
  tt_ptr_op(tor_addr_to_str(buf, &t1, 2, 0),OP_EQ, NULL); /* too short buf */
  tt_str_op(tor_addr_to_str(buf, &t1, 3, 0),OP_EQ, "::");
  tt_ptr_op(tor_addr_to_str(buf, &t1, 4, 1),OP_EQ, NULL); /* too short buf */
  tt_str_op(tor_addr_to_str(buf, &t1, 5, 1),OP_EQ, "[::]");

  tt_int_op(AF_INET6,OP_EQ, tor_addr_parse(&t1, "2000::1337")); /* 10 + \0 */
  tt_ptr_op(tor_addr_to_str(buf, &t1, 10, 0),OP_EQ, NULL); /* too short buf */
  tt_str_op(tor_addr_to_str(buf, &t1, 11, 0),OP_EQ, "2000::1337");
  tt_ptr_op(tor_addr_to_str(buf, &t1, 12, 1),OP_EQ, NULL); /* too short buf */
  tt_str_op(tor_addr_to_str(buf, &t1, 13, 1),OP_EQ, "[2000::1337]");

  tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&t1, "1.2.3.4")); /* 7 + \0 */
  tt_ptr_op(tor_addr_to_str(buf, &t1, 7, 0),OP_EQ, NULL); /* too short buf */
  tt_str_op(tor_addr_to_str(buf, &t1, 8, 0),OP_EQ, "1.2.3.4");

  tt_int_op(AF_INET, OP_EQ,
            tor_addr_parse(&t1, "255.255.255.255")); /* 15 + \0 */
  tt_ptr_op(tor_addr_to_str(buf, &t1, 15, 0),OP_EQ, NULL); /* too short buf */
  tt_str_op(tor_addr_to_str(buf, &t1, 16, 0),OP_EQ, "255.255.255.255");
  tt_ptr_op(tor_addr_to_str(buf, &t1, 15, 1),OP_EQ, NULL); /* too short buf */
  tt_str_op(tor_addr_to_str(buf, &t1, 16, 1),OP_EQ, "255.255.255.255");

  t1.family = AF_UNSPEC;
  tt_ptr_op(tor_addr_to_str(buf, &t1, sizeof(buf), 0),OP_EQ, NULL);

  /* Test tor_addr_parse_PTR_name */
  i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 0);
  tt_int_op(0,OP_EQ, i);
  i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 1);
  tt_int_op(0,OP_EQ, i);
  i = tor_addr_parse_PTR_name(&t1, "9999999999999999999999999999.in-addr.arpa",
                              AF_UNSPEC, 1);
  tt_int_op(-1,OP_EQ, i);
  i = tor_addr_parse_PTR_name(&t1, "1.0.168.192.in-addr.arpa",
                                         AF_UNSPEC, 1);
  tt_int_op(1,OP_EQ, i);
  tt_int_op(tor_addr_family(&t1),OP_EQ, AF_INET);
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  tt_str_op(p1,OP_EQ, "192.168.0.1");
  i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 0);
  tt_int_op(0,OP_EQ, i);
  i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 1);
  tt_int_op(1,OP_EQ, i);
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  tt_str_op(p1,OP_EQ, "192.168.0.99");
  memset(&t1, 0, sizeof(t1));
  i = tor_addr_parse_PTR_name(&t1,
                                         "0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_UNSPEC, 0);
  tt_int_op(1,OP_EQ, i);
  p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
  tt_str_op(p1,OP_EQ, "[9dee:effe:ebe1:beef:fedc:ba98:7654:3210]");
  /* Failing cases. */
  i = tor_addr_parse_PTR_name(&t1,
                                         "6.7.8.9.a.b.c.d.e.f."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_UNSPEC, 0);
  tt_int_op(i,OP_EQ, -1);
  i = tor_addr_parse_PTR_name(&t1,
                                         "6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.f.0."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_UNSPEC, 0);
  tt_int_op(i,OP_EQ, -1);
  i = tor_addr_parse_PTR_name(&t1,
                                         "6.7.8.9.a.b.c.d.e.f.X.0.0.0.0.9."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_UNSPEC, 0);
  tt_int_op(i,OP_EQ, -1);
  i = tor_addr_parse_PTR_name(&t1, "32.1.1.in-addr.arpa",
                                         AF_UNSPEC, 0);
  tt_int_op(i,OP_EQ, -1);
  i = tor_addr_parse_PTR_name(&t1, ".in-addr.arpa",
                                         AF_UNSPEC, 0);
  tt_int_op(i,OP_EQ, -1);
  i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa",
                                         AF_UNSPEC, 0);
  tt_int_op(i,OP_EQ, -1);
  i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa",
                                         AF_INET6, 0);
  tt_int_op(i,OP_EQ, -1);
  i = tor_addr_parse_PTR_name(&t1,
                                         "6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.0."
                                         "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
                                         "ip6.ARPA",
                                         AF_INET, 0);
  tt_int_op(i,OP_EQ, -1);

  /* === Test tor_addr_to_PTR_name */

  /* Stage IPv4 addr */
  memset(&sa_storage, 0, sizeof(sa_storage));
  sin = (struct sockaddr_in *)&sa_storage;
  sin->sin_family = AF_INET;
  sin->sin_addr.s_addr = htonl(0x7f010203); /* 127.1.2.3 */
  tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL);

  /* Check IPv4 PTR - too short buffer */
  tt_int_op(tor_addr_to_PTR_name(rbuf, 1, &t1),OP_EQ, -1);
  tt_int_op(tor_addr_to_PTR_name(rbuf,
                               strlen("3.2.1.127.in-addr.arpa") - 1,
                               &t1),OP_EQ, -1);

  /* Check IPv4 PTR - valid addr */
  tt_int_op(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),OP_EQ,
          strlen("3.2.1.127.in-addr.arpa"));
  tt_str_op(rbuf,OP_EQ, "3.2.1.127.in-addr.arpa");

  /* Invalid addr family */
  t1.family = AF_UNSPEC;
  tt_int_op(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),OP_EQ, -1);

  /* Stage IPv6 addr */
  memset(&sa_storage, 0, sizeof(sa_storage));
  sin6 = (struct sockaddr_in6 *)&sa_storage;
  sin6->sin6_family = AF_INET6;
  sin6->sin6_addr.s6_addr[0] = 0x80; /* 8000::abcd */
  sin6->sin6_addr.s6_addr[14] = 0xab;
  sin6->sin6_addr.s6_addr[15] = 0xcd;

  tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL);

  {
    const char* addr_PTR = "d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0."
      "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.ip6.arpa";

    /* Check IPv6 PTR - too short buffer */
    tt_int_op(tor_addr_to_PTR_name(rbuf, 0, &t1),OP_EQ, -1);
    tt_int_op(tor_addr_to_PTR_name(rbuf, strlen(addr_PTR) - 1, &t1),OP_EQ, -1);

    /* Check IPv6 PTR - valid addr */
    tt_int_op(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),OP_EQ,
            strlen(addr_PTR));
    tt_str_op(rbuf,OP_EQ, addr_PTR);
  }

  /* XXXX turn this into a separate function; it's not all IPv6. */
  /* test tor_addr_parse_mask_ports */
  test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6,
                             0, 0, 0, 0x0000000f, 17, 47, 95);
  tt_str_op(p1,OP_EQ, "::f");
  //test_addr_parse("[::fefe:4.1.1.7/120]:999-1000");
  //test_addr_parse_check("::fefe:401:107", 120, 999, 1000);
  test_addr_mask_ports_parse("[::ffff:4.1.1.7]/120:443", AF_INET6,
                             0, 0, 0x0000ffff, 0x04010107, 120, 443, 443);
  tt_str_op(p1,OP_EQ, "::ffff:4.1.1.7");
  test_addr_mask_ports_parse("[abcd:2::44a:0]:2-65000", AF_INET6,
                             0xabcd0002, 0, 0, 0x044a0000, 128, 2, 65000);

  tt_str_op(p1,OP_EQ, "abcd:2::44a:0");
  /* Try some long addresses. */
  r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111]",
                              0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, AF_INET6);
  r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:11111]",
                              0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111:1]",
                              0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports(
         "[ffff:1111:1111:1111:1111:1111:1111:ffff:"
         "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
         "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
         "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
         0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  /* Try some failing cases. */
  r=tor_addr_parse_mask_ports("[fefef::]/112", 0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[fefe::/112", 0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[fefe::", 0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[fefe::X]", 0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("efef::/112", 0, &t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]",0,&t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/fred",0,&t1,&mask, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/255.255.0.0",
                              0,&t1, NULL, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  /* This one will get rejected because it isn't a pure prefix. */
  r=tor_addr_parse_mask_ports("1.1.2.3/255.255.64.0",0,&t1, &mask,NULL,NULL);
  tt_int_op(r, OP_EQ, -1);
  /* Test for V4-mapped address with mask < 96.  (arguably not valid) */
  r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]",0,&t1, &mask, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("1.1.2.2/33",0,&t1, &mask, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  /* Try extended wildcard addresses with out TAPMP_EXTENDED_STAR*/
  r=tor_addr_parse_mask_ports("*4",0,&t1, &mask, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("*6",0,&t1, &mask, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  tt_int_op(r, OP_EQ, -1);
  /* Try a mask with a wildcard. */
  r=tor_addr_parse_mask_ports("*/16",0,&t1, &mask, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("*4/16",TAPMP_EXTENDED_STAR,
                              &t1, &mask, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  r=tor_addr_parse_mask_ports("*6/30",TAPMP_EXTENDED_STAR,
                              &t1, &mask, NULL, NULL);
  tt_int_op(r, OP_EQ, -1);
  /* Basic mask tests*/
  r=tor_addr_parse_mask_ports("1.1.2.2/31",0,&t1, &mask, NULL, NULL);
  tt_int_op(r, OP_EQ, AF_INET);
  tt_int_op(mask,OP_EQ,31);
  tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
  tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010202);
  r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2);
  tt_int_op(r, OP_EQ, AF_INET);
  tt_int_op(mask,OP_EQ,32);
  tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
  tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x03041020);
  tt_uint_op(port1, OP_EQ, 1);
  tt_uint_op(port2, OP_EQ, 2);
  r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
  tt_int_op(r, OP_EQ, AF_INET);
  tt_int_op(mask,OP_EQ,17);
  tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
  tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010203);
  r=tor_addr_parse_mask_ports("[efef::]/112",0,&t1, &mask, &port1, &port2);
  tt_int_op(r, OP_EQ, AF_INET6);
  tt_uint_op(port1, OP_EQ, 1);
  tt_uint_op(port2, OP_EQ, 65535);
  /* Try regular wildcard behavior without TAPMP_EXTENDED_STAR */
  r=tor_addr_parse_mask_ports("*:80-443",0,&t1,&mask,&port1,&port2);
  tt_int_op(r,OP_EQ,AF_INET); /* Old users of this always get inet */
  tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
  tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0);
  tt_int_op(mask,OP_EQ,0);
  tt_int_op(port1,OP_EQ,80);
  tt_int_op(port2,OP_EQ,443);
  /* Now try wildcards *with* TAPMP_EXTENDED_STAR */
  r=tor_addr_parse_mask_ports("*:8000-9000",TAPMP_EXTENDED_STAR,
                              &t1,&mask,&port1,&port2);
  tt_int_op(r,OP_EQ,AF_UNSPEC);
  tt_int_op(tor_addr_family(&t1),OP_EQ,AF_UNSPEC);
  tt_int_op(mask,OP_EQ,0);
  tt_int_op(port1,OP_EQ,8000);
  tt_int_op(port2,OP_EQ,9000);
  r=tor_addr_parse_mask_ports("*4:6667",TAPMP_EXTENDED_STAR,
                              &t1,&mask,&port1,&port2);
  tt_int_op(r,OP_EQ,AF_INET);
  tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
  tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0);
  tt_int_op(mask,OP_EQ,0);
  tt_int_op(port1,OP_EQ,6667);
  tt_int_op(port2,OP_EQ,6667);
  r=tor_addr_parse_mask_ports("*6",TAPMP_EXTENDED_STAR,
                              &t1,&mask,&port1,&port2);
  tt_int_op(r,OP_EQ,AF_INET6);
  tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET6);
  tt_assert(tor_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16));
  tt_int_op(mask,OP_EQ,0);
  tt_int_op(port1,OP_EQ,1);
  tt_int_op(port2,OP_EQ,65535);

  /* make sure inet address lengths >= max */
  tt_int_op(INET_NTOA_BUF_LEN, OP_GE, sizeof("255.255.255.255"));
  tt_int_op(TOR_ADDR_BUF_LEN, OP_GE,
            sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"));

  tt_assert(sizeof(tor_addr_t) >= sizeof(struct in6_addr));

  /* get interface addresses */
  r = get_interface_address6(LOG_DEBUG, AF_INET, &t1);
  tt_int_op(r, OP_LE, 0); // "it worked or it didn't"
  i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2);
  tt_int_op(i, OP_LE, 0); // "it worked or it didn't"

  TT_BLATHER(("v4 address: %s (family=%d)", fmt_addr(&t1),
              tor_addr_family(&t1)));
  TT_BLATHER(("v6 address: %s (family=%d)", fmt_addr(&t2),
              tor_addr_family(&t2)));

 done:
  ;
}