[tor-commits] [tor/master] Merge branch 'bug7555_v2_squashed'

nickm at torproject.org nickm at torproject.org
Mon Jan 19 16:44:20 UTC 2015


commit 1053af0b9c4127873034a935ce3382940696e693
Merge: 6376539 758d771
Author: Nick Mathewson <nickm at torproject.org>
Date:   Mon Jan 19 11:43:41 2015 -0500

    Merge branch 'bug7555_v2_squashed'
    
    Conflicts:
    	src/or/connection_edge.c

 changes/bug14193          |    4 +
 changes/bug14259          |    6 +
 changes/bug7555           |    5 +
 src/or/addressmap.c       |   42 ++-
 src/or/addressmap.h       |    7 +-
 src/or/connection_edge.c  |  352 ++++++++++++++++-----
 src/or/connection_edge.h  |   25 ++
 src/test/include.am       |    1 +
 src/test/test.c           |    2 +
 src/test/test_config.c    |    3 +-
 src/test/test_entryconn.c |  770 +++++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 1118 insertions(+), 99 deletions(-)

diff --cc src/or/connection_edge.c
index 33c4257,06d3546..13053a3
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@@ -963,16 -978,24 +978,24 @@@ connection_ap_handshake_rewrite(entry_c
    if (socks->command == SOCKS_COMMAND_RESOLVE &&
        tor_addr_parse(&addr_tmp, socks->address)<0 &&
        options->AutomapHostsOnResolve) {
-     automap = addressmap_address_should_automap(socks->address, options);
-     if (automap) {
+     /* Check the suffix... */
+     out->automap = addressmap_address_should_automap(socks->address, options);
+     if (out->automap) {
+       /* If we get here, then we should apply an automapping for this. */
        const char *new_addr;
+       /* We return an IPv4 address by default, or an IPv6 address if we
+        * are allowed to do so. */
        int addr_type = RESOLVED_TYPE_IPV4;
        if (conn->socks_request->socks_version != 4) {
 -        if (!conn->ipv4_traffic_ok ||
 -            (conn->ipv6_traffic_ok && conn->prefer_ipv6_traffic) ||
 -            conn->prefer_ipv6_virtaddr)
 +        if (!conn->entry_cfg.ipv4_traffic ||
 +            (conn->entry_cfg.ipv6_traffic && conn->entry_cfg.prefer_ipv6) ||
 +            conn->entry_cfg.prefer_ipv6_virtaddr)
            addr_type = RESOLVED_TYPE_IPV6;
        }
+       /* Okay, register the target address as automapped, and find the new
+        * address we're supposed to give as a resolve answer.  (Return a cached
+        * value if we've looked up this address before.
+        */
        new_addr = addressmap_register_virtual_address(
                                      addr_type, tor_strdup(socks->address));
        if (! new_addr) {
@@@ -988,11 -1012,13 +1012,13 @@@
      }
    }
  
+   /* Now handle reverse lookups, if they're in the cache.  This doesn't
+    * happen too often, since client-side DNS caching is off by default. */
    if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
      unsigned rewrite_flags = 0;
 -    if (conn->use_cached_ipv4_answers)
 +    if (conn->entry_cfg.use_cached_ipv4_answers)
        rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
 -    if (conn->use_cached_ipv6_answers)
 +    if (conn->entry_cfg.use_cached_ipv6_answers)
        rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
  
      if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address),
@@@ -1019,21 -1050,30 +1050,30 @@@
        if (ok == 1 && tor_addr_is_internal(&addr, 0)) {
          connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR,
                                                 0, NULL, -1, TIME_MAX);
-         connection_mark_unattached_ap(conn,
-                                  END_STREAM_REASON_SOCKSPROTOCOL |
-                                  END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
-         return -1;
+         out->end_reason = END_STREAM_REASON_SOCKSPROTOCOL |
+                           END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED;
+         out->should_close = 1;
+         return;
        }
      }
-   } else if (!automap) {
-     /* For address map controls, remap the address. */
-     unsigned rewrite_flags = 0;
+   }
+ 
+   /* If we didn't automap it before, then this is still the address
+    * that came straight from the user, mapped according to any
+    * MapAddress/MAPADDRESS commands.  Now other mappings, including
+    * previously registered Automap entries, TrackHostExits entries,
+    * and client-side DNS cache entries (not recommended).
+    */
+   if (!socks->command != SOCKS_COMMAND_RESOLVE_PTR &&
+       !out->automap) {
+     unsigned rewrite_flags = AMR_FLAG_USE_AUTOMAP | AMR_FLAG_USE_TRACKEXIT;
+     addressmap_entry_source_t exit_source2;
 -    if (conn->use_cached_ipv4_answers)
 +    if (conn->entry_cfg.use_cached_ipv4_answers)
        rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
 -    if (conn->use_cached_ipv6_answers)
 +    if (conn->entry_cfg.use_cached_ipv6_answers)
        rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
      if (addressmap_rewrite(socks->address, sizeof(socks->address),
-                            rewrite_flags, &map_expires, &exit_source)) {
+                         rewrite_flags, &out->map_expires, &exit_source2)) {
        control_event_stream_status(conn, STREAM_EVENT_REMAP,
                                    REMAP_STREAM_SOURCE_CACHE);
      }
