/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #include "or.h" #include "addressmap.h" #include "config.h" #include "confparse.h" #include "connection_edge.h" #include "test.h" #include "util.h" #include "address.h" static void test_config_addressmap(void *arg) { char buf[1024]; char address[256]; time_t expires = TIME_MAX; (void)arg; strlcpy(buf, "MapAddress .invalidwildcard.com *.torserver.exit\n" // invalid "MapAddress *invalidasterisk.com *.torserver.exit\n" // invalid "MapAddress *.google.com *.torserver.exit\n" "MapAddress *.yahoo.com *.google.com.torserver.exit\n" "MapAddress *.cn.com www.cnn.com\n" "MapAddress *.cnn.com www.cnn.com\n" "MapAddress ex.com www.cnn.com\n" "MapAddress ey.com *.cnn.com\n" "MapAddress www.torproject.org 1.1.1.1\n" "MapAddress other.torproject.org " "this.torproject.org.otherserver.exit\n" "MapAddress test.torproject.org 2.2.2.2\n" "MapAddress www.google.com 3.3.3.3\n" "MapAddress www.example.org 4.4.4.4\n" "MapAddress 4.4.4.4 7.7.7.7\n" "MapAddress 4.4.4.4 5.5.5.5\n" "MapAddress www.infiniteloop.org 6.6.6.6\n" "MapAddress 6.6.6.6 www.infiniteloop.org\n" , sizeof(buf)); config_get_lines(buf, &(get_options_mutable()->AddressMap), 0); config_register_addressmaps(get_options()); /* Use old interface for now, so we don't need to rewrite the unit tests */ #define addressmap_rewrite(a,s,eo,ao) \ addressmap_rewrite((a),(s),AMR_FLAG_USE_IPV4_DNS|AMR_FLAG_USE_IPV6_DNS, \ (eo),(ao)) /* MapAddress .invalidwildcard.com .torserver.exit - no match */ strlcpy(address, "www.invalidwildcard.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* MapAddress *invalidasterisk.com .torserver.exit - no match */ strlcpy(address, "www.invalidasterisk.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* Where no mapping for FQDN match on top-level domain */ /* MapAddress .google.com .torserver.exit */ strlcpy(address, "reader.google.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "reader.torserver.exit"); /* MapAddress *.yahoo.com *.google.com.torserver.exit */ strlcpy(address, "reader.yahoo.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "reader.google.com.torserver.exit"); /*MapAddress *.cnn.com www.cnn.com */ strlcpy(address, "cnn.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.cnn.com"); /* MapAddress .cn.com www.cnn.com */ strlcpy(address, "www.cn.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.cnn.com"); /* MapAddress ex.com www.cnn.com - no match */ strlcpy(address, "www.ex.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* MapAddress ey.com *.cnn.com - invalid expression */ strlcpy(address, "ey.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* Where mapping for FQDN match on FQDN */ strlcpy(address, "www.google.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "3.3.3.3"); strlcpy(address, "www.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "1.1.1.1"); strlcpy(address, "other.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "this.torproject.org.otherserver.exit"); strlcpy(address, "test.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "2.2.2.2"); /* Test a chain of address mappings and the order in which they were added: "MapAddress www.example.org 4.4.4.4" "MapAddress 4.4.4.4 7.7.7.7" "MapAddress 4.4.4.4 5.5.5.5" */ strlcpy(address, "www.example.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "5.5.5.5"); /* Test infinite address mapping results in no change */ strlcpy(address, "www.infiniteloop.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.infiniteloop.org"); /* Test we don't find false positives */ strlcpy(address, "www.example.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* Test top-level-domain matching a bit harder */ addressmap_clear_configured(); strlcpy(buf, "MapAddress *.com *.torserver.exit\n" "MapAddress *.torproject.org 1.1.1.1\n" "MapAddress *.net 2.2.2.2\n" , sizeof(buf)); config_get_lines(buf, &(get_options_mutable()->AddressMap), 0); config_register_addressmaps(get_options()); strlcpy(address, "www.abc.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.abc.torserver.exit"); strlcpy(address, "www.def.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.def.torserver.exit"); strlcpy(address, "www.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "1.1.1.1"); strlcpy(address, "test.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "1.1.1.1"); strlcpy(address, "torproject.net", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "2.2.2.2"); /* We don't support '*' as a mapping directive */ addressmap_clear_configured(); strlcpy(buf, "MapAddress * *.torserver.exit\n", sizeof(buf)); config_get_lines(buf, &(get_options_mutable()->AddressMap), 0); config_register_addressmaps(get_options()); strlcpy(address, "www.abc.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); strlcpy(address, "www.def.net", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); strlcpy(address, "www.torproject.org", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); #undef addressmap_rewrite done: ; } /* Test helper function: Make sure that a bridge line gets parsed * properly. Also make sure that the resulting bridge_line_t structure * has its fields set correctly. */ static void good_bridge_line_test(const char *string, const char *test_addrport, const char *test_digest, const char *test_transport, const smartlist_t *test_socks_args) { char *tmp = NULL; bridge_line_t *bridge_line = parse_bridge_line(string); test_assert(bridge_line); /* test addrport */ tmp = tor_strdup(fmt_addrport(&bridge_line->addr, bridge_line->port)); test_streq(test_addrport, tmp); tor_free(tmp); /* If we were asked to validate a digest, but we did not get a digest after parsing, we failed. */ if (test_digest && tor_digest_is_zero(bridge_line->digest)) test_assert(0); /* If we were not asked to validate a digest, and we got a digest after parsing, we failed again. */ if (!test_digest && !tor_digest_is_zero(bridge_line->digest)) test_assert(0); /* If we were asked to validate a digest, and we got a digest after parsing, make sure it's correct. */ if (test_digest) { tmp = tor_strdup(hex_str(bridge_line->digest, DIGEST_LEN)); tor_strlower(tmp); test_streq(test_digest, tmp); tor_free(tmp); } /* If we were asked to validate a transport name, make sure tha it matches with the transport name that was parsed. */ if (test_transport && !bridge_line->transport_name) test_assert(0); if (!test_transport && bridge_line->transport_name) test_assert(0); if (test_transport) test_streq(test_transport, bridge_line->transport_name); /* Validate the SOCKS argument smartlist. */ if (test_socks_args && !bridge_line->socks_args) test_assert(0); if (!test_socks_args && bridge_line->socks_args) test_assert(0); if (test_socks_args) test_assert(smartlist_strings_eq(test_socks_args, bridge_line->socks_args)); done: tor_free(tmp); bridge_line_free(bridge_line); } /* Test helper function: Make sure that a bridge line is * unparseable. */ static void bad_bridge_line_test(const char *string) { bridge_line_t *bridge_line = parse_bridge_line(string); test_assert(!bridge_line); done: bridge_line_free(bridge_line); } static void test_config_parse_bridge_line(void *arg) { (void) arg; good_bridge_line_test("192.0.2.1:4123", "192.0.2.1:4123", NULL, NULL, NULL); good_bridge_line_test("192.0.2.1", "192.0.2.1:443", NULL, NULL, NULL); good_bridge_line_test("transport [::1]", "[::1]:443", NULL, "transport", NULL); good_bridge_line_test("transport 192.0.2.1:12 " "4352e58420e68f5e40bf7c74faddccd9d1349413", "192.0.2.1:12", "4352e58420e68f5e40bf7c74faddccd9d1349413", "transport", NULL); { smartlist_t *sl_tmp = smartlist_new(); smartlist_add_asprintf(sl_tmp, "twoandtwo=five"); good_bridge_line_test("transport 192.0.2.1:12 " "4352e58420e68f5e40bf7c74faddccd9d1349413 twoandtwo=five", "192.0.2.1:12", "4352e58420e68f5e40bf7c74faddccd9d1349413", "transport", sl_tmp); SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); smartlist_free(sl_tmp); } { smartlist_t *sl_tmp = smartlist_new(); smartlist_add_asprintf(sl_tmp, "twoandtwo=five"); smartlist_add_asprintf(sl_tmp, "z=z"); good_bridge_line_test("transport 192.0.2.1:12 twoandtwo=five z=z", "192.0.2.1:12", NULL, "transport", sl_tmp); SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); smartlist_free(sl_tmp); } good_bridge_line_test("192.0.2.1:1231 " "4352e58420e68f5e40bf7c74faddccd9d1349413", "192.0.2.1:1231", "4352e58420e68f5e40bf7c74faddccd9d1349413", NULL, NULL); /* Empty line */ bad_bridge_line_test(""); /* bad transport name */ bad_bridge_line_test("tr$n_sp0r7 190.20.2.2"); /* weird ip address */ bad_bridge_line_test("a.b.c.d"); /* invalid fpr */ bad_bridge_line_test("2.2.2.2:1231 4352e58420e68f5e40bf7c74faddccd9d1349"); /* no k=v in the end */ bad_bridge_line_test("obfs2 2.2.2.2:1231 " "4352e58420e68f5e40bf7c74faddccd9d1349413 what"); /* no addrport */ bad_bridge_line_test("asdw"); /* huge k=v value that can't fit in SOCKS fields */ bad_bridge_line_test( "obfs2 2.2.2.2:1231 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aa=b"); } #define CONFIG_TEST(name, flags) \ { #name, test_config_ ## name, flags, NULL, NULL } struct testcase_t config_tests[] = { CONFIG_TEST(addressmap, 0), CONFIG_TEST(parse_bridge_line, 0), END_OF_TESTCASES };