commit c6d8c6baaa983aecd6a5121ec6ed8e2d9a2a24be Author: Robert Hogan robert@webkit.org Date: Mon Aug 2 20:09:37 2010 +0100
bug933 - Match against super-domains in MapAddress
Allow MapAddress to handle directives such as:
MapAddress .torproject.org .torserver.exit MapAddress .org 1.1.1.1
Add tests for addressmap_rewrite. --- changes/bug933 | 4 ++ doc/tor.1.txt | 7 ++- src/or/connection_edge.c | 41 ++++++++++++++- src/test/Makefile.am | 1 + src/test/test.c | 2 + src/test/test_config.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 4 deletions(-)
diff --git a/changes/bug933 b/changes/bug933 new file mode 100644 index 0000000..b646858 --- /dev/null +++ b/changes/bug933 @@ -0,0 +1,4 @@ + o Minor features: + - Allow MapAddress directives to specify matches against super-domains, + as in 'MapAddress *.torproject.org *.torproject.org.torserver.exit'. + Implements issue 933. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 4edee80..4d4ad9f 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -659,7 +659,12 @@ The following options are useful only for clients (that is, if before processing it. For example, if you always want connections to www.indymedia.org to exit via __torserver__ (where __torserver__ is the nickname of the server), use "MapAddress www.indymedia.org - www.indymedia.org.torserver.exit". + www.indymedia.org.torserver.exit". If the value is prepended with a '.', + it is treated as matching an entire domain.For example, if you always + want connections to any sub-domain of indymedia.org to exit via + __torserver__ (where __torserver__ is the nickname of the server), use + "MapAddress .indymedia.org .torserver.exit". (Note the leading '.' in + each part of the directive.)
**NewCircuitPeriod** __NUM__:: Every NUM seconds consider whether to build a new circuit. (Default: 30 diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index f59f44c..4bb49c8 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1037,6 +1037,29 @@ addressmap_free_all(void) virtaddress_reversemap = NULL; }
+/** Try to find a match for AddressMap directives that use + * domain notation such as '.torproject.org .exitnode.exit'. + */ +static addressmap_entry_t * +addressmap_match_superdomains(char *address) +{ + strmap_iter_t *iter; + const char *key; + void *_val; + addressmap_entry_t *val; + + for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) { + strmap_iter_get(iter, &key, &_val); + val = _val; + if (key[0] == '.') { /* match end */ + if (!strcasecmpend(address, key) || !strcasecmp(address, &key[1])) + return val; + } + iter = strmap_iter_next(addressmap,iter); + } + return 0; +} + /** Look at address, and rewrite it until it doesn't want any * more rewrites; but don't get into an infinite loop. * Don't write more than maxlen chars into address. Return true if the @@ -1050,24 +1073,36 @@ addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out) addressmap_entry_t *ent; int rewrites; char *cp; + char *s; time_t expires = TIME_MAX;
for (rewrites = 0; rewrites < 16; rewrites++) { ent = strmap_get(addressmap, address);
+ if (!ent || !ent->new_address) + ent = addressmap_match_superdomains(address); + if (!ent || !ent->new_address) { if (expires_out) *expires_out = expires; return (rewrites > 0); /* done, no rewrite needed */ }
- cp = tor_strdup(escaped_safe_str_client(ent->new_address)); + cp = tor_strdup(escaped_safe_str_client(address)); + /* If the address to rewrite to is in the form '.exitnode.exit' + then append it to the given address */ + s = strrchr(ent->new_address,'.'); + if (ent->new_address[0] == '.' && !strcmp(s+1,"exit")) + strlcpy(address + strlen(address), ent->new_address, + (maxlen - strlen(address))); + else + strlcpy(address, ent->new_address, maxlen); + log_info(LD_APP, "Addressmap: rewriting %s to %s", - escaped_safe_str_client(address), cp); + cp, escaped_safe_str_client(address)); if (ent->expires > 1 && ent->expires < expires) expires = ent->expires; tor_free(cp); - strlcpy(address, ent->new_address, maxlen); } log_warn(LD_CONFIG, "Loop detected: we've rewritten %s 16 times! Using it as-is.", diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 8527150..e675431 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -20,6 +20,7 @@ test_SOURCES = \ test_dir.c \ test_microdesc.c \ test_util.c \ + test_config.c \ tinytest.c
test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ diff --git a/src/test/test.c b/src/test/test.c index 605e44c..76644a7 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1941,6 +1941,7 @@ extern struct testcase_t container_tests[]; extern struct testcase_t util_tests[]; extern struct testcase_t dir_tests[]; extern struct testcase_t microdesc_tests[]; +extern struct testcase_t config_tests[];
static struct testgroup_t testgroups[] = { { "", test_array }, @@ -1951,6 +1952,7 @@ static struct testgroup_t testgroups[] = { { "util/", util_tests }, { "dir/", dir_tests }, { "dir/md/", microdesc_tests }, + { "config/", config_tests }, END_OF_GROUPS };
diff --git a/src/test/test_config.c b/src/test/test_config.c new file mode 100644 index 0000000..f39a9ef --- /dev/null +++ b/src/test/test_config.c @@ -0,0 +1,127 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2010, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "or.h" +#include "config.h" +#include "connection_edge.h" +#include "test.h" + +static void +test_config_addressmap(void) +{ + char buf[1024]; + char address[256]; + time_t expires = TIME_MAX; + strlcpy(buf, "MapAddress .google.com .torserver.exit\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 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()->AddressMap)); + config_register_addressmaps(get_options()); + + /* Where no mapping for FQDN match on top-level domain */ + strlcpy(address, "reader.google.com", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "reader.google.com.torserver.exit"); + + /* Where mapping for FQDN match on FQDN */ + strlcpy(address, "www.google.com", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "3.3.3.3"); + + strlcpy(address, "www.torproject.org", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "1.1.1.1"); + + strlcpy(address, "other.torproject.org", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "this.torproject.org.otherserver.exit"); + + strlcpy(address, "test.torproject.org", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "2.2.2.2"); + + /* Test a chain of address mappings */ + strlcpy(address, "www.example.org", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + 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)); + 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)); + + /* 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()->AddressMap)); + config_register_addressmaps(get_options()); + + strlcpy(address, "www.abc.com", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "www.abc.com.torserver.exit"); + + strlcpy(address, "www.def.com", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "www.def.com.torserver.exit"); + + strlcpy(address, "www.torproject.org", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "1.1.1.1"); + + strlcpy(address, "test.torproject.org", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + test_streq(address, "1.1.1.1"); + + strlcpy(address, "torproject.net", sizeof(address)); + test_assert(addressmap_rewrite(address, sizeof(address), &expires)); + 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()->AddressMap)); + config_register_addressmaps(get_options()); + + strlcpy(address, "www.abc.com", sizeof(address)); + test_assert(!addressmap_rewrite(address, sizeof(address), &expires)); + + strlcpy(address, "www.def.net", sizeof(address)); + test_assert(!addressmap_rewrite(address, sizeof(address), &expires)); + + strlcpy(address, "www.torproject.org", sizeof(address)); + test_assert(!addressmap_rewrite(address, sizeof(address), &expires)); + +done: + ; +} + +#define CONFIG_LEGACY(name) \ + { #name, legacy_test_helper, 0, &legacy_setup, test_config_ ## name } + +#define CONFIG_TEST(name, flags) \ + { #name, test_config_ ## name, flags, NULL, NULL } + +struct testcase_t config_tests[] = { + CONFIG_LEGACY(addressmap), + END_OF_TESTCASES +}; +