s4-python: import a copy of the python dns library
authorAndrew Tridgell <tridge@samba.org>
Fri, 5 Mar 2010 00:45:40 +0000 (11:45 +1100)
committerAndrew Tridgell <tridge@samba.org>
Fri, 5 Mar 2010 00:54:36 +0000 (11:54 +1100)
This library is not installed on enough systems for us to rely
on it being available. We use the system copy if possible, and
fallback to this local copy

Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>

114 files changed:
source4/scripting/python/samba_external/README [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/ChangeLog [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/LICENSE [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/PKG-INFO [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/README [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/TODO [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/__init__.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/dnssec.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/e164.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/edns.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/entropy.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/exception.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/flags.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/inet.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/ipv4.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/ipv6.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/message.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/name.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/namedict.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/node.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/opcode.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/query.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rcode.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdata.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdataclass.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdataset.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdatatype.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/AFSDB.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/CERT.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/CNAME.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DLV.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DNAME.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DNSKEY.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DS.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/GPOS.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/HINFO.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/HIP.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/ISDN.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/KEY.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/LOC.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/MX.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NS.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC3.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NXT.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/PTR.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RP.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RRSIG.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RT.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SIG.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SOA.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SPF.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SSHFP.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/TXT.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/X25.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/__init__.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/A.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/AAAA.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/APL.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/DHCID.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/IPSECKEY.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/KX.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NAPTR.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NSAP.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NSAP_PTR.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/PX.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/SRV.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/WKS.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/__init__.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/__init__.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/dsbase.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/keybase.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/mxbase.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/nsbase.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/sigbase.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rdtypes/txtbase.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/renderer.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/resolver.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/reversename.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/rrset.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/set.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/tokenizer.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/tsig.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/tsigkeyring.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/ttl.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/update.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/version.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/dns/zone.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/examples/ddns.py [new file with mode: 0755]
source4/scripting/python/samba_external/dnspython/examples/e164.py [new file with mode: 0755]
source4/scripting/python/samba_external/dnspython/examples/mx.py [new file with mode: 0755]
source4/scripting/python/samba_external/dnspython/examples/name.py [new file with mode: 0755]
source4/scripting/python/samba_external/dnspython/examples/reverse.py [new file with mode: 0755]
source4/scripting/python/samba_external/dnspython/examples/reverse_name.py [new file with mode: 0755]
source4/scripting/python/samba_external/dnspython/examples/xfr.py [new file with mode: 0755]
source4/scripting/python/samba_external/dnspython/setup.py [new file with mode: 0755]
source4/scripting/python/samba_external/dnspython/tests/Makefile [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/bugs.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/example [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/example1.good [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/example2.good [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/flags.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/message.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/name.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/namedict.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/ntoaaton.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/rdtypeandclass.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/resolver.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/rrset.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/set.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/tokenizer.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/update.py [new file with mode: 0644]
source4/scripting/python/samba_external/dnspython/tests/zone.py [new file with mode: 0644]

diff --git a/source4/scripting/python/samba_external/README b/source4/scripting/python/samba_external/README
new file mode 100644 (file)
index 0000000..d6a4dec
--- /dev/null
@@ -0,0 +1,4 @@
+This directory is for external python libraries that may not be
+installed on the local system. We always should try to use the
+system version of the library if possible, then use the Samba
+supplied copy if the system copy is unavailable
diff --git a/source4/scripting/python/samba_external/dnspython/ChangeLog b/source4/scripting/python/samba_external/dnspython/ChangeLog
new file mode 100644 (file)
index 0000000..f5a74da
--- /dev/null
@@ -0,0 +1,1023 @@
+2010-01-13  Bob Halley  <halley@dnspython.org>
+
+       * dns/dnssec.py: Added RSASHA256 and RSASHA512 codepoints; added
+         other missing codepoints to _algorithm_by_text.
+
+2010-01-12  Bob Halley  <halley@dnspython.org>
+
+       * Escapes in masterfiles now work correctly.  Previously they were
+         only working correctly when the text involved was part of a domain
+         name.
+
+       * dns/tokenizer.py: The tokenizer's get() method now returns Token
+         objects, not (type, text) tuples.
+
+2009-11-13  Bob Halley  <halley@dnspython.org>
+
+       * Support has been added for hmac-sha1, hmac-sha224, hmac-sha256,
+         hmac-sha384 and hmac-sha512.  Thanks to Kevin Chen for a
+         thoughtful, high quality patch.
+
+       * dns/update.py (Update::present): A zero TTL was not added if
+         present() was called with a single rdata, causing _add() to be
+         unhappy.  Thanks to Eugene Kim for reporting the problem and
+         submitting a patch.
+
+       * dns/entropy.py: Use os.urandom() if present.  Don't seed until
+         someone wants randomness.
+
+2009-09-16  Bob Halley  <halley@dnspython.org>
+
+       * dns/entropy.py: The entropy module needs locking in order to be
+         used safely in a multithreaded environment.  Thanks to Beda Kosata
+         for reporting the problem.
+
+2009-07-27  Bob Halley  <halley@dnspython.org>
+
+       * dns/query.py (xfr): The socket was not set to nonblocking mode.
+         Thanks to Erik Romijn for reporting this problem.
+
+2009-07-23  Bob Halley  <halley@dnspython.org>
+
+       * dns/rdtypes/IN/SRV.py (SRV._cmp): SRV records were compared
+         incorrectly due to a cut-and-paste error.  Thanks to Tommie
+         Gannert for reporting this bug.
+
+       * dns/e164.py (query): The resolver parameter was not used.
+         Thanks to Matías Bellone for reporting this bug.
+
+2009-06-23  Bob Halley  <halley@dnspython.org>
+
+       * dns/entropy.py (EntropyPool.__init__): open /dev/random unbuffered;
+         there's no need to consume more randomness than we need.  Thanks
+         to Brian Wellington for the patch.
+
+2009-06-19  Bob Halley  <halley@dnspython.org>
+
+       * (Version 1.7.1 released)
+
+2009-06-19  Bob Halley  <halley@dnspython.org>
+
+       * DLV.py was omitted from the kit
+
+       * Negative prerequisites were not handled correctly in _get_section().
+
+2009-06-19  Bob Halley  <halley@dnspython.org>
+
+       * (Version 1.7.0 released)
+
+2009-06-19  Bob Halley  <halley@dnspython.org>
+
+       * On Windows, the resolver set the domain incorrectly.  Thanks
+         to Brandon Carpenter for reporting this bug.
+
+        * Added a to_digestable() method to rdata classes; it returns the
+         digestable form (i.e. DNSSEC canonical form) of the rdata.  For
+         most rdata types this is the same uncompressed wire form.  For
+         certain older DNS RR types, however, domain names in the rdata
+         are downcased.
+
+       * Added support for the HIP RR type.
+
+2009-06-18  Bob Halley  <halley@dnspython.org>
+
+       * Added support for the DLV RR type.
+
+       * Added various DNSSEC related constants (e.g. algorithm identifiers,
+         flag values).
+
+       * dns/tsig.py: Added support for BADTRUNC result code.
+
+       * dns/query.py (udp): When checking that addresses are the same,
+         use the binary form of the address in the comparison.  This
+         ensures that we don't treat addresses as different if they have
+         equivalent but differing textual representations.  E.g. "1:00::1"
+         and "1::1" represent the same address but are not textually equal.
+         Thanks to Kim Davies for reporting this bug.
+
+       * The resolver's query() method now has an optional 'source' parameter,
+         allowing the source IP address to be specified.  Thanks to
+         Alexander Lind for suggesting the change and sending a patch.
+
+       * Added NSEC3 and NSEC3PARAM support.
+
+2009-06-17  Bob Halley  <halley@dnspython.org>
+
+        * Fixed NSEC.to_text(), which was only printing the last window.
+          Thanks to Brian Wellington for finding the problem and fixing it.
+
+2009-03-30  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py (xfr): Allow UDP IXFRs.  Use "one_rr_per_rrset" mode when
+          doing IXFR.
+
+2009-03-30  Bob Halley  <halley@dnspython.org>
+
+        * Add "one_rr_per_rrset" mode switch to methods which parse
+          messages from wire format (e.g. dns.message.from_wire(),
+          dns.query.udp(), dns.query.tcp()).  If set, each RR read is
+          placed in its own RRset (instead of being coalesced).
+
+2009-03-30  Bob Halley  <halley@dnspython.org>
+
+        * Added EDNS option support.
+
+2008-10-16  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/ANY/DS.py: The from_text() parser for DS RRs did not
+          allow multiple Base64 chunks.  Thanks to Rakesh Banka for
+          finding this bug and submitting a patch.
+
+2008-10-08  Bob Halley  <halley@dnspython.org>
+
+        * Add entropy module.
+
+        * When validating TSIGs, we need to use the absolute name.
+
+2008-06-03  Bob Halley  <halley@dnspython.org>
+
+        * dns/message.py (Message.set_rcode): The mask used preserved the
+          extended rcode, instead of everything else in ednsflags.
+
+        * dns/message.py (Message.use_edns): ednsflags was not kept
+          coherent with the specified edns version.
+
+2008-02-06  Bob Halley  <halley@dnspython.org>
+
+        * dns/ipv6.py (inet_aton):  We could raise an exception other than
+          dns.exception.SyntaxError in some cases.
+
+        * dns/tsig.py: Raise an exception when the peer has set a non-zero
+          TSIG error.
+
+2007-11-25  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.6.0 released)
+
+2007-11-25  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py (_wait_for): if select() raises an exception due to
+          EINTR, we should just select() again.
+
+2007-06-13  Bob Halley  <halley@dnspython.org>
+
+        * dns/inet.py: Added is_multicast().
+
+        * dns/query.py (udp):  If the queried address is a multicast address, then
+          don't check that the address of the response is the same as the address
+          queried.
+
+2007-05-24  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/IN/NAPTR.py: NAPTR comparisons didn't compare the
+          preference field due to a typo.
+
+2007-02-07  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py: Integrate code submitted by Paul Marks to
+          determine whether a Windows NIC is enabled.  The way dnspython
+          used to do this does not work on Windows Vista.
+
+2006-12-10  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.5.0 released)
+
+2006-11-03  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/IN/DHCID.py: Added support for the DHCID RR type.
+
+2006-11-02  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py (udp): Messages from unexpected sources can now be
+          ignored by setting ignore_unexpected to True.
+
+2006-10-31  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py (udp): When raising UnexpectedSource, add more
+          detail about what went wrong to the exception.
+
+2006-09-22  Bob Halley  <halley@dnspython.org>
+
+        * dns/message.py (Message.use_edns): add reasonable defaults for
+          the ednsflags, payload, and request_payload parameters.
+
+        * dns/message.py (Message.want_dnssec): add a convenience method for
+          enabling/disabling the "DNSSEC desired" flag in requests.
+
+        * dns/message.py (make_query): add "use_edns" and "want_dnssec"
+          parameters.
+
+2006-08-17  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Resolver.read_resolv_conf): If /etc/resolv.conf
+          doesn't exist, just use the default resolver configuration (i.e.
+          the same thing we would have used if resolv.conf had existed and
+          been empty).
+
+2006-07-26  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Resolver._config_win32_fromkey): fix
+          cut-and-paste error where we passed the wrong variable to
+          self._config_win32_search().  Thanks to David Arnold for finding
+          the bug and submitting a patch.
+
+2006-07-20  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Answer): Add more support for the sequence
+          protocol, forwarding requests to the answer object's rrset.
+          E.g. "for a in answer" is equivalent to "for a in answer.rrset",
+          "answer[i]" is equivalent to "answer.rrset[i]", and
+          "answer[i:j]" is equivalent to "answer.rrset[i:j]".
+
+2006-07-19  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py (xfr): Add IXFR support.
+
+2006-06-22  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/IN/IPSECKEY.py: Added support for the IPSECKEY RR type.
+
+2006-06-21  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/ANY/SPF.py: Added support for the SPF RR type.
+
+2006-06-02  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.4.0 released)
+
+2006-04-25  Bob Halley  <halley@dnspython.org>
+
+        * dns/rrset.py (RRset.to_rdataset): Added a convenience method
+          to convert an rrset into an rdataset.
+
+2006-03-27  Bob Halley  <halley@dnspython.org>
+
+        * Added dns.e164.query().  This function can be used to look for
+          NAPTR RRs for a specified number in several domains, e.g.:
+
+                dns.e164.query('16505551212',
+                               ['e164.dnspython.org.', 'e164.arpa.'])
+
+2006-03-26  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Resolver.query): The resolver deleted from
+          a list while iterating it, which makes the iterator unhappy.
+
+2006-03-17  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Resolver.query): The resolver needlessly
+          delayed responses for successful queries.
+
+2006-01-18  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdata.py: added a validate() method to the rdata class.  If
+          you change an rdata by assigning to its fields, it is a good
+          idea to call validate() when you are done making changes.
+          For example, if 'r' is an MX record and then you execute:
+
+                r.preference = 100000   # invalid, because > 65535
+                r.validate()
+
+          The validation will fail and an exception will be raised.
+
+2006-01-11  Bob Halley  <halley@dnspython.org>
+
+        * dns/ttl.py: TTLs are now bounds checked to be within the closed
+          interval [0, 2^31 - 1].
+
+        * The BIND 8 TTL syntax is now accepted in the SOA refresh, retry,
+          expire, and minimum fields, and in the original_ttl field of
+          SIG and RRSIG records.
+
+2006-01-04  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py: The windows registry irritatingly changes the
+          list element delimiter in between ' ' and ',' (and vice-versa)
+          in various versions of windows.  We now cope by always looking
+          for either one (' ' first).
+
+2005-12-27  Bob Halley  <halley@dnspython.org>
+
+        * dns/e164.py: Added routines to convert between E.164 numbers and
+          their ENUM domain name equivalents.
+
+        * dns/reversename.py: Added routines to convert between IPv4 and
+          IPv6 addresses and their DNS reverse-map equivalents.
+
+2005-12-18  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/ANY/LOC.py (_tuple_to_float): The sign was lost when
+          converting a tuple into a float, which broke conversions of
+          south latitudes and west longitudes.
+
+2005-11-17  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py: The 'origin' parameter to from_text() and from_file()
+          is now optional.  If not specified, dnspython will use the
+          first $ORIGIN in the text as the zone's origin.
+
+        * dns/zone.py: Sanity checks of the zone's origin node can now
+          be disabled.
+
+2005-11-12  Bob Halley  <halley@dnspython.org>
+
+        * dns/name.py: Preliminary Unicode support has been added for
+          domain names.  Running dns.name.from_text() on a Unicode string
+          will now encode each label using the IDN ACE encoding.  The
+          to_unicode() method may be used to convert a dns.name.Name with
+          IDN ACE labels back into a Unicode string.  This functionality
+          requires Python 2.3 or greater.
+
+2005-10-31  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.3.5 released)
+
+2005-10-12  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py: Zone.iterate_rdatasets() and Zone.iterate_rdatas()
+          did not have a default rdtype of dns.rdatatype.ANY as their
+          docstrings said they did.  They do now.
+
+2005-10-06  Bob Halley  <halley@dnspython.org>
+
+        * dns/name.py: Added the parent() method, which returns the
+          parent of a name.
+
+2005-10-01  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py: Added zone_for_name() helper, which returns
+          the name of the zone which contains the specified name.
+
+        * dns/resolver.py: Added get_default_resolver(), which returns
+          the default resolver, initializing it if necessary.
+
+2005-09-29  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Resolver._compute_timeout): If time goes
+          backwards a little bit, ignore it.
+
+2005-07-31  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.3.4 released)
+
+2005-07-31  Bob Halley  <halley@dnspython.org>
+
+        * dns/message.py (make_response): Trying to respond to a response
+          threw a NameError while trying to throw a FormErr since it used
+          the wrong name for the FormErr exception.
+
+        * dns/query.py (_connect): We needed to ignore EALREADY too.
+
+        * dns/query.py: Optional "source" and "source_port" parameters
+          have been added to udp(), tcp(), and xfr().  Thanks to Ralf
+          Weber for suggesting the change and providing a patch.
+
+2005-06-05  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py: The requirement that the "where" parameter be
+          an IPv4 or IPv6 address is now documented.
+
+2005-06-04  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py: The resolver now does exponential backoff
+          each time it runs through all of the nameservers.
+
+        * dns/resolver.py: rcodes which indicate a nameserver is likely
+          to be a "permanent failure" for a query cause the nameserver
+          to be removed from the mix for that query.
+
+2005-01-30  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.3.3 released)
+
+2004-10-25  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/ANY/TXT.py (TXT.from_text): The masterfile parser
+        incorrectly rejected TXT records where a value was not quoted.
+
+2004-10-11  Bob Halley  <halley@dnspython.org>
+
+        * dns/message.py: Added make_response(), which creates a skeletal
+        response for the specified query.  Added opcode() and set_opcode()
+        convenience methods to the Message class.  Added the request_payload
+        attribute to the Message class.
+
+2004-10-10  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py (from_xfr): dns.zone.from_xfr() in relativization
+        mode incorrectly set zone.origin to the empty name.
+
+2004-09-02  Bob Halley  <halley@dnspython.org>
+
+        * dns/name.py (Name.to_wire): The 'file' parameter to
+        Name.to_wire() is now optional; if omitted, the wire form will
+        be returned as the value of the function.
+
+2004-08-14  Bob Halley  <halley@dnspython.org>
+
+        * dns/message.py (Message.find_rrset): find_rrset() now uses an
+        index, vastly improving the from_wire() performance of large
+        messages such as zone transfers.
+
+2004-08-07  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.3.2 released)
+
+2004-08-04  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py: sending queries to a nameserver via IPv6 now
+        works.
+
+        * dns/inet.py (af_for_address): Add af_for_address(), which looks
+        at a textual-form address and attempts to determine which address
+        family it is.
+
+        * dns/query.py: the default for the 'af' parameter of the udp(),
+        tcp(), and xfr() functions has been changed from AF_INET to None,
+        which causes dns.inet.af_for_address() to be used to determine the
+        address family.  If dns.inet.af_for_address() can't figure it out,
+        we fall back to AF_INET and hope for the best.
+
+2004-07-31  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/ANY/NSEC.py (NSEC.from_text): The NSEC text format
+        does not allow specifying types by number, so we shouldn't either.
+
+        * dns/renderer.py: the renderer module didn't import random,
+        causing an exception to be raised if a query id wasn't provided
+        when a Renderer was created.
+
+        * dns/resolver.py (Resolver.query): the resolver wasn't catching
+        dns.exception.Timeout, so a timeout erroneously caused the whole
+        resolution to fail instead of just going on to the next server.
+
+2004-06-16  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/ANY/LOC.py (LOC.from_text): LOC milliseconds values
+        were converted incorrectly if the length of the milliseconds
+        string was less than 3.
+
+2004-06-06  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.3.1 released)
+
+2004-05-22  Bob Halley  <halley@dnspython.org>
+
+        * dns/update.py (Update.delete): We erroneously specified a
+        "deleting" value of dns.rdatatype.NONE instead of
+        dns.rdataclass.NONE when the thing being deleted was either an
+        Rdataset instance or an Rdata instance.
+
+        * dns/rdtypes/ANY/SSHFP.py: Added support for the proposed SSHFP
+        RR type.
+
+2004-05-14  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdata.py (from_text): The masterfile reader did not
+        accept the unknown RR syntax when used with a known RR type.
+
+2004-05-08  Bob Halley  <halley@dnspython.org>
+
+        * dns/name.py (from_text): dns.name.from_text() did not raise
+        an exception if a backslash escape ended prematurely.
+
+2004-04-09  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py (_MasterReader._rr_line): The masterfile reader
+        erroneously treated lines starting with leading whitespace but
+        not having any RR definition as an error.  It now treats
+        them like a blank line (which is not an error).
+
+2004-04-01  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.3.0 released)
+
+2004-03-19  Bob Halley  <halley@dnspython.org>
+
+        * Added support for new DNSSEC types RRSIG, NSEC, and DNSKEY.
+
+2004-01-16  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py (_connect): Windows returns EWOULDBLOCK instead
+        of EINPROGRESS when trying to connect a nonblocking socket.
+
+2003-11-13  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdtypes/ANY/LOC.py (LOC.to_wire): We encoded and decoded LOC
+        incorrectly, since we were interpreting the values of altitiude,
+        size, hprec, and vprec in meters instead of centimeters.
+
+        * dns/rdtypes/IN/WKS.py (WKS.from_wire): The WKS protocol value is
+        encoded with just one octet, not two!
+
+2003-11-09  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Cache.maybe_clean): The cleaner deleted items
+        from the dictionary while iterating it, causing a RuntimeError
+        to be raised.  Thanks to Mark R. Levinson for the bug report,
+        regression test, and fix.
+
+2003-11-07  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.2.0 released)
+
+2003-11-03  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py (_MasterReader.read): The saved_state now includes
+        the default TTL.
+
+2003-11-01  Bob Halley  <halley@dnspython.org>
+
+        * dns/tokenizer.py (Tokenizer.get): The tokenizer didn't
+        handle escaped delimiters.
+
+2003-10-27  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Resolver.read_resolv_conf): If no nameservers
+        are configured in /etc/resolv.conf, the default nameserver
+        list should be ['127.0.0.1'].
+
+2003-09-08  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Resolver._config_win32_fromkey): We didn't
+        catch WindowsError, which can happen if a key is not defined
+        in the registry.
+
+2003-09-06  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.2.0b1 released)
+
+2003-09-05  Bob Halley  <halley@dnspython.org>
+
+        * dns/query.py: Timeout support has been overhauled to provide
+        timeouts under Python 2.2 as well as 2.3, and to provide more
+        accurate expiration.
+
+2003-08-30  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py: dns.exception.SyntaxError is raised for unknown
+        master file directives.
+
+2003-08-28  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py: $INCLUDE processing is now enabled/disabled using
+        the allow_include parameter.  The default is to process $INCLUDE
+        for from_file(), and to disallow $INCLUDE for from_text().  The
+        master reader now calls zone.check_origin_node() by default after
+        the zone has been read.  find_rdataset() called get_node() instead
+        of find_node(), which result in an incorrect exception.  The
+        relativization state of a zone is now remembered and applied
+        consistently when looking up names.  from_xfr() now supports
+        relativization like the _MasterReader.
+
+2003-08-22  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py: The _MasterReader now understands $INCLUDE.
+
+2003-08-12  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py: The _MasterReader now specifies the file and line
+        number when a syntax error occurs.  The BIND 8 TTL format is now
+        understood when loading a zone, though it will never be emitted.
+        The from_file() function didn't pass the zone_factory parameter
+        to from_text().
+
+2003-08-10  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.1.0 released)
+
+2003-08-07  Bob Halley  <halley@dnspython.org>
+
+        * dns/update.py (Update._add): A typo meant that _add would
+        fail if the thing being added was an Rdata object (as
+        opposed to an Rdataset or the textual form of an Rdata).
+
+2003-08-05  Bob Halley  <halley@dnspython.org>
+
+        * dns/set.py: the simple Set class has been moved to its
+        own module, and augmented to support more set operations.
+
+2003-08-04  Bob Halley  <halley@dnspython.org>
+
+        * Node and all rdata types have been "slotted".  This speeds
+        things up a little and reduces memory usage noticeably.
+
+2003-08-02  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.1.0c1 released)
+
+2003-08-02  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdataset.py: SimpleSets now support more set options.
+
+        * dns/message.py: Added the get_rrset() method.  from_file() now
+        allows Unicode filenames and turns on universal newline support if
+        it opens the file itself.
+
+        * dns/node.py: Added the delete_rdataset() and replace_rdataset()
+        methods.
+
+        * dns/zone.py: Added the delete_node(), delete_rdataset(), and
+        replace_rdataset() methods.  from_file() now allows Unicode
+        filenames and turns on universal newline support if it opens the
+        file itself.  Added a to_file() method.
+
+2003-08-01  Bob Halley  <halley@dnspython.org>
+
+        * dns/opcode.py: Opcode from/to text converters now understand
+        numeric opcodes.  The to_text() method will return a numeric opcode
+        string if it doesn't know a text name for the opcode.
+
+        * dns/message.py: Added set_rcode().  Fixed code where ednsflags
+        wasn't treated as a long.
+
+        * dns/rcode.py: ednsflags wasn't treated as a long.  Rcode from/to
+        text converters now understand numeric rcodes.  The to_text()
+        method will return a numeric rcode string if it doesn't know
+        a text name for the rcode.
+
+        * examples/reverse.py: Added a new example program that builds a
+        reverse (address-to-name) mapping table from the name-to-address
+        mapping specified by A RRs in zone files.
+
+        * dns/node.py: Added get_rdataset() method.
+
+        * dns/zone.py: Added get_rdataset() and get_rrset() methods.  Added
+        iterate_rdatas().
+
+2003-07-31  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py: Added the iterate_rdatasets() method which returns
+        a generator which yields (name, rdataset) tuples for all the
+        rdatasets in the zone matching the specified rdatatype.
+
+2003-07-30  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.1.0b2 released)
+
+2003-07-30  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py: Added find_rrset() and find_rdataset() convenience
+        methods.  They let you retrieve rdata with the specified name
+        and type in one call.
+
+        * dns/node.py: Nodes no longer have names; owner names are
+        associated with nodes in the Zone object's nodes dictionary.
+
+        * dns/zone.py: Zone objects now implement more of the standard
+        mapping interface.  __iter__ has been changed to iterate the keys
+        rather than values to match the standard mapping interface's
+        behavior.
+
+2003-07-20  Bob Halley  <halley@dnspython.org>
+
+        * dns/ipv6.py (inet_ntoa): Handle embedded IPv4 addresses.
+
+2003-07-19  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.1.0b1 released)
+
+2003-07-18  Bob Halley  <halley@dnspython.org>
+
+        * dns/tsig.py: The TSIG validation of TCP streams where not
+        every message is signed now works correctly.
+
+        * dns/zone.py: Zones can now be compared for equality and
+        inequality.  If the other object in the comparison is also
+        a zone, then "the right thing" happens; i.e. the zones are
+        equal iff.: they have the same rdclass, origin, and nodes.
+
+2003-07-17  Bob Halley  <halley@dnspython.org>
+
+        * dns/message.py (Message.use_tsig): The method now allows for
+        greater control over the various fields in the generated signature
+        (e.g. fudge).
+        (_WireReader._get_section): UnknownTSIGKey is now raised if an
+        unknown key is encountered, or if a signed message has no keyring.
+
+2003-07-16  Bob Halley  <halley@dnspython.org>
+
+        * dns/tokenizer.py (Tokenizer._get_char): get_char and unget_char
+        have been renamed to _get_char and _unget_char since they are not
+        useful to clients of the tokenizer.
+
+2003-07-15  Bob Halley  <halley@dnspython.org>
+
+        * dns/zone.py (_MasterReader._rr_line): owner names were being
+        unconditionally relativized; it makes much more sense for them
+        to be relativized according to the relativization setting of
+        the reader.
+
+2003-07-12  Bob Halley  <halley@dnspython.org>
+
+        * dns/resolver.py (Resolver.read_resolv_conf): The resolv.conf
+        parser did not allow blank / whitespace-only lines, nor did it
+        allow comments.  Both are now supported.
+
+2003-07-11  Bob Halley  <halley@dnspython.org>
+
+        * dns/name.py (Name.to_digestable): to_digestable() now
+        requires an origin to be specified if the name is relative.
+        It will raise NeedAbsoluteNameOrOrigin if the name is
+        relative and there is either no origin or the origin is
+        itself relative.
+        (Name.split): returned the wrong answer if depth was 0 or depth
+        was the length of the name.  split() now does bounds checking
+        on depth, and raises ValueError if depth < 0 or depth > the length
+        of the name.
+
+2003-07-10  Bob Halley  <halley@dnspython.org>
+
+        * dns/ipv6.py (inet_ntoa): The routine now minimizes its output
+        strings.  E.g. the IPv6 address
+        "0000:0000:0000:0000:0000:0000:0000:0001" is minimized to "::1".
+        We do not, however, make any effort to display embedded IPv4
+        addresses in the dot-quad notation.
+
+2003-07-09  Bob Halley  <halley@dnspython.org>
+
+        * dns/inet.py: We now supply our own AF_INET and AF_INET6
+        constants since AF_INET6 may not always be available.  If the
+        socket module has AF_INET6, we will use it.  If not, we will
+        use our own value for the constant.
+
+        * dns/query.py: the functions now take an optional af argument
+        specifying the address family to use when creating the socket.
+
+        * dns/rdatatype.py (is_metatype): a typo caused the function
+        return true only for type OPT.
+
+        * dns/message.py: message section list elements are now RRsets
+        instead of Nodes.  This API change makes processing messages
+        easier for many applications.
+
+2003-07-07  Bob Halley  <halley@dnspython.org>
+
+        * dns/rrset.py: added.  An RRset is a named rdataset.
+
+        * dns/rdataset.py (Rdataset.__eq__): rdatasets may now be compared
+        for equality and inequality with other objects.  Rdataset instance
+        variables are now slotted.
+
+        * dns/message.py: The wire format and text format readers are now
+        classes.  Variables related to reader state have been moved out
+        of the message class.
+
+2003-07-06  Bob Halley  <halley@dnspython.org>
+
+        * dns/name.py (from_text): '@' was not interpreted as the empty
+        name.
+
+        * dns/zone.py: the master file reader derelativized names in rdata
+        relative to the zone's origin, not relative to the current origin.
+        The reader now deals with relativization in two steps.  The rdata
+        is read and derelativized using the current origin.  The rdata's
+        relativity is then chosen using the zone origin and the relativize
+        boolean.  Here's an example.
+
+                $ORIGIN foo.example.
+                $TTL 300
+                bar MX 0 blaz
+
+        If the zone origin is example., and relativization is on, then
+        This fragment will become:
+
+                bar.foo.example. 300 IN MX 0 blaz.foo.example.
+
+        after the first step (derelativization to current origin), and
+
+                bar.foo 300 IN MX 0 blaz.foo
+
+        after the second step (relativiation to zone origin).
+
+        * dns/namedict.py: added.
+
+        * dns/zone.py: The master file reader has been made into its
+        own class.  Reader-related instance variables have been moved
+        form the zone class into the reader class.
+
+        * dns/zone.py: Add node_factory class attribute.  An application
+        can now subclass Zone and Node and have a zone whose nodes are of
+        the subclassed Node type.  The from_text(), from_file(), and
+        from_xfr() algorithms now take an optional zone_factory argument.
+        This allows the algorithms to be used to create zones whose class
+        is a subclass of Zone.
+
+
+2003-07-04  Bob Halley  <halley@dnspython.org>
+
+        * dns/renderer.py: added new wire format rendering module and
+        converted message.py to use it.  Applications which want
+        fine-grained control over the conversion to wire format may call
+        the renderer directy, instead of having it called on their behalf
+        by the message code.
+
+2003-07-02  Bob Halley  <halley@dnspython.org>
+
+        * dns/name.py (_validate_labels): The NameTooLong test was
+        incorrect.
+
+        * dns/message.py (Message.to_wire): dns.exception.TooBig is
+        now raised if the wire encoding exceeds the specified
+        maximum size.
+
+2003-07-01  Bob Halley  <halley@dnspython.org>
+
+        * dns/message.py: EDNS encoding was broken.  from_text()
+        didn't parse rcodes, flags, or eflags correctly.  Comparing
+        messages with other types of objects didn't work.
+
+2003-06-30  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.0.0 released)
+
+2003-06-30  Bob Halley  <halley@dnspython.org>
+
+        * dns/rdata.py: Rdatas now implement rich comparisons instead of
+        __cmp__.
+
+        * dns/name.py: Names now implement rich comparisons instead of
+        __cmp__.
+
+        * dns/inet.py (inet_ntop): Always use our code, since the code
+        in the socket module doesn't support AF_INET6 conversions if
+        IPv6 sockets are not available on the system.
+
+        * dns/resolver.py (Answer.__init__): A dangling CNAME chain was
+        not raising NoAnswer.
+
+        * Added a simple resolver Cache class.
+
+        * Added an expiration attribute to answer instances.
+
+2003-06-24  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.0.0b3 released)
+
+2003-06-24  Bob Halley  <halley@dnspython.org>
+
+        * Renamed module "DNS" to "dns" to avoid conflicting with
+        PyDNS.
+
+2003-06-23  Bob Halley  <halley@dnspython.org>
+
+        * The from_text() relativization controls now work the same way as
+        the to_text() controls.
+
+        * DNS/rdata.py: The parsing of generic rdata was broken.
+
+2003-06-21  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.0.0b2 released)
+
+2003-06-21  Bob Halley  <halley@dnspython.org>
+
+        * The Python 2.2 socket.inet_aton() doesn't seem to like
+        '255.255.255.255'.  We work around this.
+
+        * Fixed bugs in rdata to_wire() and from_wire() routines of a few
+        types.  These bugs were discovered by running the tests/zone.py
+        Torture1 test.
+
+        * Added implementation of type APL.
+
+2003-06-20  Bob Halley  <halley@dnspython.org>
+
+        * DNS/rdtypes/IN/AAAA.py: Use our own versions of inet_ntop and
+        inet_pton if the socket module doesn't provide them for us.
+
+        * The resolver now does a better job handling exceptions.  In
+        particular, it no longer eats all exceptions; rather it handles
+        those exceptions it understands, and leaves the rest uncaught.
+
+        * Exceptions have been pulled into their own module.  Almost all
+        exceptions raised by the code are now subclasses of
+        DNS.exception.DNSException.  All form errors are subclasses of
+        DNS.exception.FormError (which is itself a subclass of
+        DNS.exception.DNSException).
+
+2003-06-19  Bob Halley  <halley@dnspython.org>
+
+        * Added implementations of types DS, NXT, SIG, and WKS.
+
+        * __cmp__ for type A and AAAA could produce incorrect results.
+
+2003-06-18  Bob Halley  <halley@dnspython.org>
+
+        * Started test suites for zone.py and tokenizer.py.
+
+        * Added implementation of type KEY.
+
+        * DNS/rdata.py(_base64ify): \n could be emitted erroneously.
+
+        * DNS/rdtypes/ANY/SOA.py (SOA.from_text): The SOA RNAME field could
+        be set to the value of MNAME in common cases.
+
+        * DNS/rdtypes/ANY/X25.py: __init__ was broken.
+
+        * DNS/zone.py (from_text): $TTL handling erroneously caused the
+        next line to be eaten.
+
+        * DNS/tokenizer.py (Tokenizer.get): parsing was broken for empty
+        quoted strings.  Quoted strings didn't handle \ddd escapes.  Such
+        escapes are appear not to comply with RFC 1035, but BIND allows
+        them and they seem useful, so we allow them too.
+
+        * DNS/rdtypes/ANY/ISDN.py (ISDN.from_text): parsing was
+        broken for ISDN RRs without subaddresses.
+
+        * DNS/zone.py (from_file): from_file() didn't work because
+        some required parameters were not passed to from_text().
+
+2003-06-17  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.0.0b1 released)
+
+2003-06-17  Bob Halley  <halley@dnspython.org>
+
+        * Added implementation of type PX.
+
+2003-06-16  Bob Halley  <halley@dnspython.org>
+
+        * Added implementation of types CERT, GPOS, LOC, NSAP, NSAP-PTR.
+
+        * DNS/rdatatype.py (_by_value): A cut-and-paste error had broken
+        NSAP and NSAP-PTR.
+
+2003-06-12  Bob Halley  <halley@dnspython.org>
+
+        * Created a tests directory and started adding tests.
+
+        * Added "and its documentation" to the permission grant in the
+        license.
+
+2003-06-12  Bob Halley  <halley@dnspython.org>
+
+        * DNS/name.py (Name.is_wild): is_wild() erroneously raised IndexError
+        if the name was empty.
+
+2003-06-10  Bob Halley  <halley@dnspython.org>
+
+        * Added implementations of types AFSDB, X25, and ISDN.
+
+        * The documentation associated with the various rdata types has been
+        improved.  In particular, instance variables are now described.
+
+2003-06-09  Bob Halley  <halley@dnspython.org>
+
+        * Added implementations of types HINFO, RP, and RT.
+
+        * DNS/message.py (make_query): Document that make_query() sets
+        flags to DNS.flags.RD, and chooses a random query id.
+
+2003-06-05  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.0.0a2 released)
+
+2003-06-05  Bob Halley  <halley@dnspython.org>
+
+        * DNS/node.py: removed __getitem__ and __setitem__, since
+        they are not used by the codebase and were not useful in
+        general either.
+
+        * DNS/message.py (from_file): from_file() now allows a
+        filename to be specified instead of a file object.
+
+        * DNS/rdataset.py: The is_compatible() method of the
+        DNS.rdataset.Rdataset class was deleted.
+
+2003-06-04  Bob Halley  <halley@dnspython.org>
+
+        * DNS/name.py (class Name): Names are now immutable.
+
+        * DNS/name.py: the is_comparable() method has been removed, since
+        names are always comparable.
+
+        * DNS/resolver.py (Resolver.query): A query could run for up
+        to the lifetime + the timeout.  This has been corrected and the
+        query will now only run up to the lifetime.
+
+2003-06-03  Bob Halley  <halley@dnspython.org>
+
+        * DNS/resolver.py: removed the 'new' function since it is not the
+        style of the library to have such a function.  Call
+        DNS.resolver.Resolver() to make a new resolver.
+
+2003-06-03  Bob Halley  <halley@dnspython.org>
+
+        * DNS/resolver.py (Resolver._config_win32_fromkey): The DhcpServer
+        list is space separated, not comma separated.
+
+2003-06-03  Bob Halley  <halley@dnspython.org>
+
+        * DNS/update.py: Added an update module to make generating updates
+        easier.
+
+2003-06-03  Bob Halley  <halley@dnspython.org>
+
+        * Commas were missing in some of the __all__ entries in various
+        __init__.py files.
+
+2003-05-30  Bob Halley  <halley@dnspython.org>
+
+        * (Version 1.0.0a1 released)
diff --git a/source4/scripting/python/samba_external/dnspython/LICENSE b/source4/scripting/python/samba_external/dnspython/LICENSE
new file mode 100644 (file)
index 0000000..633c18c
--- /dev/null
@@ -0,0 +1,14 @@
+Copyright (C) 2001-2003 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.
diff --git a/source4/scripting/python/samba_external/dnspython/PKG-INFO b/source4/scripting/python/samba_external/dnspython/PKG-INFO
new file mode 100644 (file)
index 0000000..455915d
--- /dev/null
@@ -0,0 +1,28 @@
+Metadata-Version: 1.1
+Name: dnspython
+Version: 1.8.0
+Summary: DNS toolkit
+Home-page: http://www.dnspython.org
+Author: Bob Halley
+Author-email: halley@dnspython.org
+License: BSD-like
+Download-URL: http://www.dnspython.org/kits/1.8.0/dnspython-1.8.0.tar.gz
+Description: dnspython is a DNS toolkit for Python. It supports almost all
+        record types. It can be used for queries, zone transfers, and dynamic
+        updates.  It supports TSIG authenticated messages and EDNS0.
+
+        dnspython provides both high and low level access to DNS. The high
+        level classes perform queries for data of a given name, type, and
+        class, and return an answer set.  The low level classes allow
+        direct manipulation of DNS zones, messages, names, and records.
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: Freeware
+Classifier: Operating System :: Microsoft :: Windows :: Windows 95/98/2000
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: Name Service (DNS)
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Provides: dns
diff --git a/source4/scripting/python/samba_external/dnspython/README b/source4/scripting/python/samba_external/dnspython/README
new file mode 100644 (file)
index 0000000..0e5793a
--- /dev/null
@@ -0,0 +1,347 @@
+dnspython
+
+INTRODUCTION
+
+dnspython is a DNS toolkit for Python. It supports almost all record
+types. It can be used for queries, zone transfers, and dynamic
+updates.  It supports TSIG authenticated messages and EDNS0.
+
+dnspython provides both high and low level access to DNS. The high
+level classes perform queries for data of a given name, type, and
+class, and return an answer set.  The low level classes allow direct
+manipulation of DNS zones, messages, names, and records.
+
+To see a few of the ways dnspython can be used, look in the examples/
+directory.
+
+dnspython originated at Nominum where it was developed to facilitate
+the testing of DNS software.  Nominum has generously allowed it to be
+open sourced under a BSD-style license, and helps support its future
+development by continuing to employ the author :).
+
+
+ABOUT THIS RELEASE
+
+This is dnspython 1.8.0
+
+New since 1.7.1:
+
+       Support for hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384
+       and hmac-sha512 has been contributed by Kevin Chen.
+
+       The tokenizer's tokens are now Token objects instead of (type,
+       value) tuples.
+
+Bugs fixed since 1.7.1:
+
+        Escapes in masterfiles now work correctly.  Previously they
+       were only working correctly when the text involved was part of
+       a domain name.
+
+       When constructing a DDNS update, if the present() method was
+       used with a single rdata, a zero TTL was not added.
+
+       The entropy pool needed locking to be thread safe.
+
+       The entropy pool's reading of /dev/random could cause
+       dnspython to block.
+
+       The entropy pool did buffered reads, potentially consuming more
+       randomness than we needed.
+
+       The entropy pool did not seed with high quality randomness on
+       Windows.
+
+       SRV records were compared incorrectly.
+
+       In the e164 query function, the resolver parameter was not
+       used.
+
+New since 1.7.0:
+
+       Nothing
+
+Bugs fixed since 1.7.0:
+
+       The 1.7.0 kitting process inadventently omitted the code for the
+       DLV RR.
+
+       Negative DDNS prerequisites are now handled correctly.
+
+New since 1.6.0:
+
+       Rdatas now have a to_digestable() method, which returns the
+       DNSSEC canonical form of the rdata, suitable for use in
+       signature computations.
+
+       The NSEC3, NSEC3PARAM, DLV, and HIP RR types are now supported.
+
+       An entropy module has been added and is used to randomize query ids.
+
+       EDNS0 options are now supported.
+
+       UDP IXFR is now supported.
+
+       The wire format parser now has a 'one_rr_per_rrset' mode, which
+       suppresses the usual coalescing of all RRs of a given type into a
+       single RRset.
+
+       Various helpful DNSSEC-related constants are now defined.
+
+       The resolver's query() method now has an optional 'source' parameter,
+        allowing the source IP address to be specified.
+
+Bugs fixed since 1.6.0:
+
+       On Windows, the resolver set the domain incorrectly.
+
+       DS RR parsing only allowed one Base64 chunk.
+
+       TSIG validation didn't always use absolute names.
+
+       NSEC.to_text() only printed the last window.
+
+       We did not canonicalize IPv6 addresses before comparing them; we
+       would thus treat equivalent but different textual forms, e.g.
+       "1:00::1" and "1::1" as being non-equivalent.
+
+       If the peer set a TSIG error, we didn't raise an exception.
+
+       Some EDNS bugs in the message code have been fixed (see the ChangeLog
+       for details).
+
+New since 1.5.0:
+       Added dns.inet.is_multicast().
+
+Bugs fixed since 1.5.0:
+
+       If select() raises an exception due to EINTR, we should just
+       select() again.
+
+       If the queried address is a multicast address, then don't
+       check that the address of the response is the same as the
+       address queried.
+
+       NAPTR comparisons didn't compare the preference field due to a
+       typo.
+
+       Testing of whether a Windows NIC is enabled now works on Vista
+       thanks to code contributed by Paul Marks.
+
+New since 1.4.0:
+
+       Answer objects now support more of the python sequence
+       protocol, forwarding the requests to the answer rrset.
+       E.g. "for a in answer" is equivalent to "for a in
+       answer.rrset", "answer[i]" is equivalent to "answer.rrset[i]",
+       and "answer[i:j]" is equivalent to "answer.rrset[i:j]".
+
+       Making requests using EDNS, including indicating DNSSEC awareness,
+       is now easier.  For example, you can now say:
+
+          q = dns.message.make_query('www.dnspython.org', 'MX',
+                                     want_dnssec=True)
+
+       dns.query.xfr() can now be used for IXFR.
+
+       Support has been added for the DHCID, IPSECKEY, and SPF RR types.
+
+       UDP messages from unexpected sources can now be ignored by
+       setting ignore_unexpected to True when calling dns.query.udp.
+
+Bugs fixed since 1.4.0:
+
+        If /etc/resolv.conf didn't exist, we raised an exception
+       instead of simply using the default resolver configuration.
+
+       In dns.resolver.Resolver._config_win32_fromkey(), we were
+       passing the wrong variable to self._config_win32_search().
+
+New since 1.3.5:
+
+        You can now convert E.164 numbers to/from their ENUM name
+        forms:
+
+             >>> import dns.e164
+             >>> n = dns.e164.from_e164("+1 555 1212")
+             >>> n
+             <DNS name 2.1.2.1.5.5.5.1.e164.arpa.>
+             >>> dns.e164.to_e164(n)
+             '+15551212'
+
+       You can now convert IPv4 and IPv6 address to/from their
+       corresponding DNS reverse map names:
+
+             >>> import dns.reversename
+             >>> n = dns.reversename.from_address("127.0.0.1")
+             >>> n
+             <DNS name 1.0.0.127.in-addr.arpa.>
+             >>> dns.reversename.to_address(n)
+             '127.0.0.1'
+
+       You can now convert between Unicode strings and their IDN ACE
+       form:
+
+             >>> n = dns.name.from_text(u'les-\u00e9l\u00e8ves.example.')
+             >>> n
+             <DNS name xn--les-lves-50ai.example.>
+             >>> n.to_unicode()
+             u'les-\xe9l\xe8ves.example.'
+
+       The origin parameter to dns.zone.from_text() and dns.zone.to_text()
+       is now optional.  If not specified, the origin will be taken from
+       the first $ORIGIN statement in the master file.
+
+       Sanity checking of a zone can be disabled; this is useful when
+       working with files which are zone fragments.
+
+Bugs fixed since 1.3.5:
+
+       The correct delimiter was not used when retrieving the
+       list of nameservers from the registry in certain versions of
+       windows.
+
+        The floating-point version of latitude and longitude in LOC RRs
+       (float_latitude and float_longitude) had incorrect signs for
+       south latitudes and west longitudes.
+
+       BIND 8 TTL syntax is now accepted in all TTL-like places (i.e.
+       SOA fields refresh, retry, expire, and minimum; SIG/RRSIG
+       field original_ttl).
+
+       TTLs are now bounds checked when their text form is parsed,
+       and their values must be in the closed interval [0, 2^31 - 1].
+
+New since 1.3.4:
+
+       In the resolver, if time goes backward a little bit, ignore
+       it.
+
+       zone_for_name() has been added to the resolver module.  It
+       returns the zone which is authoritative for the specified
+       name, which is handy for dynamic update.  E.g.
+
+             import dns.resolver
+             print dns.resolver.zone_for_name('www.dnspython.org')
+
+       will output "dnspython.org." and
+
+             print dns.resolver.zone_for_name('a.b.c.d.e.f.example.')
+
+       will output ".".
+
+       The default resolver can be fetched with the
+       get_default_resolver() method.
+
+       You can now get the parent (immediate superdomain) of a name
+       by using the parent() method.
+
+       Zone.iterate_rdatasets() and Zone.iterate_rdatas() now have
+       a default rdtype of dns.rdatatype.ANY like the documentation
+       says.
+
+       A Dynamic DNS example, ddns.py, has been added.
+
+New since 1.3.3:
+
+       The source address and port may now be specified when calling
+       dns.query.{udp,tcp,xfr}.
+
+       The resolver now does exponential backoff each time it runs
+       through all of the nameservers.
+
+       Rcodes which indicate a nameserver is likely to be a
+       "permanent failure" for a query cause the nameserver to be removed
+       from the mix for that query.
+
+New since 1.3.2:
+
+       dns.message.Message.find_rrset() now uses an index, vastly
+       improving the from_wire() performance of large messages such
+       as zone transfers.
+
+       Added dns.message.make_response(), which creates a skeletal
+       response for the specified query.
+
+       Added opcode() and set_opcode() convenience methods to the
+       dns.message.Message class.  Added the request_payload
+       attribute to the Message class.
+
+        The 'file' parameter of dns.name.Name.to_wire() is now
+       optional; if omitted, the wire form will be returned as the
+       value of the function.
+
+       dns.zone.from_xfr() in relativization mode incorrectly set
+       zone.origin to the empty name.
+
+       The masterfile parser incorrectly rejected TXT records where a
+       value was not quoted.
+
+New since 1.3.1:
+
+       The NSEC format doesn't allow specifying types by number, so
+       we shouldn't either.  (Using the unknown type format is still
+       OK though.)
+
+       The resolver wasn't catching dns.exception.Timeout, so a timeout
+       erroneously caused the whole resolution to fail instead of just
+       going on to the next server.
+
+       The renderer module didn't import random, causing an exception
+       to be raised if a query id wasn't provided when a Renderer was
+       created.
+
+        The conversion of LOC milliseconds values from text to binary was
+       incorrect if the length of the milliseconds string was not 3.
+
+New since 1.3.0:
+
+       Added support for the SSHFP type.
+
+New since 1.2.0:
+
+       Added support for new DNSSEC types RRSIG, NSEC, and DNSKEY.
+
+This release fixes all known bugs.
+
+See the ChangeLog file for more detailed information on changes since
+the prior release.
+
+
+REQUIREMENTS
+
+Python 2.2 or later.
+
+
+INSTALLATION
+
+To build and install dnspython, type
+
+       python setup.py install
+
+
+HOME PAGE
+
+For the latest in releases, documentation, and information, visit the
+dnspython home page at
+
+       http://www.dnspython.org/
+
+
+
+DOCUMENTATION
+
+Documentation is sparse at the moment.  Use pydoc, or read the HTML
+documentation at the dnspython home page, or download the HTML
+documentation.
+
+
+BUG REPORTS
+
+Bug reports may be sent to bugs@dnspython.org
+
+
+MAILING LISTS
+
+A number of mailing lists are available.  Visit the dnspython home
+page to subscribe or unsubscribe.
diff --git a/source4/scripting/python/samba_external/dnspython/TODO b/source4/scripting/python/samba_external/dnspython/TODO
new file mode 100644 (file)
index 0000000..59ce1be
--- /dev/null
@@ -0,0 +1,17 @@
+Tutorial documentation
+
+More examples
+
+It would be nice to have a tokenizer that used regular expressions
+because it would be faster.
+
+Teach the resolver about DNAME (right now it relies on the server adding
+synthesized CNAMEs)
+
+Add TKEY support.
+
+TSIG works, but needs cleaning up -- probably better encapsulation of
+TSIG state to make things much simpler and easier to use.
+
+Pickling support.
+
diff --git a/source4/scripting/python/samba_external/dnspython/dns/__init__.py b/source4/scripting/python/samba_external/dnspython/dns/__init__.py
new file mode 100644 (file)
index 0000000..5ad5737
--- /dev/null
@@ -0,0 +1,52 @@
+# 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.
+
+"""dnspython DNS toolkit"""
+
+__all__ = [
+    'dnssec',
+    'e164',
+    'edns',
+    'entropy',
+    'exception',
+    'flags',
+    'inet',
+    'ipv4',
+    'ipv6',
+    'message',
+    'name',
+    'namedict',
+    'node',
+    'opcode',
+    'query',
+    'rcode',
+    'rdata',
+    'rdataclass',
+    'rdataset',
+    'rdatatype',
+    'renderer',
+    'resolver',
+    'reversename',
+    'rrset',
+    'set',
+    'tokenizer',
+    'tsig',
+    'tsigkeyring',
+    'ttl',
+    'rdtypes',
+    'update',
+    'version',
+    'zone',
+]
diff --git a/source4/scripting/python/samba_external/dnspython/dns/dnssec.py b/source4/scripting/python/samba_external/dnspython/dns/dnssec.py
new file mode 100644 (file)
index 0000000..acf4653
--- /dev/null
@@ -0,0 +1,72 @@
+# 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."""
+
+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(Exception):
+    """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
diff --git a/source4/scripting/python/samba_external/dnspython/dns/e164.py b/source4/scripting/python/samba_external/dnspython/dns/e164.py
new file mode 100644 (file)
index 0000000..d8f71ec
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright (C) 2006, 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.
+
+"""DNS E.164 helpers
+
+@var public_enum_domain: The DNS public ENUM domain, e164.arpa.
+@type public_enum_domain: dns.name.Name object
+"""
+
+import dns.exception
+import dns.name
+import dns.resolver
+
+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
+    value is the ENUM domain name for that number.
+    @param text: an E.164 number in textual form.
+    @type text: str
+    @param origin: The domain in which the number should be constructed.
+    The default is e164.arpa.
+    @type: dns.name.Name object or None
+    @rtype: dns.name.Name object
+    """
+    parts = [d for d in text if d.isdigit()]
+    parts.reverse()
+    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: 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: dns.name.Name object or None
+    @param want_plus_prefix: if True, add a '+' to the beginning of the
+    returned number.
+    @rtype: str
+    """
+    if not origin is None:
+        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 dns.exception.SyntaxError('non-digit labels in ENUM domain name')
+    dlabels.reverse()
+    text = ''.join(dlabels)
+    if want_plus_prefix:
+        text = '+' + text
+    return text
+
+def query(number, domains, resolver=None):
+    """Look for NAPTR RRs for the specified number in the specified domains.
+
+    e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.'])
+    """
+    if resolver is None:
+        resolver = dns.resolver.get_default_resolver()
+    for domain in domains:
+        if isinstance(domain, (str, unicode)):
+            domain = dns.name.from_text(domain)
+        qname = dns.e164.from_e164(number, domain)
+        try:
+            return resolver.query(qname, 'NAPTR')
+        except dns.resolver.NXDOMAIN:
+            pass
+    raise dns.resolver.NXDOMAIN
diff --git a/source4/scripting/python/samba_external/dnspython/dns/edns.py b/source4/scripting/python/samba_external/dnspython/dns/edns.py
new file mode 100644 (file)
index 0000000..1731ced
--- /dev/null
@@ -0,0 +1,142 @@
+# Copyright (C) 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.
+
+"""EDNS Options"""
+
+NSID = 3
+
+class Option(object):
+    """Base class for all EDNS option types.
+    """
+
+    def __init__(self, otype):
+        """Initialize an option.
+        @param rdtype: The rdata type
+        @type rdtype: int
+        """
+        self.otype = otype
+
+    def to_wire(self, file):
+        """Convert an option to wire format.
+        """
+        raise NotImplementedError
+
+    def from_wire(cls, otype, wire, current, olen):
+        """Build an EDNS option object from wire format
+
+        @param otype: The option type
+        @type otype: int
+        @param wire: The wire-format message
+        @type wire: string
+        @param current: The offet in wire of the beginning of the rdata.
+        @type current: int
+        @param olen: The length of the wire-format option data
+        @type olen: int
+        @rtype: dns.ends.Option instance"""
+        raise NotImplementedError
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        """Compare an ENDS option with another option of the same type.
+        Return < 0 if self < other, 0 if self == other, and > 0 if self > other.
+        """
+        raise NotImplementedError
+
+    def __eq__(self, other):
+        if not isinstance(other, Option):
+            return False
+        if self.otype != other.otype:
+            return False
+        return self._cmp(other) == 0
+
+    def __ne__(self, other):
+        if not isinstance(other, Option):
+            return False
+        if self.otype != other.otype:
+            return False
+        return self._cmp(other) != 0
+
+    def __lt__(self, other):
+        if not isinstance(other, Option) or \
+               self.otype != other.otype:
+            return NotImplemented
+        return self._cmp(other) < 0
+
+    def __le__(self, other):
+        if not isinstance(other, Option) or \
+               self.otype != other.otype:
+            return NotImplemented
+        return self._cmp(other) <= 0
+
+    def __ge__(self, other):
+        if not isinstance(other, Option) or \
+               self.otype != other.otype:
+            return NotImplemented
+        return self._cmp(other) >= 0
+
+    def __gt__(self, other):
+        if not isinstance(other, Option) or \
+               self.otype != other.otype:
+            return NotImplemented
+        return self._cmp(other) > 0
+
+
+class GenericOption(Option):
+    """Generate Rdata Class
+
+    This class is used for EDNS option types for which we have no better
+    implementation.
+    """
+
+    def __init__(self, otype, data):
+        super(GenericOption, self).__init__(otype)
+        self.data = data
+
+    def to_wire(self, file):
+        file.write(self.data)
+
+    def from_wire(cls, otype, wire, current, olen):
+        return cls(otype, wire[current : current + olen])
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+       return cmp(self.data, other.data)
+
+_type_to_class = {
+}
+
+def get_option_class(otype):
+    cls = _type_to_class.get(otype)
+    if cls is None:
+        cls = GenericOption
+    return cls
+
+def option_from_wire(otype, wire, current, olen):
+    """Build an EDNS option object from wire format
+
+    @param otype: The option type
+    @type otype: int
+    @param wire: The wire-format message
+    @type wire: string
+    @param current: The offet in wire of the beginning of the rdata.
+    @type current: int
+    @param olen: The length of the wire-format option data
+    @type olen: int
+    @rtype: dns.ends.Option instance"""
+
+    cls = get_option_class(otype)
+    return cls.from_wire(otype, wire, current, olen)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/entropy.py b/source4/scripting/python/samba_external/dnspython/dns/entropy.py
new file mode 100644 (file)
index 0000000..fd9d4f8
--- /dev/null
@@ -0,0 +1,123 @@
+# Copyright (C) 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.
+
+import os
+import time
+try:
+    import threading as _threading
+except ImportError:
+    import dummy_threading as _threading
+
+class EntropyPool(object):
+    def __init__(self, seed=None):
+        self.pool_index = 0
+        self.digest = None
+        self.next_byte = 0
+        self.lock = _threading.Lock()
+        try:
+            import hashlib
+            self.hash = hashlib.sha1()
+            self.hash_len = 20
+        except:
+            try:
+                import sha
+                self.hash = sha.new()
+                self.hash_len = 20
+            except:
+                import md5
+                self.hash = md5.new()
+                self.hash_len = 16
+        self.pool = '\0' * self.hash_len
+        if not seed is None:
+            self.stir(seed)
+            self.seeded = True
+        else:
+            self.seeded = False
+
+    def stir(self, entropy, already_locked=False):
+        if not already_locked:
+            self.lock.acquire()
+        try:
+            bytes = [ord(c) for c in self.pool]
+            for c in entropy:
+                if self.pool_index == self.hash_len:
+                    self.pool_index = 0
+                b = ord(c) & 0xff
+                bytes[self.pool_index] ^= b
+                self.pool_index += 1
+            self.pool = ''.join([chr(c) for c in bytes])
+        finally:
+            if not already_locked:
+                self.lock.release()
+
+    def _maybe_seed(self):
+        if not self.seeded:
+            try:
+                seed = os.urandom(16)
+            except:
+                try:
+                    r = file('/dev/urandom', 'r', 0)
+                    try:
+                        seed = r.read(16)
+                    finally:
+                        r.close()
+                except:
+                    seed = str(time.time())
+            self.seeded = True
+            self.stir(seed, True)
+
+    def random_8(self):
+        self.lock.acquire()
+        self._maybe_seed()
+        try:
+            if self.digest is None or self.next_byte == self.hash_len:
+                self.hash.update(self.pool)
+                self.digest = self.hash.digest()
+                self.stir(self.digest, True)
+                self.next_byte = 0
+            value = ord(self.digest[self.next_byte])
+            self.next_byte += 1
+        finally:
+            self.lock.release()
+        return value
+
+    def random_16(self):
+        return self.random_8() * 256 + self.random_8()
+
+    def random_32(self):
+        return self.random_16() * 65536 + self.random_16()
+
+    def random_between(self, first, last):
+        size = last - first + 1
+        if size > 4294967296L:
+            raise ValueError('too big')
+        if size > 65536:
+            rand = self.random_32
+            max = 4294967295L
+        elif size > 256:
+            rand = self.random_16
+            max = 65535
+        else:
+            rand = self.random_8
+            max = 255
+       return (first + size * rand() // (max + 1))
+
+pool = EntropyPool()
+
+def random_16():
+    return pool.random_16()
+
+def between(first, last):
+    return pool.random_between(first, last)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/exception.py b/source4/scripting/python/samba_external/dnspython/dns/exception.py
new file mode 100644 (file)
index 0000000..c6d6570
--- /dev/null
@@ -0,0 +1,40 @@
+# 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.
+
+"""Common DNS Exceptions."""
+
+class DNSException(Exception):
+    """Abstract base class shared by all dnspython exceptions."""
+    pass
+
+class FormError(DNSException):
+    """DNS message is malformed."""
+    pass
+
+class SyntaxError(DNSException):
+    """Text input is malformed."""
+    pass
+
+class UnexpectedEnd(SyntaxError):
+    """Raised if text input ends unexpectedly."""
+    pass
+
+class TooBig(DNSException):
+    """The message is too big."""
+    pass
+
+class Timeout(DNSException):
+    """The operation timed out."""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/flags.py b/source4/scripting/python/samba_external/dnspython/dns/flags.py
new file mode 100644 (file)
index 0000000..79375ea
--- /dev/null
@@ -0,0 +1,106 @@
+# Copyright (C) 2001-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.
+
+"""DNS Message Flags."""
+
+# Standard DNS flags
+
+QR = 0x8000
+AA = 0x0400
+TC = 0x0200
+RD = 0x0100
+RA = 0x0080
+AD = 0x0020
+CD = 0x0010
+
+# EDNS flags
+
+DO = 0x8000
+
+_by_text = {
+    'QR' : QR,
+    'AA' : AA,
+    'TC' : TC,
+    'RD' : RD,
+    'RA' : RA,
+    'AD' : AD,
+    'CD' : CD
+}
+
+_edns_by_text = {
+    'DO' : DO
+}
+
+
+# We construct the inverse mappings programmatically to ensure that we
+# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that
+# would cause the mappings not to be true inverses.
+
+_by_value = dict([(y, x) for x, y in _by_text.iteritems()])
+
+_edns_by_value = dict([(y, x) for x, y in _edns_by_text.iteritems()])
+
+def _order_flags(table):
+    order = list(table.iteritems())
+    order.sort()
+    order.reverse()
+    return order
+
+_flags_order = _order_flags(_by_value)
+
+_edns_flags_order = _order_flags(_edns_by_value)
+
+def _from_text(text, table):
+    flags = 0
+    tokens = text.split()
+    for t in tokens:
+        flags = flags | table[t.upper()]
+    return flags
+
+def _to_text(flags, table, order):
+    text_flags = []
+    for k, v in order:
+        if flags & k != 0:
+            text_flags.append(v)
+    return ' '.join(text_flags)
+
+def from_text(text):
+    """Convert a space-separated list of flag text values into a flags
+    value.
+    @rtype: int"""
+
+    return _from_text(text, _by_text)
+
+def to_text(flags):
+    """Convert a flags value into a space-separated list of flag text
+    values.
+    @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
+    flags value.
+    @rtype: int"""
+
+    return _from_text(text, _edns_by_text)
+
+def edns_to_text(flags):
+    """Convert an EDNS flags value into a space-separated list of EDNS flag
+    text values.
+    @rtype: string"""
+
+    return _to_text(flags, _edns_by_value, _edns_flags_order)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/inet.py b/source4/scripting/python/samba_external/dnspython/dns/inet.py
new file mode 100644 (file)
index 0000000..993a2f9
--- /dev/null
@@ -0,0 +1,108 @@
+# 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.
+
+"""Generic Internet address helper functions."""
+
+import socket
+
+import dns.ipv4
+import dns.ipv6
+
+
+# We assume that AF_INET is always defined.
+
+AF_INET = socket.AF_INET
+
+# AF_INET6 might not be defined in the socket module, but we need it.
+# We'll try to use the socket module's value, and if it doesn't work,
+# we'll use our own value.
+
+try:
+    AF_INET6 = socket.AF_INET6
+except AttributeError:
+    AF_INET6 = 9999
+
+def inet_pton(family, text):
+    """Convert the textual form of a network address into its binary form.
+
+    @param family: the address family
+    @type family: int
+    @param text: the textual address
+    @type text: string
+    @raises NotImplementedError: the address family specified is not
+    implemented.
+    @rtype: string
+    """
+
+    if family == AF_INET:
+        return dns.ipv4.inet_aton(text)
+    elif family == AF_INET6:
+        return dns.ipv6.inet_aton(text)
+    else:
+        raise NotImplementedError
+
+def inet_ntop(family, address):
+    """Convert the binary form of a network address into its textual form.
+
+    @param family: the address family
+    @type family: int
+    @param address: the binary address
+    @type address: string
+    @raises NotImplementedError: the address family specified is not
+    implemented.
+    @rtype: string
+    """
+    if family == AF_INET:
+        return dns.ipv4.inet_ntoa(address)
+    elif family == AF_INET6:
+        return dns.ipv6.inet_ntoa(address)
+    else:
+        raise NotImplementedError
+
+def af_for_address(text):
+    """Determine the address family of a textual-form network address.
+
+    @param text: the textual address
+    @type text: string
+    @raises ValueError: the address family cannot be determined from the input.
+    @rtype: int
+    """
+    try:
+        junk = dns.ipv4.inet_aton(text)
+        return AF_INET
+    except:
+        try:
+            junk = dns.ipv6.inet_aton(text)
+            return AF_INET6
+        except:
+            raise ValueError
+
+def is_multicast(text):
+    """Is the textual-form network address a multicast address?
+
+    @param text: the textual address
+    @raises ValueError: the address family cannot be determined from the input.
+    @rtype: bool
+    """
+    try:
+        first = ord(dns.ipv4.inet_aton(text)[0])
+        return (first >= 224 and first <= 239)
+    except:
+        try:
+            first = ord(dns.ipv6.inet_aton(text)[0])
+            return (first == 255)
+        except:
+            raise ValueError
+
diff --git a/source4/scripting/python/samba_external/dnspython/dns/ipv4.py b/source4/scripting/python/samba_external/dnspython/dns/ipv4.py
new file mode 100644 (file)
index 0000000..1569da5
--- /dev/null
@@ -0,0 +1,36 @@
+# 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.
+
+"""IPv4 helper functions."""
+
+import socket
+import sys
+
+if sys.hexversion < 0x02030000 or sys.platform == 'win32':
+    #
+    # Some versions of Python 2.2 have an inet_aton which rejects
+    # the valid IP address '255.255.255.255'.  It appears this
+    # problem is still present on the Win32 platform even in 2.3.
+    # We'll work around the problem.
+    #
+    def inet_aton(text):
+        if text == '255.255.255.255':
+            return '\xff' * 4
+        else:
+            return socket.inet_aton(text)
+else:
+    inet_aton = socket.inet_aton
+
+inet_ntoa = socket.inet_ntoa
diff --git a/source4/scripting/python/samba_external/dnspython/dns/ipv6.py b/source4/scripting/python/samba_external/dnspython/dns/ipv6.py
new file mode 100644 (file)
index 0000000..33c6713
--- /dev/null
@@ -0,0 +1,163 @@
+# 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.
+
+"""IPv6 helper functions."""
+
+import re
+
+import dns.exception
+import dns.ipv4
+
+_leading_zero = re.compile(r'0+([0-9a-f]+)')
+
+def inet_ntoa(address):
+    """Convert a network format IPv6 address into text.
+
+    @param address: the binary address
+    @type address: string
+    @rtype: string
+    @raises ValueError: the address isn't 16 bytes long
+    """
+
+    if len(address) != 16:
+        raise ValueError("IPv6 addresses are 16 bytes long")
+    hex = address.encode('hex_codec')
+    chunks = []
+    i = 0
+    l = len(hex)
+    while i < l:
+        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(chunk)
+        if not m is None:
+            chunk = m.group(1)
+        chunks.append(chunk)
+        i += 4
+    #
+    # Compress the longest subsequence of 0-value chunks to ::
+    #
+    best_start = 0
+    best_len = 0
+    start = -1
+    last_was_zero = False
+    for i in xrange(8):
+        if chunks[i] != '0':
+            if last_was_zero:
+                end = i
+                current_len = end - start
+                if current_len > best_len:
+                    best_start = start
+                    best_len = current_len
+                last_was_zero = False
+        elif not last_was_zero:
+            start = i
+            last_was_zero = True
+    if last_was_zero:
+        end = 8
+        current_len = end - start
+        if current_len > best_len:
+            best_start = start
+            best_len = current_len
+    if best_len > 0:
+        if best_start == 0 and \
+           (best_len == 6 or
+            best_len == 5 and chunks[5] == 'ffff'):
+            # We have an embedded IPv4 address
+            if best_len == 6:
+                prefix = '::'
+            else:
+                prefix = '::ffff:'
+            hex = prefix + dns.ipv4.inet_ntoa(address[12:])
+        else:
+            hex = ':'.join(chunks[:best_start]) + '::' + \
+                  ':'.join(chunks[best_start + best_len:])
+    else:
+        hex = ':'.join(chunks)
+    return hex
+
+_v4_ending = re.compile(r'(.*):(\d+)\.(\d+)\.(\d+)\.(\d+)$')
+_colon_colon_start = re.compile(r'::.*')
+_colon_colon_end = re.compile(r'.*::$')
+
+def inet_aton(text):
+    """Convert a text format IPv6 address into network format.
+
+    @param text: the textual address
+    @type text: string
+    @rtype: string
+    @raises dns.exception.SyntaxError: the text was not properly formatted
+    """
+
+    #
+    # Our aim here is not something fast; we just want something that works.
+    #
+
+    if text == '::':
+        text = '0::'
+    #
+    # Get rid of the icky dot-quad syntax if we have it.
+    #
+    m = _v4_ending.match(text)
+    if not m is None:
+        text = "%s:%04x:%04x" % (m.group(1),
+                                 int(m.group(2)) * 256 + int(m.group(3)),
+                                 int(m.group(4)) * 256 + int(m.group(5)))
+    #
+    # Try to turn '::<whatever>' into ':<whatever>'; if no match try to
+    # turn '<whatever>::' into '<whatever>:'
+    #
+    m = _colon_colon_start.match(text)
+    if not m is None:
+        text = text[1:]
+    else:
+        m = _colon_colon_end.match(text)
+        if not m is None:
+            text = text[:-1]
+    #
+    # Now canonicalize into 8 chunks of 4 hex digits each
+    #
+    chunks = text.split(':')
+    l = len(chunks)
+    if l > 8:
+        raise dns.exception.SyntaxError
+    seen_empty = False
+    canonical = []
+    for c in chunks:
+        if c == '':
+            if seen_empty:
+                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 dns.exception.SyntaxError
+            if lc != 4:
+                c = ('0' * (4 - lc)) + c
+            canonical.append(c)
+    if l < 8 and not seen_empty:
+        raise dns.exception.SyntaxError
+    text = ''.join(canonical)
+
+    #
+    # Finally we can go to binary.
+    #
+    try:
+        return text.decode('hex_codec')
+    except TypeError:
+        raise dns.exception.SyntaxError
diff --git a/source4/scripting/python/samba_external/dnspython/dns/message.py b/source4/scripting/python/samba_external/dnspython/dns/message.py
new file mode 100644 (file)
index 0000000..ba0ebf6
--- /dev/null
@@ -0,0 +1,1083 @@
+# Copyright (C) 2001-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.
+
+"""DNS Messages"""
+
+import cStringIO
+import random
+import struct
+import sys
+import time
+
+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
+
+class ShortHeader(dns.exception.FormError):
+    """Raised if the DNS packet passed to from_wire() is too short."""
+    pass
+
+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(dns.exception.DNSException):
+    """Raised if a header field name is not recognized when converting from
+    text into a message."""
+    pass
+
+class BadEDNS(dns.exception.FormError):
+    """Raised if an OPT record occurs somewhere other than the start of
+    the additional data section."""
+    pass
+
+class BadTSIG(dns.exception.FormError):
+    """Raised if a TSIG record occurs somewhere other than the end of
+    the additional data section."""
+    pass
+
+class UnknownTSIGKey(dns.exception.DNSException):
+    """Raised if we got a TSIG but don't know the key."""
+    pass
+
+class Message(object):
+    """A DNS message.
+
+    @ivar id: The query id; the default is a randomly chosen id.
+    @type id: int
+    @ivar flags: The DNS flags of the message.  @see: RFC 1035 for an
+    explanation of these flags.
+    @type flags: int
+    @ivar question: The question section.
+    @type question: list of dns.rrset.RRset objects
+    @ivar answer: The answer section.
+    @type answer: list of dns.rrset.RRset objects
+    @ivar authority: The authority section.
+    @type authority: list of dns.rrset.RRset objects
+    @ivar additional: The additional data section.
+    @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 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: dns.name.Name object
+    @ivar keyalgorithm: The TSIG key algorithm to use.  The default is
+    dns.tsig.default_algorithm.
+    @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
+    @ivar original_id: TSIG original id; defaults to the message's id
+    @type original_id: int
+    @ivar tsig_error: TSIG error code; default is 0.
+    @type tsig_error: int
+    @ivar other_data: TSIG other data.
+    @type other_data: string
+    @ivar mac: The TSIG MAC for this message.
+    @type mac: string
+    @ivar xfr: Is the message being used to contain the results of a DNS
+    zone transfer?  The default is False.
+    @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: 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
+    @ivar had_tsig: Did the message decoded from wire format have a TSIG
+    signature?
+    @type had_tsig: bool
+    @ivar multi: Is this message part of a multi-message sequence?  The
+    default is false.  This variable is used when validating TSIG signatures
+    on messages which are part of a zone transfer.
+    @type multi: bool
+    @ivar first: Is this message standalone, or the first of a multi
+    message sequence?  This variable is used when validating TSIG signatures
+    on messages which are part of a zone transfer.
+    @type first: bool
+    @ivar index: An index of rrsets in the message.  The index key is
+    (section, name, rdclass, rdtype, covers, deleting).  Indexing can be
+    disabled by setting the index to None.
+    @type index: dict
+    """
+
+    def __init__(self, id=None):
+        if id is None:
+            self.id = dns.entropy.random_16()
+        else:
+            self.id = id
+        self.flags = 0
+        self.question = []
+        self.answer = []
+        self.authority = []
+        self.additional = []
+        self.edns = -1
+        self.ednsflags = 0
+        self.payload = 0
+        self.options = []
+        self.request_payload = 0
+        self.keyring = None
+        self.keyname = None
+        self.keyalgorithm = dns.tsig.default_algorithm
+        self.request_mac = ''
+        self.other_data = ''
+        self.tsig_error = 0
+        self.fudge = 300
+        self.original_id = self.id
+        self.mac = ''
+        self.xfr = False
+        self.origin = None
+        self.tsig_ctx = None
+        self.had_tsig = False
+        self.multi = False
+        self.first = True
+        self.index = {}
+
+    def __repr__(self):
+        return '<DNS message, ID ' + `self.id` + '>'
+
+    def __str__(self):
+        return self.to_text()
+
+    def to_text(self,  origin=None, relativize=True, **kw):
+        """Convert the message to text.
+
+        The I{origin}, I{relativize}, and any other keyword
+        arguments are passed to the rrset to_wire() method.
+
+        @rtype: string
+        """
+
+        s = cStringIO.StringIO()
+        print >> s, 'id %d' % self.id
+        print >> s, 'opcode %s' % \
+              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' % \
+                      dns.flags.edns_to_text(self.ednsflags)
+            print >> s, 'payload', self.payload
+        is_update = dns.opcode.is_update(self.flags)
+        if is_update:
+            print >> s, ';ZONE'
+        else:
+            print >> s, ';QUESTION'
+        for rrset in self.question:
+            print >> s, rrset.to_text(origin, relativize, **kw)
+        if is_update:
+            print >> s, ';PREREQ'
+        else:
+            print >> s, ';ANSWER'
+        for rrset in self.answer:
+            print >> s, rrset.to_text(origin, relativize, **kw)
+        if is_update:
+            print >> s, ';UPDATE'
+        else:
+            print >> s, ';AUTHORITY'
+        for rrset in self.authority:
+            print >> s, rrset.to_text(origin, relativize, **kw)
+        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):
+        """Two messages are equal if they have the same content in the
+        header, question, answer, and authority sections.
+        @rtype: bool"""
+        if not isinstance(other, Message):
+            return False
+        if self.id != other.id:
+            return False
+        if self.flags != other.flags:
+            return False
+        for n in self.question:
+            if n not in other.question:
+                return False
+        for n in other.question:
+            if n not in self.question:
+                return False
+        for n in self.answer:
+            if n not in other.answer:
+                return False
+        for n in other.answer:
+            if n not in self.answer:
+                return False
+        for n in self.authority:
+            if n not in other.authority:
+                return False
+        for n in other.authority:
+            if n not in self.authority:
+                return False
+        return True
+
+    def __ne__(self, other):
+        """Are two messages not equal?
+        @rtype: bool"""
+        return not self.__eq__(other)
+
+    def is_response(self, other):
+        """Is other a response to self?
+        @rtype: bool"""
+        if other.flags & dns.flags.QR == 0 or \
+           self.id != other.id or \
+           dns.opcode.from_flags(self.flags) != \
+           dns.opcode.from_flags(other.flags):
+            return False
+        if dns.rcode.from_flags(other.flags, other.ednsflags) != \
+               dns.rcode.NOERROR:
+            return True
+        if dns.opcode.is_update(self.flags):
+            return True
+        for n in self.question:
+            if n not in other.question:
+                return False
+        for n in other.question:
+            if n not in self.question:
+                return False
+        return True
+
+    def section_number(self, section):
+        if section is self.question:
+            return 0
+        elif section is self.answer:
+            return 1
+        elif section is self.authority:
+            return 2
+        elif section is self.additional:
+            return 3
+        else:
+            raise ValueError('unknown section')
+
+    def find_rrset(self, section, name, rdclass, rdtype,
+                   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 dns.rrset.RRset objects
+        @param name: the name of the RRset
+        @type name: dns.name.Name object
+        @param rdclass: the class of the RRset
+        @type rdclass: int
+        @param rdtype: the type of the RRset
+        @type rdtype: int
+        @param covers: the covers value of the RRset
+        @type covers: int
+        @param deleting: the deleting value of the RRset
+        @type deleting: int
+        @param create: If True, create the RRset if it is not found.
+        The created RRset is appended to I{section}.
+        @type create: bool
+        @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
+        @raises KeyError: the RRset was not found and create was False
+        @rtype: dns.rrset.RRset object"""
+
+        key = (self.section_number(section),
+               name, rdclass, rdtype, covers, deleting)
+        if not force_unique:
+            if not self.index is None:
+                rrset = self.index.get(key)
+                if not rrset is None:
+                    return rrset
+            else:
+                for rrset in section:
+                    if rrset.match(name, rdclass, rdtype, covers, deleting):
+                        return rrset
+        if not create:
+            raise KeyError
+        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=dns.rdatatype.NONE, deleting=None, create=False,
+                  force_unique=False):
+        """Get the RRset with the given attributes in the specified section.
+
+        If the RRset is not found, None is returned.
+
+        @param section: the section of the message to look in, e.g.
+        self.answer.
+        @type section: list of dns.rrset.RRset objects
+        @param name: the name of the RRset
+        @type name: dns.name.Name object
+        @param rdclass: the class of the RRset
+        @type rdclass: int
+        @param rdtype: the type of the RRset
+        @type rdtype: int
+        @param covers: the covers value of the RRset
+        @type covers: int
+        @param deleting: the deleting value of the RRset
+        @type deleting: int
+        @param create: If True, create the RRset if it is not found.
+        The created RRset is appended to I{section}.
+        @type create: bool
+        @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: dns.rrset.RRset object or None"""
+
+        try:
+            rrset = self.find_rrset(section, name, rdclass, rdtype, covers,
+                                    deleting, create, force_unique)
+        except KeyError:
+            rrset = None
+        return rrset
+
+    def to_wire(self, origin=None, max_size=0, **kw):
+        """Return a string containing the message in DNS compressed wire
+        format.
+
+        Additional keyword arguments are passed to the rrset to_wire()
+        method.
+
+        @param origin: The origin to be appended to any relative names.
+        @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 dns.exception.TooBig: max_size was exceeded
+        @rtype: string
+        """
+
+        if max_size == 0:
+            if self.request_payload != 0:
+                max_size = self.request_payload
+            else:
+                max_size = 65535
+        if max_size < 512:
+            max_size = 512
+        elif max_size > 65535:
+            max_size = 65535
+        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(dns.renderer.ANSWER, rrset, **kw)
+        for rrset in self.authority:
+            r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw)
+        if self.edns >= 0:
+            r.add_edns(self.edns, self.ednsflags, self.payload, self.options)
+        for rrset in self.additional:
+            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],
+                       self.fudge, self.original_id, self.tsig_error,
+                       self.other_data, self.request_mac,
+                       self.keyalgorithm)
+            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=dns.tsig.default_algorithm):
+        """When sending, a TSIG signature using the specified keyring
+        and keyname should be added.
+
+        @param keyring: The TSIG keyring to use; defaults to None.
+        @type keyring: dict
+        @param keyname: The name of the TSIG key to use; defaults to None.
+        The key must be defined in the keyring.  If a keyring is specified
+        but a keyname is not, then the key used will be the first key in the
+        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: 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
+        @type original_id: int
+        @param tsig_error: TSIG error code; default is 0.
+        @type tsig_error: int
+        @param other_data: TSIG other data.
+        @type other_data: string
+        @param algorithm: The TSIG algorithm to use; defaults to
+        dns.tsig.default_algorithm
+        """
+
+        self.keyring = keyring
+        if keyname is None:
+            self.keyname = self.keyring.keys()[0]
+        else:
+            if isinstance(keyname, (str, unicode)):
+                keyname = dns.name.from_text(keyname)
+            self.keyname = keyname
+        self.keyalgorithm = algorithm
+        self.fudge = fudge
+        if original_id is None:
+            self.original_id = self.id
+        else:
+            self.original_id = original_id
+        self.tsig_error = tsig_error
+        self.other_data = other_data
+
+    def use_edns(self, edns=0, ednsflags=0, payload=1280, request_payload=None, options=None):
+        """Configure EDNS behavior.
+        @param edns: The EDNS level to use.  Specifying None, False, or -1
+        means 'do not use EDNS', and in this case the other parameters are
+        ignored.  Specifying True is equivalent to specifying 0, i.e. 'use
+        EDNS0'.
+        @type edns: int or bool or None
+        @param ednsflags: EDNS flag values.
+        @type ednsflags: int
+        @param payload: The EDNS sender's payload field, which is the maximum
+        size of UDP datagram the sender can handle.
+        @type payload: int
+        @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
+        @param options: The EDNS options
+        @type options: None or list of dns.edns.Option objects
+        @see: RFC 2671
+        """
+        if edns is None or edns is False:
+            edns = -1
+        if edns is True:
+            edns = 0
+        if request_payload is None:
+            request_payload = payload
+        if edns < 0:
+            ednsflags = 0
+            payload = 0
+            request_payload = 0
+            options = []
+        else:
+            # make sure the EDNS version in ednsflags agrees with edns
+            ednsflags &= 0xFF00FFFFL
+            ednsflags |= (edns << 16)
+            if options is None:
+                options = []
+        self.edns = edns
+        self.ednsflags = ednsflags
+        self.payload = payload
+        self.options = options
+        self.request_payload = request_payload
+
+    def want_dnssec(self, wanted=True):
+        """Enable or disable 'DNSSEC desired' flag in requests.
+        @param wanted: Is DNSSEC desired?  If True, EDNS is enabled if
+        required, and then the DO bit is set.  If False, the DO bit is
+        cleared if EDNS is enabled.
+        @type wanted: bool
+        """
+        if wanted:
+            if self.edns < 0:
+                self.use_edns()
+            self.ednsflags |= dns.flags.DO
+        elif self.edns >= 0:
+            self.ednsflags &= ~dns.flags.DO
+
+    def rcode(self):
+        """Return the rcode.
+        @rtype: int
+        """
+        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) = dns.rcode.to_flags(rcode)
+        self.flags &= 0xFFF0
+        self.flags |= value
+        self.ednsflags &= 0x00FFFFFFL
+        self.ednsflags |= evalue
+        if self.ednsflags != 0 and self.edns < 0:
+            self.edns = 0
+
+    def opcode(self):
+        """Return the opcode.
+        @rtype: int
+        """
+        return dns.opcode.from_flags(self.flags)
+
+    def set_opcode(self, opcode):
+        """Set the opcode.
+        @param opcode: the opcode
+        @type opcode: int
+        """
+        self.flags &= 0x87FF
+        self.flags |= dns.opcode.to_flags(opcode)
+
+class _WireReader(object):
+    """Wire format reader.
+
+    @ivar wire: the wire-format message.
+    @type wire: string
+    @ivar message: The message object being built
+    @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.
+    @type current: int
+    @ivar updating: Is the message a dynamic update?
+    @type updating: bool
+    @ivar one_rr_per_rrset: Put each RR into its own RRset?
+    @type one_rr_per_rrset: bool
+    @ivar zone_rdclass: The class of the zone in messages which are
+    DNS dynamic updates.
+    @type zone_rdclass: int
+    """
+
+    def __init__(self, wire, message, question_only=False,
+                 one_rr_per_rrset=False):
+        self.wire = wire
+        self.message = message
+        self.current = 0
+        self.updating = False
+        self.zone_rdclass = dns.rdataclass.IN
+        self.question_only = question_only
+        self.one_rr_per_rrset = one_rr_per_rrset
+
+    def _get_question(self, qcount):
+        """Read the next I{qcount} records from the wire data and add them to
+        the question section.
+        @param qcount: the number of questions in the message
+        @type qcount: int"""
+
+        if self.updating and qcount > 1:
+            raise dns.exception.FormError
+
+        for i in xrange(0, qcount):
+            (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
+            (rdtype, rdclass) = \
+                     struct.unpack('!HH',
+                                   self.wire[self.current:self.current + 4])
+            self.current = self.current + 4
+            self.message.find_rrset(self.message.question, qname,
+                                    rdclass, rdtype, create=True,
+                                    force_unique=True)
+            if self.updating:
+                self.zone_rdclass = rdclass
+
+    def _get_section(self, section, count):
+        """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 dns.rrset.RRset objects
+        @param count: the number of records to read
+        @type count: int"""
+
+        if self.updating or self.one_rr_per_rrset:
+            force_unique = True
+        else:
+            force_unique = False
+        seen_opt = False
+        for i in xrange(0, count):
+            rr_start = 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)
+            self.current = self.current + used
+            (rdtype, rdclass, ttl, rdlen) = \
+                     struct.unpack('!HHIH',
+                                   self.wire[self.current:self.current + 10])
+            self.current = self.current + 10
+            if rdtype == dns.rdatatype.OPT:
+                if not section is self.message.additional or seen_opt:
+                    raise BadEDNS
+                self.message.payload = rdclass
+                self.message.ednsflags = ttl
+                self.message.edns = (ttl & 0xff0000) >> 16
+                self.message.options = []
+                current = self.current
+                optslen = rdlen
+                while optslen > 0:
+                    (otype, olen) = \
+                            struct.unpack('!HH',
+                                          self.wire[current:current + 4])
+                    current = current + 4
+                    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 == dns.rdatatype.TSIG:
+                if not (section is self.message.additional and
+                        i == (count - 1)):
+                    raise BadTSIG
+                if self.message.keyring is None:
+                    raise UnknownTSIGKey('got signed message without keyring')
+                secret = self.message.keyring.get(absolute_name)
+                if secret is None:
+                    raise UnknownTSIGKey("key '%s' unknown" % name)
+                self.message.tsig_ctx = \
+                                      dns.tsig.validate(self.wire,
+                                          absolute_name,
+                                          secret,
+                                          int(time.time()),
+                                          self.message.request_mac,
+                                          rr_start,
+                                          self.current,
+                                          rdlen,
+                                          self.message.tsig_ctx,
+                                          self.message.multi,
+                                          self.message.first)
+                self.message.had_tsig = True
+            else:
+                if ttl < 0:
+                    ttl = 0
+                if self.updating and \
+                   (rdclass == dns.rdataclass.ANY or
+                    rdclass == dns.rdataclass.NONE):
+                    deleting = rdclass
+                    rdclass = self.zone_rdclass
+                else:
+                    deleting = None
+                if deleting == dns.rdataclass.ANY or \
+                   (deleting == dns.rdataclass.NONE and \
+                    section == self.message.answer):
+                    covers = dns.rdatatype.NONE
+                    rd = None
+                else:
+                    rd = dns.rdata.from_wire(rdclass, rdtype, self.wire,
+                                             self.current, rdlen,
+                                             self.message.origin)
+                    covers = rd.covers()
+                if self.message.xfr and rdtype == dns.rdatatype.SOA:
+                    force_unique = True
+                rrset = self.message.find_rrset(section, name,
+                                                rdclass, rdtype, covers,
+                                                deleting, True, force_unique)
+                if not rd is None:
+                    rrset.add(rd, ttl)
+            self.current = self.current + rdlen
+
+    def read(self):
+        """Read a wire format DNS message and build a dns.message.Message
+        object."""
+
+        l = len(self.wire)
+        if l < 12:
+            raise ShortHeader
+        (self.message.id, self.message.flags, qcount, ancount,
+         aucount, adcount) = struct.unpack('!HHHHHH', self.wire[:12])
+        self.current = 12
+        if dns.opcode.is_update(self.message.flags):
+            self.updating = True
+        self._get_question(qcount)
+        if self.question_only:
+            return
+        self._get_section(self.message.answer, ancount)
+        self._get_section(self.message.authority, aucount)
+        self._get_section(self.message.additional, adcount)
+        if self.current != l:
+            raise TrailingJunk
+        if self.message.multi and self.message.tsig_ctx and \
+               not self.message.had_tsig:
+            self.message.tsig_ctx.update(self.wire)
+
+
+def from_wire(wire, keyring=None, request_mac='', xfr=False, origin=None,
+              tsig_ctx = None, multi = False, first = True,
+              question_only = False, one_rr_per_rrset = False):
+    """Convert a DNS wire format message into a message
+    object.
+
+    @param keyring: The keyring to use if the message is signed.
+    @type keyring: dict
+    @param request_mac: If the message is a response to a TSIG-signed request,
+    I{request_mac} should be set to the MAC of that request.
+    @type request_mac: string
+    @param xfr: Is this message part of a zone transfer?
+    @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: dns.name.Name object
+    @param tsig_ctx: The ongoing TSIG context, used when validating zone
+    transfers.
+    @type tsig_ctx: hmac.HMAC object
+    @param multi: Is this message part of a multiple message sequence?
+    @type multi: bool
+    @param first: Is this message standalone, or the first of a multi
+    message sequence?
+    @type first: bool
+    @param question_only: Read only up to the end of the question section?
+    @type question_only: bool
+    @param one_rr_per_rrset: Put each RR into its own RRset
+    @type one_rr_per_rrset: bool
+    @raises ShortHeader: The message is less than 12 octets long.
+    @raises TrailingJunk: There were octets in the message past the end
+    of the proper DNS message.
+    @raises BadEDNS: An OPT record was in the wrong section, or occurred more
+    than once.
+    @raises BadTSIG: A TSIG record was not the last record of the additional
+    data section.
+    @rtype: dns.message.Message object"""
+
+    m = Message(id=0)
+    m.keyring = keyring
+    m.request_mac = request_mac
+    m.xfr = xfr
+    m.origin = origin
+    m.tsig_ctx = tsig_ctx
+    m.multi = multi
+    m.first = first
+
+    reader = _WireReader(wire, m, question_only, one_rr_per_rrset)
+    reader.read()
+
+    return m
+
+
+class _TextReader(object):
+    """Text format reader.
+
+    @ivar tok: the tokenizer
+    @type tok: dns.tokenizer.Tokenizer object
+    @ivar message: The message object being built
+    @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
+    DNS dynamic updates.
+    @type zone_rdclass: int
+    @ivar last_name: The most recently read name when building a message object
+    from text format.
+    @type last_name: dns.name.Name object
+    """
+
+    def __init__(self, text, message):
+        self.message = message
+        self.tok = dns.tokenizer.Tokenizer(text)
+        self.last_name = None
+        self.zone_rdclass = dns.rdataclass.IN
+        self.updating = False
+
+    def _header_line(self, section):
+        """Process one line from the text format header section."""
+
+        token = self.tok.get()
+        what = token.value
+        if what == 'id':
+            self.message.id = self.tok.get_int()
+        elif what == 'flags':
+            while True:
+                token = self.tok.get()
+                if not token.is_identifier():
+                    self.tok.unget(token)
+                    break
+                self.message.flags = 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()
+            self.message.ednsflags = self.message.ednsflags | \
+                                     (self.message.edns << 16)
+        elif what == 'eflags':
+            if self.message.edns < 0:
+                self.message.edns = 0
+            while True:
+                token = self.tok.get()
+                if not token.is_identifier():
+                    self.tok.unget(token)
+                    break
+                self.message.ednsflags = self.message.ednsflags | \
+                              dns.flags.edns_from_text(token.value)
+        elif what == 'payload':
+            self.message.payload = self.tok.get_int()
+            if self.message.edns < 0:
+                self.message.edns = 0
+        elif what == 'opcode':
+            text = self.tok.get_string()
+            self.message.flags = self.message.flags | \
+                      dns.opcode.to_flags(dns.opcode.from_text(text))
+        elif what == 'rcode':
+            text = self.tok.get_string()
+            self.message.set_rcode(dns.rcode.from_text(text))
+        else:
+            raise UnknownHeaderField
+        self.tok.get_eol()
+
+    def _question_line(self, section):
+        """Process one line from the text format question section."""
+
+        token = self.tok.get(want_leading = True)
+        if not token.is_whitespace():
+            self.last_name = dns.name.from_text(token.value, None)
+        name = self.last_name
+        token = self.tok.get()
+        if not token.is_identifier():
+            raise dns.exception.SyntaxError
+        # 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 = dns.rdataclass.IN
+        # Type
+        rdtype = dns.rdatatype.from_text(token.value)
+        self.message.find_rrset(self.message.question, name,
+                                rdclass, rdtype, create=True,
+                                force_unique=True)
+        if self.updating:
+            self.zone_rdclass = rdclass
+        self.tok.get_eol()
+
+    def _rr_line(self, section):
+        """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 = dns.name.from_text(token.value, None)
+        name = self.last_name
+        token = self.tok.get()
+        if not token.is_identifier():
+            raise dns.exception.SyntaxError
+        # TTL
+        try:
+            ttl = int(token.value, 0)
+            token = self.tok.get()
+            if not token.is_identifier():
+                raise dns.exception.SyntaxError
+        except dns.exception.SyntaxError:
+            raise dns.exception.SyntaxError
+        except:
+            ttl = 0
+        # Class
+        try:
+            rdclass = dns.rdataclass.from_text(token.value)
+            token = self.tok.get()
+            if not token.is_identifier():
+                raise dns.exception.SyntaxError
+            if rdclass == dns.rdataclass.ANY or rdclass == dns.rdataclass.NONE:
+                deleting = rdclass
+                rdclass = self.zone_rdclass
+        except dns.exception.SyntaxError:
+            raise dns.exception.SyntaxError
+        except:
+            rdclass = dns.rdataclass.IN
+        # Type
+        rdtype = dns.rdatatype.from_text(token.value)
+        token = self.tok.get()
+        if not token.is_eol_or_eof():
+            self.tok.unget(token)
+            rd = dns.rdata.from_text(rdclass, rdtype, self.tok, None)
+            covers = rd.covers()
+        else:
+            rd = None
+            covers = dns.rdatatype.NONE
+        rrset = self.message.find_rrset(section, name,
+                                        rdclass, rdtype, covers,
+                                        deleting, True, self.updating)
+        if not rd is None:
+            rrset.add(rd, ttl)
+
+    def read(self):
+        """Read a text format DNS message and build a dns.message.Message
+        object."""
+
+        line_method = self._header_line
+        section = None
+        while 1:
+            token = self.tok.get(True, True)
+            if token.is_eol_or_eof():
+                break
+            if token.is_comment():
+                u = token.value.upper()
+                if u == 'HEADER':
+                    line_method = self._header_line
+                elif u == 'QUESTION' or u == 'ZONE':
+                    line_method = self._question_line
+                    section = self.message.question
+                elif u == 'ANSWER' or u == 'PREREQ':
+                    line_method = self._rr_line
+                    section = self.message.answer
+                elif u == 'AUTHORITY' or u == 'UPDATE':
+                    line_method = self._rr_line
+                    section = self.message.authority
+                elif u == 'ADDITIONAL':
+                    line_method = self._rr_line
+                    section = self.message.additional
+                self.tok.get_eol()
+                continue
+            self.tok.unget(token)
+            line_method(section)
+
+
+def from_text(text):
+    """Convert the text format message into a message object.
+
+    @param text: The text format message.
+    @type text: string
+    @raises UnknownHeaderField:
+    @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
+    # interface is from_file().
+
+    m = Message()
+
+    reader = _TextReader(text, m)
+    reader.read()
+
+    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 dns.exception.SyntaxError:
+    @rtype: dns.message.Message object"""
+
+    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
+    else:
+        want_close = False
+
+    try:
+        m = from_text(f)
+    finally:
+        if want_close:
+            f.close()
+    return m
+
+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 dns.flags.RD.
+
+    @param qname: The query name.
+    @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 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: dns.message.Message object"""
+
+    if isinstance(qname, (str, unicode)):
+        qname = dns.name.from_text(qname)
+    if isinstance(rdtype, str):
+        rdtype = dns.rdatatype.from_text(rdtype)
+    if isinstance(rdclass, str):
+        rdclass = dns.rdataclass.from_text(rdclass)
+    m = Message()
+    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
+    of the infrastructure required of a response, but none of the
+    content.
+
+    The response's question section is a shallow copy of the query's
+    question section, so the query's question RRsets should not be
+    changed.
+
+    @param query: the query to respond to
+    @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: dns.message.Message object"""
+
+    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 |= dns.flags.RA
+    response.set_opcode(query.opcode())
+    response.question = list(query.question)
+    if query.edns >= 0:
+        response.use_edns(0, 0, our_payload, query.payload)
+    if not query.keyname is None:
+        response.keyname = query.keyname
+        response.keyring = query.keyring
+        response.request_mac = query.mac
+    return response
diff --git a/source4/scripting/python/samba_external/dnspython/dns/name.py b/source4/scripting/python/samba_external/dnspython/dns/name.py
new file mode 100644 (file)
index 0000000..f239c9b
--- /dev/null
@@ -0,0 +1,700 @@
+# Copyright (C) 2001-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.
+
+"""DNS Names.
+
+@var root: The DNS root name.
+@type root: dns.name.Name object
+@var empty: The empty DNS name.
+@type empty: dns.name.Name object
+"""
+
+import cStringIO
+import struct
+import sys
+
+if sys.hexversion >= 0x02030000:
+    import encodings.idna
+
+import dns.exception
+
+NAMERELN_NONE = 0
+NAMERELN_SUPERDOMAIN = 1
+NAMERELN_SUBDOMAIN = 2
+NAMERELN_EQUAL = 3
+NAMERELN_COMMONANCESTOR = 4
+
+class EmptyLabel(dns.exception.SyntaxError):
+    """Raised if a label is empty."""
+    pass
+
+class BadEscape(dns.exception.SyntaxError):
+    """Raised if an escaped code in a text format name is invalid."""
+    pass
+
+class BadPointer(dns.exception.FormError):
+    """Raised if a compression pointer points forward instead of backward."""
+    pass
+
+class BadLabelType(dns.exception.FormError):
+    """Raised if the label type of a wire format name is unknown."""
+    pass
+
+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(dns.exception.FormError):
+    """Raised if a name is > 255 octets long."""
+    pass
+
+class LabelTooLong(dns.exception.SyntaxError):
+    """Raised if a label is > 63 octets long."""
+    pass
+
+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(dns.exception.DNSException):
+    """Raised if an attempt is made to get the parent of the root name
+    or the empty name."""
+    pass
+
+_escaped = {
+    '"' : True,
+    '(' : True,
+    ')' : True,
+    '.' : True,
+    ';' : True,
+    '\\' : True,
+    '@' : True,
+    '$' : True
+    }
+
+def _escapify(label):
+    """Escape the characters in label which need it.
+    @returns: the escaped string
+    @rtype: string"""
+    text = ''
+    for c in label:
+        if c in _escaped:
+            text += '\\' + c
+        elif ord(c) > 0x20 and ord(c) < 0x7F:
+            text += c
+        else:
+            text += '\\%03d' % ord(c)
+    return text
+
+def _validate_labels(labels):
+    """Check for empty labels in the middle of a label sequence,
+    labels that are too long, and for too many labels.
+    @raises NameTooLong: the name as a whole is too long
+    @raises LabelTooLong: an individual label is too long
+    @raises EmptyLabel: a label is empty (i.e. the root label) and appears
+    in a position other than the end of the label sequence"""
+
+    l = len(labels)
+    total = 0
+    i = -1
+    j = 0
+    for label in labels:
+        ll = len(label)
+        total += ll + 1
+        if ll > 63:
+            raise LabelTooLong
+        if i < 0 and label == '':
+            i = j
+        j += 1
+    if total > 255:
+        raise NameTooLong
+    if i >= 0 and i != l - 1:
+        raise EmptyLabel
+
+class Name(object):
+    """A DNS name.
+
+    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
+    up to 63 octets."""
+
+    __slots__ = ['labels']
+
+    def __init__(self, labels):
+        """Initialize a domain name from a list of labels.
+        @param labels: the labels
+        @type labels: any iterable whose values are strings
+        """
+
+        super(Name, self).__setattr__('labels', tuple(labels))
+        _validate_labels(self.labels)
+
+    def __setattr__(self, name, value):
+        raise TypeError("object doesn't support attribute assignment")
+
+    def is_absolute(self):
+        """Is the most significant label of this name the root label?
+        @rtype: bool
+        """
+
+        return len(self.labels) > 0 and self.labels[-1] == ''
+
+    def is_wild(self):
+        """Is this name wild?  (I.e. Is the least significant label '*'?)
+        @rtype: bool
+        """
+
+        return len(self.labels) > 0 and self.labels[0] == '*'
+
+    def __hash__(self):
+        """Return a case-insensitive hash of the name.
+        @rtype: int
+        """
+
+        h = 0L
+        for label in self.labels:
+            for c in label:
+                h += ( h << 3 ) + ord(c.lower())
+        return int(h % sys.maxint)
+
+    def fullcompare(self, other):
+        """Compare two names, returning a 3-tuple (relation, order, nlabels).
+
+        I{relation} describes the relation ship beween the names,
+        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
+        absolute name.  If both names have the same relativity, then
+        the DNSSEC order relation is used to order them.
+
+        I{nlabels} is the number of significant labels that the two names
+        have in common.
+        """
+
+        sabs = self.is_absolute()
+        oabs = other.is_absolute()
+        if sabs != oabs:
+            if sabs:
+                return (NAMERELN_NONE, 1, 0)
+            else:
+                return (NAMERELN_NONE, -1, 0)
+        l1 = len(self.labels)
+        l2 = len(other.labels)
+        ldiff = l1 - l2
+        if ldiff < 0:
+            l = l1
+        else:
+            l = l2
+
+        order = 0
+        nlabels = 0
+        namereln = NAMERELN_NONE
+        while l > 0:
+            l -= 1
+            l1 -= 1
+            l2 -= 1
+            label1 = self.labels[l1].lower()
+            label2 = other.labels[l2].lower()
+            if label1 < label2:
+                order = -1
+                if nlabels > 0:
+                    namereln = NAMERELN_COMMONANCESTOR
+                return (namereln, order, nlabels)
+            elif label1 > label2:
+                order = 1
+                if nlabels > 0:
+                    namereln = NAMERELN_COMMONANCESTOR
+                return (namereln, order, nlabels)
+            nlabels += 1
+        order = ldiff
+        if ldiff < 0:
+            namereln = NAMERELN_SUPERDOMAIN
+        elif ldiff > 0:
+            namereln = NAMERELN_SUBDOMAIN
+        else:
+            namereln = NAMERELN_EQUAL
+        return (namereln, order, nlabels)
+
+    def is_subdomain(self, other):
+        """Is self a subdomain of other?
+
+        The notion of subdomain includes equality.
+        @rtype: bool
+        """
+
+        (nr, o, nl) = self.fullcompare(other)
+        if nr == NAMERELN_SUBDOMAIN or nr == NAMERELN_EQUAL:
+            return True
+        return False
+
+    def is_superdomain(self, other):
+        """Is self a superdomain of other?
+
+        The notion of subdomain includes equality.
+        @rtype: bool
+        """
+
+        (nr, o, nl) = self.fullcompare(other)
+        if nr == NAMERELN_SUPERDOMAIN or nr == NAMERELN_EQUAL:
+            return True
+        return False
+
+    def canonicalize(self):
+        """Return a name which is equal to the current name, but is in
+        DNSSEC canonical form.
+        @rtype: dns.name.Name object
+        """
+
+        return Name([x.lower() for x in self.labels])
+
+    def __eq__(self, other):
+        if isinstance(other, Name):
+            return self.fullcompare(other)[1] == 0
+        else:
+            return False
+
+    def __ne__(self, other):
+        if isinstance(other, Name):
+            return self.fullcompare(other)[1] != 0
+        else:
+            return True
+
+    def __lt__(self, other):
+        if isinstance(other, Name):
+            return self.fullcompare(other)[1] < 0
+        else:
+            return NotImplemented
+
+    def __le__(self, other):
+        if isinstance(other, Name):
+            return self.fullcompare(other)[1] <= 0
+        else:
+            return NotImplemented
+
+    def __ge__(self, other):
+        if isinstance(other, Name):
+            return self.fullcompare(other)[1] >= 0
+        else:
+            return NotImplemented
+
+    def __gt__(self, other):
+        if isinstance(other, Name):
+            return self.fullcompare(other)[1] > 0
+        else:
+            return NotImplemented
+
+    def __repr__(self):
+        return '<DNS name ' + self.__str__() + '>'
+
+    def __str__(self):
+        return self.to_text(False)
+
+    def to_text(self, omit_final_dot = False):
+        """Convert name to text format.
+        @param omit_final_dot: If True, don't emit the final dot (denoting the
+        root label) for absolute names.  The default is False.
+        @rtype: string
+        """
+
+        if len(self.labels) == 0:
+            return '@'
+        if len(self.labels) == 1 and self.labels[0] == '':
+            return '.'
+        if omit_final_dot and self.is_absolute():
+            l = self.labels[:-1]
+        else:
+            l = self.labels
+        s = '.'.join(map(_escapify, l))
+        return s
+
+    def to_unicode(self, omit_final_dot = False):
+        """Convert name to Unicode text format.
+
+        IDN ACE lables are converted to Unicode.
+
+        @param omit_final_dot: If True, don't emit the final dot (denoting the
+        root label) for absolute names.  The default is False.
+        @rtype: string
+        """
+
+        if len(self.labels) == 0:
+            return u'@'
+        if len(self.labels) == 1 and self.labels[0] == '':
+            return u'.'
+        if omit_final_dot and self.is_absolute():
+            l = self.labels[:-1]
+        else:
+            l = self.labels
+        s = u'.'.join([encodings.idna.ToUnicode(_escapify(x)) for x in l])
+        return s
+
+    def to_digestable(self, origin=None):
+        """Convert name to a format suitable for digesting in hashes.
+
+        The name is canonicalized and converted to uncompressed wire format.
+
+        @param origin: If the name is relative and origin is not None, then
+        origin will be appended to it.
+        @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
+        @rtype: string
+        """
+
+        if not self.is_absolute():
+            if origin is None or not origin.is_absolute():
+                raise NeedAbsoluteNameOrOrigin
+            labels = list(self.labels)
+            labels.extend(list(origin.labels))
+        else:
+            labels = self.labels
+        dlabels = ["%s%s" % (chr(len(x)), x.lower()) for x in labels]
+        return ''.join(dlabels)
+
+    def to_wire(self, file = None, compress = None, origin = None):
+        """Convert name to wire format, possibly compressing it.
+
+        @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
+        will not be compressed.
+        @type compress: dict
+        @param origin: If the name is relative and origin is not None, then
+        origin will be appended to it.
+        @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 = cStringIO.StringIO()
+            want_return = True
+        else:
+            want_return = False
+
+        if not self.is_absolute():
+            if origin is None or not origin.is_absolute():
+                raise NeedAbsoluteNameOrOrigin
+            labels = list(self.labels)
+            labels.extend(list(origin.labels))
+        else:
+            labels = self.labels
+        i = 0
+        for label in labels:
+            n = Name(labels[i:])
+            i += 1
+            if not compress is None:
+                pos = compress.get(n)
+            else:
+                pos = None
+            if not pos is None:
+                value = 0xc000 + pos
+                s = struct.pack('!H', value)
+                file.write(s)
+                break
+            else:
+                if not compress is None and len(n) > 1:
+                    pos = file.tell()
+                    if pos < 0xc000:
+                        compress[n] = pos
+                l = len(label)
+                file.write(chr(l))
+                if l > 0:
+                    file.write(label)
+        if want_return:
+            return file.getvalue()
+
+    def __len__(self):
+        """The length of the name (in labels).
+        @rtype: int
+        """
+
+        return len(self.labels)
+
+    def __getitem__(self, index):
+        return self.labels[index]
+
+    def __getslice__(self, start, stop):
+        return self.labels[start:stop]
+
+    def __add__(self, other):
+        return self.concatenate(other)
+
+    def __sub__(self, other):
+        return self.relativize(other)
+
+    def split(self, depth):
+        """Split a name into a prefix and suffix at depth.
+
+        @param depth: the number of labels in the suffix
+        @type depth: int
+        @raises ValueError: the depth was not >= 0 and <= the length of the
+        name.
+        @returns: the tuple (prefix, suffix)
+        @rtype: tuple
+        """
+
+        l = len(self.labels)
+        if depth == 0:
+            return (self, dns.name.empty)
+        elif depth == l:
+            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: dns.name.Name object
+        @raises AbsoluteConcatenation: self is absolute and other is
+        not the empty name
+        """
+
+        if self.is_absolute() and len(other) > 0:
+            raise AbsoluteConcatenation
+        labels = list(self.labels)
+        labels.extend(list(other.labels))
+        return Name(labels)
+
+    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: dns.name.Name object
+        """
+
+        if not origin is None and self.is_subdomain(origin):
+            return Name(self[: -len(origin)])
+        else:
+            return self
+
+    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: dns.name.Name object
+        """
+
+        if not self.is_absolute():
+            return self.concatenate(origin)
+        else:
+            return self
+
+    def choose_relativity(self, origin=None, relativize=True):
+        """Return a name with the relativity desired by the caller.  If
+        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: dns.name.Name object
+        """
+
+        if origin:
+            if relativize:
+                return self.relativize(origin)
+            else:
+                return self.derelativize(origin)
+        else:
+            return self
+
+    def parent(self):
+        """Return the parent of the 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:
+            raise NoParent
+        return Name(self.labels[1:])
+
+root = Name([''])
+empty = Name([])
+
+def from_unicode(text, origin = root):
+    """Convert unicode text into a Name object.
+
+    Lables are encoded in IDN ACE form.
+
+    @rtype: dns.name.Name object
+    """
+
+    if not isinstance(text, unicode):
+        raise ValueError("input to from_unicode() must be a unicode string")
+    if not (origin is None or isinstance(origin, Name)):
+        raise ValueError("origin must be a Name or None")
+    labels = []
+    label = u''
+    escaping = False
+    edigits = 0
+    total = 0
+    if text == u'@':
+        text = u''
+    if text:
+        if text == u'.':
+            return Name([''])  # no Unicode "u" on this constant!
+        for c in text:
+            if escaping:
+                if edigits == 0:
+                    if c.isdigit():
+                        total = int(c)
+                        edigits += 1
+                    else:
+                        label += c
+                        escaping = False
+                else:
+                    if not c.isdigit():
+                        raise BadEscape
+                    total *= 10
+                    total += int(c)
+                    edigits += 1
+                    if edigits == 3:
+                        escaping = False
+                        label += chr(total)
+            elif c == u'.' or c == u'\u3002' or \
+                 c == u'\uff0e' or c == u'\uff61':
+                if len(label) == 0:
+                    raise EmptyLabel
+                labels.append(encodings.idna.ToASCII(label))
+                label = u''
+            elif c == u'\\':
+                escaping = True
+                edigits = 0
+                total = 0
+            else:
+                label += c
+        if escaping:
+            raise BadEscape
+        if len(label) > 0:
+            labels.append(encodings.idna.ToASCII(label))
+        else:
+            labels.append('')
+    if (len(labels) == 0 or labels[-1] != '') and not origin is None:
+        labels.extend(list(origin.labels))
+    return Name(labels)
+
+def from_text(text, origin = root):
+    """Convert text into a Name object.
+    @rtype: dns.name.Name object
+    """
+
+    if not isinstance(text, str):
+        if isinstance(text, unicode) and sys.hexversion >= 0x02030000:
+            return from_unicode(text, origin)
+        else:
+            raise ValueError("input to from_text() must be a string")
+    if not (origin is None or isinstance(origin, Name)):
+        raise ValueError("origin must be a Name or None")
+    labels = []
+    label = ''
+    escaping = False
+    edigits = 0
+    total = 0
+    if text == '@':
+        text = ''
+    if text:
+        if text == '.':
+            return Name([''])
+        for c in text:
+            if escaping:
+                if edigits == 0:
+                    if c.isdigit():
+                        total = int(c)
+                        edigits += 1
+                    else:
+                        label += c
+                        escaping = False
+                else:
+                    if not c.isdigit():
+                        raise BadEscape
+                    total *= 10
+                    total += int(c)
+                    edigits += 1
+                    if edigits == 3:
+                        escaping = False
+                        label += chr(total)
+            elif c == '.':
+                if len(label) == 0:
+                    raise EmptyLabel
+                labels.append(label)
+                label = ''
+            elif c == '\\':
+                escaping = True
+                edigits = 0
+                total = 0
+            else:
+                label += c
+        if escaping:
+            raise BadEscape
+        if len(label) > 0:
+            labels.append(label)
+        else:
+            labels.append('')
+    if (len(labels) == 0 or labels[-1] != '') and not origin is None:
+        labels.extend(list(origin.labels))
+    return Name(labels)
+
+def from_wire(message, current):
+    """Convert possibly compressed wire format into a Name.
+    @param message: the entire DNS message
+    @type message: string
+    @param current: the offset of the beginning of the name from the start
+    of the message
+    @type current: int
+    @raises dns.name.BadPointer: a compression pointer did not point backwards
+    in the message
+    @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: (dns.name.Name object, int) tuple
+    """
+
+    if not isinstance(message, str):
+        raise ValueError("input to from_wire() must be a byte string")
+    labels = []
+    biggest_pointer = current
+    hops = 0
+    count = ord(message[current])
+    current += 1
+    cused = 1
+    while count != 0:
+        if count < 64:
+            labels.append(message[current : current + count])
+            current += count
+            if hops == 0:
+                cused += count
+        elif count >= 192:
+            current = (count & 0x3f) * 256 + ord(message[current])
+            if hops == 0:
+                cused += 1
+            if current >= biggest_pointer:
+                raise BadPointer
+            biggest_pointer = current
+            hops += 1
+        else:
+            raise BadLabelType
+        count = ord(message[current])
+        current += 1
+        if hops == 0:
+            cused += 1
+    labels.append('')
+    return (Name(labels), cused)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/namedict.py b/source4/scripting/python/samba_external/dnspython/dns/namedict.py
new file mode 100644 (file)
index 0000000..54afb77
--- /dev/null
@@ -0,0 +1,59 @@
+# 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.
+
+"""DNS name dictionary"""
+
+import dns.name
+
+class NameDict(dict):
+
+    """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
+    """
+
+    def __init__(self, *args, **kwargs):
+        super(NameDict, self).__init__(*args, **kwargs)
+        self.max_depth = 0
+
+    def __setitem__(self, key, value):
+        if not isinstance(key, dns.name.Name):
+            raise ValueError('NameDict key must be a name')
+        depth = len(key)
+        if depth > self.max_depth:
+            self.max_depth = depth
+        super(NameDict, self).__setitem__(key, value)
+
+    def get_deepest_match(self, name):
+        """Find the deepest match to I{name} in the dictionary.
+
+        The deepest match is the longest name in the dictionary which is
+        a superdomain of I{name}.
+
+        @param name: the name
+        @type name: dns.name.Name object
+        @rtype: (key, value) tuple
+        """
+
+        depth = len(name)
+        if depth > self.max_depth:
+            depth = self.max_depth
+        for i in xrange(-depth, 0):
+            n = dns.name.Name(name[i:])
+            if self.has_key(n):
+                return (n, self[n])
+        v = self[dns.name.empty]
+        return (dns.name.empty, v)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/node.py b/source4/scripting/python/samba_external/dnspython/dns/node.py
new file mode 100644 (file)
index 0000000..785a245
--- /dev/null
@@ -0,0 +1,172 @@
+# Copyright (C) 2001-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.
+
+"""DNS nodes.  A node is a set of rdatasets."""
+
+import StringIO
+
+import dns.rdataset
+import dns.rdatatype
+import dns.renderer
+
+class Node(object):
+    """A DNS node.
+
+    A node is a set of rdatasets
+
+    @ivar rdatasets: the node's rdatasets
+    @type rdatasets: list of dns.rdataset.Rdataset objects"""
+
+    __slots__ = ['rdatasets']
+
+    def __init__(self):
+        """Initialize a DNS node.
+        """
+
+        self.rdatasets = [];
+
+    def to_text(self, name, **kw):
+        """Convert a node to text format.
+
+        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: dns.name.Name object
+        @rtype: string
+        """
+
+        s = StringIO.StringIO()
+        for rds in self.rdatasets:
+            print >> s, rds.to_text(name, **kw)
+        return s.getvalue()[:-1]
+
+    def __repr__(self):
+        return '<DNS node ' + str(id(self)) + '>'
+
+    def __eq__(self, other):
+        """Two nodes are equal if they have the same rdatasets.
+
+        @rtype: bool
+        """
+        #
+        # This is inefficient.  Good thing we don't need to do it much.
+        #
+        for rd in self.rdatasets:
+            if rd not in other.rdatasets:
+                return False
+        for rd in other.rdatasets:
+            if rd not in self.rdatasets:
+                return False
+        return True
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __len__(self):
+        return len(self.rdatasets)
+
+    def __iter__(self):
+        return iter(self.rdatasets)
+
+    def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
+                      create=False):
+        """Find an rdataset matching the specified properties in the
+        current node.
+
+        @param rdclass: The class of the rdataset
+        @type rdclass: int
+        @param rdtype: The type of the rdataset
+        @type rdtype: int
+        @param covers: The covered type.  Usually this value is
+        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
+        easier to work with than if RRSIGs covering different rdata
+        types were aggregated into a single RRSIG rdataset.
+        @type covers: int
+        @param create: If True, create the rdataset if it is not found.
+        @type create: bool
+        @raises KeyError: An rdataset of the desired type and class does
+        not exist and I{create} is not True.
+        @rtype: dns.rdataset.Rdataset object
+        """
+
+        for rds in self.rdatasets:
+            if rds.match(rdclass, rdtype, covers):
+                return rds
+        if not create:
+            raise KeyError
+        rds = dns.rdataset.Rdataset(rdclass, rdtype)
+        self.rdatasets.append(rds)
+        return rds
+
+    def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
+                     create=False):
+        """Get an rdataset matching the specified properties in the
+        current node.
+
+        None is returned if an rdataset of the specified type and
+        class does not exist and I{create} is not True.
+
+        @param rdclass: The class of the rdataset
+        @type rdclass: int
+        @param rdtype: The type of the rdataset
+        @type rdtype: int
+        @param covers: The covered type.
+        @type covers: int
+        @param create: If True, create the rdataset if it is not found.
+        @type create: bool
+        @rtype: dns.rdataset.Rdataset object or None
+        """
+
+        try:
+            rds = self.find_rdataset(rdclass, rdtype, covers, create)
+        except KeyError:
+            rds = None
+        return rds
+
+    def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE):
+        """Delete the rdataset matching the specified properties in the
+        current node.
+
+        If a matching rdataset does not exist, it is not an error.
+
+        @param rdclass: The class of the rdataset
+        @type rdclass: int
+        @param rdtype: The type of the rdataset
+        @type rdtype: int
+        @param covers: The covered type.
+        @type covers: int
+        """
+
+        rds = self.get_rdataset(rdclass, rdtype, covers)
+        if not rds is None:
+            self.rdatasets.remove(rds)
+
+    def replace_rdataset(self, replacement):
+        """Replace an rdataset.
+
+        It is not an error if there is no rdataset matching I{replacement}.
+
+        Ownership of the I{replacement} object is transferred to the node;
+        in other words, this method does not store a copy of I{replacement}
+        at the node, it stores I{replacement} itself.
+        """
+
+        self.delete_rdataset(replacement.rdclass, replacement.rdtype,
+                             replacement.covers)
+        self.rdatasets.append(replacement)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/opcode.py b/source4/scripting/python/samba_external/dnspython/dns/opcode.py
new file mode 100644 (file)
index 0000000..735d3a1
--- /dev/null
@@ -0,0 +1,104 @@
+# Copyright (C) 2001-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.
+
+"""DNS Opcodes."""
+
+import dns.exception
+
+QUERY = 0
+IQUERY = 1
+STATUS = 2
+NOTIFY = 4
+UPDATE = 5
+
+_by_text = {
+    'QUERY' : QUERY,
+    'IQUERY' : IQUERY,
+    'STATUS' : STATUS,
+    'NOTIFY' : NOTIFY,
+    'UPDATE' : UPDATE
+}
+
+# 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.
+
+_by_value = dict([(y, x) for x, y in _by_text.iteritems()])
+
+
+class UnknownOpcode(dns.exception.DNSException):
+    """Raised if an opcode is unknown."""
+    pass
+
+def from_text(text):
+    """Convert text into an opcode.
+
+    @param text: the textual opcode
+    @type text: string
+    @raises UnknownOpcode: the opcode is unknown
+    @rtype: int
+    """
+
+    if text.isdigit():
+        value = int(text)
+        if value >= 0 and value <= 15:
+            return value
+    value = _by_text.get(text.upper())
+    if value is None:
+        raise UnknownOpcode
+    return value
+
+def from_flags(flags):
+    """Extract an opcode from DNS message flags.
+
+    @param flags: int
+    @rtype: int
+    """
+
+    return (flags & 0x7800) >> 11
+
+def to_flags(value):
+    """Convert an opcode to a value suitable for ORing into DNS message
+    flags.
+    @rtype: int
+    """
+
+    return (value << 11) & 0x7800
+
+def to_text(value):
+    """Convert an opcode to text.
+
+    @param value: the opcdoe
+    @type value: int
+    @raises UnknownOpcode: the opcode is unknown
+    @rtype: string
+    """
+
+    text = _by_value.get(value)
+    if text is None:
+        text = str(value)
+    return text
+
+def is_update(flags):
+    """True if the opcode in flags is UPDATE.
+
+    @param flags: DNS flags
+    @type flags: int
+    @rtype: bool
+    """
+
+    if (from_flags(flags) == UPDATE):
+        return True
+    return False
diff --git a/source4/scripting/python/samba_external/dnspython/dns/query.py b/source4/scripting/python/samba_external/dnspython/dns/query.py
new file mode 100644 (file)
index 0000000..c023b14
--- /dev/null
@@ -0,0 +1,428 @@
+# 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.
+
+"""Talk to a DNS server."""
+
+from __future__ import generators
+
+import errno
+import select
+import socket
+import struct
+import sys
+import time
+
+import dns.exception
+import dns.inet
+import dns.name
+import dns.message
+import dns.rdataclass
+import dns.rdatatype
+
+class UnexpectedSource(dns.exception.DNSException):
+    """Raised if a query response comes from an unexpected address or port."""
+    pass
+
+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 _wait_for(ir, iw, ix, expiration):
+    done = False
+    while not done:
+        if expiration is None:
+            timeout = None
+        else:
+            timeout = expiration - time.time()
+            if timeout <= 0.0:
+                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)
+        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 dns.exception.Timeout
+
+def _wait_for_readable(s, expiration):
+    _wait_for([s], [], [s], expiration)
+
+def _wait_for_writable(s, expiration):
+    _wait_for([], [s], [s], 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 = 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,
+        ignore_unexpected=False, one_rr_per_rrset=False):
+    """Return the response obtained after sending a query via UDP.
+
+    @param q: the query
+    @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.
+    If None, the default, wait forever.
+    @type timeout: float
+    @param port: The port to which to send the message.  The default is 53.
+    @type port: int
+    @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.
+    If the inference attempt fails, AF_INET is used.
+    @type af: int
+    @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.
+    The default is 0.
+    @type source_port: int
+    @param ignore_unexpected: If True, ignore responses from unexpected
+    sources.  The default is False.
+    @type ignore_unexpected: bool
+    @param one_rr_per_rrset: Put each RR into its own RRset
+    @type one_rr_per_rrset: bool
+    """
+
+    wire = q.to_wire()
+    if af is None:
+        try:
+            af = dns.inet.af_for_address(where)
+        except:
+            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 == dns.inet.AF_INET6:
+        destination = (where, port, 0, 0)
+        if source is not None:
+            source = (source, source_port, 0, 0)
+    s = socket.socket(af, socket.SOCK_DGRAM, 0)
+    try:
+        expiration = _compute_expiration(timeout)
+        s.setblocking(0)
+        if source is not None:
+            s.bind(source)
+        _wait_for_writable(s, expiration)
+        s.sendto(wire, destination)
+        while 1:
+            _wait_for_readable(s, expiration)
+            (wire, from_address) = s.recvfrom(65535)
+            if _addresses_equal(af, from_address, destination) or \
+                    (dns.inet.is_multicast(where) and \
+                         from_address[1:] == destination[1:]):
+                break
+            if not ignore_unexpected:
+                raise UnexpectedSource('got a response from '
+                                       '%s instead of %s' % (from_address,
+                                                             destination))
+    finally:
+        s.close()
+    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 _net_read(sock, count, expiration):
+    """Read the specified number of bytes from sock.  Keep trying until we
+    either get the desired amount, or we hit EOF.
+    A Timeout exception will be raised if the operation is not completed
+    by the expiration time.
+    """
+    s = ''
+    while count > 0:
+        _wait_for_readable(sock, expiration)
+        n = sock.recv(count)
+        if n == '':
+            raise EOFError
+        count = count - len(n)
+        s = s + n
+    return s
+
+def _net_write(sock, data, expiration):
+    """Write the specified data to the socket.
+    A Timeout exception will be raised if the operation is not completed
+    by the expiration time.
+    """
+    current = 0
+    l = len(data)
+    while current < l:
+        _wait_for_writable(sock, expiration)
+        current += sock.send(data[current:])
+
+def _connect(s, address):
+    try:
+        s.connect(address)
+    except socket.error:
+        (ty, v) = sys.exc_info()[:2]
+        if v[0] != errno.EINPROGRESS and \
+               v[0] != errno.EWOULDBLOCK and \
+               v[0] != errno.EALREADY:
+            raise v
+
+def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0,
+        one_rr_per_rrset=False):
+    """Return the response obtained after sending a query via TCP.
+
+    @param q: the query
+    @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.
+    If None, the default, wait forever.
+    @type timeout: float
+    @param port: The port to which to send the message.  The default is 53.
+    @type port: int
+    @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.
+    If the inference attempt fails, AF_INET is used.
+    @type af: int
+    @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.
+    The default is 0.
+    @type source_port: int
+    @param one_rr_per_rrset: Put each RR into its own RRset
+    @type one_rr_per_rrset: bool
+    """
+
+    wire = q.to_wire()
+    if af is None:
+        try:
+            af = dns.inet.af_for_address(where)
+        except:
+            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 == dns.inet.AF_INET6:
+        destination = (where, port, 0, 0)
+        if source is not None:
+            source = (source, source_port, 0, 0)
+    s = socket.socket(af, socket.SOCK_STREAM, 0)
+    try:
+        expiration = _compute_expiration(timeout)
+        s.setblocking(0)
+        if source is not None:
+            s.bind(source)
+        _connect(s, destination)
+
+        l = len(wire)
+
+        # copying the wire into tcpmsg is inefficient, but lets us
+        # avoid writev() or doing a short write that would get pushed
+        # onto the net
+        tcpmsg = struct.pack("!H", l) + wire
+        _net_write(s, tcpmsg, expiration)
+        ldata = _net_read(s, 2, expiration)
+        (l,) = struct.unpack("!H", ldata)
+        wire = _net_read(s, l, expiration)
+    finally:
+        s.close()
+    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=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: dns.name.Name object or string
+    @param rdtype: The type of zone transfer.  The default is
+    dns.rdatatype.AXFR.
+    @type rdtype: int or string
+    @param rdclass: The class of the zone transfer.  The default is
+    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.
+    @type timeout: float
+    @param port: The port to which to send the message.  The default is 53.
+    @type port: int
+    @param keyring: The TSIG keyring to use
+    @type keyring: dict
+    @param keyname: The name of the TSIG key to use
+    @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 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.
+    If the inference attempt fails, AF_INET is used.
+    @type af: int
+    @param lifetime: The total number of seconds to spend doing the transfer.
+    If None, the default, then there is no limit on the time the transfer may
+    take.
+    @type lifetime: float
+    @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 == 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
+    dns.tsig.default_algorithm
+    @type keyalgorithm: string
+    """
+
+    if isinstance(zone, (str, unicode)):
+        zone = dns.name.from_text(zone)
+    if isinstance(rdtype, str):
+        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 = dns.inet.af_for_address(where)
+        except:
+            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 == 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 != dns.rdatatype.IXFR:
+            raise ValueError('cannot do a UDP AXFR')
+        s = socket.socket(af, socket.SOCK_DGRAM, 0)
+    else:
+        s = socket.socket(af, socket.SOCK_STREAM, 0)
+    s.setblocking(0)
+    if source is not None:
+        s.bind(source)
+    expiration = _compute_expiration(lifetime)
+    _connect(s, destination)
+    l = len(wire)
+    if use_udp:
+        _wait_for_writable(s, expiration)
+        s.send(wire)
+    else:
+        tcpmsg = struct.pack("!H", l) + wire
+        _net_write(s, tcpmsg, expiration)
+    done = False
+    soa_rrset = None
+    soa_count = 0
+    if relativize:
+        origin = zone
+        oname = dns.name.empty
+    else:
+        origin = None
+        oname = zone
+    tsig_ctx = None
+    first = True
+    while not done:
+        mexpiration = _compute_expiration(timeout)
+        if mexpiration is None or mexpiration > expiration:
+            mexpiration = expiration
+        if use_udp:
+            _wait_for_readable(s, expiration)
+            (wire, from_address) = s.recvfrom(65535)
+        else:
+            ldata = _net_read(s, 2, mexpiration)
+            (l,) = struct.unpack("!H", ldata)
+            wire = _net_read(s, l, mexpiration)
+        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==dns.rdatatype.IXFR))
+        tsig_ctx = r.tsig_ctx
+        first = False
+        answer_index = 0
+        delete_mode = False
+        expecting_SOA = False
+        if soa_rrset is None:
+            if not r.answer or r.answer[0].name != oname:
+                raise dns.exception.FormError
+            rrset = r.answer[0]
+            if rrset.rdtype != dns.rdatatype.SOA:
+                raise dns.exception.FormError("first RRset is not an SOA")
+            answer_index = 1
+            soa_rrset = rrset.copy()
+            if rdtype == dns.rdatatype.IXFR:
+                if soa_rrset[0].serial == serial:
+                    #
+                    # 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 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 dns.exception.FormError("IXFR base serial mismatch")
+                    expecting_SOA = False
+                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 = dns.rdatatype.AXFR
+                expecting_SOA = False
+        if done and q.keyring and not r.had_tsig:
+            raise dns.exception.FormError("missing TSIG")
+        yield r
+    s.close()
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rcode.py b/source4/scripting/python/samba_external/dnspython/dns/rcode.py
new file mode 100644 (file)
index 0000000..c055f2e
--- /dev/null
@@ -0,0 +1,119 @@
+# Copyright (C) 2001-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.
+
+"""DNS Result Codes."""
+
+import dns.exception
+
+NOERROR = 0
+FORMERR = 1
+SERVFAIL = 2
+NXDOMAIN = 3
+NOTIMP = 4
+REFUSED = 5
+YXDOMAIN = 6
+YXRRSET = 7
+NXRRSET = 8
+NOTAUTH = 9
+NOTZONE = 10
+BADVERS = 16
+
+_by_text = {
+    'NOERROR' : NOERROR,
+    'FORMERR' : FORMERR,
+    'SERVFAIL' : SERVFAIL,
+    'NXDOMAIN' : NXDOMAIN,
+    'NOTIMP' : NOTIMP,
+    'REFUSED' : REFUSED,
+    'YXDOMAIN' : YXDOMAIN,
+    'YXRRSET' : YXRRSET,
+    'NXRRSET' : NXRRSET,
+    'NOTAUTH' : NOTAUTH,
+    'NOTZONE' : NOTZONE,
+    'BADVERS' : BADVERS
+}
+
+# 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 a true inverse.
+
+_by_value = dict([(y, x) for x, y in _by_text.iteritems()])
+
+
+class UnknownRcode(dns.exception.DNSException):
+    """Raised if an rcode is unknown."""
+    pass
+
+def from_text(text):
+    """Convert text into an rcode.
+
+    @param text: the texual rcode
+    @type text: string
+    @raises UnknownRcode: the rcode is unknown
+    @rtype: int
+    """
+
+    if text.isdigit():
+        v = int(text)
+        if v >= 0 and v <= 4095:
+            return v
+    v = _by_text.get(text.upper())
+    if v is None:
+        raise UnknownRcode
+    return v
+
+def from_flags(flags, ednsflags):
+    """Return the rcode value encoded by flags and ednsflags.
+
+    @param flags: the DNS flags
+    @type flags: int
+    @param ednsflags: the EDNS flags
+    @type ednsflags: int
+    @raises ValueError: rcode is < 0 or > 4095
+    @rtype: int
+    """
+
+    value = (flags & 0x000f) | ((ednsflags >> 20) & 0xff0)
+    if value < 0 or value > 4095:
+        raise ValueError('rcode must be >= 0 and <= 4095')
+    return value
+
+def to_flags(value):
+    """Return a (flags, ednsflags) tuple which encodes the rcode.
+
+    @param value: the rcode
+    @type value: int
+    @raises ValueError: rcode is < 0 or > 4095
+    @rtype: (int, int) tuple
+    """
+
+    if value < 0 or value > 4095:
+        raise ValueError('rcode must be >= 0 and <= 4095')
+    v = value & 0xf
+    ev = long(value & 0xff0) << 20
+    return (v, ev)
+
+def to_text(value):
+    """Convert rcode into text.
+
+    @param value: the rcode
+    @type value: int
+    @rtype: string
+    """
+
+    text = _by_value.get(value)
+    if text is None:
+        text = str(value)
+    return text
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdata.py b/source4/scripting/python/samba_external/dnspython/dns/rdata.py
new file mode 100644 (file)
index 0000000..ce02686
--- /dev/null
@@ -0,0 +1,456 @@
+# Copyright (C) 2001-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.
+
+"""DNS rdata.
+
+@var _rdata_modules: A dictionary mapping a (rdclass, rdtype) tuple to
+the module which implements that type.
+@type _rdata_modules: dict
+@var _module_prefix: The prefix to use when forming modules names.  The
+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"""
+
+import cStringIO
+
+import dns.exception
+import dns.rdataclass
+import dns.rdatatype
+import dns.tokenizer
+
+_hex_chunksize = 32
+
+def _hexify(data, chunksize=None):
+    """Convert a binary string into its hex encoding, broken up into chunks
+    of I{chunksize} characters separated by a space.
+
+    @param data: the binary string
+    @type data: string
+    @param chunksize: the chunk size.  Default is L{dns.rdata._hex_chunksize}
+    @rtype: string
+    """
+
+    if chunksize is None:
+        chunksize = _hex_chunksize
+    hex = data.encode('hex_codec')
+    l = len(hex)
+    if l > chunksize:
+        chunks = []
+        i = 0
+        while i < l:
+            chunks.append(hex[i : i + chunksize])
+            i += chunksize
+        hex = ' '.join(chunks)
+    return hex
+
+_base64_chunksize = 32
+
+def _base64ify(data, chunksize=None):
+    """Convert a binary string into its base64 encoding, broken up into chunks
+    of I{chunksize} characters separated by a space.
+
+    @param data: the binary string
+    @type data: string
+    @param chunksize: the chunk size.  Default is
+    L{dns.rdata._base64_chunksize}
+    @rtype: string
+    """
+
+    if chunksize is None:
+        chunksize = _base64_chunksize
+    b64 = data.encode('base64_codec')
+    b64 = b64.replace('\n', '')
+    l = len(b64)
+    if l > chunksize:
+        chunks = []
+        i = 0
+        while i < l:
+            chunks.append(b64[i : i + chunksize])
+            i += chunksize
+        b64 = ' '.join(chunks)
+    return b64
+
+__escaped = {
+    '"' : True,
+    '\\' : True,
+    }
+
+def _escapify(qstring):
+    """Escape the characters in a quoted string which need it.
+
+    @param qstring: the string
+    @type qstring: string
+    @returns: the escaped string
+    @rtype: string
+    """
+
+    text = ''
+    for c in qstring:
+        if c in __escaped:
+            text += '\\' + c
+        elif ord(c) >= 0x20 and ord(c) < 0x7F:
+            text += c
+        else:
+            text += '\\%03d' % ord(c)
+    return text
+
+def _truncate_bitmap(what):
+    """Determine the index of greatest byte that isn't all zeros, and
+    return the bitmap that contains all the bytes less than that index.
+
+    @param what: a string of octets representing a bitmap.
+    @type what: string
+    @rtype: string
+    """
+
+    for i in xrange(len(what) - 1, -1, -1):
+        if what[i] != '\x00':
+            break
+    return ''.join(what[0 : i + 1])
+
+class Rdata(object):
+    """Base class for all DNS rdata types.
+    """
+
+    __slots__ = ['rdclass', 'rdtype']
+
+    def __init__(self, rdclass, rdtype):
+        """Initialize an rdata.
+        @param rdclass: The rdata class
+        @type rdclass: int
+        @param rdtype: The rdata type
+        @type rdtype: int
+        """
+
+        self.rdclass = rdclass
+        self.rdtype = rdtype
+
+    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, 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 dns.rdatatype.NONE
+
+    def extended_rdatatype(self):
+        """Return a 32-bit type value, the least significant 16 bits of
+        which are the ordinary DNS type, and the upper 16 bits of which are
+        the "covered" type, if any.
+        @rtype: int
+        """
+
+        return self.covers() << 16 | self.rdtype
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        """Convert an rdata to text format.
+        @rtype: string
+        """
+        raise NotImplementedError
+
+    def to_wire(self, file, compress = None, origin = None):
+        """Convert an rdata to wire format.
+        @rtype: string
+        """
+
+        raise NotImplementedError
+
+    def to_digestable(self, origin = None):
+        """Convert rdata to a format suitable for digesting in hashes.  This
+        is also the DNSSEC canonical form."""
+        f = cStringIO.StringIO()
+        self.to_wire(f, None, origin)
+        return f.getvalue()
+
+    def validate(self):
+        """Check that the current contents of the rdata's fields are
+        valid.  If you change an rdata by assigning to its fields,
+        it is a good idea to call validate() when you are done making
+        changes.
+        """
+        dns.rdata.from_text(self.rdclass, self.rdtype, self.to_text())
+
+    def __repr__(self):
+        covers = self.covers()
+        if covers == dns.rdatatype.NONE:
+            ctext = ''
+        else:
+            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):
+        return self.to_text()
+
+    def _cmp(self, other):
+        """Compare an rdata with another rdata of the same rdtype and
+        rdclass.  Return < 0 if self < other in the DNSSEC ordering,
+        0 if self == other, and > 0 if self > other.
+        """
+
+        raise NotImplementedError
+
+    def __eq__(self, other):
+        if not isinstance(other, Rdata):
+            return False
+        if self.rdclass != other.rdclass or \
+           self.rdtype != other.rdtype:
+            return False
+        return self._cmp(other) == 0
+
+    def __ne__(self, other):
+        if not isinstance(other, Rdata):
+            return True
+        if self.rdclass != other.rdclass or \
+           self.rdtype != other.rdtype:
+            return True
+        return self._cmp(other) != 0
+
+    def __lt__(self, other):
+        if not isinstance(other, Rdata) or \
+               self.rdclass != other.rdclass or \
+               self.rdtype != other.rdtype:
+            return NotImplemented
+        return self._cmp(other) < 0
+
+    def __le__(self, other):
+        if not isinstance(other, Rdata) or \
+               self.rdclass != other.rdclass or \
+               self.rdtype != other.rdtype:
+            return NotImplemented
+        return self._cmp(other) <= 0
+
+    def __ge__(self, other):
+        if not isinstance(other, Rdata) or \
+               self.rdclass != other.rdclass or \
+               self.rdtype != other.rdtype:
+            return NotImplemented
+        return self._cmp(other) >= 0
+
+    def __gt__(self, other):
+        if not isinstance(other, Rdata) or \
+               self.rdclass != other.rdclass or \
+               self.rdtype != other.rdtype:
+            return NotImplemented
+        return self._cmp(other) > 0
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        """Build an rdata object from text format.
+
+        @param rdclass: The rdata class
+        @type rdclass: int
+        @param rdtype: The rdata type
+        @type rdtype: int
+        @param tok: The tokenizer
+        @type tok: dns.tokenizer.Tokenizer
+        @param origin: The origin to use for relative names
+        @type origin: dns.name.Name
+        @param relativize: should names be relativized?
+        @type relativize: bool
+        @rtype: dns.rdata.Rdata instance
+        """
+
+        raise NotImplementedError
+
+    from_text = classmethod(from_text)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        """Build an rdata object from wire format
+
+        @param rdclass: The rdata class
+        @type rdclass: int
+        @param rdtype: The rdata type
+        @type rdtype: int
+        @param wire: The wire-format message
+        @type wire: string
+        @param current: The offet in wire of the beginning of the rdata.
+        @type current: int
+        @param rdlen: The length of the wire-format rdata
+        @type rdlen: int
+        @param origin: The origin to use for relative names
+        @type origin: dns.name.Name
+        @rtype: dns.rdata.Rdata instance
+        """
+
+        raise NotImplementedError
+
+    from_wire = classmethod(from_wire)
+
+    def choose_relativity(self, origin = None, relativize = True):
+        """Convert any domain names in the rdata to the specified
+        relativization.
+        """
+
+        pass
+
+
+class GenericRdata(Rdata):
+    """Generate Rdata Class
+
+    This class is used for rdata types for which we have no better
+    implementation.  It implements the DNS "unknown RRs" scheme.
+    """
+
+    __slots__ = ['data']
+
+    def __init__(self, rdclass, rdtype, data):
+        super(GenericRdata, self).__init__(rdclass, rdtype)
+        self.data = data
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        return r'\# %d ' % len(self.data) + _hexify(self.data)
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        token = tok.get()
+        if not token.is_identifier() or token.value != '\#':
+            raise dns.exception.SyntaxError(r'generic rdata does not start with \#')
+        length = tok.get_int()
+        chunks = []
+        while 1:
+            token = tok.get()
+            if token.is_eol_or_eof():
+                break
+            chunks.append(token.value)
+        hex = ''.join(chunks)
+        data = hex.decode('hex_codec')
+        if len(data) != length:
+            raise dns.exception.SyntaxError('generic rdata hex data has wrong length')
+        return cls(rdclass, rdtype, data)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        file.write(self.data)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        return cls(rdclass, rdtype, wire[current : current + rdlen])
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        return cmp(self.data, other.data)
+
+_rdata_modules = {}
+_module_prefix = 'dns.rdtypes'
+
+def get_rdata_class(rdclass, rdtype):
+
+    def import_module(name):
+        mod = __import__(name)
+        components = name.split('.')
+        for comp in components[1:]:
+            mod = getattr(mod, comp)
+        return mod
+
+    mod = _rdata_modules.get((rdclass, 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((dns.rdatatype.ANY, rdtype))
+        if not mod:
+            try:
+                mod = import_module('.'.join([_module_prefix,
+                                              rdclass_text, rdtype_text]))
+                _rdata_modules[(rdclass, rdtype)] = mod
+            except ImportError:
+                try:
+                    mod = import_module('.'.join([_module_prefix,
+                                                  'ANY', rdtype_text]))
+                    _rdata_modules[(dns.rdataclass.ANY, rdtype)] = mod
+                except ImportError:
+                    mod = None
+    if mod:
+        cls = getattr(mod, rdtype_text)
+    else:
+        cls = GenericRdata
+    return cls
+
+def from_text(rdclass, rdtype, tok, origin = None, relativize = True):
+    """Build an rdata object from text format.
+
+    This function attempts to dynamically load a class which
+    implements the specified rdata class and type.  If there is no
+    class-and-type-specific implementation, the GenericRdata class
+    is used.
+
+    Once a class is chosen, its from_text() class method is called
+    with the parameters to this function.
+
+    @param rdclass: The rdata class
+    @type rdclass: int
+    @param rdtype: The rdata type
+    @type rdtype: int
+    @param tok: The tokenizer
+    @type tok: dns.tokenizer.Tokenizer
+    @param origin: The origin to use for relative names
+    @type origin: dns.name.Name
+    @param relativize: Should names be relativized?
+    @type relativize: bool
+    @rtype: dns.rdata.Rdata instance"""
+
+    if isinstance(tok, str):
+        tok = dns.tokenizer.Tokenizer(tok)
+    cls = get_rdata_class(rdclass, rdtype)
+    if cls != GenericRdata:
+        # peek at first token
+        token = tok.get()
+        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),
+                             origin)
+    return cls.from_text(rdclass, rdtype, tok, origin, relativize)
+
+def from_wire(rdclass, rdtype, wire, current, rdlen, origin = None):
+    """Build an rdata object from wire format
+
+    This function attempts to dynamically load a class which
+    implements the specified rdata class and type.  If there is no
+    class-and-type-specific implementation, the GenericRdata class
+    is used.
+
+    Once a class is chosen, its from_wire() class method is called
+    with the parameters to this function.
+
+    @param rdclass: The rdata class
+    @type rdclass: int
+    @param rdtype: The rdata type
+    @type rdtype: int
+    @param wire: The wire-format message
+    @type wire: string
+    @param current: The offet in wire of the beginning of the rdata.
+    @type current: int
+    @param rdlen: The length of the wire-format rdata
+    @type rdlen: int
+    @param origin: The origin to use for relative names
+    @type origin: dns.name.Name
+    @rtype: dns.rdata.Rdata instance"""
+
+    cls = get_rdata_class(rdclass, rdtype)
+    return cls.from_wire(rdclass, rdtype, wire, current, rdlen, origin)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdataclass.py b/source4/scripting/python/samba_external/dnspython/dns/rdataclass.py
new file mode 100644 (file)
index 0000000..887fd1a
--- /dev/null
@@ -0,0 +1,114 @@
+# Copyright (C) 2001-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.
+
+"""DNS Rdata Classes.
+
+@var _by_text: The rdata class textual name to value mapping
+@type _by_text: dict
+@var _by_value: The rdata class value to textual name mapping
+@type _by_value: dict
+@var _metaclasses: If an rdataclass is a metaclass, there will be a mapping
+whose key is the rdatatype value and whose value is True in this dictionary.
+@type _metaclasses: dict"""
+
+import re
+
+import dns.exception
+
+RESERVED0 = 0
+IN = 1
+CH = 3
+HS = 4
+NONE = 254
+ANY = 255
+
+_by_text = {
+    'RESERVED0' : RESERVED0,
+    'IN' : IN,
+    'CH' : CH,
+    'HS' : HS,
+    'NONE' : NONE,
+    'ANY' : ANY
+    }
+
+# 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.
+
+_by_value = dict([(y, x) for x, y in _by_text.iteritems()])
+
+# Now that we've built the inverse map, we can add class aliases to
+# the _by_text mapping.
+
+_by_text.update({
+    'INTERNET' : IN,
+    'CHAOS' : CH,
+    'HESIOD' : HS
+    })
+
+_metaclasses = {
+    NONE : True,
+    ANY : True
+    }
+
+_unknown_class_pattern = re.compile('CLASS([0-9]+)$', re.I);
+
+class UnknownRdataclass(dns.exception.DNSException):
+    """Raised when a class is unknown."""
+    pass
+
+def from_text(text):
+    """Convert text into a DNS rdata class value.
+    @param text: the text
+    @type text: string
+    @rtype: int
+    @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 == None:
+            raise UnknownRdataclass
+        value = int(match.group(1))
+        if value < 0 or value > 65535:
+            raise ValueError("class must be between >= 0 and <= 65535")
+    return value
+
+def to_text(value):
+    """Convert a DNS rdata class to text.
+    @param value: the rdata class value
+    @type value: int
+    @rtype: string
+    @raises ValueError: the rdata class value is not >= 0 and <= 65535
+    """
+
+    if value < 0 or value > 65535:
+        raise ValueError("class must be between >= 0 and <= 65535")
+    text = _by_value.get(value)
+    if text is None:
+        text = 'CLASS' + `value`
+    return text
+
+def is_metaclass(rdclass):
+    """True if the class is a metaclass.
+    @param rdclass: the rdata class
+    @type rdclass: int
+    @rtype: bool"""
+
+    if _metaclasses.has_key(rdclass):
+        return True
+    return False
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdataset.py b/source4/scripting/python/samba_external/dnspython/dns/rdataset.py
new file mode 100644 (file)
index 0000000..0af018b
--- /dev/null
@@ -0,0 +1,329 @@
+# Copyright (C) 2001-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.
+
+"""DNS rdatasets (an rdataset is a set of rdatas of a given type and class)"""
+
+import random
+import StringIO
+import struct
+
+import dns.exception
+import dns.rdatatype
+import dns.rdataclass
+import dns.rdata
+import dns.set
+
+# 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(dns.exception.DNSException):
+    """Raised if an attempt is made to add rdata of an incompatible type."""
+    pass
+
+class Rdataset(dns.set.Set):
+    """A DNS rdataset.
+
+    @ivar rdclass: The class of the rdataset
+    @type rdclass: int
+    @ivar rdtype: The type of the rdataset
+    @type rdtype: int
+    @ivar covers: The covered type.  Usually this value is
+    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
+    easier to work with than if RRSIGs covering different rdata
+    types were aggregated into a single RRSIG rdataset.
+    @type covers: int
+    @ivar ttl: The DNS TTL (Time To Live) value
+    @type ttl: int
+    """
+
+    __slots__ = ['rdclass', 'rdtype', 'covers', 'ttl']
+
+    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
+        meaning of I{rdclass} and I{rdtype}"""
+
+        super(Rdataset, self).__init__()
+        self.rdclass = rdclass
+        self.rdtype = rdtype
+        self.covers = covers
+        self.ttl = 0
+
+    def _clone(self):
+        obj = super(Rdataset, self)._clone()
+        obj.rdclass = self.rdclass
+        obj.rdtype = self.rdtype
+        obj.covers = self.covers
+        obj.ttl = self.ttl
+        return obj
+
+    def update_ttl(self, ttl):
+        """Set the TTL of the rdataset to be the lesser of the set's current
+        TTL or the specified TTL.  If the set contains no rdatas, set the TTL
+        to the specified TTL.
+        @param ttl: The TTL
+        @type ttl: int"""
+
+        if len(self) == 0:
+            self.ttl = ttl
+        elif ttl < self.ttl:
+            self.ttl = ttl
+
+    def add(self, rd, ttl=None):
+        """Add the specified rdata to the rdataset.
+
+        If the optional I{ttl} parameter is supplied, then
+        self.update_ttl(ttl) will be called prior to adding the rdata.
+
+        @param rd: The rdata
+        @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 == dns.rdatatype.RRSIG or \
+           self.rdtype == dns.rdatatype.SIG:
+            covers = rd.covers()
+            if len(self) == 0 and self.covers == dns.rdatatype.NONE:
+                self.covers = covers
+            elif self.covers != covers:
+                raise DifferingCovers
+        if dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0:
+            self.clear()
+        super(Rdataset, self).add(rd)
+
+    def union_update(self, other):
+        self.update_ttl(other.ttl)
+        super(Rdataset, self).union_update(other)
+
+    def intersection_update(self, other):
+        self.update_ttl(other.ttl)
+        super(Rdataset, self).intersection_update(other)
+
+    def update(self, other):
+        """Add all rdatas in other to self.
+
+        @param other: The rdataset from which to update
+        @type other: dns.rdataset.Rdataset object"""
+
+        self.update_ttl(other.ttl)
+        super(Rdataset, self).update(other)
+
+    def __repr__(self):
+        if self.covers == 0:
+            ctext = ''
+        else:
+            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()
+
+    def __eq__(self, other):
+        """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 \
+           self.rdtype != other.rdtype or \
+           self.covers != other.covers:
+            return False
+        return super(Rdataset, self).__eq__(other)
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def to_text(self, name=None, origin=None, relativize=True,
+                override_rdclass=None, **kw):
+        """Convert the rdataset into DNS master file format.
+
+        @see: L{dns.name.Name.choose_relativity} for more information
+        on how I{origin} and I{relativize} determine the way names
+        are emitted.
+
+        Any additional keyword arguments are passed on to the rdata
+        to_text() method.
+
+        @param name: If name is not None, emit a RRs with I{name} as
+        the owner name.
+        @type name: dns.name.Name object
+        @param origin: The origin for relative names, or None.
+        @type origin: dns.name.Name object
+        @param relativize: True if names should names be relativized
+        @type relativize: bool"""
+        if not name is None:
+            name = name.choose_relativity(origin, relativize)
+            ntext = str(name)
+            pad = ' '
+        else:
+            ntext = ''
+            pad = ''
+        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,
+                                       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, 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,
+                override_rdclass=None, want_shuffle=True):
+        """Convert the rdataset to wire format.
+
+        @param name: The owner name of the RRset that will be emitted
+        @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.
+        @type compress: dict
+        @param origin: The origin to be appended to any relative names when
+        they are emitted.  The default is None.
+        @returns: the number of records emitted
+        @rtype: int
+        """
+
+        if not override_rdclass is None:
+            rdclass =  override_rdclass
+            want_shuffle = False
+        else:
+            rdclass = self.rdclass
+        file.seek(0, 2)
+        if len(self) == 0:
+            name.to_wire(file, compress, origin)
+            stuff = struct.pack("!HHIH", self.rdtype, rdclass, 0, 0)
+            file.write(stuff)
+            return 1
+        else:
+            if want_shuffle:
+                l = list(self)
+                random.shuffle(l)
+            else:
+                l = self
+            for rd in l:
+                name.to_wire(file, compress, origin)
+                stuff = struct.pack("!HHIH", self.rdtype, rdclass,
+                                    self.ttl, 0)
+                file.write(stuff)
+                start = file.tell()
+                rd.to_wire(file, compress, origin)
+                end = file.tell()
+                assert end - start < 65536
+                file.seek(start - 2)
+                stuff = struct.pack("!H", end - start)
+                file.write(stuff)
+                file.seek(0, 2)
+            return len(self)
+
+    def match(self, rdclass, rdtype, covers):
+        """Returns True if this rdataset matches the specified class, type,
+        and covers"""
+        if self.rdclass == rdclass and \
+           self.rdtype == rdtype and \
+           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: dns.rdataset.Rdataset object
+    """
+
+    if isinstance(rdclass, str):
+        rdclass = dns.rdataclass.from_text(rdclass)
+    if isinstance(rdtype, str):
+        rdtype = dns.rdatatype.from_text(rdtype)
+    r = Rdataset(rdclass, rdtype)
+    r.update_ttl(ttl)
+    for t in text_rdatas:
+        rd = dns.rdata.from_text(r.rdclass, r.rdtype, t)
+        r.add(rd)
+    return r
+
+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: dns.rdataset.Rdataset object
+    """
+
+    return from_text_list(rdclass, rdtype, ttl, text_rdatas)
+
+def from_rdata_list(ttl, rdatas):
+    """Create an rdataset with the specified TTL, and with
+    the specified list of rdata objects.
+
+    @rtype: dns.rdataset.Rdataset object
+    """
+
+    if len(rdatas) == 0:
+        raise ValueError("rdata list must not be empty")
+    r = None
+    for rd in rdatas:
+        if r is None:
+            r = Rdataset(rd.rdclass, rd.rdtype)
+            r.update_ttl(ttl)
+            first_time = False
+        r.add(rd)
+    return r
+
+def from_rdata(ttl, *rdatas):
+    """Create an rdataset with the specified TTL, and with
+    the specified rdata objects.
+
+    @rtype: dns.rdataset.Rdataset object
+    """
+
+    return from_rdata_list(ttl, rdatas)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdatatype.py b/source4/scripting/python/samba_external/dnspython/dns/rdatatype.py
new file mode 100644 (file)
index 0000000..1a02b7d
--- /dev/null
@@ -0,0 +1,232 @@
+# Copyright (C) 2001-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.
+
+"""DNS Rdata Types.
+
+@var _by_text: The rdata type textual name to value mapping
+@type _by_text: dict
+@var _by_value: The rdata type value to textual name mapping
+@type _by_value: dict
+@var _metatypes: If an rdatatype is a metatype, there will be a mapping
+whose key is the rdatatype value and whose value is True in this dictionary.
+@type _metatypes: dict
+@var _singletons: If an rdatatype is a singleton, there will be a mapping
+whose key is the rdatatype value and whose value is True in this dictionary.
+@type _singletons: dict"""
+
+import re
+
+import dns.exception
+
+NONE = 0
+A = 1
+NS = 2
+MD = 3
+MF = 4
+CNAME = 5
+SOA = 6
+MB = 7
+MG = 8
+MR = 9
+NULL = 10
+WKS = 11
+PTR = 12
+HINFO = 13
+MINFO = 14
+MX = 15
+TXT = 16
+RP = 17
+AFSDB = 18
+X25 = 19
+ISDN = 20
+RT = 21
+NSAP = 22
+NSAP_PTR = 23
+SIG = 24
+KEY = 25
+PX = 26
+GPOS = 27
+AAAA = 28
+LOC = 29
+NXT = 30
+SRV = 33
+NAPTR = 35
+KX = 36
+CERT = 37
+A6 = 38
+DNAME = 39
+OPT = 41
+APL = 42
+DS = 43
+SSHFP = 44
+IPSECKEY = 45
+RRSIG = 46
+NSEC = 47
+DNSKEY = 48
+DHCID = 49
+NSEC3 = 50
+NSEC3PARAM = 51
+HIP = 55
+SPF = 99
+UNSPEC = 103
+TKEY = 249
+TSIG = 250
+IXFR = 251
+AXFR = 252
+MAILB = 253
+MAILA = 254
+ANY = 255
+TA = 32768
+DLV = 32769
+
+_by_text = {
+    'NONE' : NONE,
+    'A' : A,
+    'NS' : NS,
+    'MD' : MD,
+    'MF' : MF,
+    'CNAME' : CNAME,
+    'SOA' : SOA,
+    'MB' : MB,
+    'MG' : MG,
+    'MR' : MR,
+    'NULL' : NULL,
+    'WKS' : WKS,
+    'PTR' : PTR,
+    'HINFO' : HINFO,
+    'MINFO' : MINFO,
+    'MX' : MX,
+    'TXT' : TXT,
+    'RP' : RP,
+    'AFSDB' : AFSDB,
+    'X25' : X25,
+    'ISDN' : ISDN,
+    'RT' : RT,
+    'NSAP' : NSAP,
+    'NSAP-PTR' : NSAP_PTR,
+    'SIG' : SIG,
+    'KEY' : KEY,
+    'PX' : PX,
+    'GPOS' : GPOS,
+    'AAAA' : AAAA,
+    'LOC' : LOC,
+    'NXT' : NXT,
+    'SRV' : SRV,
+    'NAPTR' : NAPTR,
+    'KX' : KX,
+    'CERT' : CERT,
+    'A6' : A6,
+    'DNAME' : DNAME,
+    'OPT' : OPT,
+    'APL' : APL,
+    'DS' : DS,
+    'SSHFP' : SSHFP,
+    'IPSECKEY' : IPSECKEY,
+    'RRSIG' : RRSIG,
+    'NSEC' : NSEC,
+    'DNSKEY' : DNSKEY,
+    'DHCID' : DHCID,
+    'NSEC3' : NSEC3,
+    'NSEC3PARAM' : NSEC3PARAM,
+    'HIP' : HIP,
+    'SPF' : SPF,
+    'UNSPEC' : UNSPEC,
+    'TKEY' : TKEY,
+    'TSIG' : TSIG,
+    'IXFR' : IXFR,
+    'AXFR' : AXFR,
+    'MAILB' : MAILB,
+    'MAILA' : MAILA,
+    'ANY' : ANY,
+    'TA' : TA,
+    'DLV' : DLV,
+    }
+
+# 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.
+
+_by_value = dict([(y, x) for x, y in _by_text.iteritems()])
+
+
+_metatypes = {
+    OPT : True
+    }
+
+_singletons = {
+    SOA : True,
+    NXT : True,
+    DNAME : True,
+    NSEC : True,
+    # CNAME is technically a singleton, but we allow multiple CNAMEs.
+    }
+
+_unknown_type_pattern = re.compile('TYPE([0-9]+)$', re.I);
+
+class UnknownRdatatype(dns.exception.DNSException):
+    """Raised if a type is unknown."""
+    pass
+
+def from_text(text):
+    """Convert text into a DNS rdata type value.
+    @param text: the text
+    @type text: string
+    @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 == None:
+            raise UnknownRdatatype
+        value = int(match.group(1))
+        if value < 0 or value > 65535:
+            raise ValueError("type must be between >= 0 and <= 65535")
+    return value
+
+def to_text(value):
+    """Convert a DNS rdata type to text.
+    @param value: the rdata type value
+    @type value: int
+    @raises ValueError: the rdata type value is not >= 0 and <= 65535
+    @rtype: string"""
+
+    if value < 0 or value > 65535:
+        raise ValueError("type must be between >= 0 and <= 65535")
+    text = _by_value.get(value)
+    if text is None:
+        text = 'TYPE' + `value`
+    return text
+
+def is_metatype(rdtype):
+    """True if the type is a metatype.
+    @param rdtype: the type
+    @type rdtype: int
+    @rtype: bool"""
+
+    if rdtype >= TKEY and rdtype <= ANY or _metatypes.has_key(rdtype):
+        return True
+    return False
+
+def is_singleton(rdtype):
+    """True if the type is a singleton.
+    @param rdtype: the type
+    @type rdtype: int
+    @rtype: bool"""
+
+    if _singletons.has_key(rdtype):
+        return True
+    return False
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/AFSDB.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/AFSDB.py
new file mode 100644 (file)
index 0000000..e8ca6f5
--- /dev/null
@@ -0,0 +1,51 @@
+# 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 dns.rdtypes.mxbase
+
+class AFSDB(dns.rdtypes.mxbase.UncompressedDowncasingMX):
+    """AFSDB record
+
+    @ivar subtype: the subtype value
+    @type subtype: int
+    @ivar hostname: the hostname name
+    @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"
+    # attribute.
+    #
+    # This lets us inherit the UncompressedMX implementation but lets
+    # the caller use appropriate attribute names for the rdata type.
+    #
+    # We probably lose some performance vs. a cut-and-paste
+    # implementation, but this way we don't copy code, and that's
+    # good.
+
+    def get_subtype(self):
+        return self.preference
+
+    def set_subtype(self, subtype):
+        self.preference = subtype
+
+    subtype = property(get_subtype, set_subtype)
+
+    def get_hostname(self):
+        return self.exchange
+
+    def set_hostname(self, hostname):
+        self.exchange = hostname
+
+    hostname = property(get_hostname, set_hostname)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/CERT.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/CERT.py
new file mode 100644 (file)
index 0000000..d270351
--- /dev/null
@@ -0,0 +1,131 @@
+# 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 cStringIO
+import struct
+
+import dns.exception
+import dns.dnssec
+import dns.rdata
+import dns.tokenizer
+
+_ctype_by_value = {
+    1 : 'PKIX',
+    2 : 'SPKI',
+    3 : 'PGP',
+    253 : 'URI',
+    254 : 'OID',
+    }
+
+_ctype_by_name = {
+    'PKIX' : 1,
+    'SPKI' : 2,
+    'PGP' : 3,
+    'URI' : 253,
+    'OID' : 254,
+    }
+
+def _ctype_from_text(what):
+    v = _ctype_by_name.get(what)
+    if not v is None:
+        return v
+    return int(what)
+
+def _ctype_to_text(what):
+    v = _ctype_by_value.get(what)
+    if not v is None:
+        return v
+    return str(what)
+
+class CERT(dns.rdata.Rdata):
+    """CERT record
+
+    @ivar certificate_type: certificate type
+    @type certificate_type: int
+    @ivar key_tag: key tag
+    @type key_tag: int
+    @ivar algorithm: algorithm
+    @type algorithm: int
+    @ivar certificate: the certificate or CRL
+    @type certificate: string
+    @see: RFC 2538"""
+
+    __slots__ = ['certificate_type', 'key_tag', 'algorithm', 'certificate']
+
+    def __init__(self, rdclass, rdtype, certificate_type, key_tag, algorithm,
+                 certificate):
+        super(CERT, self).__init__(rdclass, rdtype)
+        self.certificate_type = certificate_type
+        self.key_tag = key_tag
+        self.algorithm = algorithm
+        self.certificate = certificate
+
+    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,
+                                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 = dns.dnssec.algorithm_from_text(tok.get_string())
+        if algorithm < 0 or algorithm > 255:
+            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 dns.exception.SyntaxError
+            chunks.append(t.value)
+        b64 = ''.join(chunks)
+        certificate = b64.decode('base64_codec')
+        return cls(rdclass, rdtype, certificate_type, key_tag,
+                   algorithm, certificate)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        prefix = struct.pack("!HHB", self.certificate_type, self.key_tag,
+                             self.algorithm)
+        file.write(prefix)
+        file.write(self.certificate)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        prefix = wire[current : current + 5]
+        current += 5
+        rdlen -= 5
+        if rdlen < 0:
+            raise dns.exception.FormError
+        (certificate_type, key_tag, algorithm) = struct.unpack("!HHB", prefix)
+        certificate = wire[current : current + rdlen]
+        return cls(rdclass, rdtype, certificate_type, key_tag, algorithm,
+                   certificate)
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        f = cStringIO.StringIO()
+        self.to_wire(f)
+        wire1 = f.getvalue()
+        f.seek(0)
+        f.truncate()
+        other.to_wire(f)
+        wire2 = f.getvalue()
+        f.close()
+
+        return cmp(wire1, wire2)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/CNAME.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/CNAME.py
new file mode 100644 (file)
index 0000000..7f5c4b3
--- /dev/null
@@ -0,0 +1,24 @@
+# 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 dns.rdtypes.nsbase
+
+class CNAME(dns.rdtypes.nsbase.NSBase):
+    """CNAME record
+
+    Note: although CNAME is officially a singleton type, dnspython allows
+    non-singleton CNAME rdatasets because such sets have been commonly
+    used by BIND and other nameservers for load balancing."""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DLV.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DLV.py
new file mode 100644 (file)
index 0000000..07b9548
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) 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 dns.rdtypes.dsbase
+
+class DLV(dns.rdtypes.dsbase.DSBase):
+    """DLV record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DNAME.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DNAME.py
new file mode 100644 (file)
index 0000000..99b5013
--- /dev/null
@@ -0,0 +1,21 @@
+# 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 dns.rdtypes.nsbase
+
+class DNAME(dns.rdtypes.nsbase.UncompressedNS):
+    """DNAME record"""
+    def to_digestable(self, origin = None):
+        return self.target.to_digestable(origin)
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DNSKEY.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DNSKEY.py
new file mode 100644 (file)
index 0000000..ad66ef0
--- /dev/null
@@ -0,0 +1,25 @@
+# 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 dns.rdtypes.keybase
+
+# flag constants
+SEP = 0x0001
+REVOKE = 0x0080
+ZONE = 0x0100
+
+class DNSKEY(dns.rdtypes.keybase.KEYBase):
+    """DNSKEY record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DS.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DS.py
new file mode 100644 (file)
index 0000000..3a06f44
--- /dev/null
@@ -0,0 +1,20 @@
+# 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 dns.rdtypes.dsbase
+
+class DS(dns.rdtypes.dsbase.DSBase):
+    """DS record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/GPOS.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/GPOS.py
new file mode 100644 (file)
index 0000000..aa8000f
--- /dev/null
@@ -0,0 +1,156 @@
+# 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 dns.exception
+import dns.rdata
+import dns.tokenizer
+
+def _validate_float_string(what):
+    if what[0] == '-' or what[0] == '+':
+        what = what[1:]
+    if what.isdigit():
+        return
+    (left, right) = what.split('.')
+    if left == '' and right == '':
+        raise dns.exception.FormError
+    if not left == '' and not left.isdigit():
+        raise dns.exception.FormError
+    if not right == '' and not right.isdigit():
+        raise dns.exception.FormError
+
+class GPOS(dns.rdata.Rdata):
+    """GPOS record
+
+    @ivar latitude: latitude
+    @type latitude: string
+    @ivar longitude: longitude
+    @type longitude: string
+    @ivar altitude: altitude
+    @type altitude: string
+    @see: RFC 1712"""
+
+    __slots__ = ['latitude', 'longitude', 'altitude']
+
+    def __init__(self, rdclass, rdtype, latitude, longitude, altitude):
+        super(GPOS, self).__init__(rdclass, rdtype)
+        if isinstance(latitude, float) or \
+           isinstance(latitude, int) or \
+           isinstance(latitude, long):
+            latitude = str(latitude)
+        if isinstance(longitude, float) or \
+           isinstance(longitude, int) or \
+           isinstance(longitude, long):
+            longitude = str(longitude)
+        if isinstance(altitude, float) or \
+           isinstance(altitude, int) or \
+           isinstance(altitude, long):
+            altitude = str(altitude)
+        _validate_float_string(latitude)
+        _validate_float_string(longitude)
+        _validate_float_string(altitude)
+        self.latitude = latitude
+        self.longitude = longitude
+        self.altitude = altitude
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        return '%s %s %s' % (self.latitude, self.longitude, self.altitude)
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        latitude = tok.get_string()
+        longitude = tok.get_string()
+        altitude = tok.get_string()
+        tok.get_eol()
+        return cls(rdclass, rdtype, latitude, longitude, altitude)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        l = len(self.latitude)
+        assert l < 256
+        byte = chr(l)
+        file.write(byte)
+        file.write(self.latitude)
+        l = len(self.longitude)
+        assert l < 256
+        byte = chr(l)
+        file.write(byte)
+        file.write(self.longitude)
+        l = len(self.altitude)
+        assert l < 256
+        byte = chr(l)
+        file.write(byte)
+        file.write(self.altitude)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        l = ord(wire[current])
+        current += 1
+        rdlen -= 1
+        if l > rdlen:
+            raise dns.exception.FormError
+        latitude = wire[current : current + l]
+        current += l
+        rdlen -= l
+        l = ord(wire[current])
+        current += 1
+        rdlen -= 1
+        if l > rdlen:
+            raise dns.exception.FormError
+        longitude = wire[current : current + l]
+        current += l
+        rdlen -= l
+        l = ord(wire[current])
+        current += 1
+        rdlen -= 1
+        if l != rdlen:
+            raise dns.exception.FormError
+        altitude = wire[current : current + l]
+        return cls(rdclass, rdtype, latitude, longitude, altitude)
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        v = cmp(self.latitude, other.latitude)
+        if v == 0:
+            v = cmp(self.longitude, other.longitude)
+            if v == 0:
+                v = cmp(self.altitude, other.altitude)
+        return v
+
+    def _get_float_latitude(self):
+        return float(self.latitude)
+
+    def _set_float_latitude(self, value):
+        self.latitude = str(value)
+
+    float_latitude = property(_get_float_latitude, _set_float_latitude,
+                              doc="latitude as a floating point value")
+
+    def _get_float_longitude(self):
+        return float(self.longitude)
+
+    def _set_float_longitude(self, value):
+        self.longitude = str(value)
+
+    float_longitude = property(_get_float_longitude, _set_float_longitude,
+                               doc="longitude as a floating point value")
+
+    def _get_float_altitude(self):
+        return float(self.altitude)
+
+    def _set_float_altitude(self, value):
+        self.altitude = str(value)
+
+    float_altitude = property(_get_float_altitude, _set_float_altitude,
+                              doc="altitude as a floating point value")
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/HINFO.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/HINFO.py
new file mode 100644 (file)
index 0000000..5cfef5a
--- /dev/null
@@ -0,0 +1,83 @@
+# 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 dns.exception
+import dns.rdata
+import dns.tokenizer
+
+class HINFO(dns.rdata.Rdata):
+    """HINFO record
+
+    @ivar cpu: the CPU type
+    @type cpu: string
+    @ivar os: the OS type
+    @type os: string
+    @see: RFC 1035"""
+
+    __slots__ = ['cpu', 'os']
+
+    def __init__(self, rdclass, rdtype, cpu, os):
+        super(HINFO, self).__init__(rdclass, rdtype)
+        self.cpu = cpu
+        self.os = os
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        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()
+        os = tok.get_string()
+        tok.get_eol()
+        return cls(rdclass, rdtype, cpu, os)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        l = len(self.cpu)
+        assert l < 256
+        byte = chr(l)
+        file.write(byte)
+        file.write(self.cpu)
+        l = len(self.os)
+        assert l < 256
+        byte = chr(l)
+        file.write(byte)
+        file.write(self.os)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        l = ord(wire[current])
+        current += 1
+        rdlen -= 1
+        if l > rdlen:
+            raise dns.exception.FormError
+        cpu = wire[current : current + l]
+        current += l
+        rdlen -= l
+        l = ord(wire[current])
+        current += 1
+        rdlen -= 1
+        if l != rdlen:
+            raise dns.exception.FormError
+        os = wire[current : current + l]
+        return cls(rdclass, rdtype, cpu, os)
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        v = cmp(self.cpu, other.cpu)
+        if v == 0:
+            v = cmp(self.os, other.os)
+        return v
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/HIP.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/HIP.py
new file mode 100644 (file)
index 0000000..8f96ae9
--- /dev/null
@@ -0,0 +1,140 @@
+# Copyright (C) 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 cStringIO
+import string
+import struct
+
+import dns.exception
+import dns.rdata
+import dns.rdatatype
+
+class HIP(dns.rdata.Rdata):
+    """HIP record
+
+    @ivar hit: the host identity tag
+    @type hit: string
+    @ivar algorithm: the public key cryptographic algorithm
+    @type algorithm: int
+    @ivar key: the public key
+    @type key: string
+    @ivar servers: the rendezvous servers
+    @type servers: list of dns.name.Name objects
+    @see: RFC 5205"""
+
+    __slots__ = ['hit', 'algorithm', 'key', 'servers']
+
+    def __init__(self, rdclass, rdtype, hit, algorithm, key, servers):
+        super(HIP, self).__init__(rdclass, rdtype)
+        self.hit = hit
+        self.algorithm = algorithm
+        self.key = key
+        self.servers = servers
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        hit = self.hit.encode('hex-codec')
+        key = self.key.encode('base64-codec').replace('\n', '')
+        text = ''
+        servers = []
+        for server in self.servers:
+            servers.append(str(server.choose_relativity(origin, relativize)))
+        if len(servers) > 0:
+            text += (' ' + ' '.join(servers))
+        return '%u %s %s%s' % (self.algorithm, hit, key, text)
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        algorithm = tok.get_uint8()
+        hit = tok.get_string().decode('hex-codec')
+        if len(hit) > 255:
+            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 = dns.name.from_text(token.value, origin)
+            server.choose_relativity(origin, relativize)
+            servers.append(server)
+        return cls(rdclass, rdtype, hit, algorithm, key, servers)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        lh = len(self.hit)
+        lk = len(self.key)
+        file.write(struct.pack("!BBH", lh, self.algorithm, lk))
+        file.write(self.hit)
+        file.write(self.key)
+        for server in self.servers:
+            server.to_wire(file, None, origin)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        (lh, algorithm, lk) = struct.unpack('!BBH',
+                                            wire[current : current + 4])
+        current += 4
+        rdlen -= 4
+        hit = wire[current : current + lh]
+        current += lh
+        rdlen -= lh
+        key = wire[current : current + lk]
+        current += lk
+        rdlen -= lk
+        servers = []
+        while rdlen > 0:
+            (server, cused) = dns.name.from_wire(wire[: current + rdlen],
+                                                 current)
+            current += cused
+            rdlen -= cused
+            if not origin is None:
+                server = server.relativize(origin)
+            servers.append(server)
+        return cls(rdclass, rdtype, hit, algorithm, key, servers)
+
+    from_wire = classmethod(from_wire)
+
+    def choose_relativity(self, origin = None, relativize = True):
+        servers = []
+        for server in self.servers:
+            server = server.choose_relativity(origin, relativize)
+            servers.append(server)
+        self.servers = servers
+
+    def _cmp(self, other):
+        b1 = cStringIO.StringIO()
+        lh = len(self.hit)
+        lk = len(self.key)
+        b1.write(struct.pack("!BBH", lh, self.algorithm, lk))
+        b1.write(self.hit)
+        b1.write(self.key)
+        b2 = cStringIO.StringIO()
+        lh = len(other.hit)
+        lk = len(other.key)
+        b2.write(struct.pack("!BBH", lh, other.algorithm, lk))
+        b2.write(other.hit)
+        b2.write(other.key)
+        v = cmp(b1.getvalue(), b2.getvalue())
+        if v != 0:
+            return v
+        ls = len(self.servers)
+        lo = len(other.servers)
+        count = min(ls, lo)
+        i = 0
+        while i < count:
+            v = cmp(self.servers[i], other.servers[i])
+            if v != 0:
+                return v
+            i += 1
+        return ls - lo
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/ISDN.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/ISDN.py
new file mode 100644 (file)
index 0000000..424d3a9
--- /dev/null
@@ -0,0 +1,96 @@
+# 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 dns.exception
+import dns.rdata
+import dns.tokenizer
+
+class ISDN(dns.rdata.Rdata):
+    """ISDN record
+
+    @ivar address: the ISDN address
+    @type address: string
+    @ivar subaddress: the ISDN subaddress (or '' if not present)
+    @type subaddress: string
+    @see: RFC 1183"""
+
+    __slots__ = ['address', 'subaddress']
+
+    def __init__(self, rdclass, rdtype, address, subaddress):
+        super(ISDN, self).__init__(rdclass, rdtype)
+        self.address = address
+        self.subaddress = subaddress
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        if self.subaddress:
+            return '"%s" "%s"' % (dns.rdata._escapify(self.address),
+                                  dns.rdata._escapify(self.subaddress))
+        else:
+            return '"%s"' % dns.rdata._escapify(self.address)
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        address = tok.get_string()
+        t = tok.get()
+        if not t.is_eol_or_eof():
+            tok.unget(t)
+            subaddress = tok.get_string()
+        else:
+            tok.unget(t)
+            subaddress = ''
+        tok.get_eol()
+        return cls(rdclass, rdtype, address, subaddress)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        l = len(self.address)
+        assert l < 256
+        byte = chr(l)
+        file.write(byte)
+        file.write(self.address)
+        l = len(self.subaddress)
+        if l > 0:
+            assert l < 256
+            byte = chr(l)
+            file.write(byte)
+            file.write(self.subaddress)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        l = ord(wire[current])
+        current += 1
+        rdlen -= 1
+        if l > rdlen:
+            raise dns.exception.FormError
+        address = wire[current : current + l]
+        current += l
+        rdlen -= l
+        if rdlen > 0:
+            l = ord(wire[current])
+            current += 1
+            rdlen -= 1
+            if l != rdlen:
+                raise dns.exception.FormError
+            subaddress = wire[current : current + l]
+        else:
+            subaddress = ''
+        return cls(rdclass, rdtype, address, subaddress)
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        v = cmp(self.address, other.address)
+        if v == 0:
+            v = cmp(self.subaddress, other.subaddress)
+        return v
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/KEY.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/KEY.py
new file mode 100644 (file)
index 0000000..c8581ed
--- /dev/null
@@ -0,0 +1,20 @@
+# 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 dns.rdtypes.keybase
+
+class KEY(dns.rdtypes.keybase.KEYBase):
+    """KEY record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/LOC.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/LOC.py
new file mode 100644 (file)
index 0000000..518dd60
--- /dev/null
@@ -0,0 +1,334 @@
+# 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 cStringIO
+import struct
+
+import dns.exception
+import dns.rdata
+
+_pows = (1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L,
+         100000000L, 1000000000L, 10000000000L)
+
+def _exponent_of(what, desc):
+    exp = None
+    for i in xrange(len(_pows)):
+        if what // _pows[i] == 0L:
+            exp = i - 1
+            break
+    if exp is None or exp < 0:
+        raise dns.exception.SyntaxError("%s value out of bounds" % desc)
+    return exp
+
+def _float_to_tuple(what):
+    if what < 0:
+        sign = -1
+        what *= -1
+    else:
+        sign = 1
+    what = long(round(what * 3600000))
+    degrees = int(what // 3600000)
+    what -= degrees * 3600000
+    minutes = int(what // 60000)
+    what -= minutes * 60000
+    seconds = int(what // 1000)
+    what -= int(seconds * 1000)
+    what = int(what)
+    return (degrees * sign, minutes, seconds, what)
+
+def _tuple_to_float(what):
+    if what[0] < 0:
+        sign = -1
+        value = float(what[0]) * -1
+    else:
+        sign = 1
+        value = float(what[0])
+    value += float(what[1]) / 60.0
+    value += float(what[2]) / 3600.0
+    value += float(what[3]) / 3600000.0
+    return sign * value
+
+def _encode_size(what, desc):
+    what = long(what);
+    exponent = _exponent_of(what, desc) & 0xF
+    base = what // pow(10, exponent) & 0xF
+    return base * 16 + exponent
+
+def _decode_size(what, desc):
+    exponent = what & 0x0F
+    if exponent > 9:
+        raise dns.exception.SyntaxError("bad %s exponent" % desc)
+    base = (what & 0xF0) >> 4
+    if base > 9:
+        raise dns.exception.SyntaxError("bad %s base" % desc)
+    return long(base) * pow(10, exponent)
+
+class LOC(dns.rdata.Rdata):
+    """LOC record
+
+    @ivar latitude: latitude
+    @type latitude: (int, int, int, int) tuple specifying the degrees, minutes,
+    seconds, and milliseconds of the coordinate.
+    @ivar longitude: longitude
+    @type longitude: (int, int, int, int) tuple specifying the degrees,
+    minutes, seconds, and milliseconds of the coordinate.
+    @ivar altitude: altitude
+    @type altitude: float
+    @ivar size: size of the sphere
+    @type size: float
+    @ivar horizontal_precision: horizontal precision
+    @type horizontal_precision: float
+    @ivar vertical_precision: vertical precision
+    @type vertical_precision: float
+    @see: RFC 1876"""
+
+    __slots__ = ['latitude', 'longitude', 'altitude', 'size',
+                 'horizontal_precision', 'vertical_precision']
+
+    def __init__(self, rdclass, rdtype, latitude, longitude, altitude,
+                 size=1.0, hprec=10000.0, vprec=10.0):
+        """Initialize a LOC record instance.
+
+        The parameters I{latitude} and I{longitude} may be either a 4-tuple
+        of integers specifying (degrees, minutes, seconds, milliseconds),
+        or they may be floating point values specifying the number of
+        degrees.  The other parameters are floats."""
+
+        super(LOC, self).__init__(rdclass, rdtype)
+        if isinstance(latitude, int) or isinstance(latitude, long):
+            latitude = float(latitude)
+        if isinstance(latitude, float):
+            latitude = _float_to_tuple(latitude)
+        self.latitude = latitude
+        if isinstance(longitude, int) or isinstance(longitude, long):
+            longitude = float(longitude)
+        if isinstance(longitude, float):
+            longitude = _float_to_tuple(longitude)
+        self.longitude = longitude
+        self.altitude = float(altitude)
+        self.size = float(size)
+        self.horizontal_precision = float(hprec)
+        self.vertical_precision = float(vprec)
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        if self.latitude[0] > 0:
+            lat_hemisphere = 'N'
+            lat_degrees = self.latitude[0]
+        else:
+            lat_hemisphere = 'S'
+            lat_degrees = -1 * self.latitude[0]
+        if self.longitude[0] > 0:
+            long_hemisphere = 'E'
+            long_degrees = self.longitude[0]
+        else:
+            long_hemisphere = 'W'
+            long_degrees = -1 * self.longitude[0]
+        text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % (
+            lat_degrees, self.latitude[1], self.latitude[2], self.latitude[3],
+            lat_hemisphere, long_degrees, self.longitude[1], self.longitude[2],
+            self.longitude[3], long_hemisphere, self.altitude / 100.0
+            )
+
+        if self.size != 1.0 or self.horizontal_precision != 10000.0 or \
+           self.vertical_precision != 10.0:
+            text += " %0.2fm %0.2fm %0.2fm" % (
+                self.size / 100.0, self.horizontal_precision / 100.0,
+                self.vertical_precision / 100.0
+            )
+        return text
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        latitude = [0, 0, 0, 0]
+        longitude = [0, 0, 0, 0]
+        size = 1.0
+        hprec = 10000.0
+        vprec = 10.0
+
+        latitude[0] = tok.get_int()
+        t = tok.get_string()
+        if t.isdigit():
+            latitude[1] = int(t)
+            t = tok.get_string()
+            if '.' in t:
+                (seconds, milliseconds) = t.split('.')
+                if not seconds.isdigit():
+                    raise dns.exception.SyntaxError('bad latitude seconds value')
+                latitude[2] = int(seconds)
+                if latitude[2] >= 60:
+                    raise dns.exception.SyntaxError('latitude seconds >= 60')
+                l = len(milliseconds)
+                if l == 0 or l > 3 or not milliseconds.isdigit():
+                    raise dns.exception.SyntaxError('bad latitude milliseconds value')
+                if l == 1:
+                    m = 100
+                elif l == 2:
+                    m = 10
+                else:
+                    m = 1
+                latitude[3] = m * int(milliseconds)
+                t = tok.get_string()
+            elif t.isdigit():
+                latitude[2] = int(t)
+                t = tok.get_string()
+        if t == 'S':
+            latitude[0] *= -1
+        elif t != 'N':
+            raise dns.exception.SyntaxError('bad latitude hemisphere value')
+
+        longitude[0] = tok.get_int()
+        t = tok.get_string()
+        if t.isdigit():
+            longitude[1] = int(t)
+            t = tok.get_string()
+            if '.' in t:
+                (seconds, milliseconds) = t.split('.')
+                if not seconds.isdigit():
+                    raise dns.exception.SyntaxError('bad longitude seconds value')
+                longitude[2] = int(seconds)
+                if longitude[2] >= 60:
+                    raise dns.exception.SyntaxError('longitude seconds >= 60')
+                l = len(milliseconds)
+                if l == 0 or l > 3 or not milliseconds.isdigit():
+                    raise dns.exception.SyntaxError('bad longitude milliseconds value')
+                if l == 1:
+                    m = 100
+                elif l == 2:
+                    m = 10
+                else:
+                    m = 1
+                longitude[3] = m * int(milliseconds)
+                t = tok.get_string()
+            elif t.isdigit():
+                longitude[2] = int(t)
+                t = tok.get_string()
+        if t == 'W':
+            longitude[0] *= -1
+        elif t != 'E':
+            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
+
+        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
+            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
+                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
+                        tok.get_eol()
+
+        return cls(rdclass, rdtype, latitude, longitude, altitude,
+                   size, hprec, vprec)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        if self.latitude[0] < 0:
+            sign = -1
+            degrees = long(-1 * self.latitude[0])
+        else:
+            sign = 1
+            degrees = long(self.latitude[0])
+        milliseconds = (degrees * 3600000 +
+                        self.latitude[1] * 60000 +
+                        self.latitude[2] * 1000 +
+                        self.latitude[3]) * sign
+        latitude = 0x80000000L + milliseconds
+        if self.longitude[0] < 0:
+            sign = -1
+            degrees = long(-1 * self.longitude[0])
+        else:
+            sign = 1
+            degrees = long(self.longitude[0])
+        milliseconds = (degrees * 3600000 +
+                        self.longitude[1] * 60000 +
+                        self.longitude[2] * 1000 +
+                        self.longitude[3]) * sign
+        longitude = 0x80000000L + milliseconds
+        altitude = long(self.altitude) + 10000000L
+        size = _encode_size(self.size, "size")
+        hprec = _encode_size(self.horizontal_precision, "horizontal precision")
+        vprec = _encode_size(self.vertical_precision, "vertical precision")
+        wire = struct.pack("!BBBBIII", 0, size, hprec, vprec, latitude,
+                           longitude, altitude)
+        file.write(wire)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        (version, size, hprec, vprec, latitude, longitude, altitude) = \
+                  struct.unpack("!BBBBIII", wire[current : current + rdlen])
+        if latitude > 0x80000000L:
+            latitude = float(latitude - 0x80000000L) / 3600000
+        else:
+            latitude = -1 * float(0x80000000L - latitude) / 3600000
+        if latitude < -90.0 or latitude > 90.0:
+            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 dns.exception.FormError("bad longitude")
+        altitude = float(altitude) - 10000000.0
+        size = _decode_size(size, "size")
+        hprec = _decode_size(hprec, "horizontal precision")
+        vprec = _decode_size(vprec, "vertical precision")
+        return cls(rdclass, rdtype, latitude, longitude, altitude,
+                   size, hprec, vprec)
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        f = cStringIO.StringIO()
+        self.to_wire(f)
+        wire1 = f.getvalue()
+        f.seek(0)
+        f.truncate()
+        other.to_wire(f)
+        wire2 = f.getvalue()
+        f.close()
+
+        return cmp(wire1, wire2)
+
+    def _get_float_latitude(self):
+        return _tuple_to_float(self.latitude)
+
+    def _set_float_latitude(self, value):
+        self.latitude = _float_to_tuple(value)
+
+    float_latitude = property(_get_float_latitude, _set_float_latitude,
+                              doc="latitude as a floating point value")
+
+    def _get_float_longitude(self):
+        return _tuple_to_float(self.longitude)
+
+    def _set_float_longitude(self, value):
+        self.longitude = _float_to_tuple(value)
+
+    float_longitude = property(_get_float_longitude, _set_float_longitude,
+                               doc="longitude as a floating point value")
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/MX.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/MX.py
new file mode 100644 (file)
index 0000000..9cad260
--- /dev/null
@@ -0,0 +1,20 @@
+# 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 dns.rdtypes.mxbase
+
+class MX(dns.rdtypes.mxbase.MXBase):
+    """MX record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NS.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NS.py
new file mode 100644 (file)
index 0000000..4b03a3a
--- /dev/null
@@ -0,0 +1,20 @@
+# 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 dns.rdtypes.nsbase
+
+class NS(dns.rdtypes.nsbase.NSBase):
+    """NS record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC.py
new file mode 100644 (file)
index 0000000..72859ce
--- /dev/null
@@ -0,0 +1,141 @@
+# 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 cStringIO
+
+import dns.exception
+import dns.rdata
+import dns.rdatatype
+import dns.name
+
+class NSEC(dns.rdata.Rdata):
+    """NSEC record
+
+    @ivar next: the next name
+    @type next: dns.name.Name object
+    @ivar windows: the windowed bitmap list
+    @type windows: list of (window number, string) tuples"""
+
+    __slots__ = ['next', 'windows']
+
+    def __init__(self, rdclass, rdtype, next, windows):
+        super(NSEC, self).__init__(rdclass, rdtype)
+        self.next = next
+        self.windows = windows
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        next = self.next.choose_relativity(origin, relativize)
+        text = ''
+        for (window, bitmap) in self.windows:
+            bits = []
+            for i in xrange(0, len(bitmap)):
+                byte = ord(bitmap[i])
+                for j in xrange(0, 8):
+                    if byte & (0x80 >> j):
+                        bits.append(dns.rdatatype.to_text(window * 256 + \
+                                                          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)
+        rdtypes = []
+        while 1:
+            token = tok.get().unescape()
+            if token.is_eol_or_eof():
+                break
+            nrdtype = dns.rdatatype.from_text(token.value)
+            if nrdtype == 0:
+                raise dns.exception.SyntaxError("NSEC with bit 0")
+            if nrdtype > 65535:
+                raise dns.exception.SyntaxError("NSEC with bit > 65535")
+            rdtypes.append(nrdtype)
+        rdtypes.sort()
+        window = 0
+        octets = 0
+        prior_rdtype = 0
+        bitmap = ['\0'] * 32
+        windows = []
+        for nrdtype in rdtypes:
+            if nrdtype == prior_rdtype:
+                continue
+            prior_rdtype = nrdtype
+            new_window = nrdtype // 256
+            if new_window != window:
+                windows.append((window, ''.join(bitmap[0:octets])))
+                bitmap = ['\0'] * 32
+                window = new_window
+            offset = nrdtype % 256
+            byte = offset / 8
+            bit = offset % 8
+            octets = byte + 1
+            bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit))
+        windows.append((window, ''.join(bitmap[0:octets])))
+        return cls(rdclass, rdtype, next, windows)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        self.next.to_wire(file, None, origin)
+        for (window, bitmap) in self.windows:
+            file.write(chr(window))
+            file.write(chr(len(bitmap)))
+            file.write(bitmap)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        (next, cused) = dns.name.from_wire(wire[: current + rdlen], current)
+        current += cused
+        rdlen -= cused
+        windows = []
+        while rdlen > 0:
+            if rdlen < 3:
+                raise dns.exception.FormError("NSEC too short")
+            window = ord(wire[current])
+            octets = ord(wire[current + 1])
+            if octets == 0 or octets > 32:
+                raise dns.exception.FormError("bad NSEC octets")
+            current += 2
+            rdlen -= 2
+            if rdlen < octets:
+                raise dns.exception.FormError("bad NSEC bitmap length")
+            bitmap = wire[current : current + octets]
+            current += octets
+            rdlen -= octets
+            windows.append((window, bitmap))
+        if not origin is None:
+            next = next.relativize(origin)
+        return cls(rdclass, rdtype, next, windows)
+
+    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:
+            b1 = cStringIO.StringIO()
+            for (window, bitmap) in self.windows:
+                b1.write(chr(window))
+                b1.write(chr(len(bitmap)))
+                b1.write(bitmap)
+            b2 = cStringIO.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
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC3.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC3.py
new file mode 100644 (file)
index 0000000..932d7b4
--- /dev/null
@@ -0,0 +1,182 @@
+# 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 base64
+import cStringIO
+import string
+import struct
+
+import dns.exception
+import dns.rdata
+import dns.rdatatype
+
+b32_hex_to_normal = string.maketrans('0123456789ABCDEFGHIJKLMNOPQRSTUV',
+                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567')
+b32_normal_to_hex = string.maketrans('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
+                                     '0123456789ABCDEFGHIJKLMNOPQRSTUV')
+
+# hash algorithm constants
+SHA1 = 1
+
+# flag constants
+OPTOUT = 1
+
+class NSEC3(dns.rdata.Rdata):
+    """NSEC3 record
+
+    @ivar algorithm: the hash algorithm number
+    @type algorithm: int
+    @ivar flags: the flags
+    @type flags: int
+    @ivar iterations: the number of iterations
+    @type iterations: int
+    @ivar salt: the salt
+    @type salt: string
+    @ivar next: the next name hash
+    @type next: string
+    @ivar windows: the windowed bitmap list
+    @type windows: list of (window number, string) tuples"""
+
+    __slots__ = ['algorithm', 'flags', 'iterations', 'salt', 'next', 'windows']
+
+    def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt,
+                 next, windows):
+        super(NSEC3, self).__init__(rdclass, rdtype)
+        self.algorithm = algorithm
+        self.flags = flags
+        self.iterations = iterations
+        self.salt = salt
+        self.next = next
+        self.windows = windows
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        next = base64.b32encode(self.next).translate(b32_normal_to_hex).lower()
+        if self.salt == '':
+            salt = '-'
+        else:
+            salt = self.salt.encode('hex-codec')
+        text = ''
+        for (window, bitmap) in self.windows:
+            bits = []
+            for i in xrange(0, len(bitmap)):
+                byte = ord(bitmap[i])
+                for j in xrange(0, 8):
+                    if byte & (0x80 >> j):
+                        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,
+                                     salt, next, text)
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        algorithm = tok.get_uint8()
+        flags = tok.get_uint8()
+        iterations = tok.get_uint16()
+        salt = tok.get_string()
+        if salt == '-':
+            salt = ''
+        else:
+            salt = salt.decode('hex-codec')
+        next = tok.get_string().upper().translate(b32_hex_to_normal)
+        next = base64.b32decode(next)
+        rdtypes = []
+        while 1:
+            token = tok.get().unescape()
+            if token.is_eol_or_eof():
+                break
+            nrdtype = dns.rdatatype.from_text(token.value)
+            if nrdtype == 0:
+                raise dns.exception.SyntaxError("NSEC3 with bit 0")
+            if nrdtype > 65535:
+                raise dns.exception.SyntaxError("NSEC3 with bit > 65535")
+            rdtypes.append(nrdtype)
+        rdtypes.sort()
+        window = 0
+        octets = 0
+        prior_rdtype = 0
+        bitmap = ['\0'] * 32
+        windows = []
+        for nrdtype in rdtypes:
+            if nrdtype == prior_rdtype:
+                continue
+            prior_rdtype = nrdtype
+            new_window = nrdtype // 256
+            if new_window != window:
+                windows.append((window, ''.join(bitmap[0:octets])))
+                bitmap = ['\0'] * 32
+                window = new_window
+            offset = nrdtype % 256
+            byte = offset / 8
+            bit = offset % 8
+            octets = byte + 1
+            bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit))
+        windows.append((window, ''.join(bitmap[0:octets])))
+        return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, windows)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        l = len(self.salt)
+        file.write(struct.pack("!BBHB", self.algorithm, self.flags,
+                               self.iterations, l))
+        file.write(self.salt)
+        l = len(self.next)
+        file.write(struct.pack("!B", l))
+        file.write(self.next)
+        for (window, bitmap) in self.windows:
+            file.write(chr(window))
+            file.write(chr(len(bitmap)))
+            file.write(bitmap)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        (algorithm, flags, iterations, slen) = struct.unpack('!BBHB',
+                                                             wire[current : current + 5])
+        current += 5
+        rdlen -= 5
+        salt = wire[current : current + slen]
+        current += slen
+        rdlen -= slen
+        (nlen, ) = struct.unpack('!B', wire[current])
+        current += 1
+        rdlen -= 1
+        next = wire[current : current + nlen]
+        current += nlen
+        rdlen -= nlen
+        windows = []
+        while rdlen > 0:
+            if rdlen < 3:
+                raise dns.exception.FormError("NSEC3 too short")
+            window = ord(wire[current])
+            octets = ord(wire[current + 1])
+            if octets == 0 or octets > 32:
+                raise dns.exception.FormError("bad NSEC3 octets")
+            current += 2
+            rdlen -= 2
+            if rdlen < octets:
+                raise dns.exception.FormError("bad NSEC3 bitmap length")
+            bitmap = wire[current : current + octets]
+            current += octets
+            rdlen -= octets
+            windows.append((window, bitmap))
+        return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, windows)
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        b1 = cStringIO.StringIO()
+        self.to_wire(b1)
+        b2 = cStringIO.StringIO()
+        other.to_wire(b2)
+        return cmp(b1.getvalue(), b2.getvalue())
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py
new file mode 100644 (file)
index 0000000..ec91e5e
--- /dev/null
@@ -0,0 +1,88 @@
+# 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 cStringIO
+import struct
+
+import dns.exception
+import dns.rdata
+
+class NSEC3PARAM(dns.rdata.Rdata):
+    """NSEC3PARAM record
+
+    @ivar algorithm: the hash algorithm number
+    @type algorithm: int
+    @ivar flags: the flags
+    @type flags: int
+    @ivar iterations: the number of iterations
+    @type iterations: int
+    @ivar salt: the salt
+    @type salt: string"""
+
+    __slots__ = ['algorithm', 'flags', 'iterations', 'salt']
+
+    def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt):
+        super(NSEC3PARAM, self).__init__(rdclass, rdtype)
+        self.algorithm = algorithm
+        self.flags = flags
+        self.iterations = iterations
+        self.salt = salt
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        if self.salt == '':
+            salt = '-'
+        else:
+            salt = self.salt.encode('hex-codec')
+        return '%u %u %u %s' % (self.algorithm, self.flags, self.iterations, salt)
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        algorithm = tok.get_uint8()
+        flags = tok.get_uint8()
+        iterations = tok.get_uint16()
+        salt = tok.get_string()
+        if salt == '-':
+            salt = ''
+        else:
+            salt = salt.decode('hex-codec')
+        return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        l = len(self.salt)
+        file.write(struct.pack("!BBHB", self.algorithm, self.flags,
+                               self.iterations, l))
+        file.write(self.salt)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        (algorithm, flags, iterations, slen) = struct.unpack('!BBHB',
+                                                             wire[current : current + 5])
+        current += 5
+        rdlen -= 5
+        salt = wire[current : current + slen]
+        current += slen
+        rdlen -= slen
+        if rdlen != 0:
+            raise dns.exception.FormError
+        return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
+
+    from_wire = classmethod(from_wire)
+
+    def _cmp(self, other):
+        b1 = cStringIO.StringIO()
+        self.to_wire(b1)
+        b2 = cStringIO.StringIO()
+        other.to_wire(b2)
+        return cmp(b1.getvalue(), b2.getvalue())
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NXT.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NXT.py
new file mode 100644 (file)
index 0000000..99ae9b9
--- /dev/null
@@ -0,0 +1,99 @@
+# 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 dns.exception
+import dns.rdata
+import dns.rdatatype
+import dns.name
+
+class NXT(dns.rdata.Rdata):
+    """NXT record
+
+    @ivar next: the next name
+    @type next: 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(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 = dns.rdatatype.from_text(token.value)
+            if nrdtype == 0:
+                raise dns.exception.SyntaxError("NXT with bit 0")
+            if nrdtype > 127:
+                raise dns.exception.SyntaxError("NXT with bit > 127")
+            i = nrdtype // 8
+            bitmap[i] = chr(ord(bitmap[i]) | (0x80 >> (nrdtype % 8)))
+        bitmap = 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) = dns.name.from_wire(wire[: current + rdlen], current)
+        current += cused
+        rdlen -= cused
+        bitmap = wire[current : current + rdlen]
+        if not origin is None:
+            next = next.relativize(origin)
+        return cls(rdclass, rdtype, next, bitmap)
+
+    from_wire = classmethod(from_wire)
+
+    def choose_relativity(self, origin = None, relativize = True):
+        self.next = self.next.choose_relativity(origin, relativize)
+
+    def _cmp(self, other):
+        v = cmp(self.next, other.next)
+        if v == 0:
+            v = cmp(self.bitmap, other.bitmap)
+        return v
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/PTR.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/PTR.py
new file mode 100644 (file)
index 0000000..6c4b79e
--- /dev/null
@@ -0,0 +1,20 @@
+# 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 dns.rdtypes.nsbase
+
+class PTR(dns.rdtypes.nsbase.NSBase):
+    """PTR record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RP.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RP.py
new file mode 100644 (file)
index 0000000..421ce8e
--- /dev/null
@@ -0,0 +1,86 @@
+# 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 dns.exception
+import dns.rdata
+import dns.name
+
+class RP(dns.rdata.Rdata):
+    """RP record
+
+    @ivar mbox: The responsible person's mailbox
+    @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: dns.name.Name object
+    @see: RFC 1183"""
+
+    __slots__ = ['mbox', 'txt']
+
+    def __init__(self, rdclass, rdtype, mbox, txt):
+        super(RP, self).__init__(rdclass, rdtype)
+        self.mbox = mbox
+        self.txt = txt
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        mbox = self.mbox.choose_relativity(origin, relativize)
+        txt = self.txt.choose_relativity(origin, relativize)
+        return "%s %s" % (str(mbox), str(txt))
+
+    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
+        mbox = tok.get_name()
+        txt = tok.get_name()
+        mbox = mbox.choose_relativity(origin, relativize)
+        txt = txt.choose_relativity(origin, relativize)
+        tok.get_eol()
+        return cls(rdclass, rdtype, mbox, txt)
+
+    from_text = classmethod(from_text)
+
+    def to_wire(self, file, compress = None, origin = None):
+        self.mbox.to_wire(file, None, origin)
+        self.txt.to_wire(file, None, origin)
+
+    def to_digestable(self, origin = None):
+        return self.mbox.to_digestable(origin) + \
+            self.txt.to_digestable(origin)
+
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
+        (mbox, cused) = dns.name.from_wire(wire[: current + rdlen],
+                                           current)
+        current += cused
+        rdlen -= cused
+        if rdlen <= 0:
+            raise dns.exception.FormError
+        (txt, cused) = dns.name.from_wire(wire[: current + rdlen],
+                                          current)
+        if cused != rdlen:
+            raise dns.exception.FormError
+        if not origin is None:
+            mbox = mbox.relativize(origin)
+            txt = txt.relativize(origin)
+        return cls(rdclass, rdtype, mbox, txt)
+
+    from_wire = classmethod(from_wire)
+
+    def choose_relativity(self, origin = None, relativize = True):
+        self.mbox = self.mbox.choose_relativity(origin, relativize)
+        self.txt = self.txt.choose_relativity(origin, relativize)
+
+    def _cmp(self, other):
+        v = cmp(self.mbox, other.mbox)
+        if v == 0:
+            v = cmp(self.txt, other.txt)
+        return v
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RRSIG.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RRSIG.py
new file mode 100644 (file)
index 0000000..0e4816f
--- /dev/null
@@ -0,0 +1,20 @@
+# 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 dns.rdtypes.sigbase
+
+class RRSIG(dns.rdtypes.sigbase.SIGBase):
+    """RRSIG record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RT.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RT.py
new file mode 100644 (file)
index 0000000..1efd372
--- /dev/null
@@ -0,0 +1,20 @@
+# 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 dns.rdtypes.mxbase
+
+class RT(dns.rdtypes.mxbase.UncompressedDowncasingMX):
+    """RT record"""
+    pass
diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SIG.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SIG.py
new file mode 100644 (file)
index 0000000..501e29c
--- /dev/null
@@ -0,0 +1,26 @@
+# 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