[Python-modules-commits] [dnspython3] 01/03: Import dnspython3_1.12.0.orig.tar.gz
Scott Kitterman
kitterman at moszumanska.debian.org
Thu Jan 14 05:18:54 UTC 2016
This is an automated email from the git hooks/post-receive script.
kitterman pushed a commit to branch master
in repository dnspython3.
commit 11befa72e1fe52835c1e25557601cbef51abf2b6
Author: Scott Kitterman <scott at kitterman.com>
Date: Thu Jan 14 00:16:13 2016 -0500
Import dnspython3_1.12.0.orig.tar.gz
---
ChangeLog | 73 +++++++++++++
PKG-INFO | 4 +-
README | 40 ++++++-
dns/dnssec.py | 2 +
dns/inet.py | 7 +-
dns/ipv6.py | 5 +
dns/message.py | 15 ++-
dns/name.py | 24 ++++-
dns/query.py | 17 ++-
dns/rdtypes/ANY/DNSKEY.py | 48 +++++++++
dns/rdtypes/ANY/LOC.py | 28 +++--
dns/rdtypes/ANY/NSEC3PARAM.py | 1 +
dns/rdtypes/ANY/RRSIG.py | 2 +-
dns/rdtypes/IN/APL.py | 4 +-
dns/resolver.py | 7 ++
dns/reversename.py | 9 +-
dns/tsig.py | 16 +++
dns/version.py | 4 +-
dns/zone.py | 28 ++++-
setup.py | 2 +-
tests/Makefile | 5 +-
tests/example3.good | 117 +++++++++++++++++++++
tests/{bugs.py => test_bugs.py} | 8 ++
tests/{dnssec.py => test_dnssec.py} | 14 +++
tests/{flags.py => test_flags.py} | 0
tests/{generate.py => test_generate.py} | 0
tests/{message.py => test_message.py} | 0
tests/{name.py => test_name.py} | 5 +
tests/{namedict.py => test_namedict.py} | 0
tests/{ntoaaton.py => test_ntoaaton.py} | 8 ++
.../{rdtypeandclass.py => test_rdtypeandclass.py} | 0
tests/test_rdtypeanydnskey.py | 68 ++++++++++++
tests/{resolver.py => test_resolver.py} | 0
tests/{rrset.py => test_rrset.py} | 0
tests/{set.py => test_set.py} | 0
tests/{tokenizer.py => test_tokenizer.py} | 0
tests/{update.py => test_update.py} | 0
tests/{zone.py => test_zone.py} | 23 ++++
tests/utest.py | 8 ++
39 files changed, 551 insertions(+), 41 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index a66722c..b28613f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,76 @@
+2014-09-01 Bob Halley <halley at dnspython.org>
+
+ * (Version 1.12.0 released)
+
+2014-08-31 Bob Halley <halley at dnspython.org>
+
+ * The test system can now run the tests without requiring dnspython
+ to be installed.
+
+ * When reading from a masterfile, if the first content line started
+ with leading whitespace, we raised an ugly exception instead of
+ doing the right thing, namely using the zone origin as the name.
+ [#73] Thanks to Tassatux for reporting the issue.
+
+ * Added dns.zone.to_text() convenience method. Thanks to Brandon
+ Whaley <redkrieg at gmail.com> for the patch.
+
+ * The /etc/resolv.conf setting "options rotate" is now understood
+ by the resolver. If present, the resolver will shuffle the
+ nameserver list each time dns.resolver.query() is called. Thanks
+ to underrun for the patch. Note that you don't want to add
+ "options rotate" to your /etc/resolv.conf if your system's
+ resolver library does not understand it. In this case, just set
+ resolver.rotate = True by hand.
+
+ * Escaping of Unicode has been corrected. Previously we escaped
+ and then converted to Unicode, but the right thing to do is
+ convert to Unicode, then escape. Also, characters > 0x7f should
+ NOT be escaped in Unicode mode. Thanks to Martin Basti for the
+ patch.
+
+ * dns.rdtypes.ANY.DNSKEY now has helpers functions to convert
+ between the numeric form of the flags and a set of human-friendly
+ strings. Thanks to Petr Spacek for the patch.
+
+ * RRSIGs did not respect relativization settings in to_text().
+ Thanks to Brian Smith for reporting the bug and submitting a
+ (slightly different) patch.
+
+ * dns/rdtypes/IN/APL.py: The APL from_wire() method did not accept
+ an rdata length of 0 as valid. Thanks to salzmdan for reporting
+ the problem.
+
+2014-05-31 Bob Halley <halley at dnspython.org>
+
+ * dns/ipv6.py: Add is_mapped()
+
+ * dns/reversename.py: Lookup IPv6 mapped IPv4 addresses in the v4
+ reverse namespace. Thanks to Devin Bayer. Yes, I finally fixed
+ this one :)
+
+2014-04-11 Bob Halley <halley at dnspython.org>
+
+ * dns/zone.py: Do not put back an unescaped token. This was
+ causing escape processing for domain names to break. Thanks to
+ connormclaud for reporting the problem.
+
+2014-04-04 Bob Halley <halley at dnspython.org>
+
+ * dns/message.py: Making a response didn't work correctly if the
+ query was signed with TSIG and we knew the key. Thanks to Jeffrey
+ Stiles for reporting the problem.
+
+2014-01-10 Bob Halley <halley at ndnspython.org>
+
+ * dns/inet.py (is_multicast): Removed lingering ord()s.
+
+2013-12-11 Bob Halley <halley at dnspython.org>
+
+ * dns/query.py: Fix problems with the IXFR state machine which caused
+ long diffs to fail. Thanks to James Raftery for the fix and the
+ repeated prodding to get it applied :)
+
2013-09-02 Bob Halley <halley at dnspython.org>
* (Version 1.11.1 released)
diff --git a/PKG-INFO b/PKG-INFO
index c80abaa..41339a7 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: dnspython3
-Version: 1.11.1
+Version: 1.12.0
Summary: DNS toolkit
Home-page: http://www.dnspython.org
Author: Bob Halley
Author-email: halley at dnspython.org
License: BSD-like
-Download-URL: http://www.dnspython.org/kits3/1.11.1/dnspython3-1.11.1.tar.gz
+Download-URL: http://www.dnspython.org/kits3/1.12.0/dnspython3-1.12.0.tar.gz
Description: dnspython3 is a DNS toolkit for Python 3. It supports almost all
record types. It can be used for queries, zone transfers, and dynamic
updates. It supports TSIG authenticated messages and EDNS0.
diff --git a/README b/README
index f4bd391..2ea6151 100644
--- a/README
+++ b/README
@@ -22,7 +22,45 @@ development by continuing to employ the author :).
ABOUT THIS RELEASE
-This is dnspython3 1.11.1
+This is dnspython3 1.12.0
+
+New since 1.11.1:
+
+ Added dns.zone.to_text().
+
+ Added support for "options rotate" in /etc/resolv.conf.
+
+ dns.rdtypes.ANY.DNSKEY now has helpers functions to convert
+ between the numeric form of the flags and a set of
+ human-friendly strings
+
+ The reverse name of an IPv6 mapped IPv4 address is now in the
+ IPv4 reverse namespace.
+
+ The test system can now run the tests without requiring
+ dnspython to be installed.
+
+Bugs fixed since 1.11.1:
+
+ dnspython raised an exception when reading a masterfile starting
+ with leading whitespace
+
+ dnspython was affected by a python slicing API bug present on
+ 64-bit windows.
+
+ Unicode escaping was applied at the wrong time.
+
+ RRSIG to_text() did not respect the relativize setting.
+
+ APL RRs with zero rdlength were rejected.
+
+ The tokenizer could put back an unescaped token.
+
+ Making a response to a message signed with TSIG was broken.
+
+ The IXFR state machine didn't handle long IXFR diffs.
+
+ dns.inet.is_multicast had python3 port issues.
New since 1.11.0:
diff --git a/dns/dnssec.py b/dns/dnssec.py
index c1cd1cb..2dd4a67 100644
--- a/dns/dnssec.py
+++ b/dns/dnssec.py
@@ -370,6 +370,8 @@ try:
import Crypto.Util.number
validate = _validate
validate_rrsig = _validate_rrsig
+ _have_pycrypto = True
except ImportError:
validate = _need_pycrypto
validate_rrsig = _need_pycrypto
+ _have_pycrypto = False
diff --git a/dns/inet.py b/dns/inet.py
index 3b7e88f..56a1bd7 100644
--- a/dns/inet.py
+++ b/dns/inet.py
@@ -45,7 +45,7 @@ def inet_pton(family, text):
implemented.
@rtype: string
"""
-
+
if family == AF_INET:
return dns.ipv4.inet_aton(text)
elif family == AF_INET6:
@@ -97,12 +97,11 @@ def is_multicast(text):
@rtype: bool
"""
try:
- first = ord(dns.ipv4.inet_aton(text)[0])
+ first = dns.ipv4.inet_aton(text)[0]
return (first >= 224 and first <= 239)
except:
try:
- first = ord(dns.ipv6.inet_aton(text)[0])
+ first = dns.ipv6.inet_aton(text)[0]
return (first == 255)
except:
raise ValueError
-
diff --git a/dns/ipv6.py b/dns/ipv6.py
index 73f6232..e2c0164 100644
--- a/dns/ipv6.py
+++ b/dns/ipv6.py
@@ -155,3 +155,8 @@ def inet_aton(text):
return bytes.fromhex(text)
except:
raise dns.exception.SyntaxError
+
+_mapped_prefix = b'\x00' * 10 + b'\xff\xff'
+
+def is_mapped(address):
+ return address.startswith(_mapped_prefix)
diff --git a/dns/message.py b/dns/message.py
index 85096f3..869a247 100644
--- a/dns/message.py
+++ b/dns/message.py
@@ -666,6 +666,10 @@ class _WireReader(object):
secret = self.message.keyring.get(absolute_name)
if secret is None:
raise UnknownTSIGKey("key '%s' unknown" % name)
+ self.message.keyname = absolute_name
+ (self.message.keyalgorithm, self.message.mac) = \
+ dns.tsig.get_algorithm_and_mac(self.wire, self.current,
+ rdlen)
self.message.tsig_ctx = \
dns.tsig.validate(self.wire,
absolute_name,
@@ -1065,7 +1069,8 @@ def make_query(qname, rdtype, rdclass = dns.rdataclass.IN, use_edns=None,
m.want_dnssec(want_dnssec)
return m
-def make_response(query, recursion_available=False, our_payload=8192):
+def make_response(query, recursion_available=False, our_payload=8192,
+ fudge=300):
"""Make a message which is a response for the specified query.
The message returned is really a response skeleton; it has all
of the infrastructure required of a response, but none of the
@@ -1082,6 +1087,8 @@ def make_response(query, recursion_available=False, our_payload=8192):
@param our_payload: payload size to advertise in EDNS responses; default
is 8192.
@type our_payload: int
+ @param fudge: TSIG time fudge; default is 300 seconds.
+ @type fudge: int
@rtype: dns.message.Message object"""
if query.flags & dns.flags.QR:
@@ -1094,8 +1101,8 @@ def make_response(query, recursion_available=False, our_payload=8192):
response.question = list(query.question)
if query.edns >= 0:
response.use_edns(0, 0, our_payload, query.payload)
- if not query.keyname is None:
- response.keyname = query.keyname
- response.keyring = query.keyring
+ if query.had_tsig:
+ response.use_tsig(query.keyring, query.keyname, fudge, None, 0, '',
+ query.keyalgorithm)
response.request_mac = query.mac
return response
diff --git a/dns/name.py b/dns/name.py
index 3d3b1be..daa5261 100644
--- a/dns/name.py
+++ b/dns/name.py
@@ -25,6 +25,7 @@ import encodings.idna
import io
import struct
import sys
+import copy
import dns.exception
import dns.util
@@ -95,6 +96,20 @@ def _escapify(label):
text += '\\%03d' % c
return text
+def _escapify_unicode(label):
+ """Escape the characters in label which need it.
+ @returns: the escaped string
+ @rtype: string"""
+ text = ''
+ for c in label:
+ if ord(c) in _escaped:
+ text += '\\' + c
+ elif ord(c) > 0x20:
+ text += c
+ else:
+ text += '\\%03d' % ord(c)
+ return text
+
def _bytesify(label):
if isinstance(label, str):
return label.encode('latin_1')
@@ -156,6 +171,12 @@ class Name(object):
def __setattr__(self, name, value):
raise TypeError("object doesn't support attribute assignment")
+ def __copy__(self):
+ return Name(self.labels)
+
+ def __deepcopy__(self, memo):
+ return Name(copy.deepcopy(self.labels, memo))
+
def is_absolute(self):
"""Is the most significant label of this name the root label?
@rtype: bool
@@ -353,7 +374,8 @@ class Name(object):
l = self.labels[:-1]
else:
l = self.labels
- s = '.'.join([encodings.idna.ToUnicode(_escapify(x)) for x in l])
+ s = '.'.join([_escapify_unicode(encodings.idna.ToUnicode(x))
+ for x in l])
return s
def to_digestable(self, origin=None):
diff --git a/dns/query.py b/dns/query.py
index 2dc3f80..2a252c7 100644
--- a/dns/query.py
+++ b/dns/query.py
@@ -411,6 +411,8 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
tcpmsg = struct.pack("!H", l) + wire
_net_write(s, tcpmsg, expiration)
done = False
+ delete_mode = True
+ expecting_SOA = False
soa_rrset = None
soa_count = 0
if relativize:
@@ -439,18 +441,16 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
tsig_ctx = r.tsig_ctx
first = False
answer_index = 0
- delete_mode = False
- expecting_SOA = False
if soa_rrset is None:
if not r.answer or r.answer[0].name != oname:
- raise dns.exception.FormError
+ raise dns.exception.FormError("No answer or RRset not for qname")
rrset = r.answer[0]
if rrset.rdtype != dns.rdatatype.SOA:
raise dns.exception.FormError("first RRset is not an SOA")
answer_index = 1
soa_rrset = rrset.copy()
if rdtype == dns.rdatatype.IXFR:
- if soa_rrset[0].serial == serial:
+ if soa_rrset[0].serial <= serial:
#
# We're already up-to-date.
#
@@ -471,7 +471,14 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
expecting_SOA = False
elif rdtype == dns.rdatatype.IXFR:
delete_mode = not delete_mode
- if rrset == soa_rrset and not delete_mode:
+ #
+ # If this SOA RRset is equal to the first we saw then we're
+ # finished. If this is an IXFR we also check that we're seeing
+ # the record in the expected part of the response.
+ #
+ if rrset == soa_rrset and \
+ (rdtype == dns.rdatatype.AXFR or \
+ (rdtype == dns.rdatatype.IXFR and delete_mode)):
done = True
elif expecting_SOA:
#
diff --git a/dns/rdtypes/ANY/DNSKEY.py b/dns/rdtypes/ANY/DNSKEY.py
index 3673b2a..246a2fd 100644
--- a/dns/rdtypes/ANY/DNSKEY.py
+++ b/dns/rdtypes/ANY/DNSKEY.py
@@ -21,11 +21,54 @@ import dns.dnssec
import dns.rdata
import dns.util
+
# flag constants
SEP = 0x0001
REVOKE = 0x0080
ZONE = 0x0100
+_flag_by_text = {
+ 'SEP': SEP,
+ 'REVOKE': REVOKE,
+ 'ZONE': ZONE
+ }
+
+# We construct the inverse mapping programmatically to ensure that we
+# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that
+# would cause the mapping not to be true inverse.
+_flag_by_value = dict([(y, x) for x, y in _flag_by_text.items()])
+
+
+def flags_to_text_set(flags):
+ """Convert a DNSKEY flags value to set texts
+ @rtype: set([string])"""
+
+ flags_set = set()
+ mask = 0x1
+ while mask <= 0x8000:
+ if flags & mask:
+ text = _flag_by_value.get(mask)
+ if not text:
+ text = hex(mask)
+ flags_set.add(text)
+ mask <<= 1
+ return flags_set
+
+
+def flags_from_text_set(texts_set):
+ """Convert set of DNSKEY flag mnemonic texts to DNSKEY flag value
+ @rtype: int"""
+
+ flags = 0
+ for text in texts_set:
+ try:
+ flags += _flag_by_text[text]
+ except KeyError:
+ raise NotImplementedError(
+ "DNSKEY flag '%s' is not supported" % text)
+ return flags
+
+
class DNSKEY(dns.rdata.Rdata):
"""DNSKEY record
@@ -91,3 +134,8 @@ class DNSKEY(dns.rdata.Rdata):
if v == 0:
v = dns.util.cmp(self.key, other.key)
return v
+
+ def flags_to_text_set(self):
+ """Convert a DNSKEY flags value to set texts
+ @rtype: set([string])"""
+ return flags_to_text_set(self.flags)
diff --git a/dns/rdtypes/ANY/LOC.py b/dns/rdtypes/ANY/LOC.py
index 64b50c9..0c9bbdd 100644
--- a/dns/rdtypes/ANY/LOC.py
+++ b/dns/rdtypes/ANY/LOC.py
@@ -23,7 +23,14 @@ import dns.util
_pows = (1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
100000000, 1000000000, 10000000000)
+# default values are in centimeters
+_default_size = 100.0
+_default_hprec = 1000000.0
+_default_vprec = 1000.0
+
def _exponent_of(what, desc):
+ if what == 0:
+ return 0
exp = None
for i in range(len(_pows)):
if what // _pows[i] == 0:
@@ -98,13 +105,14 @@ class LOC(dns.rdata.Rdata):
'horizontal_precision', 'vertical_precision']
def __init__(self, rdclass, rdtype, latitude, longitude, altitude,
- size=1.0, hprec=10000.0, vprec=10.0):
+ size=_default_size, hprec=_default_hprec, vprec=_default_vprec):
"""Initialize a LOC record instance.
The parameters I{latitude} and I{longitude} may be either a 4-tuple
of integers specifying (degrees, minutes, seconds, milliseconds),
or they may be floating point values specifying the number of
- degrees. The other parameters are floats."""
+ degrees. The other parameters are floats. Size, horizontal precision,
+ and vertical precision are specified in centimeters."""
super(LOC, self).__init__(rdclass, rdtype)
if isinstance(latitude, int):
@@ -141,8 +149,10 @@ class LOC(dns.rdata.Rdata):
self.longitude[3], long_hemisphere, self.altitude / 100.0
)
- if self.size != 1.0 or self.horizontal_precision != 10000.0 or \
- self.vertical_precision != 10.0:
+ # do not print default values
+ if self.size != _default_size or \
+ self.horizontal_precision != _default_hprec or \
+ self.vertical_precision != _default_vprec:
text += " %0.2fm %0.2fm %0.2fm" % (
self.size / 100.0, self.horizontal_precision / 100.0,
self.vertical_precision / 100.0
@@ -152,9 +162,9 @@ class LOC(dns.rdata.Rdata):
def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
latitude = [0, 0, 0, 0]
longitude = [0, 0, 0, 0]
- size = 1.0
- hprec = 10000.0
- vprec = 10.0
+ size = _default_size
+ hprec = _default_hprec
+ vprec = _default_vprec
latitude[0] = tok.get_int()
t = tok.get_string()
@@ -240,8 +250,8 @@ class LOC(dns.rdata.Rdata):
value = token.value
if value[-1] == 'm':
value = value[0 : -1]
- vprec = float(value) * 100.0 # m -> cm
- tok.get_eol()
+ vprec = float(value) * 100.0 # m -> cm
+ tok.get_eol()
return cls(rdclass, rdtype, latitude, longitude, altitude,
size, hprec, vprec)
diff --git a/dns/rdtypes/ANY/NSEC3PARAM.py b/dns/rdtypes/ANY/NSEC3PARAM.py
index f323d3f..ede6863 100644
--- a/dns/rdtypes/ANY/NSEC3PARAM.py
+++ b/dns/rdtypes/ANY/NSEC3PARAM.py
@@ -58,6 +58,7 @@ class NSEC3PARAM(dns.rdata.Rdata):
salt = b''
else:
salt = bytes.fromhex(salt)
+ tok.get_eol()
return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
from_text = classmethod(from_text)
diff --git a/dns/rdtypes/ANY/RRSIG.py b/dns/rdtypes/ANY/RRSIG.py
index 2e69821..b45e0c9 100644
--- a/dns/rdtypes/ANY/RRSIG.py
+++ b/dns/rdtypes/ANY/RRSIG.py
@@ -95,7 +95,7 @@ class RRSIG(dns.rdata.Rdata):
posixtime_to_sigtime(self.expiration),
posixtime_to_sigtime(self.inception),
self.key_tag,
- self.signer,
+ self.signer.choose_relativity(origin, relativize),
dns.rdata._base64ify(self.signature)
)
diff --git a/dns/rdtypes/IN/APL.py b/dns/rdtypes/IN/APL.py
index a7b8510..58e35b6 100644
--- a/dns/rdtypes/IN/APL.py
+++ b/dns/rdtypes/IN/APL.py
@@ -119,6 +119,8 @@ class APL(dns.rdata.Rdata):
def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
items = []
while 1:
+ if rdlen == 0:
+ break
if rdlen < 4:
raise dns.exception.FormError
header = struct.unpack('!HBB', wire[current : current + 4])
@@ -152,8 +154,6 @@ class APL(dns.rdata.Rdata):
rdlen -= afdlen
item = APLItem(header[0], negation, address, header[1])
items.append(item)
- if rdlen == 0:
- break
return cls(rdclass, rdtype, items)
from_wire = classmethod(from_wire)
diff --git a/dns/resolver.py b/dns/resolver.py
index 2d28f70..3d3cccb 100644
--- a/dns/resolver.py
+++ b/dns/resolver.py
@@ -21,6 +21,7 @@
import socket
import sys
import time
+import random
try:
import threading as _threading
@@ -510,6 +511,7 @@ class Resolver(object):
self.cache = None
self.flags = None
self.retry_servfail = False
+ self.rotate = False
def read_resolv_conf(self, f):
"""Process f as a file in the /etc/resolv.conf format. If f is
@@ -540,6 +542,9 @@ class Resolver(object):
elif tokens[0] == 'search':
for suffix in tokens[1:]:
self.search.append(dns.name.from_text(suffix))
+ elif tokens[0] == 'options':
+ if 'rotate' in tokens[1:]:
+ self.rotate = True
finally:
if want_close:
f.close()
@@ -808,6 +813,8 @@ class Resolver(object):
# make a copy of the servers list so we can alter it later.
#
nameservers = self.nameservers[:]
+ if self.rotate:
+ random.shuffle(nameservers)
backoff = 0.10
while response is None:
if len(nameservers) == 0:
diff --git a/dns/reversename.py b/dns/reversename.py
index f8bd9e0..276393c 100644
--- a/dns/reversename.py
+++ b/dns/reversename.py
@@ -39,8 +39,13 @@ def from_address(text):
@rtype: dns.name.Name object
"""
try:
- parts = ['%x.%x' % (byte & 0x0f, byte >> 4) for byte in dns.ipv6.inet_aton(text)]
- origin = ipv6_reverse_domain
+ v6 = dns.ipv6.inet_aton(text)
+ if dns.ipv6.is_mapped(v6):
+ parts = ['%d' % byte for byte in v6[12:]]
+ origin = ipv4_reverse_domain
+ else:
+ parts = ['%x.%x' % (byte & 0x0f, byte >> 4) for byte in v6]
+ origin = ipv6_reverse_domain
except:
parts = ['%d' % byte for byte in dns.ipv4.inet_aton(text)]
origin = ipv4_reverse_domain
diff --git a/dns/tsig.py b/dns/tsig.py
index 6d801d4..4333016 100644
--- a/dns/tsig.py
+++ b/dns/tsig.py
@@ -216,3 +216,19 @@ def get_algorithm(algorithm):
except KeyError:
raise NotImplementedError("TSIG algorithm " + str(algorithm) +
" is not supported")
+
+def get_algorithm_and_mac(wire, tsig_rdata, tsig_rdlen):
+ """Return the tsig algorithm for the specified tsig_rdata
+ @raises FormError: The TSIG is badly formed.
+ """
+ current = tsig_rdata
+ (aname, used) = dns.name.from_wire(wire, current)
+ current = current + used
+ (upper_time, lower_time, fudge, mac_size) = \
+ struct.unpack("!HIHH", wire[current:current + 10])
+ current += 10
+ mac = wire[current:current + mac_size]
+ current += mac_size
+ if current > tsig_rdata + tsig_rdlen:
+ raise dns.exception.FormError
+ return (aname, mac)
diff --git a/dns/version.py b/dns/version.py
index c3d305e..c382279 100644
--- a/dns/version.py
+++ b/dns/version.py
@@ -16,8 +16,8 @@
"""dnspython release version information."""
MAJOR = 1
-MINOR = 11
-MICRO = 1
+MINOR = 12
+MICRO = 0
RELEASELEVEL = 0x0f
SERIAL = 0
diff --git a/dns/zone.py b/dns/zone.py
index 6d19409..ece898a 100644
--- a/dns/zone.py
+++ b/dns/zone.py
@@ -18,6 +18,7 @@
from __future__ import generators
import builtins
+import io
import re
import sys
@@ -491,6 +492,27 @@ class Zone(object):
if want_close:
f.close()
+ def to_text(self, sorted=True, relativize=True, nl=None):
+ """Return a zone's text as though it were written to a file.
+
+ @param sorted: if True, the file will be written with the
+ names sorted in DNSSEC order from least to greatest. Otherwise
+ the names will be written in whatever order they happen to have
+ in the zone's dictionary.
+ @param relativize: if True, domain names in the output will be
+ relativized to the zone's origin (if possible).
+ @type relativize: bool
+ @param nl: The end of line string. If not specified, the
+ output will use the platform's native end-of-line marker (i.e.
+ LF on POSIX, CRLF on Windows, CR on Macintosh).
+ @type nl: string or None
+ """
+ temp_buffer = io.BytesIO()
+ self.to_file(temp_buffer, sorted, relativize, nl)
+ return_value = temp_buffer.getvalue()
+ temp_buffer.close()
+ return return_value
+
def check_origin(self):
"""Do some simple checking of the zone's origin.
@@ -543,7 +565,7 @@ class _MasterReader(object):
self.current_origin = origin
self.relativize = relativize
self.ttl = 0
- self.last_name = None
+ self.last_name = self.current_origin
self.zone = zone_factory(origin, rdclass, relativize=relativize)
self.saved_state = []
self.current_file = None
@@ -798,7 +820,7 @@ class _MasterReader(object):
try:
while 1:
- token = self.tok.get(True, True).unescape()
+ token = self.tok.get(True, True)
if token.is_eof():
if not self.current_file is None:
self.current_file.close()
@@ -943,7 +965,7 @@ def from_file(f, origin = None, rdclass = dns.rdataclass.IN,
if isinstance(f, str):
if filename is None:
filename = f
- f = open(f, 'rU')
+ f = open(f, 'r')
want_close = True
else:
if filename is None:
diff --git a/setup.py b/setup.py
index 03bf2ca..23c2126 100755
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,7 @@
import sys
from distutils.core import setup
-version = '1.11.1'
+version = '1.12.0'
kwargs = {
'name' : 'dnspython3',
diff --git a/tests/Makefile b/tests/Makefile
index cd6e4fa..8c465df 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -20,7 +20,4 @@ PYTHON=python3
check: test
test:
- @for i in *.py; do \
- echo "Running $$i:"; \
- ${PYTHON} $$i || exit 1; \
- done
+ ${PYTHON} ./utest.py
diff --git a/tests/example3.good b/tests/example3.good
new file mode 100644
index 0000000..100842e
--- /dev/null
+++ b/tests/example3.good
@@ -0,0 +1,117 @@
+@ 300 IN SOA ns1 hostmaster 1 2000 2000 1814400 3600
+@ 300 IN NS ns1
+@ 300 IN NS ns2
+* 300 IN MX 10 mail
+a 300 IN TXT "foo foo foo"
+a 300 IN PTR foo.net.
+a01 3600 IN A 0.0.0.0
+a02 3600 IN A 255.255.255.255
+aaaa01 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+aaaa02 3600 IN AAAA ::1
+afsdb01 3600 IN AFSDB 0 hostname
+afsdb02 3600 IN AFSDB 65535 .
+apl01 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28
+apl02 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8
+b 300 IN CNAME foo.net.
+c 300 IN A 73.80.65.49
+cert01 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY=
+cname01 3600 IN CNAME cname-target.
+cname02 3600 IN CNAME cname-target
+cname03 3600 IN CNAME .
+d 300 IN A 73.80.65.49
+dhcid01 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA=
+dhcid02 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No=
+dhcid03 3600 IN DHCID AAABxLmlskllE0MVjd57zHcWmEH3pCQ6 VytcKD//7es/deY=
+dlv01 3600 IN DLV 12345 3 1 123456789abcdef67890123456789abcdef67890
+dname01 3600 IN DNAME dname-target.
+dname02 3600 IN DNAME dname-target
+dname03 3600 IN DNAME .
+dnskey01 3600 IN DNSKEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8=
+dnskey02 3600 IN DNSKEY 257 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8=
+ds01 3600 IN DS 12345 3 1 123456789abcdef67890123456789abcdef67890
+e 300 IN MX 10 mail
+e 300 IN TXT "one"
+e 300 IN TXT "three"
+e 300 IN TXT "two"
+e 300 IN A 73.80.65.49
+e 300 IN A 73.80.65.50
+e 300 IN A 73.80.65.52
+e 300 IN A 73.80.65.51
+f 300 IN A 73.80.65.52
+gpos01 3600 IN GPOS -22.6882 116.8652 250.0
+hinfo01 3600 IN HINFO "Generic PC clone" "NetBSD-1.4"
+hinfo02 3600 IN HINFO "PC" "NetBSD"
+hip01 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2
+ipseckey01 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+ipseckey02 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+ipseckey03 3600 IN IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+ipseckey04 3600 IN IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+ipseckey05 3600 IN IPSECKEY 10 3 2 mygateway2 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+isdn01 3600 IN ISDN "isdn-address"
+isdn02 3600 IN ISDN "isdn-address" "subaddress"
+isdn03 3600 IN ISDN "isdn-address"
+isdn04 3600 IN ISDN "isdn-address" "subaddress"
+kx01 3600 IN KX 10 kdc
+kx02 3600 IN KX 10 .
+loc01 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
+loc02 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
+loc03 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
+loc04 3600 IN LOC 60 9 1.500 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
+loc05 3600 IN LOC 60 9 1.510 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
+mx01 3600 IN MX 10 mail
+mx02 3600 IN MX 10 .
+naptr01 3600 IN NAPTR 0 0 "" "" "" .
+naptr02 3600 IN NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo.
+ns1 300 IN A 10.53.0.1
+ns2 300 IN A 10.53.0.2
+nsap-ptr01 3600 IN NSAP-PTR foo.
+nsap-ptr01 3600 IN NSAP-PTR .
+nsap01 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100
+nsap02 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100
+nsec01 3600 IN NSEC a.secure. A MX RRSIG NSEC TYPE1234
+nsec02 3600 IN NSEC . NSAP-PTR NSEC
+nsec03 3600 IN NSEC . NSEC TYPE65535
+nsec301 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
+nsec302 3600 IN NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
+nsec3param01 3600 IN NSEC3PARAM 1 1 12 aabbccdd
+nsec3param02 3600 IN NSEC3PARAM 1 1 12 -
+ptr01 3600 IN PTR @
+px01 3600 IN PX 65535 foo. bar.
+px02 3600 IN PX 65535 . .
+rp01 3600 IN RP mbox-dname txt-dname
+rp02 3600 IN RP . .
+rrsig01 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY=
+rt01 3600 IN RT 0 intermediate-host
+rt02 3600 IN RT 65535 .
+s 300 IN NS ns.s
+ns.s 300 IN A 73.80.65.49
+spf 3600 IN SPF "v=spf1 mx -all"
+srv01 3600 IN SRV 0 0 0 .
+srv02 3600 IN SRV 65535 65535 65535 old-slow-box.example.com.
+sshfp1 3600 IN SSHFP 1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab
+t 301 IN A 73.80.65.49
+tlsa1 3600 IN TLSA 3 1 1 a9cdf989b504fe5dca90c0d2167b6550570734f7c763e09fdf88904e06157065
+tlsa2 3600 IN TLSA 1 0 1 efddf0d915c7bdc5782c0881e1b2a95ad099fbdd06d7b1f77982d9364338d955
+tlsa3 3600 IN TLSA 1 0 2 81ee7f6c0ecc6b09b7785a9418f54432de630dd54dc6ee9e3c49de547708d236d4c413c3e97e44f969e635958aa410495844127c04883503e5b024cf7a8f6a94
+txt01 3600 IN TXT "foo"
+txt02 3600 IN TXT "foo" "bar"
+txt03 3600 IN TXT "foo"
+txt04 3600 IN TXT "foo" "bar"
+txt05 3600 IN TXT "foo bar"
+txt06 3600 IN TXT "foo bar"
+txt07 3600 IN TXT "foo bar"
+txt08 3600 IN TXT "foo\010bar"
+txt09 3600 IN TXT "foo\010bar"
+txt10 3600 IN TXT "foo bar"
+txt11 3600 IN TXT "\"foo\""
+txt12 3600 IN TXT "\"foo\""
+txt13 3600 IN TXT "foo"
+u 300 IN TXT "txt-not-in-nxt"
+a.u 300 IN A 73.80.65.49
+b.u 300 IN A 73.80.65.49
+unknown2 3600 IN TYPE999 \# 8 0a0000010a000001
+unknown3 3600 IN A 127.0.0.2
+wks01 3600 IN WKS 10.0.0.1 6 0 1 2 21 23
+wks02 3600 IN WKS 10.0.0.1 17 0 1 2 53
+wks03 3600 IN WKS 10.0.0.2 6 65535
+x2501 3600 IN X25 "123456789"
diff --git a/tests/bugs.py b/tests/test_bugs.py
similarity index 88%
rename from tests/bugs.py
rename to tests/test_bugs.py
index 79b30eb..906e0fd 100644
--- a/tests/bugs.py
+++ b/tests/test_bugs.py
@@ -52,5 +52,13 @@ class BugsTestCase(unittest.TestCase):
out4 = rd4.to_digestable(dns.name.from_text("test"))
self.assertTrue(binascii.hexlify(out4).decode('ascii') == '000101817f')
+ def test_zero_size_APL(self):
+ rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.APL,
+ "")
+ rdata2 = dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.APL,
+ b"", 0, 0)
+ self.assertTrue(rdata == rdata2)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/dnssec.py b/tests/test_dnssec.py
similarity index 93%
rename from tests/dnssec.py
rename to tests/test_dnssec.py
index f5fd54a..98c4788 100644
--- a/tests/dnssec.py
+++ b/tests/test_dnssec.py
@@ -99,22 +99,32 @@ example_ds_sha256 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS,
class DNSSECValidatorTestCase(unittest.TestCase):
+ @unittest.skipIf(not dns.dnssec._have_pycrypto,
+ "PyCrypto cannot be imported")
def testAbsoluteRSAGood(self):
dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when)
+ @unittest.skipIf(not dns.dnssec._have_pycrypto,
+ "PyCrypto cannot be imported")
def testDuplicateKeytag(self):
dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys_duplicate_keytag, None, when)
+ @unittest.skipIf(not dns.dnssec._have_pycrypto,
+ "PyCrypto cannot be imported")
def testAbsoluteRSABad(self):
def bad():
dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None,
when)
self.assertRaises(dns.dnssec.ValidationFailure, bad)
+ @unittest.skipIf(not dns.dnssec._have_pycrypto,
+ "PyCrypto cannot be imported")
def testRelativeRSAGood(self):
dns.dnssec.validate(rel_soa, rel_soa_rrsig, rel_keys,
abs_dnspython_org, when)
+ @unittest.skipIf(not dns.dnssec._have_pycrypto,
+ "PyCrypto cannot be imported")
def testRelativeRSABad(self):
def bad():
dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys,
@@ -125,10 +135,14 @@ class DNSSECValidatorTestCase(unittest.TestCase):
ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256')
self.assertTrue(ds == good_ds)
+ @unittest.skipIf(not dns.dnssec._have_pycrypto,
+ "PyCrypto cannot be imported")
def testAbsoluteDSAGood(self):
dns.dnssec.validate(abs_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None,
when2)
+ @unittest.skipIf(not dns.dnssec._have_pycrypto,
+ "PyCrypto cannot be imported")
def testAbsoluteDSABad(self):
def bad():
dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig,
diff --git a/tests/flags.py b/tests/test_flags.py
similarity index 100%
rename from tests/flags.py
rename to tests/test_flags.py
diff --git a/tests/generate.py b/tests/test_generate.py
similarity index 100%
rename from tests/generate.py
rename to tests/test_generate.py
diff --git a/tests/message.py b/tests/test_message.py
similarity index 100%
rename from tests/message.py
rename to tests/test_message.py
diff --git a/tests/name.py b/tests/test_name.py
similarity index 99%
rename from tests/name.py
rename to tests/test_name.py
index 2139409..c125a15 100644
--- a/tests/name.py
... 193 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/dnspython3.git
More information about the Python-modules-commits
mailing list