@@@ -1234,9 -1361,13 +1361,14 @@@ connection_ap_handshake_rewrite_and_att
          tor_addr_t addr;
          /* XXX Duplicate call to tor_addr_parse. */
          if (tor_addr_parse(&addr, socks->address) >= 0) {
+           /* If we reach this point, it's an IPv4 or an IPv6 address. */
            sa_family_t family = tor_addr_family(&addr);
+ 
 -          if ((family == AF_INET && ! conn->ipv4_traffic_ok) ||
 -              (family == AF_INET6 && ! conn->ipv4_traffic_ok)) {
++          /* XXXX bug: the second one should be "ipv6_traffic" */
 +          if ((family == AF_INET && ! conn->entry_cfg.ipv4_traffic) ||
 +              (family == AF_INET6 && ! conn->entry_cfg.ipv4_traffic)) {
+             /* You can't do an IPv4 address on a v6-only socks listener,
+              * or vice versa. */
              log_warn(LD_NET, "Rejecting SOCKS request for an IP address "
                       "family that this listener does not support.");
              connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
@@@ -1245,22 -1378,32 +1379,32 @@@
              log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address.");
              connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
              return -1;
 -          } else if (socks->socks_version == 4 && !conn->ipv4_traffic_ok) {
 +          } else if (socks->socks_version == 4 && !conn->entry_cfg.ipv4_traffic) {
+             /* You can't do any kind of Socks4 request when IPv4 is forbidden.
+              *
+              * XXX raise this check outside the enclosing block? */
              log_warn(LD_NET, "Rejecting SOCKS4 request on a listener with "
                       "no IPv4 traffic supported.");
              connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
              return -1;
            } else if (family == AF_INET6) {
+             /* Tell the exit: we won't accept any ipv4 connection to an IPv6
+              * address. */
 -            conn->ipv4_traffic_ok = 0;
 +            conn->entry_cfg.ipv4_traffic = 0;
            } else if (family == AF_INET) {
+             /* Tell the exit: we won't accept any ipv6 connection to an IPv4
+              * address. */
 -            conn->ipv6_traffic_ok = 0;
 +            conn->entry_cfg.ipv6_traffic = 0;
            }
          }
        }
  
        if (socks->socks_version == 4)
 -        conn->ipv6_traffic_ok = 0;
 +        conn->entry_cfg.ipv6_traffic = 0;
  
+       /* Still handling CONNECT. Now, check for exit enclaves.  (Which we
+        * don't do on BEGINDIR, or there is a chosen exit.)
+        */
        if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
          /* see if we can find a suitable enclave exit */
          const node_t *r =
