Bläddra i källkod

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.
Robert Hogan 15 år sedan
förälder
incheckning
c6d8c6baaa
6 ändrade filer med 178 tillägg och 4 borttagningar
  1. 4 0
      changes/bug933
  2. 6 1
      doc/tor.1.txt
  3. 38 3
      src/or/connection_edge.c
  4. 1 0
      src/test/Makefile.am
  5. 2 0
      src/test/test.c
  6. 127 0
      src/test/test_config.c

+ 4 - 0
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.

+ 6 - 1
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
     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

+ 38 - 3
src/or/connection_edge.c

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

+ 1 - 0
src/test/Makefile.am

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

+ 2 - 0
src/test/test.c

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