From e915736e98ba8ef8ba583d448755ccdda4ff30bb Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Fri, 2 Sep 2005 05:33:20 +0000 Subject: [PATCH] allow source address and port to be specified in query.{udp,tcp,xfr} Original author: Bob Halley Date: 2005-08-01 04:24:59 --- ChangeLog | 10 ++++++++++ README | 8 ++++---- dns/query.py | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 26bf5904..cbfc804e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,19 @@ +2005-07-31 Bob Halley + + * (Version 1.3.4 released) + 2005-07-31 Bob Halley * dns/message.py (make_response): Trying to respond to a response threw a NameError while trying to throw a FormErr since it used the wrong name for the FormErr exception. + * dns/query.py (_connect): We needed to ignore EALREADY too. + + * dns/query.py: Optional "source" and "source_port" parameters + have been added to udp(), tcp(), and xfr(). Thanks to Ralf + Weber for suggesting the change and providing a patch. + 2005-06-05 Bob Halley * dns/query.py: The requirement that the "where" parameter be diff --git a/README b/README index 2ca957c7..1ca7b55a 100644 --- a/README +++ b/README @@ -22,13 +22,13 @@ development by continuing to employ the author :). ABOUT THIS RELEASE -This is dnspython 1.3.4. +This is dnspython 1.3.4 New since 1.3.3: - The requirement that the "where" parameter in dns.query.{udp,tcp,xfr} - be an IPv4 or IPv6 address is now documented. - + The source address and port may now be specified when calling + dns.query.{udp,tcp,xfr}. + The resolver now does exponential backoff each time it runs through all of the nameservers. diff --git a/dns/query.py b/dns/query.py index f8c0ae3e..86df19c9 100644 --- a/dns/query.py +++ b/dns/query.py @@ -64,8 +64,8 @@ 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=None): + +def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0): """Return the response obtained after sending a query via UDP. @param q: the query @@ -81,7 +81,12 @@ def udp(q, where, timeout=None, port=53, af=None): 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""" + @rtype: dns.message.Message object + @param source: source address. The default is the IPv4 wildcard address. + @type source: string + @param source_port: The port from which to send the message. + The default is 0. + @type port: int""" wire = q.to_wire() if af is None: @@ -91,12 +96,18 @@ def udp(q, where, timeout=None, port=53, af=None): af = dns.inet.AF_INET if af == dns.inet.AF_INET: destination = (where, port) + if source is not None: + source = (source, source_port) elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) + if source is not None: + source = (source, source_port, 0, 0) s = socket.socket(af, socket.SOCK_DGRAM, 0) try: expiration = _compute_expiration(timeout) s.setblocking(0) + if source is not None: + s.bind(source) _wait_for_writable(s, expiration) s.sendto(wire, destination) _wait_for_readable(s, expiration) @@ -142,10 +153,12 @@ def _connect(s, address): s.connect(address) except socket.error: (ty, v) = sys.exc_info()[:2] - if v[0] != errno.EINPROGRESS and v[0] != errno.EWOULDBLOCK and v[0] != errno.EALREADY: + if v[0] != errno.EINPROGRESS and \ + v[0] != errno.EWOULDBLOCK and \ + v[0] != errno.EALREADY: raise ty, v -def tcp(q, where, timeout=None, port=53, af=None): +def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0): """Return the response obtained after sending a query via TCP. @param q: the query @@ -161,7 +174,12 @@ def tcp(q, where, timeout=None, port=53, af=None): 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""" + @rtype: dns.message.Message object + @param source: source address. The default is the IPv4 wildcard address. + @type source: string + @param source_port: The port from which to send the message. + The default is 0. + @type port: int""" wire = q.to_wire() if af is None: @@ -171,12 +189,18 @@ def tcp(q, where, timeout=None, port=53, af=None): af = dns.inet.AF_INET if af == dns.inet.AF_INET: destination = (where, port) + if source is not None: + source = (source, source_port) elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) + if source is not None: + source = (source, source_port, 0, 0) s = socket.socket(af, socket.SOCK_STREAM, 0) try: expiration = _compute_expiration(timeout) s.setblocking(0) + if source is not None: + s.bind(source) _connect(s, destination) l = len(wire) @@ -198,7 +222,7 @@ def tcp(q, where, timeout=None, port=53, af=None): def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, timeout=None, port=53, keyring=None, keyname=None, relativize=True, - af=None, lifetime=None): + af=None, lifetime=None, source=None, source_port=0): """Return a generator for the responses to a zone transfer. @param where: where to send the message @@ -231,7 +255,12 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, If None, the default, then there is no limit on the time the transfer may take. @type lifetime: float - @rtype: generator of dns.message.Message objects.""" + @rtype: generator of dns.message.Message objects. + @param source: source address. The default is the IPv4 wildcard address. + @type source: string + @param source_port: The port from which to send the message. + The default is 0. + @type port: int""" if isinstance(zone, str): zone = dns.name.from_text(zone) @@ -246,9 +275,15 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, af = dns.inet.AF_INET if af == dns.inet.AF_INET: destination = (where, port) + if source is not None: + source = (source, source_port) elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) + if source is not None: + source = (source, source_port, 0, 0) s = socket.socket(af, socket.SOCK_STREAM, 0) + if source is not None: + s.bind(source) expiration = _compute_expiration(lifetime) _connect(s, destination) l = len(wire) -- 2.47.3