summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoruberj <uberj@onid.orst.edu>2012-05-23 10:44:04 -0700
committeruberj <uberj@onid.orst.edu>2012-09-21 09:12:03 -0700
commitad792be4a666ee0a487188f3979423588945fa19 (patch)
treeeed863483bf604ad3877cbaf1884e3e0bd0beff2
parentee8ef8bef9d6b01bc2c66fa9aa49651f626ef306 (diff)
downloaddnspython-ad792be4a666ee0a487188f3979423588945fa19.tar.gz
This patch adds the ability to parse '$GENERATE' statements. See tests for examples.
-rw-r--r--.gitignore1
-rw-r--r--dns/grange.py65
-rw-r--r--dns/zone.py165
-rw-r--r--tests/generate.py499
-rw-r--r--tests/grange.py95
5 files changed, 825 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 5592c97..ae6319f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ html
html.zip
html.tar.gz
tests/*.out
+*.pyc
diff --git a/dns/grange.py b/dns/grange.py
new file mode 100644
index 0000000..2d4799d
--- /dev/null
+++ b/dns/grange.py
@@ -0,0 +1,65 @@
+# 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.
+
+"""DNS GENERATE range conversion."""
+
+import dns
+
+def from_text(text):
+ """Convert the text form of a range in a GENERATE statement to an
+ integer.
+
+ @param text: the textual range
+ @type text: string
+ @return range: The start, stop and step values.
+ @type range: tuple
+ """
+ # TODO, figure out the bounds on start, stop and step.
+
+ import pdb
+ step = 1
+ cur = ''
+ state = 0
+ # state 0 1 2 3 4
+ # x - y / z
+ for c in text:
+ if c == '-' and state == 0:
+ start = int(cur)
+ cur = ''
+ state = 2
+ elif c == '/':
+ stop = int(cur)
+ cur = ''
+ state = 4
+ elif c.isdigit():
+ cur += c
+ else:
+ raise dns.exception.SyntaxError("Could not parse %s" % (c))
+
+ if state in (1, 3):
+ raise dns.exception.SyntaxError
+
+ if state == 2:
+ stop = int(cur)
+
+ if state == 4:
+ step = int(cur)
+
+ assert step >= 1
+ assert start >= 0
+ assert start <= stop
+ # TODO, can start == stop?
+
+ return (start, stop, step)
diff --git a/dns/zone.py b/dns/zone.py
index 404f818..9efcf43 100644
--- a/dns/zone.py
+++ b/dns/zone.py
@@ -18,6 +18,7 @@
from __future__ import generators
import sys
+import re
import dns.exception
import dns.name
@@ -28,6 +29,8 @@ import dns.rdata
import dns.rrset
import dns.tokenizer
import dns.ttl
+import dns.grange
+
class BadZone(dns.exception.DNSException):
"""The zone is malformed."""
@@ -641,6 +644,166 @@ class _MasterReader(object):
rds = n.find_rdataset(rdclass, rdtype, covers, True)
rds.add(rd, ttl)
+ def _parse_modify(self, side):
+ # Here we catch everything in '{' '}' in a group so we can replace it
+ # with ''.
+ is_generate1 = re.compile("^.*\$({(\+|-?)(\d+),(\d+),(.)}).*$")
+ is_generate2 = re.compile("^.*\$({(\+|-?)(\d+)}).*$")
+ is_generate3 = re.compile("^.*\$({(\+|-?)(\d+),(\d+)}).*$")
+ # Sometimes there are modifiers in the hostname. These come after
+ # the dollar sign. They are in the form: ${offset[,width[,base]]}.
+ # Make names
+ g1 = is_generate1.match(side)
+ if g1:
+ mod, sign, offset, width, base = g1.groups()
+ if sign == '':
+ sign = '+'
+ g2 = is_generate2.match(side)
+ if g2:
+ mod, sign, offset = g2.groups()
+ if sign == '':
+ sign = '+'
+ width = 0
+ base = 'd'
+ g3 = is_generate3.match(side)
+ if g3:
+ mod, sign, offset, width = g1.groups()
+ if sign == '':
+ sign = '+'
+ width = g1.groups()[2]
+ base = 'd'
+
+ if not (g1 or g2 or g3):
+ mod = ''
+ sign = '+'
+ offset = 0
+ width = 0
+ base = 'd'
+
+ if base != 'd':
+ raise NotImplemented
+
+ return mod, sign, offset, width, base
+
+ def _generate_line(self):
+ # range lhs [ttl] [class] type rhs [ comment ]
+ """Process one line containing the GENERATE statement from a DNS
+ master file."""
+ if self.current_origin is None:
+ raise UnknownOrigin
+
+ token = self.tok.get()
+ # Range (required)
+ try:
+ start, stop, step = dns.grange.from_text(token.value)
+ token = self.tok.get()
+ if not token.is_identifier():
+ raise dns.exception.SyntaxError
+ except:
+ raise dns.exception.SyntaxError
+
+ # lhs (required)
+ try:
+ lhs = token.value
+ token = self.tok.get()
+ if not token.is_identifier():
+ raise dns.exception.SyntaxError
+ except:
+ raise dns.exception.SyntaxError
+
+ # TTL
+ try:
+ ttl = dns.ttl.from_text(token.value)
+ token = self.tok.get()
+ if not token.is_identifier():
+ raise dns.exception.SyntaxError
+ except dns.ttl.BadTTL:
+ ttl = self.ttl
+ # Class
+ try:
+ rdclass = dns.rdataclass.from_text(token.value)
+ token = self.tok.get()
+ if not token.is_identifier():
+ raise dns.exception.SyntaxError
+ except dns.exception.SyntaxError:
+ raise dns.exception.SyntaxError
+ except:
+ rdclass = self.zone.rdclass
+ if rdclass != self.zone.rdclass:
+ raise dns.exception.SyntaxError("RR class is not zone's class")
+ # Type
+ try:
+ rdtype = dns.rdatatype.from_text(token.value)
+ token = self.tok.get()
+ if not token.is_identifier():
+ raise dns.exception.SyntaxError
+ except:
+ raise dns.exception.SyntaxError("unknown rdatatype '%s'" %
+ token.value)
+
+ # lhs (required)
+ try:
+ rhs = token.value
+ except:
+ raise dns.exception.SyntaxError
+
+
+ lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs)
+ rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs)
+ for i in range(start, stop + 1, step):
+ # +1 because bind is inclusive and python is exclusive
+
+ if lsign == '+':
+ lindex = i + int(loffset)
+ elif lsign == '-':
+ lindex = i - int(loffset)
+
+ if rsign == '-':
+ rindex = i - int(roffset)
+ elif rsign == '+':
+ rindex = i + int(roffset)
+
+ lzfindex = str(lindex).zfill(int(lwidth))
+ rzfindex = str(rindex).zfill(int(rwidth))
+
+
+ name = lhs.replace('$%s' % (lmod), lzfindex)
+ rdata = rhs.replace('$%s' % (rmod), rzfindex)
+
+ self.last_name = dns.name.from_text(name, self.current_origin)
+ name = self.last_name
+ if not name.is_subdomain(self.zone.origin):
+ self._eat_line()
+ return
+ if self.relativize:
+ name = name.relativize(self.zone.origin)
+
+ n = self.zone.nodes.get(name)
+ if n is None:
+ n = self.zone.node_factory()
+ self.zone.nodes[name] = n
+ try:
+ rd = dns.rdata.from_text(rdclass, rdtype, rdata,
+ self.current_origin, False)
+ except dns.exception.SyntaxError:
+ # Catch and reraise.
+ (ty, va) = sys.exc_info()[:2]
+ raise va
+ except:
+ # All exceptions that occur in the processing of rdata
+ # are treated as syntax errors. This is not strictly
+ # correct, but it is correct almost all of the time.
+ # We convert them to syntax errors so that we can emit
+ # helpful filename:line info.
+ (ty, va) = sys.exc_info()[:2]
+ raise dns.exception.SyntaxError("caught exception %s: %s" %
+ (str(ty), str(va)))
+
+ rd.choose_relativity(self.zone.origin, self.relativize)
+ covers = rd.covers()
+ rds = n.find_rdataset(rdclass, rdtype, covers, True)
+ rds.add(rd, ttl)
+
def read(self):
"""Read a DNS master file and build a zone object.
@@ -701,6 +864,8 @@ class _MasterReader(object):
self.tok = dns.tokenizer.Tokenizer(self.current_file,
filename)
self.current_origin = new_origin
+ elif u == '$GENERATE':
+ self._generate_line()
else:
raise dns.exception.SyntaxError("Unknown master file directive '" + u + "'")
continue
diff --git a/tests/generate.py b/tests/generate.py
new file mode 100644
index 0000000..43c5f9a
--- /dev/null
+++ b/tests/generate.py
@@ -0,0 +1,499 @@
+# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose with or without fee is hereby granted,
+# provided that the above copyright notice and this permission notice
+# appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import sys
+sys.path.insert(0, '../') # Force the local project to be *the* dns
+
+import cStringIO
+import filecmp
+import os
+import unittest
+
+import dns.exception
+import dns.rdata
+import dns.rdataclass
+import dns.rdatatype
+import dns.rrset
+import dns.zone
+
+import pprint
+
+pp = pprint.PrettyPrinter(indent=2)
+
+import pdb
+example_text = """$TTL 1h
+$ORIGIN 0.0.192.IN-ADDR.ARPA.
+$GENERATE 1-2 0 CNAME SERVER$.EXAMPLE.
+"""
+
+example_text1 = """$TTL 1h
+$ORIGIN 0.0.192.IN-ADDR.ARPA.
+$GENERATE 1-10 fooo$ CNAME $.0
+"""
+
+example_text2 = """$TTL 1h
+@ 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
+$GENERATE 3-5 foo$ A 10.0.0.$
+"""
+
+example_text3 = """$TTL 1h
+@ 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
+$GENERATE 4-8/2 foo$ A 10.0.0.$
+"""
+
+example_text4 = """$TTL 1h
+@ 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
+$GENERATE 11-13 wp-db${-10,2,d}.services.mozilla.com 0 CNAME SERVER.FOOBAR.
+"""
+
+example_text5 = """$TTL 1h
+@ 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
+$GENERATE 11-13 wp-db${10,2,d}.services.mozilla.com 0 CNAME SERVER.FOOBAR.
+"""
+
+example_text6 = """$TTL 1h
+@ 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
+$GENERATE 11-13 wp-db${+10,2,d}.services.mozilla.com 0 CNAME SERVER.FOOBAR.
+"""
+
+example_text7 = """$TTL 1h
+@ 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
+$GENERATE 11-13 sync${-10}.db IN A 10.10.16.0
+"""
+
+example_text8 = """$TTL 1h
+@ 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
+$GENERATE 11-12 wp-db${-10,2,d} IN A 10.10.16.0
+"""
+
+example_text9 = """$TTL 1h
+@ 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
+$GENERATE 11-12 wp-db${-10,2,d} IN A 10.10.16.0
+$GENERATE 11-13 sync${-10}.db IN A 10.10.16.0
+"""
+example_text10 = """$TTL 1h
+@ 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
+$GENERATE 27-28 $.2 PTR zlb${-26}.oob
+"""
+
+
+class GenerateTestCase(unittest.TestCase):
+
+ def testFromText(self):
+ def bad():
+ z = dns.zone.from_text(example_text, 'example.', relativize=True)
+ self.failUnlessRaises(dns.zone.NoSOA, bad)
+
+ def testFromText1(self):
+ def bad():
+ z = dns.zone.from_text(example_text1, 'example.', relativize=True)
+ self.failUnlessRaises(dns.zone.NoSOA, bad)
+
+ def testIterateAllRdatas2(self):
+ z = dns.zone.from_text(example_text2, 'example.', relativize=True)
+ l = list(z.iterate_rdatas())
+ l.sort()
+ exl = [(dns.name.from_text('@', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns1')),
+ (dns.name.from_text('@', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns2')),
+ (dns.name.from_text('@', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
+ 'foo bar 1 2 3 4 5')),
+ (dns.name.from_text('bar.foo', None),
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
+ '0 blaz.foo')),
+ (dns.name.from_text('ns1', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.1')),
+ (dns.name.from_text('ns2', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.2')),
+ (dns.name.from_text('foo3', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.3')),
+ (dns.name.from_text('foo4', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.4')),
+ (dns.name.from_text('foo5', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.5'))]
+
+ exl.sort()
+ self.failUnless(l == exl)
+
+ def testIterateAllRdatas3(self):
+ z = dns.zone.from_text(example_text3, 'example.', relativize=True)
+ l = list(z.iterate_rdatas())
+ l.sort()
+ exl = [(dns.name.from_text('@', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns1')),
+ (dns.name.from_text('@', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns2')),
+ (dns.name.from_text('@', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
+ 'foo bar 1 2 3 4 5')),
+ (dns.name.from_text('bar.foo', None),
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
+ '0 blaz.foo')),
+ (dns.name.from_text('ns1', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.1')),
+ (dns.name.from_text('ns2', None),
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.2')),
+ (dns.name.from_text('foo4', None), 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.4')),
+ (dns.name.from_text('foo6', None), 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.6')),
+ (dns.name.from_text('foo8', None), 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.8'))]
+ exl.sort()
+ self.failUnless(l == exl)
+ def testGenerate1(self):
+ z = dns.zone.from_text(example_text4, 'example.', relativize=True)
+ l = list(z.iterate_rdatas())
+ l.sort()
+ exl = [(dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns1')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns2')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
+ 'foo bar 1 2 3 4 5')),
+ (dns.name.from_text('bar.foo', None),
+ 300L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
+ '0 blaz.foo')),
+ (dns.name.from_text('ns1', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.1')),
+ (dns.name.from_text('ns2', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.2')),
+
+ (dns.name.from_text('wp-db01.services.mozilla.com', None),
+ 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.')),
+
+ (dns.name.from_text('wp-db02.services.mozilla.com', None),
+ 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.')),
+
+ (dns.name.from_text('wp-db03.services.mozilla.com', None),
+ 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.'))]
+ exl.sort()
+ self.failUnless(l == exl)
+
+ def testGenerate2(self):
+ z = dns.zone.from_text(example_text5, 'example.', relativize=True)
+ l = list(z.iterate_rdatas())
+ l.sort()
+ exl = [(dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns1')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns2')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
+ 'foo bar 1 2 3 4 5')),
+ (dns.name.from_text('bar.foo', None),
+ 300L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
+ '0 blaz.foo')),
+ (dns.name.from_text('ns1', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.1')),
+ (dns.name.from_text('ns2', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.2')),
+
+ (dns.name.from_text('wp-db21.services.mozilla.com', None), 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.')),
+
+ (dns.name.from_text('wp-db22.services.mozilla.com', None), 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.')),
+
+ (dns.name.from_text('wp-db23.services.mozilla.com', None), 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.'))]
+ exl.sort()
+ self.failUnless(l == exl)
+
+ def testGenerate3(self):
+ z = dns.zone.from_text(example_text6, 'example.', relativize=True)
+ l = list(z.iterate_rdatas())
+ l.sort()
+
+ exl = [(dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns1')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns2')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
+ 'foo bar 1 2 3 4 5')),
+ (dns.name.from_text('bar.foo', None),
+ 300L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
+ '0 blaz.foo')),
+ (dns.name.from_text('ns1', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.1')),
+ (dns.name.from_text('ns2', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.2')),
+ (dns.name.from_text('wp-db21.services.mozilla.com', None), 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.')),
+
+ (dns.name.from_text('wp-db22.services.mozilla.com', None), 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.')),
+
+ (dns.name.from_text('wp-db23.services.mozilla.com', None), 0L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME,
+ 'SERVER.FOOBAR.'))]
+ exl.sort()
+ self.failUnless(l == exl)
+
+ def testGenerate4(self):
+ z = dns.zone.from_text(example_text7, 'example.', relativize=True)
+ l = list(z.iterate_rdatas())
+ l.sort()
+ exl = [(dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns1')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns2')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
+ 'foo bar 1 2 3 4 5')),
+ (dns.name.from_text('bar.foo', None),
+ 300L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
+ '0 blaz.foo')),
+ (dns.name.from_text('ns1', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.1')),
+ (dns.name.from_text('ns2', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.2')),
+
+ (dns.name.from_text('sync1.db', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.10.16.0')),
+
+ (dns.name.from_text('sync2.db', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.10.16.0')),
+
+ (dns.name.from_text('sync3.db', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.10.16.0'))]
+ exl.sort()
+ self.failUnless(l == exl)
+
+ def testGenerate6(self):
+ z = dns.zone.from_text(example_text9, 'example.', relativize=True)
+ l = list(z.iterate_rdatas())
+ l.sort()
+ exl = [(dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns1')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns2')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
+ 'foo bar 1 2 3 4 5')),
+ (dns.name.from_text('bar.foo', None),
+ 300L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
+ '0 blaz.foo')),
+ (dns.name.from_text('ns1', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.1')),
+ (dns.name.from_text('ns2', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.2')),
+
+ (dns.name.from_text('wp-db01', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.10.16.0')),
+ (dns.name.from_text('wp-db02', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.10.16.0')),
+
+ (dns.name.from_text('sync1.db', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.10.16.0')),
+
+ (dns.name.from_text('sync2.db', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.10.16.0')),
+
+ (dns.name.from_text('sync3.db', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.10.16.0'))]
+ exl.sort()
+ self.failUnless(l == exl)
+
+ def testGenerate7(self):
+ z = dns.zone.from_text(example_text10, 'example.', relativize=True)
+ l = list(z.iterate_rdatas())
+ l.sort()
+ exl = [(dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns1')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+ 'ns2')),
+ (dns.name.from_text('@', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
+ 'foo bar 1 2 3 4 5')),
+ (dns.name.from_text('bar.foo', None),
+ 300L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
+ '0 blaz.foo')),
+ (dns.name.from_text('ns1', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.1')),
+ (dns.name.from_text('ns2', None),
+ 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
+ '10.0.0.2')),
+
+ (dns.name.from_text('27.2', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.PTR,
+ 'zlb1.oob')),
+
+ (dns.name.from_text('28.2', None), 3600L,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.PTR,
+ 'zlb2.oob'))]
+
+ exl.sort()
+ self.failUnless(l == exl)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/grange.py b/tests/grange.py
new file mode 100644
index 0000000..cbfc896
--- /dev/null
+++ b/tests/grange.py
@@ -0,0 +1,95 @@
+# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose with or without fee is hereby granted,
+# provided that the above copyright notice and this permission notice
+# appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import sys
+sys.path.insert(0, '../')
+
+import cStringIO
+import filecmp
+import os
+import unittest
+
+import dns
+import dns.exception
+import dns.grange
+
+import pdb
+
+
+
+class GRangeTestCase(unittest.TestCase):
+
+ def testFromText1(self):
+ start, stop, step = dns.grange.from_text('1-1')
+ self.assertEqual(start, 1)
+ self.assertEqual(stop, 1)
+ self.assertEqual(step, 1)
+
+ def testFromText2(self):
+ start, stop, step = dns.grange.from_text('1-4')
+ self.assertEqual(start, 1)
+ self.assertEqual(stop, 4)
+ self.assertEqual(step, 1)
+
+ def testFromText3(self):
+ start, stop, step = dns.grange.from_text('4-255')
+ self.assertEqual(start, 4)
+ self.assertEqual(stop, 255)
+ self.assertEqual(step, 1)
+
+ def testFromText4(self):
+ start, stop, step = dns.grange.from_text('1-1/1')
+ self.assertEqual(start, 1)
+ self.assertEqual(stop, 1)
+ self.assertEqual(step, 1)
+
+ def testFromText5(self):
+ start, stop, step = dns.grange.from_text('1-4/2')
+ self.assertEqual(start, 1)
+ self.assertEqual(stop, 4)
+ self.assertEqual(step, 2)
+
+ def testFromText6(self):
+ start, stop, step = dns.grange.from_text('4-255/77')
+ self.assertEqual(start, 4)
+ self.assertEqual(stop, 255)
+ self.assertEqual(step, 77)
+
+ def testFailFromText1(self):
+ def bad():
+ start = 2
+ stop = 1
+ step = 1
+ dns.grange.from_text('{0}-{1}/{2}'.format(start, stop, step))
+ self.assertRaises(AssertionError, bad)
+
+ def testFailFromText2(self):
+ def bad():
+ start = '-1'
+ stop = 3
+ step = 1
+ dns.grange.from_text('{0}-{1}/{2}'.format(start, stop, step))
+ self.assertRaises(dns.exception.SyntaxError, bad)
+
+ def testFailFromText2(self):
+ def bad():
+ start = 1
+ stop = 4
+ step = '-2'
+ dns.grange.from_text('{0}-{1}/{2}'.format(start, stop, step))
+ self.assertRaises(dns.exception.SyntaxError, bad)
+
+if __name__ == '__main__':
+ unittest.main()