diff --cc src/test/test_entryconn.c
index 0000000,4c14ede..146cddc
mode 000000,100644..100644
--- a/src/test/test_entryconn.c
+++ b/src/test/test_entryconn.c
@@@ -1,0 -1,770 +1,770 @@@
+ /* Copyright (c) 2014-2015, The Tor Project, Inc. */
+ /* See LICENSE for licensing information */
+ 
+ #include "orconfig.h"
+ 
+ #define CONNECTION_PRIVATE
+ #define CONNECTION_EDGE_PRIVATE
+ 
+ #include "or.h"
+ #include "test.h"
+ 
+ #include "addressmap.h"
+ #include "config.h"
+ #include "confparse.h"
+ #include "connection.h"
+ #include "connection_edge.h"
+ 
+ static void *
+ entryconn_rewrite_setup(const struct testcase_t *tc)
+ {
+   (void)tc;
+   entry_connection_t *ec = entry_connection_new(CONN_TYPE_AP, AF_INET);
+   addressmap_init();
+   return ec;
+ }
+ 
+ static int
+ entryconn_rewrite_teardown(const struct testcase_t *tc, void *arg)
+ {
+   (void)tc;
+   entry_connection_t *ec = arg;
+   if (ec)
+     connection_free_(ENTRY_TO_CONN(ec));
+   addressmap_free_all();
+   return 1;
+ }
+ 
+ static struct testcase_setup_t test_rewrite_setup = {
+   entryconn_rewrite_setup, entryconn_rewrite_teardown
+ };
+ 
+ /* Simple rewrite: no changes needed */
+ static void
+ test_entryconn_rewrite_basic(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   rewrite_result_t rr;
+ 
+   tt_assert(ec->socks_request);
+   strlcpy(ec->socks_request->address, "www.TORproject.org",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.torproject.org");
+   tt_str_op(ec->socks_request->address, OP_EQ, "www.torproject.org");
+   tt_str_op(ec->original_dest_address, OP_EQ, "www.torproject.org");
+ 
+  done:
+   ;
+ }
+ 
+ /* Rewrite but reject because of disallowed .exit */
+ static void
+ test_entryconn_rewrite_bad_dotexit(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   rewrite_result_t rr;
+ 
+   get_options_mutable()->AllowDotExit = 0;
+   tt_assert(ec->socks_request);
+   strlcpy(ec->socks_request->address, "www.TORproject.org.foo.exit",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.should_close, OP_EQ, 1);
+   tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_TORPROTOCOL);
+ 
+  done:
+   ;
+ }
+ 
+ /* Automap on resolve, connect to automapped address, resolve again and get
+  * same answer. (IPv4) */
+ static void
+ test_entryconn_rewrite_automap_ipv4(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   entry_connection_t *ec2=NULL, *ec3=NULL;
+   rewrite_result_t rr;
+   char *msg = NULL;
+ 
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+   ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ 
+   get_options_mutable()->AutomapHostsOnResolve = 1;
+   smartlist_add(get_options_mutable()->AutomapHostsSuffixes, tor_strdup("."));
+   parse_virtual_addr_network("127.202.0.0/16", AF_INET, 0, &msg);
+ 
+   /* Automap this on resolve. */
+   strlcpy(ec->socks_request->address, "WWW.MIT.EDU",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 1);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu");
+   tt_str_op(ec->original_dest_address, OP_EQ, "www.mit.edu");
+ 
+   tt_assert(!strcmpstart(ec->socks_request->address,"127.202."));
+ 
+   /* Connect to it and make sure we get the original address back. */
+   strlcpy(ec2->socks_request->address, ec->socks_request->address,
+           sizeof(ec2->socks_request->address));
+ 
+   ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec2, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address);
+   tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address);
+   tt_str_op(ec2->socks_request->address, OP_EQ, "www.mit.edu");
+ 
+   /* Resolve it again, make sure the answer is the same. */
+   strlcpy(ec3->socks_request->address, "www.MIT.EDU",
+           sizeof(ec3->socks_request->address));
+   ec3->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec3, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 1);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu");
+   tt_str_op(ec3->original_dest_address, OP_EQ, "www.mit.edu");
+ 
+   tt_str_op(ec3->socks_request->address, OP_EQ,
+             ec->socks_request->address);
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec2));
+   connection_free_(ENTRY_TO_CONN(ec3));
+ }
+ 
+ /* Automap on resolve, connect to automapped address, resolve again and get
+  * same answer. (IPv6) */
+ static void
+ test_entryconn_rewrite_automap_ipv6(void *arg)
+ {
+   (void)arg;
+   entry_connection_t *ec =NULL;
+   entry_connection_t *ec2=NULL, *ec3=NULL;
+   rewrite_result_t rr;
+   char *msg = NULL;
+ 
+   ec = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+   ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+ 
+   get_options_mutable()->AutomapHostsOnResolve = 1;
+   smartlist_add(get_options_mutable()->AutomapHostsSuffixes, tor_strdup("."));
+   parse_virtual_addr_network("FE80::/32", AF_INET6, 0, &msg);
+ 
+   /* Automap this on resolve. */
+   strlcpy(ec->socks_request->address, "WWW.MIT.EDU",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 1);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu");
+   tt_str_op(ec->original_dest_address, OP_EQ, "www.mit.edu");
+ 
+   /* Yes, this [ should be here. */
+   tt_assert(!strcmpstart(ec->socks_request->address,"[fe80:"));
+ 
+   /* Connect to it and make sure we get the original address back. */
+   strlcpy(ec2->socks_request->address, ec->socks_request->address,
+           sizeof(ec2->socks_request->address));
+ 
+   ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec2, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address);
+   tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address);
+   tt_str_op(ec2->socks_request->address, OP_EQ, "www.mit.edu");
+ 
+   /* Resolve it again, make sure the answer is the same. */
+   strlcpy(ec3->socks_request->address, "www.MIT.EDU",
+           sizeof(ec3->socks_request->address));
+   ec3->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec3, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 1);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu");
+   tt_str_op(ec3->original_dest_address, OP_EQ, "www.mit.edu");
+ 
+   tt_str_op(ec3->socks_request->address, OP_EQ,
+             ec->socks_request->address);
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec));
+   connection_free_(ENTRY_TO_CONN(ec2));
+   connection_free_(ENTRY_TO_CONN(ec3));
+ }
+ 
+ #if 0
+ /* FFFF not actually supported. */
+ /* automap on resolve, reverse lookup. */
+ static void
+ test_entryconn_rewrite_automap_reverse(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   entry_connection_t *ec2=NULL;
+   rewrite_result_t rr;
+   char *msg = NULL;
+ 
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ 
+   get_options_mutable()->AutomapHostsOnResolve = 1;
+   get_options_mutable()->SafeLogging_ = SAFELOG_SCRUB_NONE;
+   smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+                 tor_strdup(".bloom"));
+   parse_virtual_addr_network("127.80.0.0/16", AF_INET, 0, &msg);
+ 
+   /* Automap this on resolve. */
+   strlcpy(ec->socks_request->address, "www.poldy.BLOOM",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 1);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.poldy.bloom");
+   tt_str_op(ec->original_dest_address, OP_EQ, "www.poldy.bloom");
+ 
+   tt_assert(!strcmpstart(ec->socks_request->address,"127.80."));
+ 
+   strlcpy(ec2->socks_request->address, ec->socks_request->address,
+           sizeof(ec2->socks_request->address));
 -  ec2->use_cached_ipv4_answers = 1; // XXXX REMOVE.  This is only there to hide a bug.
