commit d3e27be5f375a80917c84e0881aa5c78bfd3d1f1 Author: Ximin Luo infinity0@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):
tor-commits@lists.torproject.org