summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Stasiak <jakub.stasiak@smarkets.com>2016-09-27 11:18:07 +0100
committerJakub Stasiak <jakub.stasiak@smarkets.com>2016-09-27 11:27:15 +0100
commit8337e1a0cc295458361539b82fefe7824a08eef0 (patch)
tree2a48f7ed32288016b4e0dfb3f6f032be044fa864
parent1d4ce40c1bef04159daa685b09a9884cb5727fe6 (diff)
downloadeventlet-fix-dns-resolution.tar.gz
Upgrade bundled dnspython to fix DNS resolutionfix-dns-resolution
The version introduced in commit [1] ([2]) has a critical bug - "The DNS resolver doesn't return any records and under some circumstances throws KeyError exceptions from within dnspython" [3]. dnspython commit [4] fixes it so let's update to the latest development version. Simple script to reproduce: import eventlet eventlet.monkey_patch(all=True) import socket print(socket.gethostbyname('google.co.uk')) Before this change it'd raise an exception, after - it produces a result. [1] 52b09becacd23f384cf69ae37d70c893c43e3b13 [2] https://github.com/rthalley/dnspython/commit/188aa701a6826c607da0624e31a8c4618d0a8017 [3] https://github.com/rthalley/dnspython/issues/206 [4] https://github.com/rthalley/dnspython/commit/292995db18f16a528471250fab5cb25082b7d193
-rwxr-xr-xbin/pull-dnspython2
-rw-r--r--eventlet/support/dns/entropy.py6
-rw-r--r--eventlet/support/dns/exception.py4
-rw-r--r--eventlet/support/dns/inet.py6
-rw-r--r--eventlet/support/dns/message.py6
-rw-r--r--eventlet/support/dns/name.py164
-rw-r--r--eventlet/support/dns/query.py2
-rw-r--r--eventlet/support/dns/rdatatype.py2
-rw-r--r--eventlet/support/dns/rdtypes/ANY/AVC.py23
-rw-r--r--eventlet/support/dns/rdtypes/ANY/CAA.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/CERT.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/HINFO.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/ISDN.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/LOC.py4
-rw-r--r--eventlet/support/dns/rdtypes/ANY/NSEC3.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/SSHFP.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/TLSA.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/URI.py1
-rw-r--r--eventlet/support/dns/rdtypes/ANY/X25.py1
-rw-r--r--eventlet/support/dns/rdtypes/IN/A.py1
-rw-r--r--eventlet/support/dns/rdtypes/IN/AAAA.py1
-rw-r--r--eventlet/support/dns/rdtypes/IN/APL.py1
-rw-r--r--eventlet/support/dns/rdtypes/IN/DHCID.py1
-rw-r--r--eventlet/support/dns/rdtypes/IN/IPSECKEY.py1
-rw-r--r--eventlet/support/dns/rdtypes/IN/NSAP.py1
-rw-r--r--eventlet/support/dns/rdtypes/IN/WKS.py1
-rw-r--r--eventlet/support/dns/rdtypes/dsbase.py1
-rw-r--r--eventlet/support/dns/rdtypes/euibase.py1
-rw-r--r--eventlet/support/dns/rdtypes/txtbase.py1
-rw-r--r--eventlet/support/dns/resolver.py51
-rw-r--r--eventlet/support/dns/reversename.py2
-rw-r--r--eventlet/support/dns/rrset.py9
-rw-r--r--eventlet/support/dns/set.py3
-rw-r--r--eventlet/support/dns/wiredata.py59
-rw-r--r--eventlet/support/dns/zone.py44
36 files changed, 290 insertions, 117 deletions
diff --git a/bin/pull-dnspython b/bin/pull-dnspython
index ddbd6e1..56d1a76 100755
--- a/bin/pull-dnspython
+++ b/bin/pull-dnspython
@@ -1,6 +1,6 @@
#!/bin/bash -eux
cd "$( dirname "${BASH_SOURCE[0]}" )/.."
-version=${1-188aa701a6826c607da0624e31a8c4618d0a8017}
+version=${1-bb0c9f21f4a6f56f2fe8d7c1fc991080ef89d223}
upstream_path=./dnspython-${version}
if [[ ! -d "${upstream_path}" ]]; then
curl -L -odnspython.zip "https://github.com/rthalley/dnspython/archive/${version}.zip"
diff --git a/eventlet/support/dns/entropy.py b/eventlet/support/dns/entropy.py
index 7a2d87d..de7a70a 100644
--- a/eventlet/support/dns/entropy.py
+++ b/eventlet/support/dns/entropy.py
@@ -70,14 +70,14 @@ class EntropyPool(object):
if not self.seeded or self.seed_pid != os.getpid():
try:
seed = os.urandom(16)
- except:
+ except Exception:
try:
r = open('/dev/urandom', 'rb', 0)
try:
seed = r.read(16)
finally:
r.close()
- except:
+ except Exception:
seed = str(time.time())
self.seeded = True
self.seed_pid = os.getpid()
@@ -125,7 +125,7 @@ pool = EntropyPool()
try:
system_random = random.SystemRandom()
-except:
+except Exception:
system_random = None
def random_16():
diff --git a/eventlet/support/dns/exception.py b/eventlet/support/dns/exception.py
index 151f584..6c0b1f4 100644
--- a/eventlet/support/dns/exception.py
+++ b/eventlet/support/dns/exception.py
@@ -23,14 +23,14 @@ class DNSException(Exception):
It supports two basic modes of operation:
a) Old/compatible mode is used if __init__ was called with
- empty **kwargs.
+ empty **kwargs.
In compatible mode all *args are passed to standard Python Exception class
as before and all *args are printed by standard __str__ implementation.
Class variable msg (or doc string if msg is None) is returned from str()
if *args is empty.
b) New/parametrized mode is used if __init__ was called with
- non-empty **kwargs.
+ non-empty **kwargs.
In the new mode *args has to be empty and all kwargs has to exactly match
set in class variable self.supp_kwargs. All kwargs are stored inside
self.kwargs and used in new __str__ implementation to construct
diff --git a/eventlet/support/dns/inet.py b/eventlet/support/dns/inet.py
index cc22e64..73490a9 100644
--- a/eventlet/support/dns/inet.py
+++ b/eventlet/support/dns/inet.py
@@ -85,7 +85,7 @@ def af_for_address(text):
try:
dns.ipv4.inet_aton(text)
return AF_INET
- except:
+ except Exception:
try:
dns.ipv6.inet_aton(text)
return AF_INET6
@@ -103,9 +103,9 @@ def is_multicast(text):
try:
first = ord(dns.ipv4.inet_aton(text)[0])
return first >= 224 and first <= 239
- except:
+ except Exception:
try:
first = ord(dns.ipv6.inet_aton(text)[0])
return first == 255
- except:
+ except Exception:
raise ValueError
diff --git a/eventlet/support/dns/message.py b/eventlet/support/dns/message.py
index ff0ea81..a0df18e 100644
--- a/eventlet/support/dns/message.py
+++ b/eventlet/support/dns/message.py
@@ -898,7 +898,7 @@ class _TextReader(object):
raise dns.exception.SyntaxError
except dns.exception.SyntaxError:
raise dns.exception.SyntaxError
- except:
+ except Exception:
rdclass = dns.rdataclass.IN
# Type
rdtype = dns.rdatatype.from_text(token.value)
@@ -931,7 +931,7 @@ class _TextReader(object):
raise dns.exception.SyntaxError
except dns.exception.SyntaxError:
raise dns.exception.SyntaxError
- except:
+ except Exception:
ttl = 0
# Class
try:
@@ -944,7 +944,7 @@ class _TextReader(object):
rdclass = self.zone_rdclass
except dns.exception.SyntaxError:
raise dns.exception.SyntaxError
- except:
+ except Exception:
rdclass = dns.rdataclass.IN
# Type
rdtype = dns.rdatatype.from_text(token.value)
diff --git a/eventlet/support/dns/name.py b/eventlet/support/dns/name.py
index ef812cf..758a394 100644
--- a/eventlet/support/dns/name.py
+++ b/eventlet/support/dns/name.py
@@ -26,6 +26,11 @@ import struct
import sys
import copy
import encodings.idna
+try:
+ import idna
+ have_idna_2008 = True
+except ImportError:
+ have_idna_2008 = False
import dns.exception
import dns.wiredata
@@ -34,7 +39,7 @@ from ._compat import long, binary_type, text_type, unichr
try:
maxint = sys.maxint
-except:
+except AttributeError:
maxint = (1 << (8 * struct.calcsize("P"))) // 2 - 1
NAMERELN_NONE = 0
@@ -91,8 +96,115 @@ class NoParent(dns.exception.DNSException):
"""An attempt was made to get the parent of the root name
or the empty name."""
+class NoIDNA2008(dns.exception.DNSException):
+
+ """IDNA 2008 processing was requested but the idna module is not
+ available."""
+
+
+class IDNAException(dns.exception.DNSException):
+
+ """IDNA 2008 processing raised an exception."""
+
+ supp_kwargs = set(['idna_exception'])
+ fmt = "IDNA processing exception: {idna_exception}"
+
+class IDNACodec(object):
+
+ """Abstract base class for IDNA encoder/decoders."""
+
+ def encode(self, label):
+ raise NotImplementedError
+
+ def decode(self, label):
+ raise NotImplementedError
+
+class IDNA2003Codec(IDNACodec):
+
+ """IDNA 2003 encoder/decoder."""
+
+ def encode(self, label):
+ if label == '':
+ return b''
+ try:
+ return encodings.idna.ToASCII(label)
+ except UnicodeError:
+ raise LabelTooLong
+
+ def decode(self, label):
+ if label == b'':
+ return u''
+ return _escapify(encodings.idna.ToUnicode(label), True)
+
+class IDNA2008Codec(IDNACodec):
+
+ """IDNA 2008 encoder/decoder."""
+
+ def __init__(self, uts_46=False, transitional=False,
+ allow_pure_ascii=False):
+ """Initialize the IDNA 2008 encoder/decoder.
+ @param uts_46: If True, apply Unicode IDNA compatibility processing
+ as described in Unicode Technical Standard #46
+ (U{http://unicode.org/reports/tr46/}). This parameter is only
+ meaningful if IDNA 2008 is in use. If False, do not apply
+ the mapping. The default is False
+ @type uts_46: bool
+ @param transitional: If True, use the "transitional" mode described
+ in Unicode Technical Standard #46. This parameter is only
+ meaningful if IDNA 2008 is in use. The default is False.
+ @type transitional: bool
+ @param allow_pure_ascii: If True, then a label which
+ consists of only ASCII characters is allowed. This is less strict
+ than regular IDNA 2008, but is also necessary for mixed names,
+ e.g. a name with starting with "_sip._tcp." and ending in an IDN
+ suffixm which would otherwise be disallowed. The default is False
+ @type allow_pure_ascii: bool
+ """
+ self.uts_46 = uts_46
+ self.transitional = transitional
+ self.allow_pure_ascii = allow_pure_ascii
+
+ def is_all_ascii(self, label):
+ for c in label:
+ if ord(c) > 0x7f:
+ return False
+ return True
+
+ def encode(self, label):
+ if label == '':
+ return b''
+ if self.allow_pure_ascii and self.is_all_ascii(label):
+ return label.encode('ascii')
+ if not have_idna_2008:
+ raise NoIDNA2008
+ try:
+ if self.uts_46:
+ label = idna.uts46_remap(label, False, self.transitional)
+ return idna.alabel(label)
+ except idna.IDNAError as e:
+ raise IDNAException(idna_exception=e)
+
+ def decode(self, label):
+ if label == b'':
+ return u''
+ if not have_idna_2008:
+ raise NoIDNA2008
+ try:
+ if self.uts_46:
+ label = idna.uts46_remap(label, False, False)
+ return _escapify(idna.ulabel(label), True)
+ except idna.IDNAError as e:
+ raise IDNAException(idna_exception=e)
+
+
_escaped = bytearray(b'"().;\\@$')
+IDNA_2003 = IDNA2003Codec()
+IDNA_2008_Practical = IDNA2008Codec(True, False, True)
+IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False)
+IDNA_2008_Strict = IDNA2008Codec(False, False, False)
+IDNA_2008_Transitional = IDNA2008Codec(True, True, False)
+IDNA_2008 = IDNA_2008_Practical
def _escapify(label, unicode_mode=False):
"""Escape the characters in label which need it.
@@ -126,7 +238,6 @@ def _escapify(label, unicode_mode=False):
text += u'\\%03d' % ord(c)
return text
-
def _validate_labels(labels):
"""Check for empty labels in the middle of a label sequence,
labels that are too long, and for too many labels.
@@ -375,13 +486,18 @@ class Name(object):
s = b'.'.join(map(_escapify, l))
return s
- def to_unicode(self, omit_final_dot=False):
+ def to_unicode(self, omit_final_dot=False, idna_codec=None):
"""Convert name to Unicode text format.
IDN ACE labels are converted to Unicode.
@param omit_final_dot: If True, don't emit the final dot (denoting the
root label) for absolute names. The default is False.
+ @type omit_final_dot: bool
+ @param: idna_codec: IDNA encoder/decoder. If None, the default IDNA
+ 2003
+ encoder/decoder is used.
+ @type idna_codec: dns.name.IDNA
@rtype: string
"""
@@ -393,9 +509,9 @@ class Name(object):
l = self.labels[:-1]
else:
l = self.labels
- s = u'.'.join([_escapify(encodings.idna.ToUnicode(x), True)
- for x in l])
- return s
+ if idna_codec is None:
+ idna_codec = IDNA_2003
+ return u'.'.join([idna_codec.decode(x) for x in l])
def to_digestable(self, origin=None):
"""Convert name to a format suitable for digesting in hashes.
@@ -488,9 +604,6 @@ class Name(object):
def __getitem__(self, index):
return self.labels[index]
- def __getslice__(self, start, stop):
- return self.labels[start:stop]
-
def __add__(self, other):
return self.concatenate(other)
@@ -583,11 +696,18 @@ root = Name([b''])
empty = Name([])
-def from_unicode(text, origin=root):
+def from_unicode(text, origin=root, idna_codec=None):
"""Convert unicode text into a Name object.
Labels are encoded in IDN ACE form.
+ @param text: The text to convert into a name.
+ @type text: Unicode string
+ @param origin: The origin to append to non-absolute names.
+ @type origin: dns.name.Name
+ @param: idna_codec: IDNA encoder/decoder. If None, the default IDNA 2003
+ encoder/decoder is used.
+ @type idna_codec: dns.name.IDNA
@rtype: dns.name.Name object
"""
@@ -600,6 +720,8 @@ def from_unicode(text, origin=root):
escaping = False
edigits = 0
total = 0
+ if idna_codec is None:
+ idna_codec = IDNA_2003
if text == u'@':
text = u''
if text:
@@ -626,10 +748,7 @@ def from_unicode(text, origin=root):
elif c in [u'.', u'\u3002', u'\uff0e', u'\uff61']:
if len(label) == 0:
raise EmptyLabel
- try:
- labels.append(encodings.idna.ToASCII(label))
- except UnicodeError:
- raise LabelTooLong
+ labels.append(idna_codec.encode(label))
label = u''
elif c == u'\\':
escaping = True
@@ -640,10 +759,7 @@ def from_unicode(text, origin=root):
if escaping:
raise BadEscape
if len(label) > 0:
- try:
- labels.append(encodings.idna.ToASCII(label))
- except UnicodeError:
- raise LabelTooLong
+ labels.append(idna_codec.encode(label))
else:
labels.append(b'')
@@ -652,13 +768,21 @@ def from_unicode(text, origin=root):
return Name(labels)
-def from_text(text, origin=root):
+def from_text(text, origin=root, idna_codec=None):
"""Convert text into a Name object.
+
+ @param text: The text to convert into a name.
+ @type text: string
+ @param origin: The origin to append to non-absolute names.
+ @type origin: dns.name.Name
+ @param: idna_codec: IDNA encoder/decoder. If None, the default IDNA 2003
+ encoder/decoder is used.
+ @type idna_codec: dns.name.IDNA
@rtype: dns.name.Name object
"""
if isinstance(text, text_type):
- return from_unicode(text, origin)
+ return from_unicode(text, origin, idna_codec)
if not isinstance(text, binary_type):
raise ValueError("input to from_text() must be a string")
if not (origin is None or isinstance(origin, Name)):
diff --git a/eventlet/support/dns/query.py b/eventlet/support/dns/query.py
index 6b76b42..bfecd43 100644
--- a/eventlet/support/dns/query.py
+++ b/eventlet/support/dns/query.py
@@ -176,7 +176,7 @@ def _destination_and_source(af, where, port, source, source_port):
if af is None:
try:
af = dns.inet.af_for_address(where)
- except:
+ except Exception:
af = dns.inet.AF_INET
if af == dns.inet.AF_INET:
destination = (where, port)
diff --git a/eventlet/support/dns/rdatatype.py b/eventlet/support/dns/rdatatype.py
index cde1a0a..15284f6 100644
--- a/eventlet/support/dns/rdatatype.py
+++ b/eventlet/support/dns/rdatatype.py
@@ -96,6 +96,7 @@ MAILA = 254
ANY = 255
URI = 256
CAA = 257
+AVC = 258
TA = 32768
DLV = 32769
@@ -166,6 +167,7 @@ _by_text = {
'ANY': ANY,
'URI': URI,
'CAA': CAA,
+ 'AVC': AVC,
'TA': TA,
'DLV': DLV,
}
diff --git a/eventlet/support/dns/rdtypes/ANY/AVC.py b/eventlet/support/dns/rdtypes/ANY/AVC.py
new file mode 100644
index 0000000..137c9de
--- /dev/null
+++ b/eventlet/support/dns/rdtypes/ANY/AVC.py
@@ -0,0 +1,23 @@
+# Copyright (C) 2016 Nominum, Inc.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose with or without fee is hereby granted,
+# provided that the above copyright notice and this permission notice
+# appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import dns.rdtypes.txtbase
+
+
+class AVC(dns.rdtypes.txtbase.TXTBase):
+
+ """AVC record
+
+ @see: U{http://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template}"""
diff --git a/eventlet/support/dns/rdtypes/ANY/CAA.py b/eventlet/support/dns/rdtypes/ANY/CAA.py
index e80d469..f2e41ad 100644
--- a/eventlet/support/dns/rdtypes/ANY/CAA.py
+++ b/eventlet/support/dns/rdtypes/ANY/CAA.py
@@ -71,4 +71,3 @@ class CAA(dns.rdata.Rdata):
tag = wire[current: current + l]
value = wire[current + l:current + rdlen - 2]
return cls(rdclass, rdtype, flags, tag, value)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/CERT.py b/eventlet/support/dns/rdtypes/ANY/CERT.py
index b745440..1c35c23 100644
--- a/eventlet/support/dns/rdtypes/ANY/CERT.py
+++ b/eventlet/support/dns/rdtypes/ANY/CERT.py
@@ -119,4 +119,3 @@ class CERT(dns.rdata.Rdata):
certificate = wire[current: current + rdlen].unwrap()
return cls(rdclass, rdtype, certificate_type, key_tag, algorithm,
certificate)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/HINFO.py b/eventlet/support/dns/rdtypes/ANY/HINFO.py
index 52298bc..e5a1bea 100644
--- a/eventlet/support/dns/rdtypes/ANY/HINFO.py
+++ b/eventlet/support/dns/rdtypes/ANY/HINFO.py
@@ -82,4 +82,3 @@ class HINFO(dns.rdata.Rdata):
raise dns.exception.FormError
os = wire[current: current + l].unwrap()
return cls(rdclass, rdtype, cpu, os)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/ISDN.py b/eventlet/support/dns/rdtypes/ANY/ISDN.py
index 01284a8..da2ae3a 100644
--- a/eventlet/support/dns/rdtypes/ANY/ISDN.py
+++ b/eventlet/support/dns/rdtypes/ANY/ISDN.py
@@ -95,4 +95,3 @@ class ISDN(dns.rdata.Rdata):
else:
subaddress = ''
return cls(rdclass, rdtype, address, subaddress)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/LOC.py b/eventlet/support/dns/rdtypes/ANY/LOC.py
index f2544c3..b433da9 100644
--- a/eventlet/support/dns/rdtypes/ANY/LOC.py
+++ b/eventlet/support/dns/rdtypes/ANY/LOC.py
@@ -138,16 +138,12 @@ class LOC(dns.rdata.Rdata):
def to_text(self, origin=None, relativize=True, **kw):
if self.latitude[4] > 0:
lat_hemisphere = 'N'
- lat_degrees = self.latitude[0]
else:
lat_hemisphere = 'S'
- lat_degrees = -1 * self.latitude[0]
if self.longitude[4] > 0:
long_hemisphere = 'E'
- long_degrees = self.longitude[0]
else:
long_hemisphere = 'W'
- long_degrees = -1 * self.longitude[0]
text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % (
self.latitude[0], self.latitude[1],
self.latitude[2], self.latitude[3], lat_hemisphere,
diff --git a/eventlet/support/dns/rdtypes/ANY/NSEC3.py b/eventlet/support/dns/rdtypes/ANY/NSEC3.py
index 3982f4b..9a15687 100644
--- a/eventlet/support/dns/rdtypes/ANY/NSEC3.py
+++ b/eventlet/support/dns/rdtypes/ANY/NSEC3.py
@@ -189,4 +189,3 @@ class NSEC3(dns.rdata.Rdata):
windows.append((window, bitmap))
return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
windows)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py b/eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py
index b506282..36bf740 100644
--- a/eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py
+++ b/eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py
@@ -86,4 +86,3 @@ class NSEC3PARAM(dns.rdata.Rdata):
if rdlen != 0:
raise dns.exception.FormError
return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/SSHFP.py b/eventlet/support/dns/rdtypes/ANY/SSHFP.py
index b6ed396..7e846b3 100644
--- a/eventlet/support/dns/rdtypes/ANY/SSHFP.py
+++ b/eventlet/support/dns/rdtypes/ANY/SSHFP.py
@@ -75,4 +75,3 @@ class SSHFP(dns.rdata.Rdata):
rdlen -= 2
fingerprint = wire[current: current + rdlen].unwrap()
return cls(rdclass, rdtype, header[0], header[1], fingerprint)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/TLSA.py b/eventlet/support/dns/rdtypes/ANY/TLSA.py
index 23f4e94..790a93b 100644
--- a/eventlet/support/dns/rdtypes/ANY/TLSA.py
+++ b/eventlet/support/dns/rdtypes/ANY/TLSA.py
@@ -80,4 +80,3 @@ class TLSA(dns.rdata.Rdata):
rdlen -= 3
cert = wire[current: current + rdlen].unwrap()
return cls(rdclass, rdtype, header[0], header[1], header[2], cert)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/URI.py b/eventlet/support/dns/rdtypes/ANY/URI.py
index 0c121d2..b5595b5 100644
--- a/eventlet/support/dns/rdtypes/ANY/URI.py
+++ b/eventlet/support/dns/rdtypes/ANY/URI.py
@@ -78,4 +78,3 @@ class URI(dns.rdata.Rdata):
current += rdlen
return cls(rdclass, rdtype, priority, weight, target)
-
diff --git a/eventlet/support/dns/rdtypes/ANY/X25.py b/eventlet/support/dns/rdtypes/ANY/X25.py
index f5cca11..8732ccf 100644
--- a/eventlet/support/dns/rdtypes/ANY/X25.py
+++ b/eventlet/support/dns/rdtypes/ANY/X25.py
@@ -62,4 +62,3 @@ class X25(dns.rdata.Rdata):
raise dns.exception.FormError
address = wire[current: current + l].unwrap()
return cls(rdclass, rdtype, address)
-
diff --git a/eventlet/support/dns/rdtypes/IN/A.py b/eventlet/support/dns/rdtypes/IN/A.py
index 42faf9b..3775548 100644
--- a/eventlet/support/dns/rdtypes/IN/A.py
+++ b/eventlet/support/dns/rdtypes/IN/A.py
@@ -50,4 +50,3 @@ class A(dns.rdata.Rdata):
def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
address = dns.ipv4.inet_ntoa(wire[current: current + rdlen]).decode()
return cls(rdclass, rdtype, address)
-
diff --git a/eventlet/support/dns/rdtypes/IN/AAAA.py b/eventlet/support/dns/rdtypes/IN/AAAA.py
index d2c65c6..4352404 100644
--- a/eventlet/support/dns/rdtypes/IN/AAAA.py
+++ b/eventlet/support/dns/rdtypes/IN/AAAA.py
@@ -51,4 +51,3 @@ class AAAA(dns.rdata.Rdata):
address = dns.inet.inet_ntop(dns.inet.AF_INET6,
wire[current: current + rdlen])
return cls(rdclass, rdtype, address)
-
diff --git a/eventlet/support/dns/rdtypes/IN/APL.py b/eventlet/support/dns/rdtypes/IN/APL.py
index 698dde7..57ef6c0 100644
--- a/eventlet/support/dns/rdtypes/IN/APL.py
+++ b/eventlet/support/dns/rdtypes/IN/APL.py
@@ -159,4 +159,3 @@ class APL(dns.rdata.Rdata):
item = APLItem(header[0], negation, address, header[1])
items.append(item)
return cls(rdclass, rdtype, items)
-
diff --git a/eventlet/support/dns/rdtypes/IN/DHCID.py b/eventlet/support/dns/rdtypes/IN/DHCID.py
index 06a850a..5b8626a 100644
--- a/eventlet/support/dns/rdtypes/IN/DHCID.py
+++ b/eventlet/support/dns/rdtypes/IN/DHCID.py
@@ -57,4 +57,3 @@ class DHCID(dns.rdata.Rdata):
def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
data = wire[current: current + rdlen].unwrap()
return cls(rdclass, rdtype, data)
-
diff --git a/eventlet/support/dns/rdtypes/IN/IPSECKEY.py b/eventlet/support/dns/rdtypes/IN/IPSECKEY.py
index 4f07bd0..c673e83 100644
--- a/eventlet/support/dns/rdtypes/IN/IPSECKEY.py
+++ b/eventlet/support/dns/rdtypes/IN/IPSECKEY.py
@@ -146,4 +146,3 @@ class IPSECKEY(dns.rdata.Rdata):
key = wire[current: current + rdlen].unwrap()
return cls(rdclass, rdtype, header[0], gateway_type, header[2],
gateway, key)
-
diff --git a/eventlet/support/dns/rdtypes/IN/NSAP.py b/eventlet/support/dns/rdtypes/IN/NSAP.py
index 6dbe5af..05d0745 100644
--- a/eventlet/support/dns/rdtypes/IN/NSAP.py
+++ b/eventlet/support/dns/rdtypes/IN/NSAP.py
@@ -56,4 +56,3 @@ class NSAP(dns.rdata.Rdata):
def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
address = wire[current: current + rdlen].unwrap()
return cls(rdclass, rdtype, address)
-
diff --git a/eventlet/support/dns/rdtypes/IN/WKS.py b/eventlet/support/dns/rdtypes/IN/WKS.py
index da2a2d8..1d4012c 100644
--- a/eventlet/support/dns/rdtypes/IN/WKS.py
+++ b/eventlet/support/dns/rdtypes/IN/WKS.py
@@ -103,4 +103,3 @@ class WKS(dns.rdata.Rdata):
rdlen -= 5
bitmap = wire[current: current + rdlen].unwrap()
return cls(rdclass, rdtype, address, protocol, bitmap)
-
diff --git a/eventlet/support/dns/rdtypes/dsbase.py b/eventlet/support/dns/rdtypes/dsbase.py
index 80f792a..1ee28e4 100644
--- a/eventlet/support/dns/rdtypes/dsbase.py
+++ b/eventlet/support/dns/rdtypes/dsbase.py
@@ -81,4 +81,3 @@ class DSBase(dns.rdata.Rdata):
rdlen -= 4
digest = wire[current: current + rdlen].unwrap()
return cls(rdclass, rdtype, header[0], header[1], header[2], digest)
-
diff --git a/eventlet/support/dns/rdtypes/euibase.py b/eventlet/support/dns/rdtypes/euibase.py
index c7d0045..cc5fdaa 100644
--- a/eventlet/support/dns/rdtypes/euibase.py
+++ b/eventlet/support/dns/rdtypes/euibase.py
@@ -69,4 +69,3 @@ class EUIBase(dns.rdata.Rdata):
def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
eui = wire[current:current + rdlen].unwrap()
return cls(rdclass, rdtype, eui)
-
diff --git a/eventlet/support/dns/rdtypes/txtbase.py b/eventlet/support/dns/rdtypes/txtbase.py
index 54d7e6f..352b027 100644
--- a/eventlet/support/dns/rdtypes/txtbase.py
+++ b/eventlet/support/dns/rdtypes/txtbase.py
@@ -88,4 +88,3 @@ class TXTBase(dns.rdata.Rdata):
rdlen -= l
strings.append(s)
return cls(rdclass, rdtype, strings)
-
diff --git a/eventlet/support/dns/resolver.py b/eventlet/support/dns/resolver.py
index 5bd1e8d..abc431d 100644
--- a/eventlet/support/dns/resolver.py
+++ b/eventlet/support/dns/resolver.py
@@ -135,8 +135,9 @@ class NoNameservers(dns.exception.DNSException):
"""All nameservers failed to answer the query.
- @param errors: list of servers and respective errors
- @type errors: [(server ip address, any object convertible to string)]
+ errors: list of servers and respective errors
+ The type of errors is
+ [(server ip address, any object convertible to string)].
Non-empty errors list will add explanatory message ()
"""
@@ -271,10 +272,10 @@ class Answer(object):
raise AttributeError(attr)
def __len__(self):
- return len(self.rrset)
+ return self.rrset and len(self.rrset) or 0
def __iter__(self):
- return iter(self.rrset)
+ return self.rrset and iter(self.rrset) or iter(tuple())
def __getitem__(self, i):
return self.rrset[i]
@@ -282,9 +283,6 @@ class Answer(object):
def __delitem__(self, i):
del self.rrset[i]
- def __getslice__(self, i, j):
- return self.rrset[i:j]
-
class Cache(object):
@@ -434,7 +432,7 @@ class LRUCache(object):
"""Initialize a DNS cache.
@param max_size: The maximum number of nodes to cache; the default is
- 100000. Must be > 1.
+ 100,000. Must be greater than 1.
@type max_size: int
"""
self.data = {}
@@ -581,6 +579,24 @@ class Resolver(object):
POSIX systems and from the registry on Windows systems.)
@type configure: bool"""
+ self.domain = None
+ self.nameservers = None
+ self.nameserver_ports = None
+ self.port = None
+ self.search = None
+ self.timeout = None
+ self.lifetime = None
+ self.keyring = None
+ self.keyname = None
+ self.keyalgorithm = None
+ self.edns = None
+ self.ednsflags = None
+ self.payload = None
+ self.cache = None
+ self.flags = None
+ self.retry_servfail = False
+ self.rotate = False
+
self.reset()
if configure:
if sys.platform == 'win32':
@@ -901,12 +917,13 @@ class Resolver(object):
all_nxdomain = True
nxdomain_responses = {}
start = time.time()
+ _qname = None # make pylint happy
for _qname in qnames_to_try:
if self.cache:
answer = self.cache.get((_qname, rdtype, rdclass))
if answer is not None:
if answer.rrset is None and raise_on_no_answer:
- raise NoAnswer
+ raise NoAnswer(response=answer.response)
else:
return answer
request = dns.message.make_query(_qname, rdtype, rdclass)
@@ -1032,10 +1049,10 @@ class Resolver(object):
break
if all_nxdomain:
raise NXDOMAIN(qnames=qnames_to_try, responses=nxdomain_responses)
- answer = Answer(qname, rdtype, rdclass, response,
+ answer = Answer(_qname, rdtype, rdclass, response,
raise_on_no_answer)
if self.cache:
- self.cache.put((qname, rdtype, rdclass), answer)
+ self.cache.put((_qname, rdtype, rdclass), answer)
return answer
def use_tsig(self, keyring, keyname=None,
@@ -1194,13 +1211,13 @@ def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0,
addr = dns.ipv6.inet_aton(ahost)
v6addrs.append(host)
canonical_name = host
- except:
+ except Exception:
try:
# Is it a V4 address literal?
addr = dns.ipv4.inet_aton(host)
v4addrs.append(host)
canonical_name = host
- except:
+ except Exception:
if flags & socket.AI_NUMERICHOST == 0:
try:
if family == socket.AF_INET6 or family == socket.AF_UNSPEC:
@@ -1232,11 +1249,11 @@ def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0,
port = 0
else:
port = int(service)
- except:
+ except Exception:
if flags & socket.AI_NUMERICSERV == 0:
try:
port = socket.getservbyname(service)
- except:
+ except Exception:
pass
if port is None:
raise socket.gaierror(socket.EAI_NONAME)
@@ -1311,7 +1328,7 @@ def _getfqdn(name=None):
name = socket.gethostname()
try:
return _getnameinfo(_getaddrinfo(name, 80)[0][4])[0]
- except:
+ except Exception:
return name
@@ -1336,7 +1353,7 @@ def _gethostbyaddr(ip):
dns.ipv6.inet_aton(ip)
sockaddr = (ip, 80, 0, 0)
family = socket.AF_INET6
- except:
+ except Exception:
sockaddr = (ip, 80)
family = socket.AF_INET
(name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD)
diff --git a/eventlet/support/dns/reversename.py b/eventlet/support/dns/reversename.py
index a27e705..9ea9395 100644
--- a/eventlet/support/dns/reversename.py
+++ b/eventlet/support/dns/reversename.py
@@ -51,7 +51,7 @@ def from_address(text):
else:
parts = [x for x in str(binascii.hexlify(v6).decode())]
origin = ipv6_reverse_domain
- except:
+ except Exception:
parts = ['%d' %
byte for byte in bytearray(dns.ipv4.inet_aton(text))]
origin = ipv4_reverse_domain
diff --git a/eventlet/support/dns/rrset.py b/eventlet/support/dns/rrset.py
index 6ad71da..d0f8f93 100644
--- a/eventlet/support/dns/rrset.py
+++ b/eventlet/support/dns/rrset.py
@@ -119,7 +119,8 @@ class RRset(dns.rdataset.Rdataset):
return dns.rdataset.from_rdata_list(self.ttl, list(self))
-def from_text_list(name, ttl, rdclass, rdtype, text_rdatas):
+def from_text_list(name, ttl, rdclass, rdtype, text_rdatas,
+ idna_codec=None):
"""Create an RRset with the specified name, TTL, class, and type, and with
the specified list of rdatas in text format.
@@ -127,7 +128,7 @@ def from_text_list(name, ttl, rdclass, rdtype, text_rdatas):
"""
if isinstance(name, string_types):
- name = dns.name.from_text(name, None)
+ name = dns.name.from_text(name, None, idna_codec=idna_codec)
if isinstance(rdclass, string_types):
rdclass = dns.rdataclass.from_text(rdclass)
if isinstance(rdtype, string_types):
@@ -150,7 +151,7 @@ def from_text(name, ttl, rdclass, rdtype, *text_rdatas):
return from_text_list(name, ttl, rdclass, rdtype, text_rdatas)
-def from_rdata_list(name, ttl, rdatas):
+def from_rdata_list(name, ttl, rdatas, idna_codec=None):
"""Create an RRset with the specified name and TTL, and with
the specified list of rdata objects.
@@ -158,7 +159,7 @@ def from_rdata_list(name, ttl, rdatas):
"""
if isinstance(name, string_types):
- name = dns.name.from_text(name, None)
+ name = dns.name.from_text(name, None, idna_codec=idna_codec)
if len(rdatas) == 0:
raise ValueError("rdata list must not be empty")
diff --git a/eventlet/support/dns/set.py b/eventlet/support/dns/set.py
index 0efc7d9..ef7fd29 100644
--- a/eventlet/support/dns/set.py
+++ b/eventlet/support/dns/set.py
@@ -232,9 +232,6 @@ class Set(object):
def __delitem__(self, i):
del self.items[i]
- def __getslice__(self, i, j):
- return self.items[i:j]
-
def issubset(self, other):
"""Is I{self} a subset of I{other}?
diff --git a/eventlet/support/dns/wiredata.py b/eventlet/support/dns/wiredata.py
index b381f7b..ccef595 100644
--- a/eventlet/support/dns/wiredata.py
+++ b/eventlet/support/dns/wiredata.py
@@ -15,6 +15,7 @@
"""DNS Wire Data Helper"""
+import sys
import dns.exception
from ._compat import binary_type, string_types
@@ -26,12 +27,16 @@ from ._compat import binary_type, string_types
# out what constant Python will use.
-class _SliceUnspecifiedBound(str):
+class _SliceUnspecifiedBound(binary_type):
- def __getslice__(self, i, j):
- return j
+ def __getitem__(self, key):
+ return key.stop
+
+ if sys.version_info < (3,):
+ def __getslice__(self, i, j): # pylint: disable=getslice-method
+ return self.__getitem__(slice(i, j))
-_unspecified_bound = _SliceUnspecifiedBound('')[1:]
+_unspecified_bound = _SliceUnspecifiedBound()[1:]
class WireData(binary_type):
@@ -40,26 +45,40 @@ class WireData(binary_type):
def __getitem__(self, key):
try:
if isinstance(key, slice):
- return WireData(super(WireData, self).__getitem__(key))
+ # make sure we are not going outside of valid ranges,
+ # do stricter control of boundaries than python does
+ # by default
+ start = key.start
+ stop = key.stop
+
+ if sys.version_info < (3,):
+ if stop == _unspecified_bound:
+ # handle the case where the right bound is unspecified
+ stop = len(self)
+
+ if start < 0 or stop < 0:
+ raise dns.exception.FormError
+ # If it's not an empty slice, access left and right bounds
+ # to make sure they're valid
+ if start != stop:
+ super(WireData, self).__getitem__(start)
+ super(WireData, self).__getitem__(stop - 1)
+ else:
+ for index in (start, stop):
+ if index is None:
+ continue
+ elif abs(index) > len(self):
+ raise dns.exception.FormError
+
+ return WireData(super(WireData, self).__getitem__(
+ slice(start, stop)))
return bytearray(self.unwrap())[key]
except IndexError:
raise dns.exception.FormError
- def __getslice__(self, i, j):
- try:
- if j == _unspecified_bound:
- # handle the case where the right bound is unspecified
- j = len(self)
- if i < 0 or j < 0:
- raise dns.exception.FormError
- # If it's not an empty slice, access left and right bounds
- # to make sure they're valid
- if i != j:
- super(WireData, self).__getitem__(i)
- super(WireData, self).__getitem__(j - 1)
- return WireData(super(WireData, self).__getslice__(i, j))
- except IndexError:
- raise dns.exception.FormError
+ if sys.version_info < (3,):
+ def __getslice__(self, i, j): # pylint: disable=getslice-method
+ return self.__getitem__(slice(i, j))
def __iter__(self):
i = 0
diff --git a/eventlet/support/dns/zone.py b/eventlet/support/dns/zone.py
index 4a73e1e..468618f 100644
--- a/eventlet/support/dns/zone.py
+++ b/eventlet/support/dns/zone.py
@@ -19,6 +19,7 @@ from __future__ import generators
import sys
import re
+import os
from io import BytesIO
import dns.exception
@@ -498,18 +499,27 @@ class Zone(object):
@type nl: string or None
"""
- str_type = string_types
+ if isinstance(f, string_types):
+ f = open(f, 'wb')
+ want_close = True
+ else:
+ want_close = False
+
+ # must be in this way, f.encoding may contain None, or even attribute
+ # may not be there
+ file_enc = getattr(f, 'encoding', None)
+ if file_enc is None:
+ file_enc = 'utf-8'
if nl is None:
- opts = 'wb'
+ nl_b = os.linesep.encode(file_enc) # binary mode, '\n' is not enough
+ nl = u'\n'
+ elif isinstance(nl, string_types):
+ nl_b = nl.encode(file_enc)
else:
- opts = 'wb'
+ nl_b = nl
+ nl = nl.decode()
- if isinstance(f, str_type):
- f = open(f, opts)
- want_close = True
- else:
- want_close = False
try:
if sorted:
names = list(self.keys())
@@ -520,11 +530,15 @@ class Zone(object):
l = self[n].to_text(n, origin=self.origin,
relativize=relativize)
if isinstance(l, text_type):
- l = l.encode()
- if nl is None:
- f.write(l)
- f.write('\n')
+ l_b = l.encode(file_enc)
else:
+ l_b = l
+ l = l.decode()
+
+ try:
+ f.write(l_b)
+ f.write(nl_b)
+ except TypeError: # textual mode
f.write(l)
f.write(nl)
finally:
@@ -658,7 +672,7 @@ class _MasterReader(object):
raise dns.exception.SyntaxError
except dns.exception.SyntaxError:
raise dns.exception.SyntaxError
- except:
+ except Exception:
rdclass = self.zone.rdclass
if rdclass != self.zone.rdclass:
raise dns.exception.SyntaxError("RR class is not zone's class")
@@ -777,7 +791,7 @@ class _MasterReader(object):
raise dns.exception.SyntaxError
except dns.exception.SyntaxError:
raise dns.exception.SyntaxError
- except:
+ except Exception:
rdclass = self.zone.rdclass
if rdclass != self.zone.rdclass:
raise dns.exception.SyntaxError("RR class is not zone's class")
@@ -787,7 +801,7 @@ class _MasterReader(object):
token = self.tok.get()
if not token.is_identifier():
raise dns.exception.SyntaxError
- except:
+ except Exception:
raise dns.exception.SyntaxError("unknown rdatatype '%s'" %
token.value)