++  ec2->entry_cfg.use_cached_ipv4_answers = 1; // XXXX REMOVE.  This is only there to hide a bug.
+   ec2->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
+   connection_ap_handshake_rewrite(ec2, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 1);
+   tt_int_op(rr.end_reason, OP_EQ,
+           END_STREAM_REASON_DONE|END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec2));
+ }
+ #endif
+ 
+ /* Rewrite because of cached DNS entry. */
+ static void
+ test_entryconn_rewrite_cached_dns_ipv4(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   rewrite_result_t rr;
+   time_t expires = time(NULL) + 3600;
+   entry_connection_t *ec2=NULL;
+ 
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ 
+   addressmap_register("www.friendly.example.com",
+                       tor_strdup("240.240.241.241"),
+                       expires,
+                       ADDRMAPSRC_DNS,
+                       0, 0);
+ 
+   strlcpy(ec->socks_request->address, "www.friendly.example.com",
+           sizeof(ec->socks_request->address));
+   strlcpy(ec2->socks_request->address, "www.friendly.example.com",
+           sizeof(ec2->socks_request->address));
+ 
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+ 
 -  ec2->use_cached_ipv4_answers = 1; /* only ec2 gets this flag */
++  ec2->entry_cfg.use_cached_ipv4_answers = 1; /* only ec2 gets this flag */
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com");
+   tt_str_op(ec->socks_request->address, OP_EQ, "www.friendly.example.com");
+ 
+   connection_ap_handshake_rewrite(ec2, &rr);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, expires);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com");
+   tt_str_op(ec2->socks_request->address, OP_EQ, "240.240.241.241");
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec2));
+ }
+ 
+ /* Rewrite because of cached DNS entry. */
+ static void
+ test_entryconn_rewrite_cached_dns_ipv6(void *arg)
+ {
+   entry_connection_t *ec = NULL;
+   rewrite_result_t rr;
+   time_t expires = time(NULL) + 3600;
+   entry_connection_t *ec2=NULL;
+ 
+   (void)arg;
+ 
+   ec  = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+ 
+   addressmap_register("www.friendly.example.com",
+                       tor_strdup("[::f00f]"),
+                       expires,
+                       ADDRMAPSRC_DNS,
+                       0, 0);
+ 
+   strlcpy(ec->socks_request->address, "www.friendly.example.com",
+           sizeof(ec->socks_request->address));
+   strlcpy(ec2->socks_request->address, "www.friendly.example.com",
+           sizeof(ec2->socks_request->address));
+ 
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+ 
 -  ec2->use_cached_ipv6_answers = 1; /* only ec2 gets this flag */
++  ec2->entry_cfg.use_cached_ipv6_answers = 1; /* only ec2 gets this flag */
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com");
+   tt_str_op(ec->socks_request->address, OP_EQ, "www.friendly.example.com");
+ 
+   connection_ap_handshake_rewrite(ec2, &rr);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, expires);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com");
+   tt_str_op(ec2->socks_request->address, OP_EQ, "[::f00f]");
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec));
+   connection_free_(ENTRY_TO_CONN(ec2));
+ }
+ 
+ /* Fail to connect to unmapped address in virtual range. */
+ static void
+ test_entryconn_rewrite_unmapped_virtual(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   rewrite_result_t rr;
+   entry_connection_t *ec2 = NULL;
+   char *msg = NULL;
+ 
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+ 
+   parse_virtual_addr_network("18.202.0.0/16", AF_INET, 0, &msg);
+   parse_virtual_addr_network("[ABCD::]/16", AF_INET6, 0, &msg);
+ 
+   strlcpy(ec->socks_request->address, "18.202.5.5",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.should_close, OP_EQ, 1);
+   tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_INTERNAL);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ 
+   strlcpy(ec2->socks_request->address, "[ABCD:9::5314:9543]",
+           sizeof(ec2->socks_request->address));
+   ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec2, &rr);
+ 
+   tt_int_op(rr.should_close, OP_EQ, 1);
+   tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_INTERNAL);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec2));
+ }
+ 
+ /* Rewrite because of mapaddress option */
+ static void
+ test_entryconn_rewrite_mapaddress(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   rewrite_result_t rr;
+ 
+   config_line_append(&get_options_mutable()->AddressMap,
+                      "MapAddress", "meta metaobjects.example");
+   config_register_addressmaps(get_options());
+ 
+   strlcpy(ec->socks_request->address, "meta",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(ec->socks_request->address, OP_EQ, "metaobjects.example");
+ 
+  done:
+   ;
+ }
+ 
+ /* Reject reverse lookups of internal address. */
+ static void
+ test_entryconn_rewrite_reject_internal_reverse(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   rewrite_result_t rr;
+ 
+   strlcpy(ec->socks_request->address, "10.0.0.1",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.should_close, OP_EQ, 1);
+   tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_SOCKSPROTOCOL |
+             END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ 
+  done:
+   ;
+ }
+ 
+ /* Rewrite into .exit because of virtual address mapping */
+ static void
+ test_entryconn_rewrite_automap_exit(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   entry_connection_t *ec2=NULL;
+   rewrite_result_t rr;
+   char *msg = NULL;
+ 
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ 
+   get_options_mutable()->AutomapHostsOnResolve = 1;
+   get_options_mutable()->AllowDotExit = 1;
+   smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+                 tor_strdup(".EXIT"));
+   parse_virtual_addr_network("127.1.0.0/16", AF_INET, 0, &msg);
+ 
+   /* Automap this on resolve. */
+   strlcpy(ec->socks_request->address, "website.example.exit",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 1);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "website.example.exit");
+   tt_str_op(ec->original_dest_address, OP_EQ, "website.example.exit");
+ 
+   tt_assert(!strcmpstart(ec->socks_request->address,"127.1."));
+ 
+   /* Connect to it and make sure we get the original address back. */
+   strlcpy(ec2->socks_request->address, ec->socks_request->address,
+           sizeof(ec2->socks_request->address));
+ 
+   ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec2, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_AUTOMAP);
+   tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address);
+   tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address);
+   tt_str_op(ec2->socks_request->address, OP_EQ, "website.example.exit");
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec2));
+ }
+ 
+ /* Rewrite into .exit because of mapaddress */
+ static void
+ test_entryconn_rewrite_mapaddress_exit(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   rewrite_result_t rr;
+ 
+   config_line_append(&get_options_mutable()->AddressMap,
+                      "MapAddress", "*.example.com  *.example.com.abc.exit");
+   config_register_addressmaps(get_options());
+ 
+   /* Automap this on resolve. */
+   strlcpy(ec->socks_request->address, "abc.example.com",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_TORRC);
+   tt_str_op(rr.orig_address, OP_EQ, "abc.example.com");
+   tt_str_op(ec->socks_request->address, OP_EQ, "abc.example.com.abc.exit");
+  done:
+   ;
+ }
+ 
+ /* Map foo.onion to longthing.onion, and also automap. */
+ static void
+ test_entryconn_rewrite_mapaddress_automap_onion(void *arg)
+ {
+   entry_connection_t *ec = arg;
+   entry_connection_t *ec2 = NULL;
+   entry_connection_t *ec3 = NULL;
+   entry_connection_t *ec4 = NULL;
+   rewrite_result_t rr;
+   char *msg = NULL;
+ 
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+   ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+   ec4 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ 
+   get_options_mutable()->AutomapHostsOnResolve = 1;
+   get_options_mutable()->AllowDotExit = 1;
+   smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+                 tor_strdup(".onion"));
+   parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
+   config_line_append(&get_options_mutable()->AddressMap,
+                      "MapAddress", "foo.onion abcdefghijklmnop.onion");
+   config_register_addressmaps(get_options());
+ 
+   /* Connect to foo.onion. */
+   strlcpy(ec->socks_request->address, "foo.onion",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "foo.onion");
+   tt_str_op(ec->socks_request->address, OP_EQ, "abcdefghijklmnop.onion");
+ 
+   /* Okay, resolve foo.onion */
+   strlcpy(ec2->socks_request->address, "foo.onion",
+           sizeof(ec2->socks_request->address));
+   ec2->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec2, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 1);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "foo.onion");
+   tt_assert(!strcmpstart(ec2->socks_request->address, "192.168."));
+ 
+   /* Now connect */
+   strlcpy(ec3->socks_request->address, ec2->socks_request->address,
+           sizeof(ec3->socks_request->address));
+   ec3->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec3, &rr);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_assert(!strcmpstart(ec3->socks_request->address, "abcdefghijklmnop.onion"));
+ 
+   /* Now resolve abcefghijklmnop.onion. */
+   strlcpy(ec4->socks_request->address, "abcdefghijklmnop.onion",
+           sizeof(ec4->socks_request->address));
+   ec4->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec4, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 1);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "abcdefghijklmnop.onion");
+   tt_assert(!strcmpstart(ec4->socks_request->address, "192.168."));
+   /* XXXX doesn't work
+      tt_str_op(ec4->socks_request->address, OP_EQ, ec2->socks_request->address);
+   */
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec2));
+   connection_free_(ENTRY_TO_CONN(ec3));
+   connection_free_(ENTRY_TO_CONN(ec4));
+ }
+ 
+ static void
+ test_entryconn_rewrite_mapaddress_automap_onion_common(entry_connection_t *ec,
+                                                        int map_to_onion,
+                                                        int map_to_address)
+ {
+   entry_connection_t *ec2 = NULL;
+   entry_connection_t *ec3 = NULL;
+   rewrite_result_t rr;
+ 
+   ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+   ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ 
+   /* Connect to irc.example.com */
+   strlcpy(ec->socks_request->address, "irc.example.com",
+           sizeof(ec->socks_request->address));
+   ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "irc.example.com");
+   tt_str_op(ec->socks_request->address, OP_EQ,
+             map_to_onion ? "abcdefghijklmnop.onion" : "irc.example.com");
+ 
+   /* Okay, resolve irc.example.com */
+   strlcpy(ec2->socks_request->address, "irc.example.com",
+           sizeof(ec2->socks_request->address));
+   ec2->socks_request->command = SOCKS_COMMAND_RESOLVE;
+   connection_ap_handshake_rewrite(ec2, &rr);
+ 
+   tt_int_op(rr.automap, OP_EQ, map_to_onion && map_to_address);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+   tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+   tt_str_op(rr.orig_address, OP_EQ, "irc.example.com");
+   if (map_to_onion && map_to_address)
+     tt_assert(!strcmpstart(ec2->socks_request->address, "192.168."));
+ 
+   /* Now connect */
+   strlcpy(ec3->socks_request->address, ec2->socks_request->address,
+           sizeof(ec3->socks_request->address));
+   ec3->socks_request->command = SOCKS_COMMAND_CONNECT;
+   connection_ap_handshake_rewrite(ec3, &rr);
+   tt_int_op(rr.automap, OP_EQ, 0);
+   tt_int_op(rr.should_close, OP_EQ, 0);
+   tt_int_op(rr.end_reason, OP_EQ, 0);
+   if (map_to_onion)
+     tt_assert(!strcmpstart(ec3->socks_request->address,
+                            "abcdefghijklmnop.onion"));
+ 
+  done:
+   connection_free_(ENTRY_TO_CONN(ec2));
+   connection_free_(ENTRY_TO_CONN(ec3));
+ }
+ 
+ /* This time is the same, but we start with a mapping from a non-onion
+  * address. */
+ static void
+ test_entryconn_rewrite_mapaddress_automap_onion2(void *arg)
+ {
+   char *msg = NULL;
+   get_options_mutable()->AutomapHostsOnResolve = 1;
+   smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+                 tor_strdup(".onion"));
+   parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
+   config_line_append(&get_options_mutable()->AddressMap,
+                      "MapAddress", "irc.example.com abcdefghijklmnop.onion");
+   config_register_addressmaps(get_options());
+ 
+   test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 1, 1);
+ }
+ 
+ /* Same as above, with automapped turned off */
+ static void
+ test_entryconn_rewrite_mapaddress_automap_onion3(void *arg)
+ {
+   config_line_append(&get_options_mutable()->AddressMap,
+                      "MapAddress", "irc.example.com abcdefghijklmnop.onion");
+   config_register_addressmaps(get_options());
+ 
+   test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 1, 0);
+ }
+ 
+ /* As above, with no mapping. */
+ static void
+ test_entryconn_rewrite_mapaddress_automap_onion4(void *arg)
+ {
+   char *msg = NULL;
+   get_options_mutable()->AutomapHostsOnResolve = 1;
+   smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+                 tor_strdup(".onion"));
+   parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
+ 
+   test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 0, 1);
+ }
+ 
+ 
+ #define REWRITE(name)                           \
+   { #name, test_entryconn_##name, TT_FORK, &test_rewrite_setup, NULL }
+ 
+ struct testcase_t entryconn_tests[] = {
+   REWRITE(rewrite_basic),
+   REWRITE(rewrite_bad_dotexit),
+   REWRITE(rewrite_automap_ipv4),
+   REWRITE(rewrite_automap_ipv6),
+   // REWRITE(rewrite_automap_reverse),
+   REWRITE(rewrite_cached_dns_ipv4),
+   REWRITE(rewrite_cached_dns_ipv6),
+   REWRITE(rewrite_unmapped_virtual),
+   REWRITE(rewrite_mapaddress),
+   REWRITE(rewrite_reject_internal_reverse),
+   REWRITE(rewrite_automap_exit),
+   REWRITE(rewrite_mapaddress_exit),
+   REWRITE(rewrite_mapaddress_automap_onion),
+   REWRITE(rewrite_mapaddress_automap_onion2),
+   REWRITE(rewrite_mapaddress_automap_onion3),
+   REWRITE(rewrite_mapaddress_automap_onion4),
+ 
+   END_OF_TESTCASES
+ };
+ 



More information about the tor-commits mailing list