Upgrade bundled dnspython to fix DNS resolution
The version introduced in commit [1] ([2]) has a major 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]52b09becac
[2]188aa701a6
[3] https://github.com/rthalley/dnspython/issues/206 [4]292995db18
This commit is contained in:
@@ -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"
|
||||
|
@@ -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():
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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)):
|
||||
|
@@ -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)
|
||||
|
@@ -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,
|
||||
}
|
||||
|
23
eventlet/support/dns/rdtypes/ANY/AVC.py
Normal file
23
eventlet/support/dns/rdtypes/ANY/AVC.py
Normal file
@@ -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}"""
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -95,4 +95,3 @@ class ISDN(dns.rdata.Rdata):
|
||||
else:
|
||||
subaddress = ''
|
||||
return cls(rdclass, rdtype, address, subaddress)
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -189,4 +189,3 @@ class NSEC3(dns.rdata.Rdata):
|
||||
windows.append((window, bitmap))
|
||||
return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
|
||||
windows)
|
||||
|
||||
|
@@ -86,4 +86,3 @@ class NSEC3PARAM(dns.rdata.Rdata):
|
||||
if rdlen != 0:
|
||||
raise dns.exception.FormError
|
||||
return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -78,4 +78,3 @@ class URI(dns.rdata.Rdata):
|
||||
current += rdlen
|
||||
|
||||
return cls(rdclass, rdtype, priority, weight, target)
|
||||
|
||||
|
@@ -62,4 +62,3 @@ class X25(dns.rdata.Rdata):
|
||||
raise dns.exception.FormError
|
||||
address = wire[current: current + l].unwrap()
|
||||
return cls(rdclass, rdtype, address)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -103,4 +103,3 @@ class WKS(dns.rdata.Rdata):
|
||||
rdlen -= 5
|
||||
bitmap = wire[current: current + rdlen].unwrap()
|
||||
return cls(rdclass, rdtype, address, protocol, bitmap)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -88,4 +88,3 @@ class TXTBase(dns.rdata.Rdata):
|
||||
rdlen -= l
|
||||
strings.append(s)
|
||||
return cls(rdclass, rdtype, strings)
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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")
|
||||
|
@@ -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}?
|
||||
|
||||
|
@@ -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
|
||||
|
||||
_unspecified_bound = _SliceUnspecifiedBound('')[1:]
|
||||
if sys.version_info < (3,):
|
||||
def __getslice__(self, i, j): # pylint: disable=getslice-method
|
||||
return self.__getitem__(slice(i, j))
|
||||
|
||||
_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
|
||||
|
@@ -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 nl is None:
|
||||
opts = 'wb'
|
||||
else:
|
||||
opts = 'wb'
|
||||
|
||||
if isinstance(f, str_type):
|
||||
f = open(f, opts)
|
||||
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:
|
||||
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:
|
||||
nl_b = nl
|
||||
nl = nl.decode()
|
||||
|
||||
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)
|
||||
|
||||
|
Reference in New Issue
Block a user