Move dnspython module into third_party directory.

This commit is contained in:
Bastian Kleineidam 2011-05-24 20:18:58 +02:00
parent dcd1318bce
commit e1f724908d
122 changed files with 4740 additions and 3836 deletions

View file

@ -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

View file

@ -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:

View file

@ -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()

View file

@ -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 = [

View file

@ -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)]

View file

@ -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))

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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',

View file

@ -1 +0,0 @@
# -*- coding: iso-8859-1 -*-

View file

@ -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")

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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'))

View file

@ -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)

View file

@ -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

View file

@ -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',
]

372
third_party/dnspython/dns/dnssec.py vendored Normal file
View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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()

View file

@ -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

View file

@ -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

67
third_party/dnspython/dns/hash.py vendored Normal file
View file

@ -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()]

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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 '<DNS message, ID %r>' % self.id
return '<DNS message, ID ' + `self.id` + '>'
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:

View file

@ -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

View file

@ -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)

View file

@ -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.

View file

@ -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

View file

@ -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()

View file

@ -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)

View file

@ -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 '<DNS ' + linkcheck.dns.rdataclass.to_text(self.rdclass) + ' ' + \
linkcheck.dns.rdatatype.to_text(self.rdtype) + ctext + ' rdata: ' + \
ctext = '(' + dns.rdatatype.to_text(covers) + ')'
return '<DNS ' + dns.rdataclass.to_text(self.rdclass) + ' ' + \
dns.rdatatype.to_text(self.rdtype) + ctext + ' rdata: ' + \
str(self) + '>'
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)

View file

@ -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

View file

@ -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 '<DNS ' + linkcheck.dns.rdataclass.to_text(self.rdclass) + ' ' + \
linkcheck.dns.rdatatype.to_text(self.rdtype) + ctext + ' rdataset>'
ctext = '(' + dns.rdatatype.to_text(self.covers) + ')'
return '<DNS ' + dns.rdataclass.to_text(self.rdclass) + ' ' + \
dns.rdatatype.to_text(self.rdtype) + ctext + ' rdataset>'
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)

View file

@ -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

View file

@ -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"

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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))

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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:

View file

@ -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"""

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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',

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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],

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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,

View file

@ -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',
]

View file

@ -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)

View file

@ -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()

View file

@ -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()

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -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 ' + str(self.name) + ' ' + \
linkcheck.dns.rdataclass.to_text(self.rdclass) + ' ' + \
linkcheck.dns.rdatatype.to_text(self.rdtype) + ctext + dtext + ' RRset>'
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)

263
third_party/dnspython/dns/set.py vendored Normal file
View file

@ -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

View file

@ -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 = '<string>'
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)

View file

@ -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])

View file

@ -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

View file

@ -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
"""

Some files were not shown because too many files have changed in this diff Show more