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.
This commit is contained in:
Robert Hogan 2010-08-02 20:09:37 +01:00 committed by Nick Mathewson
parent d3ff167e09
commit c6d8c6baaa
6 changed files with 178 additions and 4 deletions

4
changes/bug933 Normal file
View File

@ -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.

View File

@ -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 before processing it. For example, if you always want connections to
www.indymedia.org to exit via __torserver__ (where __torserver__ is the www.indymedia.org to exit via __torserver__ (where __torserver__ is the
nickname of the server), use "MapAddress www.indymedia.org 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__:: **NewCircuitPeriod** __NUM__::
Every NUM seconds consider whether to build a new circuit. (Default: 30 Every NUM seconds consider whether to build a new circuit. (Default: 30

View File

@ -1037,6 +1037,29 @@ addressmap_free_all(void)
virtaddress_reversemap = NULL; 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 /** Look at address, and rewrite it until it doesn't want any
* more rewrites; but don't get into an infinite loop. * more rewrites; but don't get into an infinite loop.
* Don't write more than maxlen chars into address. Return true if the * 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; addressmap_entry_t *ent;
int rewrites; int rewrites;
char *cp; char *cp;
char *s;
time_t expires = TIME_MAX; time_t expires = TIME_MAX;
for (rewrites = 0; rewrites < 16; rewrites++) { for (rewrites = 0; rewrites < 16; rewrites++) {
ent = strmap_get(addressmap, address); ent = strmap_get(addressmap, address);
if (!ent || !ent->new_address)
ent = addressmap_match_superdomains(address);
if (!ent || !ent->new_address) { if (!ent || !ent->new_address) {
if (expires_out) if (expires_out)
*expires_out = expires; *expires_out = expires;
return (rewrites > 0); /* done, no rewrite needed */ 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", 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) if (ent->expires > 1 && ent->expires < expires)
expires = ent->expires; expires = ent->expires;
tor_free(cp); tor_free(cp);
strlcpy(address, ent->new_address, maxlen);
} }
log_warn(LD_CONFIG, log_warn(LD_CONFIG,
"Loop detected: we've rewritten %s 16 times! Using it as-is.", "Loop detected: we've rewritten %s 16 times! Using it as-is.",

View File

@ -20,6 +20,7 @@ test_SOURCES = \
test_dir.c \ test_dir.c \
test_microdesc.c \ test_microdesc.c \
test_util.c \ test_util.c \
test_config.c \
tinytest.c tinytest.c
test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \

View File

@ -1941,6 +1941,7 @@ extern struct testcase_t container_tests[];
extern struct testcase_t util_tests[]; extern struct testcase_t util_tests[];
extern struct testcase_t dir_tests[]; extern struct testcase_t dir_tests[];
extern struct testcase_t microdesc_tests[]; extern struct testcase_t microdesc_tests[];
extern struct testcase_t config_tests[];
static struct testgroup_t testgroups[] = { static struct testgroup_t testgroups[] = {
{ "", test_array }, { "", test_array },
@ -1951,6 +1952,7 @@ static struct testgroup_t testgroups[] = {
{ "util/", util_tests }, { "util/", util_tests },
{ "dir/", dir_tests }, { "dir/", dir_tests },
{ "dir/md/", microdesc_tests }, { "dir/md/", microdesc_tests },
{ "config/", config_tests },
END_OF_GROUPS END_OF_GROUPS
}; };

127
src/test/test_config.c Normal file
View File

@ -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
};