diff --git a/MANIFEST.in b/MANIFEST.in index a2b6ef55..7b2a9cea 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -52,5 +52,5 @@ include doc/de/*.1 doc/de/*.5 include doc/Makefile include doc/examples/*.sh doc/examples/*.bat doc/examples/*.py include doc/examples/linkcheckerrc_loginurl -include linkcheck/dns/changelog.txt +recursive-include third_party * recursive-include tests *.py *.result *.html *.ico *.txt *.zip *.asc *.css *.xhtml *.sqlite *.adr *.swf diff --git a/Makefile b/Makefile index 4ec03b9c..da43e94d 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,10 @@ PAGER ?= less BUILDDIR:=$(HOME)/packages/official DEB_ORIG_TARGET:=$(BUILDDIR)/linkchecker_$(VERSION).orig.tar.bz2 # original dnspython repository module -DNSPYTHON:=$(HOME)/src/dnspython-git/dns +DNSPYTHON:=$(HOME)/src/dnspython-git # options to run the pep8 utility PEP8OPTS:=--repeat --ignore=E211,E501,E225,E301,E302,E241 \ - --exclude="dns,gzip2.py,httplib2.py,robotparser2.py,reindent.py" + --exclude="gzip2.py,httplib2.py,robotparser2.py,reindent.py" PY2APPOPTS ?= @@ -223,9 +223,12 @@ diff: diff -u linkcheck/$${f}2.py $(PYTHONSRC)/$${f}.py | $(PAGER); \ done +# Compare dnspython files with the ones from upstream repository .PHONY: dnsdiff dnsdiff: - diff -BurN --exclude=changelog.txt linkcheck/dns $(DNSPYTHON) | $(PAGER) + @(for d in dns tests; do \ + diff -BurN --exclude=*.pyc third_party/dnspython/$$d $(DNSPYTHON)/$$d; \ + done) | $(PAGER) .PHONY: changelog changelog: diff --git a/linkcheck/__init__.py b/linkcheck/__init__.py index 2c5b89ca..aed9e813 100644 --- a/linkcheck/__init__.py +++ b/linkcheck/__init__.py @@ -56,7 +56,6 @@ def get_config_dir (): LOG_ROOT = "linkcheck" LOG_CMDLINE = "linkcheck.cmdline" LOG_CHECK = "linkcheck.check" -LOG_DNS = "linkcheck.dns" LOG_CACHE = "linkcheck.cache" LOG_GUI = "linkcheck.gui" LOG_THREAD = "linkcheck.thread" @@ -65,7 +64,6 @@ lognames = { "checking": LOG_CHECK, "cache": LOG_CACHE, "gui": LOG_GUI, - "dns": LOG_DNS, "thread": LOG_THREAD, "all": LOG_ROOT, } @@ -136,7 +134,7 @@ def init_i18n (): logging.addLevelName(logging.DEBUG, _('DEBUG')) logging.addLevelName(logging.NOTSET, _('NOTSET')) -# initialize i18n, puts _() function into global namespace +# initialize i18n, puts _() and _n() function into global namespace init_i18n() @@ -149,3 +147,13 @@ def drop_privileges (): "dropping privileges by changing user to nobody.")) import pwd os.seteuid(pwd.getpwnam('nobody')[3]) + + +def find_third_party_modules (): + """Find third party modules and add them to the python path.""" + parent = os.path.dirname(os.path.dirname(__file__)) + third_party = os.path.join(parent, "third_party") + if os.path.isdir(third_party): + sys.path.append(os.path.join(third_party, "dnspython")) + +find_third_party_modules() diff --git a/linkcheck/checker/const.py b/linkcheck/checker/const.py index fdf821c7..5a1a7097 100644 --- a/linkcheck/checker/const.py +++ b/linkcheck/checker/const.py @@ -23,7 +23,7 @@ import nntplib import ftplib import httplib as orighttplib from .. import LinkCheckerError, httplib2 as httplib -from ..dns.exception import DNSException +from dns.exception import DNSException # Catch these exception on syntax checks. ExcSyntaxList = [ diff --git a/linkcheck/checker/mailtourl.py b/linkcheck/checker/mailtourl.py index 3d14c886..394a475c 100644 --- a/linkcheck/checker/mailtourl.py +++ b/linkcheck/checker/mailtourl.py @@ -27,11 +27,11 @@ from email._parseaddr import AddressList from . import urlbase from .. import log, LOG_CHECK, strformat, url as urlutil -from ..dns import resolver +from dns import resolver if False: # needed for py2exe to properly include all dns submodules - from ..dns.rdtypes.ANY import * - from ..dns.rdtypes.IN import * + from dns.rdtypes.ANY import * + from dns.rdtypes.IN import * from ..network import iputil from .const import WARN_MAIL_NO_MX_HOST, \ WARN_MAIL_UNVERIFIED_ADDRESS, WARN_MAIL_NO_CONNECTION @@ -249,7 +249,7 @@ class MailtoUrl (urlbase.UrlBase): """ Check a single mail address. """ - from ..dns.exception import DNSException + from dns.exception import DNSException log.debug(LOG_CHECK, "checking mail address %r", mail) mail = strformat.ascii_safe(mail) username, domain = mail.rsplit('@', 1) @@ -275,7 +275,7 @@ class MailtoUrl (urlbase.UrlBase): mxdata = [(0, rdata.to_text(omit_final_dot=True)) for rdata in answers] else: - from linkcheck.dns.rdtypes.mxbase import MXBase + from dns.rdtypes.mxbase import MXBase mxdata = [(rdata.preference, rdata.exchange.to_text(omit_final_dot=True)) for rdata in answers if isinstance(rdata, MXBase)] diff --git a/linkcheck/dns/dnssec.py b/linkcheck/dns/dnssec.py deleted file mode 100644 index 448ba1c7..00000000 --- a/linkcheck/dns/dnssec.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009 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. - -"""Common DNSSEC-related functions and constants.""" - -import linkcheck.dns.name -import linkcheck.dns.rdata -import linkcheck.dns.rdatatype -import linkcheck.dns.rdataclass - -RSAMD5 = 1 -DH = 2 -DSA = 3 -ECC = 4 -RSASHA1 = 5 -DSANSEC3SHA1 = 6 -RSASHA1NSEC3SHA1 = 7 -RSASHA256 = 8 -RSASHA512 = 10 -INDIRECT = 252 -PRIVATEDNS = 253 -PRIVATEOID = 254 - -_algorithm_by_text = { - 'RSAMD5' : RSAMD5, - 'DH' : DH, - 'DSA' : DSA, - 'ECC' : ECC, - 'RSASHA1' : RSASHA1, - 'DSANSEC3SHA1' : DSANSEC3SHA1, - 'RSASHA1NSEC3SHA1' : RSASHA1NSEC3SHA1, - 'RSASHA256' : RSASHA256, - 'RSASHA512' : RSASHA512, - 'INDIRECT' : INDIRECT, - 'PRIVATEDNS' : PRIVATEDNS, - 'PRIVATEOID' : PRIVATEOID, - } - -# 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. - -_algorithm_by_value = dict([(y, x) for x, y in _algorithm_by_text.iteritems()]) - -class UnknownAlgorithm(StandardError): - """Raised if an algorithm is unknown.""" - pass - -def algorithm_from_text(text): - """Convert text into a DNSSEC algorithm value - @rtype: int""" - - value = _algorithm_by_text.get(text.upper()) - if value is None: - value = int(text) - return value - -def algorithm_to_text(value): - """Convert a DNSSEC algorithm value to text - @rtype: string""" - - text = _algorithm_by_value.get(value) - if text is None: - text = str(value) - return text - -def _to_rdata(record): - from cStringIO import StringIO - s = StringIO() - record.to_wire(s) - return s.getvalue() - -def key_id(key): - rdata = _to_rdata(key) - if key.algorithm == RSAMD5: - return (ord(rdata[-3]) << 8) + ord(rdata[-2]) - else: - total = 0 - for i in range(len(rdata) / 2): - total += (ord(rdata[2 * i]) << 8) + ord(rdata[2 * i + 1]) - if len(rdata) % 2 != 0: - total += ord(rdata[len(rdata) - 1]) << 8 - total += ((total >> 16) & 0xffff); - return total & 0xffff - -def make_ds(name, key, algorithm): - import hashlib - import struct - if algorithm.upper() == 'SHA1': - dsalg = 1 - hash = hashlib.sha1() - elif algorithm.upper() == 'SHA256': - dsalg = 2 - hash = hashlib.sha256() - else: - raise ValueError, 'unsupported algorithm "%s"' % algorithm - - if isinstance(name, basestring): - name = linkcheck.dns.name.from_text(name) - hash.update(name.canonicalize().to_wire()) - hash.update(_to_rdata(key)) - digest = hash.digest() - - dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest - return linkcheck.dns.rdata.from_wire(linkcheck.dns.rdataclass.IN, - linkcheck.dns.rdatatype.DS, dsrdata, 0, len(dsrdata)) diff --git a/linkcheck/dns/rdtypes/ANY/DNSKEY.py b/linkcheck/dns/rdtypes/ANY/DNSKEY.py deleted file mode 100644 index 6b3152fa..00000000 --- a/linkcheck/dns/rdtypes/ANY/DNSKEY.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2004-2007, 2009, 2010 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 linkcheck.dns.rdtypes.keybase - -# flag constants -SEP = 0x0001 -REVOKE = 0x0080 -ZONE = 0x0100 - -class DNSKEY(linkcheck.dns.rdtypes.keybase.KEYBase): - """DNSKEY record""" - pass diff --git a/linkcheck/dns/rdtypes/ANY/KEY.py b/linkcheck/dns/rdtypes/ANY/KEY.py deleted file mode 100644 index d094ccc4..00000000 --- a/linkcheck/dns/rdtypes/ANY/KEY.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 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 linkcheck.dns.rdtypes.keybase - -class KEY(linkcheck.dns.rdtypes.keybase.KEYBase): - """KEY record""" - pass diff --git a/linkcheck/dns/rdtypes/ANY/NXT.py b/linkcheck/dns/rdtypes/ANY/NXT.py deleted file mode 100644 index 2192af53..00000000 --- a/linkcheck/dns/rdtypes/ANY/NXT.py +++ /dev/null @@ -1,100 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 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 linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.rdatatype -import linkcheck.dns.name - -class NXT(linkcheck.dns.rdata.Rdata): - """NXT record - - @ivar next: the next name - @type next: linkcheck.dns.name.Name object - @ivar bitmap: the type bitmap - @type bitmap: string - @see: RFC 2535""" - - __slots__ = ['next', 'bitmap'] - - def __init__(self, rdclass, rdtype, next, bitmap): - super(NXT, self).__init__(rdclass, rdtype) - self.next = next - self.bitmap = bitmap - - def to_text(self, origin=None, relativize=True, **kw): - next = self.next.choose_relativity(origin, relativize) - bits = [] - for i in xrange(0, len(self.bitmap)): - byte = ord(self.bitmap[i]) - for j in xrange(0, 8): - if byte & (0x80 >> j): - bits.append(linkcheck.dns.rdatatype.to_text(i * 8 + j)) - text = ' '.join(bits) - return '%s %s' % (next, text) - - def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): - next = tok.get_name() - next = next.choose_relativity(origin, relativize) - bitmap = ['\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00' ] - while 1: - token = tok.get().unescape() - if token.is_eol_or_eof(): - break - if token.value.isdigit(): - nrdtype = int(token.value) - else: - nrdtype = linkcheck.dns.rdatatype.from_text(token.value) - if nrdtype == 0: - raise linkcheck.dns.exception.DNSSyntaxError("NXT with bit 0") - if nrdtype > 127: - raise linkcheck.dns.exception.DNSSyntaxError("NXT with bit > 127") - i = nrdtype // 8 - bitmap[i] = chr(ord(bitmap[i]) | (0x80 >> (nrdtype % 8))) - bitmap = linkcheck.dns.rdata._truncate_bitmap(bitmap) - return cls(rdclass, rdtype, next, bitmap) - - from_text = classmethod(from_text) - - def to_wire(self, file, compress = None, origin = None): - self.next.to_wire(file, None, origin) - file.write(self.bitmap) - - def to_digestable(self, origin = None): - return self.next.to_digestable(origin) + self.bitmap - - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - (next, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], current) - current += cused - rdlen -= cused - bitmap = wire[current : current + rdlen] - if not origin is None: - next = next.relativize(origin) - return cls(rdclass, rdtype, next, bitmap) - - from_wire = classmethod(from_wire) - - def choose_relativity(self, origin = None, relativize = True): - self.next = self.next.choose_relativity(origin, relativize) - - def _cmp(self, other): - v = cmp(self.next, other.next) - if v == 0: - v = cmp(self.bitmap, other.bitmap) - return v diff --git a/linkcheck/dns/rdtypes/ANY/SIG.py b/linkcheck/dns/rdtypes/ANY/SIG.py deleted file mode 100644 index eb2d1e0e..00000000 --- a/linkcheck/dns/rdtypes/ANY/SIG.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 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 struct -import linkcheck.dns.rdtypes.sigbase - -class SIG(linkcheck.dns.rdtypes.sigbase.SIGBase): - """SIG record""" - def to_digestable(self, origin = None): - return struct.pack('!HBBIIIH', self.type_covered, - self.algorithm, self.labels, - self.original_ttl, self.expiration, - self.inception, self.key_tag) + \ - self.signer.to_digestable(origin) + \ - self.signature diff --git a/linkcheck/network/__init__.py b/linkcheck/network/__init__.py index 200bbbb2..e18bde80 100644 --- a/linkcheck/network/__init__.py +++ b/linkcheck/network/__init__.py @@ -8,7 +8,7 @@ import array import struct import subprocess from _network import ifreq_size -from .. import log, LOG_DNS +from .. import log, LOG_CHECK def pipecmd (cmd1, cmd2): @@ -89,7 +89,7 @@ class IfConfig (object): try: result = self._ioctl(func, self._getifreq(ifname)) except IOError, msg: - log.warn(LOG_DNS, + log.warn(LOG_CHECK, "error getting addr for interface %r: %s", ifname, msg) return None return socket.inet_ntoa(result[20:24]) @@ -140,7 +140,7 @@ class IfConfig (object): try: result = self._ioctl(self.SIOCGIFFLAGS, self._getifreq(ifname)) except IOError, msg: - log.warn(LOG_DNS, + log.warn(LOG_CHECK, "error getting flags for interface %r: %s", ifname, msg) return 0 # extract the interface's flags from the return value diff --git a/linkcheck/network/iputil.py b/linkcheck/network/iputil.py index 6c7c4da7..d9feba97 100644 --- a/linkcheck/network/iputil.py +++ b/linkcheck/network/iputil.py @@ -21,7 +21,7 @@ Ip number related utility functions. import re import socket import struct -from .. import log, LOG_DNS +from .. import log, LOG_CHECK # IP Adress regular expressions @@ -213,20 +213,20 @@ def hosts2map (hosts): host, mask = host.split("/") mask = int(mask) if not is_valid_cidrmask(mask): - log.error(LOG_DNS, + log.error(LOG_CHECK, "CIDR mask %d is not a valid network mask", mask) continue if not is_valid_ipv4(host): - log.error(LOG_DNS, "host %r is not a valid ip address", host) + log.error(LOG_CHECK, "host %r is not a valid ip address", host) continue nets.append(dq2net(host, cidr2mask(mask))) elif _host_netmask_re.match(host): host, mask = host.split("/") if not is_valid_ipv4(host): - log.error(LOG_DNS, "host %r is not a valid ip address", host) + log.error(LOG_CHECK, "host %r is not a valid ip address", host) continue if not is_valid_ipv4(mask): - log.error(LOG_DNS, + log.error(LOG_CHECK, "mask %r is not a valid ip network mask", mask) continue nets.append(dq2net(host, netmask2mask(mask))) @@ -274,7 +274,7 @@ def resolve_host (host): # add first ip of socket address ips.add(res[4][0]) except socket.error: - log.info(LOG_DNS, "Ignored invalid host %r", host) + log.info(LOG_CHECK, "Ignored invalid host %r", host) return ips diff --git a/setup.py b/setup.py index c03bcd4b..4180e43b 100644 --- a/setup.py +++ b/setup.py @@ -680,13 +680,25 @@ o a (Fast)CGI web interface (requires HTTP server) 'py2app': MyPy2app, 'register': MyRegister, }, + package_dir = { + 'dns': 'third_party/dnspython/dns', + }, packages = [ - 'linkcheck', 'linkcheck.logger', 'linkcheck.checker', - 'linkcheck.director', 'linkcheck.configuration', 'linkcheck.cache', - 'linkcheck.htmlutil', 'linkcheck.dns', 'linkcheck.dns.rdtypes', - 'linkcheck.dns.rdtypes.ANY', 'linkcheck.dns.rdtypes.IN', - 'linkcheck.HtmlParser', 'linkcheck.network', 'linkcheck.gui', + 'linkcheck', 'linkcheck.bookmarks', + 'linkcheck.cache', + 'linkcheck.checker', + 'linkcheck.configuration', + 'linkcheck.director', + 'linkcheck.gui', + 'linkcheck.htmlutil', + 'linkcheck.HtmlParser', + 'linkcheck.logger', + 'linkcheck.network', + 'dns', + 'dns.rdtypes', + 'dns.rdtypes.ANY', + 'dns.rdtypes.IN', ], ext_modules = [ Extension('linkcheck.HtmlParser.htmlsax', diff --git a/tests/dns/__init__.py b/tests/dns/__init__.py deleted file mode 100644 index 5d3edfa5..00000000 --- a/tests/dns/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: iso-8859-1 -*- diff --git a/tests/dns/test_flags.py b/tests/dns/test_flags.py deleted file mode 100644 index aafcae5b..00000000 --- a/tests/dns/test_flags.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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 unittest - -import linkcheck.dns.flags -import linkcheck.dns.rcode -import linkcheck.dns.opcode - -class TestFlags (unittest.TestCase): - - def test_rcode1(self): - self.assertEqual(linkcheck.dns.rcode.from_text('FORMERR'), - linkcheck.dns.rcode.FORMERR) - - def test_rcode2(self): - self.assertEqual(linkcheck.dns.rcode.to_text(linkcheck.dns.rcode.FORMERR), - "FORMERR") - - def test_rcode3(self): - self.assertEqual(linkcheck.dns.rcode.to_flags(linkcheck.dns.rcode.FORMERR), (1, 0)) - - def test_rcode4(self): - self.assertEqual(linkcheck.dns.rcode.to_flags(linkcheck.dns.rcode.BADVERS), - (0, 0x01000000)) - - def test_rcode5(self): - self.assertEqual(linkcheck.dns.rcode.from_flags(0, 0x01000000), - linkcheck.dns.rcode.BADVERS) - - def test_rcode6(self): - self.assertEqual(linkcheck.dns.rcode.from_flags(5, 0), linkcheck.dns.rcode.REFUSED) - - def test_rcode7(self): - def bad(): - linkcheck.dns.rcode.to_flags(4096) - self.assertRaises(ValueError, bad) - - def test_flags1(self): - self.assertEqual(linkcheck.dns.flags.from_text("RA RD AA QR"), - linkcheck.dns.flags.QR|linkcheck.dns.flags.AA|linkcheck.dns.flags.RD|linkcheck.dns.flags.RA) - - def test_flags2(self): - flgs = linkcheck.dns.flags.QR|linkcheck.dns.flags.AA|linkcheck.dns.flags.RD|linkcheck.dns.flags.RA - self.assertEqual(linkcheck.dns.flags.to_text(flgs), "QR AA RD RA") diff --git a/tests/dns/test_name.py b/tests/dns/test_name.py deleted file mode 100644 index e2abdb87..00000000 --- a/tests/dns/test_name.py +++ /dev/null @@ -1,704 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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 unittest -import socket -from cStringIO import StringIO - -import linkcheck.dns.name -import linkcheck.dns.reversename -import linkcheck.dns.e164 - - -class TestName (unittest.TestCase): - def setUp(self): - self.origin = linkcheck.dns.name.from_text('example.') - - def testFromTextRel1(self): - n = linkcheck.dns.name.from_text('foo.bar') - self.assertEqual(n.labels, ('foo', 'bar', '')) - - def testFromTextRel2(self): - n = linkcheck.dns.name.from_text('foo.bar', origin=self.origin) - self.assertEqual(n.labels, ('foo', 'bar', 'example', '')) - - def testFromTextRel3(self): - n = linkcheck.dns.name.from_text('foo.bar', origin=None) - self.assertEqual(n.labels, ('foo', 'bar')) - - def testFromTextRel4(self): - n = linkcheck.dns.name.from_text('@', origin=None) - self.assertEqual(n, linkcheck.dns.name.empty) - - def testFromTextRel5(self): - n = linkcheck.dns.name.from_text('@', origin=self.origin) - self.assertEqual(n, self.origin) - - def testFromTextAbs1(self): - n = linkcheck.dns.name.from_text('foo.bar.') - self.assertEqual(n.labels, ('foo', 'bar', '')) - - def testTortureFromText(self): - good = [ - r'.', - r'a', - r'a.', - r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - r'\000.\008.\010.\032.\046.\092.\099.\255', - r'\\', - r'\..\.', - r'\\.\\', - r'!"#%&/()=+-', - r'\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255', - ] - bad = [ - r'..', - r'.a', - r'\\..', - '\\', # yes, we don't want the 'r' prefix! - r'\0', - r'\00', - r'\00Z', - r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - r'\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255', - ] - for t in good: - try: - n = linkcheck.dns.name.from_text(t) - except StandardError: - self.fail("good test '%s' raised an exception" % t) - for t in bad: - caught = False - try: - n = linkcheck.dns.name.from_text(t) - except StandardError: - caught = True - if not caught: - self.fail("bad test '%s' did not raise an exception" % t) - - def testImmutable1(self): - def bad(): - self.origin.labels = () - self.assertRaises(TypeError, bad) - - def testImmutable2(self): - def bad(): - self.origin.labels[0] = 'foo' - self.assertRaises(TypeError, bad) - - def testAbs1(self): - self.assertTrue(linkcheck.dns.name.root.is_absolute()) - - def testAbs2(self): - self.assertTrue(not linkcheck.dns.name.empty.is_absolute()) - - def testAbs3(self): - self.assertTrue(self.origin.is_absolute()) - - def testAbs4(self): - n = linkcheck.dns.name.from_text('foo', origin=None) - self.assertTrue(not n.is_absolute()) - - def testWild1(self): - n = linkcheck.dns.name.from_text('*.foo', origin=None) - self.assertTrue(n.is_wild()) - - def testWild2(self): - n = linkcheck.dns.name.from_text('*a.foo', origin=None) - self.assertTrue(not n.is_wild()) - - def testWild3(self): - n = linkcheck.dns.name.from_text('a.*.foo', origin=None) - self.assertTrue(not n.is_wild()) - - def testWild4(self): - self.assertTrue(not linkcheck.dns.name.root.is_wild()) - - def testWild5(self): - self.assertTrue(not linkcheck.dns.name.empty.is_wild()) - - def testHash1(self): - n1 = linkcheck.dns.name.from_text('fOo.COM') - n2 = linkcheck.dns.name.from_text('foo.com') - self.assertEqual(hash(n1), hash(n2)) - - def testCompare1(self): - n1 = linkcheck.dns.name.from_text('a') - n2 = linkcheck.dns.name.from_text('b') - self.assertTrue(n1 < n2) - self.assertTrue(n2 > n1) - - def testCompare2(self): - n1 = linkcheck.dns.name.from_text('') - n2 = linkcheck.dns.name.from_text('b') - self.assertTrue(n1 < n2) - self.assertTrue(n2 > n1) - - def testCompare3(self): - self.assertTrue(linkcheck.dns.name.empty < linkcheck.dns.name.root) - self.assertTrue(linkcheck.dns.name.root > linkcheck.dns.name.empty) - - def testCompare4(self): - self.assertNotEqual(linkcheck.dns.name.root, 1) - - def testCompare5(self): - self.assertTrue(linkcheck.dns.name.root < 1 or linkcheck.dns.name.root > 1) - - def testSubdomain1(self): - self.assertTrue(not linkcheck.dns.name.empty.is_subdomain(linkcheck.dns.name.root)) - - def testSubdomain2(self): - self.assertTrue(not linkcheck.dns.name.root.is_subdomain(linkcheck.dns.name.empty)) - - def testSubdomain3(self): - n = linkcheck.dns.name.from_text('foo', origin=self.origin) - self.assertTrue(n.is_subdomain(self.origin)) - - def testSubdomain4(self): - n = linkcheck.dns.name.from_text('foo', origin=self.origin) - self.assertTrue(n.is_subdomain(linkcheck.dns.name.root)) - - def testSubdomain5(self): - n = linkcheck.dns.name.from_text('foo', origin=self.origin) - self.assertTrue(n.is_subdomain(n)) - - def testSuperdomain1(self): - self.assertTrue(not linkcheck.dns.name.empty.is_superdomain(linkcheck.dns.name.root)) - - def testSuperdomain2(self): - self.assertTrue(not linkcheck.dns.name.root.is_superdomain(linkcheck.dns.name.empty)) - - def testSuperdomain3(self): - n = linkcheck.dns.name.from_text('foo', origin=self.origin) - self.assertTrue(self.origin.is_superdomain(n)) - - def testSuperdomain4(self): - n = linkcheck.dns.name.from_text('foo', origin=self.origin) - self.assertTrue(linkcheck.dns.name.root.is_superdomain(n)) - - def testSuperdomain5(self): - n = linkcheck.dns.name.from_text('foo', origin=self.origin) - self.assertTrue(n.is_superdomain(n)) - - def testCanonicalize1(self): - n = linkcheck.dns.name.from_text('FOO.bar', origin=self.origin) - c = n.canonicalize() - self.assertEqual(c.labels, ('foo', 'bar', 'example', '')) - - def testToText1(self): - n = linkcheck.dns.name.from_text('FOO.bar', origin=self.origin) - t = n.to_text() - self.assertEqual(t, 'FOO.bar.example.') - - def testToText2(self): - n = linkcheck.dns.name.from_text('FOO.bar', origin=self.origin) - t = n.to_text(True) - self.assertEqual(t, 'FOO.bar.example') - - def testToText3(self): - n = linkcheck.dns.name.from_text('FOO.bar', origin=None) - t = n.to_text() - self.assertEqual(t, 'FOO.bar') - - def testToText4(self): - t = linkcheck.dns.name.empty.to_text() - self.assertEqual(t, '@') - - def testToText5(self): - t = linkcheck.dns.name.root.to_text() - self.assertEqual(t, '.') - - def testToText6(self): - n = linkcheck.dns.name.from_text('FOO bar', origin=None) - t = n.to_text() - self.assertEqual(t, r'FOO\032bar') - - def testToText7(self): - n = linkcheck.dns.name.from_text(r'FOO\.bar', origin=None) - t = n.to_text() - self.assertEqual(t, r'FOO\.bar') - - def testToText8(self): - n = linkcheck.dns.name.from_text(r'\070OO\.bar', origin=None) - t = n.to_text() - self.assertEqual(t, r'FOO\.bar') - - def testSlice1(self): - n = linkcheck.dns.name.from_text(r'a.b.c.', origin=None) - s = n[:] - self.assertEqual(s, ('a', 'b', 'c', '')) - - def testSlice2(self): - n = linkcheck.dns.name.from_text(r'a.b.c.', origin=None) - s = n[:2] - self.assertEqual(s, ('a', 'b')) - - def testSlice3(self): - n = linkcheck.dns.name.from_text(r'a.b.c.', origin=None) - s = n[2:] - self.assertEqual(s, ('c', '')) - - def testEmptyLabel1(self): - def bad(): - n = linkcheck.dns.name.Name(['a', '', 'b']) - self.assertRaises(linkcheck.dns.name.EmptyLabel, bad) - - def testEmptyLabel2(self): - def bad(): - n = linkcheck.dns.name.Name(['', 'b']) - self.assertRaises(linkcheck.dns.name.EmptyLabel, bad) - - def testEmptyLabel3(self): - n = linkcheck.dns.name.Name(['b', '']) - self.assertTrue(n) - - def testLongLabel(self): - n = linkcheck.dns.name.Name(['a' * 63]) - self.assertTrue(n) - - def testLabelTooLong(self): - def bad(): - n = linkcheck.dns.name.Name(['a' * 64, 'b']) - self.assertRaises(linkcheck.dns.name.LabelTooLong, bad) - - def testLongName(self): - n = linkcheck.dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 62]) - self.assertTrue(n) - - def testNameTooLong(self): - def bad(): - n = linkcheck.dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 63]) - self.assertRaises(linkcheck.dns.name.NameTooLong, bad) - - def testConcat1(self): - n1 = linkcheck.dns.name.Name(['a', 'b']) - n2 = linkcheck.dns.name.Name(['c', 'd']) - e = linkcheck.dns.name.Name(['a', 'b', 'c', 'd']) - r = n1 + n2 - self.assertEqual(r, e) - - def testConcat2(self): - n1 = linkcheck.dns.name.Name(['a', 'b']) - n2 = linkcheck.dns.name.Name([]) - e = linkcheck.dns.name.Name(['a', 'b']) - r = n1 + n2 - self.assertEqual(r, e) - - def testConcat2a(self): - n1 = linkcheck.dns.name.Name([]) - n2 = linkcheck.dns.name.Name(['a', 'b']) - e = linkcheck.dns.name.Name(['a', 'b']) - r = n1 + n2 - self.assertEqual(r, e) - - def testConcat3(self): - n1 = linkcheck.dns.name.Name(['a', 'b', '']) - n2 = linkcheck.dns.name.Name([]) - e = linkcheck.dns.name.Name(['a', 'b', '']) - r = n1 + n2 - self.assertEqual(r, e) - - def testConcat4(self): - n1 = linkcheck.dns.name.Name(['a', 'b']) - n2 = linkcheck.dns.name.Name(['c', '']) - e = linkcheck.dns.name.Name(['a', 'b', 'c', '']) - r = n1 + n2 - self.assertEqual(r, e) - - def testConcat5(self): - def bad(): - n1 = linkcheck.dns.name.Name(['a', 'b', '']) - n2 = linkcheck.dns.name.Name(['c']) - r = n1 + n2 - self.assertRaises(linkcheck.dns.name.AbsoluteConcatenation, bad) - - def testBadEscape(self): - def bad(): - n = linkcheck.dns.name.from_text(r'a.b\0q1.c.') - print n - self.assertRaises(linkcheck.dns.name.BadEscape, bad) - - def testDigestable1(self): - n = linkcheck.dns.name.from_text('FOO.bar') - d = n.to_digestable() - self.assertEqual(d, '\x03foo\x03bar\x00') - - def testDigestable2(self): - n1 = linkcheck.dns.name.from_text('FOO.bar') - n2 = linkcheck.dns.name.from_text('foo.BAR.') - d1 = n1.to_digestable() - d2 = n2.to_digestable() - self.assertEqual(d1, d2) - - def testDigestable3(self): - d = linkcheck.dns.name.root.to_digestable() - self.assertEqual(d, '\x00') - - def testDigestable4(self): - n = linkcheck.dns.name.from_text('FOO.bar', None) - d = n.to_digestable(linkcheck.dns.name.root) - self.assertEqual(d, '\x03foo\x03bar\x00') - - def testBadDigestable(self): - def bad(): - n = linkcheck.dns.name.from_text('FOO.bar', None) - d = n.to_digestable() - self.assertRaises(linkcheck.dns.name.NeedAbsoluteNameOrOrigin, bad) - - def testToWire1(self): - n = linkcheck.dns.name.from_text('FOO.bar') - f = StringIO() - compress = {} - n.to_wire(f, compress) - self.assertEqual(f.getvalue(), '\x03FOO\x03bar\x00') - - def testToWire2(self): - n = linkcheck.dns.name.from_text('FOO.bar') - f = StringIO() - compress = {} - n.to_wire(f, compress) - n.to_wire(f, compress) - self.assertEqual(f.getvalue(), '\x03FOO\x03bar\x00\xc0\x00') - - def testToWire3(self): - n1 = linkcheck.dns.name.from_text('FOO.bar') - n2 = linkcheck.dns.name.from_text('foo.bar') - f = StringIO() - compress = {} - n1.to_wire(f, compress) - n2.to_wire(f, compress) - self.assertEqual(f.getvalue(), '\x03FOO\x03bar\x00\xc0\x00') - - def testToWire4(self): - n1 = linkcheck.dns.name.from_text('FOO.bar') - n2 = linkcheck.dns.name.from_text('a.foo.bar') - f = StringIO() - compress = {} - n1.to_wire(f, compress) - n2.to_wire(f, compress) - self.assertEqual(f.getvalue(), '\x03FOO\x03bar\x00\x01\x61\xc0\x00') - - def testToWire5(self): - n1 = linkcheck.dns.name.from_text('FOO.bar') - n2 = linkcheck.dns.name.from_text('a.foo.bar') - f = StringIO() - compress = {} - n1.to_wire(f, compress) - n2.to_wire(f, None) - self.assertEqual(f.getvalue(), - '\x03FOO\x03bar\x00\x01\x61\x03foo\x03bar\x00') - - def testToWire6(self): - n = linkcheck.dns.name.from_text('FOO.bar') - v = n.to_wire() - self.assertEqual(v, '\x03FOO\x03bar\x00') - - def testBadToWire(self): - def bad(): - n = linkcheck.dns.name.from_text('FOO.bar', None) - f = StringIO() - compress = {} - n.to_wire(f, compress) - self.assertRaises(linkcheck.dns.name.NeedAbsoluteNameOrOrigin, bad) - - def testSplit1(self): - n = linkcheck.dns.name.from_text('foo.bar.') - (prefix, suffix) = n.split(2) - ep = linkcheck.dns.name.from_text('foo', None) - es = linkcheck.dns.name.from_text('bar.', None) - self.assertEqual(prefix, ep) - self.assertEqual(suffix, es) - - def testSplit2(self): - n = linkcheck.dns.name.from_text('foo.bar.') - (prefix, suffix) = n.split(1) - ep = linkcheck.dns.name.from_text('foo.bar', None) - es = linkcheck.dns.name.from_text('.', None) - self.assertEqual(prefix, ep) - self.assertEqual(suffix, es) - - def testSplit3(self): - n = linkcheck.dns.name.from_text('foo.bar.') - (prefix, suffix) = n.split(0) - ep = linkcheck.dns.name.from_text('foo.bar.', None) - es = linkcheck.dns.name.from_text('', None) - self.assertEqual(prefix, ep) - self.assertEqual(suffix, es) - - def testSplit4(self): - n = linkcheck.dns.name.from_text('foo.bar.') - (prefix, suffix) = n.split(3) - ep = linkcheck.dns.name.from_text('', None) - es = linkcheck.dns.name.from_text('foo.bar.', None) - self.assertEqual(prefix, ep) - self.assertEqual(suffix, es) - - def testBadSplit1(self): - def bad(): - n = linkcheck.dns.name.from_text('foo.bar.') - (prefix, suffix) = n.split(-1) - self.assertRaises(ValueError, bad) - - def testBadSplit2(self): - def bad(): - n = linkcheck.dns.name.from_text('foo.bar.') - (prefix, suffix) = n.split(4) - self.assertRaises(ValueError, bad) - - def testRelativize1(self): - n = linkcheck.dns.name.from_text('a.foo.bar.', None) - o = linkcheck.dns.name.from_text('bar.', None) - e = linkcheck.dns.name.from_text('a.foo', None) - self.assertEqual(n.relativize(o), e) - - def testRelativize2(self): - n = linkcheck.dns.name.from_text('a.foo.bar.', None) - o = n - e = linkcheck.dns.name.empty - self.assertEqual(n.relativize(o), e) - - def testRelativize3(self): - n = linkcheck.dns.name.from_text('a.foo.bar.', None) - o = linkcheck.dns.name.from_text('blaz.', None) - e = n - self.assertEqual(n.relativize(o), e) - - def testRelativize4(self): - n = linkcheck.dns.name.from_text('a.foo', None) - o = linkcheck.dns.name.root - e = n - self.assertEqual(n.relativize(o), e) - - def testDerelativize1(self): - n = linkcheck.dns.name.from_text('a.foo', None) - o = linkcheck.dns.name.from_text('bar.', None) - e = linkcheck.dns.name.from_text('a.foo.bar.', None) - self.assertEqual(n.derelativize(o), e) - - def testDerelativize2(self): - n = linkcheck.dns.name.empty - o = linkcheck.dns.name.from_text('a.foo.bar.', None) - e = o - self.assertEqual(n.derelativize(o), e) - - def testDerelativize3(self): - n = linkcheck.dns.name.from_text('a.foo.bar.', None) - o = linkcheck.dns.name.from_text('blaz.', None) - e = n - self.assertEqual(n.derelativize(o), e) - - def testChooseRelativity1(self): - n = linkcheck.dns.name.from_text('a.foo.bar.', None) - o = linkcheck.dns.name.from_text('bar.', None) - e = linkcheck.dns.name.from_text('a.foo', None) - self.assertEqual(n.choose_relativity(o, True), e) - - def testChooseRelativity2(self): - n = linkcheck.dns.name.from_text('a.foo.bar.', None) - o = linkcheck.dns.name.from_text('bar.', None) - e = n - self.assertEqual(n.choose_relativity(o, False), e) - - def testChooseRelativity3(self): - n = linkcheck.dns.name.from_text('a.foo', None) - o = linkcheck.dns.name.from_text('bar.', None) - e = linkcheck.dns.name.from_text('a.foo.bar.', None) - self.assertEqual(n.choose_relativity(o, False), e) - - def testChooseRelativity4(self): - n = linkcheck.dns.name.from_text('a.foo', None) - o = None - e = n - self.assertEqual(n.choose_relativity(o, True), e) - - def testChooseRelativity5(self): - n = linkcheck.dns.name.from_text('a.foo', None) - o = None - e = n - self.assertEqual(n.choose_relativity(o, False), e) - - def testChooseRelativity6(self): - n = linkcheck.dns.name.from_text('a.foo.', None) - o = None - e = n - self.assertEqual(n.choose_relativity(o, True), e) - - def testChooseRelativity7(self): - n = linkcheck.dns.name.from_text('a.foo.', None) - o = None - e = n - self.assertEqual(n.choose_relativity(o, False), e) - - def testFromWire1(self): - w = '\x03foo\x00\xc0\x00' - (n1, cused1) = linkcheck.dns.name.from_wire(w, 0) - (n2, cused2) = linkcheck.dns.name.from_wire(w, cused1) - en1 = linkcheck.dns.name.from_text('foo.') - en2 = en1 - ecused1 = 5 - ecused2 = 2 - self.assertEqual(n1, en1) - self.assertEqual(cused1, ecused1) - self.assertEqual(n2, en2) - self.assertEqual(cused2, ecused2) - - def testFromWire2(self): - w = '\x03foo\x00\x01a\xc0\x00\x01b\xc0\x05' - current = 0 - (n1, cused1) = linkcheck.dns.name.from_wire(w, current) - current += cused1 - (n2, cused2) = linkcheck.dns.name.from_wire(w, current) - current += cused2 - (n3, cused3) = linkcheck.dns.name.from_wire(w, current) - en1 = linkcheck.dns.name.from_text('foo.') - en2 = linkcheck.dns.name.from_text('a.foo.') - en3 = linkcheck.dns.name.from_text('b.a.foo.') - ecused1 = 5 - ecused2 = 4 - ecused3 = 4 - self.assertEqual(n1, en1) - self.assertEqual(cused1, ecused1) - self.assertEqual(n2, en2) - self.assertEqual(cused2, ecused2) - self.assertEqual(n3, en3) - self.assertEqual(cused3, ecused3) - - def testBadFromWire1(self): - def bad(): - w = '\x03foo\xc0\x04' - (n, cused) = linkcheck.dns.name.from_wire(w, 0) - self.assertRaises(linkcheck.dns.name.BadPointer, bad) - - def testBadFromWire2(self): - def bad(): - w = '\x03foo\xc0\x05' - (n, cused) = linkcheck.dns.name.from_wire(w, 0) - self.assertRaises(linkcheck.dns.name.BadPointer, bad) - - def testBadFromWire3(self): - def bad(): - w = '\xbffoo' - (n, cused) = linkcheck.dns.name.from_wire(w, 0) - self.assertRaises(linkcheck.dns.name.BadLabelType, bad) - - def testBadFromWire4(self): - def bad(): - w = '\x41foo' - (n, cused) = linkcheck.dns.name.from_wire(w, 0) - self.assertRaises(linkcheck.dns.name.BadLabelType, bad) - - def testParent1(self): - n = linkcheck.dns.name.from_text('foo.bar.') - self.assertEqual(n.parent(), linkcheck.dns.name.from_text('bar.')) - self.assertEqual(n.parent().parent(), linkcheck.dns.name.root) - - def testParent2(self): - n = linkcheck.dns.name.from_text('foo.bar', None) - self.assertEqual(n.parent(), linkcheck.dns.name.from_text('bar', None)) - self.assertEqual(n.parent().parent(), linkcheck.dns.name.empty) - - def testParent3(self): - def bad(): - n = linkcheck.dns.name.root - n.parent() - self.assertRaises(linkcheck.dns.name.NoParent, bad) - - def testParent4(self): - def bad(): - n = linkcheck.dns.name.empty - n.parent() - self.assertRaises(linkcheck.dns.name.NoParent, bad) - - def testFromUnicode1(self): - n = linkcheck.dns.name.from_text(u'foo.bar') - self.assertEqual(n.labels, ('foo', 'bar', '')) - - def testFromUnicode2(self): - n = linkcheck.dns.name.from_text(u'foo\u1234bar.bar') - self.assertEqual(n.labels, ('xn--foobar-r5z', 'bar', '')) - - def testFromUnicodeAlternateDot1(self): - n = linkcheck.dns.name.from_text(u'foo\u3002bar') - self.assertEqual(n.labels, ('foo', 'bar', '')) - - def testFromUnicodeAlternateDot2(self): - n = linkcheck.dns.name.from_text(u'foo\uff0ebar') - self.assertEqual(n.labels, ('foo', 'bar', '')) - - def testFromUnicodeAlternateDot3(self): - n = linkcheck.dns.name.from_text(u'foo\uff61bar') - self.assertEqual(n.labels, ('foo', 'bar', '')) - - def testToUnicode1(self): - n = linkcheck.dns.name.from_text(u'foo.bar') - s = n.to_unicode() - self.assertEqual(s, u'foo.bar.') - - def testToUnicode2(self): - n = linkcheck.dns.name.from_text(u'foo\u1234bar.bar') - s = n.to_unicode() - self.assertEqual(s, u'foo\u1234bar.bar.') - - def testToUnicode3(self): - n = linkcheck.dns.name.from_text('foo.bar') - s = n.to_unicode() - self.assertEqual(s, u'foo.bar.') - - def testReverseIPv4(self): - e = linkcheck.dns.name.from_text('1.0.0.127.in-addr.arpa.') - n = linkcheck.dns.reversename.from_address('127.0.0.1') - self.assertEqual(e, n) - - def testReverseIPv6(self): - e = linkcheck.dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') - n = linkcheck.dns.reversename.from_address('::1') - self.assertEqual(e, n) - - def testBadReverseIPv4(self): - def bad(): - n = linkcheck.dns.reversename.from_address('127.0.foo.1') - self.assertRaises(socket.error, bad) - - def testBadReverseIPv6(self): - def bad(): - n = linkcheck.dns.reversename.from_address('::1::1') - self.assertRaises(socket.error, bad) - - def testForwardIPv4(self): - n = linkcheck.dns.name.from_text('1.0.0.127.in-addr.arpa.') - e = '127.0.0.1' - text = linkcheck.dns.reversename.to_address(n) - self.assertEqual(text, e) - - def testForwardIPv6(self): - n = linkcheck.dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') - e = '::1' - text = linkcheck.dns.reversename.to_address(n) - self.assertEqual(text, e) - - def testE164ToEnum(self): - text = '+1 650 555 1212' - e = linkcheck.dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') - n = linkcheck.dns.e164.from_e164(text) - self.assertEqual(n, e) - - def testEnumToE164(self): - n = linkcheck.dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') - e = '+16505551212' - text = linkcheck.dns.e164.to_e164(n) - self.assertEqual(text, e) diff --git a/tests/dns/test_namedict.py b/tests/dns/test_namedict.py deleted file mode 100644 index 1fe7403f..00000000 --- a/tests/dns/test_namedict.py +++ /dev/null @@ -1,100 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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 unittest - -import linkcheck.dns.name -import linkcheck.dns.namedict - -class TestNameDict (unittest.TestCase): - - def setUp(self): - self.ndict = linkcheck.dns.namedict.NameDict() - n1 = linkcheck.dns.name.from_text('foo.bar.') - n2 = linkcheck.dns.name.from_text('bar.') - self.ndict[n1] = 1 - self.ndict[n2] = 2 - self.rndict = linkcheck.dns.namedict.NameDict() - n1 = linkcheck.dns.name.from_text('foo.bar', None) - n2 = linkcheck.dns.name.from_text('bar', None) - self.rndict[n1] = 1 - self.rndict[n2] = 2 - - def testDepth(self): - self.assertEqual(self.ndict.max_depth, 3) - - def testLookup1(self): - k = linkcheck.dns.name.from_text('foo.bar.') - self.assertEqual(self.ndict[k], 1) - - def testLookup2(self): - k = linkcheck.dns.name.from_text('foo.bar.') - self.assertEqual(self.ndict.get_deepest_match(k)[1], 1) - - def testLookup3(self): - k = linkcheck.dns.name.from_text('a.b.c.foo.bar.') - self.assertEqual(self.ndict.get_deepest_match(k)[1], 1) - - def testLookup4(self): - k = linkcheck.dns.name.from_text('a.b.c.bar.') - self.assertEqual(self.ndict.get_deepest_match(k)[1], 2) - - def testLookup5(self): - def bad(): - n = linkcheck.dns.name.from_text('a.b.c.') - (k, v) = self.ndict.get_deepest_match(n) - self.assertRaises(KeyError, bad) - - def testLookup6(self): - def bad(): - (k, v) = self.ndict.get_deepest_match(linkcheck.dns.name.empty) - self.assertRaises(KeyError, bad) - - def testLookup7(self): - self.ndict[linkcheck.dns.name.empty] = 100 - n = linkcheck.dns.name.from_text('a.b.c.') - (k, v) = self.ndict.get_deepest_match(n) - self.assertEqual(v, 100) - - def testLookup8(self): - def bad(): - self.ndict['foo'] = 100 - self.assertRaises(ValueError, bad) - - def testRelDepth(self): - self.assertEqual(self.rndict.max_depth, 2) - - def testRelLookup1(self): - k = linkcheck.dns.name.from_text('foo.bar', None) - self.assertEqual(self.rndict[k], 1) - - def testRelLookup2(self): - k = linkcheck.dns.name.from_text('foo.bar', None) - self.assertEqual(self.rndict.get_deepest_match(k)[1], 1) - - def testRelLookup3(self): - k = linkcheck.dns.name.from_text('a.b.c.foo.bar', None) - self.assertEqual(self.rndict.get_deepest_match(k)[1], 1) - - def testRelLookup4(self): - k = linkcheck.dns.name.from_text('a.b.c.bar', None) - self.assertEqual(self.rndict.get_deepest_match(k)[1], 2) - - def testRelLookup7(self): - self.rndict[linkcheck.dns.name.empty] = 100 - n = linkcheck.dns.name.from_text('a.b.c', None) - (k, v) = self.rndict.get_deepest_match(n) - self.assertEqual(v, 100) diff --git a/tests/dns/test_ntoaaton.py b/tests/dns/test_ntoaaton.py deleted file mode 100644 index c7fef6cb..00000000 --- a/tests/dns/test_ntoaaton.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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 unittest - -import linkcheck.dns.exception -import linkcheck.dns.ipv6 - -class TestNtoAAtoN (unittest.TestCase): - - def test_aton1(self): - a = linkcheck.dns.ipv6.inet_aton('::') - self.assertEqual(a, '\x00' * 16) - - def test_aton2(self): - a = linkcheck.dns.ipv6.inet_aton('::1') - self.assertEqual(a, '\x00' * 15 + '\x01') - - def test_aton3(self): - a = linkcheck.dns.ipv6.inet_aton('::10.0.0.1') - self.assertEqual(a, '\x00' * 12 + '\x0a\x00\x00\x01') - - def test_aton4(self): - a = linkcheck.dns.ipv6.inet_aton('abcd::dcba') - self.assertEqual(a, '\xab\xcd' + '\x00' * 12 + '\xdc\xba') - - def test_aton5(self): - a = linkcheck.dns.ipv6.inet_aton('1:2:3:4:5:6:7:8') - self.assertEqual(a, - '00010002000300040005000600070008'.decode('hex_codec')) - - def test_bad_aton1(self): - def bad(): - a = linkcheck.dns.ipv6.inet_aton('abcd:dcba') - self.assertRaises(linkcheck.dns.exception.DNSSyntaxError, bad) - - def test_bad_aton2(self): - def bad(): - a = linkcheck.dns.ipv6.inet_aton('abcd::dcba::1') - self.assertRaises(linkcheck.dns.exception.DNSSyntaxError, bad) - - def test_bad_aton3(self): - def bad(): - a = linkcheck.dns.ipv6.inet_aton('1:2:3:4:5:6:7:8:9') - self.assertRaises(linkcheck.dns.exception.DNSSyntaxError, bad) - - def test_ntoa1(self): - b = '00010002000300040005000600070008'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '1:2:3:4:5:6:7:8') - - def test_ntoa2(self): - b = '\x00' * 16 - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '::') - - def test_ntoa3(self): - b = '\x00' * 15 + '\x01' - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '::1') - - def test_ntoa4(self): - b = '\x80' + '\x00' * 15 - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '8000::') - - def test_ntoa5(self): - b = '\x01\xcd' + '\x00' * 12 + '\x03\xef' - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '1cd::3ef') - - def test_ntoa6(self): - b = 'ffff00000000ffff000000000000ffff'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, 'ffff:0:0:ffff::ffff') - - def test_ntoa7(self): - b = '00000000ffff000000000000ffffffff'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '0:0:ffff::ffff:ffff') - - def test_ntoa8(self): - b = 'ffff0000ffff00000000ffff00000000'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, 'ffff:0:ffff::ffff:0:0') - - def test_ntoa9(self): - b = '0000000000000000000000000a000001'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '::10.0.0.1') - - def test_ntoa10(self): - b = '0000000000000000000000010a000001'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '::1:a00:1') - - def test_ntoa11(self): - b = '00000000000000000000ffff0a000001'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '::ffff:10.0.0.1') - - def test_ntoa12(self): - b = '000000000000000000000000ffffffff'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '::255.255.255.255') - - def test_ntoa13(self): - b = '00000000000000000000ffffffffffff'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '::ffff:255.255.255.255') - - def test_ntoa14(self): - b = '0000000000000000000000000001ffff'.decode('hex_codec') - t = linkcheck.dns.ipv6.inet_ntoa(b) - self.assertEqual(t, '::0.1.255.255') - - def test_bad_ntoa1(self): - def bad(): - a = linkcheck.dns.ipv6.inet_ntoa('') - self.assertRaises(ValueError, bad) - - def test_bad_ntoa2(self): - def bad(): - a = linkcheck.dns.ipv6.inet_ntoa('\x00' * 17) - self.assertRaises(ValueError, bad) diff --git a/tests/dns/test_rdtypeandclass.py b/tests/dns/test_rdtypeandclass.py deleted file mode 100644 index 750c0b57..00000000 --- a/tests/dns/test_rdtypeandclass.py +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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 unittest - -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype - -class TestRdTypeAndClass (unittest.TestCase): - - # Classes - - def test_class_meta1(self): - self.assertTrue(linkcheck.dns.rdataclass.is_metaclass(linkcheck.dns.rdataclass.ANY)) - - def test_class_meta2(self): - self.assertTrue(not linkcheck.dns.rdataclass.is_metaclass(linkcheck.dns.rdataclass.IN)) - - def test_class_bytext1(self): - self.assertEqual(linkcheck.dns.rdataclass.from_text('IN'), - linkcheck.dns.rdataclass.IN) - - def test_class_bytext2(self): - self.assertEqual(linkcheck.dns.rdataclass.from_text('CLASS1'), - linkcheck.dns.rdataclass.IN) - - def test_class_bytext_bounds1(self): - self.assertEqual(linkcheck.dns.rdataclass.from_text('CLASS0'), 0) - self.assertEqual(linkcheck.dns.rdataclass.from_text('CLASS65535'), 65535) - - def test_class_bytext_bounds2(self): - def bad(): - junk = linkcheck.dns.rdataclass.from_text('CLASS65536') - self.assertRaises(ValueError, bad) - - def test_class_bytext_unknown(self): - def bad(): - junk = linkcheck.dns.rdataclass.from_text('XYZ') - self.assertRaises(linkcheck.dns.rdataclass.UnknownRdataclass, bad) - - def test_class_totext1(self): - self.assertEqual(linkcheck.dns.rdataclass.to_text(linkcheck.dns.rdataclass.IN), - 'IN') - - def test_class_totext2(self): - self.assertEqual(linkcheck.dns.rdataclass.to_text(999), 'CLASS999') - - def test_class_totext_bounds1(self): - def bad(): - junk = linkcheck.dns.rdataclass.to_text(-1) - self.assertRaises(ValueError, bad) - - def test_class_totext_bounds2(self): - def bad(): - junk = linkcheck.dns.rdataclass.to_text(65536) - self.assertRaises(ValueError, bad) - - # Types - - def test_type_meta1(self): - self.assertTrue(linkcheck.dns.rdatatype.is_metatype(linkcheck.dns.rdatatype.ANY)) - - def test_type_meta2(self): - self.assertTrue(linkcheck.dns.rdatatype.is_metatype(linkcheck.dns.rdatatype.OPT)) - - def test_type_meta3(self): - self.assertTrue(not linkcheck.dns.rdatatype.is_metatype(linkcheck.dns.rdatatype.A)) - - def test_type_singleton1(self): - self.assertTrue(linkcheck.dns.rdatatype.is_singleton(linkcheck.dns.rdatatype.SOA)) - - def test_type_singleton2(self): - self.assertTrue(not linkcheck.dns.rdatatype.is_singleton(linkcheck.dns.rdatatype.A)) - - def test_type_bytext1(self): - self.assertEqual(linkcheck.dns.rdatatype.from_text('A'), linkcheck.dns.rdatatype.A) - - def test_type_bytext2(self): - self.assertEqual(linkcheck.dns.rdatatype.from_text('TYPE1'), - linkcheck.dns.rdatatype.A) - - def test_type_bytext_bounds1(self): - self.assertEqual(linkcheck.dns.rdatatype.from_text('TYPE0'), 0) - self.assertEqual(linkcheck.dns.rdatatype.from_text('TYPE65535'), 65535) - - def test_type_bytext_bounds2(self): - def bad(): - junk = linkcheck.dns.rdatatype.from_text('TYPE65536') - self.assertRaises(ValueError, bad) - - def test_type_bytext_unknown(self): - def bad(): - junk = linkcheck.dns.rdatatype.from_text('XYZ') - self.assertRaises(linkcheck.dns.rdatatype.UnknownRdatatype, bad) - - def test_type_totext1(self): - self.assertEqual(linkcheck.dns.rdatatype.to_text(linkcheck.dns.rdatatype.A), 'A') - - def test_type_totext2(self): - self.assertEqual(linkcheck.dns.rdatatype.to_text(999), 'TYPE999') - - def test_type_totext_bounds1(self): - def bad(): - junk = linkcheck.dns.rdatatype.to_text(-1) - self.assertRaises(ValueError, bad) - - def test_type_totext_bounds2(self): - def bad(): - junk = linkcheck.dns.rdatatype.to_text(65536) - self.assertRaises(ValueError, bad) diff --git a/tests/dns/test_resolver.py b/tests/dns/test_resolver.py deleted file mode 100644 index e3affe69..00000000 --- a/tests/dns/test_resolver.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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. - -from cStringIO import StringIO -import sys -import time -import unittest - -import linkcheck.dns.name -import linkcheck.dns.message -import linkcheck.dns.name -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype -import linkcheck.dns.resolver - -resolv_conf = """ - /t/t -# comment 1 -; comment 2 -domain foo -nameserver 10.0.0.1 -nameserver 10.0.0.2 -""" - -message_text = """id 1234 -opcode QUERY -rcode NOERROR -flags QR AA RD -;QUESTION -example. IN A -;ANSWER -example. 1 IN A 10.0.0.1 -;AUTHORITY -;ADDITIONAL -""" - -class TestResolver (unittest.TestCase): - - if sys.platform != 'win32': - def testRead(self): - f = StringIO(resolv_conf) - r = linkcheck.dns.resolver.Resolver(f) - self.assertEqual(r.nameservers, ['10.0.0.1', '10.0.0.2']) - self.assertEqual(r.domain, linkcheck.dns.name.from_text('foo')) - - def testCacheExpiration(self): - message = linkcheck.dns.message.from_text(message_text) - name = linkcheck.dns.name.from_text('example.') - answer = linkcheck.dns.resolver.Answer(name, linkcheck.dns.rdatatype.A, linkcheck.dns.rdataclass.IN, - message) - cache = linkcheck.dns.resolver.Cache() - cache.put((name, linkcheck.dns.rdatatype.A, linkcheck.dns.rdataclass.IN), answer) - time.sleep(2) - self.assertTrue(cache.get((name, linkcheck.dns.rdatatype.A, - linkcheck.dns.rdataclass.IN)) is None) - - def testCacheCleaning(self): - message = linkcheck.dns.message.from_text(message_text) - name = linkcheck.dns.name.from_text('example.') - answer = linkcheck.dns.resolver.Answer(name, linkcheck.dns.rdatatype.A, linkcheck.dns.rdataclass.IN, - message) - cache = linkcheck.dns.resolver.Cache(cleaning_interval=1.0) - cache.put((name, linkcheck.dns.rdatatype.A, linkcheck.dns.rdataclass.IN), answer) - time.sleep(2) - self.assertTrue(cache.get((name, linkcheck.dns.rdatatype.A, - linkcheck.dns.rdataclass.IN)) is None) - - def testZoneForName1(self): - name = linkcheck.dns.name.from_text('www.dnspython.org.') - ezname = linkcheck.dns.name.from_text('dnspython.org.') - zname = linkcheck.dns.resolver.zone_for_name(name) - self.assertTrue(zname == ezname) - - def testZoneForName2(self): - name = linkcheck.dns.name.from_text('a.b.www.dnspython.org.') - ezname = linkcheck.dns.name.from_text('dnspython.org.') - zname = linkcheck.dns.resolver.zone_for_name(name) - self.assertTrue(zname == ezname) - - def testZoneForName3(self): - name = linkcheck.dns.name.from_text('dnspython.org.') - ezname = linkcheck.dns.name.from_text('dnspython.org.') - zname = linkcheck.dns.resolver.zone_for_name(name) - self.assertTrue(zname == ezname) - - def testZoneForName4(self): - def bad(): - name = linkcheck.dns.name.from_text('dnspython.org', None) - zname = linkcheck.dns.resolver.zone_for_name(name) - self.assertRaises(linkcheck.dns.resolver.NotAbsolute, bad) diff --git a/tests/dns/test_rrset.py b/tests/dns/test_rrset.py deleted file mode 100644 index d9909bb7..00000000 --- a/tests/dns/test_rrset.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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 unittest - -import linkcheck.dns.rrset - -class TestRRset (unittest.TestCase): - - def testEqual1(self): - r1 = linkcheck.dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') - r2 = linkcheck.dns.rrset.from_text('FOO', 300, 'in', 'a', '10.0.0.2', '10.0.0.1') - self.assertEqual(r1, r2) - - def testEqual2(self): - r1 = linkcheck.dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') - r2 = linkcheck.dns.rrset.from_text('FOO', 600, 'in', 'a', '10.0.0.2', '10.0.0.1') - self.assertEqual(r1, r2) - - def testNotEqual1(self): - r1 = linkcheck.dns.rrset.from_text('fooa', 30, 'in', 'a', '10.0.0.1', '10.0.0.2') - r2 = linkcheck.dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') - self.assertNotEqual(r1, r2) - - def testNotEqual2(self): - r1 = linkcheck.dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.3') - r2 = linkcheck.dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') - self.assertNotEqual(r1, r2) - - def testNotEqual3(self): - r1 = linkcheck.dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.2', - '10.0.0.3') - r2 = linkcheck.dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') - self.assertNotEqual(r1, r2) - - def testNotEqual4(self): - r1 = linkcheck.dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1') - r2 = linkcheck.dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') - self.assertNotEqual(r1, r2) diff --git a/tests/dns/test_tokenizer.py b/tests/dns/test_tokenizer.py deleted file mode 100644 index 948fadf3..00000000 --- a/tests/dns/test_tokenizer.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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 unittest - -import linkcheck.dns.exception -import linkcheck.dns.tokenizer - -class TestTokenizer (unittest.TestCase): - - def testQuotedString1(self): - tok = linkcheck.dns.tokenizer.Tokenizer(r'"foo"') - (ttype, value) = tok.get() - self.assertEqual(ttype, linkcheck.dns.tokenizer.QUOTED_STRING) - self.assertEqual(value, 'foo') - - def testQuotedString2(self): - tok = linkcheck.dns.tokenizer.Tokenizer(r'""') - (ttype, value) = tok.get() - self.assertEqual(ttype, linkcheck.dns.tokenizer.QUOTED_STRING) - self.assertEqual(value, '') - - def testQuotedString3(self): - tok = linkcheck.dns.tokenizer.Tokenizer(r'"\"foo\""') - (ttype, value) = tok.get() - self.assertEqual(ttype, linkcheck.dns.tokenizer.QUOTED_STRING) - self.assertEqual(value, '"foo"') - - def testQuotedString4(self): - tok = linkcheck.dns.tokenizer.Tokenizer(r'"foo\010bar"') - (ttype, value) = tok.get() - self.assertEqual(ttype, linkcheck.dns.tokenizer.QUOTED_STRING) - self.assertEqual(value, 'foo\x0abar') - - def testQuotedString5(self): - def bad(): - tok = linkcheck.dns.tokenizer.Tokenizer(r'"foo') - (ttype, value) = tok.get() - self.assertRaises(linkcheck.dns.exception.UnexpectedEnd, bad) - - def testQuotedString6(self): - def bad(): - tok = linkcheck.dns.tokenizer.Tokenizer(r'"foo\01') - (ttype, value) = tok.get() - self.assertRaises(linkcheck.dns.exception.DNSSyntaxError, bad) - - def testQuotedString7(self): - def bad(): - tok = linkcheck.dns.tokenizer.Tokenizer('"foo\nbar"') - (ttype, value) = tok.get() - self.assertRaises(linkcheck.dns.exception.DNSSyntaxError, bad) - - def testEmpty1(self): - tok = linkcheck.dns.tokenizer.Tokenizer('') - (ttype, value) = tok.get() - self.assertEqual(ttype, linkcheck.dns.tokenizer.EOF) - - def testEmpty2(self): - tok = linkcheck.dns.tokenizer.Tokenizer('') - (ttype1, value1) = tok.get() - (ttype2, value2) = tok.get() - self.assertEqual(ttype1, linkcheck.dns.tokenizer.EOF) - self.assertEqual(ttype2, linkcheck.dns.tokenizer.EOF) - - def testEOL(self): - tok = linkcheck.dns.tokenizer.Tokenizer('\n') - (ttype1, value1) = tok.get() - (ttype2, value2) = tok.get() - self.assertEqual(ttype1, linkcheck.dns.tokenizer.EOL) - self.assertEqual(ttype2, linkcheck.dns.tokenizer.EOF) - - def testWS1(self): - tok = linkcheck.dns.tokenizer.Tokenizer(' \n') - (ttype1, value1) = tok.get() - self.assertEqual(ttype1, linkcheck.dns.tokenizer.EOL) - - def testWS2(self): - tok = linkcheck.dns.tokenizer.Tokenizer(' \n') - (ttype1, value1) = tok.get(want_leading=True) - self.assertEqual(ttype1, linkcheck.dns.tokenizer.WHITESPACE) - - def testComment1(self): - tok = linkcheck.dns.tokenizer.Tokenizer(' ;foo\n') - (ttype1, value1) = tok.get() - self.assertEqual(ttype1, linkcheck.dns.tokenizer.EOL) - - def testComment2(self): - tok = linkcheck.dns.tokenizer.Tokenizer(' ;foo\n') - (ttype1, value1) = tok.get(want_comment = True) - (ttype2, value2) = tok.get() - self.assertEqual(ttype1, linkcheck.dns.tokenizer.COMMENT) - self.assertEqual(value1, 'foo') - self.assertEqual(ttype2, linkcheck.dns.tokenizer.EOL) - - def testComment3(self): - tok = linkcheck.dns.tokenizer.Tokenizer(' ;foo bar\n') - (ttype1, value1) = tok.get(want_comment = True) - (ttype2, value2) = tok.get() - self.assertEqual(ttype1, linkcheck.dns.tokenizer.COMMENT) - self.assertEqual(value1, 'foo bar') - self.assertEqual(ttype2, linkcheck.dns.tokenizer.EOL) - - def testMultiline1(self): - tok = linkcheck.dns.tokenizer.Tokenizer('( foo\n\n bar\n)') - tokens = list(iter(tok)) - self.assertEqual(tokens, [(linkcheck.dns.tokenizer.IDENTIFIER, 'foo'), - (linkcheck.dns.tokenizer.IDENTIFIER, 'bar')]) - - def testMultiline2(self): - tok = linkcheck.dns.tokenizer.Tokenizer('( foo\n\n bar\n)\n') - tokens = list(iter(tok)) - self.assertEqual(tokens, [(linkcheck.dns.tokenizer.IDENTIFIER, 'foo'), - (linkcheck.dns.tokenizer.IDENTIFIER, 'bar'), - (linkcheck.dns.tokenizer.EOL, '\n')]) - def testMultiline3(self): - def bad(): - tok = linkcheck.dns.tokenizer.Tokenizer('foo)') - tokens = list(iter(tok)) - self.assertRaises(linkcheck.dns.exception.DNSSyntaxError, bad) - - def testMultiline4(self): - def bad(): - tok = linkcheck.dns.tokenizer.Tokenizer('((foo)') - tokens = list(iter(tok)) - self.assertRaises(linkcheck.dns.exception.DNSSyntaxError, bad) - - def testUnget1(self): - tok = linkcheck.dns.tokenizer.Tokenizer('foo') - t1 = tok.get() - tok.unget(t1) - t2 = tok.get() - self.assertEqual(t1, t2) - self.assertEqual(t1, (linkcheck.dns.tokenizer.IDENTIFIER, 'foo')) - - def testUnget2(self): - def bad(): - tok = linkcheck.dns.tokenizer.Tokenizer('foo') - t1 = tok.get() - tok.unget(t1) - tok.unget(t1) - self.assertRaises(linkcheck.dns.tokenizer.UngetBufferFull, bad) - - def testGetEOL1(self): - tok = linkcheck.dns.tokenizer.Tokenizer('\n') - t = tok.get_eol() - self.assertEqual(t, '\n') - - def testGetEOL2(self): - tok = linkcheck.dns.tokenizer.Tokenizer('') - t = tok.get_eol() - self.assertEqual(t, '') - - def testEscapedDelimiter1(self): - tok = linkcheck.dns.tokenizer.Tokenizer(r'ch\ ld') - t = tok.get() - self.assertEqual(t, (linkcheck.dns.tokenizer.IDENTIFIER, r'ch ld')) - - def testEscapedDelimiter2(self): - tok = linkcheck.dns.tokenizer.Tokenizer(r'ch\0ld') - t = tok.get() - self.assertEqual(t, (linkcheck.dns.tokenizer.IDENTIFIER, r'ch\0ld')) diff --git a/tests/dns/test_zone.py b/tests/dns/test_zone.py deleted file mode 100644 index 355540ba..00000000 --- a/tests/dns/test_zone.py +++ /dev/null @@ -1,422 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 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. - -from cStringIO import StringIO -import os -import unittest -import difflib - -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype -import linkcheck.dns.rrset -import linkcheck.dns.zone - -_paths = ["tests", "dns"] - -def fname (name, sep=None): - args = tuple(_paths + [name]) - if sep is not None: - return sep.join(args) - else: - return os.path.join(*args) - - -example_text = """$TTL 3600 -$ORIGIN example. -@ soa foo bar 1 2 3 4 5 -@ ns ns1 -@ ns ns2 -ns1 a 10.0.0.1 -ns2 a 10.0.0.2 -$TTL 300 -$ORIGIN foo.example. -bar mx 0 blaz -""" - -example_text_output = """@ 3600 IN SOA foo bar 1 2 3 4 5 -@ 3600 IN NS ns1 -@ 3600 IN NS ns2 -bar.foo 300 IN MX 0 blaz.foo -ns1 3600 IN A 10.0.0.1 -ns2 3600 IN A 10.0.0.2 -""" - -something_quite_similar = """@ 3600 IN SOA foo bar 1 2 3 4 5 -@ 3600 IN NS ns1 -@ 3600 IN NS ns2 -bar.foo 300 IN MX 0 blaz.foo -ns1 3600 IN A 10.0.0.1 -ns2 3600 IN A 10.0.0.3 -""" - -something_different = """@ 3600 IN SOA fooa bar 1 2 3 4 5 -@ 3600 IN NS ns11 -@ 3600 IN NS ns21 -bar.fooa 300 IN MX 0 blaz.fooa -ns11 3600 IN A 10.0.0.11 -ns21 3600 IN A 10.0.0.21 -""" - -ttl_example_text = """$TTL 1h -$ORIGIN example. -@ soa foo bar 1 2 3 4 5 -@ ns ns1 -@ ns ns2 -ns1 1d1s a 10.0.0.1 -ns2 1w1D1h1m1S a 10.0.0.2 -""" - -no_soa_text = """$TTL 1h -$ORIGIN example. -@ ns ns1 -@ ns ns2 -ns1 1d1s a 10.0.0.1 -ns2 1w1D1h1m1S a 10.0.0.2 -""" - -no_ns_text = """$TTL 1h -$ORIGIN example. -@ soa foo bar 1 2 3 4 5 -""" - -include_text = """$INCLUDE "%s" -""" % fname("example", sep="/") - -bad_directive_text = """$FOO bar -$ORIGIN example. -@ soa foo bar 1 2 3 4 5 -@ ns ns1 -@ ns ns2 -ns1 1d1s a 10.0.0.1 -ns2 1w1D1h1m1S a 10.0.0.2 -""" - -def get_file_lines (fn): - res = [] - with open(fn) as fd: - for line in fd: - res.append(line) - return res - - -def get_file_diff (fn1, fn2): - res = [] - c1 = get_file_lines(fn1) - c2 = get_file_lines(fn2) - for line in difflib.unified_diff(c1, c2): - if not isinstance(line, unicode): - line = unicode(line, "iso8859-1", "ignore") - res.append(line) - return res - - -class TestZone (unittest.TestCase): - - def testFromFile1(self): - z = linkcheck.dns.zone.from_file(fname('example'), 'example') - diff = True - try: - z.to_file(fname('example1.out'), nl='\x0a') - fn1 = fname('example1.out') - fn2 = fname('example1.good') - diff = get_file_diff(fn1, fn2) - finally: - os.unlink(fname('example1.out')) - self.assertFalse(diff) - - def testFromFile2(self): - z = linkcheck.dns.zone.from_file(fname('example'), 'example', - relativize=False) - diff = True - try: - z.to_file(fname('example2.out'), relativize=False, nl='\x0a') - fn1 = fname('example2.out') - fn2 = fname('example2.good') - diff = get_file_diff(fn1, fn2) - finally: - os.unlink(fname('example2.out')) - self.assertFalse(diff) - - def testFromText(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - f = StringIO() - names = z.nodes.keys() - names.sort() - for n in names: - print >> f, z[n].to_text(n) - self.assertEqual(f.getvalue(), example_text_output) - - def testTorture1(self): - - # Read a zone containing all our supported RR types, and - # for each RR in the zone, convert the rdata into wire format - # and then back out, and see if we get equal rdatas. - - f = StringIO() - o = linkcheck.dns.name.from_text('example.') - z = linkcheck.dns.zone.from_file(fname('example'), o) - for (name, node) in z.iteritems(): - for rds in node: - for rd in rds: - f.seek(0) - f.truncate() - rd.to_wire(f, origin=o) - wire = f.getvalue() - rd2 = linkcheck.dns.rdata.from_wire(rds.rdclass, rds.rdtype, - wire, 0, len(wire), - origin = o) - self.assertEqual(rd, rd2) - - def testEqual(self): - z1 = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - z2 = linkcheck.dns.zone.from_text(example_text_output, 'example.', - relativize=True) - self.assertEqual(z1, z2) - - def testNotEqual1(self): - z1 = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - z2 = linkcheck.dns.zone.from_text(something_quite_similar, 'example.', - relativize=True) - self.assertNotEqual(z1, z2) - - def testNotEqual2(self): - z1 = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - z2 = linkcheck.dns.zone.from_text(something_different, 'example.', - relativize=True) - self.assertNotEqual(z1, z2) - - def testNotEqual3(self): - z1 = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - z2 = linkcheck.dns.zone.from_text(something_different, 'example2.', - relativize=True) - self.assertNotEqual(z1, z2) - - def testFindRdataset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rds = z.find_rdataset('@', 'soa') - exrds = linkcheck.dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') - self.assertEqual(rds, exrds) - - def testFindRdataset2(self): - def bad(): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rds = z.find_rdataset('@', 'loc') - self.assertRaises(KeyError, bad) - - def testFindRRset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rrs = z.find_rrset('@', 'soa') - exrrs = linkcheck.dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') - self.assertEqual(rrs, exrrs) - - def testFindRRset2(self): - def bad(): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rrs = z.find_rrset('@', 'loc') - self.assertRaises(KeyError, bad) - - def testGetRdataset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rds = z.get_rdataset('@', 'soa') - exrds = linkcheck.dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') - self.assertEqual(rds, exrds) - - def testGetRdataset2(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rds = z.get_rdataset('@', 'loc') - self.assertEqual(rds, None) - - def testGetRRset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rrs = z.get_rrset('@', 'soa') - exrrs = linkcheck.dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') - self.assertEqual(rrs, exrrs) - - def testGetRRset2(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rrs = z.get_rrset('@', 'loc') - self.assertEqual(rrs, None) - - def testReplaceRdataset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rdataset = linkcheck.dns.rdataset.from_text('in', 'ns', 300, 'ns3', 'ns4') - z.replace_rdataset('@', rdataset) - rds = z.get_rdataset('@', 'ns') - self.assertTrue(rds is rdataset) - - def testReplaceRdataset2(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - rdataset = linkcheck.dns.rdataset.from_text('in', 'txt', 300, '"foo"') - z.replace_rdataset('@', rdataset) - rds = z.get_rdataset('@', 'txt') - self.assertTrue(rds is rdataset) - - def testDeleteRdataset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - z.delete_rdataset('@', 'ns') - rds = z.get_rdataset('@', 'ns') - self.assertTrue(rds is None) - - def testDeleteRdataset2(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - z.delete_rdataset('ns1', 'a') - node = z.get_node('ns1') - self.assertTrue(node is None) - - def testNodeFindRdataset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - node = z['@'] - rds = node.find_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.SOA) - exrds = linkcheck.dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') - self.assertEqual(rds, exrds) - - def testNodeFindRdataset2(self): - def bad(): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - node = z['@'] - rds = node.find_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.LOC) - self.assertRaises(KeyError, bad) - - def testNodeGetRdataset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - node = z['@'] - rds = node.get_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.SOA) - exrds = linkcheck.dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') - self.assertEqual(rds, exrds) - - def testNodeGetRdataset2(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - node = z['@'] - rds = node.get_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.LOC) - self.assertEqual(rds, None) - - def testNodeDeleteRdataset1(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - node = z['@'] - rds = node.delete_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.SOA) - rds = node.get_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.SOA) - self.assertEqual(rds, None) - - def testNodeDeleteRdataset2(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - node = z['@'] - rds = node.delete_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.LOC) - rds = node.get_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.LOC) - self.assertEqual(rds, None) - - def testIterateRdatasets(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - ns = [n for n, r in z.iterate_rdatasets('A')] - ns.sort() - self.assertEqual(ns, [linkcheck.dns.name.from_text('ns1', None), - linkcheck.dns.name.from_text('ns2', None)]) - - def testIterateAllRdatasets(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - ns = [n for n, r in z.iterate_rdatasets()] - ns.sort() - self.assertTrue(ns == [linkcheck.dns.name.from_text('@', None), - linkcheck.dns.name.from_text('@', None), - linkcheck.dns.name.from_text('bar.foo', None), - linkcheck.dns.name.from_text('ns1', None), - linkcheck.dns.name.from_text('ns2', None)]) - - def testIterateRdatas(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - l = list(z.iterate_rdatas('A')) - l.sort() - exl = [(linkcheck.dns.name.from_text('ns1', None), - 3600, - linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.A, - '10.0.0.1')), - (linkcheck.dns.name.from_text('ns2', None), - 3600, - linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.A, - '10.0.0.2'))] - self.assertEqual(l, exl) - - def testIterateAllRdatas(self): - z = linkcheck.dns.zone.from_text(example_text, 'example.', relativize=True) - l = list(z.iterate_rdatas()) - l.sort() - exl = [(linkcheck.dns.name.from_text('@', None), - 3600, - linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, - linkcheck.dns.rdatatype.NS, 'ns1')), - (linkcheck.dns.name.from_text('@', None), - 3600, - linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, - linkcheck.dns.rdatatype.NS, 'ns2')), - (linkcheck.dns.name.from_text('@', None), - 3600, - linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, - linkcheck.dns.rdatatype.SOA, - 'foo bar 1 2 3 4 5')), - (linkcheck.dns.name.from_text('bar.foo', None), - 300, - linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, - linkcheck.dns.rdatatype.MX, - '0 blaz.foo')), - (linkcheck.dns.name.from_text('ns1', None), - 3600, - linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, - linkcheck.dns.rdatatype.A, - '10.0.0.1')), - (linkcheck.dns.name.from_text('ns2', None), - 3600, - linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, - linkcheck.dns.rdatatype.A, - '10.0.0.2'))] - self.assertEqual(l, exl) - - def testTTLs(self): - z = linkcheck.dns.zone.from_text(ttl_example_text, 'example.', relativize=True) - n = z['@'] - rds = n.get_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.SOA) - self.assertEqual(rds.ttl, 3600) - n = z['ns1'] - rds = n.get_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.A) - self.assertEqual(rds.ttl, 86401) - n = z['ns2'] - rds = n.get_rdataset(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.A) - self.assertEqual(rds.ttl, 694861) - - def testNoSOA(self): - def bad(): - z = linkcheck.dns.zone.from_text(no_soa_text, 'example.', - relativize=True) - self.assertRaises(linkcheck.dns.zone.NoSOA, bad) - - def testNoNS(self): - def bad(): - z = linkcheck.dns.zone.from_text(no_ns_text, 'example.', - relativize=True) - self.assertRaises(linkcheck.dns.zone.NoNS, bad) - - def testInclude(self): - z1 = linkcheck.dns.zone.from_text(include_text, 'example.', relativize=True, - allow_include=True) - z2 = linkcheck.dns.zone.from_file(fname('example'), 'example.', - relativize=True) - self.assertEqual(z1, z2) - - def testBadDirective(self): - def bad(): - z = linkcheck.dns.zone.from_text(bad_directive_text, 'example.', - relativize=True) - self.assertRaises(linkcheck.dns.exception.DNSSyntaxError, bad) diff --git a/linkcheck/dns/changelog.txt b/third_party/dnspython/changelog.txt similarity index 55% rename from linkcheck/dns/changelog.txt rename to third_party/dnspython/changelog.txt index 2448532e..bc743bdc 100644 --- a/linkcheck/dns/changelog.txt +++ b/third_party/dnspython/changelog.txt @@ -1,23 +1,20 @@ The following changes were made to the original dnspython sources: -* moved everything into the linkcheck package +* Replace bare "except:" with "except StandardError:" and + make DNSException inherit from StandardError. + Avoids catching StopIteration and Warning exceptions. + Changed: *.py + +* Replace "x.has_key(y)" with "y in x". Changed: *.py -* moved unittests and adapted them for the schooltool.org test runner - Changed: tests/*.py - -* fixed missing random import - Changed: renderer.py - -* honor EnableDHCP flag in Windows registry config +* honor EnableDHCP flag in Windows registry config and add __str__() + method Changed: resolver.py * strip() lines from /etc/resolv.conf Changed: resolver.py -* minor syntax cleanups - Changed: *.py - * added set of localhost addresses to resolver config Changed: resolver.py Added: ifconfig.py diff --git a/linkcheck/dns/__init__.py b/third_party/dnspython/dns/__init__.py similarity index 93% rename from linkcheck/dns/__init__.py rename to third_party/dnspython/dns/__init__.py index 29f60073..c848e485 100644 --- a/linkcheck/dns/__init__.py +++ b/third_party/dnspython/dns/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009 Nominum, Inc. +# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -23,6 +22,7 @@ __all__ = [ 'entropy', 'exception', 'flags', + 'hash', 'inet', 'ipv4', 'ipv6', @@ -49,5 +49,6 @@ __all__ = [ 'rdtypes', 'update', 'version', + 'wiredata', 'zone', ] diff --git a/third_party/dnspython/dns/dnssec.py b/third_party/dnspython/dns/dnssec.py new file mode 100644 index 00000000..dd6a27a5 --- /dev/null +++ b/third_party/dnspython/dns/dnssec.py @@ -0,0 +1,372 @@ +# Copyright (C) 2003-2007, 2009, 2011 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. + +"""Common DNSSEC-related functions and constants.""" + +import cStringIO +import struct +import time + +import dns.exception +import dns.hash +import dns.name +import dns.node +import dns.rdataset +import dns.rdata +import dns.rdatatype +import dns.rdataclass + +class UnsupportedAlgorithm(dns.exception.DNSException): + """Raised if an algorithm is not supported.""" + pass + +class ValidationFailure(dns.exception.DNSException): + """The DNSSEC signature is invalid.""" + pass + +RSAMD5 = 1 +DH = 2 +DSA = 3 +ECC = 4 +RSASHA1 = 5 +DSANSEC3SHA1 = 6 +RSASHA1NSEC3SHA1 = 7 +RSASHA256 = 8 +RSASHA512 = 10 +INDIRECT = 252 +PRIVATEDNS = 253 +PRIVATEOID = 254 + +_algorithm_by_text = { + 'RSAMD5' : RSAMD5, + 'DH' : DH, + 'DSA' : DSA, + 'ECC' : ECC, + 'RSASHA1' : RSASHA1, + 'DSANSEC3SHA1' : DSANSEC3SHA1, + 'RSASHA1NSEC3SHA1' : RSASHA1NSEC3SHA1, + 'RSASHA256' : RSASHA256, + 'RSASHA512' : RSASHA512, + 'INDIRECT' : INDIRECT, + 'PRIVATEDNS' : PRIVATEDNS, + 'PRIVATEOID' : PRIVATEOID, + } + +# 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. + +_algorithm_by_value = dict([(y, x) for x, y in _algorithm_by_text.iteritems()]) + +def algorithm_from_text(text): + """Convert text into a DNSSEC algorithm value + @rtype: int""" + + value = _algorithm_by_text.get(text.upper()) + if value is None: + value = int(text) + return value + +def algorithm_to_text(value): + """Convert a DNSSEC algorithm value to text + @rtype: string""" + + text = _algorithm_by_value.get(value) + if text is None: + text = str(value) + return text + +def _to_rdata(record, origin): + s = cStringIO.StringIO() + record.to_wire(s, origin=origin) + return s.getvalue() + +def key_id(key, origin=None): + rdata = _to_rdata(key, origin) + if key.algorithm == RSAMD5: + return (ord(rdata[-3]) << 8) + ord(rdata[-2]) + else: + total = 0 + for i in range(len(rdata) // 2): + total += (ord(rdata[2 * i]) << 8) + ord(rdata[2 * i + 1]) + if len(rdata) % 2 != 0: + total += ord(rdata[len(rdata) - 1]) << 8 + total += ((total >> 16) & 0xffff); + return total & 0xffff + +def make_ds(name, key, algorithm, origin=None): + if algorithm.upper() == 'SHA1': + dsalg = 1 + hash = dns.hash.get('SHA1')() + elif algorithm.upper() == 'SHA256': + dsalg = 2 + hash = dns.hash.get('SHA256')() + else: + raise UnsupportedAlgorithm, 'unsupported algorithm "%s"' % algorithm + + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, origin) + hash.update(name.canonicalize().to_wire()) + hash.update(_to_rdata(key, origin)) + digest = hash.digest() + + dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest + return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, + len(dsrdata)) + +def _find_key(keys, rrsig): + value = keys.get(rrsig.signer) + if value is None: + return None + if isinstance(value, dns.node.Node): + try: + rdataset = node.find_rdataset(dns.rdataclass.IN, + dns.rdatatype.DNSKEY) + except KeyError: + return None + else: + rdataset = value + for rdata in rdataset: + if rdata.algorithm == rrsig.algorithm and \ + key_id(rdata) == rrsig.key_tag: + return rdata + return None + +def _is_rsa(algorithm): + return algorithm in (RSAMD5, RSASHA1, + RSASHA1NSEC3SHA1, RSASHA256, + RSASHA512) + +def _is_dsa(algorithm): + return algorithm in (DSA, DSANSEC3SHA1) + +def _is_md5(algorithm): + return algorithm == RSAMD5 + +def _is_sha1(algorithm): + return algorithm in (DSA, RSASHA1, + DSANSEC3SHA1, RSASHA1NSEC3SHA1) + +def _is_sha256(algorithm): + return algorithm == RSASHA256 + +def _is_sha512(algorithm): + return algorithm == RSASHA512 + +def _make_hash(algorithm): + if _is_md5(algorithm): + return dns.hash.get('MD5')() + if _is_sha1(algorithm): + return dns.hash.get('SHA1')() + if _is_sha256(algorithm): + return dns.hash.get('SHA256')() + if _is_sha512(algorithm): + return dns.hash.get('SHA512')() + raise ValidationFailure, 'unknown hash for algorithm %u' % algorithm + +def _make_algorithm_id(algorithm): + if _is_md5(algorithm): + oid = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05] + elif _is_sha1(algorithm): + oid = [0x2b, 0x0e, 0x03, 0x02, 0x1a] + elif _is_sha256(algorithm): + oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01] + elif _is_sha512(algorithm): + oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03] + else: + raise ValidationFailure, 'unknown algorithm %u' % algorithm + olen = len(oid) + dlen = _make_hash(algorithm).digest_size + idbytes = [0x30] + [8 + olen + dlen] + \ + [0x30, olen + 4] + [0x06, olen] + oid + \ + [0x05, 0x00] + [0x04, dlen] + return ''.join(map(chr, idbytes)) + +def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): + """Validate an RRset against a single signature rdata + + The owner name of the rrsig is assumed to be the same as the owner name + of the rrset. + + @param rrset: The RRset to validate + @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) + tuple + @param rrsig: The signature rdata + @type rrsig: dns.rrset.Rdata + @param keys: The key dictionary. + @type keys: a dictionary keyed by dns.name.Name with node or rdataset values + @param origin: The origin to use for relative names + @type origin: dns.name.Name or None + @param now: The time to use when validating the signatures. The default + is the current time. + @type now: int + """ + + if isinstance(origin, (str, unicode)): + origin = dns.name.from_text(origin, dns.name.root) + + key = _find_key(keys, rrsig) + if not key: + raise ValidationFailure, 'unknown key' + + # For convenience, allow the rrset to be specified as a (name, rdataset) + # tuple as well as a proper rrset + if isinstance(rrset, tuple): + rrname = rrset[0] + rdataset = rrset[1] + else: + rrname = rrset.name + rdataset = rrset + + if now is None: + now = time.time() + if rrsig.expiration < now: + raise ValidationFailure, 'expired' + if rrsig.inception > now: + raise ValidationFailure, 'not yet valid' + + hash = _make_hash(rrsig.algorithm) + + if _is_rsa(rrsig.algorithm): + keyptr = key.key + (bytes,) = struct.unpack('!B', keyptr[0:1]) + keyptr = keyptr[1:] + if bytes == 0: + (bytes,) = struct.unpack('!H', keyptr[0:2]) + keyptr = keyptr[2:] + rsa_e = keyptr[0:bytes] + rsa_n = keyptr[bytes:] + keylen = len(rsa_n) * 8 + pubkey = Crypto.PublicKey.RSA.construct( + (Crypto.Util.number.bytes_to_long(rsa_n), + Crypto.Util.number.bytes_to_long(rsa_e))) + sig = (Crypto.Util.number.bytes_to_long(rrsig.signature),) + elif _is_dsa(rrsig.algorithm): + keyptr = key.key + (t,) = struct.unpack('!B', keyptr[0:1]) + keyptr = keyptr[1:] + octets = 64 + t * 8 + dsa_q = keyptr[0:20] + keyptr = keyptr[20:] + dsa_p = keyptr[0:octets] + keyptr = keyptr[octets:] + dsa_g = keyptr[0:octets] + keyptr = keyptr[octets:] + dsa_y = keyptr[0:octets] + pubkey = Crypto.PublicKey.DSA.construct( + (Crypto.Util.number.bytes_to_long(dsa_y), + Crypto.Util.number.bytes_to_long(dsa_g), + Crypto.Util.number.bytes_to_long(dsa_p), + Crypto.Util.number.bytes_to_long(dsa_q))) + (dsa_r, dsa_s) = struct.unpack('!20s20s', rrsig.signature[1:]) + sig = (Crypto.Util.number.bytes_to_long(dsa_r), + Crypto.Util.number.bytes_to_long(dsa_s)) + else: + raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm + + hash.update(_to_rdata(rrsig, origin)[:18]) + hash.update(rrsig.signer.to_digestable(origin)) + + if rrsig.labels < len(rrname) - 1: + suffix = rrname.split(rrsig.labels + 1)[1] + rrname = dns.name.from_text('*', suffix) + rrnamebuf = rrname.to_digestable(origin) + rrfixed = struct.pack('!HHI', rdataset.rdtype, rdataset.rdclass, + rrsig.original_ttl) + rrlist = sorted(rdataset); + for rr in rrlist: + hash.update(rrnamebuf) + hash.update(rrfixed) + rrdata = rr.to_digestable(origin) + rrlen = struct.pack('!H', len(rrdata)) + hash.update(rrlen) + hash.update(rrdata) + + digest = hash.digest() + + if _is_rsa(rrsig.algorithm): + # PKCS1 algorithm identifier goop + digest = _make_algorithm_id(rrsig.algorithm) + digest + padlen = keylen // 8 - len(digest) - 3 + digest = chr(0) + chr(1) + chr(0xFF) * padlen + chr(0) + digest + elif _is_dsa(rrsig.algorithm): + pass + else: + # Raise here for code clarity; this won't actually ever happen + # since if the algorithm is really unknown we'd already have + # raised an exception above + raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm + + if not pubkey.verify(digest, sig): + raise ValidationFailure, 'verify failure' + +def _validate(rrset, rrsigset, keys, origin=None, now=None): + """Validate an RRset + + @param rrset: The RRset to validate + @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) + tuple + @param rrsigset: The signature RRset + @type rrsigset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) + tuple + @param keys: The key dictionary. + @type keys: a dictionary keyed by dns.name.Name with node or rdataset values + @param origin: The origin to use for relative names + @type origin: dns.name.Name or None + @param now: The time to use when validating the signatures. The default + is the current time. + @type now: int + """ + + if isinstance(origin, (str, unicode)): + origin = dns.name.from_text(origin, dns.name.root) + + if isinstance(rrset, tuple): + rrname = rrset[0] + else: + rrname = rrset.name + + if isinstance(rrsigset, tuple): + rrsigname = rrsigset[0] + rrsigrdataset = rrsigset[1] + else: + rrsigname = rrsigset.name + rrsigrdataset = rrsigset + + rrname = rrname.choose_relativity(origin) + rrsigname = rrname.choose_relativity(origin) + if rrname != rrsigname: + raise ValidationFailure, "owner names do not match" + + for rrsig in rrsigrdataset: + try: + _validate_rrsig(rrset, rrsig, keys, origin, now) + return + except ValidationFailure, e: + pass + raise ValidationFailure, "no RRSIGs validated" + +def _need_pycrypto(*args, **kwargs): + raise NotImplementedError, "DNSSEC validation requires pycrypto" + +try: + import Crypto.PublicKey.RSA + import Crypto.PublicKey.DSA + import Crypto.Util.number + validate = _validate + validate_rrsig = _validate_rrsig +except ImportError: + validate = _need_pycrypto + validate_rrsig = _need_pycrypto diff --git a/linkcheck/dns/e164.py b/third_party/dnspython/dns/e164.py similarity index 70% rename from linkcheck/dns/e164.py rename to third_party/dnspython/dns/e164.py index c916a52e..d6dcd1b1 100644 --- a/linkcheck/dns/e164.py +++ b/third_party/dnspython/dns/e164.py @@ -1,4 +1,4 @@ -# Copyright (C) 2006, 2007, 2009 Nominum, Inc. +# Copyright (C) 2006, 2007, 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,14 +16,14 @@ """DNS E.164 helpers @var public_enum_domain: The DNS public ENUM domain, e164.arpa. -@type public_enum_domain: linkcheck.dns.name.Name object +@type public_enum_domain: dns.name.Name object """ -import linkcheck.dns.exception -import linkcheck.dns.name -import linkcheck.dns.resolver +import dns.exception +import dns.name +import dns.resolver -public_enum_domain = linkcheck.dns.name.from_text('e164.arpa.') +public_enum_domain = dns.name.from_text('e164.arpa.') def from_e164(text, origin=public_enum_domain): """Convert an E.164 number in textual form into a Name object whose @@ -32,20 +32,20 @@ def from_e164(text, origin=public_enum_domain): @type text: str @param origin: The domain in which the number should be constructed. The default is e164.arpa. - @type: linkcheck.dns.name.Name object or None - @rtype: linkcheck.dns.name.Name object + @type: dns.name.Name object or None + @rtype: dns.name.Name object """ parts = [d for d in text if d.isdigit()] parts.reverse() - return linkcheck.dns.name.from_text('.'.join(parts), origin=origin) + return dns.name.from_text('.'.join(parts), origin=origin) def to_e164(name, origin=public_enum_domain, want_plus_prefix=True): """Convert an ENUM domain name into an E.164 number. @param name: the ENUM domain name. - @type name: linkcheck.dns.name.Name object. + @type name: dns.name.Name object. @param origin: A domain containing the ENUM domain name. The name is relativized to this domain before being converted to text. - @type: linkcheck.dns.name.Name object or None + @type: dns.name.Name object or None @param want_plus_prefix: if True, add a '+' to the beginning of the returned number. @rtype: str @@ -54,7 +54,7 @@ def to_e164(name, origin=public_enum_domain, want_plus_prefix=True): name = name.relativize(origin) dlabels = [d for d in name.labels if (d.isdigit() and len(d) == 1)] if len(dlabels) != len(name.labels): - raise linkcheck.dns.exception.SyntaxError('non-digit labels in ENUM domain name') + raise dns.exception.SyntaxError('non-digit labels in ENUM domain name') dlabels.reverse() text = ''.join(dlabels) if want_plus_prefix: @@ -67,13 +67,13 @@ def query(number, domains, resolver=None): e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.']) """ if resolver is None: - resolver = linkcheck.dns.resolver.get_default_resolver() + resolver = dns.resolver.get_default_resolver() for domain in domains: if isinstance(domain, (str, unicode)): - domain = linkcheck.dns.name.from_text(domain) - qname = linkcheck.dns.e164.from_e164(number, domain) + domain = dns.name.from_text(domain) + qname = dns.e164.from_e164(number, domain) try: - return linkcheck.dns.resolver.query(qname, 'NAPTR') - except linkcheck.dns.resolver.NXDOMAIN: + return resolver.query(qname, 'NAPTR') + except dns.resolver.NXDOMAIN: pass - raise linkcheck.dns.resolver.NXDOMAIN + raise dns.resolver.NXDOMAIN diff --git a/linkcheck/dns/edns.py b/third_party/dnspython/dns/edns.py similarity index 95% rename from linkcheck/dns/edns.py rename to third_party/dnspython/dns/edns.py index 41a62c3f..f8b6009d 100644 --- a/linkcheck/dns/edns.py +++ b/third_party/dnspython/dns/edns.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Nominum, Inc. +# Copyright (C) 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -44,7 +44,7 @@ class Option(object): @type current: int @param olen: The length of the wire-format option data @type olen: int - @rtype: linkcheck.dns.ends.Option instance""" + @rtype: dns.ends.Option instance""" raise NotImplementedError from_wire = classmethod(from_wire) @@ -114,7 +114,7 @@ class GenericOption(Option): from_wire = classmethod(from_wire) def _cmp(self, other): - return cmp(self.data, other.data) + return cmp(self.data, other.data) _type_to_class = { } @@ -136,7 +136,7 @@ def option_from_wire(otype, wire, current, olen): @type current: int @param olen: The length of the wire-format option data @type olen: int - @rtype: linkcheck.dns.ends.Option instance""" + @rtype: dns.ends.Option instance""" cls = get_option_class(otype) return cls.from_wire(otype, wire, current, olen) diff --git a/linkcheck/dns/entropy.py b/third_party/dnspython/dns/entropy.py similarity index 94% rename from linkcheck/dns/entropy.py rename to third_party/dnspython/dns/entropy.py index 5396732f..7efd2e53 100644 --- a/linkcheck/dns/entropy.py +++ b/third_party/dnspython/dns/entropy.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Nominum, Inc. +# Copyright (C) 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -30,12 +30,12 @@ class EntropyPool(object): import hashlib self.hash = hashlib.sha1() self.hash_len = 20 - except: + except StandardError: try: import sha self.hash = sha.new() self.hash_len = 20 - except: + except StandardError: import md5 self.hash = md5.new() self.hash_len = 16 @@ -66,14 +66,14 @@ class EntropyPool(object): if not self.seeded: try: seed = os.urandom(16) - except: + except StandardError: try: r = file('/dev/urandom', 'r', 0) try: seed = r.read(16) finally: r.close() - except: + except StandardError: seed = str(time.time()) self.seeded = True self.stir(seed, True) @@ -112,7 +112,7 @@ class EntropyPool(object): else: rand = self.random_8 max = 255 - return (first + size * rand() // (max + 1)) + return (first + size * rand() // (max + 1)) pool = EntropyPool() diff --git a/linkcheck/dns/exception.py b/third_party/dnspython/dns/exception.py similarity index 88% rename from linkcheck/dns/exception.py rename to third_party/dnspython/dns/exception.py index e124b53b..675b6c89 100644 --- a/linkcheck/dns/exception.py +++ b/third_party/dnspython/dns/exception.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -24,11 +23,11 @@ class FormError(DNSException): """DNS message is malformed.""" pass -class DNSSyntaxError(DNSException): +class SyntaxError(DNSException): """Text input is malformed.""" pass -class UnexpectedEnd(DNSSyntaxError): +class UnexpectedEnd(SyntaxError): """Raised if text input ends unexpectedly.""" pass diff --git a/linkcheck/dns/flags.py b/third_party/dnspython/dns/flags.py similarity index 96% rename from linkcheck/dns/flags.py rename to third_party/dnspython/dns/flags.py index 873fadfa..35a8305e 100644 --- a/linkcheck/dns/flags.py +++ b/third_party/dnspython/dns/flags.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -90,7 +89,7 @@ def to_text(flags): @rtype: string""" return _to_text(flags, _by_value, _flags_order) - + def edns_from_text(text): """Convert a space-separated list of EDNS flag text values into a EDNS diff --git a/third_party/dnspython/dns/hash.py b/third_party/dnspython/dns/hash.py new file mode 100644 index 00000000..0c708036 --- /dev/null +++ b/third_party/dnspython/dns/hash.py @@ -0,0 +1,67 @@ +# Copyright (C) 2011 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. + +"""Hashing backwards compatibility wrapper""" + +import sys + +_hashes = None + +def _need_later_python(alg): + def func(*args, **kwargs): + raise NotImplementedError("TSIG algorithm " + alg + + " requires Python 2.5.2 or later") + return func + +def _setup(): + global _hashes + _hashes = {} + try: + import hashlib + _hashes['MD5'] = hashlib.md5 + _hashes['SHA1'] = hashlib.sha1 + _hashes['SHA224'] = hashlib.sha224 + _hashes['SHA256'] = hashlib.sha256 + if sys.hexversion >= 0x02050200: + _hashes['SHA384'] = hashlib.sha384 + _hashes['SHA512'] = hashlib.sha512 + else: + _hashes['SHA384'] = _need_later_python('SHA384') + _hashes['SHA512'] = _need_later_python('SHA512') + + if sys.hexversion < 0x02050000: + # hashlib doesn't conform to PEP 247: API for + # Cryptographic Hash Functions, which hmac before python + # 2.5 requires, so add the necessary items. + class HashlibWrapper: + def __init__(self, basehash): + self.basehash = basehash + self.digest_size = self.basehash().digest_size + + def new(self, *args, **kwargs): + return self.basehash(*args, **kwargs) + + for name in _hashes: + _hashes[name] = HashlibWrapper(_hashes[name]) + + except ImportError: + import md5, sha + _hashes['MD5'] = md5 + _hashes['SHA1'] = sha + +def get(algorithm): + if _hashes is None: + _setup() + return _hashes[algorithm.upper()] diff --git a/linkcheck/dns/inet.py b/third_party/dnspython/dns/inet.py similarity index 81% rename from linkcheck/dns/inet.py rename to third_party/dnspython/dns/inet.py index cdd9864e..27ca5c6a 100644 --- a/linkcheck/dns/inet.py +++ b/third_party/dnspython/dns/inet.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -18,8 +17,8 @@ import socket -import linkcheck.dns.ipv4 -import linkcheck.dns.ipv6 +import dns.ipv4 +import dns.ipv6 # We assume that AF_INET is always defined. @@ -46,11 +45,11 @@ def inet_pton(family, text): implemented. @rtype: string """ - + if family == AF_INET: - return linkcheck.dns.ipv4.inet_aton(text) + return dns.ipv4.inet_aton(text) elif family == AF_INET6: - return linkcheck.dns.ipv6.inet_aton(text) + return dns.ipv6.inet_aton(text) else: raise NotImplementedError @@ -66,9 +65,9 @@ def inet_ntop(family, address): @rtype: string """ if family == AF_INET: - return linkcheck.dns.ipv4.inet_ntoa(address) + return dns.ipv4.inet_ntoa(address) elif family == AF_INET6: - return linkcheck.dns.ipv6.inet_ntoa(address) + return dns.ipv6.inet_ntoa(address) else: raise NotImplementedError @@ -78,14 +77,14 @@ def af_for_address(text): @param text: the textual address @type text: string @raises ValueError: the address family cannot be determined from the input. - @rtype int + @rtype: int """ try: - junk = linkcheck.dns.ipv4.inet_aton(text) + junk = dns.ipv4.inet_aton(text) return AF_INET except StandardError: try: - junk = linkcheck.dns.ipv6.inet_aton(text) + junk = dns.ipv6.inet_aton(text) return AF_INET6 except StandardError: raise ValueError @@ -98,11 +97,12 @@ def is_multicast(text): @rtype: bool """ try: - first = ord(linkcheck.dns.ipv4.inet_aton(text)[0]) + first = ord(dns.ipv4.inet_aton(text)[0]) return (first >= 224 and first <= 239) - except: + except StandardError: try: - first = ord(linkcheck.dns.ipv6.inet_aton(text)[0]) + first = ord(dns.ipv6.inet_aton(text)[0]) return (first == 255) - except: + except StandardError: raise ValueError + diff --git a/linkcheck/dns/ipv4.py b/third_party/dnspython/dns/ipv4.py similarity index 94% rename from linkcheck/dns/ipv4.py rename to third_party/dnspython/dns/ipv4.py index 17c7bd6c..8d45b44e 100644 --- a/linkcheck/dns/ipv4.py +++ b/third_party/dnspython/dns/ipv4.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, diff --git a/linkcheck/dns/ipv6.py b/third_party/dnspython/dns/ipv6.py similarity index 82% rename from linkcheck/dns/ipv6.py rename to third_party/dnspython/dns/ipv6.py index 9c2f9759..8363fe42 100644 --- a/linkcheck/dns/ipv6.py +++ b/third_party/dnspython/dns/ipv6.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -18,8 +17,8 @@ import re -import linkcheck.dns.exception -import linkcheck.dns.ipv4 +import dns.exception +import dns.ipv4 _leading_zero = re.compile(r'0+([0-9a-f]+)') @@ -34,19 +33,19 @@ def inet_ntoa(address): if len(address) != 16: raise ValueError("IPv6 addresses are 16 bytes long") - hexip = address.encode('hex_codec') + hex = address.encode('hex_codec') chunks = [] i = 0 - l = len(hexip) + l = len(hex) while i < l: - ipchunk = hexip[i : i + 4] + chunk = hex[i : i + 4] # strip leading zeros. we do this with an re instead of # with lstrip() because lstrip() didn't support chars until # python 2.2.2 - m = _leading_zero.match(ipchunk) + m = _leading_zero.match(chunk) if not m is None: - ipchunk = m.group(1) - chunks.append(ipchunk) + chunk = m.group(1) + chunks.append(chunk) i += 4 # # Compress the longest subsequence of 0-value chunks to :: @@ -82,13 +81,13 @@ def inet_ntoa(address): prefix = '::' else: prefix = '::ffff:' - hexip = prefix + linkcheck.dns.ipv4.inet_ntoa(address[12:]) + hex = prefix + dns.ipv4.inet_ntoa(address[12:]) else: - hexip = ':'.join(chunks[:best_start]) + '::' + \ + hex = ':'.join(chunks[:best_start]) + '::' + \ ':'.join(chunks[best_start + best_len:]) else: - hexip = ':'.join(chunks) - return hexip + hex = ':'.join(chunks) + return hex _v4_ending = re.compile(r'(.*):(\d+)\.(\d+)\.(\d+)\.(\d+)$') _colon_colon_start = re.compile(r'::.*') @@ -100,7 +99,7 @@ def inet_aton(text): @param text: the textual address @type text: string @rtype: string - @raises linkcheck.dns.exception.DNSSyntaxError: the text was not properly formatted + @raises dns.exception.SyntaxError: the text was not properly formatted """ # @@ -134,25 +133,25 @@ def inet_aton(text): chunks = text.split(':') l = len(chunks) if l > 8: - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError seen_empty = False canonical = [] for c in chunks: if c == '': if seen_empty: - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError seen_empty = True for i in xrange(0, 8 - l + 1): canonical.append('0000') else: lc = len(c) if lc > 4: - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError if lc != 4: c = ('0' * (4 - lc)) + c canonical.append(c) if l < 8 and not seen_empty: - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError text = ''.join(canonical) # @@ -161,4 +160,4 @@ def inet_aton(text): try: return text.decode('hex_codec') except TypeError: - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError diff --git a/linkcheck/dns/message.py b/third_party/dnspython/dns/message.py similarity index 77% rename from linkcheck/dns/message.py rename to third_party/dnspython/dns/message.py index ae86e546..32896173 100644 --- a/linkcheck/dns/message.py +++ b/third_party/dnspython/dns/message.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,49 +15,52 @@ """DNS Messages""" -from cStringIO import StringIO +import cStringIO +import random import struct +import sys import time -import linkcheck.dns.edns -import linkcheck.dns.exception -import linkcheck.dns.flags -import linkcheck.dns.name -import linkcheck.dns.opcode -import linkcheck.dns.entropy -import linkcheck.dns.rcode -import linkcheck.dns.rdata -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype -import linkcheck.dns.rrset -import linkcheck.dns.renderer -import linkcheck.dns.tsig +import dns.edns +import dns.exception +import dns.flags +import dns.name +import dns.opcode +import dns.entropy +import dns.rcode +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset +import dns.renderer +import dns.tsig +import dns.wiredata -class ShortHeader(linkcheck.dns.exception.FormError): +class ShortHeader(dns.exception.FormError): """Raised if the DNS packet passed to from_wire() is too short.""" pass -class TrailingJunk(linkcheck.dns.exception.FormError): +class TrailingJunk(dns.exception.FormError): """Raised if the DNS packet passed to from_wire() has extra junk at the end of it.""" pass -class UnknownHeaderField(linkcheck.dns.exception.DNSException): +class UnknownHeaderField(dns.exception.DNSException): """Raised if a header field name is not recognized when converting from text into a message.""" pass -class BadEDNS(linkcheck.dns.exception.FormError): +class BadEDNS(dns.exception.FormError): """Raised if an OPT record occurs somewhere other than the start of the additional data section.""" pass -class BadTSIG(linkcheck.dns.exception.FormError): +class BadTSIG(dns.exception.FormError): """Raised if a TSIG record occurs somewhere other than the end of the additional data section.""" pass -class UnknownTSIGKey(linkcheck.dns.exception.DNSException): +class UnknownTSIGKey(dns.exception.DNSException): """Raised if we got a TSIG but don't know the key.""" pass @@ -71,36 +73,36 @@ class Message(object): explanation of these flags. @type flags: int @ivar question: The question section. - @type question: list of linkcheck.dns.rrset.RRset objects + @type question: list of dns.rrset.RRset objects @ivar answer: The answer section. - @type answer: list of linkcheck.dns.rrset.RRset objects + @type answer: list of dns.rrset.RRset objects @ivar authority: The authority section. - @type authority: list of linkcheck.dns.rrset.RRset objects + @type authority: list of dns.rrset.RRset objects @ivar additional: The additional data section. - @type additional: list of linkcheck.dns.rrset.RRset objects - @ivar edns: The EDNS level to use. The default is -1, no Elinkcheck.dns. + @type additional: list of dns.rrset.RRset objects + @ivar edns: The EDNS level to use. The default is -1, no Edns. @type edns: int @ivar ednsflags: The EDNS flags @type ednsflags: long @ivar payload: The EDNS payload size. The default is 0. @type payload: int @ivar options: The EDNS options - @type options: list of linkcheck.dns.edns.Option objects + @type options: list of dns.edns.Option objects @ivar request_payload: The associated request's EDNS payload size. @type request_payload: int @ivar keyring: The TSIG keyring to use. The default is None. @type keyring: dict @ivar keyname: The TSIG keyname to use. The default is None. - @type keyname: linkcheck.dns.name.Name object - @ivar request_mac: The TSIG MAC of the request message associated with - this message; used when validating TSIG signatures. @see: RFC 2845 for - more information on TSIG fields. + @type keyname: dns.name.Name object @ivar keyalgorithm: The TSIG algorithm to use; defaults to - linkcheck.dns.tsig.default_algorithm. Constants for TSIG algorithms are defined - in linkcheck.dns.tsig, and the currently implemented algorithms are + dns.tsig.default_algorithm. Constants for TSIG algorithms are defined + in dns.tsig, and the currently implemented algorithms are HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, and HMAC_SHA512. @type keyalgorithm: string + @ivar request_mac: The TSIG MAC of the request message associated with + this message; used when validating TSIG signatures. @see: RFC 2845 for + more information on TSIG fields. @type request_mac: string @ivar fudge: TSIG time fudge; default is 300 seconds. @type fudge: int @@ -117,7 +119,7 @@ class Message(object): @type xfr: bool @ivar origin: The origin of the zone in messages which are used for zone transfers or for DNS dynamic updates. The default is None. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @ivar tsig_ctx: The TSIG signature context associated with this message. The default is None. @type tsig_ctx: hmac.HMAC object @@ -140,7 +142,7 @@ class Message(object): def __init__(self, id=None): if id is None: - self.id = linkcheck.dns.entropy.random_16() + self.id = dns.entropy.random_16() else: self.id = id self.flags = 0 @@ -155,7 +157,7 @@ class Message(object): self.request_payload = 0 self.keyring = None self.keyname = None - self.keyalgorithm = linkcheck.dns.tsig.default_algorithm + self.keyalgorithm = dns.tsig.default_algorithm self.request_mac = '' self.other_data = '' self.tsig_error = 0 @@ -171,7 +173,7 @@ class Message(object): self.index = {} def __repr__(self): - return '' % self.id + return '' def __str__(self): return self.to_text() @@ -185,20 +187,20 @@ class Message(object): @rtype: string """ - s = StringIO() + s = cStringIO.StringIO() print >> s, 'id %d' % self.id print >> s, 'opcode %s' % \ - linkcheck.dns.opcode.to_text(linkcheck.dns.opcode.from_flags(self.flags)) - rc = linkcheck.dns.rcode.from_flags(self.flags, self.ednsflags) - print >> s, 'rcode %s' % linkcheck.dns.rcode.to_text(rc) - print >> s, 'flags %s' % linkcheck.dns.flags.to_text(self.flags) + dns.opcode.to_text(dns.opcode.from_flags(self.flags)) + rc = dns.rcode.from_flags(self.flags, self.ednsflags) + print >> s, 'rcode %s' % dns.rcode.to_text(rc) + print >> s, 'flags %s' % dns.flags.to_text(self.flags) if self.edns >= 0: print >> s, 'edns %s' % self.edns if self.ednsflags != 0: print >> s, 'eflags %s' % \ - linkcheck.dns.flags.edns_to_text(self.ednsflags) + dns.flags.edns_to_text(self.ednsflags) print >> s, 'payload', self.payload - is_update = linkcheck.dns.opcode.is_update(self.flags) + is_update = dns.opcode.is_update(self.flags) if is_update: print >> s, ';ZONE' else: @@ -220,11 +222,11 @@ class Message(object): print >> s, ';ADDITIONAL' for rrset in self.additional: print >> s, rrset.to_text(origin, relativize, **kw) - + # # We strip off the final \n so the caller can print the result without # doing weird things to get around eccentricities in Python print # formatting - + # return s.getvalue()[:-1] def __eq__(self, other): @@ -265,15 +267,15 @@ class Message(object): def is_response(self, other): """Is other a response to self? @rtype: bool""" - if other.flags & linkcheck.dns.flags.QR == 0 or \ + if other.flags & dns.flags.QR == 0 or \ self.id != other.id or \ - linkcheck.dns.opcode.from_flags(self.flags) != \ - linkcheck.dns.opcode.from_flags(other.flags): + dns.opcode.from_flags(self.flags) != \ + dns.opcode.from_flags(other.flags): return False - if linkcheck.dns.rcode.from_flags(other.flags, other.ednsflags) != \ - linkcheck.dns.rcode.NOERROR: + if dns.rcode.from_flags(other.flags, other.ednsflags) != \ + dns.rcode.NOERROR: return True - if linkcheck.dns.opcode.is_update(self.flags): + if dns.opcode.is_update(self.flags): return True for n in self.question: if n not in other.question: @@ -296,15 +298,15 @@ class Message(object): raise ValueError('unknown section') def find_rrset(self, section, name, rdclass, rdtype, - covers=linkcheck.dns.rdatatype.NONE, deleting=None, create=False, + covers=dns.rdatatype.NONE, deleting=None, create=False, force_unique=False): """Find the RRset with the given attributes in the specified section. @param section: the section of the message to look in, e.g. self.answer. - @type section: list of linkcheck.dns.rrset.RRset objects + @type section: list of dns.rrset.RRset objects @param name: the name of the RRset - @type name: linkcheck.dns.name.Name object + @type name: dns.name.Name object @param rdclass: the class of the RRset @type rdclass: int @param rdtype: the type of the RRset @@ -320,7 +322,7 @@ class Message(object): new RRset regardless of whether a matching RRset exists already. @type force_unique: bool @raises KeyError: the RRset was not found and create was False - @rtype: linkcheck.dns.rrset.RRset object""" + @rtype: dns.rrset.RRset object""" key = (self.section_number(section), name, rdclass, rdtype, covers, deleting) @@ -335,14 +337,14 @@ class Message(object): return rrset if not create: raise KeyError - rrset = linkcheck.dns.rrset.RRset(name, rdclass, rdtype, covers, deleting) + rrset = dns.rrset.RRset(name, rdclass, rdtype, covers, deleting) section.append(rrset) if not self.index is None: self.index[key] = rrset return rrset def get_rrset(self, section, name, rdclass, rdtype, - covers=linkcheck.dns.rdatatype.NONE, deleting=None, create=False, + covers=dns.rdatatype.NONE, deleting=None, create=False, force_unique=False): """Get the RRset with the given attributes in the specified section. @@ -350,9 +352,9 @@ class Message(object): @param section: the section of the message to look in, e.g. self.answer. - @type section: list of linkcheck.dns.rrset.RRset objects + @type section: list of dns.rrset.RRset objects @param name: the name of the RRset - @type name: linkcheck.dns.name.Name object + @type name: dns.name.Name object @param rdclass: the class of the RRset @type rdclass: int @param rdtype: the type of the RRset @@ -367,7 +369,7 @@ class Message(object): @param force_unique: If True and create is also True, create a new RRset regardless of whether a matching RRset exists already. @type force_unique: bool - @rtype: linkcheck.dns.rrset.RRset object or None""" + @rtype: dns.rrset.RRset object or None""" try: rrset = self.find_rrset(section, name, rdclass, rdtype, covers, @@ -384,12 +386,12 @@ class Message(object): method. @param origin: The origin to be appended to any relative names. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @param max_size: The maximum size of the wire format output; default is 0, which means 'the message's request payload, if nonzero, or 65536'. @type max_size: int - @raises linkcheck.dns.exception.TooBig: max_size was exceeded + @raises dns.exception.TooBig: max_size was exceeded @rtype: string """ @@ -402,17 +404,17 @@ class Message(object): max_size = 512 elif max_size > 65535: max_size = 65535 - r = linkcheck.dns.renderer.Renderer(self.id, self.flags, max_size, origin) + r = dns.renderer.Renderer(self.id, self.flags, max_size, origin) for rrset in self.question: r.add_question(rrset.name, rrset.rdtype, rrset.rdclass) for rrset in self.answer: - r.add_rrset(linkcheck.dns.renderer.ANSWER, rrset, **kw) + r.add_rrset(dns.renderer.ANSWER, rrset, **kw) for rrset in self.authority: - r.add_rrset(linkcheck.dns.renderer.AUTHORITY, rrset, **kw) + r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw) if self.edns >= 0: - r.add_edns(self.edns, self.ednsflags, self.payload) + r.add_edns(self.edns, self.ednsflags, self.payload, self.options) for rrset in self.additional: - r.add_rrset(linkcheck.dns.renderer.ADDITIONAL, rrset, **kw) + r.add_rrset(dns.renderer.ADDITIONAL, rrset, **kw) r.write_header() if not self.keyname is None: r.add_tsig(self.keyname, self.keyring[self.keyname], @@ -422,9 +424,9 @@ class Message(object): self.mac = r.mac return r.get_wire() - def use_tsig(self, keyring, keyname=None, fudge=300, original_id=None, - tsig_error=0, other_data='', - algorithm=linkcheck.dns.tsig.default_algorithm): + def use_tsig(self, keyring, keyname=None, fudge=300, + original_id=None, tsig_error=0, other_data='', + algorithm=dns.tsig.default_algorithm): """When sending, a TSIG signature using the specified keyring and keyname should be added. @@ -436,7 +438,7 @@ class Message(object): keyring. Note that the order of keys in a dictionary is not defined, so applications should supply a keyname when a keyring is used, unless they know the keyring contains only one key. - @type keyname: linkcheck.dns.name.Name or string + @type keyname: dns.name.Name or string @param fudge: TSIG time fudge; default is 300 seconds. @type fudge: int @param original_id: TSIG original id; defaults to the message's id @@ -446,15 +448,15 @@ class Message(object): @param other_data: TSIG other data. @type other_data: string @param algorithm: The TSIG algorithm to use; defaults to - linkcheck.dns.tsig.default_algorithm + dns.tsig.default_algorithm """ self.keyring = keyring if keyname is None: self.keyname = self.keyring.keys()[0] else: - if isinstance(keyname, basestring): - keyname = linkcheck.dns.name.from_text(keyname) + if isinstance(keyname, (str, unicode)): + keyname = dns.name.from_text(keyname) self.keyname = keyname self.keyalgorithm = algorithm self.fudge = fudge @@ -480,9 +482,9 @@ class Message(object): @param request_payload: The EDNS payload size to use when sending this message. If not specified, defaults to the value of payload. @type request_payload: int or None - @see: RFC 2671 @param options: The EDNS options - @type options: None or list of linkcheck.dns.edns.Option objects + @type options: None or list of dns.edns.Option objects + @see: RFC 2671 """ if edns is None or edns is False: edns = -1 @@ -517,22 +519,22 @@ class Message(object): if wanted: if self.edns < 0: self.use_edns() - self.ednsflags |= linkcheck.dns.flags.DO + self.ednsflags |= dns.flags.DO elif self.edns >= 0: - self.ednsflags &= ~linkcheck.dns.flags.DO + self.ednsflags &= ~dns.flags.DO def rcode(self): """Return the rcode. @rtype: int """ - return linkcheck.dns.rcode.from_flags(self.flags, self.ednsflags) + return dns.rcode.from_flags(self.flags, self.ednsflags) def set_rcode(self, rcode): """Set the rcode. @param rcode: the rcode @type rcode: int """ - (value, evalue) = linkcheck.dns.rcode.to_flags(rcode) + (value, evalue) = dns.rcode.to_flags(rcode) self.flags &= 0xFFF0 self.flags |= value self.ednsflags &= 0x00FFFFFFL @@ -544,7 +546,7 @@ class Message(object): """Return the opcode. @rtype: int """ - return linkcheck.dns.opcode.from_flags(self.flags) + return dns.opcode.from_flags(self.flags) def set_opcode(self, opcode): """Set the opcode. @@ -552,8 +554,7 @@ class Message(object): @type opcode: int """ self.flags &= 0x87FF - self.flags |= linkcheck.dns.opcode.to_flags(opcode) - + self.flags |= dns.opcode.to_flags(opcode) class _WireReader(object): """Wire format reader. @@ -561,7 +562,7 @@ class _WireReader(object): @ivar wire: the wire-format message. @type wire: string @ivar message: The message object being built - @type message: linkcheck.dns.message.Message object + @type message: dns.message.Message object @ivar current: When building a message object from wire format, this variable contains the offset from the beginning of wire of the next octet to be read. @@ -577,11 +578,11 @@ class _WireReader(object): def __init__(self, wire, message, question_only=False, one_rr_per_rrset=False): - self.wire = wire + self.wire = dns.wiredata.maybe_wrap(wire) self.message = message self.current = 0 self.updating = False - self.zone_rdclass = linkcheck.dns.rdataclass.IN + self.zone_rdclass = dns.rdataclass.IN self.question_only = question_only self.one_rr_per_rrset = one_rr_per_rrset @@ -592,10 +593,10 @@ class _WireReader(object): @type qcount: int""" if self.updating and qcount > 1: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError for i in xrange(0, qcount): - (qname, used) = linkcheck.dns.name.from_wire(self.wire, self.current) + (qname, used) = dns.name.from_wire(self.wire, self.current) if not self.message.origin is None: qname = qname.relativize(self.message.origin) self.current = self.current + used @@ -613,7 +614,7 @@ class _WireReader(object): """Read the next I{count} records from the wire data and add them to the specified section. @param section: the section of the message to which to add records - @type section: list of linkcheck.dns.rrset.RRset objects + @type section: list of dns.rrset.RRset objects @param count: the number of records to read @type count: int""" @@ -624,7 +625,7 @@ class _WireReader(object): seen_opt = False for i in xrange(0, count): rr_start = self.current - (name, used) = linkcheck.dns.name.from_wire(self.wire, self.current) + (name, used) = dns.name.from_wire(self.wire, self.current) absolute_name = name if not self.message.origin is None: name = name.relativize(self.message.origin) @@ -633,7 +634,7 @@ class _WireReader(object): struct.unpack('!HHIH', self.wire[self.current:self.current + 10]) self.current = self.current + 10 - if rdtype == linkcheck.dns.rdatatype.OPT: + if rdtype == dns.rdatatype.OPT: if not section is self.message.additional or seen_opt: raise BadEDNS self.message.payload = rdclass @@ -647,12 +648,12 @@ class _WireReader(object): struct.unpack('!HH', self.wire[current:current + 4]) current = current + 4 - opt = linkcheck.dns.edns.option_from_wire(otype, self.wire, current, olen) + opt = dns.edns.option_from_wire(otype, self.wire, current, olen) self.message.options.append(opt) current = current + olen optslen = optslen - 4 - olen seen_opt = True - elif rdtype == linkcheck.dns.rdatatype.TSIG: + elif rdtype == dns.rdatatype.TSIG: if not (section is self.message.additional and i == (count - 1)): raise BadTSIG @@ -662,7 +663,7 @@ class _WireReader(object): if secret is None: raise UnknownTSIGKey("key '%s' unknown" % name) self.message.tsig_ctx = \ - linkcheck.dns.tsig.validate(self.wire, + dns.tsig.validate(self.wire, absolute_name, secret, int(time.time()), @@ -678,23 +679,23 @@ class _WireReader(object): if ttl < 0: ttl = 0 if self.updating and \ - (rdclass == linkcheck.dns.rdataclass.ANY or - rdclass == linkcheck.dns.rdataclass.NONE): + (rdclass == dns.rdataclass.ANY or + rdclass == dns.rdataclass.NONE): deleting = rdclass rdclass = self.zone_rdclass else: deleting = None - if deleting == linkcheck.dns.rdataclass.ANY or \ - (deleting == linkcheck.dns.rdataclass.NONE and \ - section == self.message.answer): - covers = linkcheck.dns.rdatatype.NONE + if deleting == dns.rdataclass.ANY or \ + (deleting == dns.rdataclass.NONE and \ + section is self.message.answer): + covers = dns.rdatatype.NONE rd = None else: - rd = linkcheck.dns.rdata.from_wire(rdclass, rdtype, self.wire, + rd = dns.rdata.from_wire(rdclass, rdtype, self.wire, self.current, rdlen, self.message.origin) covers = rd.covers() - if self.message.xfr and rdtype == linkcheck.dns.rdatatype.SOA: + if self.message.xfr and rdtype == dns.rdatatype.SOA: force_unique = True rrset = self.message.find_rrset(section, name, rdclass, rdtype, covers, @@ -704,7 +705,7 @@ class _WireReader(object): self.current = self.current + rdlen def read(self): - """Read a wire format DNS message and build a linkcheck.dns.message.Message + """Read a wire format DNS message and build a dns.message.Message object.""" l = len(self.wire) @@ -713,7 +714,7 @@ class _WireReader(object): (self.message.id, self.message.flags, qcount, ancount, aucount, adcount) = struct.unpack('!HHHHHH', self.wire[:12]) self.current = 12 - if linkcheck.dns.opcode.is_update(self.message.flags): + if dns.opcode.is_update(self.message.flags): self.updating = True self._get_question(qcount) if self.question_only: @@ -743,7 +744,7 @@ def from_wire(wire, keyring=None, request_mac='', xfr=False, origin=None, @type xfr: bool @param origin: If the message is part of a zone transfer, I{origin} should be the origin name of the zone. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @param tsig_ctx: The ongoing TSIG context, used when validating zone transfers. @type tsig_ctx: hmac.HMAC object @@ -763,7 +764,7 @@ def from_wire(wire, keyring=None, request_mac='', xfr=False, origin=None, than once. @raises BadTSIG: A TSIG record was not the last record of the additional data section. - @rtype: linkcheck.dns.message.Message object""" + @rtype: dns.message.Message object""" m = Message(id=0) m.keyring = keyring @@ -784,9 +785,9 @@ class _TextReader(object): """Text format reader. @ivar tok: the tokenizer - @type tok: linkcheck.dns.tokenizer.Tokenizer object + @type tok: dns.tokenizer.Tokenizer object @ivar message: The message object being built - @type message: linkcheck.dns.message.Message object + @type message: dns.message.Message object @ivar updating: Is the message a dynamic update? @type updating: bool @ivar zone_rdclass: The class of the zone in messages which are @@ -794,14 +795,14 @@ class _TextReader(object): @type zone_rdclass: int @ivar last_name: The most recently read name when building a message object from text format. - @type last_name: linkcheck.dns.name.Name object + @type last_name: dns.name.Name object """ def __init__(self, text, message): self.message = message - self.tok = linkcheck.dns.tokenizer.Tokenizer(text) + self.tok = dns.tokenizer.Tokenizer(text) self.last_name = None - self.zone_rdclass = linkcheck.dns.rdataclass.IN + self.zone_rdclass = dns.rdataclass.IN self.updating = False def _header_line(self, section): @@ -818,8 +819,8 @@ class _TextReader(object): self.tok.unget(token) break self.message.flags = self.message.flags | \ - linkcheck.dns.flags.from_text(token[1]) - if linkcheck.dns.opcode.is_update(self.message.flags): + dns.flags.from_text(token.value) + if dns.opcode.is_update(self.message.flags): self.updating = True elif what == 'edns': self.message.edns = self.tok.get_int() @@ -830,11 +831,11 @@ class _TextReader(object): self.message.edns = 0 while True: token = self.tok.get() - if token[0] != linkcheck.dns.tokenizer.IDENTIFIER: + if not token.is_identifier(): self.tok.unget(token) break self.message.ednsflags = self.message.ednsflags | \ - linkcheck.dns.flags.edns_from_text(token[1]) + dns.flags.edns_from_text(token.value) elif what == 'payload': self.message.payload = self.tok.get_int() if self.message.edns < 0: @@ -842,10 +843,10 @@ class _TextReader(object): elif what == 'opcode': text = self.tok.get_string() self.message.flags = self.message.flags | \ - linkcheck.dns.opcode.to_flags(linkcheck.dns.opcode.from_text(text)) + dns.opcode.to_flags(dns.opcode.from_text(text)) elif what == 'rcode': text = self.tok.get_string() - self.message.set_rcode(linkcheck.dns.rcode.from_text(text)) + self.message.set_rcode(dns.rcode.from_text(text)) else: raise UnknownHeaderField self.tok.get_eol() @@ -855,23 +856,23 @@ class _TextReader(object): token = self.tok.get(want_leading = True) if not token.is_whitespace(): - self.last_name = linkcheck.dns.name.from_text(token.value, None) + self.last_name = dns.name.from_text(token.value, None) name = self.last_name token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError # Class try: - rdclass = linkcheck.dns.rdataclass.from_text(token.value) + rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError - except linkcheck.dns.exception.DNSSyntaxError: - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError + except dns.exception.SyntaxError: + raise dns.exception.SyntaxError except StandardError: - rdclass = linkcheck.dns.rdataclass.IN + rdclass = dns.rdataclass.IN # Type - rdtype = linkcheck.dns.rdatatype.from_text(token.value) + rdtype = dns.rdatatype.from_text(token.value) self.message.find_rrset(self.message.question, name, rdclass, rdtype, create=True, force_unique=True) @@ -883,48 +884,49 @@ class _TextReader(object): """Process one line from the text format answer, authority, or additional data sections. """ + deleting = None # Name token = self.tok.get(want_leading = True) if not token.is_whitespace(): - self.last_name = linkcheck.dns.name.from_text(token.value, None) + self.last_name = dns.name.from_text(token.value, None) name = self.last_name token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError # TTL try: ttl = int(token.value, 0) token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError - except linkcheck.dns.exception.DNSSyntaxError: - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError + except dns.exception.SyntaxError: + raise dns.exception.SyntaxError except StandardError: ttl = 0 # Class try: - rdclass = linkcheck.dns.rdataclass.from_text(token.value) + rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError - if rdclass == linkcheck.dns.rdataclass.ANY or rdclass == linkcheck.dns.rdataclass.NONE: + raise dns.exception.SyntaxError + if rdclass == dns.rdataclass.ANY or rdclass == dns.rdataclass.NONE: deleting = rdclass rdclass = self.zone_rdclass - except linkcheck.dns.exception.DNSSyntaxError: - raise linkcheck.dns.exception.DNSSyntaxError + except dns.exception.SyntaxError: + raise dns.exception.SyntaxError except StandardError: - rdclass = linkcheck.dns.rdataclass.IN + rdclass = dns.rdataclass.IN # Type - rdtype = linkcheck.dns.rdatatype.from_text(token.value) + rdtype = dns.rdatatype.from_text(token.value) token = self.tok.get() if not token.is_eol_or_eof(): self.tok.unget(token) - rd = linkcheck.dns.rdata.from_text(rdclass, rdtype, self.tok, None) + rd = dns.rdata.from_text(rdclass, rdtype, self.tok, None) covers = rd.covers() else: rd = None - covers = linkcheck.dns.rdatatype.NONE + covers = dns.rdatatype.NONE rrset = self.message.find_rrset(section, name, rdclass, rdtype, covers, deleting, True, self.updating) @@ -932,8 +934,9 @@ class _TextReader(object): rrset.add(rd, ttl) def read(self): - """Read a text format DNS message and build a linkcheck.dns.message.Message + """Read a text format DNS message and build a dns.message.Message object.""" + line_method = self._header_line section = None while 1: @@ -968,8 +971,8 @@ def from_text(text): @param text: The text format message. @type text: string @raises UnknownHeaderField: - @raises linkcheck.dns.exception.DNSSyntaxError: - @rtype: linkcheck.dns.message.Message object""" + @raises dns.exception.SyntaxError: + @rtype: dns.message.Message object""" # 'text' can also be a file, but we don't publish that fact # since it's an implementation detail. The official file @@ -982,19 +985,22 @@ def from_text(text): return m - def from_file(f): """Read the next text format message from the specified file. @param f: file or string. If I{f} is a string, it is treated as the name of a file to open. @raises UnknownHeaderField: - @raises linkcheck.dns.exception.DNSSyntaxError: - @rtype: linkcheck.dns.message.Message object""" + @raises dns.exception.SyntaxError: + @rtype: dns.message.Message object""" - # allow Unicode filenames; turn on universal newline support - str_type = basestring - opts = 'rU' + if sys.hexversion >= 0x02030000: + # allow Unicode filenames; turn on universal newline support + str_type = basestring + opts = 'rU' + else: + str_type = str + opts = 'r' if isinstance(f, str_type): f = file(f, opts) want_close = True @@ -1008,46 +1014,44 @@ def from_file(f): f.close() return m - -def make_query(qname, rdtype, rdclass = linkcheck.dns.rdataclass.IN, - use_edns=None, want_dnssec=False): +def make_query(qname, rdtype, rdclass = dns.rdataclass.IN, use_edns=None, + want_dnssec=False): """Make a query message. The query name, type, and class may all be specified either as objects of the appropriate type, or as strings. The query will have a randomly choosen query id, and its DNS flags - will be set to linkcheck.dns.flags.RD. + will be set to dns.flags.RD. @param qname: The query name. - @type qname: linkcheck.dns.name.Name object or string + @type qname: dns.name.Name object or string @param rdtype: The desired rdata type. @type rdtype: int @param rdclass: The desired rdata class; the default is class IN. @type rdclass: int @param use_edns: The EDNS level to use; the default is None (no EDNS). - See the description of linkcheck.dns.message.Message.use_edns() for the possible + See the description of dns.message.Message.use_edns() for the possible values for use_edns and their meanings. @type use_edns: int or bool or None @param want_dnssec: Should the query indicate that DNSSEC is desired? @type want_dnssec: bool - @rtype: linkcheck.dns.message.Message object""" + @rtype: dns.message.Message object""" - if isinstance(qname, basestring): - qname = linkcheck.dns.name.from_text(qname) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) - if isinstance(rdclass, basestring): - rdclass = linkcheck.dns.rdataclass.from_text(rdclass) + if isinstance(qname, (str, unicode)): + qname = dns.name.from_text(qname) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(rdclass, (str, unicode)): + rdclass = dns.rdataclass.from_text(rdclass) m = Message() - m.flags |= linkcheck.dns.flags.RD + m.flags |= dns.flags.RD m.find_rrset(m.question, qname, rdclass, rdtype, create=True, force_unique=True) m.use_edns(use_edns) m.want_dnssec(want_dnssec) return m - def make_response(query, recursion_available=False, our_payload=8192): """Make a message which is a response for the specified query. The message returned is really a response skeleton; it has all @@ -1059,20 +1063,20 @@ def make_response(query, recursion_available=False, our_payload=8192): changed. @param query: the query to respond to - @type query: linkcheck.dns.message.Message object + @type query: dns.message.Message object @param recursion_available: should RA be set in the response? @type recursion_available: bool @param our_payload: payload size to advertise in EDNS responses; default is 8192. @type our_payload: int - @rtype: linkcheck.dns.message.Message object""" + @rtype: dns.message.Message object""" - if query.flags & linkcheck.dns.flags.QR: - raise linkcheck.dns.exception.FormError('specified query message is not a query') - response = linkcheck.dns.message.Message(query.id) - response.flags = linkcheck.dns.flags.QR | (query.flags & linkcheck.dns.flags.RD) + if query.flags & dns.flags.QR: + raise dns.exception.FormError('specified query message is not a query') + response = dns.message.Message(query.id) + response.flags = dns.flags.QR | (query.flags & dns.flags.RD) if recursion_available: - response.flags |= linkcheck.dns.flags.RA + response.flags |= dns.flags.RA response.set_opcode(query.opcode()) response.question = list(query.question) if query.edns >= 0: diff --git a/linkcheck/dns/name.py b/third_party/dnspython/dns/name.py similarity index 89% rename from linkcheck/dns/name.py rename to third_party/dnspython/dns/name.py index 0dff042e..ed3ffeec 100644 --- a/linkcheck/dns/name.py +++ b/third_party/dnspython/dns/name.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -17,17 +16,20 @@ """DNS Names. @var root: The DNS root name. -@type root: linkcheck.dns.name.Name object +@type root: dns.name.Name object @var empty: The empty DNS name. -@type empty: linkcheck.dns.name.Name object +@type empty: dns.name.Name object """ -from cStringIO import StringIO +import cStringIO import struct import sys -import encodings.idna -import linkcheck.dns.exception +if sys.hexversion >= 0x02030000: + import encodings.idna + +import dns.exception +import dns.wiredata NAMERELN_NONE = 0 NAMERELN_SUPERDOMAIN = 1 @@ -35,41 +37,41 @@ NAMERELN_SUBDOMAIN = 2 NAMERELN_EQUAL = 3 NAMERELN_COMMONANCESTOR = 4 -class EmptyLabel(linkcheck.dns.exception.DNSSyntaxError): +class EmptyLabel(dns.exception.SyntaxError): """Raised if a label is empty.""" pass -class BadEscape(linkcheck.dns.exception.DNSSyntaxError): +class BadEscape(dns.exception.SyntaxError): """Raised if an escaped code in a text format name is invalid.""" pass -class BadPointer(linkcheck.dns.exception.FormError): +class BadPointer(dns.exception.FormError): """Raised if a compression pointer points forward instead of backward.""" pass -class BadLabelType(linkcheck.dns.exception.FormError): +class BadLabelType(dns.exception.FormError): """Raised if the label type of a wire format name is unknown.""" pass -class NeedAbsoluteNameOrOrigin(linkcheck.dns.exception.DNSException): +class NeedAbsoluteNameOrOrigin(dns.exception.DNSException): """Raised if an attempt is made to convert a non-absolute name to wire when there is also a non-absolute (or missing) origin.""" pass -class NameTooLong(linkcheck.dns.exception.FormError): +class NameTooLong(dns.exception.FormError): """Raised if a name is > 255 octets long.""" pass -class LabelTooLong(linkcheck.dns.exception.DNSSyntaxError): +class LabelTooLong(dns.exception.SyntaxError): """Raised if a label is > 63 octets long.""" pass -class AbsoluteConcatenation(linkcheck.dns.exception.DNSException): +class AbsoluteConcatenation(dns.exception.DNSException): """Raised if an attempt is made to append anything other than the empty name to an absolute name.""" pass -class NoParent(linkcheck.dns.exception.DNSException): +class NoParent(dns.exception.DNSException): """Raised if an attempt is made to get the parent of the root name or the empty name.""" pass @@ -127,7 +129,7 @@ def _validate_labels(labels): class Name(object): """A DNS name. - The linkcheck.dns.name.Name class represents a DNS name as a tuple of labels. + The dns.name.Name class represents a DNS name as a tuple of labels. Instances of the class are immutable. @ivar labels: The tuple of labels in the name. Each label is a string of @@ -176,9 +178,9 @@ class Name(object): """Compare two names, returning a 3-tuple (relation, order, nlabels). I{relation} describes the relation ship beween the names, - and is one of: linkcheck.dns.name.NAMERELN_NONE, - linkcheck.dns.name.NAMERELN_SUPERDOMAIN, linkcheck.dns.name.NAMERELN_SUBDOMAIN, - linkcheck.dns.name.NAMERELN_EQUAL, or linkcheck.dns.name.NAMERELN_COMMONANCESTOR + and is one of: dns.name.NAMERELN_NONE, + dns.name.NAMERELN_SUPERDOMAIN, dns.name.NAMERELN_SUBDOMAIN, + dns.name.NAMERELN_EQUAL, or dns.name.NAMERELN_COMMONANCESTOR I{order} is < 0 if self < other, > 0 if self > other, and == 0 if self == other. A relative name is always less than an @@ -260,7 +262,7 @@ class Name(object): def canonicalize(self): """Return a name which is equal to the current name, but is in DNSSEC canonical form. - @rtype: linkcheck.dns.name.Name object + @rtype: dns.name.Name object """ return Name([x.lower() for x in self.labels]) @@ -353,7 +355,7 @@ class Name(object): @param origin: If the name is relative and origin is not None, then origin will be appended to it. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @raises NeedAbsoluteNameOrOrigin: All names in wire format are absolute. If self is a relative name, then an origin must be supplied; if it is missing, then this exception is raised @@ -373,8 +375,8 @@ class Name(object): def to_wire(self, file = None, compress = None, origin = None): """Convert name to wire format, possibly compressing it. - @param file: the file where the compressed name is emitted (typically - a cStringIO file) If None, a string containing the wire name + @param file: the file where the name is emitted (typically + a cStringIO file). If None, a string containing the wire name will be returned. @type file: file or None @param compress: The compression table. If None (the default) names @@ -382,14 +384,14 @@ class Name(object): @type compress: dict @param origin: If the name is relative and origin is not None, then origin will be appended to it. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @raises NeedAbsoluteNameOrOrigin: All names in wire format are absolute. If self is a relative name, then an origin must be supplied; if it is missing, then this exception is raised """ if file is None: - file = StringIO() + file = cStringIO.StringIO() want_return = True else: want_return = False @@ -458,16 +460,16 @@ class Name(object): l = len(self.labels) if depth == 0: - return (self, linkcheck.dns.name.empty) + return (self, dns.name.empty) elif depth == l: - return (linkcheck.dns.name.empty, self) + return (dns.name.empty, self) elif depth < 0 or depth > l: raise ValueError('depth must be >= 0 and <= the length of the name') return (Name(self[: -depth]), Name(self[-depth :])) def concatenate(self, other): """Return a new name which is the concatenation of self and other. - @rtype: linkcheck.dns.name.Name object + @rtype: dns.name.Name object @raises AbsoluteConcatenation: self is absolute and other is not the empty name """ @@ -481,7 +483,7 @@ class Name(object): def relativize(self, origin): """If self is a subdomain of origin, return a new name which is self relative to origin. Otherwise return self. - @rtype: linkcheck.dns.name.Name object + @rtype: dns.name.Name object """ if not origin is None and self.is_subdomain(origin): @@ -492,7 +494,7 @@ class Name(object): def derelativize(self, origin): """If self is a relative name, return a new name which is the concatenation of self and origin. Otherwise return self. - @rtype: linkcheck.dns.name.Name object + @rtype: dns.name.Name object """ if not self.is_absolute(): @@ -505,8 +507,9 @@ class Name(object): origin is None, then self is returned. Otherwise, if relativize is true the name is relativized, and if relativize is false the name is derelativized. - @rtype: linkcheck.dns.name.Name object + @rtype: dns.name.Name object """ + if origin: if relativize: return self.relativize(origin) @@ -517,8 +520,8 @@ class Name(object): def parent(self): """Return the parent of the name. - @rtype: linkcheck.dns.name.Name object - @raises NoParent: the name is either the root name or the enpty name + @rtype: dns.name.Name object + @raises NoParent: the name is either the root name or the empty name, and thus has no parent. """ if self == root or self == empty: @@ -533,7 +536,7 @@ def from_unicode(text, origin = root): Lables are encoded in IDN ACE form. - @rtype: linkcheck.dns.name.Name object + @rtype: dns.name.Name object """ if not isinstance(text, unicode): @@ -549,7 +552,7 @@ def from_unicode(text, origin = root): text = u'' if text: if text == u'.': - return Name(['']) # no Unicode "u" on this constant! + return Name(['']) # no Unicode "u" on this constant! for c in text: if escaping: if edigits == 0: @@ -592,11 +595,11 @@ def from_unicode(text, origin = root): def from_text(text, origin = root): """Convert text into a Name object. - @rtype: linkcheck.dns.name.Name object + @rtype: dns.name.Name object """ if not isinstance(text, str): - if isinstance(text, unicode): + if isinstance(text, unicode) and sys.hexversion >= 0x02030000: return from_unicode(text, origin) else: raise ValueError("input to from_text() must be a string") @@ -658,16 +661,17 @@ def from_wire(message, current): @param current: the offset of the beginning of the name from the start of the message @type current: int - @raises linkcheck.dns.name.BadPointer: a compression pointer did not point backwards + @raises dns.name.BadPointer: a compression pointer did not point backwards in the message - @raises linkcheck.dns.name.BadLabelType: an invalid label type was encountered. + @raises dns.name.BadLabelType: an invalid label type was encountered. @returns: a tuple consisting of the name that was read and the number of bytes of the wire format message which were consumed reading it - @rtype: (linkcheck.dns.name.Name object, int) tuple + @rtype: (dns.name.Name object, int) tuple """ if not isinstance(message, str): raise ValueError("input to from_wire() must be a byte string") + message = dns.wiredata.maybe_wrap(message) labels = [] biggest_pointer = current hops = 0 @@ -676,7 +680,7 @@ def from_wire(message, current): cused = 1 while count != 0: if count < 64: - labels.append(message[current : current + count]) + labels.append(message[current : current + count].unwrap()) current += count if hops == 0: cused += count diff --git a/linkcheck/dns/namedict.py b/third_party/dnspython/dns/namedict.py similarity index 80% rename from linkcheck/dns/namedict.py rename to third_party/dnspython/dns/namedict.py index 2967aa7f..77bb2cf2 100644 --- a/linkcheck/dns/namedict.py +++ b/third_party/dnspython/dns/namedict.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,11 +15,11 @@ """DNS name dictionary""" -import linkcheck.dns.name +import dns.name class NameDict(dict): - """A dictionary whose keys are linkcheck.dns.name.Name objects. + """A dictionary whose keys are dns.name.Name objects. @ivar max_depth: the maximum depth of the keys that have ever been added to the dictionary. @type max_depth: int @@ -31,7 +30,7 @@ class NameDict(dict): self.max_depth = 0 def __setitem__(self, key, value): - if not isinstance(key, linkcheck.dns.name.Name): + if not isinstance(key, dns.name.Name): raise ValueError('NameDict key must be a name') depth = len(key) if depth > self.max_depth: @@ -45,7 +44,7 @@ class NameDict(dict): a superdomain of I{name}. @param name: the name - @type name: linkcheck.dns.name.Name object + @type name: dns.name.Name object @rtype: (key, value) tuple """ @@ -53,8 +52,8 @@ class NameDict(dict): if depth > self.max_depth: depth = self.max_depth for i in xrange(-depth, 0): - n = linkcheck.dns.name.Name(name[i:]) + n = dns.name.Name(name[i:]) if n in self: return (n, self[n]) - v = self[linkcheck.dns.name.empty] - return (linkcheck.dns.name.empty, v) + v = self[dns.name.empty] + return (dns.name.empty, v) diff --git a/linkcheck/dns/node.py b/third_party/dnspython/dns/node.py similarity index 84% rename from linkcheck/dns/node.py rename to third_party/dnspython/dns/node.py index 1fa7bf36..7625c66d 100644 --- a/linkcheck/dns/node.py +++ b/third_party/dnspython/dns/node.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,11 +15,11 @@ """DNS nodes. A node is a set of rdatasets.""" -from cStringIO import StringIO +import StringIO -import linkcheck.dns.rdataset -import linkcheck.dns.rdatatype -import linkcheck.dns.renderer +import dns.rdataset +import dns.rdatatype +import dns.renderer class Node(object): """A DNS node. @@ -28,7 +27,7 @@ class Node(object): A node is a set of rdatasets @ivar rdatasets: the node's rdatasets - @type rdatasets: list of linkcheck.dns.rdataset.Rdataset objects""" + @type rdatasets: list of dns.rdataset.Rdataset objects""" __slots__ = ['rdatasets'] @@ -44,11 +43,11 @@ class Node(object): Each rdataset at the node is printed. Any keyword arguments to this method are passed on to the rdataset's to_text() method. @param name: the owner name of the rdatasets - @type name: linkcheck.dns.name.Name object + @type name: dns.name.Name object @rtype: string """ - s = StringIO() + s = StringIO.StringIO() for rds in self.rdatasets: print >> s, rds.to_text(name, **kw) return s.getvalue()[:-1] @@ -81,7 +80,7 @@ class Node(object): def __iter__(self): return iter(self.rdatasets) - def find_rdataset(self, rdclass, rdtype, covers=linkcheck.dns.rdatatype.NONE, + def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE, create=False): """Find an rdataset matching the specified properties in the current node. @@ -91,8 +90,8 @@ class Node(object): @param rdtype: The type of the rdataset @type rdtype: int @param covers: The covered type. Usually this value is - linkcheck.dns.rdatatype.NONE, but if the rdtype is linkcheck.dns.rdatatype.SIG or - linkcheck.dns.rdatatype.RRSIG, then the covers value will be the rdata + dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or + dns.rdatatype.RRSIG, then the covers value will be the rdata type the SIG/RRSIG covers. The library treats the SIG and RRSIG types as if they were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much @@ -103,7 +102,7 @@ class Node(object): @type create: bool @raises KeyError: An rdataset of the desired type and class does not exist and I{create} is not True. - @rtype: linkcheck.dns.rdataset.Rdataset object + @rtype: dns.rdataset.Rdataset object """ for rds in self.rdatasets: @@ -111,11 +110,11 @@ class Node(object): return rds if not create: raise KeyError - rds = linkcheck.dns.rdataset.Rdataset(rdclass, rdtype) + rds = dns.rdataset.Rdataset(rdclass, rdtype) self.rdatasets.append(rds) return rds - def get_rdataset(self, rdclass, rdtype, covers=linkcheck.dns.rdatatype.NONE, + def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE, create=False): """Get an rdataset matching the specified properties in the current node. @@ -131,7 +130,7 @@ class Node(object): @type covers: int @param create: If True, create the rdataset if it is not found. @type create: bool - @rtype: linkcheck.dns.rdataset.Rdataset object or None + @rtype: dns.rdataset.Rdataset object or None """ try: @@ -140,7 +139,7 @@ class Node(object): rds = None return rds - def delete_rdataset(self, rdclass, rdtype, covers=linkcheck.dns.rdatatype.NONE): + def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE): """Delete the rdataset matching the specified properties in the current node. diff --git a/linkcheck/dns/opcode.py b/third_party/dnspython/dns/opcode.py similarity index 93% rename from linkcheck/dns/opcode.py rename to third_party/dnspython/dns/opcode.py index aaca3983..3258c34c 100644 --- a/linkcheck/dns/opcode.py +++ b/third_party/dnspython/dns/opcode.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,7 +15,7 @@ """DNS Opcodes.""" -import linkcheck.dns.exception +import dns.exception QUERY = 0 IQUERY = 1 @@ -39,7 +38,7 @@ _by_text = { _by_value = dict([(y, x) for x, y in _by_text.iteritems()]) -class UnknownOpcode(linkcheck.dns.exception.DNSException): +class UnknownOpcode(dns.exception.DNSException): """Raised if an opcode is unknown.""" pass @@ -67,7 +66,7 @@ def from_flags(flags): @param flags: int @rtype: int """ - + return (flags & 0x7800) >> 11 def to_flags(value): @@ -75,9 +74,9 @@ def to_flags(value): flags. @rtype: int """ - + return (value << 11) & 0x7800 - + def to_text(value): """Convert an opcode to text. @@ -86,7 +85,7 @@ def to_text(value): @raises UnknownOpcode: the opcode is unknown @rtype: string """ - + text = _by_value.get(value) if text is None: text = str(value) @@ -99,7 +98,7 @@ def is_update(flags): @type flags: int @rtype: bool """ - + if (from_flags(flags) == UPDATE): return True return False diff --git a/linkcheck/dns/query.py b/third_party/dnspython/dns/query.py similarity index 69% rename from linkcheck/dns/query.py rename to third_party/dnspython/dns/query.py index 257916bf..e20380aa 100644 --- a/linkcheck/dns/query.py +++ b/third_party/dnspython/dns/query.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,6 +15,8 @@ """Talk to a DNS server.""" +from __future__ import generators + import errno import select import socket @@ -23,30 +24,80 @@ import struct import sys import time -import linkcheck.dns.exception -import linkcheck.dns.inet -import linkcheck.dns.name -import linkcheck.dns.message -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype +import dns.exception +import dns.inet +import dns.name +import dns.message +import dns.rdataclass +import dns.rdatatype -class UnexpectedSource(linkcheck.dns.exception.DNSException): +class UnexpectedSource(dns.exception.DNSException): """Raised if a query response comes from an unexpected address or port.""" pass -class BadResponse(linkcheck.dns.exception.FormError): +class BadResponse(dns.exception.FormError): """Raised if a query response does not respond to the question asked.""" pass - def _compute_expiration(timeout): if timeout is None: return None else: return time.time() + timeout +def _poll_for(fd, readable, writable, error, timeout): + """ + @param fd: File descriptor (int). + @param readable: Whether to wait for readability (bool). + @param writable: Whether to wait for writability (bool). + @param expiration: Deadline timeout (expiration time, in seconds (float)). -def _wait_for(ir, iw, ix, expiration): + @return True on success, False on timeout + """ + event_mask = 0 + if readable: + event_mask |= select.POLLIN + if writable: + event_mask |= select.POLLOUT + if error: + event_mask |= select.POLLERR + + pollable = select.poll() + pollable.register(fd, event_mask) + + if timeout: + event_list = pollable.poll(long(timeout * 1000)) + else: + event_list = pollable.poll() + + return bool(event_list) + +def _select_for(fd, readable, writable, error, timeout): + """ + @param fd: File descriptor (int). + @param readable: Whether to wait for readability (bool). + @param writable: Whether to wait for writability (bool). + @param expiration: Deadline timeout (expiration time, in seconds (float)). + + @return True on success, False on timeout + """ + rset, wset, xset = [], [], [] + + if readable: + rset = [fd] + if writable: + wset = [fd] + if error: + xset = [fd] + + if timeout is None: + (rcount, wcount, xcount) = select.select(rset, wset, xset) + else: + (rcount, wcount, xcount) = select.select(rset, wset, xset, timeout) + + return bool((rcount or wcount or xcount)) + +def _wait_for(fd, readable, writable, error, expiration): done = False while not done: if expiration is None: @@ -54,32 +105,43 @@ def _wait_for(ir, iw, ix, expiration): else: timeout = expiration - time.time() if timeout <= 0.0: - raise linkcheck.dns.exception.Timeout + raise dns.exception.Timeout try: - if timeout is None: - (r, w, x) = select.select(ir, iw, ix) - else: - (r, w, x) = select.select(ir, iw, ix, timeout) + if not _polling_backend(fd, readable, writable, error, timeout): + raise dns.exception.Timeout except select.error, e: if e.args[0] != errno.EINTR: raise e done = True - if len(r) == 0 and len(w) == 0 and len(x) == 0: - raise linkcheck.dns.exception.Timeout + +def _set_polling_backend(fn): + """ + Internal API. Do not use. + """ + global _polling_backend + + _polling_backend = fn + +if hasattr(select, 'poll'): + # Prefer poll() on platforms that support it because it has no + # limits on the maximum value of a file descriptor (plus it will + # be more efficient for high values). + _polling_backend = _poll_for +else: + _polling_backend = _select_for def _wait_for_readable(s, expiration): - _wait_for([s], [], [s], expiration) - + _wait_for(s, True, False, True, expiration) def _wait_for_writable(s, expiration): - _wait_for([], [s], [s], expiration) + _wait_for(s, False, True, True, expiration) def _addresses_equal(af, a1, a2): # Convert the first value of the tuple, which is a textual format # address into binary form, so that we are not confused by different # textual representations of the same address - n1 = linkcheck.dns.inet.inet_pton(af, a1[0]) - n2 = linkcheck.dns.inet.inet_pton(af, a2[0]) + n1 = dns.inet.inet_pton(af, a1[0]) + n2 = dns.inet.inet_pton(af, a2[0]) return n1 == n2 and a1[1:] == a2[1:] def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, @@ -87,7 +149,7 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, """Return the response obtained after sending a query via UDP. @param q: the query - @type q: linkcheck.dns.message.Message + @type q: dns.message.Message @param where: where to send the message @type where: string containing an IPv4 or IPv6 address @param timeout: The number of seconds to wait before the query times out. @@ -99,7 +161,7 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, causes the address family to use to be inferred from the form of of where. If the inference attempt fails, AF_INET is used. @type af: int - @rtype: linkcheck.dns.message.Message object + @rtype: dns.message.Message object @param source: source address. The default is the IPv4 wildcard address. @type source: string @param source_port: The port from which to send the message. @@ -115,14 +177,14 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, wire = q.to_wire() if af is None: try: - af = linkcheck.dns.inet.af_for_address(where) + af = dns.inet.af_for_address(where) except StandardError: - af = linkcheck.dns.inet.AF_INET - if af == linkcheck.dns.inet.AF_INET: + af = dns.inet.AF_INET + if af == dns.inet.AF_INET: destination = (where, port) if source is not None: source = (source, source_port) - elif af == linkcheck.dns.inet.AF_INET6: + elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) @@ -138,8 +200,8 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, _wait_for_readable(s, expiration) (wire, from_address) = s.recvfrom(65535) if _addresses_equal(af, from_address, destination) or \ - (linkcheck.dns.inet.is_multicast(where) and \ - from_address[1:] == destination[1:]): + (dns.inet.is_multicast(where) and \ + from_address[1:] == destination[1:]): break if not ignore_unexpected: raise UnexpectedSource('got a response from ' @@ -147,7 +209,7 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, destination)) finally: s.close() - r = linkcheck.dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, one_rr_per_rrset=one_rr_per_rrset) if not q.is_response(r): raise BadResponse @@ -165,8 +227,8 @@ def _net_read(sock, count, expiration): n = sock.recv(count) if n == '': raise EOFError - count -= len(n) - s += n + count = count - len(n) + s = s + n return s def _net_write(sock, data, expiration): @@ -195,7 +257,7 @@ def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, """Return the response obtained after sending a query via TCP. @param q: the query - @type q: linkcheck.dns.message.Message object + @type q: dns.message.Message object @param where: where to send the message @type where: string containing an IPv4 or IPv6 address @param timeout: The number of seconds to wait before the query times out. @@ -207,7 +269,7 @@ def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, causes the address family to use to be inferred from the form of of where. If the inference attempt fails, AF_INET is used. @type af: int - @rtype: linkcheck.dns.message.Message object + @rtype: dns.message.Message object @param source: source address. The default is the IPv4 wildcard address. @type source: string @param source_port: The port from which to send the message. @@ -220,14 +282,14 @@ def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, wire = q.to_wire() if af is None: try: - af = linkcheck.dns.inet.af_for_address(where) + af = dns.inet.af_for_address(where) except StandardError: - af = linkcheck.dns.inet.AF_INET - if af == linkcheck.dns.inet.AF_INET: + af = dns.inet.AF_INET + if af == dns.inet.AF_INET: destination = (where, port) if source is not None: source = (source, source_port) - elif af == linkcheck.dns.inet.AF_INET6: + elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) @@ -251,28 +313,27 @@ def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, wire = _net_read(s, l, expiration) finally: s.close() - r = linkcheck.dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, one_rr_per_rrset=one_rr_per_rrset) if not q.is_response(r): raise BadResponse return r -def xfr (where, zone, rdtype=linkcheck.dns.rdatatype.AXFR, - rdclass=linkcheck.dns.rdataclass.IN, - timeout=None, port=53, keyring=None, keyname=None, relativize=True, - af=None, lifetime=None, source=None, source_port=0, serial=0, - use_udp=False, keyalgorithm=linkcheck.dns.tsig.default_algorithm): +def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, + timeout=None, port=53, keyring=None, keyname=None, relativize=True, + af=None, lifetime=None, source=None, source_port=0, serial=0, + use_udp=False, keyalgorithm=dns.tsig.default_algorithm): """Return a generator for the responses to a zone transfer. @param where: where to send the message @type where: string containing an IPv4 or IPv6 address @param zone: The name of the zone to transfer - @type zone: linkcheck.dns.name.Name object or string + @type zone: dns.name.Name object or string @param rdtype: The type of zone transfer. The default is - linkcheck.dns.rdatatype.AXFR. + dns.rdatatype.AXFR. @type rdtype: int or string @param rdclass: The class of the zone transfer. The default is - linkcheck.dns.rdatatype.IN. + dns.rdatatype.IN. @type rdclass: int or string @param timeout: The number of seconds to wait for each response message. If None, the default, wait forever. @@ -282,10 +343,10 @@ def xfr (where, zone, rdtype=linkcheck.dns.rdatatype.AXFR, @param keyring: The TSIG keyring to use @type keyring: dict @param keyname: The name of the TSIG key to use - @type keyname: linkcheck.dns.name.Name object or string + @type keyname: dns.name.Name object or string @param relativize: If True, all names in the zone will be relativized to - the zone origin. It is essential that the relativize setting matches - the one specified to linkcheck.dns.zone.from_xfr(). + the zone origin. It is essential that the relativize setting matches + the one specified to dns.zone.from_xfr(). @type relativize: bool @param af: the address family to use. The default is None, which causes the address family to use to be inferred from the form of of where. @@ -295,49 +356,49 @@ def xfr (where, zone, rdtype=linkcheck.dns.rdatatype.AXFR, If None, the default, then there is no limit on the time the transfer may take. @type lifetime: float - @rtype: generator of linkcheck.dns.message.Message objects. + @rtype: generator of dns.message.Message objects. @param source: source address. The default is the IPv4 wildcard address. @type source: string @param source_port: The port from which to send the message. The default is 0. @type source_port: int @param serial: The SOA serial number to use as the base for an IXFR diff - sequence (only meaningful if rdtype == linkcheck.dns.rdatatype.IXFR). + sequence (only meaningful if rdtype == dns.rdatatype.IXFR). @type serial: int @param use_udp: Use UDP (only meaningful for IXFR) @type use_udp: bool @param keyalgorithm: The TSIG algorithm to use; defaults to - linkcheck.dns.tsig.default_algorithm + dns.tsig.default_algorithm @type keyalgorithm: string """ - if isinstance(zone, basestring): - zone = linkcheck.dns.name.from_text(zone) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) - q = linkcheck.dns.message.make_query(zone, rdtype, rdclass) - if rdtype == linkcheck.dns.rdatatype.IXFR: - rrset = linkcheck.dns.rrset.from_text(zone, 0, 'IN', 'SOA', - '. . %u 0 0 0 0' % serial) + if isinstance(zone, (str, unicode)): + zone = dns.name.from_text(zone) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) + q = dns.message.make_query(zone, rdtype, rdclass) + if rdtype == dns.rdatatype.IXFR: + rrset = dns.rrset.from_text(zone, 0, 'IN', 'SOA', + '. . %u 0 0 0 0' % serial) q.authority.append(rrset) if not keyring is None: q.use_tsig(keyring, keyname, algorithm=keyalgorithm) wire = q.to_wire() if af is None: try: - af = linkcheck.dns.inet.af_for_address(where) + af = dns.inet.af_for_address(where) except StandardError: - af = linkcheck.dns.inet.AF_INET - if af == linkcheck.dns.inet.AF_INET: + af = dns.inet.AF_INET + if af == dns.inet.AF_INET: destination = (where, port) if source is not None: source = (source, source_port) - elif af == linkcheck.dns.inet.AF_INET6: + elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) if use_udp: - if rdtype != linkcheck.dns.rdatatype.IXFR: + if rdtype != dns.rdatatype.IXFR: raise ValueError('cannot do a UDP AXFR') s = socket.socket(af, socket.SOCK_DGRAM, 0) else: @@ -359,7 +420,7 @@ def xfr (where, zone, rdtype=linkcheck.dns.rdatatype.AXFR, soa_count = 0 if relativize: origin = zone - oname = linkcheck.dns.name.empty + oname = dns.name.empty else: origin = None oname = zone @@ -376,10 +437,10 @@ def xfr (where, zone, rdtype=linkcheck.dns.rdatatype.AXFR, ldata = _net_read(s, 2, mexpiration) (l,) = struct.unpack("!H", ldata) wire = _net_read(s, l, mexpiration) - r = linkcheck.dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, xfr=True, origin=origin, tsig_ctx=tsig_ctx, multi=True, first=first, - one_rr_per_rrset=(rdtype==linkcheck.dns.rdatatype.IXFR)) + one_rr_per_rrset=(rdtype==dns.rdatatype.IXFR)) tsig_ctx = r.tsig_ctx first = False answer_index = 0 @@ -387,45 +448,45 @@ def xfr (where, zone, rdtype=linkcheck.dns.rdatatype.AXFR, expecting_SOA = False if soa_rrset is None: if not r.answer or r.answer[0].name != oname: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError rrset = r.answer[0] - if rrset.rdtype != linkcheck.dns.rdatatype.SOA: - raise linkcheck.dns.exception.FormError("first RRset is not an SOA") + 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 == linkcheck.dns.rdatatype.IXFR: + if rdtype == dns.rdatatype.IXFR: if soa_rrset[0].serial == serial: - + # # We're already up-to-date. - + # done = True else: expecting_SOA = True - + # # Process SOAs in the answer section (other than the initial # SOA in the first message). - + # for rrset in r.answer[answer_index:]: if done: - raise linkcheck.dns.exception.FormError("answers after final SOA") - if rrset.rdtype == linkcheck.dns.rdatatype.SOA and rrset.name == oname: + raise dns.exception.FormError("answers after final SOA") + if rrset.rdtype == dns.rdatatype.SOA and rrset.name == oname: if expecting_SOA: if rrset[0].serial != serial: - raise linkcheck.dns.exception.FormError("IXFR base serial mismatch") + raise dns.exception.FormError("IXFR base serial mismatch") expecting_SOA = False - elif rdtype == linkcheck.dns.rdatatype.IXFR: + elif rdtype == dns.rdatatype.IXFR: delete_mode = not delete_mode if rrset == soa_rrset and not delete_mode: done = True elif expecting_SOA: - + # # We made an IXFR request and are expecting another # SOA RR, but saw something else, so this must be an # AXFR response. - - rdtype = linkcheck.dns.rdatatype.AXFR + # + rdtype = dns.rdatatype.AXFR expecting_SOA = False if done and q.keyring and not r.had_tsig: - raise linkcheck.dns.exception.FormError("missing TSIG") + raise dns.exception.FormError("missing TSIG") yield r s.close() diff --git a/linkcheck/dns/rcode.py b/third_party/dnspython/dns/rcode.py similarity index 92% rename from linkcheck/dns/rcode.py rename to third_party/dnspython/dns/rcode.py index 6349bf7e..7807782a 100644 --- a/linkcheck/dns/rcode.py +++ b/third_party/dnspython/dns/rcode.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,7 +15,7 @@ """DNS Result Codes.""" -import linkcheck.dns.exception +import dns.exception NOERROR = 0 FORMERR = 1 @@ -53,7 +52,7 @@ _by_text = { _by_value = dict([(y, x) for x, y in _by_text.iteritems()]) -class UnknownRcode(linkcheck.dns.exception.DNSException): +class UnknownRcode(dns.exception.DNSException): """Raised if an rcode is unknown.""" pass @@ -101,7 +100,7 @@ def to_flags(value): """ if value < 0 or value > 4095: - raise ValueError, 'rcode must be >= 0 and <= 4095' + raise ValueError('rcode must be >= 0 and <= 4095') v = value & 0xf ev = long(value & 0xff0) << 20 return (v, ev) diff --git a/linkcheck/dns/rdata.py b/third_party/dnspython/dns/rdata.py similarity index 84% rename from linkcheck/dns/rdata.py rename to third_party/dnspython/dns/rdata.py index eacbde60..fda4b105 100644 --- a/linkcheck/dns/rdata.py +++ b/third_party/dnspython/dns/rdata.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -20,18 +19,20 @@ the module which implements that type. @type _rdata_modules: dict @var _module_prefix: The prefix to use when forming modules names. The -default is 'linkcheck.dns.rdtypes'. Changing this value will break the library. +default is 'dns.rdtypes'. Changing this value will break the library. @type _module_prefix: string @var _hex_chunk: At most this many octets that will be represented in each chunk of hexstring that _hexify() produces before whitespace occurs. @type _hex_chunk: int""" -from cStringIO import StringIO +import cStringIO -import linkcheck.dns.exception -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype -import linkcheck.dns.tokenizer +import dns.exception +import dns.name +import dns.rdataclass +import dns.rdatatype +import dns.tokenizer +import dns.wiredata _hex_chunksize = 32 @@ -41,7 +42,7 @@ def _hexify(data, chunksize=None): @param data: the binary string @type data: string - @param chunksize: the chunk size. Default is L{linkcheck.dns.rdata._hex_chunksize} + @param chunksize: the chunk size. Default is L{dns.rdata._hex_chunksize} @rtype: string """ @@ -67,7 +68,7 @@ def _base64ify(data, chunksize=None): @param data: the binary string @type data: string @param chunksize: the chunk size. Default is - L{linkcheck.dns.rdata._base64_chunksize} + L{dns.rdata._base64_chunksize} @rtype: string """ @@ -143,13 +144,13 @@ class Rdata(object): def covers(self): """DNS SIG/RRSIG rdatas apply to a specific type; this type is returned by the covers() function. If the rdata type is not - SIG or RRSIG, linkcheck.dns.rdatatype.NONE is returned. This is useful when + SIG or RRSIG, dns.rdatatype.NONE is returned. This is useful when creating rdatasets, allowing the rdataset to contain only RRSIGs of a particular type, e.g. RRSIG(NS). @rtype: int """ - return linkcheck.dns.rdatatype.NONE + return dns.rdatatype.NONE def extended_rdatatype(self): """Return a 32-bit type value, the least significant 16 bits of @@ -176,7 +177,7 @@ class Rdata(object): def to_digestable(self, origin = None): """Convert rdata to a format suitable for digesting in hashes. This is also the DNSSEC canonical form.""" - f = StringIO() + f = cStringIO.StringIO() self.to_wire(f, None, origin) return f.getvalue() @@ -186,16 +187,16 @@ class Rdata(object): it is a good idea to call validate() when you are done making changes. """ - linkcheck.dns.rdata.from_text(self.rdclass, self.rdtype, self.to_text()) + dns.rdata.from_text(self.rdclass, self.rdtype, self.to_text()) def __repr__(self): covers = self.covers() - if covers == linkcheck.dns.rdatatype.NONE: + if covers == dns.rdatatype.NONE: ctext = '' else: - ctext = '(' + linkcheck.dns.rdatatype.to_text(covers) + ')' - return '' def __str__(self): @@ -253,6 +254,22 @@ class Rdata(object): return NotImplemented return self._cmp(other) > 0 + def __hash__(self): + return hash(self.to_digestable(dns.name.root)) + + def _wire_cmp(self, other): + # A number of types compare rdata in wire form, so we provide + # the method here instead of duplicating it. + # + # We specifiy an arbitrary origin of '.' when doing the + # comparison, since the rdata may have relative names and we + # can't convert a relative name to wire without an origin. + b1 = cStringIO.StringIO() + self.to_wire(b1, None, dns.name.root) + b2 = cStringIO.StringIO() + other.to_wire(b2, None, dns.name.root) + return cmp(b1.getvalue(), b2.getvalue()) + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): """Build an rdata object from text format. @@ -261,12 +278,12 @@ class Rdata(object): @param rdtype: The rdata type @type rdtype: int @param tok: The tokenizer - @type tok: linkcheck.dns.tokenizer.Tokenizer + @type tok: dns.tokenizer.Tokenizer @param origin: The origin to use for relative names - @type origin: linkcheck.dns.name.Name + @type origin: dns.name.Name @param relativize: should names be relativized? @type relativize: bool - @rtype: linkcheck.dns.rdata.Rdata instance + @rtype: dns.rdata.Rdata instance """ raise NotImplementedError @@ -287,8 +304,8 @@ class Rdata(object): @param rdlen: The length of the wire-format rdata @type rdlen: int @param origin: The origin to use for relative names - @type origin: linkcheck.dns.name.Name - @rtype: linkcheck.dns.rdata.Rdata instance + @type origin: dns.name.Name + @rtype: dns.rdata.Rdata instance """ raise NotImplementedError @@ -322,7 +339,7 @@ class GenericRdata(Rdata): def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): token = tok.get() if not token.is_identifier() or token.value != '\#': - raise linkcheck.dns.exception.DNSSyntaxError(r'generic rdata does not start with \#') + raise dns.exception.SyntaxError(r'generic rdata does not start with \#') length = tok.get_int() chunks = [] while 1: @@ -333,7 +350,7 @@ class GenericRdata(Rdata): hex = ''.join(chunks) data = hex.decode('hex_codec') if len(data) != length: - raise linkcheck.dns.exception.DNSSyntaxError('generic rdata hex data has wrong length') + raise dns.exception.SyntaxError('generic rdata hex data has wrong length') return cls(rdclass, rdtype, data) from_text = classmethod(from_text) @@ -350,7 +367,7 @@ class GenericRdata(Rdata): return cmp(self.data, other.data) _rdata_modules = {} -_module_prefix = 'linkcheck.dns.rdtypes' +_module_prefix = 'dns.rdtypes' def get_rdata_class(rdclass, rdtype): @@ -362,11 +379,11 @@ def get_rdata_class(rdclass, rdtype): return mod mod = _rdata_modules.get((rdclass, rdtype)) - rdclass_text = linkcheck.dns.rdataclass.to_text(rdclass) - rdtype_text = linkcheck.dns.rdatatype.to_text(rdtype) + rdclass_text = dns.rdataclass.to_text(rdclass) + rdtype_text = dns.rdatatype.to_text(rdtype) rdtype_text = rdtype_text.replace('-', '_') if not mod: - mod = _rdata_modules.get((linkcheck.dns.rdatatype.ANY, rdtype)) + mod = _rdata_modules.get((dns.rdatatype.ANY, rdtype)) if not mod: try: mod = import_module('.'.join([_module_prefix, @@ -376,7 +393,7 @@ def get_rdata_class(rdclass, rdtype): try: mod = import_module('.'.join([_module_prefix, 'ANY', rdtype_text])) - _rdata_modules[(linkcheck.dns.rdataclass.ANY, rdtype)] = mod + _rdata_modules[(dns.rdataclass.ANY, rdtype)] = mod except ImportError: mod = None if mod: @@ -401,15 +418,15 @@ def from_text(rdclass, rdtype, tok, origin = None, relativize = True): @param rdtype: The rdata type @type rdtype: int @param tok: The tokenizer - @type tok: linkcheck.dns.tokenizer.Tokenizer + @type tok: dns.tokenizer.Tokenizer @param origin: The origin to use for relative names - @type origin: linkcheck.dns.name.Name + @type origin: dns.name.Name @param relativize: Should names be relativized? @type relativize: bool - @rtype: linkcheck.dns.rdata.Rdata instance""" + @rtype: dns.rdata.Rdata instance""" if isinstance(tok, str): - tok = linkcheck.dns.tokenizer.Tokenizer(tok) + tok = dns.tokenizer.Tokenizer(tok) cls = get_rdata_class(rdclass, rdtype) if cls != GenericRdata: # peek at first token @@ -417,11 +434,11 @@ def from_text(rdclass, rdtype, tok, origin = None, relativize = True): tok.unget(token) if token.is_identifier() and \ token.value == r'\#': - + # # Known type using the generic syntax. Extract the # wire form from the generic syntax, and then run # from_wire on it. - + # rdata = GenericRdata.from_text(rdclass, rdtype, tok, origin, relativize) return from_wire(rdclass, rdtype, rdata.data, 0, len(rdata.data), @@ -450,8 +467,9 @@ def from_wire(rdclass, rdtype, wire, current, rdlen, origin = None): @param rdlen: The length of the wire-format rdata @type rdlen: int @param origin: The origin to use for relative names - @type origin: linkcheck.dns.name.Name - @rtype: linkcheck.dns.rdata.Rdata instance""" + @type origin: dns.name.Name + @rtype: dns.rdata.Rdata instance""" + wire = dns.wiredata.maybe_wrap(wire) cls = get_rdata_class(rdclass, rdtype) return cls.from_wire(rdclass, rdtype, wire, current, rdlen, origin) diff --git a/linkcheck/dns/rdataclass.py b/third_party/dnspython/dns/rdataclass.py similarity index 89% rename from linkcheck/dns/rdataclass.py rename to third_party/dnspython/dns/rdataclass.py index b1715061..955ffbcf 100644 --- a/linkcheck/dns/rdataclass.py +++ b/third_party/dnspython/dns/rdataclass.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -26,7 +25,7 @@ whose key is the rdatatype value and whose value is True in this dictionary. import re -import linkcheck.dns.exception +import dns.exception RESERVED0 = 0 IN = 1 @@ -66,7 +65,7 @@ _metaclasses = { _unknown_class_pattern = re.compile('CLASS([0-9]+)$', re.I); -class UnknownRdataclass(linkcheck.dns.exception.DNSException): +class UnknownRdataclass(dns.exception.DNSException): """Raised when a class is unknown.""" pass @@ -75,14 +74,14 @@ def from_text(text): @param text: the text @type text: string @rtype: int - @raises linkcheck.dns.rdataclass.UnknownRdataClass: the class is unknown + @raises dns.rdataclass.UnknownRdataClass: the class is unknown @raises ValueError: the rdata class value is not >= 0 and <= 65535 """ value = _by_text.get(text.upper()) if value is None: match = _unknown_class_pattern.match(text) - if match is None: + if match == None: raise UnknownRdataclass value = int(match.group(1)) if value < 0 or value > 65535: @@ -101,7 +100,7 @@ def to_text(value): raise ValueError("class must be between >= 0 and <= 65535") text = _by_value.get(value) if text is None: - text = 'CLASS' + repr(value) + text = 'CLASS' + `value` return text def is_metaclass(rdclass): @@ -110,4 +109,6 @@ def is_metaclass(rdclass): @type rdclass: int @rtype: bool""" - return rdclass in _metaclasses + if rdclass in _metaclasses: + return True + return False diff --git a/linkcheck/dns/rdataset.py b/third_party/dnspython/dns/rdataset.py similarity index 79% rename from linkcheck/dns/rdataset.py rename to third_party/dnspython/dns/rdataset.py index 08bef8ea..dcd2b401 100644 --- a/linkcheck/dns/rdataset.py +++ b/third_party/dnspython/dns/rdataset.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -17,24 +16,28 @@ """DNS rdatasets (an rdataset is a set of rdatas of a given type and class)""" import random -from cStringIO import StringIO +import StringIO import struct -import linkcheck.dns.exception -import linkcheck.dns.rdatatype -import linkcheck.dns.rdataclass -import linkcheck.dns.rdata +import dns.exception +import dns.rdatatype +import dns.rdataclass +import dns.rdata +import dns.set -class DifferingCovers(linkcheck.dns.exception.DNSException): +# define SimpleSet here for backwards compatibility +SimpleSet = dns.set.Set + +class DifferingCovers(dns.exception.DNSException): """Raised if an attempt is made to add a SIG/RRSIG whose covered type is not the same as that of the other rdatas in the rdataset.""" pass -class IncompatibleTypes(linkcheck.dns.exception.DNSException): +class IncompatibleTypes(dns.exception.DNSException): """Raised if an attempt is made to add rdata of an incompatible type.""" pass -class Rdataset(set): +class Rdataset(dns.set.Set): """A DNS rdataset. @ivar rdclass: The class of the rdataset @@ -42,8 +45,8 @@ class Rdataset(set): @ivar rdtype: The type of the rdataset @type rdtype: int @ivar covers: The covered type. Usually this value is - linkcheck.dns.rdatatype.NONE, but if the rdtype is linkcheck.dns.rdatatype.SIG or - linkcheck.dns.rdatatype.RRSIG, then the covers value will be the rdata + dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or + dns.rdatatype.RRSIG, then the covers value will be the rdata type the SIG/RRSIG covers. The library treats the SIG and RRSIG types as if they were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much @@ -56,7 +59,7 @@ class Rdataset(set): __slots__ = ['rdclass', 'rdtype', 'covers', 'ttl'] - def __init__(self, rdclass, rdtype, covers=linkcheck.dns.rdatatype.NONE): + def __init__(self, rdclass, rdtype, covers=dns.rdatatype.NONE): """Create a new rdataset of the specified class and type. @see: the description of the class instance variables for the @@ -95,28 +98,28 @@ class Rdataset(set): self.update_ttl(ttl) will be called prior to adding the rdata. @param rd: The rdata - @type rd: linkcheck.dns.rdata.Rdata object + @type rd: dns.rdata.Rdata object @param ttl: The TTL @type ttl: int""" - + # # If we're adding a signature, do some special handling to # check that the signature covers the same type as the # other rdatas in this rdataset. If this is the first rdata # in the set, initialize the covers field. - + # if self.rdclass != rd.rdclass or self.rdtype != rd.rdtype: raise IncompatibleTypes if not ttl is None: self.update_ttl(ttl) - if self.rdtype == linkcheck.dns.rdatatype.RRSIG or \ - self.rdtype == linkcheck.dns.rdatatype.SIG: + if self.rdtype == dns.rdatatype.RRSIG or \ + self.rdtype == dns.rdatatype.SIG: covers = rd.covers() - if len(self) == 0 and self.covers == linkcheck.dns.rdatatype.NONE: + if len(self) == 0 and self.covers == dns.rdatatype.NONE: self.covers = covers elif self.covers != covers: raise DifferingCovers - if linkcheck.dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0: + if dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0: self.clear() super(Rdataset, self).add(rd) @@ -132,7 +135,8 @@ class Rdataset(set): """Add all rdatas in other to self. @param other: The rdataset from which to update - @type other: linkcheck.dns.rdataset.Rdataset object""" + @type other: dns.rdataset.Rdataset object""" + self.update_ttl(other.ttl) super(Rdataset, self).update(other) @@ -140,9 +144,9 @@ class Rdataset(set): if self.covers == 0: ctext = '' else: - ctext = '(' + linkcheck.dns.rdatatype.to_text(self.covers) + ')' - return '' + ctext = '(' + dns.rdatatype.to_text(self.covers) + ')' + return '' def __str__(self): return self.to_text() @@ -151,6 +155,7 @@ class Rdataset(set): """Two rdatasets are equal if they have the same class, type, and covers, and contain the same rdata. @rtype: bool""" + if not isinstance(other, Rdataset): return False if self.rdclass != other.rdclass or \ @@ -166,7 +171,7 @@ class Rdataset(set): override_rdclass=None, **kw): """Convert the rdataset into DNS master file format. - @see: L{linkcheck.dns.name.Name.choose_relativity} for more information + @see: L{dns.name.Name.choose_relativity} for more information on how I{origin} and I{relativize} determine the way names are emitted. @@ -175,9 +180,9 @@ class Rdataset(set): @param name: If name is not None, emit a RRs with I{name} as the owner name. - @type name: linkcheck.dns.name.Name object + @type name: dns.name.Name object @param origin: The origin for relative names, or None. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @param relativize: True if names should names be relativized @type relativize: bool""" if not name is None: @@ -187,29 +192,29 @@ class Rdataset(set): else: ntext = '' pad = '' - s = StringIO() + s = StringIO.StringIO() if not override_rdclass is None: rdclass = override_rdclass else: rdclass = self.rdclass if len(self) == 0: - + # # Empty rdatasets are used for the question section, and in # some dynamic updates, so we don't need to print out the TTL # (which is meaningless anyway). - + # print >> s, '%s%s%s %s' % (ntext, pad, - linkcheck.dns.rdataclass.to_text(rdclass), - linkcheck.dns.rdatatype.to_text(self.rdtype)) + dns.rdataclass.to_text(rdclass), + dns.rdatatype.to_text(self.rdtype)) else: for rd in self: print >> s, '%s%s%d %s %s %s' % \ - (ntext, pad, self.ttl, linkcheck.dns.rdataclass.to_text(rdclass), - linkcheck.dns.rdatatype.to_text(self.rdtype), + (ntext, pad, self.ttl, dns.rdataclass.to_text(rdclass), + dns.rdatatype.to_text(self.rdtype), rd.to_text(origin=origin, relativize=relativize, **kw)) - + # # We strip off the final \n for the caller's convenience in printing - + # return s.getvalue()[:-1] def to_wire(self, name, file, compress=None, origin=None, @@ -217,7 +222,7 @@ class Rdataset(set): """Convert the rdataset to wire format. @param name: The owner name of the RRset that will be emitted - @type name: linkcheck.dns.name.Name object + @type name: dns.name.Name object @param file: The file to which the wire format data will be appended @type file: file @param compress: The compression table to use; the default is None. @@ -263,26 +268,27 @@ class Rdataset(set): def match(self, rdclass, rdtype, covers): """Returns True if this rdataset matches the specified class, type, and covers""" - return self.rdclass == rdclass and \ + if self.rdclass == rdclass and \ self.rdtype == rdtype and \ - self.covers == covers - + self.covers == covers: + return True + return False def from_text_list(rdclass, rdtype, ttl, text_rdatas): """Create an rdataset with the specified class, type, and TTL, and with the specified list of rdatas in text format. - @rtype: linkcheck.dns.rdataset.Rdataset object + @rtype: dns.rdataset.Rdataset object """ - if isinstance(rdclass, basestring): - rdclass = linkcheck.dns.rdataclass.from_text(rdclass) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) + if isinstance(rdclass, (str, unicode)): + rdclass = dns.rdataclass.from_text(rdclass) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) r = Rdataset(rdclass, rdtype) r.update_ttl(ttl) for t in text_rdatas: - rd = linkcheck.dns.rdata.from_text(r.rdclass, r.rdtype, t) + rd = dns.rdata.from_text(r.rdclass, r.rdtype, t) r.add(rd) return r @@ -290,7 +296,7 @@ def from_text(rdclass, rdtype, ttl, *text_rdatas): """Create an rdataset with the specified class, type, and TTL, and with the specified rdatas in text format. - @rtype: linkcheck.dns.rdataset.Rdataset object + @rtype: dns.rdataset.Rdataset object """ return from_text_list(rdclass, rdtype, ttl, text_rdatas) @@ -299,7 +305,7 @@ def from_rdata_list(ttl, rdatas): """Create an rdataset with the specified TTL, and with the specified list of rdata objects. - @rtype: linkcheck.dns.rdataset.Rdataset object + @rtype: dns.rdataset.Rdataset object """ if len(rdatas) == 0: @@ -317,7 +323,7 @@ def from_rdata(ttl, *rdatas): """Create an rdataset with the specified TTL, and with the specified rdata objects. - @rtype: linkcheck.dns.rdataset.Rdataset object + @rtype: dns.rdataset.Rdataset object """ return from_rdata_list(ttl, rdatas) diff --git a/linkcheck/dns/rdatatype.py b/third_party/dnspython/dns/rdatatype.py similarity index 91% rename from linkcheck/dns/rdatatype.py rename to third_party/dnspython/dns/rdatatype.py index 6c5cf67d..74d15958 100644 --- a/linkcheck/dns/rdatatype.py +++ b/third_party/dnspython/dns/rdatatype.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -29,7 +28,7 @@ whose key is the rdatatype value and whose value is True in this dictionary. import re -import linkcheck.dns.exception +import dns.exception NONE = 0 A = 1 @@ -176,7 +175,7 @@ _singletons = { _unknown_type_pattern = re.compile('TYPE([0-9]+)$', re.I); -class UnknownRdatatype(linkcheck.dns.exception.DNSException): +class UnknownRdatatype(dns.exception.DNSException): """Raised if a type is unknown.""" pass @@ -184,14 +183,14 @@ def from_text(text): """Convert text into a DNS rdata type value. @param text: the text @type text: string - @raises linkcheck.dns.rdatatype.UnknownRdatatype: the type is unknown + @raises dns.rdatatype.UnknownRdatatype: the type is unknown @raises ValueError: the rdata type value is not >= 0 and <= 65535 @rtype: int""" value = _by_text.get(text.upper()) if value is None: match = _unknown_type_pattern.match(text) - if match is None: + if match == None: raise UnknownRdatatype value = int(match.group(1)) if value < 0 or value > 65535: @@ -209,7 +208,7 @@ def to_text(value): raise ValueError("type must be between >= 0 and <= 65535") text = _by_value.get(value) if text is None: - text = 'TYPE' + repr(value) + text = 'TYPE' + `value` return text def is_metatype(rdtype): @@ -218,7 +217,9 @@ def is_metatype(rdtype): @type rdtype: int @rtype: bool""" - return rdtype >= TKEY and rdtype <= ANY or rdtype in _metatypes + if rdtype >= TKEY and rdtype <= ANY or rdtype in _metatypes: + return True + return False def is_singleton(rdtype): """True if the type is a singleton. @@ -226,4 +227,6 @@ def is_singleton(rdtype): @type rdtype: int @rtype: bool""" - return rdtype in _singletons + if rdtype in _singletons: + return True + return False diff --git a/linkcheck/dns/rdtypes/ANY/AFSDB.py b/third_party/dnspython/dns/rdtypes/ANY/AFSDB.py similarity index 87% rename from linkcheck/dns/rdtypes/ANY/AFSDB.py rename to third_party/dnspython/dns/rdtypes/ANY/AFSDB.py index 0ba30e35..c729789a 100644 --- a/linkcheck/dns/rdtypes/ANY/AFSDB.py +++ b/third_party/dnspython/dns/rdtypes/ANY/AFSDB.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,15 +13,15 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.mxbase +import dns.rdtypes.mxbase -class AFSDB(linkcheck.dns.rdtypes.mxbase.UncompressedDowncasingMX): +class AFSDB(dns.rdtypes.mxbase.UncompressedDowncasingMX): """AFSDB record @ivar subtype: the subtype value @type subtype: int @ivar hostname: the hostname name - @type hostname: linkcheck.dns.name.Name object""" + @type hostname: dns.name.Name object""" # Use the property mechanism to make "subtype" an alias for the # "preference" attribute, and "hostname" an alias for the "exchange" diff --git a/linkcheck/dns/rdtypes/ANY/CERT.py b/third_party/dnspython/dns/rdtypes/ANY/CERT.py similarity index 81% rename from linkcheck/dns/rdtypes/ANY/CERT.py rename to third_party/dnspython/dns/rdtypes/ANY/CERT.py index 39c0313f..c102521a 100644 --- a/linkcheck/dns/rdtypes/ANY/CERT.py +++ b/third_party/dnspython/dns/rdtypes/ANY/CERT.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,13 +13,13 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from cStringIO import StringIO +import cStringIO import struct -import linkcheck.dns.exception -import linkcheck.dns.dnssec -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.dnssec +import dns.rdata +import dns.tokenizer _ctype_by_value = { 1 : 'PKIX', @@ -50,7 +49,7 @@ def _ctype_to_text(what): return v return str(what) -class CERT(linkcheck.dns.rdata.Rdata): +class CERT(dns.rdata.Rdata): """CERT record @ivar certificate_type: certificate type @@ -76,22 +75,22 @@ class CERT(linkcheck.dns.rdata.Rdata): def to_text(self, origin=None, relativize=True, **kw): certificate_type = _ctype_to_text(self.certificate_type) return "%s %d %s %s" % (certificate_type, self.key_tag, - linkcheck.dns.dnssec.algorithm_to_text(self.algorithm), - linkcheck.dns.rdata._base64ify(self.certificate)) + dns.dnssec.algorithm_to_text(self.algorithm), + dns.rdata._base64ify(self.certificate)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): certificate_type = _ctype_from_text(tok.get_string()) key_tag = tok.get_uint16() - algorithm = linkcheck.dns.dnssec.algorithm_from_text(tok.get_string()) + algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) if algorithm < 0 or algorithm > 255: - raise linkcheck.dns.exception.DNSSyntaxError("bad algorithm type") + raise dns.exception.SyntaxError("bad algorithm type") chunks = [] while 1: t = tok.get().unescape() if t.is_eol_or_eof(): break if not t.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) certificate = b64.decode('base64_codec') @@ -107,20 +106,20 @@ class CERT(linkcheck.dns.rdata.Rdata): file.write(self.certificate) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - prefix = wire[current : current + 5] + prefix = wire[current : current + 5].unwrap() current += 5 rdlen -= 5 if rdlen < 0: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError (certificate_type, key_tag, algorithm) = struct.unpack("!HHB", prefix) - certificate = wire[current : current + rdlen] + certificate = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, certificate) from_wire = classmethod(from_wire) def _cmp(self, other): - f = StringIO() + f = cStringIO.StringIO() self.to_wire(f) wire1 = f.getvalue() f.seek(0) diff --git a/linkcheck/dns/rdtypes/ANY/CNAME.py b/third_party/dnspython/dns/rdtypes/ANY/CNAME.py similarity index 85% rename from linkcheck/dns/rdtypes/ANY/CNAME.py rename to third_party/dnspython/dns/rdtypes/ANY/CNAME.py index 0effc6a7..fb8e9be4 100644 --- a/linkcheck/dns/rdtypes/ANY/CNAME.py +++ b/third_party/dnspython/dns/rdtypes/ANY/CNAME.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,9 +13,9 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.nsbase +import dns.rdtypes.nsbase -class CNAME(linkcheck.dns.rdtypes.nsbase.NSBase): +class CNAME(dns.rdtypes.nsbase.NSBase): """CNAME record Note: although CNAME is officially a singleton type, dnspython allows diff --git a/linkcheck/dns/rdtypes/ANY/DLV.py b/third_party/dnspython/dns/rdtypes/ANY/DLV.py similarity index 85% rename from linkcheck/dns/rdtypes/ANY/DLV.py rename to third_party/dnspython/dns/rdtypes/ANY/DLV.py index 00d29aeb..8bd79793 100644 --- a/linkcheck/dns/rdtypes/ANY/DLV.py +++ b/third_party/dnspython/dns/rdtypes/ANY/DLV.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009, 2010 Nominum, Inc. +# Copyright (C) 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -13,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.dsbase +import dns.rdtypes.dsbase -class DLV(linkcheck.dns.rdtypes.dsbase.DSBase): +class DLV(dns.rdtypes.dsbase.DSBase): """DLV record""" pass diff --git a/linkcheck/dns/rdtypes/ANY/DNAME.py b/third_party/dnspython/dns/rdtypes/ANY/DNAME.py similarity index 82% rename from linkcheck/dns/rdtypes/ANY/DNAME.py rename to third_party/dnspython/dns/rdtypes/ANY/DNAME.py index c99a433f..897068ce 100644 --- a/linkcheck/dns/rdtypes/ANY/DNAME.py +++ b/third_party/dnspython/dns/rdtypes/ANY/DNAME.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -15,9 +14,9 @@ # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.nsbase +import dns.rdtypes.nsbase -class DNAME(linkcheck.dns.rdtypes.nsbase.UncompressedNS): +class DNAME(dns.rdtypes.nsbase.UncompressedNS): """DNAME record""" def to_digestable(self, origin = None): return self.target.to_digestable(origin) diff --git a/linkcheck/dns/rdtypes/keybase.py b/third_party/dnspython/dns/rdtypes/ANY/DNSKEY.py similarity index 52% rename from linkcheck/dns/rdtypes/keybase.py rename to third_party/dnspython/dns/rdtypes/ANY/DNSKEY.py index b2bfd591..c51730b5 100644 --- a/linkcheck/dns/rdtypes/keybase.py +++ b/third_party/dnspython/dns/rdtypes/ANY/DNSKEY.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2004-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,55 +15,17 @@ import struct -import linkcheck.dns.exception -import linkcheck.dns.dnssec -import linkcheck.dns.rdata +import dns.exception +import dns.dnssec +import dns.rdata -_flags_from_text = { - 'NOCONF': (0x4000, 0xC000), - 'NOAUTH': (0x8000, 0xC000), - 'NOKEY': (0xC000, 0xC000), - 'FLAG2': (0x2000, 0x2000), - 'EXTEND': (0x1000, 0x1000), - 'FLAG4': (0x0800, 0x0800), - 'FLAG5': (0x0400, 0x0400), - 'USER': (0x0000, 0x0300), - 'ZONE': (0x0100, 0x0300), - 'HOST': (0x0200, 0x0300), - 'NTYP3': (0x0300, 0x0300), - 'FLAG8': (0x0080, 0x0080), - 'FLAG9': (0x0040, 0x0040), - 'FLAG10': (0x0020, 0x0020), - 'FLAG11': (0x0010, 0x0010), - 'SIG0': (0x0000, 0x000f), - 'SIG1': (0x0001, 0x000f), - 'SIG2': (0x0002, 0x000f), - 'SIG3': (0x0003, 0x000f), - 'SIG4': (0x0004, 0x000f), - 'SIG5': (0x0005, 0x000f), - 'SIG6': (0x0006, 0x000f), - 'SIG7': (0x0007, 0x000f), - 'SIG8': (0x0008, 0x000f), - 'SIG9': (0x0009, 0x000f), - 'SIG10': (0x000a, 0x000f), - 'SIG11': (0x000b, 0x000f), - 'SIG12': (0x000c, 0x000f), - 'SIG13': (0x000d, 0x000f), - 'SIG14': (0x000e, 0x000f), - 'SIG15': (0x000f, 0x000f), - } +# flag constants +SEP = 0x0001 +REVOKE = 0x0080 +ZONE = 0x0100 -_protocol_from_text = { - 'NONE' : 0, - 'TLS' : 1, - 'EMAIL' : 2, - 'DNSSEC' : 3, - 'IPSEC' : 4, - 'ALL' : 255, - } - -class KEYBase(linkcheck.dns.rdata.Rdata): - """KEY-like record base +class DNSKEY(dns.rdata.Rdata): + """DNSKEY record @ivar flags: the key flags @type flags: int @@ -78,7 +39,7 @@ class KEYBase(linkcheck.dns.rdata.Rdata): __slots__ = ['flags', 'protocol', 'algorithm', 'key'] def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): - super(KEYBase, self).__init__(rdclass, rdtype) + super(DNSKEY, self).__init__(rdclass, rdtype) self.flags = flags self.protocol = protocol self.algorithm = algorithm @@ -86,37 +47,19 @@ class KEYBase(linkcheck.dns.rdata.Rdata): def to_text(self, origin=None, relativize=True, **kw): return '%d %d %d %s' % (self.flags, self.protocol, self.algorithm, - linkcheck.dns.rdata._base64ify(self.key)) + dns.rdata._base64ify(self.key)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): - flags = tok.get_string() - if flags.isdigit(): - flags = int(flags) - else: - flag_names = flags.split('|') - flags = 0 - for flag in flag_names: - v = _flags_from_text.get(flag) - if v is None: - raise linkcheck.dns.exception.DNSSyntaxError('unknown flag %s' % flag) - flags &= ~v[1] - flags |= v[0] - protocol = tok.get_string() - if protocol.isdigit(): - protocol = int(protocol) - else: - protocol = _protocol_from_text.get(protocol) - if protocol is None: - raise linkcheck.dns.exception.DNSSyntaxError('unknown protocol %s' % protocol) - - algorithm = linkcheck.dns.dnssec.algorithm_from_text(tok.get_string()) + flags = tok.get_uint16() + protocol = tok.get_uint8() + algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) chunks = [] while 1: t = tok.get().unescape() if t.is_eol_or_eof(): break if not t.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) key = b64.decode('base64_codec') @@ -131,11 +74,11 @@ class KEYBase(linkcheck.dns.rdata.Rdata): def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): if rdlen < 4: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError header = struct.unpack('!HBB', wire[current : current + 4]) current += 4 rdlen -= 4 - key = wire[current : current + rdlen] + key = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], header[2], key) diff --git a/linkcheck/dns/rdtypes/ANY/DS.py b/third_party/dnspython/dns/rdtypes/ANY/DS.py similarity index 82% rename from linkcheck/dns/rdtypes/ANY/DS.py rename to third_party/dnspython/dns/rdtypes/ANY/DS.py index dd7b0306..56b6332d 100644 --- a/linkcheck/dns/rdtypes/ANY/DS.py +++ b/third_party/dnspython/dns/rdtypes/ANY/DS.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.dsbase +import dns.rdtypes.dsbase -class DS(linkcheck.dns.rdtypes.dsbase.DSBase): +class DS(dns.rdtypes.dsbase.DSBase): """DS record""" pass diff --git a/linkcheck/dns/rdtypes/ANY/GPOS.py b/third_party/dnspython/dns/rdtypes/ANY/GPOS.py similarity index 87% rename from linkcheck/dns/rdtypes/ANY/GPOS.py rename to third_party/dnspython/dns/rdtypes/ANY/GPOS.py index d27e5b7b..38d1d88b 100644 --- a/linkcheck/dns/rdtypes/ANY/GPOS.py +++ b/third_party/dnspython/dns/rdtypes/ANY/GPOS.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,9 +13,9 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.rdata +import dns.tokenizer def _validate_float_string(what): if what[0] == '-' or what[0] == '+': @@ -25,13 +24,13 @@ def _validate_float_string(what): return (left, right) = what.split('.') if left == '' and right == '': - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if not left == '' and not left.isdigit(): - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if not right == '' and not right.isdigit(): - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError -class GPOS(linkcheck.dns.rdata.Rdata): +class GPOS(dns.rdata.Rdata): """GPOS record @ivar latitude: latitude @@ -99,24 +98,24 @@ class GPOS(linkcheck.dns.rdata.Rdata): current += 1 rdlen -= 1 if l > rdlen: - raise linkcheck.dns.exception.FormError - latitude = wire[current : current + l] + raise dns.exception.FormError + latitude = wire[current : current + l].unwrap() current += l rdlen -= l l = ord(wire[current]) current += 1 rdlen -= 1 if l > rdlen: - raise linkcheck.dns.exception.FormError - longitude = wire[current : current + l] + raise dns.exception.FormError + longitude = wire[current : current + l].unwrap() current += l rdlen -= l l = ord(wire[current]) current += 1 rdlen -= 1 if l != rdlen: - raise linkcheck.dns.exception.FormError - altitude = wire[current : current + l] + raise dns.exception.FormError + altitude = wire[current : current + l].unwrap() return cls(rdclass, rdtype, latitude, longitude, altitude) from_wire = classmethod(from_wire) diff --git a/linkcheck/dns/rdtypes/ANY/HINFO.py b/third_party/dnspython/dns/rdtypes/ANY/HINFO.py similarity index 80% rename from linkcheck/dns/rdtypes/ANY/HINFO.py rename to third_party/dnspython/dns/rdtypes/ANY/HINFO.py index f16cd0d2..15fd54e6 100644 --- a/linkcheck/dns/rdtypes/ANY/HINFO.py +++ b/third_party/dnspython/dns/rdtypes/ANY/HINFO.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,11 +13,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.rdata +import dns.tokenizer -class HINFO(linkcheck.dns.rdata.Rdata): +class HINFO(dns.rdata.Rdata): """HINFO record @ivar cpu: the CPU type @@ -35,8 +34,8 @@ class HINFO(linkcheck.dns.rdata.Rdata): self.os = os def to_text(self, origin=None, relativize=True, **kw): - return '"%s" "%s"' % (linkcheck.dns.rdata._escapify(self.cpu), - linkcheck.dns.rdata._escapify(self.os)) + return '"%s" "%s"' % (dns.rdata._escapify(self.cpu), + dns.rdata._escapify(self.os)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): cpu = tok.get_string() @@ -63,16 +62,16 @@ class HINFO(linkcheck.dns.rdata.Rdata): current += 1 rdlen -= 1 if l > rdlen: - raise linkcheck.dns.exception.FormError - cpu = wire[current : current + l] + raise dns.exception.FormError + cpu = wire[current : current + l].unwrap() current += l rdlen -= l l = ord(wire[current]) current += 1 rdlen -= 1 if l != rdlen: - raise linkcheck.dns.exception.FormError - os = wire[current : current + l] + raise dns.exception.FormError + os = wire[current : current + l].unwrap() return cls(rdclass, rdtype, cpu, os) from_wire = classmethod(from_wire) diff --git a/linkcheck/dns/rdtypes/ANY/HIP.py b/third_party/dnspython/dns/rdtypes/ANY/HIP.py similarity index 89% rename from linkcheck/dns/rdtypes/ANY/HIP.py rename to third_party/dnspython/dns/rdtypes/ANY/HIP.py index aef83d42..968b36f5 100644 --- a/linkcheck/dns/rdtypes/ANY/HIP.py +++ b/third_party/dnspython/dns/rdtypes/ANY/HIP.py @@ -1,4 +1,4 @@ -# Copyright (C) 2010 Nominum, Inc. +# Copyright (C) 2010, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,13 +14,14 @@ # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO +import string import struct -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.rdatatype +import dns.exception +import dns.rdata +import dns.rdatatype -class HIP(linkcheck.dns.rdata.Rdata): +class HIP(dns.rdata.Rdata): """HIP record @ivar hit: the host identity tag @@ -30,7 +31,7 @@ class HIP(linkcheck.dns.rdata.Rdata): @ivar key: the public key @type key: string @ivar servers: the rendezvous servers - @type servers: list of linkcheck.dns.name.Name objects + @type servers: list of dns.name.Name objects @see: RFC 5205""" __slots__ = ['hit', 'algorithm', 'key', 'servers'] @@ -57,14 +58,14 @@ class HIP(linkcheck.dns.rdata.Rdata): algorithm = tok.get_uint8() hit = tok.get_string().decode('hex-codec') if len(hit) > 255: - raise linkcheck.dns.exception.SyntaxError("HIT too long") + raise dns.exception.SyntaxError("HIT too long") key = tok.get_string().decode('base64-codec') servers = [] while 1: token = tok.get() if token.is_eol_or_eof(): break - server = linkcheck.dns.name.from_text(token.value, origin) + server = dns.name.from_text(token.value, origin) server.choose_relativity(origin, relativize) servers.append(server) return cls(rdclass, rdtype, hit, algorithm, key, servers) @@ -85,15 +86,15 @@ class HIP(linkcheck.dns.rdata.Rdata): wire[current : current + 4]) current += 4 rdlen -= 4 - hit = wire[current : current + lh] + hit = wire[current : current + lh].unwrap() current += lh rdlen -= lh - key = wire[current : current + lk] + key = wire[current : current + lk].unwrap() current += lk rdlen -= lk servers = [] while rdlen > 0: - (server, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (server, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused diff --git a/linkcheck/dns/rdtypes/ANY/ISDN.py b/third_party/dnspython/dns/rdtypes/ANY/ISDN.py similarity index 80% rename from linkcheck/dns/rdtypes/ANY/ISDN.py rename to third_party/dnspython/dns/rdtypes/ANY/ISDN.py index 1fe6c513..0c2d3cd0 100644 --- a/linkcheck/dns/rdtypes/ANY/ISDN.py +++ b/third_party/dnspython/dns/rdtypes/ANY/ISDN.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,11 +13,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.rdata +import dns.tokenizer -class ISDN(linkcheck.dns.rdata.Rdata): +class ISDN(dns.rdata.Rdata): """ISDN record @ivar address: the ISDN address @@ -36,10 +35,10 @@ class ISDN(linkcheck.dns.rdata.Rdata): def to_text(self, origin=None, relativize=True, **kw): if self.subaddress: - return '"%s" "%s"' % (linkcheck.dns.rdata._escapify(self.address), - linkcheck.dns.rdata._escapify(self.subaddress)) + return '"%s" "%s"' % (dns.rdata._escapify(self.address), + dns.rdata._escapify(self.subaddress)) else: - return '"%s"' % linkcheck.dns.rdata._escapify(self.address) + return '"%s"' % dns.rdata._escapify(self.address) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): address = tok.get_string() @@ -73,8 +72,8 @@ class ISDN(linkcheck.dns.rdata.Rdata): current += 1 rdlen -= 1 if l > rdlen: - raise linkcheck.dns.exception.FormError - address = wire[current : current + l] + raise dns.exception.FormError + address = wire[current : current + l].unwrap() current += l rdlen -= l if rdlen > 0: @@ -82,8 +81,8 @@ class ISDN(linkcheck.dns.rdata.Rdata): current += 1 rdlen -= 1 if l != rdlen: - raise linkcheck.dns.exception.FormError - subaddress = wire[current : current + l] + raise dns.exception.FormError + subaddress = wire[current : current + l].unwrap() else: subaddress = '' return cls(rdclass, rdtype, address, subaddress) diff --git a/linkcheck/dns/rdtypes/ANY/LOC.py b/third_party/dnspython/dns/rdtypes/ANY/LOC.py similarity index 87% rename from linkcheck/dns/rdtypes/ANY/LOC.py rename to third_party/dnspython/dns/rdtypes/ANY/LOC.py index c2df5b28..154546d7 100644 --- a/linkcheck/dns/rdtypes/ANY/LOC.py +++ b/third_party/dnspython/dns/rdtypes/ANY/LOC.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,11 +13,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from cStringIO import StringIO +import cStringIO import struct -import linkcheck.dns.exception -import linkcheck.dns.rdata +import dns.exception +import dns.rdata _pows = (1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L, 1000000000L, 10000000000L) @@ -30,7 +29,7 @@ def _exponent_of(what, desc): exp = i - 1 break if exp is None or exp < 0: - raise linkcheck.dns.exception.DNSSyntaxError("%s value out of bounds" % desc) + raise dns.exception.SyntaxError("%s value out of bounds" % desc) return exp def _float_to_tuple(what): @@ -70,13 +69,13 @@ def _encode_size(what, desc): def _decode_size(what, desc): exponent = what & 0x0F if exponent > 9: - raise linkcheck.dns.exception.DNSSyntaxError("bad %s exponent" % desc) + raise dns.exception.SyntaxError("bad %s exponent" % desc) base = (what & 0xF0) >> 4 if base > 9: - raise linkcheck.dns.exception.DNSSyntaxError("bad %s base" % desc) + raise dns.exception.SyntaxError("bad %s base" % desc) return long(base) * pow(10, exponent) -class LOC(linkcheck.dns.rdata.Rdata): +class LOC(dns.rdata.Rdata): """LOC record @ivar latitude: latitude @@ -165,13 +164,13 @@ class LOC(linkcheck.dns.rdata.Rdata): if '.' in t: (seconds, milliseconds) = t.split('.') if not seconds.isdigit(): - raise linkcheck.dns.exception.DNSSyntaxError('bad latitude seconds value') + raise dns.exception.SyntaxError('bad latitude seconds value') latitude[2] = int(seconds) if latitude[2] >= 60: - raise linkcheck.dns.exception.DNSSyntaxError('latitude seconds >= 60') + raise dns.exception.SyntaxError('latitude seconds >= 60') l = len(milliseconds) if l == 0 or l > 3 or not milliseconds.isdigit(): - raise linkcheck.dns.exception.DNSSyntaxError('bad latitude milliseconds value') + raise dns.exception.SyntaxError('bad latitude milliseconds value') if l == 1: m = 100 elif l == 2: @@ -186,7 +185,7 @@ class LOC(linkcheck.dns.rdata.Rdata): if t == 'S': latitude[0] *= -1 elif t != 'N': - raise linkcheck.dns.exception.DNSSyntaxError('bad latitude hemisphere value') + raise dns.exception.SyntaxError('bad latitude hemisphere value') longitude[0] = tok.get_int() t = tok.get_string() @@ -196,13 +195,13 @@ class LOC(linkcheck.dns.rdata.Rdata): if '.' in t: (seconds, milliseconds) = t.split('.') if not seconds.isdigit(): - raise linkcheck.dns.exception.DNSSyntaxError('bad longitude seconds value') + raise dns.exception.SyntaxError('bad longitude seconds value') longitude[2] = int(seconds) if longitude[2] >= 60: - raise linkcheck.dns.exception.DNSSyntaxError('longitude seconds >= 60') + raise dns.exception.SyntaxError('longitude seconds >= 60') l = len(milliseconds) if l == 0 or l > 3 or not milliseconds.isdigit(): - raise linkcheck.dns.exception.DNSSyntaxError('bad longitude milliseconds value') + raise dns.exception.SyntaxError('bad longitude milliseconds value') if l == 1: m = 100 elif l == 2: @@ -217,31 +216,31 @@ class LOC(linkcheck.dns.rdata.Rdata): if t == 'W': longitude[0] *= -1 elif t != 'E': - raise linkcheck.dns.exception.DNSSyntaxError('bad longitude hemisphere value') + raise dns.exception.SyntaxError('bad longitude hemisphere value') t = tok.get_string() if t[-1] == 'm': t = t[0 : -1] - altitude = float(t) * 100.0 # m -> cm + altitude = float(t) * 100.0 # m -> cm token = tok.get().unescape() if not token.is_eol_or_eof(): value = token.value if value[-1] == 'm': value = value[0 : -1] - size = float(value) * 100.0 # m -> cm + size = float(value) * 100.0 # m -> cm token = tok.get().unescape() if not token.is_eol_or_eof(): value = token.value if value[-1] == 'm': value = value[0 : -1] - hprec = float(value) * 100.0 # m -> cm + hprec = float(value) * 100.0 # m -> cm token = tok.get().unescape() if not token.is_eol_or_eof(): value = token.value if value[-1] == 'm': value = value[0 : -1] - vprec = float(value) * 100.0 # m -> cm + vprec = float(value) * 100.0 # m -> cm tok.get_eol() return cls(rdclass, rdtype, latitude, longitude, altitude, @@ -288,13 +287,13 @@ class LOC(linkcheck.dns.rdata.Rdata): else: latitude = -1 * float(0x80000000L - latitude) / 3600000 if latitude < -90.0 or latitude > 90.0: - raise linkcheck.dns.exception.FormError("bad latitude") + raise dns.exception.FormError("bad latitude") if longitude > 0x80000000L: longitude = float(longitude - 0x80000000L) / 3600000 else: longitude = -1 * float(0x80000000L - longitude) / 3600000 if longitude < -180.0 or longitude > 180.0: - raise linkcheck.dns.exception.FormError("bad longitude") + raise dns.exception.FormError("bad longitude") altitude = float(altitude) - 10000000.0 size = _decode_size(size, "size") hprec = _decode_size(hprec, "horizontal precision") @@ -305,7 +304,7 @@ class LOC(linkcheck.dns.rdata.Rdata): from_wire = classmethod(from_wire) def _cmp(self, other): - f = StringIO() + f = cStringIO.StringIO() self.to_wire(f) wire1 = f.getvalue() f.seek(0) diff --git a/linkcheck/dns/rdtypes/ANY/MX.py b/third_party/dnspython/dns/rdtypes/ANY/MX.py similarity index 82% rename from linkcheck/dns/rdtypes/ANY/MX.py rename to third_party/dnspython/dns/rdtypes/ANY/MX.py index de95a7d8..92f41532 100644 --- a/linkcheck/dns/rdtypes/ANY/MX.py +++ b/third_party/dnspython/dns/rdtypes/ANY/MX.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.mxbase +import dns.rdtypes.mxbase -class MX(linkcheck.dns.rdtypes.mxbase.MXBase): +class MX(dns.rdtypes.mxbase.MXBase): """MX record""" pass diff --git a/linkcheck/dns/rdtypes/ANY/NS.py b/third_party/dnspython/dns/rdtypes/ANY/NS.py similarity index 82% rename from linkcheck/dns/rdtypes/ANY/NS.py rename to third_party/dnspython/dns/rdtypes/ANY/NS.py index 4facb8a1..6b45d4d4 100644 --- a/linkcheck/dns/rdtypes/ANY/NS.py +++ b/third_party/dnspython/dns/rdtypes/ANY/NS.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.nsbase +import dns.rdtypes.nsbase -class NS(linkcheck.dns.rdtypes.nsbase.NSBase): +class NS(dns.rdtypes.nsbase.NSBase): """NS record""" pass diff --git a/linkcheck/dns/rdtypes/ANY/NSEC.py b/third_party/dnspython/dns/rdtypes/ANY/NSEC.py similarity index 71% rename from linkcheck/dns/rdtypes/ANY/NSEC.py rename to third_party/dnspython/dns/rdtypes/ANY/NSEC.py index 51ba8b29..ad113a4b 100644 --- a/linkcheck/dns/rdtypes/ANY/NSEC.py +++ b/third_party/dnspython/dns/rdtypes/ANY/NSEC.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2004-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,18 +13,18 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from cStringIO import StringIO +import cStringIO -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.rdatatype -import linkcheck.dns.name +import dns.exception +import dns.rdata +import dns.rdatatype +import dns.name -class NSEC(linkcheck.dns.rdata.Rdata): +class NSEC(dns.rdata.Rdata): """NSEC record @ivar next: the next name - @type next: linkcheck.dns.name.Name object + @type next: dns.name.Name object @ivar windows: the windowed bitmap list @type windows: list of (window number, string) tuples""" @@ -45,7 +44,7 @@ class NSEC(linkcheck.dns.rdata.Rdata): byte = ord(bitmap[i]) for j in xrange(0, 8): if byte & (0x80 >> j): - bits.append(linkcheck.dns.rdatatype.to_text(window * 256 + \ + bits.append(dns.rdatatype.to_text(window * 256 + \ i * 8 + j)) text += (' ' + ' '.join(bits)) return '%s%s' % (next, text) @@ -58,11 +57,11 @@ class NSEC(linkcheck.dns.rdata.Rdata): token = tok.get().unescape() if token.is_eol_or_eof(): break - nrdtype = linkcheck.dns.rdatatype.from_text(token.value) + nrdtype = dns.rdatatype.from_text(token.value) if nrdtype == 0: - raise linkcheck.dns.exception.DNSSyntaxError, "NSEC with bit 0" + raise dns.exception.SyntaxError("NSEC with bit 0") if nrdtype > 65535: - raise linkcheck.dns.exception.DNSSyntaxError, "NSEC with bit > 65535" + raise dns.exception.SyntaxError("NSEC with bit > 65535") rdtypes.append(nrdtype) rdtypes.sort() window = 0 @@ -80,7 +79,7 @@ class NSEC(linkcheck.dns.rdata.Rdata): bitmap = ['\0'] * 32 window = new_window offset = nrdtype % 256 - byte = offset / 8 + byte = offset // 8 bit = offset % 8 octets = byte + 1 bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit)) @@ -97,22 +96,22 @@ class NSEC(linkcheck.dns.rdata.Rdata): file.write(bitmap) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - (next, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], current) + (next, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused windows = [] while rdlen > 0: if rdlen < 3: - raise linkcheck.dns.exception.FormError, "NSEC too short" + raise dns.exception.FormError("NSEC too short") window = ord(wire[current]) octets = ord(wire[current + 1]) if octets == 0 or octets > 32: - raise linkcheck.dns.exception.FormError, "bad NSEC octets" + raise dns.exception.FormError("bad NSEC octets") current += 2 rdlen -= 2 if rdlen < octets: - raise linkcheck.dns.exception.FormError, "bad NSEC bitmap length" - bitmap = wire[current : current + octets] + raise dns.exception.FormError("bad NSEC bitmap length") + bitmap = wire[current : current + octets].unwrap() current += octets rdlen -= octets windows.append((window, bitmap)) @@ -126,17 +125,4 @@ class NSEC(linkcheck.dns.rdata.Rdata): self.next = self.next.choose_relativity(origin, relativize) def _cmp(self, other): - v = cmp(self.next, other.next) - if v == 0: - b1 = StringIO() - for (window, bitmap) in self.windows: - b1.write(chr(window)) - b1.write(chr(len(bitmap))) - b1.write(bitmap) - b2 = StringIO() - for (window, bitmap) in other.windows: - b2.write(chr(window)) - b2.write(chr(len(bitmap))) - b2.write(bitmap) - v = cmp(b1.getvalue(), b2.getvalue()) - return v + return self._wire_cmp(other) diff --git a/linkcheck/dns/rdtypes/ANY/NSEC3.py b/third_party/dnspython/dns/rdtypes/ANY/NSEC3.py similarity index 86% rename from linkcheck/dns/rdtypes/ANY/NSEC3.py rename to third_party/dnspython/dns/rdtypes/ANY/NSEC3.py index f3ddd17d..c7ac7375 100644 --- a/linkcheck/dns/rdtypes/ANY/NSEC3.py +++ b/third_party/dnspython/dns/rdtypes/ANY/NSEC3.py @@ -1,4 +1,4 @@ -# Copyright (C) 2004-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -18,9 +18,9 @@ import cStringIO import string import struct -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.rdatatype +import dns.exception +import dns.rdata +import dns.rdatatype b32_hex_to_normal = string.maketrans('0123456789ABCDEFGHIJKLMNOPQRSTUV', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') @@ -33,7 +33,7 @@ SHA1 = 1 # flag constants OPTOUT = 1 -class NSEC3(linkcheck.dns.rdata.Rdata): +class NSEC3(dns.rdata.Rdata): """NSEC3 record @ivar algorithm: the hash algorithm number @@ -74,7 +74,7 @@ class NSEC3(linkcheck.dns.rdata.Rdata): byte = ord(bitmap[i]) for j in xrange(0, 8): if byte & (0x80 >> j): - bits.append(linkcheck.dns.rdatatype.to_text(window * 256 + \ + bits.append(dns.rdatatype.to_text(window * 256 + \ i * 8 + j)) text += (' ' + ' '.join(bits)) return '%u %u %u %s %s%s' % (self.algorithm, self.flags, self.iterations, @@ -96,11 +96,11 @@ class NSEC3(linkcheck.dns.rdata.Rdata): token = tok.get().unescape() if token.is_eol_or_eof(): break - nrdtype = linkcheck.dns.rdatatype.from_text(token.value) + nrdtype = dns.rdatatype.from_text(token.value) if nrdtype == 0: - raise linkcheck.dns.exception.SyntaxError("NSEC3 with bit 0") + raise dns.exception.SyntaxError("NSEC3 with bit 0") if nrdtype > 65535: - raise linkcheck.dns.exception.SyntaxError("NSEC3 with bit > 65535") + raise dns.exception.SyntaxError("NSEC3 with bit > 65535") rdtypes.append(nrdtype) rdtypes.sort() window = 0 @@ -118,7 +118,7 @@ class NSEC3(linkcheck.dns.rdata.Rdata): bitmap = ['\0'] * 32 window = new_window offset = nrdtype % 256 - byte = offset / 8 + byte = offset // 8 bit = offset % 8 octets = byte + 1 bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit)) @@ -145,28 +145,28 @@ class NSEC3(linkcheck.dns.rdata.Rdata): wire[current : current + 5]) current += 5 rdlen -= 5 - salt = wire[current : current + slen] + salt = wire[current : current + slen].unwrap() current += slen rdlen -= slen (nlen, ) = struct.unpack('!B', wire[current]) current += 1 rdlen -= 1 - next = wire[current : current + nlen] + next = wire[current : current + nlen].unwrap() current += nlen rdlen -= nlen windows = [] while rdlen > 0: if rdlen < 3: - raise linkcheck.dns.exception.FormError("NSEC3 too short") + raise dns.exception.FormError("NSEC3 too short") window = ord(wire[current]) octets = ord(wire[current + 1]) if octets == 0 or octets > 32: - raise linkcheck.dns.exception.FormError("bad NSEC3 octets") + raise dns.exception.FormError("bad NSEC3 octets") current += 2 rdlen -= 2 if rdlen < octets: - raise linkcheck.dns.exception.FormError("bad NSEC3 bitmap length") - bitmap = wire[current : current + octets] + raise dns.exception.FormError("bad NSEC3 bitmap length") + bitmap = wire[current : current + octets].unwrap() current += octets rdlen -= octets windows.append((window, bitmap)) diff --git a/linkcheck/dns/rdtypes/ANY/NSEC3PARAM.py b/third_party/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py similarity index 92% rename from linkcheck/dns/rdtypes/ANY/NSEC3PARAM.py rename to third_party/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py index 3223ddd3..4e687825 100644 --- a/linkcheck/dns/rdtypes/ANY/NSEC3PARAM.py +++ b/third_party/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py @@ -1,4 +1,4 @@ -# Copyright (C) 2004-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,10 +16,10 @@ import cStringIO import struct -import linkcheck.dns.exception -import linkcheck.dns.rdata +import dns.exception +import dns.rdata -class NSEC3PARAM(linkcheck.dns.rdata.Rdata): +class NSEC3PARAM(dns.rdata.Rdata): """NSEC3PARAM record @ivar algorithm: the hash algorithm number @@ -71,11 +71,11 @@ class NSEC3PARAM(linkcheck.dns.rdata.Rdata): wire[current : current + 5]) current += 5 rdlen -= 5 - salt = wire[current : current + slen] + salt = wire[current : current + slen].unwrap() current += slen rdlen -= slen if rdlen != 0: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError return cls(rdclass, rdtype, algorithm, flags, iterations, salt) from_wire = classmethod(from_wire) diff --git a/linkcheck/dns/rdtypes/ANY/PTR.py b/third_party/dnspython/dns/rdtypes/ANY/PTR.py similarity index 82% rename from linkcheck/dns/rdtypes/ANY/PTR.py rename to third_party/dnspython/dns/rdtypes/ANY/PTR.py index b81f993f..4a037537 100644 --- a/linkcheck/dns/rdtypes/ANY/PTR.py +++ b/third_party/dnspython/dns/rdtypes/ANY/PTR.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.nsbase +import dns.rdtypes.nsbase -class PTR(linkcheck.dns.rdtypes.nsbase.NSBase): +class PTR(dns.rdtypes.nsbase.NSBase): """PTR record""" pass diff --git a/linkcheck/dns/rdtypes/ANY/RP.py b/third_party/dnspython/dns/rdtypes/ANY/RP.py similarity index 83% rename from linkcheck/dns/rdtypes/ANY/RP.py rename to third_party/dnspython/dns/rdtypes/ANY/RP.py index abea76c7..26c55314 100644 --- a/linkcheck/dns/rdtypes/ANY/RP.py +++ b/third_party/dnspython/dns/rdtypes/ANY/RP.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,18 +13,18 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.name +import dns.exception +import dns.rdata +import dns.name -class RP(linkcheck.dns.rdata.Rdata): +class RP(dns.rdata.Rdata): """RP record @ivar mbox: The responsible person's mailbox - @type mbox: linkcheck.dns.name.Name object + @type mbox: dns.name.Name object @ivar txt: The owner name of a node with TXT records, or the root name if no TXT records are associated with this RP. - @type txt: linkcheck.dns.name.Name object + @type txt: dns.name.Name object @see: RFC 1183""" __slots__ = ['mbox', 'txt'] @@ -59,16 +58,16 @@ class RP(linkcheck.dns.rdata.Rdata): self.txt.to_digestable(origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - (mbox, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (mbox, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused if rdlen <= 0: - raise linkcheck.dns.exception.FormError - (txt, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + raise dns.exception.FormError + (txt, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if not origin is None: mbox = mbox.relativize(origin) txt = txt.relativize(origin) diff --git a/linkcheck/dns/rdtypes/sigbase.py b/third_party/dnspython/dns/rdtypes/ANY/RRSIG.py similarity index 76% rename from linkcheck/dns/rdtypes/sigbase.py rename to third_party/dnspython/dns/rdtypes/ANY/RRSIG.py index 98fbc583..8b80aa84 100644 --- a/linkcheck/dns/rdtypes/sigbase.py +++ b/third_party/dnspython/dns/rdtypes/ANY/RRSIG.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2004-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -18,12 +17,12 @@ import calendar import struct import time -import linkcheck.dns.dnssec -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.rdatatype +import dns.dnssec +import dns.exception +import dns.rdata +import dns.rdatatype -class BadSigTime(linkcheck.dns.exception.DNSException): +class BadSigTime(dns.exception.DNSException): """Raised when a SIG or RRSIG RR's time cannot be parsed.""" pass @@ -42,8 +41,8 @@ def sigtime_to_posixtime(what): def posixtime_to_sigtime(what): return time.strftime('%Y%m%d%H%M%S', time.gmtime(what)) -class SIGBase(linkcheck.dns.rdata.Rdata): - """SIG-like record base +class RRSIG(dns.rdata.Rdata): + """RRSIG record @ivar type_covered: the rdata type this signature covers @type type_covered: int @@ -60,7 +59,7 @@ class SIGBase(linkcheck.dns.rdata.Rdata): @ivar key_tag: the key tag @type key_tag: int @ivar signer: the signer - @type signer: linkcheck.dns.name.Name object + @type signer: dns.name.Name object @ivar signature: the signature @type signature: string""" @@ -71,7 +70,7 @@ class SIGBase(linkcheck.dns.rdata.Rdata): def __init__(self, rdclass, rdtype, type_covered, algorithm, labels, original_ttl, expiration, inception, key_tag, signer, signature): - super(SIGBase, self).__init__(rdclass, rdtype) + super(RRSIG, self).__init__(rdclass, rdtype) self.type_covered = type_covered self.algorithm = algorithm self.labels = labels @@ -87,7 +86,7 @@ class SIGBase(linkcheck.dns.rdata.Rdata): def to_text(self, origin=None, relativize=True, **kw): return '%s %d %d %d %s %s %d %s %s' % ( - linkcheck.dns.rdatatype.to_text(self.type_covered), + dns.rdatatype.to_text(self.type_covered), self.algorithm, self.labels, self.original_ttl, @@ -95,12 +94,12 @@ class SIGBase(linkcheck.dns.rdata.Rdata): posixtime_to_sigtime(self.inception), self.key_tag, self.signer, - linkcheck.dns.rdata._base64ify(self.signature) + dns.rdata._base64ify(self.signature) ) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): - type_covered = linkcheck.dns.rdatatype.from_text(tok.get_string()) - algorithm = linkcheck.dns.dnssec.algorithm_from_text(tok.get_string()) + type_covered = dns.rdatatype.from_text(tok.get_string()) + algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) labels = tok.get_int() original_ttl = tok.get_ttl() expiration = sigtime_to_posixtime(tok.get_string()) @@ -114,7 +113,7 @@ class SIGBase(linkcheck.dns.rdata.Rdata): if t.is_eol_or_eof(): break if not t.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) signature = b64.decode('base64_codec') @@ -137,12 +136,12 @@ class SIGBase(linkcheck.dns.rdata.Rdata): header = struct.unpack('!HBBIIIH', wire[current : current + 18]) current += 18 rdlen -= 18 - (signer, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], current) + (signer, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused if not origin is None: signer = signer.relativize(origin) - signature = wire[current : current + rdlen] + signature = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], header[2], header[3], header[4], header[5], header[6], signer, signature) @@ -153,17 +152,5 @@ class SIGBase(linkcheck.dns.rdata.Rdata): self.signer = self.signer.choose_relativity(origin, relativize) def _cmp(self, other): - hs = struct.pack('!HBBIIIH', self.type_covered, - self.algorithm, self.labels, - self.original_ttl, self.expiration, - self.inception, self.key_tag) - ho = struct.pack('!HBBIIIH', other.type_covered, - other.algorithm, other.labels, - other.original_ttl, other.expiration, - other.inception, other.key_tag) - v = cmp(hs, ho) - if v == 0: - v = cmp(self.signer, other.signer) - if v == 0: - v = cmp(self.signature, other.signature) - return v + return self._wire_cmp(other) + diff --git a/linkcheck/dns/rdtypes/ANY/RT.py b/third_party/dnspython/dns/rdtypes/ANY/RT.py similarity index 80% rename from linkcheck/dns/rdtypes/ANY/RT.py rename to third_party/dnspython/dns/rdtypes/ANY/RT.py index 5595b0e6..f9653fdb 100644 --- a/linkcheck/dns/rdtypes/ANY/RT.py +++ b/third_party/dnspython/dns/rdtypes/ANY/RT.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.mxbase +import dns.rdtypes.mxbase -class RT(linkcheck.dns.rdtypes.mxbase.UncompressedDowncasingMX): +class RT(dns.rdtypes.mxbase.UncompressedDowncasingMX): """RT record""" pass diff --git a/linkcheck/dns/rdtypes/ANY/SOA.py b/third_party/dnspython/dns/rdtypes/ANY/SOA.py similarity index 88% rename from linkcheck/dns/rdtypes/ANY/SOA.py rename to third_party/dnspython/dns/rdtypes/ANY/SOA.py index fa884447..2d6f21b5 100644 --- a/linkcheck/dns/rdtypes/ANY/SOA.py +++ b/third_party/dnspython/dns/rdtypes/ANY/SOA.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,25 +15,25 @@ import struct -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.name +import dns.exception +import dns.rdata +import dns.name -class SOA(linkcheck.dns.rdata.Rdata): +class SOA(dns.rdata.Rdata): """SOA record @ivar mname: the SOA MNAME (master name) field - @type mname: linkcheck.dns.name.Name object + @type mname: dns.name.Name object @ivar rname: the SOA RNAME (responsible name) field - @type rname: linkcheck.dns.name.Name object + @type rname: dns.name.Name object @ivar serial: The zone's serial number @type serial: int @ivar refresh: The zone's refresh value (in seconds) @type refresh: int @ivar retry: The zone's retry value (in seconds) @type retry: int - @ivar expiration: The zone's expiration value (in seconds) - @type expiration: int + @ivar expire: The zone's expiration value (in seconds) + @type expire: int @ivar minimum: The zone's negative caching time (in seconds, called "minimum" for historical reasons) @type minimum: int @@ -91,14 +90,14 @@ class SOA(linkcheck.dns.rdata.Rdata): self.retry, self.expire, self.minimum) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - (mname, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], current) + (mname, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused - (rname, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], current) + (rname, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused if rdlen != 20: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError five_ints = struct.unpack('!IIIII', wire[current : current + rdlen]) if not origin is None: diff --git a/linkcheck/dns/rdtypes/ANY/SPF.py b/third_party/dnspython/dns/rdtypes/ANY/SPF.py similarity index 84% rename from linkcheck/dns/rdtypes/ANY/SPF.py rename to third_party/dnspython/dns/rdtypes/ANY/SPF.py index a41fd4e5..8860dd72 100644 --- a/linkcheck/dns/rdtypes/ANY/SPF.py +++ b/third_party/dnspython/dns/rdtypes/ANY/SPF.py @@ -1,4 +1,4 @@ -# Copyright (C) 2006, 2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -13,9 +13,9 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.txtbase +import dns.rdtypes.txtbase -class SPF(linkcheck.dns.rdtypes.txtbase.TXTBase): +class SPF(dns.rdtypes.txtbase.TXTBase): """SPF record @see: RFC 4408""" diff --git a/linkcheck/dns/rdtypes/ANY/SSHFP.py b/third_party/dnspython/dns/rdtypes/ANY/SSHFP.py similarity index 89% rename from linkcheck/dns/rdtypes/ANY/SSHFP.py rename to third_party/dnspython/dns/rdtypes/ANY/SSHFP.py index 0a4f0a6d..cec650a5 100644 --- a/linkcheck/dns/rdtypes/ANY/SSHFP.py +++ b/third_party/dnspython/dns/rdtypes/ANY/SSHFP.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2005-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2005-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,10 +15,10 @@ import struct -import linkcheck.dns.rdata -import linkcheck.dns.rdatatype +import dns.rdata +import dns.rdatatype -class SSHFP(linkcheck.dns.rdata.Rdata): +class SSHFP(dns.rdata.Rdata): """SSHFP record @ivar algorithm: the algorithm @@ -42,7 +41,7 @@ class SSHFP(linkcheck.dns.rdata.Rdata): def to_text(self, origin=None, relativize=True, **kw): return '%d %d %s' % (self.algorithm, self.fp_type, - linkcheck.dns.rdata._hexify(self.fingerprint, + dns.rdata._hexify(self.fingerprint, chunksize=128)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): @@ -64,7 +63,7 @@ class SSHFP(linkcheck.dns.rdata.Rdata): header = struct.unpack("!BB", wire[current : current + 2]) current += 2 rdlen -= 2 - fingerprint = wire[current : current + rdlen] + fingerprint = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], fingerprint) from_wire = classmethod(from_wire) diff --git a/linkcheck/dns/rdtypes/ANY/TXT.py b/third_party/dnspython/dns/rdtypes/ANY/TXT.py similarity index 82% rename from linkcheck/dns/rdtypes/ANY/TXT.py rename to third_party/dnspython/dns/rdtypes/ANY/TXT.py index b7b0836c..604fd0f4 100644 --- a/linkcheck/dns/rdtypes/ANY/TXT.py +++ b/third_party/dnspython/dns/rdtypes/ANY/TXT.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.txtbase +import dns.rdtypes.txtbase -class TXT(linkcheck.dns.rdtypes.txtbase.TXTBase): +class TXT(dns.rdtypes.txtbase.TXTBase): """TXT record""" pass diff --git a/linkcheck/dns/rdtypes/ANY/X25.py b/third_party/dnspython/dns/rdtypes/ANY/X25.py similarity index 82% rename from linkcheck/dns/rdtypes/ANY/X25.py rename to third_party/dnspython/dns/rdtypes/ANY/X25.py index 17a9986b..ae91295f 100644 --- a/linkcheck/dns/rdtypes/ANY/X25.py +++ b/third_party/dnspython/dns/rdtypes/ANY/X25.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,11 +13,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.rdata +import dns.tokenizer -class X25(linkcheck.dns.rdata.Rdata): +class X25(dns.rdata.Rdata): """X25 record @ivar address: the PSDN address @@ -32,7 +31,7 @@ class X25(linkcheck.dns.rdata.Rdata): self.address = address def to_text(self, origin=None, relativize=True, **kw): - return '"%s"' % linkcheck.dns.rdata._escapify(self.address) + return '"%s"' % dns.rdata._escapify(self.address) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): address = tok.get_string() @@ -53,8 +52,8 @@ class X25(linkcheck.dns.rdata.Rdata): current += 1 rdlen -= 1 if l != rdlen: - raise linkcheck.dns.exception.FormError - address = wire[current : current + l] + raise dns.exception.FormError + address = wire[current : current + l].unwrap() return cls(rdclass, rdtype, address) from_wire = classmethod(from_wire) diff --git a/linkcheck/dns/rdtypes/ANY/__init__.py b/third_party/dnspython/dns/rdtypes/ANY/__init__.py similarity index 90% rename from linkcheck/dns/rdtypes/ANY/__init__.py rename to third_party/dnspython/dns/rdtypes/ANY/__init__.py index 6aad8078..721e9dd6 100644 --- a/linkcheck/dns/rdtypes/ANY/__init__.py +++ b/third_party/dnspython/dns/rdtypes/ANY/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -28,19 +27,16 @@ __all__ = [ 'HINFO', 'HIP', 'ISDN', - 'KEY', 'LOC', 'MX', 'NS', 'NSEC', 'NSEC3', 'NSEC3PARAM', - 'NXT', 'PTR', 'RP', 'RRSIG', 'RT', - 'SIG', 'SOA', 'SPF', 'SSHFP', diff --git a/linkcheck/dns/rdtypes/IN/A.py b/third_party/dnspython/dns/rdtypes/IN/A.py similarity index 75% rename from linkcheck/dns/rdtypes/IN/A.py rename to third_party/dnspython/dns/rdtypes/IN/A.py index 16af5869..372d3332 100644 --- a/linkcheck/dns/rdtypes/IN/A.py +++ b/third_party/dnspython/dns/rdtypes/IN/A.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,12 +13,12 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception -import linkcheck.dns.ipv4 -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.ipv4 +import dns.rdata +import dns.tokenizer -class A(linkcheck.dns.rdata.Rdata): +class A(dns.rdata.Rdata): """A record. @ivar address: an IPv4 address @@ -30,7 +29,7 @@ class A(linkcheck.dns.rdata.Rdata): def __init__(self, rdclass, rdtype, address): super(A, self).__init__(rdclass, rdtype) # check that it's OK - junk = linkcheck.dns.ipv4.inet_aton(address) + junk = dns.ipv4.inet_aton(address) self.address = address def to_text(self, origin=None, relativize=True, **kw): @@ -44,15 +43,15 @@ class A(linkcheck.dns.rdata.Rdata): from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): - file.write(linkcheck.dns.ipv4.inet_aton(self.address)) + file.write(dns.ipv4.inet_aton(self.address)) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - address = linkcheck.dns.ipv4.inet_ntoa(wire[current : current + rdlen]) + address = dns.ipv4.inet_ntoa(wire[current : current + rdlen]) return cls(rdclass, rdtype, address) from_wire = classmethod(from_wire) def _cmp(self, other): - sa = linkcheck.dns.ipv4.inet_aton(self.address) - oa = linkcheck.dns.ipv4.inet_aton(other.address) + sa = dns.ipv4.inet_aton(self.address) + oa = dns.ipv4.inet_aton(other.address) return cmp(sa, oa) diff --git a/linkcheck/dns/rdtypes/IN/AAAA.py b/third_party/dnspython/dns/rdtypes/IN/AAAA.py similarity index 72% rename from linkcheck/dns/rdtypes/IN/AAAA.py rename to third_party/dnspython/dns/rdtypes/IN/AAAA.py index 836940da..e131bd50 100644 --- a/linkcheck/dns/rdtypes/IN/AAAA.py +++ b/third_party/dnspython/dns/rdtypes/IN/AAAA.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,12 +13,12 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception -import linkcheck.dns.inet -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.inet +import dns.rdata +import dns.tokenizer -class AAAA(linkcheck.dns.rdata.Rdata): +class AAAA(dns.rdata.Rdata): """AAAA record. @ivar address: an IPv6 address @@ -30,7 +29,7 @@ class AAAA(linkcheck.dns.rdata.Rdata): def __init__(self, rdclass, rdtype, address): super(AAAA, self).__init__(rdclass, rdtype) # check that it's OK - junk = linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET6, address) + junk = dns.inet.inet_pton(dns.inet.AF_INET6, address) self.address = address def to_text(self, origin=None, relativize=True, **kw): @@ -44,16 +43,16 @@ class AAAA(linkcheck.dns.rdata.Rdata): from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): - file.write(linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET6, self.address)) + file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.address)) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - address = linkcheck.dns.inet.inet_ntop(linkcheck.dns.inet.AF_INET6, + address = dns.inet.inet_ntop(dns.inet.AF_INET6, wire[current : current + rdlen]) return cls(rdclass, rdtype, address) from_wire = classmethod(from_wire) def _cmp(self, other): - sa = linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET6, self.address) - oa = linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET6, other.address) + sa = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) + oa = dns.inet.inet_pton(dns.inet.AF_INET6, other.address) return cmp(sa, oa) diff --git a/linkcheck/dns/rdtypes/IN/APL.py b/third_party/dnspython/dns/rdtypes/IN/APL.py similarity index 85% rename from linkcheck/dns/rdtypes/IN/APL.py rename to third_party/dnspython/dns/rdtypes/IN/APL.py index 83062eea..260fd6f3 100644 --- a/linkcheck/dns/rdtypes/IN/APL.py +++ b/third_party/dnspython/dns/rdtypes/IN/APL.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,13 +13,13 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from cStringIO import StringIO +import cStringIO import struct -import linkcheck.dns.exception -import linkcheck.dns.inet -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.inet +import dns.rdata +import dns.tokenizer class APLItem(object): """An APL list item. @@ -51,9 +50,9 @@ class APLItem(object): def to_wire(self, file): if self.family == 1: - address = linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET, self.address) + address = dns.inet.inet_pton(dns.inet.AF_INET, self.address) elif self.family == 2: - address = linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET6, self.address) + address = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) else: address = self.address.decode('hex_codec') # @@ -73,7 +72,7 @@ class APLItem(object): file.write(header) file.write(address) -class APL(linkcheck.dns.rdata.Rdata): +class APL(dns.rdata.Rdata): """APL record. @ivar items: a list of APL items @@ -120,7 +119,7 @@ class APL(linkcheck.dns.rdata.Rdata): items = [] while 1: if rdlen < 4: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError header = struct.unpack('!HBB', wire[current : current + 4]) afdlen = header[2] if afdlen > 127: @@ -131,17 +130,17 @@ class APL(linkcheck.dns.rdata.Rdata): current += 4 rdlen -= 4 if rdlen < afdlen: - raise linkcheck.dns.exception.FormError - address = wire[current : current + afdlen] + raise dns.exception.FormError + address = wire[current : current + afdlen].unwrap() l = len(address) if header[0] == 1: if l < 4: address += '\x00' * (4 - l) - address = linkcheck.dns.inet.inet_ntop(linkcheck.dns.inet.AF_INET, address) + address = dns.inet.inet_ntop(dns.inet.AF_INET, address) elif header[0] == 2: if l < 16: address += '\x00' * (16 - l) - address = linkcheck.dns.inet.inet_ntop(linkcheck.dns.inet.AF_INET6, address) + address = dns.inet.inet_ntop(dns.inet.AF_INET6, address) else: # # This isn't really right according to the RFC, but it @@ -159,7 +158,7 @@ class APL(linkcheck.dns.rdata.Rdata): from_wire = classmethod(from_wire) def _cmp(self, other): - f = StringIO() + f = cStringIO.StringIO() self.to_wire(f) wire1 = f.getvalue() f.seek(0) diff --git a/linkcheck/dns/rdtypes/IN/DHCID.py b/third_party/dnspython/dns/rdtypes/IN/DHCID.py similarity index 85% rename from linkcheck/dns/rdtypes/IN/DHCID.py rename to third_party/dnspython/dns/rdtypes/IN/DHCID.py index 56b6065a..5524bead 100644 --- a/linkcheck/dns/rdtypes/IN/DHCID.py +++ b/third_party/dnspython/dns/rdtypes/IN/DHCID.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2006, 2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,9 +13,9 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception +import dns.exception -class DHCID(linkcheck.dns.rdata.Rdata): +class DHCID(dns.rdata.Rdata): """DHCID record @ivar data: the data (the content of the RR is opaque as far as the @@ -31,7 +30,7 @@ class DHCID(linkcheck.dns.rdata.Rdata): self.data = data def to_text(self, origin=None, relativize=True, **kw): - return linkcheck.dns.rdata._base64ify(self.data) + return dns.rdata._base64ify(self.data) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): chunks = [] @@ -40,7 +39,7 @@ class DHCID(linkcheck.dns.rdata.Rdata): if t.is_eol_or_eof(): break if not t.is_identifier(): - raise linkcheck.dns.exception.SyntaxError + raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) data = b64.decode('base64_codec') @@ -52,7 +51,7 @@ class DHCID(linkcheck.dns.rdata.Rdata): file.write(self.data) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - data = wire[current : current + rdlen] + data = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, data) from_wire = classmethod(from_wire) diff --git a/linkcheck/dns/rdtypes/IN/IPSECKEY.py b/third_party/dnspython/dns/rdtypes/IN/IPSECKEY.py similarity index 80% rename from linkcheck/dns/rdtypes/IN/IPSECKEY.py rename to third_party/dnspython/dns/rdtypes/IN/IPSECKEY.py index 57fde012..d85b6fe9 100644 --- a/linkcheck/dns/rdtypes/IN/IPSECKEY.py +++ b/third_party/dnspython/dns/rdtypes/IN/IPSECKEY.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2006, 2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,14 +13,14 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from cStringIO import StringIO +import cStringIO import struct -import linkcheck.dns.exception -import linkcheck.dns.inet -import linkcheck.dns.name +import dns.exception +import dns.inet +import dns.name -class IPSECKEY(linkcheck.dns.rdata.Rdata): +class IPSECKEY(dns.rdata.Rdata): """IPSECKEY record @ivar precedence: the precedence for this key data @@ -47,10 +46,10 @@ class IPSECKEY(linkcheck.dns.rdata.Rdata): gateway = None elif gateway_type == 1: # check that it's OK - junk = linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET, gateway) + junk = dns.inet.inet_pton(dns.inet.AF_INET, gateway) elif gateway_type == 2: # check that it's OK - junk = linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET6, gateway) + junk = dns.inet.inet_pton(dns.inet.AF_INET6, gateway) elif gateway_type == 3: pass else: @@ -74,7 +73,7 @@ class IPSECKEY(linkcheck.dns.rdata.Rdata): raise ValueError('invalid gateway type') return '%d %d %d %s %s' % (self.precedence, self.gateway_type, self.algorithm, gateway, - linkcheck.dns.rdata._base64ify(self.key)) + dns.rdata._base64ify(self.key)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): precedence = tok.get_uint8() @@ -90,7 +89,7 @@ class IPSECKEY(linkcheck.dns.rdata.Rdata): if t.is_eol_or_eof(): break if not t.is_identifier(): - raise linkcheck.dns.exception.SyntaxError + raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) key = b64.decode('base64_codec') @@ -106,9 +105,9 @@ class IPSECKEY(linkcheck.dns.rdata.Rdata): if self.gateway_type == 0: pass elif self.gateway_type == 1: - file.write(linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET, self.gateway)) + file.write(dns.inet.inet_pton(dns.inet.AF_INET, self.gateway)) elif self.gateway_type == 2: - file.write(linkcheck.dns.inet.inet_pton(linkcheck.dns.inet.AF_INET6, self.gateway)) + file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.gateway)) elif self.gateway_type == 3: self.gateway.to_wire(file, None, origin) else: @@ -117,7 +116,7 @@ class IPSECKEY(linkcheck.dns.rdata.Rdata): def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): if rdlen < 3: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError header = struct.unpack('!BBB', wire[current : current + 3]) gateway_type = header[1] current += 3 @@ -125,30 +124,30 @@ class IPSECKEY(linkcheck.dns.rdata.Rdata): if gateway_type == 0: gateway = None elif gateway_type == 1: - gateway = linkcheck.dns.inet.inet_ntop(linkcheck.dns.inet.AF_INET, + gateway = dns.inet.inet_ntop(dns.inet.AF_INET, wire[current : current + 4]) current += 4 rdlen -= 4 elif gateway_type == 2: - gateway = linkcheck.dns.inet.inet_ntop(linkcheck.dns.inet.AF_INET6, + gateway = dns.inet.inet_ntop(dns.inet.AF_INET6, wire[current : current + 16]) current += 16 rdlen -= 16 elif gateway_type == 3: - (gateway, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (gateway, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused else: - raise linkcheck.dns.exception.FormError('invalid IPSECKEY gateway type') - key = wire[current : current + rdlen] + raise dns.exception.FormError('invalid IPSECKEY gateway type') + key = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], gateway_type, header[2], gateway, key) from_wire = classmethod(from_wire) def _cmp(self, other): - f = StringIO() + f = cStringIO.StringIO() self.to_wire(f) wire1 = f.getvalue() f.seek(0) @@ -156,4 +155,5 @@ class IPSECKEY(linkcheck.dns.rdata.Rdata): other.to_wire(f) wire2 = f.getvalue() f.close() + return cmp(wire1, wire2) diff --git a/linkcheck/dns/rdtypes/IN/KX.py b/third_party/dnspython/dns/rdtypes/IN/KX.py similarity index 81% rename from linkcheck/dns/rdtypes/IN/KX.py rename to third_party/dnspython/dns/rdtypes/IN/KX.py index 9e43e4b8..c7bd5bbe 100644 --- a/linkcheck/dns/rdtypes/IN/KX.py +++ b/third_party/dnspython/dns/rdtypes/IN/KX.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.mxbase +import dns.rdtypes.mxbase -class KX(linkcheck.dns.rdtypes.mxbase.UncompressedMX): +class KX(dns.rdtypes.mxbase.UncompressedMX): """KX record""" pass diff --git a/linkcheck/dns/rdtypes/IN/NAPTR.py b/third_party/dnspython/dns/rdtypes/IN/NAPTR.py similarity index 86% rename from linkcheck/dns/rdtypes/IN/NAPTR.py rename to third_party/dnspython/dns/rdtypes/IN/NAPTR.py index 51b6285e..7fe04308 100644 --- a/linkcheck/dns/rdtypes/IN/NAPTR.py +++ b/third_party/dnspython/dns/rdtypes/IN/NAPTR.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,9 +15,9 @@ import struct -import linkcheck.dns.exception -import linkcheck.dns.name -import linkcheck.dns.rdata +import dns.exception +import dns.name +import dns.rdata def _write_string(file, s): l = len(s) @@ -27,7 +26,7 @@ def _write_string(file, s): file.write(byte) file.write(s) -class NAPTR(linkcheck.dns.rdata.Rdata): +class NAPTR(dns.rdata.Rdata): """NAPTR record @ivar order: order @@ -41,7 +40,7 @@ class NAPTR(linkcheck.dns.rdata.Rdata): @ivar regexp: regular expression @type regexp: string @ivar replacement: replacement name - @type replacement: linkcheck.dns.name.Name object + @type replacement: dns.name.Name object @see: RFC 3403""" __slots__ = ['order', 'preference', 'flags', 'service', 'regexp', @@ -61,9 +60,9 @@ class NAPTR(linkcheck.dns.rdata.Rdata): replacement = self.replacement.choose_relativity(origin, relativize) return '%d %d "%s" "%s" "%s" %s' % \ (self.order, self.preference, - linkcheck.dns.rdata._escapify(self.flags), - linkcheck.dns.rdata._escapify(self.service), - linkcheck.dns.rdata._escapify(self.regexp), + dns.rdata._escapify(self.flags), + dns.rdata._escapify(self.service), + dns.rdata._escapify(self.regexp), self.replacement) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): @@ -98,15 +97,15 @@ class NAPTR(linkcheck.dns.rdata.Rdata): current += 1 rdlen -= 1 if l > rdlen or rdlen < 0: - raise linkcheck.dns.exception.FormError - s = wire[current : current + l] + raise dns.exception.FormError + s = wire[current : current + l].unwrap() current += l rdlen -= l strings.append(s) - (replacement, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (replacement, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if not origin is None: replacement = replacement.relativize(origin) return cls(rdclass, rdtype, order, preference, strings[0], strings[1], diff --git a/linkcheck/dns/rdtypes/IN/NSAP.py b/third_party/dnspython/dns/rdtypes/IN/NSAP.py similarity index 80% rename from linkcheck/dns/rdtypes/IN/NSAP.py rename to third_party/dnspython/dns/rdtypes/IN/NSAP.py index 56167d4f..216cb0a8 100644 --- a/linkcheck/dns/rdtypes/IN/NSAP.py +++ b/third_party/dnspython/dns/rdtypes/IN/NSAP.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,11 +13,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.rdata +import dns.tokenizer -class NSAP(linkcheck.dns.rdata.Rdata): +class NSAP(dns.rdata.Rdata): """NSAP record. @ivar address: a NASP @@ -38,10 +37,10 @@ class NSAP(linkcheck.dns.rdata.Rdata): address = tok.get_string() t = tok.get_eol() if address[0:2] != '0x': - raise linkcheck.dns.exception.DNSSyntaxError, 'string does not start with 0x' + raise dns.exception.SyntaxError('string does not start with 0x') address = address[2:].replace('.', '') if len(address) % 2 != 0: - raise linkcheck.dns.exception.DNSSyntaxError, 'hexstring has odd length' + raise dns.exception.SyntaxError('hexstring has odd length') address = address.decode('hex_codec') return cls(rdclass, rdtype, address) @@ -51,7 +50,7 @@ class NSAP(linkcheck.dns.rdata.Rdata): file.write(self.address) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - address = wire[current : current + rdlen] + address = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, address) from_wire = classmethod(from_wire) diff --git a/linkcheck/dns/rdtypes/IN/NSAP_PTR.py b/third_party/dnspython/dns/rdtypes/IN/NSAP_PTR.py similarity index 81% rename from linkcheck/dns/rdtypes/IN/NSAP_PTR.py rename to third_party/dnspython/dns/rdtypes/IN/NSAP_PTR.py index cb078703..df5b989a 100644 --- a/linkcheck/dns/rdtypes/IN/NSAP_PTR.py +++ b/third_party/dnspython/dns/rdtypes/IN/NSAP_PTR.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.nsbase +import dns.rdtypes.nsbase -class NSAP_PTR(linkcheck.dns.rdtypes.nsbase.UncompressedNS): +class NSAP_PTR(dns.rdtypes.nsbase.UncompressedNS): """NSAP-PTR record""" pass diff --git a/linkcheck/dns/rdtypes/IN/PX.py b/third_party/dnspython/dns/rdtypes/IN/PX.py similarity index 85% rename from linkcheck/dns/rdtypes/IN/PX.py rename to third_party/dnspython/dns/rdtypes/IN/PX.py index e989be90..1422b834 100644 --- a/linkcheck/dns/rdtypes/IN/PX.py +++ b/third_party/dnspython/dns/rdtypes/IN/PX.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,19 +15,19 @@ import struct -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.name +import dns.exception +import dns.rdata +import dns.name -class PX(linkcheck.dns.rdata.Rdata): +class PX(dns.rdata.Rdata): """PX record. @ivar preference: the preference value @type preference: int @ivar map822: the map822 name - @type map822: linkcheck.dns.name.Name object + @type map822: dns.name.Name object @ivar mapx400: the mapx400 name - @type mapx400: linkcheck.dns.name.Name object + @type mapx400: dns.name.Name object @see: RFC 2163""" __slots__ = ['preference', 'map822', 'mapx400'] @@ -65,18 +64,18 @@ class PX(linkcheck.dns.rdata.Rdata): (preference, ) = struct.unpack('!H', wire[current : current + 2]) current += 2 rdlen -= 2 - (map822, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (map822, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused > rdlen: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError current += cused rdlen -= cused if not origin is None: map822 = map822.relativize(origin) - (mapx400, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (mapx400, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if not origin is None: mapx400 = mapx400.relativize(origin) return cls(rdclass, rdtype, preference, map822, mapx400) diff --git a/linkcheck/dns/rdtypes/IN/SRV.py b/third_party/dnspython/dns/rdtypes/IN/SRV.py similarity index 89% rename from linkcheck/dns/rdtypes/IN/SRV.py rename to third_party/dnspython/dns/rdtypes/IN/SRV.py index 2c240cc6..e101b26b 100644 --- a/linkcheck/dns/rdtypes/IN/SRV.py +++ b/third_party/dnspython/dns/rdtypes/IN/SRV.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,11 +15,11 @@ import struct -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.name +import dns.exception +import dns.rdata +import dns.name -class SRV(linkcheck.dns.rdata.Rdata): +class SRV(dns.rdata.Rdata): """SRV record @ivar priority: the priority @@ -30,7 +29,7 @@ class SRV(linkcheck.dns.rdata.Rdata): @ivar port: the port of the service @type port: int @ivar target: the target host - @type target: linkcheck.dns.name.Name object + @type target: dns.name.Name object @see: RFC 2782""" __slots__ = ['priority', 'weight', 'port', 'target'] @@ -68,10 +67,10 @@ class SRV(linkcheck.dns.rdata.Rdata): wire[current : current + 6]) current += 6 rdlen -= 6 - (target, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (target, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if not origin is None: target = target.relativize(origin) return cls(rdclass, rdtype, priority, weight, port, target) diff --git a/linkcheck/dns/rdtypes/IN/WKS.py b/third_party/dnspython/dns/rdtypes/IN/WKS.py similarity index 87% rename from linkcheck/dns/rdtypes/IN/WKS.py rename to third_party/dnspython/dns/rdtypes/IN/WKS.py index 72d37925..04c3054e 100644 --- a/linkcheck/dns/rdtypes/IN/WKS.py +++ b/third_party/dnspython/dns/rdtypes/IN/WKS.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -17,13 +16,13 @@ import socket import struct -import linkcheck.dns.ipv4 -import linkcheck.dns.rdata +import dns.ipv4 +import dns.rdata _proto_tcp = socket.getprotobyname('tcp') _proto_udp = socket.getprotobyname('udp') -class WKS(linkcheck.dns.rdata.Rdata): +class WKS(dns.rdata.Rdata): """WKS record @ivar address: the address @@ -80,30 +79,30 @@ class WKS(linkcheck.dns.rdata.Rdata): for j in xrange(l, i + 1): bitmap.append('\x00') bitmap[i] = chr(ord(bitmap[i]) | (0x80 >> (serv % 8))) - bitmap = linkcheck.dns.rdata._truncate_bitmap(bitmap) + bitmap = dns.rdata._truncate_bitmap(bitmap) return cls(rdclass, rdtype, address, protocol, bitmap) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): - file.write(linkcheck.dns.ipv4.inet_aton(self.address)) + file.write(dns.ipv4.inet_aton(self.address)) protocol = struct.pack('!B', self.protocol) file.write(protocol) file.write(self.bitmap) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - address = linkcheck.dns.ipv4.inet_ntoa(wire[current : current + 4]) + address = dns.ipv4.inet_ntoa(wire[current : current + 4]) protocol, = struct.unpack('!B', wire[current + 4 : current + 5]) current += 5 rdlen -= 5 - bitmap = wire[current : current + rdlen] + bitmap = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, address, protocol, bitmap) from_wire = classmethod(from_wire) def _cmp(self, other): - sa = linkcheck.dns.ipv4.inet_aton(self.address) - oa = linkcheck.dns.ipv4.inet_aton(other.address) + sa = dns.ipv4.inet_aton(self.address) + oa = dns.ipv4.inet_aton(other.address) v = cmp(sa, oa) if v == 0: sp = struct.pack('!B', self.protocol) diff --git a/linkcheck/dns/rdtypes/IN/__init__.py b/third_party/dnspython/dns/rdtypes/IN/__init__.py similarity index 91% rename from linkcheck/dns/rdtypes/IN/__init__.py rename to third_party/dnspython/dns/rdtypes/IN/__init__.py index 2afc8472..24cf1ece 100644 --- a/linkcheck/dns/rdtypes/IN/__init__.py +++ b/third_party/dnspython/dns/rdtypes/IN/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, diff --git a/linkcheck/dns/rdtypes/__init__.py b/third_party/dnspython/dns/rdtypes/__init__.py similarity index 88% rename from linkcheck/dns/rdtypes/__init__.py rename to third_party/dnspython/dns/rdtypes/__init__.py index 593aab27..49db5a37 100644 --- a/linkcheck/dns/rdtypes/__init__.py +++ b/third_party/dnspython/dns/rdtypes/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -21,6 +20,4 @@ __all__ = [ 'IN', 'mxbase', 'nsbase', - 'sigbase', - 'keybase', ] diff --git a/linkcheck/dns/rdtypes/dsbase.py b/third_party/dnspython/dns/rdtypes/dsbase.py similarity index 91% rename from linkcheck/dns/rdtypes/dsbase.py rename to third_party/dnspython/dns/rdtypes/dsbase.py index 9540627d..6f5559a7 100644 --- a/linkcheck/dns/rdtypes/dsbase.py +++ b/third_party/dnspython/dns/rdtypes/dsbase.py @@ -1,4 +1,4 @@ -# Copyright (C) 2010 Nominum, Inc. +# Copyright (C) 2010, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -15,10 +15,10 @@ import struct -import linkcheck.dns.rdata -import linkcheck.dns.rdatatype +import dns.rdata +import dns.rdatatype -class DSBase(linkcheck.dns.rdata.Rdata): +class DSBase(dns.rdata.Rdata): """Base class for rdata that is like a DS record @ivar key_tag: the key tag @@ -44,7 +44,7 @@ class DSBase(linkcheck.dns.rdata.Rdata): def to_text(self, origin=None, relativize=True, **kw): return '%d %d %d %s' % (self.key_tag, self.algorithm, self.digest_type, - linkcheck.dns.rdata._hexify(self.digest, + dns.rdata._hexify(self.digest, chunksize=128)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): @@ -57,7 +57,7 @@ class DSBase(linkcheck.dns.rdata.Rdata): if t.is_eol_or_eof(): break if not t.is_identifier(): - raise linkcheck.dns.exception.SyntaxError + raise dns.exception.SyntaxError chunks.append(t.value) digest = ''.join(chunks) digest = digest.decode('hex_codec') @@ -76,7 +76,7 @@ class DSBase(linkcheck.dns.rdata.Rdata): header = struct.unpack("!HBB", wire[current : current + 4]) current += 4 rdlen -= 4 - digest = wire[current : current + rdlen] + digest = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], header[2], digest) from_wire = classmethod(from_wire) diff --git a/linkcheck/dns/rdtypes/mxbase.py b/third_party/dnspython/dns/rdtypes/mxbase.py similarity index 87% rename from linkcheck/dns/rdtypes/mxbase.py rename to third_party/dnspython/dns/rdtypes/mxbase.py index f8e02cf5..abc6a9ed 100644 --- a/linkcheck/dns/rdtypes/mxbase.py +++ b/third_party/dnspython/dns/rdtypes/mxbase.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,20 +15,20 @@ """MX-like base classes.""" +import cStringIO import struct -from cStringIO import StringIO -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.name +import dns.exception +import dns.rdata +import dns.name -class MXBase(linkcheck.dns.rdata.Rdata): +class MXBase(dns.rdata.Rdata): """Base class for rdata that is like an MX record. @ivar preference: the preference value @type preference: int @ivar exchange: the exchange name - @type exchange: linkcheck.dns.name.Name object""" + @type exchange: dns.name.Name object""" __slots__ = ['preference', 'exchange'] @@ -64,10 +63,10 @@ class MXBase(linkcheck.dns.rdata.Rdata): (preference, ) = struct.unpack('!H', wire[current : current + 2]) current += 2 rdlen -= 2 - (exchange, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (exchange, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if not origin is None: exchange = exchange.relativize(origin) return cls(rdclass, rdtype, preference, exchange) @@ -87,14 +86,14 @@ class MXBase(linkcheck.dns.rdata.Rdata): class UncompressedMX(MXBase): """Base class for rdata that is like an MX record, but whose name - is not compressed when convert to DNS wire format, and whose + is not compressed when converted to DNS wire format, and whose digestable form is not downcased.""" def to_wire(self, file, compress = None, origin = None): super(UncompressedMX, self).to_wire(file, None, origin) def to_digestable(self, origin = None): - f = StringIO() + f = cStringIO.StringIO() self.to_wire(f, None, origin) return f.getvalue() diff --git a/linkcheck/dns/rdtypes/nsbase.py b/third_party/dnspython/dns/rdtypes/nsbase.py similarity index 85% rename from linkcheck/dns/rdtypes/nsbase.py rename to third_party/dnspython/dns/rdtypes/nsbase.py index 35b3f782..fbd5ef1e 100644 --- a/linkcheck/dns/rdtypes/nsbase.py +++ b/third_party/dnspython/dns/rdtypes/nsbase.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,17 +15,17 @@ """NS-like base classes.""" -from cStringIO import StringIO +import cStringIO -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.name +import dns.exception +import dns.rdata +import dns.name -class NSBase(linkcheck.dns.rdata.Rdata): +class NSBase(dns.rdata.Rdata): """Base class for rdata that is like an NS record. @ivar target: the target name of the rdata - @type target: linkcheck.dns.name.Name object""" + @type target: dns.name.Name object""" __slots__ = ['target'] @@ -53,10 +52,10 @@ class NSBase(linkcheck.dns.rdata.Rdata): return self.target.to_digestable(origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - (target, cused) = linkcheck.dns.name.from_wire(wire[: current + rdlen], + (target, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if not origin is None: target = target.relativize(origin) return cls(rdclass, rdtype, target) @@ -78,6 +77,6 @@ class UncompressedNS(NSBase): super(UncompressedNS, self).to_wire(file, None, origin) def to_digestable(self, origin = None): - f = StringIO() + f = cStringIO.StringIO() self.to_wire(f, None, origin) return f.getvalue() diff --git a/linkcheck/dns/rdtypes/txtbase.py b/third_party/dnspython/dns/rdtypes/txtbase.py similarity index 80% rename from linkcheck/dns/rdtypes/txtbase.py rename to third_party/dnspython/dns/rdtypes/txtbase.py index 707fd32e..580f056e 100644 --- a/linkcheck/dns/rdtypes/txtbase.py +++ b/third_party/dnspython/dns/rdtypes/txtbase.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2006, 2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,11 +15,11 @@ """TXT-like base class.""" -import linkcheck.dns.exception -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer +import dns.exception +import dns.rdata +import dns.tokenizer -class TXTBase(linkcheck.dns.rdata.Rdata): +class TXTBase(dns.rdata.Rdata): """Base class for rdata that is like a TXT record @ivar strings: the text strings @@ -39,7 +38,7 @@ class TXTBase(linkcheck.dns.rdata.Rdata): txt = '' prefix = '' for s in self.strings: - txt += '%s"%s"' % (prefix, linkcheck.dns.rdata._escapify(s)) + txt += '%s"%s"' % (prefix, dns.rdata._escapify(s)) prefix = ' ' return txt @@ -50,12 +49,12 @@ class TXTBase(linkcheck.dns.rdata.Rdata): if token.is_eol_or_eof(): break if not (token.is_quoted_string() or token.is_identifier()): - raise linkcheck.dns.exception.DNSSyntaxError("expected a string") + raise dns.exception.SyntaxError("expected a string") if len(token.value) > 255: - raise linkcheck.dns.exception.DNSSyntaxError("string too long") + raise dns.exception.SyntaxError("string too long") strings.append(token.value) if len(strings) == 0: - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd return cls(rdclass, rdtype, strings) from_text = classmethod(from_text) @@ -75,8 +74,8 @@ class TXTBase(linkcheck.dns.rdata.Rdata): current += 1 rdlen -= 1 if l > rdlen: - raise linkcheck.dns.exception.FormError - s = wire[current : current + l] + raise dns.exception.FormError + s = wire[current : current + l].unwrap() current += l rdlen -= l strings.append(s) diff --git a/linkcheck/dns/renderer.py b/third_party/dnspython/dns/renderer.py similarity index 81% rename from linkcheck/dns/renderer.py rename to third_party/dnspython/dns/renderer.py index 2f18444b..ad3f83d4 100644 --- a/linkcheck/dns/renderer.py +++ b/third_party/dnspython/dns/renderer.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,13 +15,13 @@ """Help for building DNS wire format messages""" -from cStringIO import StringIO +import cStringIO import struct import random import time -import linkcheck.dns.exception -import linkcheck.dns.tsig +import dns.exception +import dns.tsig QUESTION = 0 ANSWER = 1 @@ -32,27 +31,27 @@ ADDITIONAL = 3 class Renderer(object): """Helper class for building DNS wire-format messages. - Most applications can use the higher-level L{linkcheck.dns.message.Message} + Most applications can use the higher-level L{dns.message.Message} class and its to_wire() method to generate wire-format messages. This class is for those applications which need finer control over the generation of messages. Typical use:: - r = linkcheck.dns.renderer.Renderer(id=1, flags=0x80, max_size=512) + r = dns.renderer.Renderer(id=1, flags=0x80, max_size=512) r.add_question(qname, qtype, qclass) - r.add_rrset(linkcheck.dns.renderer.ANSWER, rrset_1) - r.add_rrset(linkcheck.dns.renderer.ANSWER, rrset_2) - r.add_rrset(linkcheck.dns.renderer.AUTHORITY, ns_rrset) + r.add_rrset(dns.renderer.ANSWER, rrset_1) + r.add_rrset(dns.renderer.ANSWER, rrset_2) + r.add_rrset(dns.renderer.AUTHORITY, ns_rrset) r.add_edns(0, 0, 4096) - r.add_rrset(linkcheck.dns.renderer.ADDTIONAL, ad_rrset_1) - r.add_rrset(linkcheck.dns.renderer.ADDTIONAL, ad_rrset_2) + r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_1) + r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_2) r.write_header() r.add_tsig(keyname, secret, 300, 1, 0, '', request_mac) wire = r.get_wire() @ivar output: where rendering is written - @type output: StringIO object + @type output: cStringIO.StringIO object @ivar id: the message id @type id: int @ivar flags: the message flags @@ -60,12 +59,12 @@ class Renderer(object): @ivar max_size: the maximum size of the message @type max_size: int @ivar origin: the origin to use when rendering relative names - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @ivar compress: the compression table @type compress: dict @ivar section: the section currently being rendered - @type section: int (linkcheck.dns.renderer.QUESTION, linkcheck.dns.renderer.ANSWER, - linkcheck.dns.renderer.AUTHORITY, or linkcheck.dns.renderer.ADDITIONAL) + @type section: int (dns.renderer.QUESTION, dns.renderer.ANSWER, + dns.renderer.AUTHORITY, or dns.renderer.ADDITIONAL) @ivar counts: list of the number of RRs in each section @type counts: int list of length 4 @ivar mac: the MAC of the rendered message (if TSIG was used) @@ -81,13 +80,13 @@ class Renderer(object): @type flags: int @param max_size: the maximum message size; the default is 65535. If rendering results in a message greater than I{max_size}, - then L{linkcheck.dns.exception.TooBig} will be raised. + then L{dns.exception.TooBig} will be raised. @type max_size: int @param origin: the origin to use when rendering relative names - @type origin: linkcheck.dns.name.Namem or None. + @type origin: dns.name.Namem or None. """ - self.output = StringIO() + self.output = cStringIO.StringIO() if id is None: self.id = random.randint(0, 65535) else: @@ -127,20 +126,20 @@ class Renderer(object): @param section: the section @type section: int - @raises linkcheck.dns.exception.FormError: an attempt was made to set + @raises dns.exception.FormError: an attempt was made to set a section value less than the current section. """ if self.section != section: if self.section > section: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError self.section = section - def add_question(self, qname, rdtype, rdclass=linkcheck.dns.rdataclass.IN): + def add_question(self, qname, rdtype, rdclass=dns.rdataclass.IN): """Add a question to the message. @param qname: the question name - @type qname: linkcheck.dns.name.Name + @type qname: dns.name.Name @param rdtype: the question rdata type @type rdtype: int @param rdclass: the question rdata class @@ -154,7 +153,7 @@ class Renderer(object): after = self.output.tell() if after >= self.max_size: self._rollback(before) - raise linkcheck.dns.exception.TooBig + raise dns.exception.TooBig self.counts[QUESTION] += 1 def add_rrset(self, section, rrset, **kw): @@ -166,7 +165,7 @@ class Renderer(object): @param section: the section @type section: int @param rrset: the rrset - @type rrset: linkcheck.dns.rrset.RRset object + @type rrset: dns.rrset.RRset object """ self._set_section(section) @@ -175,7 +174,7 @@ class Renderer(object): after = self.output.tell() if after >= self.max_size: self._rollback(before) - raise linkcheck.dns.exception.TooBig + raise dns.exception.TooBig self.counts[section] += n def add_rdataset(self, section, name, rdataset, **kw): @@ -188,9 +187,9 @@ class Renderer(object): @param section: the section @type section: int @param name: the owner name - @type name: linkcheck.dns.name.Name object + @type name: dns.name.Name object @param rdataset: the rdataset - @type rdataset: linkcheck.dns.rdataset.Rdataset object + @type rdataset: dns.rdataset.Rdataset object """ self._set_section(section) @@ -200,7 +199,7 @@ class Renderer(object): after = self.output.tell() if after >= self.max_size: self._rollback(before) - raise linkcheck.dns.exception.TooBig + raise dns.exception.TooBig self.counts[section] += n def add_edns(self, edns, ednsflags, payload, options=None): @@ -214,7 +213,7 @@ class Renderer(object): size of UDP datagram the sender can handle. @type payload: int @param options: The EDNS options list - @type options: list of linkcheck.dns.edns.Option instances + @type options: list of dns.edns.Option instances @see: RFC 2671 """ @@ -223,7 +222,7 @@ class Renderer(object): ednsflags |= (edns << 16) self._set_section(ADDITIONAL) before = self.output.tell() - self.output.write(struct.pack('!BHHIH', 0, linkcheck.dns.rdatatype.OPT, payload, + self.output.write(struct.pack('!BHHIH', 0, dns.rdatatype.OPT, payload, ednsflags, 0)) if not options is None: lstart = self.output.tell() @@ -247,18 +246,18 @@ class Renderer(object): after = self.output.tell() if after >= self.max_size: self._rollback(before) - raise linkcheck.dns.exception.TooBig + raise dns.exception.TooBig self.counts[ADDITIONAL] += 1 def add_tsig(self, keyname, secret, fudge, id, tsig_error, other_data, - request_mac, algorithm=linkcheck.dns.tsig.default_algorithm): + request_mac, algorithm=dns.tsig.default_algorithm): """Add a TSIG signature to the message. @param keyname: the TSIG key name - @type keyname: linkcheck.dns.name.Name object + @type keyname: dns.name.Name object @param secret: the secret to use @type secret: string - @param fudge: TSIG time fudge; default is 300 seconds. + @param fudge: TSIG time fudge @type fudge: int @param id: the message id to encode in the tsig signature @type id: int @@ -270,12 +269,13 @@ class Renderer(object): had the specified MAC. @type request_mac: string @param algorithm: the TSIG algorithm to use + @type algorithm: dns.name.Name object """ self._set_section(ADDITIONAL) before = self.output.tell() s = self.output.getvalue() - (tsig_rdata, self.mac, ctx) = linkcheck.dns.tsig.sign(s, + (tsig_rdata, self.mac, ctx) = dns.tsig.sign(s, keyname, secret, int(time.time()), @@ -286,15 +286,15 @@ class Renderer(object): request_mac, algorithm=algorithm) keyname.to_wire(self.output, self.compress, self.origin) - self.output.write(struct.pack('!HHIH', linkcheck.dns.rdatatype.TSIG, - linkcheck.dns.rdataclass.ANY, 0, 0)) + self.output.write(struct.pack('!HHIH', dns.rdatatype.TSIG, + dns.rdataclass.ANY, 0, 0)) rdata_start = self.output.tell() self.output.write(tsig_rdata) after = self.output.tell() assert after - rdata_start < 65536 if after >= self.max_size: self._rollback(before) - raise linkcheck.dns.exception.TooBig + raise dns.exception.TooBig self.output.seek(rdata_start - 2) self.output.write(struct.pack('!H', after - rdata_start)) self.counts[ADDITIONAL] += 1 diff --git a/linkcheck/dns/resolver.py b/third_party/dnspython/dns/resolver.py similarity index 81% rename from linkcheck/dns/resolver.py rename to third_party/dnspython/dns/resolver.py index 7e98a1dd..e03baef8 100644 --- a/linkcheck/dns/resolver.py +++ b/third_party/dnspython/dns/resolver.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -17,53 +16,56 @@ """DNS stub resolver. @var default_resolver: The default resolver object -@type default_resolver: linkcheck.dns.resolver.Resolver object""" +@type default_resolver: dns.resolver.Resolver object""" import socket import sys import os import time -from .. import log, LOG_DNS -import linkcheck.dns.exception -import linkcheck.dns.message -import linkcheck.dns.name -import linkcheck.dns.query -import linkcheck.dns.rcode -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype +import dns.exception +import dns.message +import dns.name +import dns.query +import dns.rcode +import dns.rdataclass +import dns.rdatatype if sys.platform == 'win32': import _winreg -class NXDOMAIN(linkcheck.dns.exception.DNSException): +class NXDOMAIN(dns.exception.DNSException): """The query name does not exist.""" pass # The definition of the Timeout exception has moved from here to the -# linkcheck.dns.exception module. We keep linkcheck.dns.resolver.Timeout defined for +# dns.exception module. We keep dns.resolver.Timeout defined for # backwards compatibility. -Timeout = linkcheck.dns.exception.Timeout +Timeout = dns.exception.Timeout -class NoAnswer(linkcheck.dns.exception.DNSException): +class NoAnswer(dns.exception.DNSException): """The response did not contain an answer to the question.""" pass -class NoNameservers(linkcheck.dns.exception.DNSException): +class NoNameservers(dns.exception.DNSException): """No non-broken nameservers are available to answer the query.""" pass -class NotAbsolute(linkcheck.dns.exception.DNSException): +class NotAbsolute(dns.exception.DNSException): """Raised if an absolute domain name is required but a relative name was provided.""" pass -class NoRootSOA(linkcheck.dns.exception.DNSException): +class NoRootSOA(dns.exception.DNSException): """Raised if for some reason there is no SOA at the root name. This should never happen!""" pass +class NoMetaqueries(dns.exception.DNSException): + """Metaqueries are not allowed.""" + pass + class Answer(object): """DNS stub resolver answer @@ -81,19 +83,22 @@ class Answer(object): node's name might not be the query name. @ivar qname: The query name - @type qname: linkcheck.dns.name.Name object + @type qname: dns.name.Name object @ivar rdtype: The query type @type rdtype: int @ivar rdclass: The query class @type rdclass: int @ivar response: The response message - @type response: linkcheck.dns.message.Message object + @type response: dns.message.Message object @ivar rrset: The answer - @type rrset: linkcheck.dns.rrset.RRset object + @type rrset: dns.rrset.RRset object @ivar expiration: The time when the answer expires @type expiration: float (seconds since the epoch) + @ivar canonical_name: The canonical name of the query name + @type canonical_name: dns.name.Name object """ - def __init__(self, qname, rdtype, rdclass, response): + def __init__(self, qname, rdtype, rdclass, response, + raise_on_no_answer=True): self.qname = qname self.rdtype = rdtype self.rdclass = rdclass @@ -108,12 +113,12 @@ class Answer(object): min_ttl = rrset.ttl break except KeyError: - if rdtype != linkcheck.dns.rdatatype.CNAME: + if rdtype != dns.rdatatype.CNAME: try: crrset = response.find_rrset(response.answer, qname, rdclass, - linkcheck.dns.rdatatype.CNAME) + dns.rdatatype.CNAME) if min_ttl == -1 or crrset.ttl < min_ttl: min_ttl = crrset.ttl for rd in crrset: @@ -121,11 +126,31 @@ class Answer(object): break continue except KeyError: - raise NoAnswer("DNS response had no answer") - raise NoAnswer("DNS response had no answer") - if rrset is None: + if raise_on_no_answer: + raise NoAnswer("DNS response had no answer") + if raise_on_no_answer: + raise NoAnswer("DNS response had no answer") + if rrset is None and raise_on_no_answer: raise NoAnswer("DNS response had no answer") + self.canonical_name = qname self.rrset = rrset + if rrset is None: + while 1: + # Look for a SOA RR whose owner name is a superdomain + # of qname. + try: + srrset = response.find_rrset(response.authority, qname, + rdclass, dns.rdatatype.SOA) + if min_ttl == -1 or srrset.ttl < min_ttl: + min_ttl = srrset.ttl + if srrset[0].minimum < min_ttl: + min_ttl = srrset[0].minimum + break + except KeyError: + try: + qname = qname.parent() + except dns.name.NoParent: + break self.expiration = time.time() + min_ttl def __str__ (self): @@ -207,9 +232,9 @@ class Cache(object): """Get the answer associated with I{key}. Returns None if no answer is cached for the key. @param key: the key - @type key: (linkcheck.dns.name.Name, int, int) tuple whose values are the + @type key: (dns.name.Name, int, int) tuple whose values are the query name, rdtype, and rdclass. - @rtype: linkcheck.dns.resolver.Answer object or None + @rtype: dns.resolver.Answer object or None """ self.maybe_clean() @@ -221,10 +246,10 @@ class Cache(object): def put(self, key, value): """Associate key and value in the cache. @param key: the key - @type key: (linkcheck.dns.name.Name, int, int) tuple whose values are the + @type key: (dns.name.Name, int, int) tuple whose values are the query name, rdtype, and rdclass. @param value: The answer being cached - @type value: linkcheck.dns.resolver.Answer object + @type value: dns.resolver.Answer object """ self.maybe_clean() @@ -237,7 +262,7 @@ class Cache(object): the entire cache is flushed. @param key: the key to flush - @type key: (linkcheck.dns.name.Name, int, int) tuple or None + @type key: (dns.name.Name, int, int) tuple or None """ if not key is None: @@ -252,14 +277,14 @@ class Resolver(object): """DNS stub resolver @ivar domain: The domain of this host - @type domain: linkcheck.dns.name.Name object + @type domain: dns.name.Name object @ivar nameservers: A list of nameservers to query. Each nameserver is a string which contains the IP address of a nameserver. @type nameservers: list of strings @ivar search: The search list. If the query name is a relative name, the resolver will construct an absolute query name by appending the search names one by one to the query name. - @type search: list of linkcheck.dns.name.Name objects + @type search: list of dns.name.Name objects @ivar port: The port to which to send queries. The default is 53. @type port: int @ivar timeout: The number of seconds to wait for a response from a @@ -272,18 +297,18 @@ class Resolver(object): @ivar keyring: The TSIG keyring to use. The default is None. @type keyring: dict @ivar keyname: The TSIG keyname to use. The default is None. - @type keyname: linkcheck.dns.name.Name object + @type keyname: dns.name.Name object @ivar keyalgorithm: The TSIG key algorithm to use. The default is - linkcheck.dns.tsig.default_algorithm. + dns.tsig.default_algorithm. @type keyalgorithm: string - @ivar edns: The EDNS level to use. The default is -1, no Elinkcheck.dns. + @ivar edns: The EDNS level to use. The default is -1, no Edns. @type edns: int @ivar ednsflags: The EDNS flags @type ednsflags: int @ivar payload: The EDNS payload size. The default is 0. @type payload: int @ivar cache: The cache to use. The default is None. - @type cache: linkcheck.dns.resolver.Cache object + @type cache: dns.resolver.Cache object """ def __init__(self, filename='/etc/resolv.conf', configure=True): """Initialize a resolver instance. @@ -311,9 +336,9 @@ class Resolver(object): def reset(self): """Reset all resolver configuration to the defaults.""" self.domain = \ - linkcheck.dns.name.Name(linkcheck.dns.name.from_text(socket.gethostname())[1:]) + dns.name.Name(dns.name.from_text(socket.gethostname())[1:]) if len(self.domain) == 0: - self.domain = linkcheck.dns.name.root + self.domain = dns.name.root self.nameservers = [] self.localhosts = set([ 'localhost', @@ -333,7 +358,7 @@ class Resolver(object): self.lifetime = 30.0 self.keyring = None self.keyname = None - self.keyalgorithm = linkcheck.dns.tsig.default_algorithm + self.keyalgorithm = dns.tsig.default_algorithm self.edns = -1 self.ednsflags = 0 self.payload = 0 @@ -365,10 +390,10 @@ class Resolver(object): if tokens[0] == 'nameserver': self.nameservers.append(tokens[1]) elif tokens[0] == 'domain': - self.domain = linkcheck.dns.name.from_text(tokens[1]) + self.domain = dns.name.from_text(tokens[1]) elif tokens[0] == 'search': for suffix in tokens[1:]: - self.search.add(linkcheck.dns.name.from_text(suffix)) + self.search.add(dns.name.from_text(suffix)) finally: if want_close: f.close() @@ -391,9 +416,12 @@ class Resolver(object): if os.name != 'posix': # only POSIX is supported right now return [] - from linkcheck.network import IfConfig - ifc = IfConfig() + try: + from linkcheck.network import IfConfig + except ImportError: + return [] ifaddrs = [] + ifc = IfConfig() for iface in ifc.getInterfaceList(flags=IfConfig.IFF_UP): addr = ifc.getAddr(iface) if addr: @@ -431,7 +459,7 @@ class Resolver(object): split_char = ' ' return split_char - def _config_win32_nameservers (self, nameservers, split_char=','): + def _config_win32_nameservers(self, nameservers): """Configure a NameServer registry entry.""" # we call str() on nameservers to convert it from unicode to ascii nameservers = str(nameservers) @@ -441,12 +469,12 @@ class Resolver(object): if not ns in self.nameservers: self.nameservers.append(ns) - def _config_win32_domain (self, domain): + def _config_win32_domain(self, domain): """Configure a Domain registry entry.""" # we call str() on domain to convert it from unicode to ascii - self.domain = linkcheck.dns.name.from_text(str(domain)) + self.domain = dns.name.from_text(str(domain)) - def _config_win32_search (self, search): + def _config_win32_search(self, search): """Configure a Search registry entry.""" # we call str() on search to convert it from unicode to ascii search = str(search) @@ -454,7 +482,7 @@ class Resolver(object): search_list = search.split(split_char) for s in search_list: if not s in self.search: - self.search.add(linkcheck.dns.name.from_text(s)) + self.search.add(dns.name.from_text(s)) def _config_win32_add_ifaddr (self, key, name): """Add interface ip address to self.localhosts.""" @@ -467,7 +495,7 @@ class Resolver(object): except WindowsError: pass - def _config_win32_fromkey (self, key): + def _config_win32_fromkey(self, key): """Extract DNS info from a registry key.""" try: enable_dhcp, rtype = _winreg.QueryValueEx(key, 'EnableDHCP') @@ -508,7 +536,7 @@ class Resolver(object): except WindowsError: search = None if search: - self._config_win32_search(servers) + self._config_win32_search(search) def read_registry(self): """Extract resolver configuration from the Windows registry.""" @@ -626,8 +654,8 @@ class Resolver(object): raise Timeout return min(self.lifetime - duration, self.timeout) - def query(self, qname, rdtype=linkcheck.dns.rdatatype.A, - rdclass=linkcheck.dns.rdataclass.IN, tcp=False, source=None): + def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, + tcp=False, source=None, raise_on_no_answer=True): """Query nameservers to find the answer to the question. The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects @@ -636,7 +664,7 @@ class Resolver(object): the string 'NS' both mean to query for records with DNS rdata type NS. @param qname: the query name - @type qname: linkcheck.dns.name.Name object or string + @type qname: dns.name.Name object or string @param rdtype: the query type @type rdtype: int or string @param rdclass: the query class @@ -645,25 +673,33 @@ class Resolver(object): @type tcp: bool @param source: bind to this IP address (defaults to machine default IP). @type source: IP address in dotted quad notation - @rtype: linkcheck.dns.resolver.Answer instance + @param raise_on_no_answer: raise NoAnswer if there's no answer + (defaults is True). + @type raise_on_no_answer: bool + @rtype: dns.resolver.Answer instance @raises Timeout: no answers could be found in the specified lifetime @raises NXDOMAIN: the query name does not exist - @raises NoAnswer: the response did not contain an answer + @raises NoAnswer: the response did not contain an answer and + raise_on_no_answer is True. @raises NoNameservers: no non-broken nameservers are available to answer the question.""" if isinstance(qname, basestring): - qname = linkcheck.dns.name.from_text(qname, None) + qname = dns.name.from_text(qname, None) if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) + rdtype = dns.rdatatype.from_text(rdtype) + if dns.rdatatype.is_metatype(rdtype): + raise NoMetaqueries if isinstance(rdclass, basestring): - rdclass = linkcheck.dns.rdataclass.from_text(rdclass) + rdclass = dns.rdataclass.from_text(rdclass) + if dns.rdataclass.is_metaclass(rdclass): + raise NoMetaqueries qnames_to_try = [] if qname.is_absolute(): qnames_to_try.append(qname) else: if len(qname) > 1: - qnames_to_try.append(qname.concatenate(linkcheck.dns.name.root)) + qnames_to_try.append(qname.concatenate(dns.name.root)) if self.search: for suffix in self.search: qnames_to_try.append(qname.concatenate(suffix)) @@ -676,7 +712,7 @@ class Resolver(object): answer = self.cache.get((qname, rdtype, rdclass)) if answer: return answer - request = linkcheck.dns.message.make_query(qname, rdtype, rdclass) + request = dns.message.make_query(qname, rdtype, rdclass) if not self.keyname is None: request.use_tsig(self.keyring, self.keyname, algorithm=self.keyalgorithm) @@ -695,27 +731,27 @@ class Resolver(object): timeout = self._compute_timeout(start) try: if tcp: - response = linkcheck.dns.query.tcp(request, nameserver, + response = dns.query.tcp(request, nameserver, timeout, self.port, source=source) else: - response = linkcheck.dns.query.udp(request, nameserver, + response = dns.query.udp(request, nameserver, timeout, self.port, source=source) - except (socket.error, linkcheck.dns.exception.Timeout): + except (socket.error, dns.exception.Timeout): # Communication failure or timeout. Go to the # next server response = None continue - except linkcheck.dns.query.UnexpectedSource: + except dns.query.UnexpectedSource: # Who knows? Keep going. response = None continue - except linkcheck.dns.exception.FormError: + except dns.exception.FormError: # We don't understand what this server is # saying. Take it out of the mix and @@ -725,15 +761,15 @@ class Resolver(object): response = None continue rcode = response.rcode() - if rcode == linkcheck.dns.rcode.NOERROR or \ - rcode == linkcheck.dns.rcode.NXDOMAIN: + if rcode == dns.rcode.NOERROR or \ + rcode == dns.rcode.NXDOMAIN: break # We got a response, but we're not happy with the # rcode in it. Remove the server from the mix if # the rcode isn't SERVFAIL. - if rcode != linkcheck.dns.rcode.SERVFAIL: + if rcode != dns.rcode.SERVFAIL: nameservers.remove(nameserver) response = None @@ -750,19 +786,20 @@ class Resolver(object): sleep_time = min(timeout, backoff) backoff *= 2 time.sleep(sleep_time) - if response.rcode() == linkcheck.dns.rcode.NXDOMAIN: + if response.rcode() == dns.rcode.NXDOMAIN: continue all_nxdomain = False break if all_nxdomain: raise NXDOMAIN("Domain does not exist") - 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) return answer def use_tsig(self, keyring, keyname=None, - algorithm=linkcheck.dns.tsig.default_algorithm): + algorithm=dns.tsig.default_algorithm): """Add a TSIG signature to the query. @param keyring: The TSIG keyring to use; defaults to None. @@ -774,7 +811,7 @@ class Resolver(object): so applications should supply a keyname when a keyring is used, unless they know the keyring contains only one key. @param algorithm: The TSIG key algorithm to use. The default - is linkcheck.dns.tsig.default_algorithm. + is dns.tsig.default_algorithm. @type algorithm: string""" self.keyring = keyring if keyname is None: @@ -784,9 +821,9 @@ class Resolver(object): self.keyalgorithm = algorithm def use_edns(self, edns, ednsflags, payload): - """Configure Elinkcheck.dns. + """Configure Edns. - @param edns: The EDNS level to use. The default is -1, no Elinkcheck.dns. + @param edns: The EDNS level to use. The default is -1, no Edns. @type edns: int @param ednsflags: The EDNS flags @type ednsflags: int @@ -808,45 +845,46 @@ def get_default_resolver(): default_resolver = Resolver() return default_resolver -def query(qname, rdtype=linkcheck.dns.rdatatype.A, rdclass=linkcheck.dns.rdataclass.IN, - tcp=False, source=None, resolver=None): +def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, + tcp=False, source=None, raise_on_no_answer=True, resolver=None): """Query nameservers to find the answer to the question. This is a convenience function that uses the default resolver object to make the query. - @see: L{linkcheck.dns.resolver.Resolver.query} for more information on the + @see: L{dns.resolver.Resolver.query} for more information on the parameters.""" - log.debug(LOG_DNS, "Query %s %s %s", qname, rdtype, rdclass) if resolver is None: resolver = get_default_resolver() - return resolver.query(qname, rdtype, rdclass, tcp, source) + return resolver.query(qname, rdtype, rdclass, tcp, source, raise_on_no_answer) -def zone_for_name(name, rdclass=linkcheck.dns.rdataclass.IN, - tcp=False, resolver=None): +def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None): """Find the name of the zone which contains the specified name. @param name: the query name - @type name: absolute linkcheck.dns.name.Name object or string - @ivar rdclass: The query class + @type name: absolute dns.name.Name object or string + @param rdclass: The query class @type rdclass: int @param tcp: use TCP to make the query (default is False). @type tcp: bool @param resolver: the resolver to use - @type resolver: linkcheck.dns.resolver.Resolver object or None - @rtype: linkcheck.dns.name.Name""" + @type resolver: dns.resolver.Resolver object or None + @rtype: dns.name.Name""" - if isinstance(name, str): - name = linkcheck.dns.name.from_text(name, linkcheck.dns.name.root) + if isinstance(name, basestring): + name = dns.name.from_text(name, dns.name.root) if resolver is None: resolver = get_default_resolver() if not name.is_absolute(): raise NotAbsolute(name) while 1: try: - answer = resolver.query(name, linkcheck.dns.rdatatype.SOA, rdclass, tcp) - return name - except (linkcheck.dns.resolver.NXDOMAIN, linkcheck.dns.resolver.NoAnswer): - try: - name = name.parent() - except linkcheck.dns.name.NoParent: - raise NoRootSOA + answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp) + if answer.rrset.name == name: + return name + # otherwise we were CNAMEd or DNAMEd and need to look higher + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): + pass + try: + name = name.parent() + except dns.name.NoParent: + raise NoRootSOA diff --git a/linkcheck/dns/reversename.py b/third_party/dnspython/dns/reversename.py similarity index 68% rename from linkcheck/dns/reversename.py rename to third_party/dnspython/dns/reversename.py index b58eb1b4..8e83cad4 100644 --- a/linkcheck/dns/reversename.py +++ b/third_party/dnspython/dns/reversename.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2006, 2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -17,17 +16,17 @@ """DNS Reverse Map Names. @var ipv4_reverse_domain: The DNS IPv4 reverse-map domain, in-addr.arpa. -@type ipv4_reverse_domain: linkcheck.dns.name.Name object +@type ipv4_reverse_domain: dns.name.Name object @var ipv6_reverse_domain: The DNS IPv6 reverse-map domain, ip6.arpa. -@type ipv6_reverse_domain: linkcheck.dns.name.Name object +@type ipv6_reverse_domain: dns.name.Name object """ -import linkcheck.dns.name -import linkcheck.dns.ipv6 -import linkcheck.dns.ipv4 +import dns.name +import dns.ipv6 +import dns.ipv4 -ipv4_reverse_domain = linkcheck.dns.name.from_text('in-addr.arpa.') -ipv6_reverse_domain = linkcheck.dns.name.from_text('ip6.arpa.') +ipv4_reverse_domain = dns.name.from_text('in-addr.arpa.') +ipv6_reverse_domain = dns.name.from_text('ip6.arpa.') def from_address(text): """Convert an IPv4 or IPv6 address in textual form into a Name object whose @@ -35,21 +34,21 @@ def from_address(text): @param text: an IPv4 or IPv6 address in textual form (e.g. '127.0.0.1', '::1') @type text: str - @rtype: linkcheck.dns.name.Name object + @rtype: dns.name.Name object """ try: - parts = list(linkcheck.dns.ipv6.inet_aton(text).encode('hex_codec')) + parts = list(dns.ipv6.inet_aton(text).encode('hex_codec')) origin = ipv6_reverse_domain - except: - parts = ['%d' % ord(byte) for byte in linkcheck.dns.ipv4.inet_aton(text)] + except StandardError: + parts = ['%d' % ord(byte) for byte in dns.ipv4.inet_aton(text)] origin = ipv4_reverse_domain parts.reverse() - return linkcheck.dns.name.from_text('.'.join(parts), origin=origin) + return dns.name.from_text('.'.join(parts), origin=origin) def to_address(name): """Convert a reverse map domain name into textual address form. @param name: an IPv4 or IPv6 address in reverse-map form. - @type name: linkcheck.dns.name.Name object + @type name: dns.name.Name object @rtype: str """ if name.is_subdomain(ipv4_reverse_domain): @@ -58,7 +57,7 @@ def to_address(name): labels.reverse() text = '.'.join(labels) # run through inet_aton() to check syntax and make pretty. - return linkcheck.dns.ipv4.inet_ntoa(linkcheck.dns.ipv4.inet_aton(text)) + return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) elif name.is_subdomain(ipv6_reverse_domain): name = name.relativize(ipv6_reverse_domain) labels = list(name.labels) @@ -71,6 +70,6 @@ def to_address(name): i += 4 text = ':'.join(parts) # run through inet_aton() to check syntax and make pretty. - return linkcheck.dns.ipv6.inet_ntoa(linkcheck.dns.ipv6.inet_aton(text)) + return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) else: - raise linkcheck.dns.exception.SyntaxError('unknown reverse-map address family') + raise dns.exception.SyntaxError('unknown reverse-map address family') diff --git a/linkcheck/dns/rrset.py b/third_party/dnspython/dns/rrset.py similarity index 74% rename from linkcheck/dns/rrset.py rename to third_party/dnspython/dns/rrset.py index 9ad4bf82..f6051fea 100644 --- a/linkcheck/dns/rrset.py +++ b/third_party/dnspython/dns/rrset.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,12 +15,12 @@ """DNS RRsets (an RRset is a named rdataset)""" -import linkcheck.dns.name -import linkcheck.dns.rdataset -import linkcheck.dns.rdataclass -import linkcheck.dns.renderer +import dns.name +import dns.rdataset +import dns.rdataclass +import dns.renderer -class RRset(linkcheck.dns.rdataset.Rdataset): +class RRset(dns.rdataset.Rdataset): """A DNS RRset (named rdataset). RRset inherits from Rdataset, and RRsets can be treated as @@ -33,7 +32,7 @@ class RRset(linkcheck.dns.rdataset.Rdataset): __slots__ = ['name', 'deleting'] - def __init__(self, name, rdclass, rdtype, covers=linkcheck.dns.rdatatype.NONE, + def __init__(self, name, rdclass, rdtype, covers=dns.rdatatype.NONE, deleting=None): """Create a new RRset.""" @@ -51,14 +50,14 @@ class RRset(linkcheck.dns.rdataset.Rdataset): if self.covers == 0: ctext = '' else: - ctext = '(' + linkcheck.dns.rdatatype.to_text(self.covers) + ')' + ctext = '(' + dns.rdatatype.to_text(self.covers) + ')' if not self.deleting is None: - dtext = ' delete=' + linkcheck.dns.rdataclass.to_text(self.deleting) + dtext = ' delete=' + dns.rdataclass.to_text(self.deleting) else: dtext = '' return '' + dns.rdataclass.to_text(self.rdclass) + ' ' + \ + dns.rdatatype.to_text(self.rdtype) + ctext + dtext + ' RRset>' def __str__(self): return self.to_text() @@ -87,7 +86,7 @@ class RRset(linkcheck.dns.rdataset.Rdataset): def to_text(self, origin=None, relativize=True, **kw): """Convert the RRset into DNS master file format. - @see: L{linkcheck.dns.name.Name.choose_relativity} for more information + @see: L{dns.name.Name.choose_relativity} for more information on how I{origin} and I{relativize} determine the way names are emitted. @@ -95,7 +94,7 @@ class RRset(linkcheck.dns.rdataset.Rdataset): to_text() method. @param origin: The origin for relative names, or None. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @param relativize: True if names should names be relativized @type relativize: bool""" @@ -111,28 +110,28 @@ class RRset(linkcheck.dns.rdataset.Rdataset): def to_rdataset(self): """Convert an RRset into an Rdataset. - @rtype: linkcheck.dns.rdataset.Rdataset object + @rtype: dns.rdataset.Rdataset object """ - return linkcheck.dns.rdataset.from_rdata_list(self.ttl, list(self)) + return dns.rdataset.from_rdata_list(self.ttl, list(self)) def from_text_list(name, ttl, rdclass, rdtype, text_rdatas): """Create an RRset with the specified name, TTL, class, and type, and with the specified list of rdatas in text format. - @rtype: linkcheck.dns.rrset.RRset object + @rtype: dns.rrset.RRset object """ - if isinstance(name, basestring): - name = linkcheck.dns.name.from_text(name, None) - if isinstance(rdclass, basestring): - rdclass = linkcheck.dns.rdataclass.from_text(rdclass) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + if isinstance(rdclass, (str, unicode)): + rdclass = dns.rdataclass.from_text(rdclass) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) r = RRset(name, rdclass, rdtype) r.update_ttl(ttl) for t in text_rdatas: - rd = linkcheck.dns.rdata.from_text(r.rdclass, r.rdtype, t) + rd = dns.rdata.from_text(r.rdclass, r.rdtype, t) r.add(rd) return r @@ -140,7 +139,7 @@ def from_text(name, ttl, rdclass, rdtype, *text_rdatas): """Create an RRset with the specified name, TTL, class, and type and with the specified rdatas in text format. - @rtype: linkcheck.dns.rrset.RRset object + @rtype: dns.rrset.RRset object """ return from_text_list(name, ttl, rdclass, rdtype, text_rdatas) @@ -149,11 +148,11 @@ def from_rdata_list(name, ttl, rdatas): """Create an RRset with the specified name and TTL, and with the specified list of rdata objects. - @rtype: linkcheck.dns.rrset.RRset object + @rtype: dns.rrset.RRset object """ - if isinstance(name, basestring): - name = linkcheck.dns.name.from_text(name, None) + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) if len(rdatas) == 0: raise ValueError("rdata list must not be empty") @@ -170,7 +169,7 @@ def from_rdata(name, ttl, *rdatas): """Create an RRset with the specified name and TTL, and with the specified rdata objects. - @rtype: linkcheck.dns.rrset.RRset object + @rtype: dns.rrset.RRset object """ return from_rdata_list(name, ttl, rdatas) diff --git a/third_party/dnspython/dns/set.py b/third_party/dnspython/dns/set.py new file mode 100644 index 00000000..14c76a05 --- /dev/null +++ b/third_party/dnspython/dns/set.py @@ -0,0 +1,263 @@ +# Copyright (C) 2003-2007, 2009-2011 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. + +"""A simple Set class.""" + +class Set(object): + """A simple set class. + + Sets are not in Python until 2.3, and rdata are not immutable so + we cannot use sets.Set anyway. This class implements subset of + the 2.3 Set interface using a list as the container. + + @ivar items: A list of the items which are in the set + @type items: list""" + + __slots__ = ['items'] + + def __init__(self, items=None): + """Initialize the set. + + @param items: the initial set of items + @type items: any iterable or None + """ + + self.items = [] + if not items is None: + for item in items: + self.add(item) + + def __repr__(self): + return "dns.simpleset.Set(%s)" % repr(self.items) + + def add(self, item): + """Add an item to the set.""" + if not item in self.items: + self.items.append(item) + + def remove(self, item): + """Remove an item from the set.""" + self.items.remove(item) + + def discard(self, item): + """Remove an item from the set if present.""" + try: + self.items.remove(item) + except ValueError: + pass + + def _clone(self): + """Make a (shallow) copy of the set. + + There is a 'clone protocol' that subclasses of this class + should use. To make a copy, first call your super's _clone() + method, and use the object returned as the new instance. Then + make shallow copies of the attributes defined in the subclass. + + This protocol allows us to write the set algorithms that + return new instances (e.g. union) once, and keep using them in + subclasses. + """ + + cls = self.__class__ + obj = cls.__new__(cls) + obj.items = list(self.items) + return obj + + def __copy__(self): + """Make a (shallow) copy of the set.""" + return self._clone() + + def copy(self): + """Make a (shallow) copy of the set.""" + return self._clone() + + def union_update(self, other): + """Update the set, adding any elements from other which are not + already in the set. + @param other: the collection of items with which to update the set + @type other: Set object + """ + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + if self is other: + return + for item in other.items: + self.add(item) + + def intersection_update(self, other): + """Update the set, removing any elements from other which are not + in both sets. + @param other: the collection of items with which to update the set + @type other: Set object + """ + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + if self is other: + return + # we make a copy of the list so that we can remove items from + # the list without breaking the iterator. + for item in list(self.items): + if item not in other.items: + self.items.remove(item) + + def difference_update(self, other): + """Update the set, removing any elements from other which are in + the set. + @param other: the collection of items with which to update the set + @type other: Set object + """ + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + if self is other: + self.items = [] + else: + for item in other.items: + self.discard(item) + + def union(self, other): + """Return a new set which is the union of I{self} and I{other}. + + @param other: the other set + @type other: Set object + @rtype: the same type as I{self} + """ + + obj = self._clone() + obj.union_update(other) + return obj + + def intersection(self, other): + """Return a new set which is the intersection of I{self} and I{other}. + + @param other: the other set + @type other: Set object + @rtype: the same type as I{self} + """ + + obj = self._clone() + obj.intersection_update(other) + return obj + + def difference(self, other): + """Return a new set which I{self} - I{other}, i.e. the items + in I{self} which are not also in I{other}. + + @param other: the other set + @type other: Set object + @rtype: the same type as I{self} + """ + + obj = self._clone() + obj.difference_update(other) + return obj + + def __or__(self, other): + return self.union(other) + + def __and__(self, other): + return self.intersection(other) + + def __add__(self, other): + return self.union(other) + + def __sub__(self, other): + return self.difference(other) + + def __ior__(self, other): + self.union_update(other) + return self + + def __iand__(self, other): + self.intersection_update(other) + return self + + def __iadd__(self, other): + self.union_update(other) + return self + + def __isub__(self, other): + self.difference_update(other) + return self + + def update(self, other): + """Update the set, adding any elements from other which are not + already in the set. + @param other: the collection of items with which to update the set + @type other: any iterable type""" + for item in other: + self.add(item) + + def clear(self): + """Make the set empty.""" + self.items = [] + + def __eq__(self, other): + # Yes, this is inefficient but the sets we're dealing with are + # usually quite small, so it shouldn't hurt too much. + for item in self.items: + if not item in other.items: + return False + for item in other.items: + if not item in self.items: + return False + return True + + def __ne__(self, other): + return not self.__eq__(other) + + def __len__(self): + return len(self.items) + + def __iter__(self): + return iter(self.items) + + def __getitem__(self, i): + return self.items[i] + + def __delitem__(self, i): + del self.items[i] + + def __getslice__(self, i, j): + return self.items[i:j] + + def __delslice__(self, i, j): + del self.items[i:j] + + def issubset(self, other): + """Is I{self} a subset of I{other}? + + @rtype: bool + """ + + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + for item in self.items: + if not item in other.items: + return False + return True + + def issuperset(self, other): + """Is I{self} a superset of I{other}? + + @rtype: bool + """ + + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + for item in other.items: + if not item in self.items: + return False + return True diff --git a/linkcheck/dns/tokenizer.py b/third_party/dnspython/dns/tokenizer.py similarity index 82% rename from linkcheck/dns/tokenizer.py rename to third_party/dnspython/dns/tokenizer.py index 157097c1..4bff7b6c 100644 --- a/linkcheck/dns/tokenizer.py +++ b/third_party/dnspython/dns/tokenizer.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,11 +15,12 @@ """Tokenize DNS master file format""" -from cStringIO import StringIO +import cStringIO import sys -import linkcheck.dns.exception -import linkcheck.dns.name +import dns.exception +import dns.name +import dns.ttl _DELIMITERS = { ' ' : True, @@ -41,7 +41,7 @@ QUOTED_STRING = 4 COMMENT = 5 DELIMITER = 6 -class UngetBufferFull(linkcheck.dns.exception.DNSException): +class UngetBufferFull(dns.exception.DNSException): """Raised when an attempt is made to unget a token when the unget buffer is full.""" pass @@ -121,20 +121,20 @@ class Token(object): i += 1 if c == '\\': if i >= l: - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd c = self.value[i] i += 1 if c.isdigit(): if i >= l: - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd c2 = self.value[i] i += 1 if i >= l: - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd c3 = self.value[i] i += 1 if not (c2.isdigit() and c3.isdigit()): - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError c = chr(int(c) * 100 + int(c2) * 10 + int(c3)) unescaped += c return Token(self.ttype, unescaped) @@ -198,7 +198,7 @@ class Tokenizer(object): """ if isinstance(f, str): - f = StringIO(f) + f = cStringIO.StringIO(f) if filename is None: filename = '' else: @@ -290,9 +290,9 @@ class Tokenizer(object): @param want_comment: If True, return a COMMENT token if the first token read is a comment. The default is False. @type want_comment: bool - @rtype: (int, string) tuple - @raises linkcheck.dns.exception.UnexpectedEnd: input ended prematurely - @raises linkcheck.dns.exception.DNSSyntaxError: input was badly formed + @rtype: Token object + @raises dns.exception.UnexpectedEnd: input ended prematurely + @raises dns.exception.SyntaxError: input was badly formed """ if not self.ungotten_token is None: @@ -316,7 +316,7 @@ class Tokenizer(object): c = self._get_char() if c == '' or c in self.delimiters: if c == '' and self.quoting: - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd if token == '' and ttype != QUOTED_STRING: if c == '(': self.multiline += 1 @@ -324,7 +324,7 @@ class Tokenizer(object): continue elif c == ')': if not self.multiline > 0: - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError self.multiline -= 1 self.skip_whitespace() continue @@ -352,7 +352,7 @@ class Tokenizer(object): return Token(COMMENT, token) elif c == '': if self.multiline: - raise linkcheck.dns.exception.DNSSyntaxError('unbalanced parentheses') + raise dns.exception.SyntaxError('unbalanced parentheses') return Token(EOF) elif self.multiline: self.skip_whitespace() @@ -373,33 +373,33 @@ class Tokenizer(object): if c == '\\': c = self._get_char() if c == '': - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd if c.isdigit(): c2 = self._get_char() if c2 == '': - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd c3 = self._get_char() if c == '': - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd if not (c2.isdigit() and c3.isdigit()): - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError c = chr(int(c) * 100 + int(c2) * 10 + int(c3)) elif c == '\n': - raise linkcheck.dns.exception.DNSSyntaxError('newline in quoted string') + raise dns.exception.SyntaxError('newline in quoted string') elif c == '\\': - + # # It's an escape. Put it and the next character into # the token; it will be checked later for goodness. - + # token += c has_escape = True c = self._get_char() if c == '' or c == '\n': - raise linkcheck.dns.exception.UnexpectedEnd + raise dns.exception.UnexpectedEnd token += c if token == '' and ttype != QUOTED_STRING: if self.multiline: - raise linkcheck.dns.exception.DNSSyntaxError('unbalanced parentheses') + raise dns.exception.SyntaxError('unbalanced parentheses') ttype = EOF return Token(ttype, token, has_escape) @@ -437,107 +437,111 @@ class Tokenizer(object): def get_int(self): """Read the next token and interpret it as an integer. - @raises linkcheck.dns.exception.DNSSyntaxError: + @raises dns.exception.SyntaxError: @rtype: int """ token = self.get().unescape() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError('expecting an identifier') + raise dns.exception.SyntaxError('expecting an identifier') if not token.value.isdigit(): - raise linkcheck.dns.exception.DNSSyntaxError('expecting an integer') + raise dns.exception.SyntaxError('expecting an integer') return int(token.value) def get_uint8(self): """Read the next token and interpret it as an 8-bit unsigned integer. - @raises linkcheck.dns.exception.DNSSyntaxError: + @raises dns.exception.SyntaxError: @rtype: int """ value = self.get_int() if value < 0 or value > 255: - raise linkcheck.dns.exception.DNSSyntaxError('%d is not an unsigned 8-bit integer' % value) + raise dns.exception.SyntaxError('%d is not an unsigned 8-bit integer' % value) return value def get_uint16(self): """Read the next token and interpret it as a 16-bit unsigned integer. - @raises linkcheck.dns.exception.DNSSyntaxError: + @raises dns.exception.SyntaxError: @rtype: int """ value = self.get_int() if value < 0 or value > 65535: - raise linkcheck.dns.exception.DNSSyntaxError('%d is not an unsigned 16-bit integer' % value) + raise dns.exception.SyntaxError('%d is not an unsigned 16-bit integer' % value) return value def get_uint32(self): """Read the next token and interpret it as a 32-bit unsigned integer. - @raises linkcheck.dns.exception.DNSSyntaxError: + @raises dns.exception.SyntaxError: @rtype: int """ + token = self.get().unescape() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError('expecting an identifier') + raise dns.exception.SyntaxError('expecting an identifier') if not token.value.isdigit(): - raise linkcheck.dns.exception.DNSSyntaxError('expecting an integer') + raise dns.exception.SyntaxError('expecting an integer') value = long(token.value) if value < 0 or value > 4294967296L: - raise linkcheck.dns.exception.DNSSyntaxError('%d is not an unsigned 32-bit integer' % value) + raise dns.exception.SyntaxError('%d is not an unsigned 32-bit integer' % value) return value def get_string(self, origin=None): """Read the next token and interpret it as a string. - @raises linkcheck.dns.exception.DNSSyntaxError: + @raises dns.exception.SyntaxError: @rtype: string """ + token = self.get().unescape() if not (token.is_identifier() or token.is_quoted_string()): - raise linkcheck.dns.exception.DNSSyntaxError('expecting a string') + raise dns.exception.SyntaxError('expecting a string') return token.value def get_identifier(self, origin=None): """Read the next token and raise an exception if it is not an identifier. - @raises linkcheck.dns.exception.DNSSyntaxError: + @raises dns.exception.SyntaxError: @rtype: string """ + token = self.get().unescape() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError('expecting an identifier') + raise dns.exception.SyntaxError('expecting an identifier') return token.value def get_name(self, origin=None): """Read the next token and interpret it as a DNS name. - @raises linkcheck.dns.exception.DNSSyntaxError: - @rtype: linkcheck.dns.name.Name object""" + @raises dns.exception.SyntaxError: + @rtype: dns.name.Name object""" + token = self.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError('expecting an identifier') - return linkcheck.dns.name.from_text(token.value, origin) + raise dns.exception.SyntaxError('expecting an identifier') + return dns.name.from_text(token.value, origin) def get_eol(self): """Read the next token and raise an exception if it isn't EOL or EOF. - @raises linkcheck.dns.exception.DNSSyntaxError: + @raises dns.exception.SyntaxError: @rtype: string """ token = self.get() if not token.is_eol_or_eof(): - raise linkcheck.dns.exception.DNSSyntaxError('expected EOL or EOF, got %d "%s"' % (token.ttype, token.value)) + raise dns.exception.SyntaxError('expected EOL or EOF, got %d "%s"' % (token.ttype, token.value)) return token.value def get_ttl(self): token = self.get().unescape() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError('expecting an identifier') - return linkcheck.dns.ttl.from_text(token.value) + raise dns.exception.SyntaxError('expecting an identifier') + return dns.ttl.from_text(token.value) diff --git a/linkcheck/dns/tsig.py b/third_party/dnspython/dns/tsig.py similarity index 80% rename from linkcheck/dns/tsig.py rename to third_party/dnspython/dns/tsig.py index 420c4bf2..63b925af 100644 --- a/linkcheck/dns/tsig.py +++ b/third_party/dnspython/dns/tsig.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -18,20 +17,22 @@ import hmac import struct +import sys -import linkcheck.dns.exception -import linkcheck.dns.rdataclass -import linkcheck.dns.name +import dns.exception +import dns.hash +import dns.rdataclass +import dns.name -class BadTime(linkcheck.dns.exception.DNSException): +class BadTime(dns.exception.DNSException): """Raised if the current time is not within the TSIG's validity time.""" pass -class BadSignature(linkcheck.dns.exception.DNSException): +class BadSignature(dns.exception.DNSException): """Raised if the TSIG signature fails to verify.""" pass -class PeerError(linkcheck.dns.exception.DNSException): +class PeerError(dns.exception.DNSException): """Base class for all TSIG errors generated by the remote peer""" pass @@ -53,12 +54,12 @@ class PeerBadTruncation(PeerError): # TSIG Algorithms -HMAC_MD5 = linkcheck.dns.name.from_text("HMAC-MD5.SIG-ALG.REG.INT") -HMAC_SHA1 = linkcheck.dns.name.from_text("hmac-sha1") -HMAC_SHA224 = linkcheck.dns.name.from_text("hmac-sha224") -HMAC_SHA256 = linkcheck.dns.name.from_text("hmac-sha256") -HMAC_SHA384 = linkcheck.dns.name.from_text("hmac-sha384") -HMAC_SHA512 = linkcheck.dns.name.from_text("hmac-sha512") +HMAC_MD5 = dns.name.from_text("HMAC-MD5.SIG-ALG.REG.INT") +HMAC_SHA1 = dns.name.from_text("hmac-sha1") +HMAC_SHA224 = dns.name.from_text("hmac-sha224") +HMAC_SHA256 = dns.name.from_text("hmac-sha256") +HMAC_SHA384 = dns.name.from_text("hmac-sha384") +HMAC_SHA512 = dns.name.from_text("hmac-sha512") default_algorithm = HMAC_MD5 @@ -90,7 +91,7 @@ def sign(wire, keyname, secret, time, fudge, original_id, error, ctx.update(wire[2:]) if first: ctx.update(keyname.to_digestable()) - ctx.update(struct.pack('!H', linkcheck.dns.rdataclass.ANY)) + ctx.update(struct.pack('!H', dns.rdataclass.ANY)) ctx.update(struct.pack('!I', 0)) long_time = time + 0L upper_time = (long_time >> 32) & 0xffffL @@ -136,11 +137,11 @@ def validate(wire, keyname, secret, now, request_mac, tsig_start, tsig_rdata, (adcount,) = struct.unpack("!H", wire[10:12]) if adcount == 0: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError adcount -= 1 new_wire = wire[0:10] + struct.pack("!H", adcount) + wire[12:tsig_start] current = tsig_rdata - (aname, used) = linkcheck.dns.name.from_wire(wire, current) + (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]) @@ -154,7 +155,7 @@ def validate(wire, keyname, secret, now, request_mac, tsig_start, tsig_rdata, other_data = wire[current:current + other_size] current += other_size if current != tsig_rdata + tsig_rdlen: - raise linkcheck.dns.exception.FormError + raise dns.exception.FormError if error != 0: if error == BADSIG: raise PeerBadSignature @@ -179,22 +180,21 @@ def validate(wire, keyname, secret, now, request_mac, tsig_start, tsig_rdata, _hashes = None +def _maybe_add_hash(tsig_alg, hash_alg): + try: + _hashes[tsig_alg] = dns.hash.get(hash_alg) + except KeyError: + pass + def _setup_hashes(): global _hashes _hashes = {} - try: - import hashlib - _hashes[HMAC_SHA224] = hashlib.sha224 - _hashes[HMAC_SHA256] = hashlib.sha256 - _hashes[HMAC_SHA384] = hashlib.sha384 - _hashes[HMAC_SHA512] = hashlib.sha512 - _hashes[HMAC_SHA1] = hashlib.sha1 - _hashes[HMAC_MD5] = hashlib.md5 - - except ImportError: - import md5, sha - _hashes[HMAC_MD5] = md5 - _hashes[HMAC_SHA1] = sha + _maybe_add_hash(HMAC_SHA224, 'SHA224') + _maybe_add_hash(HMAC_SHA256, 'SHA256') + _maybe_add_hash(HMAC_SHA384, 'SHA384') + _maybe_add_hash(HMAC_SHA512, 'SHA512') + _maybe_add_hash(HMAC_SHA1, 'SHA1') + _maybe_add_hash(HMAC_MD5, 'MD5') def get_algorithm(algorithm): """Returns the wire format string and the hash module to use for the @@ -208,8 +208,13 @@ def get_algorithm(algorithm): if _hashes is None: _setup_hashes() - if isinstance(algorithm, basestring): - algorithm = linkcheck.dns.name.from_text(algorithm) + if isinstance(algorithm, (str, unicode)): + algorithm = dns.name.from_text(algorithm) + + if sys.hexversion < 0x02050200 and \ + (algorithm == HMAC_SHA384 or algorithm == HMAC_SHA512): + raise NotImplementedError("TSIG algorithm " + str(algorithm) + + " requires Python 2.5.2 or later") try: return (algorithm.to_digestable(), _hashes[algorithm]) diff --git a/linkcheck/dns/tsigkeyring.py b/third_party/dnspython/dns/tsigkeyring.py similarity index 77% rename from linkcheck/dns/tsigkeyring.py rename to third_party/dnspython/dns/tsigkeyring.py index cd2a0a81..0ddd9341 100644 --- a/linkcheck/dns/tsigkeyring.py +++ b/third_party/dnspython/dns/tsigkeyring.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -18,28 +17,28 @@ import base64 -import linkcheck.dns.name +import dns.name def from_text(textring): """Convert a dictionary containing (textual DNS name, base64 secret) pairs - into a binary keyring which has (linkcheck.dns.name.Name, binary secret) pairs. + into a binary keyring which has (dns.name.Name, binary secret) pairs. @rtype: dict""" - + keyring = {} for keytext in textring: - keyname = linkcheck.dns.name.from_text(keytext) + keyname = dns.name.from_text(keytext) secret = base64.decodestring(textring[keytext]) keyring[keyname] = secret return keyring def to_text(keyring): - """Convert a dictionary containing (linkcheck.dns.name.Name, binary secret) pairs + """Convert a dictionary containing (dns.name.Name, binary secret) pairs into a text keyring which has (textual DNS name, base64 secret) pairs. @rtype: dict""" - + textring = {} for keyname in keyring: - keytext = linkcheck.dns.name.to_text(keyname) + keytext = dns.name.to_text(keyname) secret = base64.encodestring(keyring[keyname]) textring[keytext] = secret return textring diff --git a/linkcheck/dns/ttl.py b/third_party/dnspython/dns/ttl.py similarity index 89% rename from linkcheck/dns/ttl.py rename to third_party/dnspython/dns/ttl.py index 355c982d..ab6ddf4e 100644 --- a/linkcheck/dns/ttl.py +++ b/third_party/dnspython/dns/ttl.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,9 +15,9 @@ """DNS TTL conversion.""" -import linkcheck.dns.exception +import dns.exception -class BadTTL(linkcheck.dns.exception.DNSSyntaxError): +class BadTTL(dns.exception.SyntaxError): pass def from_text(text): @@ -28,7 +27,7 @@ def from_text(text): @param text: the textual TTL @type text: string - @raises linkcheck.dns.ttl.BadTTL: the TTL is not well-formed + @raises dns.ttl.BadTTL: the TTL is not well-formed @rtype: int """ diff --git a/linkcheck/dns/update.py b/third_party/dnspython/dns/update.py similarity index 63% rename from linkcheck/dns/update.py rename to third_party/dnspython/dns/update.py index ad930b64..e6922269 100644 --- a/linkcheck/dns/update.py +++ b/third_party/dnspython/dns/update.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,22 +15,22 @@ """DNS Dynamic Update Support""" -import linkcheck.dns.message -import linkcheck.dns.name -import linkcheck.dns.opcode -import linkcheck.dns.rdata -import linkcheck.dns.rdataclass -import linkcheck.dns.rdataset -import linkcheck.dns.tsig +import dns.message +import dns.name +import dns.opcode +import dns.rdata +import dns.rdataclass +import dns.rdataset +import dns.tsig -class Update(linkcheck.dns.message.Message): - def __init__(self, zone, rdclass=linkcheck.dns.rdataclass.IN, keyring=None, - keyname=None, keyalgorithm=linkcheck.dns.tsig.default_algorithm): +class Update(dns.message.Message): + def __init__(self, zone, rdclass=dns.rdataclass.IN, keyring=None, + keyname=None, keyalgorithm=dns.tsig.default_algorithm): """Initialize a new DNS Update object. @param zone: The zone which is being updated. - @type zone: A linkcheck.dns.name.Name or string - @param rdclass: The class of the zone; defaults to linkcheck.dns.rdataclass.IN. + @type zone: A dns.name.Name or string + @param rdclass: The class of the zone; defaults to dns.rdataclass.IN. @type rdclass: An int designating the class, or a string whose value is the name of a class. @param keyring: The TSIG keyring to use; defaults to None. @@ -42,23 +41,23 @@ class Update(linkcheck.dns.message.Message): keyring. Note that the order of keys in a dictionary is not defined, so applications should supply a keyname when a keyring is used, unless they know the keyring contains only one key. - @type keyname: linkcheck.dns.name.Name or string + @type keyname: dns.name.Name or string @param keyalgorithm: The TSIG algorithm to use; defaults to - linkcheck.dns.tsig.default_algorithm. Constants for TSIG algorithms are defined - in linkcheck.dns.tsig, and the currently implemented algorithms are + dns.tsig.default_algorithm. Constants for TSIG algorithms are defined + in dns.tsig, and the currently implemented algorithms are HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, and HMAC_SHA512. @type keyalgorithm: string """ super(Update, self).__init__() - self.flags |= linkcheck.dns.opcode.to_flags(linkcheck.dns.opcode.UPDATE) - if isinstance(zone, basestring): - zone = linkcheck.dns.name.from_text(zone) + self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE) + if isinstance(zone, (str, unicode)): + zone = dns.name.from_text(zone) self.origin = zone if isinstance(rdclass, str): - rdclass = linkcheck.dns.rdataclass.from_text(rdclass) + rdclass = dns.rdataclass.from_text(rdclass) self.zone_rdclass = rdclass - self.find_rrset(self.question, self.origin, rdclass, linkcheck.dns.rdatatype.SOA, + self.find_rrset(self.question, self.origin, rdclass, dns.rdatatype.SOA, create=True, force_unique=True) if not keyring is None: self.use_tsig(keyring, keyname, algorithm=keyalgorithm) @@ -86,9 +85,9 @@ class Update(linkcheck.dns.message.Message): - ttl, rdtype, string...""" - if isinstance(name, basestring): - name = linkcheck.dns.name.from_text(name, None) - if isinstance(args[0], linkcheck.dns.rdataset.Rdataset): + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + if isinstance(args[0], dns.rdataset.Rdataset): for rds in args: if replace: self.delete(name, rds.rdtype) @@ -97,19 +96,19 @@ class Update(linkcheck.dns.message.Message): else: args = list(args) ttl = int(args.pop(0)) - if isinstance(args[0], linkcheck.dns.rdata.Rdata): + if isinstance(args[0], dns.rdata.Rdata): if replace: self.delete(name, args[0].rdtype) for rd in args: self._add_rr(name, ttl, rd, section=section) else: rdtype = args.pop(0) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) if replace: self.delete(name, rdtype) for s in args: - rd = linkcheck.dns.rdata.from_text(self.zone_rdclass, rdtype, s, + rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, self.origin) self._add_rr(name, ttl, rd, section=section) @@ -136,36 +135,36 @@ class Update(linkcheck.dns.message.Message): - rdtype, [string...]""" - if isinstance(name, basestring): - name = linkcheck.dns.name.from_text(name, None) + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) if len(args) == 0: - rrset = self.find_rrset(self.authority, name, linkcheck.dns.rdataclass.ANY, - linkcheck.dns.rdatatype.ANY, linkcheck.dns.rdatatype.NONE, - linkcheck.dns.rdatatype.ANY, True, True) - elif isinstance(args[0], linkcheck.dns.rdataset.Rdataset): + rrset = self.find_rrset(self.authority, name, dns.rdataclass.ANY, + dns.rdatatype.ANY, dns.rdatatype.NONE, + dns.rdatatype.ANY, True, True) + elif isinstance(args[0], dns.rdataset.Rdataset): for rds in args: for rd in rds: - self._add_rr(name, 0, rd, linkcheck.dns.rdataclass.NONE) + self._add_rr(name, 0, rd, dns.rdataclass.NONE) else: args = list(args) - if isinstance(args[0], linkcheck.dns.rdata.Rdata): + if isinstance(args[0], dns.rdata.Rdata): for rd in args: - self._add_rr(name, 0, rd, linkcheck.dns.rdataclass.NONE) + self._add_rr(name, 0, rd, dns.rdataclass.NONE) else: rdtype = args.pop(0) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) if len(args) == 0: rrset = self.find_rrset(self.authority, name, self.zone_rdclass, rdtype, - linkcheck.dns.rdatatype.NONE, - linkcheck.dns.rdataclass.ANY, + dns.rdatatype.NONE, + dns.rdataclass.ANY, True, True) else: for s in args: - rd = linkcheck.dns.rdata.from_text(self.zone_rdclass, rdtype, s, + rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, self.origin) - self._add_rr(name, 0, rd, linkcheck.dns.rdataclass.NONE) + self._add_rr(name, 0, rd, dns.rdataclass.NONE) def replace(self, name, *args): """Replace records. The first argument is always a name. The other @@ -194,47 +193,47 @@ class Update(linkcheck.dns.message.Message): - rdtype, string...""" - if isinstance(name, basestring): - name = linkcheck.dns.name.from_text(name, None) + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) if len(args) == 0: rrset = self.find_rrset(self.answer, name, - linkcheck.dns.rdataclass.ANY, linkcheck.dns.rdatatype.ANY, - linkcheck.dns.rdatatype.NONE, None, + dns.rdataclass.ANY, dns.rdatatype.ANY, + dns.rdatatype.NONE, None, True, True) - elif isinstance(args[0], linkcheck.dns.rdataset.Rdataset) or \ - isinstance(args[0], linkcheck.dns.rdata.Rdata) or \ + elif isinstance(args[0], dns.rdataset.Rdataset) or \ + isinstance(args[0], dns.rdata.Rdata) or \ len(args) > 1: - if len(args) > 1: + if not isinstance(args[0], dns.rdataset.Rdataset): # Add a 0 TTL args = list(args) args.insert(0, 0) self._add(False, self.answer, name, *args) else: rdtype = args[0] - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) rrset = self.find_rrset(self.answer, name, - linkcheck.dns.rdataclass.ANY, rdtype, - linkcheck.dns.rdatatype.NONE, None, + dns.rdataclass.ANY, rdtype, + dns.rdatatype.NONE, None, True, True) def absent(self, name, rdtype=None): """Require that an owner name (and optionally an rdata type) does not exist as a prerequisite to the execution of the update.""" - if isinstance(name, basestring): - name = linkcheck.dns.name.from_text(name, None) + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) if rdtype is None: rrset = self.find_rrset(self.answer, name, - linkcheck.dns.rdataclass.NONE, linkcheck.dns.rdatatype.ANY, - linkcheck.dns.rdatatype.NONE, None, + dns.rdataclass.NONE, dns.rdatatype.ANY, + dns.rdatatype.NONE, None, True, True) else: - if isinstance(rdtype, str): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) rrset = self.find_rrset(self.answer, name, - linkcheck.dns.rdataclass.NONE, rdtype, - linkcheck.dns.rdatatype.NONE, None, + dns.rdataclass.NONE, rdtype, + dns.rdatatype.NONE, None, True, True) def to_wire(self, origin=None, max_size=65535): diff --git a/linkcheck/dns/version.py b/third_party/dnspython/dns/version.py similarity index 92% rename from linkcheck/dns/version.py rename to third_party/dnspython/dns/version.py index 01140583..6539cfcf 100644 --- a/linkcheck/dns/version.py +++ b/third_party/dnspython/dns/version.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -17,8 +16,8 @@ """dnspython release version information.""" MAJOR = 1 -MINOR = 8 -MICRO = 1 +MINOR = 9 +MICRO = 5 RELEASELEVEL = 0x0f SERIAL = 0 diff --git a/third_party/dnspython/dns/wiredata.py b/third_party/dnspython/dns/wiredata.py new file mode 100644 index 00000000..86d954a9 --- /dev/null +++ b/third_party/dnspython/dns/wiredata.py @@ -0,0 +1,59 @@ +# Copyright (C) 2011 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. + +"""DNS Wire Data Helper""" + +import sys + +import dns.exception + +class WireData(str): + # WireData is a string with stricter slicing + def __getitem__(self, key): + try: + return WireData(super(WireData, self).__getitem__(key)) + except IndexError: + raise dns.exception.FormError + def __getslice__(self, i, j): + try: + if j == sys.maxint: + # 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 + def __iter__(self): + i = 0 + while 1: + try: + yield self[i] + i += 1 + except dns.exception.FormError: + raise StopIteration + def unwrap(self): + return str(self) + +def maybe_wrap(wire): + if not isinstance(wire, WireData): + return WireData(wire) + else: + return wire diff --git a/linkcheck/dns/zone.py b/third_party/dnspython/dns/zone.py similarity index 77% rename from linkcheck/dns/zone.py rename to third_party/dnspython/dns/zone.py index f6b2ba05..4cb7233b 100644 --- a/linkcheck/dns/zone.py +++ b/third_party/dnspython/dns/zone.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,18 +15,21 @@ """DNS Zones.""" +from __future__ import generators + import sys -import linkcheck.dns.exception -import linkcheck.dns.name -import linkcheck.dns.node -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype -import linkcheck.dns.rdata -import linkcheck.dns.tokenizer -import linkcheck.dns.ttl +import dns.exception +import dns.name +import dns.node +import dns.rdataclass +import dns.rdatatype +import dns.rdata +import dns.rrset +import dns.tokenizer +import dns.ttl -class BadZone(linkcheck.dns.exception.DNSException): +class BadZone(dns.exception.DNSException): """The zone is malformed.""" pass @@ -49,14 +51,14 @@ class Zone(object): A Zone is a mapping from names to nodes. The zone object may be treated like a Python dictionary, e.g. zone[name] will retrieve the node associated with that name. The I{name} may be a - linkcheck.dns.name.Name object, or it may be a string. In the either case, + dns.name.Name object, or it may be a string. In the either case, if the name is relative it is treated as relative to the origin of the zone. @ivar rdclass: The zone's rdata class; the default is class IN. @type rdclass: int @ivar origin: The origin of the zone. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @ivar nodes: A dictionary mapping the names of nodes in the zone to the nodes themselves. @type nodes: dict @@ -66,15 +68,15 @@ class Zone(object): @type node_factory: class or callable """ - node_factory = linkcheck.dns.node.Node + node_factory = dns.node.Node __slots__ = ['rdclass', 'origin', 'nodes', 'relativize'] - def __init__(self, origin, rdclass=linkcheck.dns.rdataclass.IN, relativize=True): + def __init__(self, origin, rdclass=dns.rdataclass.IN, relativize=True): """Initialize a zone object. @param origin: The origin of the zone. - @type origin: linkcheck.dns.name.Name object + @type origin: dns.name.Name object @param rdclass: The zone's rdata class; the default is class IN. @type rdclass: int""" @@ -105,9 +107,9 @@ class Zone(object): return not self.__eq__(other) def _validate_name(self, name): - if isinstance(name, basestring): - name = linkcheck.dns.name.from_text(name, None) - elif not isinstance(name, linkcheck.dns.name.Name): + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + elif not isinstance(name, dns.name.Name): raise KeyError("name parameter must be convertable to a DNS name") if name.is_absolute(): if not name.is_subdomain(self.origin): @@ -160,11 +162,11 @@ class Zone(object): """Find a node in the zone, possibly creating it. @param name: the name of the node to find - @type name: linkcheck.dns.name.Name object or string + @type name: dns.name.Name object or string @param create: should the node be created if it doesn't exist? @type create: bool @raises KeyError: the name is not known and create was not specified. - @rtype linkcheck.dns.node.Node object + @rtype: dns.node.Node object """ name = self._validate_name(name) @@ -184,10 +186,10 @@ class Zone(object): has not been requested. @param name: the name of the node to find - @type name: linkcheck.dns.name.Name object or string + @type name: dns.name.Name object or string @param create: should the node be created if it doesn't exist? @type create: bool - @rtype linkcheck.dns.node.Node object or None + @rtype: dns.node.Node object or None """ try: @@ -206,7 +208,7 @@ class Zone(object): if name in self.nodes: del self.nodes[name] - def find_rdataset(self, name, rdtype, covers=linkcheck.dns.rdatatype.NONE, + def find_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE, create=False): """Look for rdata with the specified name and type in the zone, and return an rdataset encapsulating it. @@ -231,18 +233,18 @@ class Zone(object): exist? @type create: bool @raises KeyError: the node or rdata could not be found - @rtype: linkcheck.dns.rrset.RRset object + @rtype: dns.rrset.RRset object """ name = self._validate_name(name) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) - if isinstance(covers, basestring): - covers = linkcheck.dns.rdatatype.from_text(covers) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, (str, unicode)): + covers = dns.rdatatype.from_text(covers) node = self.find_node(name, create) return node.find_rdataset(self.rdclass, rdtype, covers, create) - def get_rdataset(self, name, rdtype, covers=linkcheck.dns.rdatatype.NONE, + def get_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE, create=False): """Look for rdata with the specified name and type in the zone, and return an rdataset encapsulating it. @@ -266,7 +268,7 @@ class Zone(object): @param create: should the node and rdataset be created if they do not exist? @type create: bool - @rtype: linkcheck.dns.rrset.RRset object + @rtype: dns.rrset.RRset object """ try: @@ -275,7 +277,7 @@ class Zone(object): rdataset = None return rdataset - def delete_rdataset(self, name, rdtype, covers=linkcheck.dns.rdatatype.NONE): + def delete_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE): """Delete the rdataset matching I{rdtype} and I{covers}, if it exists at the node specified by I{name}. @@ -298,10 +300,10 @@ class Zone(object): """ name = self._validate_name(name) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) - if isinstance(covers, basestring): - covers = linkcheck.dns.rdatatype.from_text(covers) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, (str, unicode)): + covers = dns.rdatatype.from_text(covers) node = self.get_node(name) if not node is None: node.delete_rdataset(self.rdclass, rdtype, covers) @@ -322,15 +324,15 @@ class Zone(object): @param name: the owner name @type name: DNS.name.Name object or string @param replacement: the replacement rdataset - @type replacement: linkcheck.dns.rdataset.Rdataset + @type replacement: dns.rdataset.Rdataset """ if replacement.rdclass != self.rdclass: - raise ValueError, 'replacement.rdclass != zone.rdclass' + raise ValueError('replacement.rdclass != zone.rdclass') node = self.find_node(name, True) node.replace_rdataset(replacement) - def find_rrset(self, name, rdtype, covers=linkcheck.dns.rdatatype.NONE): + def find_rrset(self, name, rdtype, covers=dns.rdatatype.NONE): """Look for rdata with the specified name and type in the zone, and return an RRset encapsulating it. @@ -357,20 +359,20 @@ class Zone(object): @param covers: the covered type (defaults to None) @type covers: int or string @raises KeyError: the node or rdata could not be found - @rtype: linkcheck.dns.rrset.RRset object + @rtype: dns.rrset.RRset object """ name = self._validate_name(name) - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) - if isinstance(covers, basestring): - covers = linkcheck.dns.rdatatype.from_text(covers) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, (str, unicode)): + covers = dns.rdatatype.from_text(covers) rdataset = self.nodes[name].find_rdataset(self.rdclass, rdtype, covers) - rrset = linkcheck.dns.rrset.RRset(name, self.rdclass, rdtype, covers) + rrset = dns.rrset.RRset(name, self.rdclass, rdtype, covers) rrset.update(rdataset) return rrset - def get_rrset(self, name, rdtype, covers=linkcheck.dns.rdatatype.NONE): + def get_rrset(self, name, rdtype, covers=dns.rdatatype.NONE): """Look for rdata with the specified name and type in the zone, and return an RRset encapsulating it. @@ -395,7 +397,7 @@ class Zone(object): @type rdtype: int or string @param covers: the covered type (defaults to None) @type covers: int or string - @rtype: linkcheck.dns.rrset.RRset object + @rtype: dns.rrset.RRset object """ try: @@ -404,11 +406,11 @@ class Zone(object): rrset = None return rrset - def iterate_rdatasets(self, rdtype=linkcheck.dns.rdatatype.ANY, - covers=linkcheck.dns.rdatatype.NONE): + def iterate_rdatasets(self, rdtype=dns.rdatatype.ANY, + covers=dns.rdatatype.NONE): """Return a generator which yields (name, rdataset) tuples for all rdatasets in the zone which have the specified I{rdtype} - and I{covers}. If I{rdtype} is linkcheck.dns.rdatatype.ANY, the default, + and I{covers}. If I{rdtype} is dns.rdatatype.ANY, the default, then all rdatasets will be matched. @param rdtype: int or string @@ -417,21 +419,21 @@ class Zone(object): @type covers: int or string """ - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) - if isinstance(covers, basestring): - covers = linkcheck.dns.rdatatype.from_text(covers) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, (str, unicode)): + covers = dns.rdatatype.from_text(covers) for (name, node) in self.iteritems(): for rds in node: - if rdtype == linkcheck.dns.rdatatype.ANY or \ + if rdtype == dns.rdatatype.ANY or \ (rds.rdtype == rdtype and rds.covers == covers): yield (name, rds) - def iterate_rdatas(self, rdtype=linkcheck.dns.rdatatype.ANY, - covers=linkcheck.dns.rdatatype.NONE): + def iterate_rdatas(self, rdtype=dns.rdatatype.ANY, + covers=dns.rdatatype.NONE): """Return a generator which yields (name, ttl, rdata) tuples for all rdatas in the zone which have the specified I{rdtype} - and I{covers}. If I{rdtype} is linkcheck.dns.rdatatype.ANY, the default, + and I{covers}. If I{rdtype} is dns.rdatatype.ANY, the default, then all rdatas will be matched. @param rdtype: int or string @@ -440,13 +442,13 @@ class Zone(object): @type covers: int or string """ - if isinstance(rdtype, basestring): - rdtype = linkcheck.dns.rdatatype.from_text(rdtype) - if isinstance(covers, basestring): - covers = linkcheck.dns.rdatatype.from_text(covers) + if isinstance(rdtype, (str, unicode)): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, (str, unicode)): + covers = dns.rdatatype.from_text(covers) for (name, node) in self.iteritems(): for rds in node: - if rdtype == linkcheck.dns.rdatatype.ANY or \ + if rdtype == dns.rdatatype.ANY or \ (rds.rdtype == rdtype and rds.covers == covers): for rdata in rds: yield (name, rds.ttl, rdata) @@ -469,11 +471,16 @@ class Zone(object): @type nl: string or None """ + if sys.hexversion >= 0x02030000: + # allow Unicode filenames + str_type = basestring + else: + str_type = str if nl is None: opts = 'w' else: opts = 'wb' - if isinstance(f, basestring): + if isinstance(f, str_type): f = file(f, opts) want_close = True else: @@ -499,17 +506,17 @@ class Zone(object): def check_origin(self): """Do some simple checking of the zone's origin. - @raises linkcheck.dns.zone.NoSOA: there is no SOA RR - @raises linkcheck.dns.zone.NoNS: there is no NS RRset + @raises dns.zone.NoSOA: there is no SOA RR + @raises dns.zone.NoNS: there is no NS RRset @raises KeyError: there is no origin node """ if self.relativize: - name = linkcheck.dns.name.empty + name = dns.name.empty else: name = self.origin - if self.get_rdataset(name, linkcheck.dns.rdatatype.SOA) is None: + if self.get_rdataset(name, dns.rdatatype.SOA) is None: raise NoSOA - if self.get_rdataset(name, linkcheck.dns.rdatatype.NS) is None: + if self.get_rdataset(name, dns.rdatatype.NS) is None: raise NoNS @@ -517,17 +524,17 @@ class _MasterReader(object): """Read a DNS master file @ivar tok: The tokenizer - @type tok: linkcheck.dns.tokenizer.Tokenizer object + @type tok: dns.tokenizer.Tokenizer object @ivar ttl: The default TTL @type ttl: int @ivar last_name: The last name read - @type last_name: linkcheck.dns.name.Name object + @type last_name: dns.name.Name object @ivar current_origin: The current origin - @type current_origin: linkcheck.dns.name.Name object + @type current_origin: dns.name.Name object @ivar relativize: should names in the zone be relativized? @type relativize: bool @ivar zone: the zone - @type zone: linkcheck.dns.zone.Zone object + @type zone: dns.zone.Zone object @ivar saved_state: saved reader state (used when processing $INCLUDE) @type saved_state: list of (tokenizer, current_origin, last_name, file) tuples. @@ -542,8 +549,8 @@ class _MasterReader(object): def __init__(self, tok, origin, rdclass, relativize, zone_factory=Zone, allow_include=False, check_origin=True): - if isinstance(origin, basestring): - origin = linkcheck.dns.name.from_text(origin) + if isinstance(origin, (str, unicode)): + origin = dns.name.from_text(origin) self.tok = tok self.current_origin = origin self.relativize = relativize @@ -568,7 +575,7 @@ class _MasterReader(object): raise UnknownOrigin token = self.tok.get(want_leading = True) if not token.is_whitespace(): - self.last_name = linkcheck.dns.name.from_text(token.value, self.current_origin) + self.last_name = dns.name.from_text(token.value, self.current_origin) else: token = self.tok.get() if token.is_eol_or_eof(): @@ -583,40 +590,40 @@ class _MasterReader(object): name = name.relativize(self.zone.origin) token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError + raise dns.exception.SyntaxError # TTL try: - ttl = linkcheck.dns.ttl.from_text(token.value) + ttl = dns.ttl.from_text(token.value) token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError - except linkcheck.dns.ttl.BadTTL: + raise dns.exception.SyntaxError + except dns.ttl.BadTTL: ttl = self.ttl # Class try: - rdclass = linkcheck.dns.rdataclass.from_text(token.value) + rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError - except linkcheck.dns.exception.DNSSyntaxError: + raise dns.exception.SyntaxError + except dns.exception.SyntaxError: raise except StandardError: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: - raise linkcheck.dns.exception.DNSSyntaxError("RR class is not zone's class") + raise dns.exception.SyntaxError("RR class is not zone's class") # Type try: - rdtype = linkcheck.dns.rdatatype.from_text(token.value) + rdtype = dns.rdatatype.from_text(token.value) except StandardError: - raise linkcheck.dns.exception.DNSSyntaxError("unknown rdatatype '%s'" % token.value) + raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: - rd = linkcheck.dns.rdata.from_text(rdclass, rdtype, self.tok, + rd = dns.rdata.from_text(rdclass, rdtype, self.tok, self.current_origin, False) - except linkcheck.dns.exception.DNSSyntaxError: + except dns.exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va @@ -626,9 +633,8 @@ class _MasterReader(object): # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. - (ty, va) = sys.exc_info()[:2] - raise linkcheck.dns.exception.DNSSyntaxError("caught exception %s: %s" % (str(ty), str(va))) + raise dns.exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) rd.choose_relativity(self.zone.origin, self.relativize) covers = rd.covers() @@ -638,8 +644,8 @@ class _MasterReader(object): def read(self): """Read a DNS master file and build a zone object. - @raises linkcheck.dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises linkcheck.dns.zone.NoNS: No NS RRset was found at the zone origin + @raises dns.zone.NoSOA: No SOA RR was found at the zone origin + @raises dns.zone.NoNS: No NS RRset was found at the zone origin """ try: @@ -666,8 +672,8 @@ class _MasterReader(object): if u == '$TTL': token = self.tok.get() if not token.is_identifier(): - raise linkcheck.dns.exception.DNSSyntaxError("bad $TTL") - self.ttl = linkcheck.dns.ttl.from_text(token.value) + raise dns.exception.SyntaxError("bad $TTL") + self.ttl = dns.ttl.from_text(token.value) self.tok.get_eol() elif u == '$ORIGIN': self.current_origin = self.tok.get_name() @@ -677,15 +683,15 @@ class _MasterReader(object): elif u == '$INCLUDE' and self.allow_include: token = self.tok.get() if not token.is_quoted_string(): - raise linkcheck.dns.exception.DNSSyntaxError("bad filename in $INCLUDE") + raise dns.exception.SyntaxError("bad filename in $INCLUDE") filename = token.value token = self.tok.get() if token.is_identifier(): - new_origin = linkcheck.dns.name.from_text(token.value, \ - self.current_origin) + new_origin = dns.name.from_text(token.value, \ + self.current_origin) self.tok.get_eol() elif not token.is_eol_or_eof(): - raise linkcheck.dns.exception.DNSSyntaxError("bad origin in $INCLUDE") + raise dns.exception.SyntaxError("bad origin in $INCLUDE") else: new_origin = self.current_origin self.saved_state.append((self.tok, @@ -694,26 +700,25 @@ class _MasterReader(object): self.current_file, self.ttl)) self.current_file = file(filename, 'r') - self.tok = linkcheck.dns.tokenizer.Tokenizer(self.current_file, + self.tok = dns.tokenizer.Tokenizer(self.current_file, filename) self.current_origin = new_origin else: - raise linkcheck.dns.exception.DNSSyntaxError("Unknown master file directive '" + u + "'") + raise dns.exception.SyntaxError("Unknown master file directive '" + u + "'") continue self.tok.unget(token) self._rr_line() - except linkcheck.dns.exception.DNSSyntaxError, detail: + except dns.exception.SyntaxError, detail: (filename, line_number) = self.tok.where() if detail is None: detail = "syntax error" - raise linkcheck.dns.exception.DNSSyntaxError, \ - "%s:%d: %s" % (filename, line_number, detail) + raise dns.exception.SyntaxError("%s:%d: %s" % (filename, line_number, detail)) # Now that we're done reading, do some basic checking of the zone. if self.check_origin: self.zone.check_origin() -def from_text(text, origin, rdclass = linkcheck.dns.rdataclass.IN, +def from_text(text, origin = None, rdclass = dns.rdataclass.IN, relativize = True, zone_factory=Zone, filename=None, allow_include=False, check_origin=True): """Build a zone object from a master file format string. @@ -723,7 +728,7 @@ def from_text(text, origin, rdclass = linkcheck.dns.rdataclass.IN, @param origin: The origin of the zone; if not specified, the first $ORIGIN statement in the master file will determine the origin of the zone. - @type origin: linkcheck.dns.name.Name object or string + @type origin: dns.name.Name object or string @param rdclass: The zone's rdata class; the default is class IN. @type rdclass: int @param relativize: should names be relativized? The default is True @@ -738,9 +743,9 @@ def from_text(text, origin, rdclass = linkcheck.dns.rdataclass.IN, @param check_origin: should sanity checks of the origin node be done? The default is True. @type check_origin: bool - @raises linkcheck.dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises linkcheck.dns.zone.NoNS: No NS RRset was found at the zone origin - @rtype: linkcheck.dns.zone.Zone object + @raises dns.zone.NoSOA: No SOA RR was found at the zone origin + @raises dns.zone.NoNS: No NS RRset was found at the zone origin + @rtype: dns.zone.Zone object """ # 'text' can also be a file, but we don't publish that fact @@ -749,15 +754,15 @@ def from_text(text, origin, rdclass = linkcheck.dns.rdataclass.IN, if filename is None: filename = '' - tok = linkcheck.dns.tokenizer.Tokenizer(text, filename) + tok = dns.tokenizer.Tokenizer(text, filename) reader = _MasterReader(tok, origin, rdclass, relativize, zone_factory, allow_include=allow_include, check_origin=check_origin) reader.read() return reader.zone -def from_file(f, origin, rdclass = linkcheck.dns.rdataclass.IN, relativize = True, - zone_factory=Zone, filename=None, +def from_file(f, origin = None, rdclass = dns.rdataclass.IN, + relativize = True, zone_factory=Zone, filename=None, allow_include=True, check_origin=True): """Read a master file and build a zone object. @@ -766,7 +771,7 @@ def from_file(f, origin, rdclass = linkcheck.dns.rdataclass.IN, relativize = Tru @param origin: The origin of the zone; if not specified, the first $ORIGIN statement in the master file will determine the origin of the zone. - @type origin: linkcheck.dns.name.Name object or string + @type origin: dns.name.Name object or string @param rdclass: The zone's rdata class; the default is class IN. @type rdclass: int @param relativize: should names be relativized? The default is True @@ -782,15 +787,22 @@ def from_file(f, origin, rdclass = linkcheck.dns.rdataclass.IN, relativize = Tru @param check_origin: should sanity checks of the origin node be done? The default is True. @type check_origin: bool - @raises linkcheck.dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises linkcheck.dns.zone.NoNS: No NS RRset was found at the zone origin - @rtype: linkcheck.dns.zone.Zone object + @raises dns.zone.NoSOA: No SOA RR was found at the zone origin + @raises dns.zone.NoNS: No NS RRset was found at the zone origin + @rtype: dns.zone.Zone object """ - if isinstance(f, basestring): + if sys.hexversion >= 0x02030000: + # allow Unicode filenames; turn on universal newline support + str_type = basestring + opts = 'rU' + else: + str_type = str + opts = 'r' + if isinstance(f, str_type): if filename is None: filename = f - f = file(f, 'rU') + f = file(f, opts) want_close = True else: if filename is None: @@ -809,14 +821,14 @@ def from_xfr(xfr, zone_factory=Zone, relativize=True): """Convert the output of a zone transfer generator into a zone object. @param xfr: The xfr generator - @type xfr: generator of linkcheck.dns.message.Message objects + @type xfr: generator of dns.message.Message objects @param relativize: should names be relativized? The default is True. It is essential that the relativize setting matches the one specified - to linkcheck.dns.query.xfr(). + to dns.query.xfr(). @type relativize: bool - @raises linkcheck.dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises linkcheck.dns.zone.NoNS: No NS RRset was found at the zone origin - @rtype: linkcheck.dns.zone.Zone object + @raises dns.zone.NoSOA: No SOA RR was found at the zone origin + @raises dns.zone.NoNS: No NS RRset was found at the zone origin + @rtype: dns.zone.Zone object """ z = None diff --git a/linkcheck/dns/rdtypes/ANY/RRSIG.py b/third_party/dnspython/tests/Makefile similarity index 75% rename from linkcheck/dns/rdtypes/ANY/RRSIG.py rename to third_party/dnspython/tests/Makefile index fc4610df..4e53dd5d 100644 --- a/linkcheck/dns/rdtypes/ANY/RRSIG.py +++ b/third_party/dnspython/tests/Makefile @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2004-2007, 2009, 2010 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,8 +13,14 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import linkcheck.dns.rdtypes.sigbase +# $Id: Makefile,v 1.5 2004/03/19 00:17:27 halley Exp $ -class RRSIG(linkcheck.dns.rdtypes.sigbase.SIGBase): - """RRSIG record""" - pass +PYTHON=python + +check: test + +test: + @for i in *.py; do \ + echo "Running $$i:"; \ + PYTHONPATH=.. ${PYTHON} $$i || exit 1; \ + done diff --git a/tests/dns/test_bugs.py b/third_party/dnspython/tests/bugs.py similarity index 60% rename from tests/dns/test_bugs.py rename to third_party/dnspython/tests/bugs.py index f44b5044..c2fa6b66 100644 --- a/tests/dns/test_bugs.py +++ b/third_party/dnspython/tests/bugs.py @@ -1,4 +1,4 @@ -# Copyright (C) 2006, 2007 Nominum, Inc. +# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -15,27 +15,30 @@ import unittest -import linkcheck.dns.rdata -import linkcheck.dns.rdataclass -import linkcheck.dns.rdatatype -import linkcheck.dns.ttl +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.ttl class BugsTestCase(unittest.TestCase): def test_float_LOC(self): - rdata = linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.LOC, + rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.LOC, "30 30 0.000 N 100 30 0.000 W 10.00m 20m 2000m 20m") - self.assertTrue(rdata.float_latitude == 30.5) - self.assertTrue(rdata.float_longitude == -100.5) + self.failUnless(rdata.float_latitude == 30.5) + self.failUnless(rdata.float_longitude == -100.5) def test_SOA_BIND8_TTL(self): - rdata1 = linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.SOA, + rdata1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, "a b 100 1s 1m 1h 1d") - rdata2 = linkcheck.dns.rdata.from_text(linkcheck.dns.rdataclass.IN, linkcheck.dns.rdatatype.SOA, + rdata2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, "a b 100 1 60 3600 86400") - self.assertTrue(rdata1 == rdata2) + self.failUnless(rdata1 == rdata2) def test_TTL_bounds_check(self): def bad(): - ttl = linkcheck.dns.ttl.from_text("2147483648") - self.assertRaises(linkcheck.dns.ttl.BadTTL, bad) + ttl = dns.ttl.from_text("2147483648") + self.failUnlessRaises(dns.ttl.BadTTL, bad) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/dnssec.py b/third_party/dnspython/tests/dnssec.py new file mode 100644 index 00000000..7b4546a0 --- /dev/null +++ b/third_party/dnspython/tests/dnssec.py @@ -0,0 +1,146 @@ +# Copyright (C) 2011 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 unittest + +import dns.dnssec +import dns.name +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset + +abs_dnspython_org = dns.name.from_text('dnspython.org') + +abs_keys = { abs_dnspython_org : + dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'DNSKEY', + '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', + '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') + } + +rel_keys = { dns.name.empty : + dns.rrset.from_text('@', 3600, 'IN', 'DNSKEY', + '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', + '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') + } + +when = 1290250287 + +abs_soa = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'SOA', + 'howl.dnspython.org. hostmaster.dnspython.org. 2010020047 3600 1800 604800 3600') + +abs_other_soa = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'SOA', + 'foo.dnspython.org. hostmaster.dnspython.org. 2010020047 3600 1800 604800 3600') + +abs_soa_rrsig = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'RRSIG', + 'SOA 5 2 3600 20101127004331 20101119213831 61695 dnspython.org. sDUlltRlFTQw5ITFxOXW3TgmrHeMeNpdqcZ4EXxM9FHhIlte6V9YCnDw t6dvM9jAXdIEi03l9H/RAd9xNNW6gvGMHsBGzpvvqFQxIBR2PoiZA1mX /SWHZFdbt4xjYTtXqpyYvrMK0Dt7bUYPadyhPFCJ1B+I8Zi7B5WJEOd0 8vs=') + +rel_soa = dns.rrset.from_text('@', 3600, 'IN', 'SOA', + 'howl hostmaster 2010020047 3600 1800 604800 3600') + +rel_other_soa = dns.rrset.from_text('@', 3600, 'IN', 'SOA', + 'foo hostmaster 2010020047 3600 1800 604800 3600') + +rel_soa_rrsig = dns.rrset.from_text('@', 3600, 'IN', 'RRSIG', + 'SOA 5 2 3600 20101127004331 20101119213831 61695 @ sDUlltRlFTQw5ITFxOXW3TgmrHeMeNpdqcZ4EXxM9FHhIlte6V9YCnDw t6dvM9jAXdIEi03l9H/RAd9xNNW6gvGMHsBGzpvvqFQxIBR2PoiZA1mX /SWHZFdbt4xjYTtXqpyYvrMK0Dt7bUYPadyhPFCJ1B+I8Zi7B5WJEOd0 8vs=') + +sep_key = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DNSKEY, + '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=') + +good_ds = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, + '57349 5 2 53A79A3E7488AB44FFC56B2D1109F0699D1796DD977E72108B841F96 E47D7013') + +when2 = 1290425644 + +abs_example = dns.name.from_text('example') + +abs_dsa_keys = { abs_example : + dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', + '257 3 3 CI3nCqyJsiCJHTjrNsJOT4RaszetzcJPYuoH3F9ZTVt3KJXncCVR3bwn 1w0iavKljb9hDlAYSfHbFCp4ic/rvg4p1L8vh5s8ToMjqDNl40A0hUGQ Ybx5hsECyK+qHoajilUX1phYSAD8d9WAGO3fDWzUPBuzR7o85NiZCDxz yXuNVfni0uhj9n1KYhEO5yAbbruDGN89wIZcxMKuQsdUY2GYD93ssnBv a55W6XRABYWayKZ90WkRVODLVYLSn53Pj/wwxGH+XdhIAZJXimrZL4yl My7rtBsLMqq8Ihs4Tows7LqYwY7cp6y/50tw6pj8tFqMYcPUjKZV36l1 M/2t5BVg3i7IK61Aidt6aoC3TDJtzAxg3ZxfjZWJfhHjMJqzQIfbW5b9 q1mjFsW5EUv39RaNnX+3JWPRLyDqD4pIwDyqfutMsdk/Py3paHn82FGp CaOg+nicqZ9TiMZURN/XXy5JoXUNQ3RNvbHCUiPUe18KUkY6mTfnyHld 1l9YCWmzXQVClkx/hOYxjJ4j8Ife58+Obu5X', + '256 3 3 CJE1yb9YRQiw5d2xZrMUMR+cGCTt1bp1KDCefmYKmS+Z1+q9f42ETVhx JRiQwXclYwmxborzIkSZegTNYIV6mrYwbNB27Q44c3UGcspb3PiOw5TC jNPRYEcdwGvDZ2wWy+vkSV/S9tHXY8O6ODiE6abZJDDg/RnITyi+eoDL R3KZ5n/V1f1T1b90rrV6EewhBGQJpQGDogaXb2oHww9Tm6NfXyo7SoMM pbwbzOckXv+GxRPJIQNSF4D4A9E8XCksuzVVdE/0lr37+uoiAiPia38U 5W2QWe/FJAEPLjIp2eTzf0TrADc1pKP1wrA2ASpdzpm/aX3IB5RPp8Ew S9U72eBFZJAUwg635HxJVxH1maG6atzorR566E+e0OZSaxXS9o1o6QqN 3oPlYLGPORDiExilKfez3C/x/yioOupW9K5eKF0gmtaqrHX0oq9s67f/ RIM2xVaKHgG9Vf2cgJIZkhv7sntujr+E4htnRmy9P9BxyFxsItYxPI6Z bzygHAZpGhlI/7ltEGlIwKxyTK3ZKBm67q7B') + } + +abs_dsa_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', + 'ns1.example. hostmaster.example. 2 10800 3600 604800 86400') + +abs_other_dsa_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', + 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401') + +abs_dsa_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', + 'SOA 3 1 86400 20101129143231 20101122112731 42088 example. CGul9SuBofsktunV8cJs4eRs6u+3NCS3yaPKvBbD+pB2C76OUXDZq9U=') + +example_sep_key = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DNSKEY, + '257 3 3 CI3nCqyJsiCJHTjrNsJOT4RaszetzcJPYuoH3F9ZTVt3KJXncCVR3bwn 1w0iavKljb9hDlAYSfHbFCp4ic/rvg4p1L8vh5s8ToMjqDNl40A0hUGQ Ybx5hsECyK+qHoajilUX1phYSAD8d9WAGO3fDWzUPBuzR7o85NiZCDxz yXuNVfni0uhj9n1KYhEO5yAbbruDGN89wIZcxMKuQsdUY2GYD93ssnBv a55W6XRABYWayKZ90WkRVODLVYLSn53Pj/wwxGH+XdhIAZJXimrZL4yl My7rtBsLMqq8Ihs4Tows7LqYwY7cp6y/50tw6pj8tFqMYcPUjKZV36l1 M/2t5BVg3i7IK61Aidt6aoC3TDJtzAxg3ZxfjZWJfhHjMJqzQIfbW5b9 q1mjFsW5EUv39RaNnX+3JWPRLyDqD4pIwDyqfutMsdk/Py3paHn82FGp CaOg+nicqZ9TiMZURN/XXy5JoXUNQ3RNvbHCUiPUe18KUkY6mTfnyHld 1l9YCWmzXQVClkx/hOYxjJ4j8Ife58+Obu5X') + +example_ds_sha1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, + '18673 3 1 71b71d4f3e11bbd71b4eff12cde69f7f9215bbe7') + +example_ds_sha256 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, + '18673 3 2 eb8344cbbf07c9d3d3d6c81d10c76653e28d8611a65e639ef8f716e4e4e5d913') + +class DNSSECValidatorTestCase(unittest.TestCase): + + def testAbsoluteRSAGood(self): + dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when) + + def testAbsoluteRSABad(self): + def bad(): + dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None, + when) + self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) + + def testRelativeRSAGood(self): + dns.dnssec.validate(rel_soa, rel_soa_rrsig, rel_keys, + abs_dnspython_org, when) + + def testRelativeRSABad(self): + def bad(): + dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys, + abs_dnspython_org, when) + self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) + + def testMakeSHA256DS(self): + ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256') + self.failUnless(ds == good_ds) + + def testAbsoluteDSAGood(self): + dns.dnssec.validate(abs_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, + when2) + + def testAbsoluteDSABad(self): + def bad(): + dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig, + abs_dsa_keys, None, when2) + self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) + + def testMakeExampleSHA1DS(self): + ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA1') + self.failUnless(ds == example_ds_sha1) + + def testMakeExampleSHA256DS(self): + ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') + self.failUnless(ds == example_ds_sha256) + +if __name__ == '__main__': + import_ok = False + try: + import Crypto.Util.number + import_ok = True + except: + pass + if import_ok: + unittest.main() + else: + print 'skipping DNSSEC tests because pycrypto is not installed' diff --git a/tests/dns/example b/third_party/dnspython/tests/example similarity index 81% rename from tests/dns/example rename to third_party/dnspython/tests/example index b76be34a..2f753a2f 100644 --- a/tests/dns/example +++ b/third_party/dnspython/tests/example @@ -13,6 +13,8 @@ ; NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION ; WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +; $Id: example,v 1.13 2004/03/19 00:06:37 halley Exp $ + $ORIGIN . $TTL 300 ; 5 minutes example IN SOA ns1.example. hostmaster.example. ( @@ -99,16 +101,17 @@ isdn01 ISDN "isdn-address" isdn02 ISDN "isdn-address" "subaddress" isdn03 ISDN "isdn-address" isdn04 ISDN "isdn-address" "subaddress" -key01 KEY 512 255 1 ( - AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR - yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 - GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o - jqf0BaqHT+8= ) -key02 KEY HOST|FLAG4 DNSSEC RSAMD5 ( - AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR - yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 - GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o - jqf0BaqHT+8= ) +;; dnspython no longer supports old DNSSEC +;;key01 KEY 512 255 1 ( +;; AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR +;; yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 +;; GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o +;; jqf0BaqHT+8= ) +;;key02 KEY HOST|FLAG4 DNSSEC RSAMD5 ( +;; AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR +;; yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 +;; GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o +;; jqf0BaqHT+8= ) kx01 KX 10 kdc kx02 KX 10 . loc01 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20m 2000m 20m @@ -135,10 +138,10 @@ nsap-ptr01 NSAP-PTR foo. NSAP-PTR . nsap01 NSAP 0x47000580005a0000000001e133ffffff00016100 nsap02 NSAP 0x47.000580005a0000000001e133ffffff000161.00 -nxt01 NXT a.secure ( NS SOA MX SIG KEY LOC NXT ) -nxt02 NXT . ( NSAP-PTR NXT ) -nxt03 NXT . ( A ) -nxt04 NXT . ( 127 ) +;;nxt01 NXT a.secure ( NS SOA MX SIG KEY LOC NXT ) +;;nxt02 NXT . ( NSAP-PTR NXT ) +;;nxt03 NXT . ( A ) +;;nxt04 NXT . ( 127 ) ptr01 PTR example. px01 PX 65535 foo. bar. px02 PX 65535 . . @@ -152,11 +155,11 @@ $ORIGIN s.example. ns A 73.80.65.49 $ORIGIN example. $TTL 3600 ; 1 hour -sig01 SIG NXT 1 3 3600 ( - 20200101000000 20030101000000 2143 foo - MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi - WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl - d80jEeC8aTrO+KKmCaY= ) +;;sig01 SIG NXT 1 3 3600 ( +;; 20200101000000 20030101000000 2143 foo +;; MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi +;; WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl +;; d80jEeC8aTrO+KKmCaY= ) srv01 SRV 0 0 0 . srv02 SRV 65535 65535 65535 old-slow-box.example.com. $TTL 301 ; 5 minutes 1 second @@ -186,6 +189,7 @@ wks01 WKS 10.0.0.1 6 ( 0 1 2 21 23 ) wks02 WKS 10.0.0.1 17 ( 0 1 2 53 ) wks03 WKS 10.0.0.2 6 ( 65535 ) x2501 X25 "123456789" +dlv01 DLV 12345 3 1 123456789abcdef67890123456789abcdef67890 ds01 DS 12345 3 1 123456789abcdef67890123456789abcdef67890 apl01 APL 1:192.168.32.0/21 !1:192.168.38.0/28 apl02 APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 @@ -199,7 +203,7 @@ dnskey01 DNSKEY 512 255 1 ( yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o jqf0BaqHT+8= ) -dnskey02 DNSKEY HOST|FLAG4 DNSSEC RSAMD5 ( +dnskey02 DNSKEY 257 3 RSAMD5 ( AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o @@ -215,3 +219,8 @@ ipseckey02 IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey03 IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey04 IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey05 IPSECKEY 10 3 2 mygateway2 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== +nsec301 NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG +nsec302 NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG +nsec3param01 NSEC3PARAM 1 1 12 aabbccdd +nsec3param02 NSEC3PARAM 1 1 12 - +hip01 HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2 diff --git a/tests/dns/example1.good b/third_party/dnspython/tests/example1.good similarity index 82% rename from tests/dns/example1.good rename to third_party/dnspython/tests/example1.good index 5ec1d6cf..0834d171 100644 --- a/tests/dns/example1.good +++ b/third_party/dnspython/tests/example1.good @@ -22,11 +22,12 @@ 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 2560 3 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" @@ -40,6 +41,7 @@ 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== @@ -49,8 +51,6 @@ 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" -key01 3600 IN KEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= -key02 3600 IN KEY 2560 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= 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 @@ -68,13 +68,13 @@ 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. TYPE1234 +nsec01 3600 IN NSEC a.secure. A MX RRSIG NSEC TYPE1234 nsec02 3600 IN NSEC . NSAP-PTR NSEC -nsec03 3600 IN NSEC . TYPE65535 -nxt01 3600 IN NXT a.secure NS SOA MX SIG KEY LOC NXT -nxt02 3600 IN NXT . NSAP-PTR NXT -nxt03 3600 IN NXT . A -nxt04 3600 IN NXT . TYPE127 +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 . . @@ -85,7 +85,6 @@ 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 -sig01 3600 IN SIG NXT 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= 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. diff --git a/tests/dns/example2.good b/third_party/dnspython/tests/example2.good similarity index 84% rename from tests/dns/example2.good rename to third_party/dnspython/tests/example2.good index 914accb3..de4bcd59 100644 --- a/tests/dns/example2.good +++ b/third_party/dnspython/tests/example2.good @@ -22,11 +22,12 @@ d.example. 300 IN A 73.80.65.49 dhcid01.example. 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA= dhcid02.example. 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No= dhcid03.example. 3600 IN DHCID AAABxLmlskllE0MVjd57zHcWmEH3pCQ6 VytcKD//7es/deY= +dlv01.example. 3600 IN DLV 12345 3 1 123456789abcdef67890123456789abcdef67890 dname01.example. 3600 IN DNAME dname-target. dname02.example. 3600 IN DNAME dname-target.example. dname03.example. 3600 IN DNAME . dnskey01.example. 3600 IN DNSKEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= -dnskey02.example. 3600 IN DNSKEY 2560 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +dnskey02.example. 3600 IN DNSKEY 257 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= ds01.example. 3600 IN DS 12345 3 1 123456789abcdef67890123456789abcdef67890 e.example. 300 IN MX 10 mail.example. e.example. 300 IN TXT "one" @@ -40,6 +41,7 @@ f.example. 300 IN A 73.80.65.52 gpos01.example. 3600 IN GPOS -22.6882 116.8652 250.0 hinfo01.example. 3600 IN HINFO "Generic PC clone" "NetBSD-1.4" hinfo02.example. 3600 IN HINFO "PC" "NetBSD" +hip01.example. 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2.example. ipseckey01.example. 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey02.example. 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey03.example. 3600 IN IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== @@ -49,8 +51,6 @@ isdn01.example. 3600 IN ISDN "isdn-address" isdn02.example. 3600 IN ISDN "isdn-address" "subaddress" isdn03.example. 3600 IN ISDN "isdn-address" isdn04.example. 3600 IN ISDN "isdn-address" "subaddress" -key01.example. 3600 IN KEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= -key02.example. 3600 IN KEY 2560 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= kx01.example. 3600 IN KX 10 kdc.example. kx02.example. 3600 IN KX 10 . loc01.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m @@ -68,13 +68,13 @@ nsap-ptr01.example. 3600 IN NSAP-PTR foo. nsap-ptr01.example. 3600 IN NSAP-PTR . nsap01.example. 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 nsap02.example. 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 -nsec01.example. 3600 IN NSEC a.secure. TYPE1234 +nsec01.example. 3600 IN NSEC a.secure. A MX RRSIG NSEC TYPE1234 nsec02.example. 3600 IN NSEC . NSAP-PTR NSEC -nsec03.example. 3600 IN NSEC . TYPE65535 -nxt01.example. 3600 IN NXT a.secure.example. NS SOA MX SIG KEY LOC NXT -nxt02.example. 3600 IN NXT . NSAP-PTR NXT -nxt03.example. 3600 IN NXT . A -nxt04.example. 3600 IN NXT . TYPE127 +nsec03.example. 3600 IN NSEC . NSEC TYPE65535 +nsec301.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM +nsec302.example. 3600 IN NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM +nsec3param01.example. 3600 IN NSEC3PARAM 1 1 12 aabbccdd +nsec3param02.example. 3600 IN NSEC3PARAM 1 1 12 - ptr01.example. 3600 IN PTR example. px01.example. 3600 IN PX 65535 foo. bar. px02.example. 3600 IN PX 65535 . . @@ -85,7 +85,6 @@ rt01.example. 3600 IN RT 0 intermediate-host.example. rt02.example. 3600 IN RT 65535 . s.example. 300 IN NS ns.s.example. ns.s.example. 300 IN A 73.80.65.49 -sig01.example. 3600 IN SIG NXT 1 3 3600 20200101000000 20030101000000 2143 foo.example. MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= spf.example. 3600 IN SPF "v=spf1 mx -all" srv01.example. 3600 IN SRV 0 0 0 . srv02.example. 3600 IN SRV 65535 65535 65535 old-slow-box.example.com. diff --git a/third_party/dnspython/tests/flags.py b/third_party/dnspython/tests/flags.py new file mode 100644 index 00000000..b3cf6716 --- /dev/null +++ b/third_party/dnspython/tests/flags.py @@ -0,0 +1,59 @@ +# Copyright (C) 2003-2007, 2009-2011 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 unittest + +import dns.flags +import dns.rcode +import dns.opcode + +class FlagsTestCase(unittest.TestCase): + + def test_rcode1(self): + self.failUnless(dns.rcode.from_text('FORMERR') == dns.rcode.FORMERR) + + def test_rcode2(self): + self.failUnless(dns.rcode.to_text(dns.rcode.FORMERR) == "FORMERR") + + def test_rcode3(self): + self.failUnless(dns.rcode.to_flags(dns.rcode.FORMERR) == (1, 0)) + + def test_rcode4(self): + self.failUnless(dns.rcode.to_flags(dns.rcode.BADVERS) == \ + (0, 0x01000000)) + + def test_rcode6(self): + self.failUnless(dns.rcode.from_flags(0, 0x01000000) == \ + dns.rcode.BADVERS) + + def test_rcode6(self): + self.failUnless(dns.rcode.from_flags(5, 0) == dns.rcode.REFUSED) + + def test_rcode7(self): + def bad(): + dns.rcode.to_flags(4096) + self.failUnlessRaises(ValueError, bad) + + def test_flags1(self): + self.failUnless(dns.flags.from_text("RA RD AA QR") == \ + dns.flags.QR|dns.flags.AA|dns.flags.RD|dns.flags.RA) + + def test_flags2(self): + flags = dns.flags.QR|dns.flags.AA|dns.flags.RD|dns.flags.RA + self.failUnless(dns.flags.to_text(flags) == "QR AA RD RA") + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/dns/test_message.py b/third_party/dnspython/tests/message.py similarity index 60% rename from tests/dns/test_message.py rename to third_party/dnspython/tests/message.py index a0a302d3..931bb197 100644 --- a/tests/dns/test_message.py +++ b/third_party/dnspython/tests/message.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -14,10 +13,12 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +import cStringIO +import os import unittest -import linkcheck.dns.exception -import linkcheck.dns.message +import dns.exception +import dns.message query_text = """id 1234 opcode QUERY @@ -85,91 +86,94 @@ goodhex3 = '04d2010f0001000000000001047777777709646e73707974686f6e' \ goodwire3 = goodhex3.decode('hex_codec') -class TestMessage (unittest.TestCase): +class MessageTestCase(unittest.TestCase): def test_comparison_eq1(self): - q1 = linkcheck.dns.message.from_text(query_text) - q2 = linkcheck.dns.message.from_text(query_text) - self.assertEqual(q1, q2) + q1 = dns.message.from_text(query_text) + q2 = dns.message.from_text(query_text) + self.failUnless(q1 == q2) def test_comparison_ne1(self): - q1 = linkcheck.dns.message.from_text(query_text) - q2 = linkcheck.dns.message.from_text(query_text) + q1 = dns.message.from_text(query_text) + q2 = dns.message.from_text(query_text) q2.id = 10 - self.assertNotEqual(q1, q2) + self.failUnless(q1 != q2) def test_comparison_ne2(self): - q1 = linkcheck.dns.message.from_text(query_text) - q2 = linkcheck.dns.message.from_text(query_text) + q1 = dns.message.from_text(query_text) + q2 = dns.message.from_text(query_text) q2.question = [] - self.assertNotEqual(q1, q2) + self.failUnless(q1 != q2) def test_comparison_ne3(self): - q1 = linkcheck.dns.message.from_text(query_text) - self.assertNotEqual(q1, 1) + q1 = dns.message.from_text(query_text) + self.failUnless(q1 != 1) def test_EDNS_to_wire1(self): - q = linkcheck.dns.message.from_text(query_text) + q = dns.message.from_text(query_text) w = q.to_wire() - self.assertEqual(w, goodwire) + self.failUnless(w == goodwire) def test_EDNS_from_wire1(self): - m = linkcheck.dns.message.from_wire(goodwire) - self.assertEqual(str(m), query_text) + m = dns.message.from_wire(goodwire) + self.failUnless(str(m) == query_text) def test_EDNS_to_wire2(self): - q = linkcheck.dns.message.from_text(query_text_2) + q = dns.message.from_text(query_text_2) w = q.to_wire() - self.assertEqual(w, goodwire3) + self.failUnless(w == goodwire3) def test_EDNS_from_wire2(self): - m = linkcheck.dns.message.from_wire(goodwire3) - self.assertEqual(str(m), query_text_2) + m = dns.message.from_wire(goodwire3) + self.failUnless(str(m) == query_text_2) def test_TooBig(self): def bad(): - q = linkcheck.dns.message.from_text(query_text) + q = dns.message.from_text(query_text) for i in xrange(0, 25): - rrset = linkcheck.dns.rrset.from_text('foo%d.' % i, 3600, - linkcheck.dns.rdataclass.IN, - linkcheck.dns.rdatatype.A, + rrset = dns.rrset.from_text('foo%d.' % i, 3600, + dns.rdataclass.IN, + dns.rdatatype.A, '10.0.0.%d' % i) q.additional.append(rrset) w = q.to_wire(max_size=512) - self.assertRaises(linkcheck.dns.exception.TooBig, bad) + self.failUnlessRaises(dns.exception.TooBig, bad) def test_answer1(self): - a = linkcheck.dns.message.from_text(answer_text) + a = dns.message.from_text(answer_text) wire = a.to_wire(want_shuffle=False) - self.assertEqual(wire, goodwire2) + self.failUnless(wire == goodwire2) def test_TrailingJunk(self): def bad(): badwire = goodwire + '\x00' - m = linkcheck.dns.message.from_wire(badwire) - self.assertRaises(linkcheck.dns.message.TrailingJunk, bad) + m = dns.message.from_wire(badwire) + self.failUnlessRaises(dns.message.TrailingJunk, bad) def test_ShortHeader(self): def bad(): badwire = '\x00' * 11 - m = linkcheck.dns.message.from_wire(badwire) - self.assertRaises(linkcheck.dns.message.ShortHeader, bad) + m = dns.message.from_wire(badwire) + self.failUnlessRaises(dns.message.ShortHeader, bad) def test_RespondingToResponse(self): def bad(): - q = linkcheck.dns.message.make_query('foo', 'A') - r1 = linkcheck.dns.message.make_response(q) - r2 = linkcheck.dns.message.make_response(r1) - self.assertRaises(linkcheck.dns.exception.FormError, bad) + q = dns.message.make_query('foo', 'A') + r1 = dns.message.make_response(q) + r2 = dns.message.make_response(r1) + self.failUnlessRaises(dns.exception.FormError, bad) def test_ExtendedRcodeSetting(self): - m = linkcheck.dns.message.make_query('foo', 'A') + m = dns.message.make_query('foo', 'A') m.set_rcode(4095) - self.assertEqual(m.rcode(), 4095) + self.failUnless(m.rcode() == 4095) m.set_rcode(2) - self.assertEqual(m.rcode(), 2) + self.failUnless(m.rcode() == 2) def test_EDNSVersionCoherence(self): - m = linkcheck.dns.message.make_query('foo', 'A') + m = dns.message.make_query('foo', 'A') m.use_edns(1) - self.assertEqual((m.ednsflags >> 16) & 0xFF, 1) + self.failUnless((m.ednsflags >> 16) & 0xFF == 1) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/name.py b/third_party/dnspython/tests/name.py new file mode 100644 index 00000000..55815f80 --- /dev/null +++ b/third_party/dnspython/tests/name.py @@ -0,0 +1,697 @@ +# Copyright (C) 2003-2007, 2009-2011 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 unittest + +import cStringIO +import socket + +import dns.name +import dns.reversename +import dns.e164 + +class NameTestCase(unittest.TestCase): + def setUp(self): + self.origin = dns.name.from_text('example.') + + def testFromTextRel1(self): + n = dns.name.from_text('foo.bar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testFromTextRel2(self): + n = dns.name.from_text('foo.bar', origin=self.origin) + self.failUnless(n.labels == ('foo', 'bar', 'example', '')) + + def testFromTextRel3(self): + n = dns.name.from_text('foo.bar', origin=None) + self.failUnless(n.labels == ('foo', 'bar')) + + def testFromTextRel4(self): + n = dns.name.from_text('@', origin=None) + self.failUnless(n == dns.name.empty) + + def testFromTextRel5(self): + n = dns.name.from_text('@', origin=self.origin) + self.failUnless(n == self.origin) + + def testFromTextAbs1(self): + n = dns.name.from_text('foo.bar.') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testTortureFromText(self): + good = [ + r'.', + r'a', + r'a.', + r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + r'\000.\008.\010.\032.\046.\092.\099.\255', + r'\\', + r'\..\.', + r'\\.\\', + r'!"#%&/()=+-', + r'\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255', + ] + bad = [ + r'..', + r'.a', + r'\\..', + '\\', # yes, we don't want the 'r' prefix! + r'\0', + r'\00', + r'\00Z', + r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + r'\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255', + ] + for t in good: + try: + n = dns.name.from_text(t) + except: + self.fail("good test '%s' raised an exception" % t) + for t in bad: + caught = False + try: + n = dns.name.from_text(t) + except: + caught = True + if not caught: + self.fail("bad test '%s' did not raise an exception" % t) + + def testImmutable1(self): + def bad(): + self.origin.labels = () + self.failUnlessRaises(TypeError, bad) + + def testImmutable2(self): + def bad(): + self.origin.labels[0] = 'foo' + self.failUnlessRaises(TypeError, bad) + + def testAbs1(self): + self.failUnless(dns.name.root.is_absolute()) + + def testAbs2(self): + self.failUnless(not dns.name.empty.is_absolute()) + + def testAbs3(self): + self.failUnless(self.origin.is_absolute()) + + def testAbs3(self): + n = dns.name.from_text('foo', origin=None) + self.failUnless(not n.is_absolute()) + + def testWild1(self): + n = dns.name.from_text('*.foo', origin=None) + self.failUnless(n.is_wild()) + + def testWild2(self): + n = dns.name.from_text('*a.foo', origin=None) + self.failUnless(not n.is_wild()) + + def testWild3(self): + n = dns.name.from_text('a.*.foo', origin=None) + self.failUnless(not n.is_wild()) + + def testWild4(self): + self.failUnless(not dns.name.root.is_wild()) + + def testWild5(self): + self.failUnless(not dns.name.empty.is_wild()) + + def testHash1(self): + n1 = dns.name.from_text('fOo.COM') + n2 = dns.name.from_text('foo.com') + self.failUnless(hash(n1) == hash(n2)) + + def testCompare1(self): + n1 = dns.name.from_text('a') + n2 = dns.name.from_text('b') + self.failUnless(n1 < n2) + self.failUnless(n2 > n1) + + def testCompare2(self): + n1 = dns.name.from_text('') + n2 = dns.name.from_text('b') + self.failUnless(n1 < n2) + self.failUnless(n2 > n1) + + def testCompare3(self): + self.failUnless(dns.name.empty < dns.name.root) + self.failUnless(dns.name.root > dns.name.empty) + + def testCompare4(self): + self.failUnless(dns.name.root != 1) + + def testCompare5(self): + self.failUnless(dns.name.root < 1 or dns.name.root > 1) + + def testSubdomain1(self): + self.failUnless(not dns.name.empty.is_subdomain(dns.name.root)) + + def testSubdomain2(self): + self.failUnless(not dns.name.root.is_subdomain(dns.name.empty)) + + def testSubdomain3(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(n.is_subdomain(self.origin)) + + def testSubdomain4(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(n.is_subdomain(dns.name.root)) + + def testSubdomain5(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(n.is_subdomain(n)) + + def testSuperdomain1(self): + self.failUnless(not dns.name.empty.is_superdomain(dns.name.root)) + + def testSuperdomain2(self): + self.failUnless(not dns.name.root.is_superdomain(dns.name.empty)) + + def testSuperdomain3(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(self.origin.is_superdomain(n)) + + def testSuperdomain4(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(dns.name.root.is_superdomain(n)) + + def testSuperdomain5(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(n.is_superdomain(n)) + + def testCanonicalize1(self): + n = dns.name.from_text('FOO.bar', origin=self.origin) + c = n.canonicalize() + self.failUnless(c.labels == ('foo', 'bar', 'example', '')) + + def testToText1(self): + n = dns.name.from_text('FOO.bar', origin=self.origin) + t = n.to_text() + self.failUnless(t == 'FOO.bar.example.') + + def testToText2(self): + n = dns.name.from_text('FOO.bar', origin=self.origin) + t = n.to_text(True) + self.failUnless(t == 'FOO.bar.example') + + def testToText3(self): + n = dns.name.from_text('FOO.bar', origin=None) + t = n.to_text() + self.failUnless(t == 'FOO.bar') + + def testToText4(self): + t = dns.name.empty.to_text() + self.failUnless(t == '@') + + def testToText5(self): + t = dns.name.root.to_text() + self.failUnless(t == '.') + + def testToText6(self): + n = dns.name.from_text('FOO bar', origin=None) + t = n.to_text() + self.failUnless(t == r'FOO\032bar') + + def testToText7(self): + n = dns.name.from_text(r'FOO\.bar', origin=None) + t = n.to_text() + self.failUnless(t == r'FOO\.bar') + + def testToText8(self): + n = dns.name.from_text(r'\070OO\.bar', origin=None) + t = n.to_text() + self.failUnless(t == r'FOO\.bar') + + def testSlice1(self): + n = dns.name.from_text(r'a.b.c.', origin=None) + s = n[:] + self.failUnless(s == ('a', 'b', 'c', '')) + + def testSlice2(self): + n = dns.name.from_text(r'a.b.c.', origin=None) + s = n[:2] + self.failUnless(s == ('a', 'b')) + + def testSlice3(self): + n = dns.name.from_text(r'a.b.c.', origin=None) + s = n[2:] + self.failUnless(s == ('c', '')) + + def testEmptyLabel1(self): + def bad(): + n = dns.name.Name(['a', '', 'b']) + self.failUnlessRaises(dns.name.EmptyLabel, bad) + + def testEmptyLabel2(self): + def bad(): + n = dns.name.Name(['', 'b']) + self.failUnlessRaises(dns.name.EmptyLabel, bad) + + def testEmptyLabel3(self): + n = dns.name.Name(['b', '']) + self.failUnless(n) + + def testLongLabel(self): + n = dns.name.Name(['a' * 63]) + self.failUnless(n) + + def testLabelTooLong(self): + def bad(): + n = dns.name.Name(['a' * 64, 'b']) + self.failUnlessRaises(dns.name.LabelTooLong, bad) + + def testLongName(self): + n = dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 62]) + self.failUnless(n) + + def testNameTooLong(self): + def bad(): + n = dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 63]) + self.failUnlessRaises(dns.name.NameTooLong, bad) + + def testConcat1(self): + n1 = dns.name.Name(['a', 'b']) + n2 = dns.name.Name(['c', 'd']) + e = dns.name.Name(['a', 'b', 'c', 'd']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat2(self): + n1 = dns.name.Name(['a', 'b']) + n2 = dns.name.Name([]) + e = dns.name.Name(['a', 'b']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat2(self): + n1 = dns.name.Name([]) + n2 = dns.name.Name(['a', 'b']) + e = dns.name.Name(['a', 'b']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat3(self): + n1 = dns.name.Name(['a', 'b', '']) + n2 = dns.name.Name([]) + e = dns.name.Name(['a', 'b', '']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat4(self): + n1 = dns.name.Name(['a', 'b']) + n2 = dns.name.Name(['c', '']) + e = dns.name.Name(['a', 'b', 'c', '']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat5(self): + def bad(): + n1 = dns.name.Name(['a', 'b', '']) + n2 = dns.name.Name(['c']) + r = n1 + n2 + self.failUnlessRaises(dns.name.AbsoluteConcatenation, bad) + + def testBadEscape(self): + def bad(): + n = dns.name.from_text(r'a.b\0q1.c.') + print n + self.failUnlessRaises(dns.name.BadEscape, bad) + + def testDigestable1(self): + n = dns.name.from_text('FOO.bar') + d = n.to_digestable() + self.failUnless(d == '\x03foo\x03bar\x00') + + def testDigestable2(self): + n1 = dns.name.from_text('FOO.bar') + n2 = dns.name.from_text('foo.BAR.') + d1 = n1.to_digestable() + d2 = n2.to_digestable() + self.failUnless(d1 == d2) + + def testDigestable3(self): + d = dns.name.root.to_digestable() + self.failUnless(d == '\x00') + + def testDigestable4(self): + n = dns.name.from_text('FOO.bar', None) + d = n.to_digestable(dns.name.root) + self.failUnless(d == '\x03foo\x03bar\x00') + + def testBadDigestable(self): + def bad(): + n = dns.name.from_text('FOO.bar', None) + d = n.to_digestable() + self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) + + def testToWire1(self): + n = dns.name.from_text('FOO.bar') + f = cStringIO.StringIO() + compress = {} + n.to_wire(f, compress) + self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00') + + def testToWire2(self): + n = dns.name.from_text('FOO.bar') + f = cStringIO.StringIO() + compress = {} + n.to_wire(f, compress) + n.to_wire(f, compress) + self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\xc0\x00') + + def testToWire3(self): + n1 = dns.name.from_text('FOO.bar') + n2 = dns.name.from_text('foo.bar') + f = cStringIO.StringIO() + compress = {} + n1.to_wire(f, compress) + n2.to_wire(f, compress) + self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\xc0\x00') + + def testToWire4(self): + n1 = dns.name.from_text('FOO.bar') + n2 = dns.name.from_text('a.foo.bar') + f = cStringIO.StringIO() + compress = {} + n1.to_wire(f, compress) + n2.to_wire(f, compress) + self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\x01\x61\xc0\x00') + + def testToWire5(self): + n1 = dns.name.from_text('FOO.bar') + n2 = dns.name.from_text('a.foo.bar') + f = cStringIO.StringIO() + compress = {} + n1.to_wire(f, compress) + n2.to_wire(f, None) + self.failUnless(f.getvalue() == \ + '\x03FOO\x03bar\x00\x01\x61\x03foo\x03bar\x00') + + def testToWire6(self): + n = dns.name.from_text('FOO.bar') + v = n.to_wire() + self.failUnless(v == '\x03FOO\x03bar\x00') + + def testBadToWire(self): + def bad(): + n = dns.name.from_text('FOO.bar', None) + f = cStringIO.StringIO() + compress = {} + n.to_wire(f, compress) + self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) + + def testSplit1(self): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(2) + ep = dns.name.from_text('foo', None) + es = dns.name.from_text('bar.', None) + self.failUnless(prefix == ep and suffix == es) + + def testSplit2(self): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(1) + ep = dns.name.from_text('foo.bar', None) + es = dns.name.from_text('.', None) + self.failUnless(prefix == ep and suffix == es) + + def testSplit3(self): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(0) + ep = dns.name.from_text('foo.bar.', None) + es = dns.name.from_text('', None) + self.failUnless(prefix == ep and suffix == es) + + def testSplit4(self): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(3) + ep = dns.name.from_text('', None) + es = dns.name.from_text('foo.bar.', None) + self.failUnless(prefix == ep and suffix == es) + + def testBadSplit1(self): + def bad(): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(-1) + self.failUnlessRaises(ValueError, bad) + + def testBadSplit2(self): + def bad(): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(4) + self.failUnlessRaises(ValueError, bad) + + def testRelativize1(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('bar.', None) + e = dns.name.from_text('a.foo', None) + self.failUnless(n.relativize(o) == e) + + def testRelativize2(self): + n = dns.name.from_text('a.foo.bar.', None) + o = n + e = dns.name.empty + self.failUnless(n.relativize(o) == e) + + def testRelativize3(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('blaz.', None) + e = n + self.failUnless(n.relativize(o) == e) + + def testRelativize4(self): + n = dns.name.from_text('a.foo', None) + o = dns.name.root + e = n + self.failUnless(n.relativize(o) == e) + + def testDerelativize1(self): + n = dns.name.from_text('a.foo', None) + o = dns.name.from_text('bar.', None) + e = dns.name.from_text('a.foo.bar.', None) + self.failUnless(n.derelativize(o) == e) + + def testDerelativize2(self): + n = dns.name.empty + o = dns.name.from_text('a.foo.bar.', None) + e = o + self.failUnless(n.derelativize(o) == e) + + def testDerelativize3(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('blaz.', None) + e = n + self.failUnless(n.derelativize(o) == e) + + def testChooseRelativity1(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('bar.', None) + e = dns.name.from_text('a.foo', None) + self.failUnless(n.choose_relativity(o, True) == e) + + def testChooseRelativity2(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('bar.', None) + e = n + self.failUnless(n.choose_relativity(o, False) == e) + + def testChooseRelativity3(self): + n = dns.name.from_text('a.foo', None) + o = dns.name.from_text('bar.', None) + e = dns.name.from_text('a.foo.bar.', None) + self.failUnless(n.choose_relativity(o, False) == e) + + def testChooseRelativity4(self): + n = dns.name.from_text('a.foo', None) + o = None + e = n + self.failUnless(n.choose_relativity(o, True) == e) + + def testChooseRelativity5(self): + n = dns.name.from_text('a.foo', None) + o = None + e = n + self.failUnless(n.choose_relativity(o, False) == e) + + def testChooseRelativity6(self): + n = dns.name.from_text('a.foo.', None) + o = None + e = n + self.failUnless(n.choose_relativity(o, True) == e) + + def testChooseRelativity7(self): + n = dns.name.from_text('a.foo.', None) + o = None + e = n + self.failUnless(n.choose_relativity(o, False) == e) + + def testFromWire1(self): + w = '\x03foo\x00\xc0\x00' + (n1, cused1) = dns.name.from_wire(w, 0) + (n2, cused2) = dns.name.from_wire(w, cused1) + en1 = dns.name.from_text('foo.') + en2 = en1 + ecused1 = 5 + ecused2 = 2 + self.failUnless(n1 == en1 and cused1 == ecused1 and \ + n2 == en2 and cused2 == ecused2) + + def testFromWire1(self): + w = '\x03foo\x00\x01a\xc0\x00\x01b\xc0\x05' + current = 0 + (n1, cused1) = dns.name.from_wire(w, current) + current += cused1 + (n2, cused2) = dns.name.from_wire(w, current) + current += cused2 + (n3, cused3) = dns.name.from_wire(w, current) + en1 = dns.name.from_text('foo.') + en2 = dns.name.from_text('a.foo.') + en3 = dns.name.from_text('b.a.foo.') + ecused1 = 5 + ecused2 = 4 + ecused3 = 4 + self.failUnless(n1 == en1 and cused1 == ecused1 and \ + n2 == en2 and cused2 == ecused2 and \ + n3 == en3 and cused3 == ecused3) + + def testBadFromWire1(self): + def bad(): + w = '\x03foo\xc0\x04' + (n, cused) = dns.name.from_wire(w, 0) + self.failUnlessRaises(dns.name.BadPointer, bad) + + def testBadFromWire2(self): + def bad(): + w = '\x03foo\xc0\x05' + (n, cused) = dns.name.from_wire(w, 0) + self.failUnlessRaises(dns.name.BadPointer, bad) + + def testBadFromWire3(self): + def bad(): + w = '\xbffoo' + (n, cused) = dns.name.from_wire(w, 0) + self.failUnlessRaises(dns.name.BadLabelType, bad) + + def testBadFromWire4(self): + def bad(): + w = '\x41foo' + (n, cused) = dns.name.from_wire(w, 0) + self.failUnlessRaises(dns.name.BadLabelType, bad) + + def testParent1(self): + n = dns.name.from_text('foo.bar.') + self.failUnless(n.parent() == dns.name.from_text('bar.')) + self.failUnless(n.parent().parent() == dns.name.root) + + def testParent2(self): + n = dns.name.from_text('foo.bar', None) + self.failUnless(n.parent() == dns.name.from_text('bar', None)) + self.failUnless(n.parent().parent() == dns.name.empty) + + def testParent3(self): + def bad(): + n = dns.name.root + n.parent() + self.failUnlessRaises(dns.name.NoParent, bad) + + def testParent4(self): + def bad(): + n = dns.name.empty + n.parent() + self.failUnlessRaises(dns.name.NoParent, bad) + + def testFromUnicode1(self): + n = dns.name.from_text(u'foo.bar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testFromUnicode2(self): + n = dns.name.from_text(u'foo\u1234bar.bar') + self.failUnless(n.labels == ('xn--foobar-r5z', 'bar', '')) + + def testFromUnicodeAlternateDot1(self): + n = dns.name.from_text(u'foo\u3002bar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testFromUnicodeAlternateDot2(self): + n = dns.name.from_text(u'foo\uff0ebar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testFromUnicodeAlternateDot3(self): + n = dns.name.from_text(u'foo\uff61bar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testToUnicode1(self): + n = dns.name.from_text(u'foo.bar') + s = n.to_unicode() + self.failUnless(s == u'foo.bar.') + + def testToUnicode2(self): + n = dns.name.from_text(u'foo\u1234bar.bar') + s = n.to_unicode() + self.failUnless(s == u'foo\u1234bar.bar.') + + def testToUnicode3(self): + n = dns.name.from_text('foo.bar') + s = n.to_unicode() + self.failUnless(s == u'foo.bar.') + + def testReverseIPv4(self): + e = dns.name.from_text('1.0.0.127.in-addr.arpa.') + n = dns.reversename.from_address('127.0.0.1') + self.failUnless(e == n) + + def testReverseIPv6(self): + e = dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') + n = dns.reversename.from_address('::1') + self.failUnless(e == n) + + def testBadReverseIPv4(self): + def bad(): + n = dns.reversename.from_address('127.0.foo.1') + self.failUnlessRaises(socket.error, bad) + + def testBadReverseIPv6(self): + def bad(): + n = dns.reversename.from_address('::1::1') + self.failUnlessRaises(socket.error, bad) + + def testForwardIPv4(self): + n = dns.name.from_text('1.0.0.127.in-addr.arpa.') + e = '127.0.0.1' + text = dns.reversename.to_address(n) + self.failUnless(text == e) + + def testForwardIPv6(self): + n = dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') + e = '::1' + text = dns.reversename.to_address(n) + self.failUnless(text == e) + + def testE164ToEnum(self): + text = '+1 650 555 1212' + e = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') + n = dns.e164.from_e164(text) + self.failUnless(n == e) + + def testEnumToE164(self): + n = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') + e = '+16505551212' + text = dns.e164.to_e164(n) + self.failUnless(text == e) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/namedict.py b/third_party/dnspython/tests/namedict.py new file mode 100644 index 00000000..e256bfe6 --- /dev/null +++ b/third_party/dnspython/tests/namedict.py @@ -0,0 +1,102 @@ +# Copyright (C) 2003-2007, 2009-2011 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 unittest + +import dns.name +import dns.namedict + +class NameTestCase(unittest.TestCase): + + def setUp(self): + self.ndict = dns.namedict.NameDict() + n1 = dns.name.from_text('foo.bar.') + n2 = dns.name.from_text('bar.') + self.ndict[n1] = 1 + self.ndict[n2] = 2 + self.rndict = dns.namedict.NameDict() + n1 = dns.name.from_text('foo.bar', None) + n2 = dns.name.from_text('bar', None) + self.rndict[n1] = 1 + self.rndict[n2] = 2 + + def testDepth(self): + self.failUnless(self.ndict.max_depth == 3) + + def testLookup1(self): + k = dns.name.from_text('foo.bar.') + self.failUnless(self.ndict[k] == 1) + + def testLookup2(self): + k = dns.name.from_text('foo.bar.') + self.failUnless(self.ndict.get_deepest_match(k)[1] == 1) + + def testLookup3(self): + k = dns.name.from_text('a.b.c.foo.bar.') + self.failUnless(self.ndict.get_deepest_match(k)[1] == 1) + + def testLookup4(self): + k = dns.name.from_text('a.b.c.bar.') + self.failUnless(self.ndict.get_deepest_match(k)[1] == 2) + + def testLookup5(self): + def bad(): + n = dns.name.from_text('a.b.c.') + (k, v) = self.ndict.get_deepest_match(n) + self.failUnlessRaises(KeyError, bad) + + def testLookup6(self): + def bad(): + (k, v) = self.ndict.get_deepest_match(dns.name.empty) + self.failUnlessRaises(KeyError, bad) + + def testLookup7(self): + self.ndict[dns.name.empty] = 100 + n = dns.name.from_text('a.b.c.') + (k, v) = self.ndict.get_deepest_match(n) + self.failUnless(v == 100) + + def testLookup8(self): + def bad(): + self.ndict['foo'] = 100 + self.failUnlessRaises(ValueError, bad) + + def testRelDepth(self): + self.failUnless(self.rndict.max_depth == 2) + + def testRelLookup1(self): + k = dns.name.from_text('foo.bar', None) + self.failUnless(self.rndict[k] == 1) + + def testRelLookup2(self): + k = dns.name.from_text('foo.bar', None) + self.failUnless(self.rndict.get_deepest_match(k)[1] == 1) + + def testRelLookup3(self): + k = dns.name.from_text('a.b.c.foo.bar', None) + self.failUnless(self.rndict.get_deepest_match(k)[1] == 1) + + def testRelLookup4(self): + k = dns.name.from_text('a.b.c.bar', None) + self.failUnless(self.rndict.get_deepest_match(k)[1] == 2) + + def testRelLookup7(self): + self.rndict[dns.name.empty] = 100 + n = dns.name.from_text('a.b.c', None) + (k, v) = self.rndict.get_deepest_match(n) + self.failUnless(v == 100) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/ntoaaton.py b/third_party/dnspython/tests/ntoaaton.py new file mode 100644 index 00000000..a1c191fd --- /dev/null +++ b/third_party/dnspython/tests/ntoaaton.py @@ -0,0 +1,156 @@ +# Copyright (C) 2003-2007, 2009-2011 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 unittest + +import dns.exception +import dns.ipv6 + +class NtoAAtoNTestCase(unittest.TestCase): + + def test_aton1(self): + a = dns.ipv6.inet_aton('::') + self.failUnless(a == '\x00' * 16) + + def test_aton2(self): + a = dns.ipv6.inet_aton('::1') + self.failUnless(a == '\x00' * 15 + '\x01') + + def test_aton3(self): + a = dns.ipv6.inet_aton('::10.0.0.1') + self.failUnless(a == '\x00' * 12 + '\x0a\x00\x00\x01') + + def test_aton4(self): + a = dns.ipv6.inet_aton('abcd::dcba') + self.failUnless(a == '\xab\xcd' + '\x00' * 12 + '\xdc\xba') + + def test_aton5(self): + a = dns.ipv6.inet_aton('1:2:3:4:5:6:7:8') + self.failUnless(a == \ + '00010002000300040005000600070008'.decode('hex_codec')) + + def test_bad_aton1(self): + def bad(): + a = dns.ipv6.inet_aton('abcd:dcba') + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def test_bad_aton2(self): + def bad(): + a = dns.ipv6.inet_aton('abcd::dcba::1') + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def test_bad_aton3(self): + def bad(): + a = dns.ipv6.inet_aton('1:2:3:4:5:6:7:8:9') + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def test_aton1(self): + a = dns.ipv6.inet_aton('::') + self.failUnless(a == '\x00' * 16) + + def test_aton2(self): + a = dns.ipv6.inet_aton('::1') + self.failUnless(a == '\x00' * 15 + '\x01') + + def test_aton3(self): + a = dns.ipv6.inet_aton('::10.0.0.1') + self.failUnless(a == '\x00' * 12 + '\x0a\x00\x00\x01') + + def test_aton4(self): + a = dns.ipv6.inet_aton('abcd::dcba') + self.failUnless(a == '\xab\xcd' + '\x00' * 12 + '\xdc\xba') + + def test_ntoa1(self): + b = '00010002000300040005000600070008'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '1:2:3:4:5:6:7:8') + + def test_ntoa2(self): + b = '\x00' * 16 + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::') + + def test_ntoa3(self): + b = '\x00' * 15 + '\x01' + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::1') + + def test_ntoa4(self): + b = '\x80' + '\x00' * 15 + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '8000::') + + def test_ntoa5(self): + b = '\x01\xcd' + '\x00' * 12 + '\x03\xef' + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '1cd::3ef') + + def test_ntoa6(self): + b = 'ffff00000000ffff000000000000ffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == 'ffff:0:0:ffff::ffff') + + def test_ntoa7(self): + b = '00000000ffff000000000000ffffffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '0:0:ffff::ffff:ffff') + + def test_ntoa8(self): + b = 'ffff0000ffff00000000ffff00000000'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == 'ffff:0:ffff::ffff:0:0') + + def test_ntoa9(self): + b = '0000000000000000000000000a000001'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::10.0.0.1') + + def test_ntoa10(self): + b = '0000000000000000000000010a000001'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::1:a00:1') + + def test_ntoa11(self): + b = '00000000000000000000ffff0a000001'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::ffff:10.0.0.1') + + def test_ntoa12(self): + b = '000000000000000000000000ffffffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::255.255.255.255') + + def test_ntoa13(self): + b = '00000000000000000000ffffffffffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::ffff:255.255.255.255') + + def test_ntoa14(self): + b = '0000000000000000000000000001ffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::0.1.255.255') + + def test_bad_ntoa1(self): + def bad(): + a = dns.ipv6.inet_ntoa('') + self.failUnlessRaises(ValueError, bad) + + def test_bad_ntoa2(self): + def bad(): + a = dns.ipv6.inet_ntoa('\x00' * 17) + self.failUnlessRaises(ValueError, bad) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/rdtypeandclass.py b/third_party/dnspython/tests/rdtypeandclass.py new file mode 100644 index 00000000..f3c0628d --- /dev/null +++ b/third_party/dnspython/tests/rdtypeandclass.py @@ -0,0 +1,123 @@ +# Copyright (C) 2003-2007, 2009-2011 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 unittest + +import dns.rdataclass +import dns.rdatatype + +class RdTypeAndClassTestCase(unittest.TestCase): + + # Classes + + def test_class_meta1(self): + self.failUnless(dns.rdataclass.is_metaclass(dns.rdataclass.ANY)) + + def test_class_meta2(self): + self.failUnless(not dns.rdataclass.is_metaclass(dns.rdataclass.IN)) + + def test_class_bytext1(self): + self.failUnless(dns.rdataclass.from_text('IN') == dns.rdataclass.IN) + + def test_class_bytext2(self): + self.failUnless(dns.rdataclass.from_text('CLASS1') == + dns.rdataclass.IN) + + def test_class_bytext_bounds1(self): + self.failUnless(dns.rdataclass.from_text('CLASS0') == 0) + self.failUnless(dns.rdataclass.from_text('CLASS65535') == 65535) + + def test_class_bytext_bounds2(self): + def bad(): + junk = dns.rdataclass.from_text('CLASS65536') + self.failUnlessRaises(ValueError, bad) + + def test_class_bytext_unknown(self): + def bad(): + junk = dns.rdataclass.from_text('XXX') + self.failUnlessRaises(dns.rdataclass.UnknownRdataclass, bad) + + def test_class_totext1(self): + self.failUnless(dns.rdataclass.to_text(dns.rdataclass.IN) == 'IN') + + def test_class_totext1(self): + self.failUnless(dns.rdataclass.to_text(999) == 'CLASS999') + + def test_class_totext_bounds1(self): + def bad(): + junk = dns.rdataclass.to_text(-1) + self.failUnlessRaises(ValueError, bad) + + def test_class_totext_bounds2(self): + def bad(): + junk = dns.rdataclass.to_text(65536) + self.failUnlessRaises(ValueError, bad) + + # Types + + def test_type_meta1(self): + self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.ANY)) + + def test_type_meta2(self): + self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.OPT)) + + def test_type_meta3(self): + self.failUnless(not dns.rdatatype.is_metatype(dns.rdatatype.A)) + + def test_type_singleton1(self): + self.failUnless(dns.rdatatype.is_singleton(dns.rdatatype.SOA)) + + def test_type_singleton2(self): + self.failUnless(not dns.rdatatype.is_singleton(dns.rdatatype.A)) + + def test_type_bytext1(self): + self.failUnless(dns.rdatatype.from_text('A') == dns.rdatatype.A) + + def test_type_bytext2(self): + self.failUnless(dns.rdatatype.from_text('TYPE1') == + dns.rdatatype.A) + + def test_type_bytext_bounds1(self): + self.failUnless(dns.rdatatype.from_text('TYPE0') == 0) + self.failUnless(dns.rdatatype.from_text('TYPE65535') == 65535) + + def test_type_bytext_bounds2(self): + def bad(): + junk = dns.rdatatype.from_text('TYPE65536') + self.failUnlessRaises(ValueError, bad) + + def test_type_bytext_unknown(self): + def bad(): + junk = dns.rdatatype.from_text('XXX') + self.failUnlessRaises(dns.rdatatype.UnknownRdatatype, bad) + + def test_type_totext1(self): + self.failUnless(dns.rdatatype.to_text(dns.rdatatype.A) == 'A') + + def test_type_totext1(self): + self.failUnless(dns.rdatatype.to_text(999) == 'TYPE999') + + def test_type_totext_bounds1(self): + def bad(): + junk = dns.rdatatype.to_text(-1) + self.failUnlessRaises(ValueError, bad) + + def test_type_totext_bounds2(self): + def bad(): + junk = dns.rdatatype.to_text(65536) + self.failUnlessRaises(ValueError, bad) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/resolver.py b/third_party/dnspython/tests/resolver.py new file mode 100644 index 00000000..28d5a42c --- /dev/null +++ b/third_party/dnspython/tests/resolver.py @@ -0,0 +1,127 @@ +# Copyright (C) 2003-2007, 2009-2011 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 cStringIO +import select +import sys +import time +import unittest + +import dns.name +import dns.message +import dns.name +import dns.rdataclass +import dns.rdatatype +import dns.resolver + +resolv_conf = """ + /t/t +# comment 1 +; comment 2 +domain foo +nameserver 10.0.0.1 +nameserver 10.0.0.2 +""" + +message_text = """id 1234 +opcode QUERY +rcode NOERROR +flags QR AA RD +;QUESTION +example. IN A +;ANSWER +example. 1 IN A 10.0.0.1 +;AUTHORITY +;ADDITIONAL +""" + +class BaseResolverTests(object): + + if sys.platform != 'win32': + def testRead(self): + f = cStringIO.StringIO(resolv_conf) + r = dns.resolver.Resolver(f) + self.failUnless(r.nameservers == ['10.0.0.1', '10.0.0.2'] and + r.domain == dns.name.from_text('foo')) + + def testCacheExpiration(self): + message = dns.message.from_text(message_text) + name = dns.name.from_text('example.') + answer = dns.resolver.Answer(name, dns.rdatatype.A, dns.rdataclass.IN, + message) + cache = dns.resolver.Cache() + cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) + time.sleep(2) + self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) + is None) + + def testCacheCleaning(self): + message = dns.message.from_text(message_text) + name = dns.name.from_text('example.') + answer = dns.resolver.Answer(name, dns.rdatatype.A, dns.rdataclass.IN, + message) + cache = dns.resolver.Cache(cleaning_interval=1.0) + cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) + time.sleep(2) + self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) + is None) + + def testZoneForName1(self): + name = dns.name.from_text('www.dnspython.org.') + ezname = dns.name.from_text('dnspython.org.') + zname = dns.resolver.zone_for_name(name) + self.failUnless(zname == ezname) + + def testZoneForName2(self): + name = dns.name.from_text('a.b.www.dnspython.org.') + ezname = dns.name.from_text('dnspython.org.') + zname = dns.resolver.zone_for_name(name) + self.failUnless(zname == ezname) + + def testZoneForName3(self): + name = dns.name.from_text('dnspython.org.') + ezname = dns.name.from_text('dnspython.org.') + zname = dns.resolver.zone_for_name(name) + self.failUnless(zname == ezname) + + def testZoneForName4(self): + def bad(): + name = dns.name.from_text('dnspython.org', None) + zname = dns.resolver.zone_for_name(name) + self.failUnlessRaises(dns.resolver.NotAbsolute, bad) + +class PollingMonkeyPatchMixin(object): + def setUp(self): + self.__native_polling_backend = dns.query._polling_backend + dns.query._set_polling_backend(self.polling_backend()) + + unittest.TestCase.setUp(self) + + def tearDown(self): + dns.query._set_polling_backend(self.__native_polling_backend) + + unittest.TestCase.tearDown(self) + +class SelectResolverTestCase(PollingMonkeyPatchMixin, BaseResolverTests, unittest.TestCase): + def polling_backend(self): + return dns.query._select_for + +if hasattr(select, 'poll'): + class PollResolverTestCase(PollingMonkeyPatchMixin, BaseResolverTests, unittest.TestCase): + def polling_backend(self): + return dns.query._poll_for + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/rrset.py b/third_party/dnspython/tests/rrset.py new file mode 100644 index 00000000..be1324b0 --- /dev/null +++ b/third_party/dnspython/tests/rrset.py @@ -0,0 +1,54 @@ +# Copyright (C) 2003-2007, 2009-2011 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 unittest + +import dns.rrset + +class RRsetTestCase(unittest.TestCase): + + def testEqual1(self): + r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') + r2 = dns.rrset.from_text('FOO', 300, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 == r2) + + def testEqual2(self): + r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') + r2 = dns.rrset.from_text('FOO', 600, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 == r2) + + def testNotEqual1(self): + r1 = dns.rrset.from_text('fooa', 30, 'in', 'a', '10.0.0.1', '10.0.0.2') + r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 != r2) + + def testNotEqual2(self): + r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.3') + r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 != r2) + + def testNotEqual3(self): + r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.2', + '10.0.0.3') + r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 != r2) + + def testNotEqual4(self): + r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1') + r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 != r2) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/set.py b/third_party/dnspython/tests/set.py new file mode 100644 index 00000000..583d20cf --- /dev/null +++ b/third_party/dnspython/tests/set.py @@ -0,0 +1,208 @@ +# Copyright (C) 2003-2007, 2009-2011 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 unittest + +import dns.set + +# for convenience +S = dns.set.Set + +class SimpleSetTestCase(unittest.TestCase): + + def testLen1(self): + s1 = S() + self.failUnless(len(s1) == 0) + + def testLen2(self): + s1 = S([1, 2, 3]) + self.failUnless(len(s1) == 3) + + def testLen3(self): + s1 = S([1, 2, 3, 3, 3]) + self.failUnless(len(s1) == 3) + + def testUnion1(self): + s1 = S([1, 2, 3]) + s2 = S([1, 2, 3]) + e = S([1, 2, 3]) + self.failUnless(s1 | s2 == e) + + def testUnion2(self): + s1 = S([1, 2, 3]) + s2 = S([]) + e = S([1, 2, 3]) + self.failUnless(s1 | s2 == e) + + def testUnion3(self): + s1 = S([1, 2, 3]) + s2 = S([3, 4]) + e = S([1, 2, 3, 4]) + self.failUnless(s1 | s2 == e) + + def testIntersection1(self): + s1 = S([1, 2, 3]) + s2 = S([1, 2, 3]) + e = S([1, 2, 3]) + self.failUnless(s1 & s2 == e) + + def testIntersection2(self): + s1 = S([0, 1, 2, 3]) + s2 = S([1, 2, 3, 4]) + e = S([1, 2, 3]) + self.failUnless(s1 & s2 == e) + + def testIntersection3(self): + s1 = S([1, 2, 3]) + s2 = S([]) + e = S([]) + self.failUnless(s1 & s2 == e) + + def testIntersection4(self): + s1 = S([1, 2, 3]) + s2 = S([5, 4]) + e = S([]) + self.failUnless(s1 & s2 == e) + + def testDifference1(self): + s1 = S([1, 2, 3]) + s2 = S([5, 4]) + e = S([1, 2, 3]) + self.failUnless(s1 - s2 == e) + + def testDifference2(self): + s1 = S([1, 2, 3]) + s2 = S([]) + e = S([1, 2, 3]) + self.failUnless(s1 - s2 == e) + + def testDifference3(self): + s1 = S([1, 2, 3]) + s2 = S([3, 2]) + e = S([1]) + self.failUnless(s1 - s2 == e) + + def testDifference4(self): + s1 = S([1, 2, 3]) + s2 = S([3, 2, 1]) + e = S([]) + self.failUnless(s1 - s2 == e) + + def testSubset1(self): + s1 = S([1, 2, 3]) + s2 = S([3, 2, 1]) + self.failUnless(s1.issubset(s2)) + + def testSubset2(self): + s1 = S([1, 2, 3]) + self.failUnless(s1.issubset(s1)) + + def testSubset3(self): + s1 = S([]) + s2 = S([1, 2, 3]) + self.failUnless(s1.issubset(s2)) + + def testSubset4(self): + s1 = S([1]) + s2 = S([1, 2, 3]) + self.failUnless(s1.issubset(s2)) + + def testSubset5(self): + s1 = S([]) + s2 = S([]) + self.failUnless(s1.issubset(s2)) + + def testSubset6(self): + s1 = S([1, 4]) + s2 = S([1, 2, 3]) + self.failUnless(not s1.issubset(s2)) + + def testSuperset1(self): + s1 = S([1, 2, 3]) + s2 = S([3, 2, 1]) + self.failUnless(s1.issuperset(s2)) + + def testSuperset2(self): + s1 = S([1, 2, 3]) + self.failUnless(s1.issuperset(s1)) + + def testSuperset3(self): + s1 = S([1, 2, 3]) + s2 = S([]) + self.failUnless(s1.issuperset(s2)) + + def testSuperset4(self): + s1 = S([1, 2, 3]) + s2 = S([1]) + self.failUnless(s1.issuperset(s2)) + + def testSuperset5(self): + s1 = S([]) + s2 = S([]) + self.failUnless(s1.issuperset(s2)) + + def testSuperset6(self): + s1 = S([1, 2, 3]) + s2 = S([1, 4]) + self.failUnless(not s1.issuperset(s2)) + + def testUpdate1(self): + s1 = S([1, 2, 3]) + u = (4, 5, 6) + e = S([1, 2, 3, 4, 5, 6]) + s1.update(u) + self.failUnless(s1 == e) + + def testUpdate2(self): + s1 = S([1, 2, 3]) + u = [] + e = S([1, 2, 3]) + s1.update(u) + self.failUnless(s1 == e) + + def testGetitem(self): + s1 = S([1, 2, 3]) + i0 = s1[0] + i1 = s1[1] + i2 = s1[2] + s2 = S([i0, i1, i2]) + self.failUnless(s1 == s2) + + def testGetslice(self): + s1 = S([1, 2, 3]) + slice = s1[0:2] + self.failUnless(len(slice) == 2) + item = s1[2] + slice.append(item) + s2 = S(slice) + self.failUnless(s1 == s2) + + def testDelitem(self): + s1 = S([1, 2, 3]) + del s1[0] + i1 = s1[0] + i2 = s1[1] + self.failUnless(i1 != i2) + self.failUnless(i1 == 1 or i1 == 2 or i1 == 3) + self.failUnless(i2 == 1 or i2 == 2 or i2 == 3) + + def testDelslice(self): + s1 = S([1, 2, 3]) + del s1[0:2] + i1 = s1[0] + self.failUnless(i1 == 1 or i1 == 2 or i1 == 3) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/tokenizer.py b/third_party/dnspython/tests/tokenizer.py new file mode 100644 index 00000000..1d561ae1 --- /dev/null +++ b/third_party/dnspython/tests/tokenizer.py @@ -0,0 +1,190 @@ +# Copyright (C) 2003-2007, 2009-2011 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 unittest + +import dns.exception +import dns.tokenizer + +Token = dns.tokenizer.Token + +class TokenizerTestCase(unittest.TestCase): + + def testQuotedString1(self): + tok = dns.tokenizer.Tokenizer(r'"foo"') + token = tok.get() + self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, 'foo')) + + def testQuotedString2(self): + tok = dns.tokenizer.Tokenizer(r'""') + token = tok.get() + self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, '')) + + def testQuotedString3(self): + tok = dns.tokenizer.Tokenizer(r'"\"foo\""') + token = tok.get() + self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, '"foo"')) + + def testQuotedString4(self): + tok = dns.tokenizer.Tokenizer(r'"foo\010bar"') + token = tok.get() + self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, 'foo\x0abar')) + + def testQuotedString5(self): + def bad(): + tok = dns.tokenizer.Tokenizer(r'"foo') + token = tok.get() + self.failUnlessRaises(dns.exception.UnexpectedEnd, bad) + + def testQuotedString6(self): + def bad(): + tok = dns.tokenizer.Tokenizer(r'"foo\01') + token = tok.get() + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def testQuotedString7(self): + def bad(): + tok = dns.tokenizer.Tokenizer('"foo\nbar"') + token = tok.get() + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def testEmpty1(self): + tok = dns.tokenizer.Tokenizer('') + token = tok.get() + self.failUnless(token.is_eof()) + + def testEmpty2(self): + tok = dns.tokenizer.Tokenizer('') + token1 = tok.get() + token2 = tok.get() + self.failUnless(token1.is_eof() and token2.is_eof()) + + def testEOL(self): + tok = dns.tokenizer.Tokenizer('\n') + token1 = tok.get() + token2 = tok.get() + self.failUnless(token1.is_eol() and token2.is_eof()) + + def testWS1(self): + tok = dns.tokenizer.Tokenizer(' \n') + token1 = tok.get() + self.failUnless(token1.is_eol()) + + def testWS2(self): + tok = dns.tokenizer.Tokenizer(' \n') + token1 = tok.get(want_leading=True) + self.failUnless(token1.is_whitespace()) + + def testComment1(self): + tok = dns.tokenizer.Tokenizer(' ;foo\n') + token1 = tok.get() + self.failUnless(token1.is_eol()) + + def testComment2(self): + tok = dns.tokenizer.Tokenizer(' ;foo\n') + token1 = tok.get(want_comment = True) + token2 = tok.get() + self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo') and + token2.is_eol()) + + def testComment3(self): + tok = dns.tokenizer.Tokenizer(' ;foo bar\n') + token1 = tok.get(want_comment = True) + token2 = tok.get() + self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo bar') and + token2.is_eol()) + + def testMultiline1(self): + tok = dns.tokenizer.Tokenizer('( foo\n\n bar\n)') + tokens = list(iter(tok)) + self.failUnless(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), + Token(dns.tokenizer.IDENTIFIER, 'bar')]) + + def testMultiline2(self): + tok = dns.tokenizer.Tokenizer('( foo\n\n bar\n)\n') + tokens = list(iter(tok)) + self.failUnless(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), + Token(dns.tokenizer.IDENTIFIER, 'bar'), + Token(dns.tokenizer.EOL, '\n')]) + def testMultiline3(self): + def bad(): + tok = dns.tokenizer.Tokenizer('foo)') + tokens = list(iter(tok)) + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def testMultiline4(self): + def bad(): + tok = dns.tokenizer.Tokenizer('((foo)') + tokens = list(iter(tok)) + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def testUnget1(self): + tok = dns.tokenizer.Tokenizer('foo') + t1 = tok.get() + tok.unget(t1) + t2 = tok.get() + self.failUnless(t1 == t2 and t1.ttype == dns.tokenizer.IDENTIFIER and \ + t1.value == 'foo') + + def testUnget2(self): + def bad(): + tok = dns.tokenizer.Tokenizer('foo') + t1 = tok.get() + tok.unget(t1) + tok.unget(t1) + self.failUnlessRaises(dns.tokenizer.UngetBufferFull, bad) + + def testGetEOL1(self): + tok = dns.tokenizer.Tokenizer('\n') + t = tok.get_eol() + self.failUnless(t == '\n') + + def testGetEOL2(self): + tok = dns.tokenizer.Tokenizer('') + t = tok.get_eol() + self.failUnless(t == '') + + def testEscapedDelimiter1(self): + tok = dns.tokenizer.Tokenizer(r'ch\ ld') + t = tok.get() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ ld') + + def testEscapedDelimiter2(self): + tok = dns.tokenizer.Tokenizer(r'ch\032ld') + t = tok.get() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\032ld') + + def testEscapedDelimiter3(self): + tok = dns.tokenizer.Tokenizer(r'ch\ild') + t = tok.get() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ild') + + def testEscapedDelimiter1u(self): + tok = dns.tokenizer.Tokenizer(r'ch\ ld') + t = tok.get().unescape() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch ld') + + def testEscapedDelimiter2u(self): + tok = dns.tokenizer.Tokenizer(r'ch\032ld') + t = tok.get().unescape() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == 'ch ld') + + def testEscapedDelimiter3u(self): + tok = dns.tokenizer.Tokenizer(r'ch\ild') + t = tok.get().unescape() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'child') + +if __name__ == '__main__': + unittest.main() diff --git a/tests/dns/test_update.py b/third_party/dnspython/tests/update.py similarity index 78% rename from tests/dns/test_update.py rename to third_party/dnspython/tests/update.py index 73dcd43b..92ddb565 100644 --- a/tests/dns/test_update.py +++ b/third_party/dnspython/tests/update.py @@ -1,5 +1,4 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2003-2007 Nominum, Inc. +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -16,9 +15,9 @@ import unittest -import linkcheck.dns.update -import linkcheck.dns.rdata -import linkcheck.dns.rdataset +import dns.update +import dns.rdata +import dns.rdataset goodhex = '0001 2800 0001 0005 0007 0000' \ '076578616d706c6500 0006 0001' \ @@ -58,10 +57,10 @@ blaz ANY A blaz2 ANY ANY """ -class TestUpdate (unittest.TestCase): +class UpdateTestCase(unittest.TestCase): def test_to_wire1(self): - update = linkcheck.dns.update.Update('example') + update = dns.update.Update('example') update.id = 1 update.present('foo') update.present('foo', 'a') @@ -73,10 +72,10 @@ class TestUpdate (unittest.TestCase): update.delete('bar', 'a', '10.0.0.4') update.delete('blaz','a') update.delete('blaz2') - self.assertEqual(update.to_wire(), goodwire) + self.failUnless(update.to_wire() == goodwire) def test_to_wire2(self): - update = linkcheck.dns.update.Update('example') + update = dns.update.Update('example') update.id = 1 update.present('foo') update.present('foo', 'a') @@ -84,14 +83,14 @@ class TestUpdate (unittest.TestCase): update.absent('blaz2') update.absent('blaz2', 'a') update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') - update.add('bar', 300, linkcheck.dns.rdata.from_text(1, 1, '10.0.0.3')) + update.add('bar', 300, dns.rdata.from_text(1, 1, '10.0.0.3')) update.delete('bar', 'a', '10.0.0.4') update.delete('blaz','a') update.delete('blaz2') - self.assertEqual(update.to_wire(), goodwire) + self.failUnless(update.to_wire() == goodwire) def test_to_wire3(self): - update = linkcheck.dns.update.Update('example') + update = dns.update.Update('example') update.id = 1 update.present('foo') update.present('foo', 'a') @@ -99,14 +98,17 @@ class TestUpdate (unittest.TestCase): update.absent('blaz2') update.absent('blaz2', 'a') update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') - update.add('bar', linkcheck.dns.rdataset.from_text(1, 1, 300, '10.0.0.3')) + update.add('bar', dns.rdataset.from_text(1, 1, 300, '10.0.0.3')) update.delete('bar', 'a', '10.0.0.4') update.delete('blaz','a') update.delete('blaz2') - self.assertEqual(update.to_wire(), goodwire) + self.failUnless(update.to_wire() == goodwire) def test_from_text1(self): - update = linkcheck.dns.message.from_text(update_text) - w = update.to_wire(origin=linkcheck.dns.name.from_text('example'), + update = dns.message.from_text(update_text) + w = update.to_wire(origin=dns.name.from_text('example'), want_shuffle=False) - self.assertEqual(w, goodwire) + self.failUnless(w == goodwire) + +if __name__ == '__main__': + unittest.main() diff --git a/third_party/dnspython/tests/zone.py b/third_party/dnspython/tests/zone.py new file mode 100644 index 00000000..31e7405b --- /dev/null +++ b/third_party/dnspython/tests/zone.py @@ -0,0 +1,389 @@ +# Copyright (C) 2003-2007, 2009-2011 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 cStringIO +import filecmp +import os +import unittest + +import dns.exception +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset +import dns.zone + +example_text = """$TTL 3600 +$ORIGIN example. +@ soa foo bar 1 2 3 4 5 +@ ns ns1 +@ ns ns2 +ns1 a 10.0.0.1 +ns2 a 10.0.0.2 +$TTL 300 +$ORIGIN foo.example. +bar mx 0 blaz +""" + +example_text_output = """@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +""" + +something_quite_similar = """@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.3 +""" + +something_different = """@ 3600 IN SOA fooa bar 1 2 3 4 5 +@ 3600 IN NS ns11 +@ 3600 IN NS ns21 +bar.fooa 300 IN MX 0 blaz.fooa +ns11 3600 IN A 10.0.0.11 +ns21 3600 IN A 10.0.0.21 +""" + +ttl_example_text = """$TTL 1h +$ORIGIN example. +@ soa foo bar 1 2 3 4 5 +@ ns ns1 +@ ns ns2 +ns1 1d1s a 10.0.0.1 +ns2 1w1D1h1m1S a 10.0.0.2 +""" + +no_soa_text = """$TTL 1h +$ORIGIN example. +@ ns ns1 +@ ns ns2 +ns1 1d1s a 10.0.0.1 +ns2 1w1D1h1m1S a 10.0.0.2 +""" + +no_ns_text = """$TTL 1h +$ORIGIN example. +@ soa foo bar 1 2 3 4 5 +""" + +include_text = """$INCLUDE "example" +""" + +bad_directive_text = """$FOO bar +$ORIGIN example. +@ soa foo bar 1 2 3 4 5 +@ ns ns1 +@ ns ns2 +ns1 1d1s a 10.0.0.1 +ns2 1w1D1h1m1S a 10.0.0.2 +""" + +_keep_output = False + +class ZoneTestCase(unittest.TestCase): + + def testFromFile1(self): + z = dns.zone.from_file('example', 'example') + ok = False + try: + z.to_file('example1.out', nl='\x0a') + ok = filecmp.cmp('example1.out', 'example1.good') + finally: + if not _keep_output: + os.unlink('example1.out') + self.failUnless(ok) + + def testFromFile2(self): + z = dns.zone.from_file('example', 'example', relativize=False) + ok = False + try: + z.to_file('example2.out', relativize=False, nl='\x0a') + ok = filecmp.cmp('example2.out', 'example2.good') + finally: + if not _keep_output: + os.unlink('example2.out') + self.failUnless(ok) + + def testFromText(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + f = cStringIO.StringIO() + names = z.nodes.keys() + names.sort() + for n in names: + print >> f, z[n].to_text(n) + self.failUnless(f.getvalue() == example_text_output) + + def testTorture1(self): + # + # Read a zone containing all our supported RR types, and + # for each RR in the zone, convert the rdata into wire format + # and then back out, and see if we get equal rdatas. + # + f = cStringIO.StringIO() + o = dns.name.from_text('example.') + z = dns.zone.from_file('example', o) + for (name, node) in z.iteritems(): + for rds in node: + for rd in rds: + f.seek(0) + f.truncate() + rd.to_wire(f, origin=o) + wire = f.getvalue() + rd2 = dns.rdata.from_wire(rds.rdclass, rds.rdtype, + wire, 0, len(wire), + origin = o) + self.failUnless(rd == rd2) + + def testEqual(self): + z1 = dns.zone.from_text(example_text, 'example.', relativize=True) + z2 = dns.zone.from_text(example_text_output, 'example.', + relativize=True) + self.failUnless(z1 == z2) + + def testNotEqual1(self): + z1 = dns.zone.from_text(example_text, 'example.', relativize=True) + z2 = dns.zone.from_text(something_quite_similar, 'example.', + relativize=True) + self.failUnless(z1 != z2) + + def testNotEqual2(self): + z1 = dns.zone.from_text(example_text, 'example.', relativize=True) + z2 = dns.zone.from_text(something_different, 'example.', + relativize=True) + self.failUnless(z1 != z2) + + def testNotEqual3(self): + z1 = dns.zone.from_text(example_text, 'example.', relativize=True) + z2 = dns.zone.from_text(something_different, 'example2.', + relativize=True) + self.failUnless(z1 != z2) + + def testFindRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rds = z.find_rdataset('@', 'soa') + exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') + self.failUnless(rds == exrds) + + def testFindRdataset2(self): + def bad(): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rds = z.find_rdataset('@', 'loc') + self.failUnlessRaises(KeyError, bad) + + def testFindRRset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rrs = z.find_rrset('@', 'soa') + exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') + self.failUnless(rrs == exrrs) + + def testFindRRset2(self): + def bad(): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rrs = z.find_rrset('@', 'loc') + self.failUnlessRaises(KeyError, bad) + + def testGetRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rds = z.get_rdataset('@', 'soa') + exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') + self.failUnless(rds == exrds) + + def testGetRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rds = z.get_rdataset('@', 'loc') + self.failUnless(rds == None) + + def testGetRRset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rrs = z.get_rrset('@', 'soa') + exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') + self.failUnless(rrs == exrrs) + + def testGetRRset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rrs = z.get_rrset('@', 'loc') + self.failUnless(rrs == None) + + def testReplaceRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rdataset = dns.rdataset.from_text('in', 'ns', 300, 'ns3', 'ns4') + z.replace_rdataset('@', rdataset) + rds = z.get_rdataset('@', 'ns') + self.failUnless(rds is rdataset) + + def testReplaceRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rdataset = dns.rdataset.from_text('in', 'txt', 300, '"foo"') + z.replace_rdataset('@', rdataset) + rds = z.get_rdataset('@', 'txt') + self.failUnless(rds is rdataset) + + def testDeleteRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + z.delete_rdataset('@', 'ns') + rds = z.get_rdataset('@', 'ns') + self.failUnless(rds is None) + + def testDeleteRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + z.delete_rdataset('ns1', 'a') + node = z.get_node('ns1') + self.failUnless(node is None) + + def testNodeFindRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') + self.failUnless(rds == exrds) + + def testNodeFindRdataset2(self): + def bad(): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + self.failUnlessRaises(KeyError, bad) + + def testNodeGetRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') + self.failUnless(rds == exrds) + + def testNodeGetRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + self.failUnless(rds == None) + + def testNodeDeleteRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + self.failUnless(rds == None) + + def testNodeDeleteRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + self.failUnless(rds == None) + + def testIterateRdatasets(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + ns = [n for n, r in z.iterate_rdatasets('A')] + ns.sort() + self.failUnless(ns == [dns.name.from_text('ns1', None), + dns.name.from_text('ns2', None)]) + + def testIterateAllRdatasets(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + ns = [n for n, r in z.iterate_rdatasets()] + ns.sort() + self.failUnless(ns == [dns.name.from_text('@', None), + dns.name.from_text('@', None), + dns.name.from_text('bar.foo', None), + dns.name.from_text('ns1', None), + dns.name.from_text('ns2', None)]) + + def testIterateRdatas(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + l = list(z.iterate_rdatas('A')) + l.sort() + exl = [(dns.name.from_text('ns1', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2'))] + self.failUnless(l == exl) + + def testIterateAllRdatas(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2'))] + self.failUnless(l == exl) + + def testTTLs(self): + z = dns.zone.from_text(ttl_example_text, 'example.', relativize=True) + n = z['@'] + rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + self.failUnless(rds.ttl == 3600) + n = z['ns1'] + rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + self.failUnless(rds.ttl == 86401) + n = z['ns2'] + rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + self.failUnless(rds.ttl == 694861) + + def testNoSOA(self): + def bad(): + z = dns.zone.from_text(no_soa_text, 'example.', + relativize=True) + self.failUnlessRaises(dns.zone.NoSOA, bad) + + def testNoNS(self): + def bad(): + z = dns.zone.from_text(no_ns_text, 'example.', + relativize=True) + self.failUnlessRaises(dns.zone.NoNS, bad) + + def testInclude(self): + z1 = dns.zone.from_text(include_text, 'example.', relativize=True, + allow_include=True) + z2 = dns.zone.from_file('example', 'example.', relativize=True) + self.failUnless(z1 == z2) + + def testBadDirective(self): + def bad(): + z = dns.zone.from_text(bad_directive_text, 'example.', + relativize=True) + self.failUnlessRaises(dns.exception.SyntaxError, bad) + +if __name__ == '__main__': + unittest.main()