[tor-commits] [flashproxy/master] split name-resolution behaviour out of parse_addr_spec to match flashproxy-common

infinity0 at torproject.org infinity0 at torproject.org
Thu Nov 21 13:18:47 UTC 2013


commit d3e27be5f375a80917c84e0881aa5c78bfd3d1f1
Author: Ximin Luo <infinity0 at gmx.com>
Date:   Mon Nov 18 19:15:29 2013 +0000

    split name-resolution behaviour out of parse_addr_spec to match flashproxy-common
    - keep named relays as names rather than numeric addresses
---
 facilitator/fac.py                   |   38 +++++++++++++++++++---------------
 facilitator/facilitator              |    4 ++--
 facilitator/facilitator-email-poller |    2 +-
 facilitator/facilitator-test.py      |   11 +++-------
 4 files changed, 27 insertions(+), 28 deletions(-)

diff --git a/facilitator/fac.py b/facilitator/fac.py
index f5649b3..00c103c 100644
--- a/facilitator/fac.py
+++ b/facilitator/fac.py
@@ -50,7 +50,7 @@ def catch_epipe(fn):
                 raise
     return ret
 
-def parse_addr_spec(spec, defhost = None, defport = None, resolve = False, nameOk = False):
+def parse_addr_spec(spec, defhost = None, defport = None):
     """Parse a host:port specification and return a 2-tuple ("host", port) as
     understood by the Python socket functions.
     >>> parse_addr_spec("192.168.0.1:9999")
@@ -70,11 +70,6 @@ def parse_addr_spec(spec, defhost = None, defport = None, resolve = False, nameO
     ('192.168.0.1', 9999)
     >>> parse_addr_spec("", defhost="192.168.0.1", defport=9999)
     ('192.168.0.1', 9999)
-
-    If nameOk is true, then the host in the specification or the defhost may be
-    a domain name. Otherwise, it must be a numeric IPv4 or IPv6 address.
-    If resolve is true, this implies nameOk, and the host will be resolved.
-
     IPv6 addresses must be enclosed in square brackets."""
     host = None
     port = None
