[tor-commits] [flashproxy/master] Listen on both IPv4 and IPv6 by default in flashproxy-client.

dcf at torproject.org dcf at torproject.org
Sun Sep 23 18:22:05 UTC 2012


commit 54c3d895d51562adc3e5b54f44daf8a070fba439
Author: David Fifield <david at bamsoftware.com>
Date:   Sun Sep 23 11:19:23 2012 -0700

    Listen on both IPv4 and IPv6 by default in flashproxy-client.
    
    If no host is given for the local address, listen on 127.0.0.1 and ::1.
    If no host is given for the remote address, listen on 0.0.0.0 and ::.
    
    This adds the ability to listen on more than one local or remote socket,
    though this is not exposed in the command-line interface except in this
    special case.
---
 README            |    2 +-
 flashproxy-client |   85 +++++++++++++++++++++++++++++++++++------------------
 2 files changed, 57 insertions(+), 30 deletions(-)

diff --git a/README b/README
index f5654cf..af19893 100644
--- a/README
+++ b/README
@@ -19,7 +19,7 @@ transport plugin" below to try out the system even behind NAT.
    9000. If you have to use a different port (to get through a firewall,
    for example), give it on the command lines like this (here using port
    8888):
-	$ flashproxy-client --register 127.0.0.1:9001 :8888
+	$ flashproxy-client --register :9001 :8888
 2. Run Tor using the included torrc file.
 	$ tor -f torrc
 
diff --git a/flashproxy-client b/flashproxy-client
index 16c95ec..cf0c0b7 100755
--- a/flashproxy-client
+++ b/flashproxy-client
@@ -29,16 +29,15 @@ try:
 except ImportError:
     numpy = None
 
-DEFAULT_REMOTE_ADDRESS = None
-DEFAULT_REMOTE_PORT = 9000
-DEFAULT_LOCAL_ADDRESS = "127.0.0.1"
 DEFAULT_LOCAL_PORT = 9001
+DEFAULT_REMOTE_PORT = 9000
 
 LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
 
 class options(object):
-    local_addr = None
-    remote_addr = None
+    local_addrs = []
+    remote_addrs = []
+    register_addr = None
     facilitator_url = None
 
     log_filename = None
@@ -57,7 +56,8 @@ def usage(f = sys.stdout):
 Usage: %(progname)s --register [LOCAL][:PORT] [REMOTE][:PORT]
 Wait for connections on a local and a remote port. When any pair of connections
 exists, data is ferried between them until one side is closed. By default
-LOCAL is "%(local)s" and REMOTE is "%(remote)s".
+LOCAL is localhost addresses on port %(local_port)d and REMOTE is all addresses
+on port %(remote_port)d.
 
 The local connection acts as a SOCKS4a proxy, but the host and port in the SOCKS
 request are ignored and the local connection is always linked to a remote
@@ -76,8 +76,8 @@ facilitator is used; if omitted, it uses a public default.
   --unsafe-logging        don't scrub IP addresses from logs.\
 """ % {
     "progname": sys.argv[0],
-    "local": format_addr((DEFAULT_LOCAL_ADDRESS, DEFAULT_LOCAL_PORT)),
-    "remote": format_addr((DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)),
+    "local_port": DEFAULT_LOCAL_PORT,
+    "remote_port": DEFAULT_REMOTE_PORT,
 }
 
 def safe_str(s):
@@ -433,10 +433,16 @@ class WebSocketBinaryEncoder(object):
 
 def listen_socket(addr):
     """Return a nonblocking socket listening on the given address."""
-    addr = (addr[0] or "0.0.0.0", addr[1])
     addrinfo = socket.getaddrinfo(addr[0], addr[1], 0, socket.SOCK_STREAM, socket.IPPROTO_TCP)[0]
     s = socket.socket(addrinfo[0], addrinfo[1], addrinfo[2])
     s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    if addrinfo[0] == socket.AF_INET6 and socket.has_ipv6:
+        # Set the IPV6_V6ONLY socket option, otherwise some operating systems
+        # will listen on an IPv4 address as well as IPv6 by default. For
+        # example, "::" will listen on both "::" and "0.0.0.0", and "::1" will
+        # listen on both "::1" and "127.0.0.1". See
+        # https://trac.torproject.org/projects/tor/ticket/4760.
+        s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
     s.bind(addr)
     s.listen(10)
     s.setblocking(0)
