mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-20 02:09:24 +01:00
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:
parent
d3ff167e09
commit
c6d8c6baaa
4
changes/bug933
Normal file
4
changes/bug933
Normal 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.
|
@ -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
|
||||||
|
@ -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.",
|
||||||
|
@ -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@ \
|
||||||
|
@ -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
127
src/test/test_config.c
Normal 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
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user