@@ -105,19 +100,24 @@ def parse_addr_spec(spec, defhost = None, defport = None, resolve = False, nameO
     port = port or defport
     if host is None or port is None:
         raise ValueError("Bad address specification \"%s\"" % spec)
+    return host, int(port)
+
+def resolve_to_ip(host, port, af=0, gai_flags=0):
+    """Resolves a host string to an IP address in canonical format.
+
+    Note: in many cases this is not necessary since the consumer of the address
+    can probably accept host names directly.
 
-    # Now we have split around the colon and have a guess at the address family.
+    :param: host string to resolve; may be a DNS name or an IP address.
+    :param: port of the host
+    :param: af address family, default unspecified. set to socket.AF_INET or
+        socket.AF_INET6 to force IPv4 or IPv6 name resolution.
+    :returns: (IP address in canonical format, port)
+    """
     # Forward-resolve the name into an addrinfo struct. Real DNS resolution is
     # done only if resolve is true; otherwise the address must be numeric.
-    if resolve:
-        flags = 0
-    elif nameOk:
-        # don't pass through the getaddrinfo numeric check, just return directly
-        return host, int(port)
-    else:
-        flags = socket.AI_NUMERICHOST
     try:
-        addrs = socket.getaddrinfo(host, port, af, socket.SOCK_STREAM, socket.IPPROTO_TCP, flags)
+        addrs = socket.getaddrinfo(host, port, af, 0, 0, gai_flags)
     except socket.gaierror, e:
         raise ValueError("Bad host or port: \"%s\" \"%s\": %s" % (host, port, str(e)))
     if not addrs:
@@ -126,8 +126,12 @@ def parse_addr_spec(spec, defhost = None, defport = None, resolve = False, nameO
     # Convert the result of socket.getaddrinfo (which is a 2-tuple for IPv4 and
     # a 4-tuple for IPv6) into a (host, port) 2-tuple.
     host, port = socket.getnameinfo(addrs[0][4], socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
-    port = int(port)
-    return host, port
+    return host, int(port)
+
+def canonical_ip(host, port, af=0):
+    """Convert an IP address to a canonical format. Identical to resolve_to_ip,
+    except that the host param must already be an IP address."""
+    return resolve_to_ip(host, port, af, gai_flags=socket.AI_NUMERICHOST)
 
 def format_addr(addr):
     host, port = addr
diff --git a/facilitator/facilitator b/facilitator/facilitator
index 9d90833..a2dd56a 100755
--- a/facilitator/facilitator
+++ b/facilitator/facilitator
@@ -290,7 +290,7 @@ class Handler(SocketServer.StreamRequestHandler):
         if proxy_spec is None:
             return self.error(u"GET missing FROM param")
         try:
-            proxy_addr = fac.parse_addr_spec(proxy_spec, defport=0)
+            proxy_addr = fac.canonical_ip(*fac.parse_addr_spec(proxy_spec, defport=0))
         except ValueError, e:
             return self.error(u"syntax error in proxy address %s: %s" % (safe_str(repr(proxy_spec)), safe_str(repr(str(e)))))
 
@@ -422,7 +422,7 @@ def parse_relay_file(servers, fp):
             transport_spec, addr_spec = line.strip().split()
         except ValueError, e:
             raise ValueError("Wrong line format: %s." % repr(line))
-        addr = fac.parse_addr_spec(addr_spec, defport=DEFAULT_RELAY_PORT, resolve=True)
+        addr = fac.parse_addr_spec(addr_spec, defport=DEFAULT_RELAY_PORT)
         transport = Transport.parse(transport_spec)
         if transport.outer not in options.outer_transports:
             raise ValueError(u"Unrecognized transport: %s" % transport)
diff --git a/facilitator/facilitator-email-poller b/facilitator/facilitator-email-poller
index f087507..2efceec 100755
--- a/facilitator/facilitator-email-poller
+++ b/facilitator/facilitator-email-poller
@@ -222,7 +222,7 @@ try:
             raise ValueError("could not find email or password on line %s" % (lineno0+1))
         (imap_addr_spec, email_addr, email_password) = res.groups()
         imap_addr = fac.parse_addr_spec(
-            imap_addr_spec or "", DEFAULT_IMAP_HOST, DEFAULT_IMAP_PORT, nameOk=True)
+            imap_addr_spec or "", DEFAULT_IMAP_HOST, DEFAULT_IMAP_PORT)
         break
     else:
         raise ValueError("no email line found")
diff --git a/facilitator/facilitator-test.py b/facilitator/facilitator-test.py
index 3a960fe..d63e0b5 100755
--- a/facilitator/facilitator-test.py
+++ b/facilitator/facilitator-test.py
@@ -346,14 +346,9 @@ class ParseAddrSpecTest(unittest.TestCase):
         self.assertEqual(fac.parse_addr_spec(":", defhost="1234::1", defport=9999), ("1234::1", 9999))
         self.assertEqual(fac.parse_addr_spec("", defhost="1234::1", defport=9999), ("1234::1", 9999))
 
-    def test_noresolve(self):
-        """Test that parse_addr_spec does not do DNS resolution by default."""
-        self.assertRaises(ValueError, fac.parse_addr_spec, "example.com")
-
-    def test_noresolve_nameok(self):
-        """Test that nameok passes through a domain name without resolving it."""
-        self.assertEqual(fac.parse_addr_spec("example.com:8888", defhost="other.com", defport=9999, nameOk=True), ("example.com", 8888))
-        self.assertEqual(fac.parse_addr_spec("", defhost="other.com", defport=9999, nameOk=True), ("other.com", 9999))
+    def test_canonical_ip_noresolve(self):
+        """Test that canonical_ip does not do DNS resolution by default."""
+        self.assertRaises(ValueError, fac.canonical_ip, *fac.parse_addr_spec("example.com:80"))
 
 class ParseTransactionTest(unittest.TestCase):
     def test_empty_string(self):





More information about the tor-commits mailing list