@@ -639,7 +645,7 @@ def register():
         # Maybe the script was read from stdin; in any case don't guess at the directory.
         return
     command = [os.path.join(script_dir, "flashproxy-reg-http")]
-    spec = format_addr(options.remote_addr)
+    spec = format_addr(options.register_addr)
     if options.facilitator_url is None:
         log(u"Registering \"%s\"." % spec)
     else:
@@ -792,14 +798,14 @@ class LocalSocket(object):
 
 def main():
     while True:
-        rset = [remote_s, local_s] + websocket_pending + socks_pending + locals + remotes
+        rset = remote_listen + local_listen + websocket_pending + socks_pending + locals + remotes
         rset, _, _ = select.select(rset, [], [], WEBSOCKET_REQUEST_TIMEOUT)
         for fd in rset:
-            if fd == remote_s:
+            if fd in remote_listen:
                 remote_c, addr = fd.accept()
                 log(u"Remote connection from %s." % safe_format_sockaddr(addr))
                 websocket_pending.append(TimeoutSocket(remote_c))
-            elif fd == local_s:
+            elif fd in local_listen:
                 local_c, addr = fd.accept()
                 log(u"Local connection from %s." % safe_format_sockaddr(addr))
                 socks_pending.append(local_c)
@@ -879,30 +885,51 @@ if __name__ == "__main__":
         elif o == "--unsafe-logging":
             options.safe_logging = False
 
+    if options.log_filename:
+        options.log_file = open(options.log_filename, "a")
+        # Send error tracebacks to the log.
+        sys.stderr = options.log_file
+    else:
+        options.log_file = sys.stdout
+
     if len(args) == 0:
-        options.local_addr = (DEFAULT_LOCAL_ADDRESS, DEFAULT_LOCAL_PORT)
-        options.remote_addr = (DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)
+        local_addr = (None, DEFAULT_LOCAL_PORT)
+        remote_addr = (None, DEFAULT_REMOTE_PORT)
     elif len(args) == 1:
-        options.local_addr = parse_addr_spec(args[0], DEFAULT_LOCAL_ADDRESS, DEFAULT_LOCAL_PORT)
-        options.remote_addr = (DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)
+        local_addr = parse_addr_spec(args[0], defport=DEFAULT_LOCAL_PORT)
+        remote_addr = (None, DEFAULT_REMOTE_PORT)
     elif len(args) == 2:
-        options.local_addr = parse_addr_spec(args[0], DEFAULT_LOCAL_ADDRESS, DEFAULT_LOCAL_PORT)
-        options.remote_addr = parse_addr_spec(args[1], DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)
+        local_addr = parse_addr_spec(args[0], defport=DEFAULT_LOCAL_PORT)
+        remote_addr = parse_addr_spec(args[1], defport=DEFAULT_REMOTE_PORT)
     else:
         usage(sys.stderr)
         sys.exit(1)
 
-    if options.log_filename:
-        options.log_file = open(options.log_filename, "a")
-        # Send error tracebacks to the log.
-        sys.stderr = options.log_file
+    # Listen on both IPv4 and IPv6 if no host is given.
+    if local_addr[0]:
+        options.local_addrs.append(local_addr)
     else:
-        options.log_file = sys.stdout
-
-    # Local socket, accepting SOCKS requests from localhost
-    local_s = listen_socket(options.local_addr)
-    # Remote socket, accepting remote WebSocket connections from proxies.
-    remote_s = listen_socket(options.remote_addr)
+        options.local_addrs.append(("127.0.0.1", local_addr[1]))
+        if socket.has_ipv6:
+            options.local_addrs.append(("::1", local_addr[1]))
+    if remote_addr[0]:
+        options.remote_addrs.append(remote_addr)
+    else:
+        options.remote_addrs.append(("0.0.0.0", remote_addr[1]))
+        if socket.has_ipv6:
+            options.remote_addrs.append(("::", remote_addr[1]))
+    options.register_addr = remote_addr
+
+    # Local sockets, accepting SOCKS requests from localhost
+    local_listen = []
+    for addr in options.local_addrs:
+        local_listen.append(listen_socket(addr))
+        log(u"Listening local on %s." % format_addr(addr))
+    # Remote sockets, accepting remote WebSocket connections from proxies.
+    remote_listen = []
+    for addr in options.remote_addrs:
+        remote_listen.append(listen_socket(addr))
+        log(u"Listening remote on %s." % format_addr(addr))
 
     # New remote sockets waiting to finish their WebSocket negotiation.
     websocket_pending = []



More information about the tor-commits mailing list