Browse Source

Add IPv6 client support to chutney

This adds the following flavours:
 * client-ipv6-only: test that an IPv6 client can bootstrap and transmit data
 * hs-client-ipv6: test that an IPv6 client can connect to an IPv4 HS
 * hs-ipv6: test that IPv4 and IPv6 clients can connect to an IPv6 HS

It also adds support for IPv6 hidden services, relays, and authorities.
teor 6 years ago
parent
commit
696a55c0e2

+ 12 - 7
README

@@ -44,6 +44,10 @@ Traffic Options:
   --connections      CHUTNEY_CONNECTIONS
   --hs-multi-client  CHUTNEY_HS_MULTI_CLIENT
 
+Address Options:
+  --ipv4             CHUTNEY_LISTEN_ADDRESS
+  --ipv6             CHUTNEY_LISTEN_ADDRESS_V6
+
 Standard Actions:
   ./chutney configure networks/basic
   ./chutney start networks/basic
@@ -108,14 +112,15 @@ Waiting for the network:
 
 Changing the network address:
 
-   Chutney defaults to binding to localhost. To change the bind address,
-   set the CHUTNEY_LISTEN_ADDRESS environment variable. Setting it to some
-   interface's IP address allows us to make the simulated Tor network
-   available on the network.
+   Chutney defaults to binding to localhost. To change the IPv4 bind address,
+   set the CHUTNEY_LISTEN_ADDRESS environment variable. Similarly, change
+   CHUTNEY_LISTEN_ADDRESS_V6 for IPv6: it defaults to "no IPv6 address".
+   Setting it to some interface's IP address allows us to make the simulated
+   Tor network available on the network.
 
-   IPv6 support for both Tor and Chutney is a work in progress. If your system
-   returns IPv6 ::1 as the (first) address for localhost, you might need to
-   set CHUTNEY_LISTEN_ADDRESS="127.0.0.1" for chutney to work.
+   IPv6 support for both Tor and Chutney is a work in progress. Currently,
+   chutney verifies IPv6 client, bridge client, and hidden service
+   connections. It does not use IPv6 SOCKSPort or Exit traffic.
 
 The configuration files:
   networks/basic holds the configuration for the network you're configuring

+ 14 - 6
lib/chutney/TorNet.py

@@ -206,9 +206,9 @@ class LocalNodeBuilder(NodeBuilder):
     # tor_gencert -- path to tor_gencert binary
     # tor -- path to tor binary
     # auth_cert_lifetime -- lifetime of authority certs, in months.
-    # ip -- IP to listen on (used only if authority or bridge)
-    # ipv6_addr -- IPv6 address to listen on (used only if ipv6 bridge)
-    # orport, dirport -- (used only if authority)
+    # ip -- IP to listen on
+    # ipv6_addr -- IPv6 address to listen on
+    # orport, dirport -- used on authorities, relays, and bridges
     # fingerprint -- used only if authority
     # dirserver_flags -- used only if authority
     # nick -- nickname of this router
@@ -461,8 +461,14 @@ class LocalNodeBuilder(NodeBuilder):
 
         authlines = ""
         for authopt in options:
-            authlines += "%s %s orport=%s %s %s:%s %s\n" % (
-                authopt, self._env['nick'], self._env['orport'],
+            authlines += "%s %s orport=%s" % (
+                authopt, self._env['nick'], self._env['orport'])
+            # It's ok to give an authority's IPv6 address to an IPv4-only
+            # client or relay: it will and must ignore it
+            if self._env['ipv6_addr'] is not None:
+                authlines += " ipv6=%s:%s" % (self._env['ipv6_addr'],
+                                              self._env['orport'])
+            authlines += " %s %s:%s %s\n" % (
                 self._env['dirserver_flags'], self._env['ip'],
                 self._env['dirport'], self._env['fingerprint'])
         return authlines
@@ -675,7 +681,9 @@ DEFAULTS = {
     'tor-gencert': os.environ.get('CHUTNEY_TOR_GENCERT', None),
     'auth_cert_lifetime': 12,
     'ip': os.environ.get('CHUTNEY_LISTEN_ADDRESS', '127.0.0.1'),
-    'ipv6_addr': None,
+    # Pre-0.2.8 clients will fail to parse ipv6 auth lines,
+    # so we default to ipv6_addr None
+    'ipv6_addr': os.environ.get('CHUTNEY_LISTEN_ADDRESS_V6', None),
     'dirserver_flags': 'no-v2',
     'chutney_dir': '.',
     'torrc_fname': '${dir}/torrc',

+ 20 - 0
networks/client-ipv6-only

@@ -0,0 +1,20 @@
+import os
+# By default, Authorities are not configured as exits
+Authority6 = Node(tag="a", authority=1, relay=1,
+                  ipv6_addr=os.environ.get('CHUTNEY_LISTEN_ADDRESS_V6',
+                                           '[::1]'),
+                  torrc="authority-orport-v6.tmpl")
+ExitRelay6 = Node(tag="r", relay=1, exit=1,
+                  ipv6_addr=os.environ.get('CHUTNEY_LISTEN_ADDRESS_V6',
+                                           '[::1]'),
+                  torrc="relay-orport-v6-exit.tmpl")
+Client6 = Node(tag="c", torrc="client-only-v6.tmpl")
+
+# Since only 25% of relays get the guard flag,
+# TestingDirAuthVoteGuard * may need to be used in small networks
+
+# The minimum number of authorities/relays/exits is 3, the minimum path length
+# But for some reason, Tor wants 4 "acceptable routers" (Tor bug #20071)
+NODES = Authority6.getN(3) + ExitRelay6.getN(1) + Client6.getN(1)
+
+ConfigureNodes(NODES)

+ 24 - 0
networks/hs-client-ipv6

@@ -0,0 +1,24 @@
+import os
+# By default, Authorities are not configured as exits
+Authority6 = Node(tag="a", authority=1, relay=1,
+                  ipv6_addr=os.environ.get('CHUTNEY_LISTEN_ADDRESS_V6',
+                                           '[::1]'),
+                  torrc="authority-orport-v6.tmpl")
+NonExitRelay6 = Node(tag="r", relay=1,
+                     ipv6_addr=os.environ.get('CHUTNEY_LISTEN_ADDRESS_V6',
+                                              '[::1]'),
+                     torrc="relay-orport-v6-non-exit.tmpl")
+Client6 = Node(tag="c", torrc="client-only-v6.tmpl")
+HS = Node(tag="h", hs=1, torrc="hs.tmpl")
+
+# Since only 25% of relays get the guard flag,
+# TestingDirAuthVoteGuard * may need to be used in small networks
+
+# A hidden service needs 5 authorities/relays to ensure it can build HS
+# connections:
+# a minimum path length of 3, plus the client-nominated rendezvous point,
+# plus a seperate introduction point
+NODES = Authority6.getN(2) + NonExitRelay6.getN(3) + \
+        Client6.getN(1) + HS.getN(1)
+
+ConfigureNodes(NODES)

+ 25 - 0
networks/hs-ipv6

@@ -0,0 +1,25 @@
+import os
+# By default, Authorities are not configured as exits
+Authority6 = Node(tag="a", authority=1, relay=1,
+                  ipv6_addr=os.environ.get('CHUTNEY_LISTEN_ADDRESS_V6',
+                                           '[::1]'),
+                  torrc="authority-orport-v6.tmpl")
+NonExitRelay6 = Node(tag="r", relay=1,
+                     ipv6_addr=os.environ.get('CHUTNEY_LISTEN_ADDRESS_V6',
+                                              '[::1]'),
+                     torrc="relay-orport-v6-non-exit.tmpl")
+Client = Node(tag="c", torrc="client.tmpl")
+Client6 = Node(tag="c", torrc="client-only-v6.tmpl")
+HS6 = Node(tag="h", hs=1, torrc="hs.tmpl")
+
+# Since only 25% of relays get the guard flag,
+# TestingDirAuthVoteGuard * may need to be used in small networks
+
+# A hidden service needs 5 authorities/relays to ensure it can build HS
+# connections:
+# a minimum path length of 3, plus the client-nominated rendezvous point,
+# plus a seperate introduction point
+NODES = Authority6.getN(2) + NonExitRelay6.getN(3) + \
+        Client.getN(1) + Client6.getN(1) + HS6.getN(1)
+
+ConfigureNodes(NODES)

+ 10 - 0
tools/test-network.sh

@@ -73,6 +73,16 @@ do
       export CHUTNEY_HS_MULTI_CLIENT="$2"
       shift
       ;;
+    # The IPv4 address to bind to, defaults to 127.0.0.1
+    --ipv4|--v4|-4|--ip)
+      export CHUTNEY_LISTEN_ADDRESS="$2"
+      shift
+      ;;
+    # The IPv6 address to bind to, default is not to bind to an IPv6 address
+    --ipv6|--v6|-6)
+      export CHUTNEY_LISTEN_ADDRESS_V6="$2"
+      shift
+      ;;
     --coverage)
       export USE_COVERAGE_BINARY=true
       ;;

