From d33a7f336c7637f5f6b86e8be8463e180d5a729f Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Fri, 2 Sep 2005 05:23:18 +0000 Subject: [PATCH] make sending queries via IPv6 work Original author: Bob Halley Date: 2004-08-04 09:10:14 --- ChangeLog | 15 +++++++++++++++ dns/inet.py | 18 ++++++++++++++++++ dns/query.py | 54 ++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 14b81fa3..ea213482 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2004-08-04 Bob Halley + + * dns/query.py: sending queries to a nameserver via IPv6 now + works. + + * dns/inet.py (af_for_address): Add af_for_address(), which looks + at a textual-form address and attempts to determine which address + family it is. + + * dns/query.py: the default for the 'af' parameter of the udp(), + tcp(), and xfr() functions has been changed from AF_INET to None, + which causes dns.inet.af_for_address() to be used to determine the + address family. If dns.inet.af_for_address() can't figure it out, + we fall back to AF_INET and hope for the best. + 2004-07-31 Bob Halley * dns/rdtypes/ANY/NSEC.py (NSEC.from_text): The NSEC text format diff --git a/dns/inet.py b/dns/inet.py index e8e30925..c12dbbfa 100644 --- a/dns/inet.py +++ b/dns/inet.py @@ -70,3 +70,21 @@ def inet_ntop(family, address): return dns.ipv6.inet_ntoa(address) else: raise NotImplementedError + +def af_for_address(text): + """Determine the address family of a textual-form network address. + + @param text: the textual address + @type text: string + @raises ValueError: the address family cannot be determined from the input. + @rtype int + """ + try: + junk = dns.ipv4.inet_aton(text) + return AF_INET + except: + try: + junk = dns.ipv6.inet_aton(text) + return AF_INET6 + except: + raise ValueError diff --git a/dns/query.py b/dns/query.py index d0e04d8a..d5f86fb0 100644 --- a/dns/query.py +++ b/dns/query.py @@ -25,6 +25,7 @@ import sys import time import dns.exception +import dns.inet import dns.name import dns.message import dns.rdataclass @@ -64,7 +65,7 @@ def _wait_for_readable(s, expiration): def _wait_for_writable(s, expiration): _wait_for([], [s], [s], expiration) -def udp(q, where, timeout=None, port=53, af=socket.AF_INET): +def udp(q, where, timeout=None, port=53, af=None): """Return the response obtained after sending a query via UDP. @param q: the query @@ -76,22 +77,33 @@ def udp(q, where, timeout=None, port=53, af=socket.AF_INET): @type timeout: float @param port: The port to which to send the message. The default is 53. @type port: int - @param af: the address family to use. The default is socket.AF_INET. + @param af: the address family to use. The default is None, which + causes the address family to use to be inferred from the form of of where. + If the inference attempt fails, AF_INET is used. @type af: int @rtype: dns.message.Message object""" wire = q.to_wire() + if af is None: + try: + af = dns.inet.af_for_address(where) + except: + af = dns.inet.AF_INET + if af == dns.inet.AF_INET: + destination = (where, port) + elif af == dns.inet.AF_INET6: + destination = (where, port, 0, 0) s = socket.socket(af, socket.SOCK_DGRAM, 0) try: expiration = _compute_expiration(timeout) s.setblocking(0) _wait_for_writable(s, expiration) - s.sendto(wire, (where, port)) + s.sendto(wire, destination) _wait_for_readable(s, expiration) (wire, from_address) = s.recvfrom(65535) finally: s.close() - if from_address != (where, port): + if from_address != destination: raise UnexpectedSource r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac) if not q.is_response(r): @@ -133,7 +145,7 @@ def _connect(s, address): if v[0] != errno.EINPROGRESS and v[0] != errno.EWOULDBLOCK: raise ty, v -def tcp(q, where, timeout=None, port=53, af=socket.AF_INET): +def tcp(q, where, timeout=None, port=53, af=None): """Return the response obtained after sending a query via TCP. @param q: the query @@ -145,16 +157,27 @@ def tcp(q, where, timeout=None, port=53, af=socket.AF_INET): @type timeout: float @param port: The port to which to send the message. The default is 53. @type port: int - @param af: the address family to use. The default is socket.AF_INET. + @param af: the address family to use. The default is None, which + causes the address family to use to be inferred from the form of of where. + If the inference attempt fails, AF_INET is used. @type af: int @rtype: dns.message.Message object""" wire = q.to_wire() + if af is None: + try: + af = dns.inet.af_for_address(where) + except: + af = dns.inet.AF_INET + if af == dns.inet.AF_INET: + destination = (where, port) + elif af == dns.inet.AF_INET6: + destination = (where, port, 0, 0) s = socket.socket(af, socket.SOCK_STREAM, 0) try: expiration = _compute_expiration(timeout) s.setblocking(0) - _connect(s, (where, port)) + _connect(s, destination) l = len(wire) @@ -175,7 +198,7 @@ def tcp(q, where, timeout=None, port=53, af=socket.AF_INET): def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, timeout=None, port=53, keyring=None, keyname=None, relativize=True, - af=socket.AF_INET, lifetime=None): + af=None, lifetime=None): """Return a generator for the responses to a zone transfer. @param where: where to send the message @@ -200,7 +223,9 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, @param relativize: If True, all names in the zone will be relativized to the zone origin. @type relativize: bool - @param af: the address family to use. The default is socket.AF_INET. + @param af: the address family to use. The default is None, which + causes the address family to use to be inferred from the form of of where. + If the inference attempt fails, AF_INET is used. @type af: int @param lifetime: The total number of seconds to spend doing the transfer. If None, the default, then there is no limit on the time the transfer may @@ -214,9 +239,18 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, if not keyring is None: q.use_tsig(keyring, keyname) wire = q.to_wire() + if af is None: + try: + af = dns.inet.af_for_address(where) + except: + af = dns.inet.AF_INET + if af == dns.inet.AF_INET: + destination = (where, port) + elif af == dns.inet.AF_INET6: + destination = (where, port, 0, 0) s = socket.socket(af, socket.SOCK_STREAM, 0) expiration = _compute_expiration(lifetime) - _connect(s, (where, port)) + _connect(s, destination) l = len(wire) tcpmsg = struct.pack("!H", l) + wire _net_write(s, tcpmsg, expiration) -- 2.47.3