+ 7 - 0
torrc_templates/authority-orport-v6-exit.tmpl

@@ -0,0 +1,7 @@
+${include:authority-orport-v6.tmpl}
+
+# An authority that's also an exit relay that can exit to IPv4 & IPv6 localhost
+# (newer versions of tor need this to be explicitly configured)
+
+${include:exit-v4.i}
+${include:exit-v6.i}

+ 7 - 0
torrc_templates/authority-orport-v6.tmpl

@@ -0,0 +1,7 @@
+${include:authority.tmpl}
+
+# An authority that has an IPv6 ORPort
+${include:orport-v6.i}
+
+# And has IPv6 connectivity
+AuthDirHasIPv6Connectivity 1

+ 10 - 0
torrc_templates/client-only-v6.i

@@ -0,0 +1,10 @@
+# A client that only uses IPv6 ORPorts
+ClientUseIPv4 0
+# Due to Tor bug #19608, microdescriptors can't be used by IPv6-only clients
+UseMicrodescriptors 0
+
+# Previous versions of Tor did not support IPv6-only operation
+# But this is how it would have been configured
+#ClientUseIPv6 1
+#ClientPreferIPv6ORPort 1
+#ReachableAddresses reject 0.0.0.0/0, accept [::]/0

+ 2 - 0
torrc_templates/client-only-v6.tmpl

@@ -0,0 +1,2 @@
+${include:client.tmpl}
+${include:client-only-v6.i}

+ 3 - 0
torrc_templates/client-use-v6.i

@@ -0,0 +1,3 @@
+# A client that uses and prefers IPv6
+ClientUseIPv6 1
+ClientPreferIPv6ORPort 1

+ 2 - 0
torrc_templates/client-use-v6.tmpl

@@ -0,0 +1,2 @@
+${include:client.tmpl}
+${include:client-use-v6.i}

+ 3 - 0
torrc_templates/hs-only-v6.tmpl

@@ -0,0 +1,3 @@
+${include:hs.i}
+# Hidden services are just another kind of client
+${include:client-only-v6.i}

+ 3 - 0
torrc_templates/hs-use-v6.tmpl

@@ -0,0 +1,3 @@
+${include:hs.i}
+# Hidden services are just another kind of client
+${include:client-use-v6.i}

+ 4 - 0
torrc_templates/orport-v6.i

@@ -0,0 +1,4 @@
+# Tor uses the first IPv6 ORPort address as its IPv6 address
+OrPort ${ipv6_addr}:${orport} IPv6Only
+
+# IPv6 DirPorts are not needed

+ 10 - 0
torrc_templates/relay-orport-v6-exit.tmpl

@@ -0,0 +1,10 @@
+${include:relay.tmpl}
+
+# A relay that has an IPv6 ORPort
+${include:orport-v6.i}
+
+# An exit relay that can exit to IPv4 & IPv6 localhost
+# (newer versions of tor need this to be explicitly configured)
+
+${include:exit-v4.i}
+${include:exit-v6.i}

+ 4 - 0
torrc_templates/relay-orport-v6-non-exit.tmpl

@@ -0,0 +1,4 @@
+${include:relay-non-exit.tmpl}
+
+# A relay that has an IPv6 ORPort
+${include:orport-v6.i}