diff options
author | Andrew Tridgell <tridge@samba.org> | 2010-03-05 11:45:40 +1100 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2010-03-05 11:54:36 +1100 |
commit | 7d86257d54cb59d016a051b91bdee62ab2f8a0d5 (patch) | |
tree | ca682263ae2dffeaf58134e47080078864df64d4 /source4/scripting/python/samba_external | |
parent | f3ca7a4696cadbb74f41dd71ef9336445682d406 (diff) | |
download | samba-7d86257d54cb59d016a051b91bdee62ab2f8a0d5.tar.gz samba-7d86257d54cb59d016a051b91bdee62ab2f8a0d5.tar.bz2 samba-7d86257d54cb59d016a051b91bdee62ab2f8a0d5.zip |
s4-python: import a copy of the python dns library
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>
Diffstat (limited to 'source4/scripting/python/samba_external')
114 files changed, 16829 insertions, 0 deletions
diff --git a/source4/scripting/python/samba_external/README b/source4/scripting/python/samba_external/README new file mode 100644 index 0000000000..d6a4dec7b1 --- /dev/null +++ b/source4/scripting/python/samba_external/README @@ -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 index 0000000000..f5a74da2b4 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/ChangeLog @@ -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 index 0000000000..633c18c1e7 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/LICENSE @@ -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 index 0000000000..455915df36 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/PKG-INFO @@ -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 index 0000000000..0e5793ace0 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/README @@ -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 index 0000000000..59ce1be1ce --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/TODO @@ -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 index 0000000000..5ad5737cfa --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/__init__.py @@ -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 index 0000000000..acf46535b9 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/dnssec.py @@ -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 index 0000000000..d8f71ec799 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/e164.py @@ -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 index 0000000000..1731cedde4 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/edns.py @@ -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 index 0000000000..fd9d4f8cdf --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/entropy.py @@ -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 index 0000000000..c6d6570d98 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/exception.py @@ -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 index 0000000000..79375ea2ce --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/flags.py @@ -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 index 0000000000..993a2f9436 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/inet.py @@ -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 index 0000000000..1569da5475 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/ipv4.py @@ -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 index 0000000000..33c6713796 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/ipv6.py @@ -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 index 0000000000..ba0ebf65f1 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/message.py @@ -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 index 0000000000..f239c9b5de --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/name.py @@ -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 index 0000000000..54afb77188 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/namedict.py @@ -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 index 0000000000..785a245464 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/node.py @@ -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 index 0000000000..735d3a1f7d --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/opcode.py @@ -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 index 0000000000..c023b140af --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/query.py @@ -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 index 0000000000..c055f2e7cd --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rcode.py @@ -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 index 0000000000..ce0268697b --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdata.py @@ -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 index 0000000000..887fd1ad6b --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdataclass.py @@ -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 index 0000000000..0af018bab5 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdataset.py @@ -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 index 0000000000..1a02b7d3cd --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdatatype.py @@ -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 index 0000000000..e8ca6f5cbb --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/AFSDB.py @@ -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 index 0000000000..d2703519d5 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/CERT.py @@ -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 index 0000000000..7f5c4b3bd7 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/CNAME.py @@ -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 index 0000000000..07b9548342 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DLV.py @@ -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 index 0000000000..99b5013f33 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DNAME.py @@ -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 index 0000000000..ad66ef0c69 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DNSKEY.py @@ -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 index 0000000000..3a06f448f7 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/DS.py @@ -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 index 0000000000..aa8000f8ca --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/GPOS.py @@ -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 index 0000000000..5cfef5a932 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/HINFO.py @@ -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 index 0000000000..8f96ae93d6 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/HIP.py @@ -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 index 0000000000..424d3a9a3c --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/ISDN.py @@ -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 index 0000000000..c8581edbeb --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/KEY.py @@ -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 index 0000000000..518dd6010f --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/LOC.py @@ -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 index 0000000000..9cad260672 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/MX.py @@ -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 index 0000000000..4b03a3ab47 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NS.py @@ -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 index 0000000000..72859ce108 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC.py @@ -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 index 0000000000..932d7b4032 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC3.py @@ -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 index 0000000000..ec91e5e85c --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py @@ -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 index 0000000000..99ae9b9dff --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/NXT.py @@ -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 index 0000000000..6c4b79eaac --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/PTR.py @@ -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 index 0000000000..421ce8e207 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RP.py @@ -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 index 0000000000..0e4816f648 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RRSIG.py @@ -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 index 0000000000..1efd3724d9 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/RT.py @@ -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 index 0000000000..501e29cc8c --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SIG.py @@ -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 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 SIG(dns.rdtypes.sigbase.SIGBase): + """SIG record""" + def to_digestable(self, origin = None): + return struct.pack('!HBBIIIH', self.type_covered, + self.algorithm, self.labels, + self.original_ttl, self.expiration, + self.inception, self.key_tag) + \ + self.signer.to_digestable(origin) + \ + self.signature diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SOA.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SOA.py new file mode 100644 index 0000000000..5f74b8d384 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SOA.py @@ -0,0 +1,127 @@ +# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import struct + +import dns.exception +import dns.rdata +import dns.name + +class SOA(dns.rdata.Rdata): + """SOA record + + @ivar mname: the SOA MNAME (master name) field + @type mname: dns.name.Name object + @ivar rname: the SOA RNAME (responsible name) field + @type rname: dns.name.Name object + @ivar serial: The zone's serial number + @type serial: int + @ivar refresh: The zone's refresh value (in seconds) + @type refresh: int + @ivar retry: The zone's retry value (in seconds) + @type retry: int + @ivar expire: The zone's expiration value (in seconds) + @type expire: int + @ivar minimum: The zone's negative caching time (in seconds, called + "minimum" for historical reasons) + @type minimum: int + @see: RFC 1035""" + + __slots__ = ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', + 'minimum'] + + def __init__(self, rdclass, rdtype, mname, rname, serial, refresh, retry, + expire, minimum): + super(SOA, self).__init__(rdclass, rdtype) + self.mname = mname + self.rname = rname + self.serial = serial + self.refresh = refresh + self.retry = retry + self.expire = expire + self.minimum = minimum + + def to_text(self, origin=None, relativize=True, **kw): + mname = self.mname.choose_relativity(origin, relativize) + rname = self.rname.choose_relativity(origin, relativize) + return '%s %s %d %d %d %d %d' % ( + mname, rname, self.serial, self.refresh, self.retry, + self.expire, self.minimum ) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + mname = tok.get_name() + rname = tok.get_name() + mname = mname.choose_relativity(origin, relativize) + rname = rname.choose_relativity(origin, relativize) + serial = tok.get_uint32() + refresh = tok.get_ttl() + retry = tok.get_ttl() + expire = tok.get_ttl() + minimum = tok.get_ttl() + tok.get_eol() + return cls(rdclass, rdtype, mname, rname, serial, refresh, retry, + expire, minimum ) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + self.mname.to_wire(file, compress, origin) + self.rname.to_wire(file, compress, origin) + five_ints = struct.pack('!IIIII', self.serial, self.refresh, + self.retry, self.expire, self.minimum) + file.write(five_ints) + + def to_digestable(self, origin = None): + return self.mname.to_digestable(origin) + \ + self.rname.to_digestable(origin) + \ + struct.pack('!IIIII', self.serial, self.refresh, + self.retry, self.expire, self.minimum) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + (mname, cused) = dns.name.from_wire(wire[: current + rdlen], current) + current += cused + rdlen -= cused + (rname, cused) = dns.name.from_wire(wire[: current + rdlen], current) + current += cused + rdlen -= cused + if rdlen != 20: + raise dns.exception.FormError + five_ints = struct.unpack('!IIIII', + wire[current : current + rdlen]) + if not origin is None: + mname = mname.relativize(origin) + rname = rname.relativize(origin) + return cls(rdclass, rdtype, mname, rname, + five_ints[0], five_ints[1], five_ints[2], five_ints[3], + five_ints[4]) + + from_wire = classmethod(from_wire) + + def choose_relativity(self, origin = None, relativize = True): + self.mname = self.mname.choose_relativity(origin, relativize) + self.rname = self.rname.choose_relativity(origin, relativize) + + def _cmp(self, other): + v = cmp(self.mname, other.mname) + if v == 0: + v = cmp(self.rname, other.rname) + if v == 0: + self_ints = struct.pack('!IIIII', self.serial, self.refresh, + self.retry, self.expire, self.minimum) + other_ints = struct.pack('!IIIII', other.serial, other.refresh, + other.retry, other.expire, + other.minimum) + v = cmp(self_ints, other_ints) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SPF.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SPF.py new file mode 100644 index 0000000000..9b5a9a9fed --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SPF.py @@ -0,0 +1,22 @@ +# Copyright (C) 2006, 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.txtbase + +class SPF(dns.rdtypes.txtbase.TXTBase): + """SPF record + + @see: RFC 4408""" + pass diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SSHFP.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SSHFP.py new file mode 100644 index 0000000000..bc54f5e260 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/SSHFP.py @@ -0,0 +1,77 @@ +# Copyright (C) 2005-2007, 2009, 2010 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import struct + +import dns.rdata +import dns.rdatatype + +class SSHFP(dns.rdata.Rdata): + """SSHFP record + + @ivar algorithm: the algorithm + @type algorithm: int + @ivar fp_type: the digest type + @type fp_type: int + @ivar fingerprint: the fingerprint + @type fingerprint: string + @see: draft-ietf-secsh-dns-05.txt""" + + __slots__ = ['algorithm', 'fp_type', 'fingerprint'] + + def __init__(self, rdclass, rdtype, algorithm, fp_type, + fingerprint): + super(SSHFP, self).__init__(rdclass, rdtype) + self.algorithm = algorithm + self.fp_type = fp_type + self.fingerprint = fingerprint + + def to_text(self, origin=None, relativize=True, **kw): + return '%d %d %s' % (self.algorithm, + self.fp_type, + dns.rdata._hexify(self.fingerprint, + chunksize=128)) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + algorithm = tok.get_uint8() + fp_type = tok.get_uint8() + fingerprint = tok.get_string() + fingerprint = fingerprint.decode('hex_codec') + tok.get_eol() + return cls(rdclass, rdtype, algorithm, fp_type, fingerprint) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + header = struct.pack("!BB", self.algorithm, self.fp_type) + file.write(header) + file.write(self.fingerprint) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + header = struct.unpack("!BB", wire[current : current + 2]) + current += 2 + rdlen -= 2 + fingerprint = wire[current : current + rdlen] + return cls(rdclass, rdtype, header[0], header[1], fingerprint) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + hs = struct.pack("!BB", self.algorithm, self.fp_type) + ho = struct.pack("!BB", other.algorithm, other.fp_type) + v = cmp(hs, ho) + if v == 0: + v = cmp(self.fingerprint, other.fingerprint) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/TXT.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/TXT.py new file mode 100644 index 0000000000..23f4f3b7c6 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/TXT.py @@ -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.txtbase + +class TXT(dns.rdtypes.txtbase.TXTBase): + """TXT record""" + pass diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/X25.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/X25.py new file mode 100644 index 0000000000..fc4790fe8a --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/X25.py @@ -0,0 +1,62 @@ +# 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 X25(dns.rdata.Rdata): + """X25 record + + @ivar address: the PSDN address + @type address: string + @see: RFC 1183""" + + __slots__ = ['address'] + + def __init__(self, rdclass, rdtype, address): + super(X25, self).__init__(rdclass, rdtype) + self.address = address + + def to_text(self, origin=None, relativize=True, **kw): + return '"%s"' % dns.rdata._escapify(self.address) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + address = tok.get_string() + tok.get_eol() + return cls(rdclass, rdtype, address) + + 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) + + 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] + return cls(rdclass, rdtype, address) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + return cmp(self.address, other.address) diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/__init__.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/__init__.py new file mode 100644 index 0000000000..0815dd5450 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/ANY/__init__.py @@ -0,0 +1,48 @@ +# 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. + +"""Class ANY (generic) rdata type classes.""" + +__all__ = [ + 'AFSDB', + 'CERT', + 'CNAME', + 'DLV', + 'DNAME', + 'DNSKEY', + 'DS', + 'GPOS', + 'HINFO', + 'HIP', + 'ISDN', + 'KEY', + 'LOC', + 'MX', + 'NS', + 'NSEC', + 'NSEC3', + 'NSEC3PARAM', + 'NXT', + 'PTR', + 'RP', + 'RRSIG', + 'RT', + 'SIG', + 'SOA', + 'SPF', + 'SSHFP', + 'TXT', + 'X25', +] diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/A.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/A.py new file mode 100644 index 0000000000..e05f204a2f --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/A.py @@ -0,0 +1,57 @@ +# 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.ipv4 +import dns.rdata +import dns.tokenizer + +class A(dns.rdata.Rdata): + """A record. + + @ivar address: an IPv4 address + @type address: string (in the standard "dotted quad" format)""" + + __slots__ = ['address'] + + def __init__(self, rdclass, rdtype, address): + super(A, self).__init__(rdclass, rdtype) + # check that it's OK + junk = dns.ipv4.inet_aton(address) + self.address = address + + def to_text(self, origin=None, relativize=True, **kw): + return self.address + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + address = tok.get_identifier() + tok.get_eol() + return cls(rdclass, rdtype, address) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + file.write(dns.ipv4.inet_aton(self.address)) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + address = dns.ipv4.inet_ntoa(wire[current : current + rdlen]) + return cls(rdclass, rdtype, address) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + sa = dns.ipv4.inet_aton(self.address) + oa = dns.ipv4.inet_aton(other.address) + return cmp(sa, oa) diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/AAAA.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/AAAA.py new file mode 100644 index 0000000000..2d812d39eb --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/AAAA.py @@ -0,0 +1,58 @@ +# 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.inet +import dns.rdata +import dns.tokenizer + +class AAAA(dns.rdata.Rdata): + """AAAA record. + + @ivar address: an IPv6 address + @type address: string (in the standard IPv6 format)""" + + __slots__ = ['address'] + + def __init__(self, rdclass, rdtype, address): + super(AAAA, self).__init__(rdclass, rdtype) + # check that it's OK + junk = dns.inet.inet_pton(dns.inet.AF_INET6, address) + self.address = address + + def to_text(self, origin=None, relativize=True, **kw): + return self.address + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + address = tok.get_identifier() + tok.get_eol() + return cls(rdclass, rdtype, address) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.address)) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + address = dns.inet.inet_ntop(dns.inet.AF_INET6, + wire[current : current + rdlen]) + return cls(rdclass, rdtype, address) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + sa = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) + oa = dns.inet.inet_pton(dns.inet.AF_INET6, other.address) + return cmp(sa, oa) diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/APL.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/APL.py new file mode 100644 index 0000000000..7412c02d30 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/APL.py @@ -0,0 +1,170 @@ +# 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.inet +import dns.rdata +import dns.tokenizer + +class APLItem(object): + """An APL list item. + + @ivar family: the address family (IANA address family registry) + @type family: int + @ivar negation: is this item negated? + @type negation: bool + @ivar address: the address + @type address: string + @ivar prefix: the prefix length + @type prefix: int + """ + + __slots__ = ['family', 'negation', 'address', 'prefix'] + + def __init__(self, family, negation, address, prefix): + self.family = family + self.negation = negation + self.address = address + self.prefix = prefix + + def __str__(self): + if self.negation: + return "!%d:%s/%s" % (self.family, self.address, self.prefix) + else: + return "%d:%s/%s" % (self.family, self.address, self.prefix) + + def to_wire(self, file): + if self.family == 1: + address = dns.inet.inet_pton(dns.inet.AF_INET, self.address) + elif self.family == 2: + address = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) + else: + address = self.address.decode('hex_codec') + # + # Truncate least significant zero bytes. + # + last = 0 + for i in xrange(len(address) - 1, -1, -1): + if address[i] != chr(0): + last = i + 1 + break + address = address[0 : last] + l = len(address) + assert l < 128 + if self.negation: + l |= 0x80 + header = struct.pack('!HBB', self.family, self.prefix, l) + file.write(header) + file.write(address) + +class APL(dns.rdata.Rdata): + """APL record. + + @ivar items: a list of APL items + @type items: list of APL_Item + @see: RFC 3123""" + + __slots__ = ['items'] + + def __init__(self, rdclass, rdtype, items): + super(APL, self).__init__(rdclass, rdtype) + self.items = items + + def to_text(self, origin=None, relativize=True, **kw): + return ' '.join(map(lambda x: str(x), self.items)) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + items = [] + while 1: + token = tok.get().unescape() + if token.is_eol_or_eof(): + break + item = token.value + if item[0] == '!': + negation = True + item = item[1:] + else: + negation = False + (family, rest) = item.split(':', 1) + family = int(family) + (address, prefix) = rest.split('/', 1) + prefix = int(prefix) + item = APLItem(family, negation, address, prefix) + items.append(item) + + return cls(rdclass, rdtype, items) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + for item in self.items: + item.to_wire(file) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + items = [] + while 1: + if rdlen < 4: + raise dns.exception.FormError + header = struct.unpack('!HBB', wire[current : current + 4]) + afdlen = header[2] + if afdlen > 127: + negation = True + afdlen -= 128 + else: + negation = False + current += 4 + rdlen -= 4 + if rdlen < afdlen: + raise dns.exception.FormError + address = wire[current : current + afdlen] + l = len(address) + if header[0] == 1: + if l < 4: + address += '\x00' * (4 - l) + address = dns.inet.inet_ntop(dns.inet.AF_INET, address) + elif header[0] == 2: + if l < 16: + address += '\x00' * (16 - l) + address = dns.inet.inet_ntop(dns.inet.AF_INET6, address) + else: + # + # This isn't really right according to the RFC, but it + # seems better than throwing an exception + # + address = address.encode('hex_codec') + current += afdlen + rdlen -= afdlen + item = APLItem(header[0], negation, address, header[1]) + items.append(item) + if rdlen == 0: + break + return cls(rdclass, rdtype, items) + + from_wire = classmethod(from_wire) + + 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/IN/DHCID.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/DHCID.py new file mode 100644 index 0000000000..2d35234bf0 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/DHCID.py @@ -0,0 +1,60 @@ +# Copyright (C) 2006, 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 + +class DHCID(dns.rdata.Rdata): + """DHCID record + + @ivar data: the data (the content of the RR is opaque as far as the + DNS is concerned) + @type data: string + @see: RFC 4701""" + + __slots__ = ['data'] + + def __init__(self, rdclass, rdtype, data): + super(DHCID, self).__init__(rdclass, rdtype) + self.data = data + + def to_text(self, origin=None, relativize=True, **kw): + return dns.rdata._base64ify(self.data) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + 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) + data = b64.decode('base64_codec') + 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): + data = wire[current : current + rdlen] + return cls(rdclass, rdtype, data) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + return cmp(self.data, other.data) diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/IPSECKEY.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/IPSECKEY.py new file mode 100644 index 0000000000..9ab08d881c --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/IPSECKEY.py @@ -0,0 +1,159 @@ +# Copyright (C) 2006, 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.inet +import dns.name + +class IPSECKEY(dns.rdata.Rdata): + """IPSECKEY record + + @ivar precedence: the precedence for this key data + @type precedence: int + @ivar gateway_type: the gateway type + @type gateway_type: int + @ivar algorithm: the algorithm to use + @type algorithm: int + @ivar gateway: the public key + @type gateway: None, IPv4 address, IPV6 address, or domain name + @ivar key: the public key + @type key: string + @see: RFC 4025""" + + __slots__ = ['precedence', 'gateway_type', 'algorithm', 'gateway', 'key'] + + def __init__(self, rdclass, rdtype, precedence, gateway_type, algorithm, + gateway, key): + super(IPSECKEY, self).__init__(rdclass, rdtype) + if gateway_type == 0: + if gateway != '.' and not gateway is None: + raise SyntaxError('invalid gateway for gateway type 0') + gateway = None + elif gateway_type == 1: + # check that it's OK + junk = dns.inet.inet_pton(dns.inet.AF_INET, gateway) + elif gateway_type == 2: + # check that it's OK + junk = dns.inet.inet_pton(dns.inet.AF_INET6, gateway) + elif gateway_type == 3: + pass + else: + raise SyntaxError('invalid IPSECKEY gateway type: %d' % gateway_type) + self.precedence = precedence + self.gateway_type = gateway_type + self.algorithm = algorithm + self.gateway = gateway + self.key = key + + def to_text(self, origin=None, relativize=True, **kw): + if self.gateway_type == 0: + gateway = '.' + elif self.gateway_type == 1: + gateway = self.gateway + elif self.gateway_type == 2: + gateway = self.gateway + elif self.gateway_type == 3: + gateway = str(self.gateway.choose_relativity(origin, relativize)) + else: + raise ValueError('invalid gateway type') + return '%d %d %d %s %s' % (self.precedence, self.gateway_type, + self.algorithm, gateway, + dns.rdata._base64ify(self.key)) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + precedence = tok.get_uint8() + gateway_type = tok.get_uint8() + algorithm = tok.get_uint8() + if gateway_type == 3: + gateway = tok.get_name().choose_relativity(origin, relativize) + else: + gateway = tok.get_string() + 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) + key = b64.decode('base64_codec') + return cls(rdclass, rdtype, precedence, gateway_type, algorithm, + gateway, key) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + header = struct.pack("!BBB", self.precedence, self.gateway_type, + self.algorithm) + file.write(header) + if self.gateway_type == 0: + pass + elif self.gateway_type == 1: + file.write(dns.inet.inet_pton(dns.inet.AF_INET, self.gateway)) + elif self.gateway_type == 2: + file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.gateway)) + elif self.gateway_type == 3: + self.gateway.to_wire(file, None, origin) + else: + raise ValueError('invalid gateway type') + file.write(self.key) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + if rdlen < 3: + raise dns.exception.FormError + header = struct.unpack('!BBB', wire[current : current + 3]) + gateway_type = header[1] + current += 3 + rdlen -= 3 + if gateway_type == 0: + gateway = None + elif gateway_type == 1: + gateway = dns.inet.inet_ntop(dns.inet.AF_INET, + wire[current : current + 4]) + current += 4 + rdlen -= 4 + elif gateway_type == 2: + gateway = dns.inet.inet_ntop(dns.inet.AF_INET6, + wire[current : current + 16]) + current += 16 + rdlen -= 16 + elif gateway_type == 3: + (gateway, cused) = dns.name.from_wire(wire[: current + rdlen], + current) + current += cused + rdlen -= cused + else: + raise dns.exception.FormError('invalid IPSECKEY gateway type') + key = wire[current : current + rdlen] + return cls(rdclass, rdtype, header[0], gateway_type, header[2], + gateway, key) + + 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/IN/KX.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/KX.py new file mode 100644 index 0000000000..4d8a3a7d6b --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/KX.py @@ -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 KX(dns.rdtypes.mxbase.UncompressedMX): + """KX record""" + pass diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NAPTR.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NAPTR.py new file mode 100644 index 0000000000..3a30d16d7b --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NAPTR.py @@ -0,0 +1,132 @@ +# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import struct + +import dns.exception +import dns.name +import dns.rdata + +def _write_string(file, s): + l = len(s) + assert l < 256 + byte = chr(l) + file.write(byte) + file.write(s) + +class NAPTR(dns.rdata.Rdata): + """NAPTR record + + @ivar order: order + @type order: int + @ivar preference: preference + @type preference: int + @ivar flags: flags + @type flags: string + @ivar service: service + @type service: string + @ivar regexp: regular expression + @type regexp: string + @ivar replacement: replacement name + @type replacement: dns.name.Name object + @see: RFC 3403""" + + __slots__ = ['order', 'preference', 'flags', 'service', 'regexp', + 'replacement'] + + def __init__(self, rdclass, rdtype, order, preference, flags, service, + regexp, replacement): + super(NAPTR, self).__init__(rdclass, rdtype) + self.order = order + self.preference = preference + self.flags = flags + self.service = service + self.regexp = regexp + self.replacement = replacement + + def to_text(self, origin=None, relativize=True, **kw): + replacement = self.replacement.choose_relativity(origin, relativize) + return '%d %d "%s" "%s" "%s" %s' % \ + (self.order, self.preference, + dns.rdata._escapify(self.flags), + dns.rdata._escapify(self.service), + dns.rdata._escapify(self.regexp), + self.replacement) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + order = tok.get_uint16() + preference = tok.get_uint16() + flags = tok.get_string() + service = tok.get_string() + regexp = tok.get_string() + replacement = tok.get_name() + replacement = replacement.choose_relativity(origin, relativize) + tok.get_eol() + return cls(rdclass, rdtype, order, preference, flags, service, + regexp, replacement) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + two_ints = struct.pack("!HH", self.order, self.preference) + file.write(two_ints) + _write_string(file, self.flags) + _write_string(file, self.service) + _write_string(file, self.regexp) + self.replacement.to_wire(file, compress, origin) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + (order, preference) = struct.unpack('!HH', wire[current : current + 4]) + current += 4 + rdlen -= 4 + strings = [] + for i in xrange(3): + l = ord(wire[current]) + current += 1 + rdlen -= 1 + if l > rdlen or rdlen < 0: + raise dns.exception.FormError + s = wire[current : current + l] + current += l + rdlen -= l + strings.append(s) + (replacement, cused) = dns.name.from_wire(wire[: current + rdlen], + current) + if cused != rdlen: + raise dns.exception.FormError + if not origin is None: + replacement = replacement.relativize(origin) + return cls(rdclass, rdtype, order, preference, strings[0], strings[1], + strings[2], replacement) + + from_wire = classmethod(from_wire) + + def choose_relativity(self, origin = None, relativize = True): + self.replacement = self.replacement.choose_relativity(origin, + relativize) + + def _cmp(self, other): + sp = struct.pack("!HH", self.order, self.preference) + op = struct.pack("!HH", other.order, other.preference) + v = cmp(sp, op) + if v == 0: + v = cmp(self.flags, other.flags) + if v == 0: + v = cmp(self.service, other.service) + if v == 0: + v = cmp(self.regexp, other.regexp) + if v == 0: + v = cmp(self.replacement, other.replacement) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NSAP.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NSAP.py new file mode 100644 index 0000000000..22b9131ccf --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NSAP.py @@ -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. + +import dns.exception +import dns.rdata +import dns.tokenizer + +class NSAP(dns.rdata.Rdata): + """NSAP record. + + @ivar address: a NASP + @type address: string + @see: RFC 1706""" + + __slots__ = ['address'] + + def __init__(self, rdclass, rdtype, address): + super(NSAP, self).__init__(rdclass, rdtype) + self.address = address + + def to_text(self, origin=None, relativize=True, **kw): + return "0x%s" % self.address.encode('hex_codec') + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + address = tok.get_string() + t = tok.get_eol() + if address[0:2] != '0x': + raise dns.exception.SyntaxError('string does not start with 0x') + address = address[2:].replace('.', '') + if len(address) % 2 != 0: + raise dns.exception.SyntaxError('hexstring has odd length') + address = address.decode('hex_codec') + return cls(rdclass, rdtype, address) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + file.write(self.address) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + address = wire[current : current + rdlen] + return cls(rdclass, rdtype, address) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + return cmp(self.address, other.address) diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NSAP_PTR.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NSAP_PTR.py new file mode 100644 index 0000000000..6f591f4ec0 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/NSAP_PTR.py @@ -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 NSAP_PTR(dns.rdtypes.nsbase.UncompressedNS): + """NSAP-PTR record""" + pass diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/PX.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/PX.py new file mode 100644 index 0000000000..4718944ff4 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/PX.py @@ -0,0 +1,97 @@ +# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import struct + +import dns.exception +import dns.rdata +import dns.name + +class PX(dns.rdata.Rdata): + """PX record. + + @ivar preference: the preference value + @type preference: int + @ivar map822: the map822 name + @type map822: dns.name.Name object + @ivar mapx400: the mapx400 name + @type mapx400: dns.name.Name object + @see: RFC 2163""" + + __slots__ = ['preference', 'map822', 'mapx400'] + + def __init__(self, rdclass, rdtype, preference, map822, mapx400): + super(PX, self).__init__(rdclass, rdtype) + self.preference = preference + self.map822 = map822 + self.mapx400 = mapx400 + + def to_text(self, origin=None, relativize=True, **kw): + map822 = self.map822.choose_relativity(origin, relativize) + mapx400 = self.mapx400.choose_relativity(origin, relativize) + return '%d %s %s' % (self.preference, map822, mapx400) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + preference = tok.get_uint16() + map822 = tok.get_name() + map822 = map822.choose_relativity(origin, relativize) + mapx400 = tok.get_name(None) + mapx400 = mapx400.choose_relativity(origin, relativize) + tok.get_eol() + return cls(rdclass, rdtype, preference, map822, mapx400) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + pref = struct.pack("!H", self.preference) + file.write(pref) + self.map822.to_wire(file, None, origin) + self.mapx400.to_wire(file, None, origin) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + (preference, ) = struct.unpack('!H', wire[current : current + 2]) + current += 2 + rdlen -= 2 + (map822, cused) = dns.name.from_wire(wire[: current + rdlen], + current) + if cused > rdlen: + raise dns.exception.FormError + current += cused + rdlen -= cused + if not origin is None: + map822 = map822.relativize(origin) + (mapx400, cused) = dns.name.from_wire(wire[: current + rdlen], + current) + if cused != rdlen: + raise dns.exception.FormError + if not origin is None: + mapx400 = mapx400.relativize(origin) + return cls(rdclass, rdtype, preference, map822, mapx400) + + from_wire = classmethod(from_wire) + + def choose_relativity(self, origin = None, relativize = True): + self.map822 = self.map822.choose_relativity(origin, relativize) + self.mapx400 = self.mapx400.choose_relativity(origin, relativize) + + def _cmp(self, other): + sp = struct.pack("!H", self.preference) + op = struct.pack("!H", other.preference) + v = cmp(sp, op) + if v == 0: + v = cmp(self.map822, other.map822) + if v == 0: + v = cmp(self.mapx400, other.mapx400) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/SRV.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/SRV.py new file mode 100644 index 0000000000..c9c5823381 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/SRV.py @@ -0,0 +1,89 @@ +# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import struct + +import dns.exception +import dns.rdata +import dns.name + +class SRV(dns.rdata.Rdata): + """SRV record + + @ivar priority: the priority + @type priority: int + @ivar weight: the weight + @type weight: int + @ivar port: the port of the service + @type port: int + @ivar target: the target host + @type target: dns.name.Name object + @see: RFC 2782""" + + __slots__ = ['priority', 'weight', 'port', 'target'] + + def __init__(self, rdclass, rdtype, priority, weight, port, target): + super(SRV, self).__init__(rdclass, rdtype) + self.priority = priority + self.weight = weight + self.port = port + self.target = target + + def to_text(self, origin=None, relativize=True, **kw): + target = self.target.choose_relativity(origin, relativize) + return '%d %d %d %s' % (self.priority, self.weight, self.port, + target) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + priority = tok.get_uint16() + weight = tok.get_uint16() + port = tok.get_uint16() + target = tok.get_name(None) + target = target.choose_relativity(origin, relativize) + tok.get_eol() + return cls(rdclass, rdtype, priority, weight, port, target) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + three_ints = struct.pack("!HHH", self.priority, self.weight, self.port) + file.write(three_ints) + self.target.to_wire(file, compress, origin) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + (priority, weight, port) = struct.unpack('!HHH', + wire[current : current + 6]) + current += 6 + rdlen -= 6 + (target, cused) = dns.name.from_wire(wire[: current + rdlen], + current) + if cused != rdlen: + raise dns.exception.FormError + if not origin is None: + target = target.relativize(origin) + return cls(rdclass, rdtype, priority, weight, port, target) + + from_wire = classmethod(from_wire) + + def choose_relativity(self, origin = None, relativize = True): + self.target = self.target.choose_relativity(origin, relativize) + + def _cmp(self, other): + sp = struct.pack("!HHH", self.priority, self.weight, self.port) + op = struct.pack("!HHH", other.priority, other.weight, other.port) + v = cmp(sp, op) + if v == 0: + v = cmp(self.target, other.target) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/WKS.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/WKS.py new file mode 100644 index 0000000000..85aafb3d23 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/WKS.py @@ -0,0 +1,113 @@ +# 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 socket +import struct + +import dns.ipv4 +import dns.rdata + +_proto_tcp = socket.getprotobyname('tcp') +_proto_udp = socket.getprotobyname('udp') + +class WKS(dns.rdata.Rdata): + """WKS record + + @ivar address: the address + @type address: string + @ivar protocol: the protocol + @type protocol: int + @ivar bitmap: the bitmap + @type bitmap: string + @see: RFC 1035""" + + __slots__ = ['address', 'protocol', 'bitmap'] + + def __init__(self, rdclass, rdtype, address, protocol, bitmap): + super(WKS, self).__init__(rdclass, rdtype) + self.address = address + self.protocol = protocol + self.bitmap = bitmap + + def to_text(self, origin=None, relativize=True, **kw): + 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(str(i * 8 + j)) + text = ' '.join(bits) + return '%s %d %s' % (self.address, self.protocol, text) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + address = tok.get_string() + protocol = tok.get_string() + if protocol.isdigit(): + protocol = int(protocol) + else: + protocol = socket.getprotobyname(protocol) + bitmap = [] + while 1: + token = tok.get().unescape() + if token.is_eol_or_eof(): + break + if token.value.isdigit(): + serv = int(token.value) + else: + if protocol != _proto_udp and protocol != _proto_tcp: + raise NotImplementedError("protocol must be TCP or UDP") + if protocol == _proto_udp: + protocol_text = "udp" + else: + protocol_text = "tcp" + serv = socket.getservbyname(token.value, protocol_text) + i = serv // 8 + l = len(bitmap) + if l < i + 1: + for j in xrange(l, i + 1): + bitmap.append('\x00') + bitmap[i] = chr(ord(bitmap[i]) | (0x80 >> (serv % 8))) + bitmap = dns.rdata._truncate_bitmap(bitmap) + return cls(rdclass, rdtype, address, protocol, bitmap) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + file.write(dns.ipv4.inet_aton(self.address)) + protocol = struct.pack('!B', self.protocol) + file.write(protocol) + file.write(self.bitmap) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + address = dns.ipv4.inet_ntoa(wire[current : current + 4]) + protocol, = struct.unpack('!B', wire[current + 4 : current + 5]) + current += 5 + rdlen -= 5 + bitmap = wire[current : current + rdlen] + return cls(rdclass, rdtype, address, protocol, bitmap) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + sa = dns.ipv4.inet_aton(self.address) + oa = dns.ipv4.inet_aton(other.address) + v = cmp(sa, oa) + if v == 0: + sp = struct.pack('!B', self.protocol) + op = struct.pack('!B', other.protocol) + v = cmp(sp, op) + if v == 0: + v = cmp(self.bitmap, other.bitmap) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/__init__.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/__init__.py new file mode 100644 index 0000000000..ab931296ec --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/IN/__init__.py @@ -0,0 +1,30 @@ +# 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. + +"""Class IN rdata type classes.""" + +__all__ = [ + 'A', + 'AAAA', + 'APL', + 'DHCID', + 'KX', + 'NAPTR', + 'NSAP', + 'NSAP_PTR', + 'PX', + 'SRV', + 'WKS', +] diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/__init__.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/__init__.py new file mode 100644 index 0000000000..13282be73a --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/__init__.py @@ -0,0 +1,25 @@ +# 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 rdata type classes""" + +__all__ = [ + 'ANY', + 'IN', + 'mxbase', + 'nsbase', + 'sigbase', + 'keybase', +] diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/dsbase.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/dsbase.py new file mode 100644 index 0000000000..aa46403a5f --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/dsbase.py @@ -0,0 +1,92 @@ +# 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 struct + +import dns.rdata +import dns.rdatatype + +class DSBase(dns.rdata.Rdata): + """Base class for rdata that is like a DS record + + @ivar key_tag: the key tag + @type key_tag: int + @ivar algorithm: the algorithm + @type algorithm: int + @ivar digest_type: the digest type + @type digest_type: int + @ivar digest: the digest + @type digest: int + @see: draft-ietf-dnsext-delegation-signer-14.txt""" + + __slots__ = ['key_tag', 'algorithm', 'digest_type', 'digest'] + + def __init__(self, rdclass, rdtype, key_tag, algorithm, digest_type, + digest): + super(DSBase, self).__init__(rdclass, rdtype) + self.key_tag = key_tag + self.algorithm = algorithm + self.digest_type = digest_type + self.digest = digest + + def to_text(self, origin=None, relativize=True, **kw): + return '%d %d %d %s' % (self.key_tag, self.algorithm, + self.digest_type, + dns.rdata._hexify(self.digest, + chunksize=128)) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + key_tag = tok.get_uint16() + algorithm = tok.get_uint8() + digest_type = tok.get_uint8() + 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) + digest = ''.join(chunks) + digest = digest.decode('hex_codec') + return cls(rdclass, rdtype, key_tag, algorithm, digest_type, + digest) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + header = struct.pack("!HBB", self.key_tag, self.algorithm, + self.digest_type) + file.write(header) + file.write(self.digest) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + header = struct.unpack("!HBB", wire[current : current + 4]) + current += 4 + rdlen -= 4 + digest = wire[current : current + rdlen] + return cls(rdclass, rdtype, header[0], header[1], header[2], digest) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + hs = struct.pack("!HBB", self.key_tag, self.algorithm, + self.digest_type) + ho = struct.pack("!HBB", other.key_tag, other.algorithm, + other.digest_type) + v = cmp(hs, ho) + if v == 0: + v = cmp(self.digest, other.digest) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/keybase.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/keybase.py new file mode 100644 index 0000000000..75c9272670 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/keybase.py @@ -0,0 +1,149 @@ +# 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 struct + +import dns.exception +import dns.dnssec +import dns.rdata + +_flags_from_text = { + 'NOCONF': (0x4000, 0xC000), + 'NOAUTH': (0x8000, 0xC000), + 'NOKEY': (0xC000, 0xC000), + 'FLAG2': (0x2000, 0x2000), + 'EXTEND': (0x1000, 0x1000), + 'FLAG4': (0x0800, 0x0800), + 'FLAG5': (0x0400, 0x0400), + 'USER': (0x0000, 0x0300), + 'ZONE': (0x0100, 0x0300), + 'HOST': (0x0200, 0x0300), + 'NTYP3': (0x0300, 0x0300), + 'FLAG8': (0x0080, 0x0080), + 'FLAG9': (0x0040, 0x0040), + 'FLAG10': (0x0020, 0x0020), + 'FLAG11': (0x0010, 0x0010), + 'SIG0': (0x0000, 0x000f), + 'SIG1': (0x0001, 0x000f), + 'SIG2': (0x0002, 0x000f), + 'SIG3': (0x0003, 0x000f), + 'SIG4': (0x0004, 0x000f), + 'SIG5': (0x0005, 0x000f), + 'SIG6': (0x0006, 0x000f), + 'SIG7': (0x0007, 0x000f), + 'SIG8': (0x0008, 0x000f), + 'SIG9': (0x0009, 0x000f), + 'SIG10': (0x000a, 0x000f), + 'SIG11': (0x000b, 0x000f), + 'SIG12': (0x000c, 0x000f), + 'SIG13': (0x000d, 0x000f), + 'SIG14': (0x000e, 0x000f), + 'SIG15': (0x000f, 0x000f), + } + +_protocol_from_text = { + 'NONE' : 0, + 'TLS' : 1, + 'EMAIL' : 2, + 'DNSSEC' : 3, + 'IPSEC' : 4, + 'ALL' : 255, + } + +class KEYBase(dns.rdata.Rdata): + """KEY-like record base + + @ivar flags: the key flags + @type flags: int + @ivar protocol: the protocol for which this key may be used + @type protocol: int + @ivar algorithm: the algorithm used for the key + @type algorithm: int + @ivar key: the public key + @type key: string""" + + __slots__ = ['flags', 'protocol', 'algorithm', 'key'] + + def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): + super(KEYBase, self).__init__(rdclass, rdtype) + self.flags = flags + self.protocol = protocol + self.algorithm = algorithm + self.key = key + + def to_text(self, origin=None, relativize=True, **kw): + return '%d %d %d %s' % (self.flags, self.protocol, self.algorithm, + dns.rdata._base64ify(self.key)) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + flags = tok.get_string() + if flags.isdigit(): + flags = int(flags) + else: + flag_names = flags.split('|') + flags = 0 + for flag in flag_names: + v = _flags_from_text.get(flag) + if v is None: + raise dns.exception.SyntaxError('unknown flag %s' % flag) + flags &= ~v[1] + flags |= v[0] + protocol = tok.get_string() + if protocol.isdigit(): + protocol = int(protocol) + else: + protocol = _protocol_from_text.get(protocol) + if protocol is None: + raise dns.exception.SyntaxError('unknown protocol %s' % protocol) + + algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) + chunks = [] + while 1: + t = tok.get().unescape() + if t.is_eol_or_eof(): + break + if not t.is_identifier(): + raise dns.exception.SyntaxError + chunks.append(t.value) + b64 = ''.join(chunks) + key = b64.decode('base64_codec') + return cls(rdclass, rdtype, flags, protocol, algorithm, key) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + header = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) + file.write(header) + file.write(self.key) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + if rdlen < 4: + raise dns.exception.FormError + header = struct.unpack('!HBB', wire[current : current + 4]) + current += 4 + rdlen -= 4 + key = wire[current : current + rdlen] + return cls(rdclass, rdtype, header[0], header[1], header[2], + key) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + hs = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) + ho = struct.pack("!HBB", other.flags, other.protocol, other.algorithm) + v = cmp(hs, ho) + if v == 0: + v = cmp(self.key, other.key) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/mxbase.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/mxbase.py new file mode 100644 index 0000000000..5e3515bec4 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/mxbase.py @@ -0,0 +1,105 @@ +# 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. + +"""MX-like base classes.""" + +import cStringIO +import struct + +import dns.exception +import dns.rdata +import dns.name + +class MXBase(dns.rdata.Rdata): + """Base class for rdata that is like an MX record. + + @ivar preference: the preference value + @type preference: int + @ivar exchange: the exchange name + @type exchange: dns.name.Name object""" + + __slots__ = ['preference', 'exchange'] + + def __init__(self, rdclass, rdtype, preference, exchange): + super(MXBase, self).__init__(rdclass, rdtype) + self.preference = preference + self.exchange = exchange + + def to_text(self, origin=None, relativize=True, **kw): + exchange = self.exchange.choose_relativity(origin, relativize) + return '%d %s' % (self.preference, exchange) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + preference = tok.get_uint16() + exchange = tok.get_name() + exchange = exchange.choose_relativity(origin, relativize) + tok.get_eol() + return cls(rdclass, rdtype, preference, exchange) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + pref = struct.pack("!H", self.preference) + file.write(pref) + self.exchange.to_wire(file, compress, origin) + + def to_digestable(self, origin = None): + return struct.pack("!H", self.preference) + \ + self.exchange.to_digestable(origin) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + (preference, ) = struct.unpack('!H', wire[current : current + 2]) + current += 2 + rdlen -= 2 + (exchange, cused) = dns.name.from_wire(wire[: current + rdlen], + current) + if cused != rdlen: + raise dns.exception.FormError + if not origin is None: + exchange = exchange.relativize(origin) + return cls(rdclass, rdtype, preference, exchange) + + from_wire = classmethod(from_wire) + + def choose_relativity(self, origin = None, relativize = True): + self.exchange = self.exchange.choose_relativity(origin, relativize) + + def _cmp(self, other): + sp = struct.pack("!H", self.preference) + op = struct.pack("!H", other.preference) + v = cmp(sp, op) + if v == 0: + v = cmp(self.exchange, other.exchange) + return v + +class UncompressedMX(MXBase): + """Base class for rdata that is like an MX record, but whose name + is not compressed when converted to DNS wire format, and whose + digestable form is not downcased.""" + + def to_wire(self, file, compress = None, origin = None): + super(UncompressedMX, self).to_wire(file, None, origin) + + def to_digestable(self, origin = None): + f = cStringIO.StringIO() + self.to_wire(f, None, origin) + return f.getvalue() + +class UncompressedDowncasingMX(MXBase): + """Base class for rdata that is like an MX record, but whose name + is not compressed when convert to DNS wire format.""" + + def to_wire(self, file, compress = None, origin = None): + super(UncompressedDowncasingMX, self).to_wire(file, None, origin) diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/nsbase.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/nsbase.py new file mode 100644 index 0000000000..7cdb2a0289 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/nsbase.py @@ -0,0 +1,82 @@ +# 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. + +"""NS-like base classes.""" + +import cStringIO + +import dns.exception +import dns.rdata +import dns.name + +class NSBase(dns.rdata.Rdata): + """Base class for rdata that is like an NS record. + + @ivar target: the target name of the rdata + @type target: dns.name.Name object""" + + __slots__ = ['target'] + + def __init__(self, rdclass, rdtype, target): + super(NSBase, self).__init__(rdclass, rdtype) + self.target = target + + def to_text(self, origin=None, relativize=True, **kw): + target = self.target.choose_relativity(origin, relativize) + return str(target) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + target = tok.get_name() + target = target.choose_relativity(origin, relativize) + tok.get_eol() + return cls(rdclass, rdtype, target) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + self.target.to_wire(file, compress, origin) + + def to_digestable(self, origin = None): + return self.target.to_digestable(origin) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + (target, cused) = dns.name.from_wire(wire[: current + rdlen], + current) + if cused != rdlen: + raise dns.exception.FormError + if not origin is None: + target = target.relativize(origin) + return cls(rdclass, rdtype, target) + + from_wire = classmethod(from_wire) + + def choose_relativity(self, origin = None, relativize = True): + self.target = self.target.choose_relativity(origin, relativize) + + def _cmp(self, other): + return cmp(self.target, other.target) + +class UncompressedNS(NSBase): + """Base class for rdata that is like an NS record, but whose name + is not compressed when convert to DNS wire format, and whose + digestable form is not downcased.""" + + def to_wire(self, file, compress = None, origin = None): + super(UncompressedNS, self).to_wire(file, None, origin) + + def to_digestable(self, origin = None): + f = cStringIO.StringIO() + self.to_wire(f, None, origin) + return f.getvalue() diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/sigbase.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/sigbase.py new file mode 100644 index 0000000000..ccb6dd69ae --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/sigbase.py @@ -0,0 +1,168 @@ +# 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 calendar +import struct +import time + +import dns.dnssec +import dns.exception +import dns.rdata +import dns.rdatatype + +class BadSigTime(dns.exception.DNSException): + """Raised when a SIG or RRSIG RR's time cannot be parsed.""" + pass + +def sigtime_to_posixtime(what): + if len(what) != 14: + raise BadSigTime + year = int(what[0:4]) + month = int(what[4:6]) + day = int(what[6:8]) + hour = int(what[8:10]) + minute = int(what[10:12]) + second = int(what[12:14]) + return calendar.timegm((year, month, day, hour, minute, second, + 0, 0, 0)) + +def posixtime_to_sigtime(what): + return time.strftime('%Y%m%d%H%M%S', time.gmtime(what)) + +class SIGBase(dns.rdata.Rdata): + """SIG-like record base + + @ivar type_covered: the rdata type this signature covers + @type type_covered: int + @ivar algorithm: the algorithm used for the sig + @type algorithm: int + @ivar labels: number of labels + @type labels: int + @ivar original_ttl: the original TTL + @type original_ttl: long + @ivar expiration: signature expiration time + @type expiration: long + @ivar inception: signature inception time + @type inception: long + @ivar key_tag: the key tag + @type key_tag: int + @ivar signer: the signer + @type signer: dns.name.Name object + @ivar signature: the signature + @type signature: string""" + + __slots__ = ['type_covered', 'algorithm', 'labels', 'original_ttl', + 'expiration', 'inception', 'key_tag', 'signer', + 'signature'] + + def __init__(self, rdclass, rdtype, type_covered, algorithm, labels, + original_ttl, expiration, inception, key_tag, signer, + signature): + super(SIGBase, self).__init__(rdclass, rdtype) + self.type_covered = type_covered + self.algorithm = algorithm + self.labels = labels + self.original_ttl = original_ttl + self.expiration = expiration + self.inception = inception + self.key_tag = key_tag + self.signer = signer + self.signature = signature + + def covers(self): + return self.type_covered + + def to_text(self, origin=None, relativize=True, **kw): + return '%s %d %d %d %s %s %d %s %s' % ( + dns.rdatatype.to_text(self.type_covered), + self.algorithm, + self.labels, + self.original_ttl, + posixtime_to_sigtime(self.expiration), + posixtime_to_sigtime(self.inception), + self.key_tag, + self.signer, + dns.rdata._base64ify(self.signature) + ) + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + type_covered = dns.rdatatype.from_text(tok.get_string()) + algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) + labels = tok.get_int() + original_ttl = tok.get_ttl() + expiration = sigtime_to_posixtime(tok.get_string()) + inception = sigtime_to_posixtime(tok.get_string()) + key_tag = tok.get_int() + signer = tok.get_name() + signer = signer.choose_relativity(origin, relativize) + 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) + signature = b64.decode('base64_codec') + return cls(rdclass, rdtype, type_covered, algorithm, labels, + original_ttl, expiration, inception, key_tag, signer, + signature) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + header = struct.pack('!HBBIIIH', self.type_covered, + self.algorithm, self.labels, + self.original_ttl, self.expiration, + self.inception, self.key_tag) + file.write(header) + self.signer.to_wire(file, None, origin) + file.write(self.signature) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + header = struct.unpack('!HBBIIIH', wire[current : current + 18]) + current += 18 + rdlen -= 18 + (signer, cused) = dns.name.from_wire(wire[: current + rdlen], current) + current += cused + rdlen -= cused + if not origin is None: + signer = signer.relativize(origin) + signature = wire[current : current + rdlen] + return cls(rdclass, rdtype, header[0], header[1], header[2], + header[3], header[4], header[5], header[6], signer, + signature) + + from_wire = classmethod(from_wire) + + def choose_relativity(self, origin = None, relativize = True): + self.signer = self.signer.choose_relativity(origin, relativize) + + def _cmp(self, other): + hs = struct.pack('!HBBIIIH', self.type_covered, + self.algorithm, self.labels, + self.original_ttl, self.expiration, + self.inception, self.key_tag) + ho = struct.pack('!HBBIIIH', other.type_covered, + other.algorithm, other.labels, + other.original_ttl, other.expiration, + other.inception, other.key_tag) + v = cmp(hs, ho) + if v == 0: + v = cmp(self.signer, other.signer) + if v == 0: + v = cmp(self.signature, other.signature) + return v diff --git a/source4/scripting/python/samba_external/dnspython/dns/rdtypes/txtbase.py b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/txtbase.py new file mode 100644 index 0000000000..43db2a48c0 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rdtypes/txtbase.py @@ -0,0 +1,87 @@ +# Copyright (C) 2006, 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. + +"""TXT-like base class.""" + +import dns.exception +import dns.rdata +import dns.tokenizer + +class TXTBase(dns.rdata.Rdata): + """Base class for rdata that is like a TXT record + + @ivar strings: the text strings + @type strings: list of string + @see: RFC 1035""" + + __slots__ = ['strings'] + + def __init__(self, rdclass, rdtype, strings): + super(TXTBase, self).__init__(rdclass, rdtype) + if isinstance(strings, str): + strings = [ strings ] + self.strings = strings[:] + + def to_text(self, origin=None, relativize=True, **kw): + txt = '' + prefix = '' + for s in self.strings: + txt += '%s"%s"' % (prefix, dns.rdata._escapify(s)) + prefix = ' ' + return txt + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + strings = [] + while 1: + token = tok.get().unescape() + if token.is_eol_or_eof(): + break + if not (token.is_quoted_string() or token.is_identifier()): + raise dns.exception.SyntaxError("expected a string") + if len(token.value) > 255: + raise dns.exception.SyntaxError("string too long") + strings.append(token.value) + if len(strings) == 0: + raise dns.exception.UnexpectedEnd + return cls(rdclass, rdtype, strings) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + for s in self.strings: + l = len(s) + assert l < 256 + byte = chr(l) + file.write(byte) + file.write(s) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + strings = [] + while rdlen > 0: + l = ord(wire[current]) + current += 1 + rdlen -= 1 + if l > rdlen: + raise dns.exception.FormError + s = wire[current : current + l] + current += l + rdlen -= l + strings.append(s) + return cls(rdclass, rdtype, strings) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + return cmp(self.strings, other.strings) diff --git a/source4/scripting/python/samba_external/dnspython/dns/renderer.py b/source4/scripting/python/samba_external/dnspython/dns/renderer.py new file mode 100644 index 0000000000..bb0218ac30 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/renderer.py @@ -0,0 +1,324 @@ +# 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. + +"""Help for building DNS wire format messages""" + +import cStringIO +import struct +import random +import time + +import dns.exception +import dns.tsig + +QUESTION = 0 +ANSWER = 1 +AUTHORITY = 2 +ADDITIONAL = 3 + +class Renderer(object): + """Helper class for building DNS wire-format messages. + + Most applications can use the higher-level L{dns.message.Message} + class and its to_wire() method to generate wire-format messages. + This class is for those applications which need finer control + over the generation of messages. + + Typical use:: + + r = dns.renderer.Renderer(id=1, flags=0x80, max_size=512) + r.add_question(qname, qtype, qclass) + r.add_rrset(dns.renderer.ANSWER, rrset_1) + r.add_rrset(dns.renderer.ANSWER, rrset_2) + r.add_rrset(dns.renderer.AUTHORITY, ns_rrset) + r.add_edns(0, 0, 4096) + r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_1) + r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_2) + r.write_header() + r.add_tsig(keyname, secret, 300, 1, 0, '', request_mac) + wire = r.get_wire() + + @ivar output: where rendering is written + @type output: cStringIO.StringIO object + @ivar id: the message id + @type id: int + @ivar flags: the message flags + @type flags: int + @ivar max_size: the maximum size of the message + @type max_size: int + @ivar origin: the origin to use when rendering relative names + @type origin: dns.name.Name object + @ivar compress: the compression table + @type compress: dict + @ivar section: the section currently being rendered + @type section: int (dns.renderer.QUESTION, dns.renderer.ANSWER, + dns.renderer.AUTHORITY, or dns.renderer.ADDITIONAL) + @ivar counts: list of the number of RRs in each section + @type counts: int list of length 4 + @ivar mac: the MAC of the rendered message (if TSIG was used) + @type mac: string + """ + + def __init__(self, id=None, flags=0, max_size=65535, origin=None): + """Initialize a new renderer. + + @param id: the message id + @type id: int + @param flags: the DNS message flags + @type flags: int + @param max_size: the maximum message size; the default is 65535. + If rendering results in a message greater than I{max_size}, + then L{dns.exception.TooBig} will be raised. + @type max_size: int + @param origin: the origin to use when rendering relative names + @type origin: dns.name.Namem or None. + """ + + self.output = cStringIO.StringIO() + if id is None: + self.id = random.randint(0, 65535) + else: + self.id = id + self.flags = flags + self.max_size = max_size + self.origin = origin + self.compress = {} + self.section = QUESTION + self.counts = [0, 0, 0, 0] + self.output.write('\x00' * 12) + self.mac = '' + + def _rollback(self, where): + """Truncate the output buffer at offset I{where}, and remove any + compression table entries that pointed beyond the truncation + point. + + @param where: the offset + @type where: int + """ + + self.output.seek(where) + self.output.truncate() + keys_to_delete = [] + for k, v in self.compress.iteritems(): + if v >= where: + keys_to_delete.append(k) + for k in keys_to_delete: + del self.compress[k] + + def _set_section(self, section): + """Set the renderer's current section. + + Sections must be rendered order: QUESTION, ANSWER, AUTHORITY, + ADDITIONAL. Sections may be empty. + + @param section: the section + @type section: int + @raises dns.exception.FormError: an attempt was made to set + a section value less than the current section. + """ + + if self.section != section: + if self.section > section: + raise dns.exception.FormError + self.section = section + + def add_question(self, qname, rdtype, rdclass=dns.rdataclass.IN): + """Add a question to the message. + + @param qname: the question name + @type qname: dns.name.Name + @param rdtype: the question rdata type + @type rdtype: int + @param rdclass: the question rdata class + @type rdclass: int + """ + + self._set_section(QUESTION) + before = self.output.tell() + qname.to_wire(self.output, self.compress, self.origin) + self.output.write(struct.pack("!HH", rdtype, rdclass)) + after = self.output.tell() + if after >= self.max_size: + self._rollback(before) + raise dns.exception.TooBig + self.counts[QUESTION] += 1 + + def add_rrset(self, section, rrset, **kw): + """Add the rrset to the specified section. + + Any keyword arguments are passed on to the rdataset's to_wire() + routine. + + @param section: the section + @type section: int + @param rrset: the rrset + @type rrset: dns.rrset.RRset object + """ + + self._set_section(section) + before = self.output.tell() + n = rrset.to_wire(self.output, self.compress, self.origin, **kw) + after = self.output.tell() + if after >= self.max_size: + self._rollback(before) + raise dns.exception.TooBig + self.counts[section] += n + + def add_rdataset(self, section, name, rdataset, **kw): + """Add the rdataset to the specified section, using the specified + name as the owner name. + + Any keyword arguments are passed on to the rdataset's to_wire() + routine. + + @param section: the section + @type section: int + @param name: the owner name + @type name: dns.name.Name object + @param rdataset: the rdataset + @type rdataset: dns.rdataset.Rdataset object + """ + + self._set_section(section) + before = self.output.tell() + n = rdataset.to_wire(name, self.output, self.compress, self.origin, + **kw) + after = self.output.tell() + if after >= self.max_size: + self._rollback(before) + raise dns.exception.TooBig + self.counts[section] += n + + def add_edns(self, edns, ednsflags, payload, options=None): + """Add an EDNS OPT record to the message. + + @param edns: The EDNS level to use. + @type edns: int + @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 options: The EDNS options list + @type options: list of dns.edns.Option instances + @see: RFC 2671 + """ + + # make sure the EDNS version in ednsflags agrees with edns + ednsflags &= 0xFF00FFFFL + ednsflags |= (edns << 16) + self._set_section(ADDITIONAL) + before = self.output.tell() + self.output.write(struct.pack('!BHHIH', 0, dns.rdatatype.OPT, payload, + ednsflags, 0)) + if not options is None: + lstart = self.output.tell() + for opt in options: + stuff = struct.pack("!HH", opt.otype, 0) + self.output.write(stuff) + start = self.output.tell() + opt.to_wire(self.output) + end = self.output.tell() + assert end - start < 65536 + self.output.seek(start - 2) + stuff = struct.pack("!H", end - start) + self.output.write(stuff) + self.output.seek(0, 2) + lend = self.output.tell() + assert lend - lstart < 65536 + self.output.seek(lstart - 2) + stuff = struct.pack("!H", lend - lstart) + self.output.write(stuff) + self.output.seek(0, 2) + after = self.output.tell() + if after >= self.max_size: + self._rollback(before) + raise dns.exception.TooBig + self.counts[ADDITIONAL] += 1 + + def add_tsig(self, keyname, secret, fudge, id, tsig_error, other_data, + request_mac, algorithm=dns.tsig.default_algorithm): + """Add a TSIG signature to the message. + + @param keyname: the TSIG key name + @type keyname: dns.name.Name object + @param secret: the secret to use + @type secret: string + @param fudge: TSIG time fudge + @type fudge: int + @param id: the message id to encode in the tsig signature + @type 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 request_mac: This message is a response to the request which + had the specified MAC. + @param algorithm: the TSIG algorithm to use + @type request_mac: string + """ + + self._set_section(ADDITIONAL) + before = self.output.tell() + s = self.output.getvalue() + (tsig_rdata, self.mac, ctx) = dns.tsig.sign(s, + keyname, + secret, + int(time.time()), + fudge, + id, + tsig_error, + other_data, + request_mac, + algorithm=algorithm) + keyname.to_wire(self.output, self.compress, self.origin) + self.output.write(struct.pack('!HHIH', dns.rdatatype.TSIG, + dns.rdataclass.ANY, 0, 0)) + rdata_start = self.output.tell() + self.output.write(tsig_rdata) + after = self.output.tell() + assert after - rdata_start < 65536 + if after >= self.max_size: + self._rollback(before) + raise dns.exception.TooBig + self.output.seek(rdata_start - 2) + self.output.write(struct.pack('!H', after - rdata_start)) + self.counts[ADDITIONAL] += 1 + self.output.seek(10) + self.output.write(struct.pack('!H', self.counts[ADDITIONAL])) + self.output.seek(0, 2) + + def write_header(self): + """Write the DNS message header. + + Writing the DNS message header is done asfter all sections + have been rendered, but before the optional TSIG signature + is added. + """ + + self.output.seek(0) + self.output.write(struct.pack('!HHHHHH', self.id, self.flags, + self.counts[0], self.counts[1], + self.counts[2], self.counts[3])) + self.output.seek(0, 2) + + def get_wire(self): + """Return the wire format message. + + @rtype: string + """ + + return self.output.getvalue() diff --git a/source4/scripting/python/samba_external/dnspython/dns/resolver.py b/source4/scripting/python/samba_external/dnspython/dns/resolver.py new file mode 100644 index 0000000000..372d7d8361 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/resolver.py @@ -0,0 +1,761 @@ +# 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 stub resolver. + +@var default_resolver: The default resolver object +@type default_resolver: dns.resolver.Resolver object""" + +import socket +import sys +import time + +import dns.exception +import dns.message +import dns.name +import dns.query +import dns.rcode +import dns.rdataclass +import dns.rdatatype + +if sys.platform == 'win32': + import _winreg + +class NXDOMAIN(dns.exception.DNSException): + """The query name does not exist.""" + pass + +# The definition of the Timeout exception has moved from here to the +# dns.exception module. We keep dns.resolver.Timeout defined for +# backwards compatibility. + +Timeout = dns.exception.Timeout + +class NoAnswer(dns.exception.DNSException): + """The response did not contain an answer to the question.""" + pass + +class NoNameservers(dns.exception.DNSException): + """No non-broken nameservers are available to answer the query.""" + pass + +class NotAbsolute(dns.exception.DNSException): + """Raised if an absolute domain name is required but a relative name + was provided.""" + pass + +class NoRootSOA(dns.exception.DNSException): + """Raised if for some reason there is no SOA at the root name. + This should never happen!""" + pass + + +class Answer(object): + """DNS stub resolver answer + + Instances of this class bundle up the result of a successful DNS + resolution. + + For convenience, the answer object implements much of the sequence + protocol, forwarding to its 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]". + + Note that CNAMEs or DNAMEs in the response may mean that answer + node's name might not be the query name. + + @ivar qname: The query name + @type qname: dns.name.Name object + @ivar rdtype: The query type + @type rdtype: int + @ivar rdclass: The query class + @type rdclass: int + @ivar response: The response message + @type response: dns.message.Message object + @ivar rrset: The answer + @type rrset: dns.rrset.RRset object + @ivar expiration: The time when the answer expires + @type expiration: float (seconds since the epoch) + """ + def __init__(self, qname, rdtype, rdclass, response): + self.qname = qname + self.rdtype = rdtype + self.rdclass = rdclass + self.response = response + min_ttl = -1 + rrset = None + for count in xrange(0, 15): + try: + rrset = response.find_rrset(response.answer, qname, + rdclass, rdtype) + if min_ttl == -1 or rrset.ttl < min_ttl: + min_ttl = rrset.ttl + break + except KeyError: + if rdtype != dns.rdatatype.CNAME: + try: + crrset = response.find_rrset(response.answer, + qname, + rdclass, + dns.rdatatype.CNAME) + if min_ttl == -1 or crrset.ttl < min_ttl: + min_ttl = crrset.ttl + for rd in crrset: + qname = rd.target + break + continue + except KeyError: + raise NoAnswer + raise NoAnswer + if rrset is None: + raise NoAnswer + self.rrset = rrset + self.expiration = time.time() + min_ttl + + def __getattr__(self, attr): + if attr == 'name': + return self.rrset.name + elif attr == 'ttl': + return self.rrset.ttl + elif attr == 'covers': + return self.rrset.covers + elif attr == 'rdclass': + return self.rrset.rdclass + elif attr == 'rdtype': + return self.rrset.rdtype + else: + raise AttributeError(attr) + + def __len__(self): + return len(self.rrset) + + def __iter__(self): + return iter(self.rrset) + + def __getitem__(self, i): + return self.rrset[i] + + def __delitem__(self, i): + del self.rrset[i] + + def __getslice__(self, i, j): + return self.rrset[i:j] + + def __delslice__(self, i, j): + del self.rrset[i:j] + +class Cache(object): + """Simple DNS answer cache. + + @ivar data: A dictionary of cached data + @type data: dict + @ivar cleaning_interval: The number of seconds between cleanings. The + default is 300 (5 minutes). + @type cleaning_interval: float + @ivar next_cleaning: The time the cache should next be cleaned (in seconds + since the epoch.) + @type next_cleaning: float + """ + + def __init__(self, cleaning_interval=300.0): + """Initialize a DNS cache. + + @param cleaning_interval: the number of seconds between periodic + cleanings. The default is 300.0 + @type cleaning_interval: float. + """ + + self.data = {} + self.cleaning_interval = cleaning_interval + self.next_cleaning = time.time() + self.cleaning_interval + + def maybe_clean(self): + """Clean the cache if it's time to do so.""" + + now = time.time() + if self.next_cleaning <= now: + keys_to_delete = [] + for (k, v) in self.data.iteritems(): + if v.expiration <= now: + keys_to_delete.append(k) + for k in keys_to_delete: + del self.data[k] + now = time.time() + self.next_cleaning = now + self.cleaning_interval + + def get(self, key): + """Get the answer associated with I{key}. Returns None if + no answer is cached for the key. + @param key: the key + @type key: (dns.name.Name, int, int) tuple whose values are the + query name, rdtype, and rdclass. + @rtype: dns.resolver.Answer object or None + """ + + self.maybe_clean() + v = self.data.get(key) + if v is None or v.expiration <= time.time(): + return None + return v + + def put(self, key, value): + """Associate key and value in the cache. + @param key: the key + @type key: (dns.name.Name, int, int) tuple whose values are the + query name, rdtype, and rdclass. + @param value: The answer being cached + @type value: dns.resolver.Answer object + """ + + self.maybe_clean() + self.data[key] = value + + def flush(self, key=None): + """Flush the cache. + + If I{key} is specified, only that item is flushed. Otherwise + the entire cache is flushed. + + @param key: the key to flush + @type key: (dns.name.Name, int, int) tuple or None + """ + + if not key is None: + if self.data.has_key(key): + del self.data[key] + else: + self.data = {} + self.next_cleaning = time.time() + self.cleaning_interval + +class Resolver(object): + """DNS stub resolver + + @ivar domain: The domain of this host + @type domain: dns.name.Name object + @ivar nameservers: A list of nameservers to query. Each nameserver is + a string which contains the IP address of a nameserver. + @type nameservers: list of strings + @ivar search: The search list. If the query name is a relative name, + the resolver will construct an absolute query name by appending the search + names one by one to the query name. + @type search: list of dns.name.Name objects + @ivar port: The port to which to send queries. The default is 53. + @type port: int + @ivar timeout: The number of seconds to wait for a response from a + server, before timing out. + @type timeout: float + @ivar lifetime: The total number of seconds to spend trying to get an + answer to the question. If the lifetime expires, a Timeout exception + will occur. + @type lifetime: float + @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 edns: The EDNS level to use. The default is -1, no Edns. + @type edns: int + @ivar ednsflags: The EDNS flags + @type ednsflags: int + @ivar payload: The EDNS payload size. The default is 0. + @type payload: int + @ivar cache: The cache to use. The default is None. + @type cache: dns.resolver.Cache object + """ + def __init__(self, filename='/etc/resolv.conf', configure=True): + """Initialize a resolver instance. + + @param filename: The filename of a configuration file in + standard /etc/resolv.conf format. This parameter is meaningful + only when I{configure} is true and the platform is POSIX. + @type filename: string or file object + @param configure: If True (the default), the resolver instance + is configured in the normal fashion for the operating system + the resolver is running on. (I.e. a /etc/resolv.conf file on + POSIX systems and from the registry on Windows systems.) + @type configure: bool""" + + self.reset() + if configure: + if sys.platform == 'win32': + self.read_registry() + elif filename: + self.read_resolv_conf(filename) + + def reset(self): + """Reset all resolver configuration to the defaults.""" + self.domain = \ + dns.name.Name(dns.name.from_text(socket.gethostname())[1:]) + if len(self.domain) == 0: + self.domain = dns.name.root + self.nameservers = [] + self.search = [] + self.port = 53 + self.timeout = 2.0 + self.lifetime = 30.0 + self.keyring = None + self.keyname = None + self.keyalgorithm = dns.tsig.default_algorithm + self.edns = -1 + self.ednsflags = 0 + self.payload = 0 + self.cache = None + + def read_resolv_conf(self, f): + """Process f as a file in the /etc/resolv.conf format. If f is + a string, it is used as the name of the file to open; otherwise it + is treated as the file itself.""" + if isinstance(f, str) or isinstance(f, unicode): + try: + f = open(f, 'r') + except IOError: + # /etc/resolv.conf doesn't exist, can't be read, etc. + # We'll just use the default resolver configuration. + self.nameservers = ['127.0.0.1'] + return + want_close = True + else: + want_close = False + try: + for l in f: + if len(l) == 0 or l[0] == '#' or l[0] == ';': + continue + tokens = l.split() + if len(tokens) == 0: + continue + if tokens[0] == 'nameserver': + self.nameservers.append(tokens[1]) + elif tokens[0] == 'domain': + self.domain = dns.name.from_text(tokens[1]) + elif tokens[0] == 'search': + for suffix in tokens[1:]: + self.search.append(dns.name.from_text(suffix)) + finally: + if want_close: + f.close() + if len(self.nameservers) == 0: + self.nameservers.append('127.0.0.1') + + def _determine_split_char(self, entry): + # + # The windows registry irritatingly changes the list element + # delimiter in between ' ' and ',' (and vice-versa) in various + # versions of windows. + # + if entry.find(' ') >= 0: + split_char = ' ' + elif entry.find(',') >= 0: + split_char = ',' + else: + # probably a singleton; treat as a space-separated list. + split_char = ' ' + return split_char + + def _config_win32_nameservers(self, nameservers): + """Configure a NameServer registry entry.""" + # we call str() on nameservers to convert it from unicode to ascii + nameservers = str(nameservers) + split_char = self._determine_split_char(nameservers) + ns_list = nameservers.split(split_char) + for ns in ns_list: + if not ns in self.nameservers: + self.nameservers.append(ns) + + def _config_win32_domain(self, domain): + """Configure a Domain registry entry.""" + # we call str() on domain to convert it from unicode to ascii + self.domain = dns.name.from_text(str(domain)) + + def _config_win32_search(self, search): + """Configure a Search registry entry.""" + # we call str() on search to convert it from unicode to ascii + search = str(search) + split_char = self._determine_split_char(search) + search_list = search.split(split_char) + for s in search_list: + if not s in self.search: + self.search.append(dns.name.from_text(s)) + + def _config_win32_fromkey(self, key): + """Extract DNS info from a registry key.""" + try: + servers, rtype = _winreg.QueryValueEx(key, 'NameServer') + except WindowsError: + servers = None + if servers: + self._config_win32_nameservers(servers) + try: + dom, rtype = _winreg.QueryValueEx(key, 'Domain') + if dom: + self._config_win32_domain(dom) + except WindowsError: + pass + else: + try: + servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer') + except WindowsError: + servers = None + if servers: + self._config_win32_nameservers(servers) + try: + dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain') + if dom: + self._config_win32_domain(dom) + except WindowsError: + pass + try: + search, rtype = _winreg.QueryValueEx(key, 'SearchList') + except WindowsError: + search = None + if search: + self._config_win32_search(search) + + def read_registry(self): + """Extract resolver configuration from the Windows registry.""" + lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + want_scan = False + try: + try: + # XP, 2000 + tcp_params = _winreg.OpenKey(lm, + r'SYSTEM\CurrentControlSet' + r'\Services\Tcpip\Parameters') + want_scan = True + except EnvironmentError: + # ME + tcp_params = _winreg.OpenKey(lm, + r'SYSTEM\CurrentControlSet' + r'\Services\VxD\MSTCP') + try: + self._config_win32_fromkey(tcp_params) + finally: + tcp_params.Close() + if want_scan: + interfaces = _winreg.OpenKey(lm, + r'SYSTEM\CurrentControlSet' + r'\Services\Tcpip\Parameters' + r'\Interfaces') + try: + i = 0 + while True: + try: + guid = _winreg.EnumKey(interfaces, i) + i += 1 + key = _winreg.OpenKey(interfaces, guid) + if not self._win32_is_nic_enabled(lm, guid, key): + continue + try: + self._config_win32_fromkey(key) + finally: + key.Close() + except EnvironmentError: + break + finally: + interfaces.Close() + finally: + lm.Close() + + def _win32_is_nic_enabled(self, lm, guid, interface_key): + # Look in the Windows Registry to determine whether the network + # interface corresponding to the given guid is enabled. + # + # (Code contributed by Paul Marks, thanks!) + # + try: + # This hard-coded location seems to be consistent, at least + # from Windows 2000 through Vista. + connection_key = _winreg.OpenKey( + lm, + r'SYSTEM\CurrentControlSet\Control\Network' + r'\{4D36E972-E325-11CE-BFC1-08002BE10318}' + r'\%s\Connection' % guid) + + try: + # The PnpInstanceID points to a key inside Enum + (pnp_id, ttype) = _winreg.QueryValueEx( + connection_key, 'PnpInstanceID') + + if ttype != _winreg.REG_SZ: + raise ValueError + + device_key = _winreg.OpenKey( + lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id) + + try: + # Get ConfigFlags for this device + (flags, ttype) = _winreg.QueryValueEx( + device_key, 'ConfigFlags') + + if ttype != _winreg.REG_DWORD: + raise ValueError + + # Based on experimentation, bit 0x1 indicates that the + # device is disabled. + return not (flags & 0x1) + + finally: + device_key.Close() + finally: + connection_key.Close() + except (EnvironmentError, ValueError): + # Pre-vista, enabled interfaces seem to have a non-empty + # NTEContextList; this was how dnspython detected enabled + # nics before the code above was contributed. We've retained + # the old method since we don't know if the code above works + # on Windows 95/98/ME. + try: + (nte, ttype) = _winreg.QueryValueEx(interface_key, + 'NTEContextList') + return nte is not None + except WindowsError: + return False + + def _compute_timeout(self, start): + now = time.time() + if now < start: + if start - now > 1: + # Time going backwards is bad. Just give up. + raise Timeout + else: + # Time went backwards, but only a little. This can + # happen, e.g. under vmware with older linux kernels. + # Pretend it didn't happen. + now = start + duration = now - start + if duration >= self.lifetime: + raise Timeout + return min(self.lifetime - duration, self.timeout) + + def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, + tcp=False, source=None): + """Query nameservers to find the answer to the question. + + The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects + of the appropriate type, or strings that can be converted into objects + of the appropriate type. E.g. For I{rdtype} the integer 2 and the + the string 'NS' both mean to query for records with DNS rdata type NS. + + @param qname: the query name + @type qname: dns.name.Name object or string + @param rdtype: the query type + @type rdtype: int or string + @param rdclass: the query class + @type rdclass: int or string + @param tcp: use TCP to make the query (default is False). + @type tcp: bool + @param source: bind to this IP address (defaults to machine default IP). + @type source: IP address in dotted quad notation + @rtype: dns.resolver.Answer instance + @raises Timeout: no answers could be found in the specified lifetime + @raises NXDOMAIN: the query name does not exist + @raises NoAnswer: the response did not contain an answer + @raises NoNameservers: no non-broken nameservers are available to + answer the question.""" + + if isinstance(qname, (str, unicode)): + qname = dns.name.from_text(qname, None) + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(rdclass, str): + rdclass = dns.rdataclass.from_text(rdclass) + qnames_to_try = [] + if qname.is_absolute(): + qnames_to_try.append(qname) + else: + if len(qname) > 1: + qnames_to_try.append(qname.concatenate(dns.name.root)) + if self.search: + for suffix in self.search: + qnames_to_try.append(qname.concatenate(suffix)) + else: + qnames_to_try.append(qname.concatenate(self.domain)) + all_nxdomain = True + start = time.time() + for qname in qnames_to_try: + if self.cache: + answer = self.cache.get((qname, rdtype, rdclass)) + if answer: + return answer + request = dns.message.make_query(qname, rdtype, rdclass) + if not self.keyname is None: + request.use_tsig(self.keyring, self.keyname, self.keyalgorithm) + request.use_edns(self.edns, self.ednsflags, self.payload) + response = None + # + # make a copy of the servers list so we can alter it later. + # + nameservers = self.nameservers[:] + backoff = 0.10 + while response is None: + if len(nameservers) == 0: + raise NoNameservers + for nameserver in nameservers[:]: + timeout = self._compute_timeout(start) + try: + if tcp: + response = dns.query.tcp(request, nameserver, + timeout, self.port, + source=source) + else: + response = dns.query.udp(request, nameserver, + timeout, self.port, + source=source) + except (socket.error, dns.exception.Timeout): + # + # Communication failure or timeout. Go to the + # next server + # + response = None + continue + except dns.query.UnexpectedSource: + # + # Who knows? Keep going. + # + response = None + continue + except dns.exception.FormError: + # + # We don't understand what this server is + # saying. Take it out of the mix and + # continue. + # + nameservers.remove(nameserver) + response = None + continue + rcode = response.rcode() + if rcode == dns.rcode.NOERROR or \ + rcode == dns.rcode.NXDOMAIN: + break + # + # We got a response, but we're not happy with the + # rcode in it. Remove the server from the mix if + # the rcode isn't SERVFAIL. + # + if rcode != dns.rcode.SERVFAIL: + nameservers.remove(nameserver) + response = None + if not response is None: + break + # + # All nameservers failed! + # + if len(nameservers) > 0: + # + # But we still have servers to try. Sleep a bit + # so we don't pound them! + # + timeout = self._compute_timeout(start) + sleep_time = min(timeout, backoff) + backoff *= 2 + time.sleep(sleep_time) + if response.rcode() == dns.rcode.NXDOMAIN: + continue + all_nxdomain = False + break + if all_nxdomain: + raise NXDOMAIN + answer = Answer(qname, rdtype, rdclass, response) + if self.cache: + self.cache.put((qname, rdtype, rdclass), answer) + return answer + + def use_tsig(self, keyring, keyname=None, + algorithm=dns.tsig.default_algorithm): + """Add a TSIG signature to the query. + + @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. + @param algorithm: The TSIG key algorithm to use. The default + is dns.tsig.default_algorithm. + @type algorithm: string""" + self.keyring = keyring + if keyname is None: + self.keyname = self.keyring.keys()[0] + else: + self.keyname = keyname + self.keyalgorithm = algorithm + + def use_edns(self, edns, ednsflags, payload): + """Configure Edns. + + @param edns: The EDNS level to use. The default is -1, no Edns. + @type edns: int + @param ednsflags: The EDNS flags + @type ednsflags: int + @param payload: The EDNS payload size. The default is 0. + @type payload: int""" + + if edns is None: + edns = -1 + self.edns = edns + self.ednsflags = ednsflags + self.payload = payload + +default_resolver = None + +def get_default_resolver(): + """Get the default resolver, initializing it if necessary.""" + global default_resolver + if default_resolver is None: + default_resolver = Resolver() + return default_resolver + +def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, + tcp=False, source=None): + """Query nameservers to find the answer to the question. + + This is a convenience function that uses the default resolver + object to make the query. + @see: L{dns.resolver.Resolver.query} for more information on the + parameters.""" + return get_default_resolver().query(qname, rdtype, rdclass, tcp, source) + +def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None): + """Find the name of the zone which contains the specified name. + + @param name: the query name + @type name: absolute dns.name.Name object or string + @param rdclass: The query class + @type rdclass: int + @param tcp: use TCP to make the query (default is False). + @type tcp: bool + @param resolver: the resolver to use + @type resolver: dns.resolver.Resolver object or None + @rtype: dns.name.Name""" + + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, dns.name.root) + if resolver is None: + resolver = get_default_resolver() + if not name.is_absolute(): + raise NotAbsolute(name) + while 1: + try: + answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp) + return name + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): + try: + name = name.parent() + except dns.name.NoParent: + raise NoRootSOA diff --git a/source4/scripting/python/samba_external/dnspython/dns/reversename.py b/source4/scripting/python/samba_external/dnspython/dns/reversename.py new file mode 100644 index 0000000000..0a61b827b0 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/reversename.py @@ -0,0 +1,75 @@ +# Copyright (C) 2006, 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 Reverse Map Names. + +@var ipv4_reverse_domain: The DNS IPv4 reverse-map domain, in-addr.arpa. +@type ipv4_reverse_domain: dns.name.Name object +@var ipv6_reverse_domain: The DNS IPv6 reverse-map domain, ip6.arpa. +@type ipv6_reverse_domain: dns.name.Name object +""" + +import dns.name +import dns.ipv6 +import dns.ipv4 + +ipv4_reverse_domain = dns.name.from_text('in-addr.arpa.') +ipv6_reverse_domain = dns.name.from_text('ip6.arpa.') + +def from_address(text): + """Convert an IPv4 or IPv6 address in textual form into a Name object whose + value is the reverse-map domain name of the address. + @param text: an IPv4 or IPv6 address in textual form (e.g. '127.0.0.1', + '::1') + @type text: str + @rtype: dns.name.Name object + """ + try: + parts = list(dns.ipv6.inet_aton(text).encode('hex_codec')) + origin = ipv6_reverse_domain + except: + parts = ['%d' % ord(byte) for byte in dns.ipv4.inet_aton(text)] + origin = ipv4_reverse_domain + parts.reverse() + return dns.name.from_text('.'.join(parts), origin=origin) + +def to_address(name): + """Convert a reverse map domain name into textual address form. + @param name: an IPv4 or IPv6 address in reverse-map form. + @type name: dns.name.Name object + @rtype: str + """ + if name.is_subdomain(ipv4_reverse_domain): + name = name.relativize(ipv4_reverse_domain) + labels = list(name.labels) + labels.reverse() + text = '.'.join(labels) + # run through inet_aton() to check syntax and make pretty. + return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) + elif name.is_subdomain(ipv6_reverse_domain): + name = name.relativize(ipv6_reverse_domain) + labels = list(name.labels) + labels.reverse() + parts = [] + i = 0 + l = len(labels) + while i < l: + parts.append(''.join(labels[i:i+4])) + i += 4 + text = ':'.join(parts) + # run through inet_aton() to check syntax and make pretty. + return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) + else: + raise dns.exception.SyntaxError('unknown reverse-map address family') diff --git a/source4/scripting/python/samba_external/dnspython/dns/rrset.py b/source4/scripting/python/samba_external/dnspython/dns/rrset.py new file mode 100644 index 0000000000..7f6c4afed4 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/rrset.py @@ -0,0 +1,175 @@ +# 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 RRsets (an RRset is a named rdataset)""" + +import dns.name +import dns.rdataset +import dns.rdataclass +import dns.renderer + +class RRset(dns.rdataset.Rdataset): + """A DNS RRset (named rdataset). + + RRset inherits from Rdataset, and RRsets can be treated as + Rdatasets in most cases. There are, however, a few notable + exceptions. RRsets have different to_wire() and to_text() method + arguments, reflecting the fact that RRsets always have an owner + name. + """ + + __slots__ = ['name', 'deleting'] + + def __init__(self, name, rdclass, rdtype, covers=dns.rdatatype.NONE, + deleting=None): + """Create a new RRset.""" + + super(RRset, self).__init__(rdclass, rdtype) + self.name = name + self.deleting = deleting + + def _clone(self): + obj = super(RRset, self)._clone() + obj.name = self.name + obj.deleting = self.deleting + return obj + + def __repr__(self): + if self.covers == 0: + ctext = '' + else: + ctext = '(' + dns.rdatatype.to_text(self.covers) + ')' + if not self.deleting is None: + dtext = ' delete=' + dns.rdataclass.to_text(self.deleting) + else: + dtext = '' + return '<DNS ' + str(self.name) + ' ' + \ + dns.rdataclass.to_text(self.rdclass) + ' ' + \ + dns.rdatatype.to_text(self.rdtype) + ctext + dtext + ' RRset>' + + def __str__(self): + return self.to_text() + + def __eq__(self, other): + """Two RRsets are equal if they have the same name and the same + rdataset + + @rtype: bool""" + if not isinstance(other, RRset): + return False + if self.name != other.name: + return False + return super(RRset, self).__eq__(other) + + def match(self, name, rdclass, rdtype, covers, deleting=None): + """Returns True if this rrset matches the specified class, type, + covers, and deletion state.""" + + if not super(RRset, self).match(rdclass, rdtype, covers): + return False + if self.name != name or self.deleting != deleting: + return False + return True + + def to_text(self, origin=None, relativize=True, **kw): + """Convert the RRset 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 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""" + + return super(RRset, self).to_text(self.name, origin, relativize, + self.deleting, **kw) + + def to_wire(self, file, compress=None, origin=None, **kw): + """Convert the RRset to wire format.""" + + return super(RRset, self).to_wire(self.name, file, compress, origin, + self.deleting, **kw) + + def to_rdataset(self): + """Convert an RRset into an Rdataset. + + @rtype: dns.rdataset.Rdataset object + """ + return dns.rdataset.from_rdata_list(self.ttl, list(self)) + + +def from_text_list(name, ttl, rdclass, rdtype, text_rdatas): + """Create an RRset with the specified name, TTL, class, and type, and with + the specified list of rdatas in text format. + + @rtype: dns.rrset.RRset object + """ + + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + if isinstance(rdclass, str): + rdclass = dns.rdataclass.from_text(rdclass) + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + r = RRset(name, 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(name, ttl, rdclass, rdtype, *text_rdatas): + """Create an RRset with the specified name, TTL, class, and type and with + the specified rdatas in text format. + + @rtype: dns.rrset.RRset object + """ + + return from_text_list(name, ttl, rdclass, rdtype, text_rdatas) + +def from_rdata_list(name, ttl, rdatas): + """Create an RRset with the specified name and TTL, and with + the specified list of rdata objects. + + @rtype: dns.rrset.RRset object + """ + + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + + if len(rdatas) == 0: + raise ValueError("rdata list must not be empty") + r = None + for rd in rdatas: + if r is None: + r = RRset(name, rd.rdclass, rd.rdtype) + r.update_ttl(ttl) + first_time = False + r.add(rd) + return r + +def from_rdata(name, ttl, *rdatas): + """Create an RRset with the specified name and TTL, and with + the specified rdata objects. + + @rtype: dns.rrset.RRset object + """ + + return from_rdata_list(name, ttl, rdatas) diff --git a/source4/scripting/python/samba_external/dnspython/dns/set.py b/source4/scripting/python/samba_external/dnspython/dns/set.py new file mode 100644 index 0000000000..91f9fb8766 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/set.py @@ -0,0 +1,263 @@ +# 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. + +"""A simple Set class.""" + +class Set(object): + """A simple set class. + + Sets are not in Python until 2.3, and rdata are not immutable so + we cannot use sets.Set anyway. This class implements subset of + the 2.3 Set interface using a list as the container. + + @ivar items: A list of the items which are in the set + @type items: list""" + + __slots__ = ['items'] + + def __init__(self, items=None): + """Initialize the set. + + @param items: the initial set of items + @type items: any iterable or None + """ + + self.items = [] + if not items is None: + for item in items: + self.add(item) + + def __repr__(self): + return "dns.simpleset.Set(%s)" % repr(self.items) + + def add(self, item): + """Add an item to the set.""" + if not item in self.items: + self.items.append(item) + + def remove(self, item): + """Remove an item from the set.""" + self.items.remove(item) + + def discard(self, item): + """Remove an item from the set if present.""" + try: + self.items.remove(item) + except ValueError: + pass + + def _clone(self): + """Make a (shallow) copy of the set. + + There is a 'clone protocol' that subclasses of this class + should use. To make a copy, first call your super's _clone() + method, and use the object returned as the new instance. Then + make shallow copies of the attributes defined in the subclass. + + This protocol allows us to write the set algorithms that + return new instances (e.g. union) once, and keep using them in + subclasses. + """ + + cls = self.__class__ + obj = cls.__new__(cls) + obj.items = list(self.items) + return obj + + def __copy__(self): + """Make a (shallow) copy of the set.""" + return self._clone() + + def copy(self): + """Make a (shallow) copy of the set.""" + return self._clone() + + def union_update(self, other): + """Update the set, adding any elements from other which are not + already in the set. + @param other: the collection of items with which to update the set + @type other: Set object + """ + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + if self is other: + return + for item in other.items: + self.add(item) + + def intersection_update(self, other): + """Update the set, removing any elements from other which are not + in both sets. + @param other: the collection of items with which to update the set + @type other: Set object + """ + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + if self is other: + return + # we make a copy of the list so that we can remove items from + # the list without breaking the iterator. + for item in list(self.items): + if item not in other.items: + self.items.remove(item) + + def difference_update(self, other): + """Update the set, removing any elements from other which are in + the set. + @param other: the collection of items with which to update the set + @type other: Set object + """ + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + if self is other: + self.items = [] + else: + for item in other.items: + self.discard(item) + + def union(self, other): + """Return a new set which is the union of I{self} and I{other}. + + @param other: the other set + @type other: Set object + @rtype: the same type as I{self} + """ + + obj = self._clone() + obj.union_update(other) + return obj + + def intersection(self, other): + """Return a new set which is the intersection of I{self} and I{other}. + + @param other: the other set + @type other: Set object + @rtype: the same type as I{self} + """ + + obj = self._clone() + obj.intersection_update(other) + return obj + + def difference(self, other): + """Return a new set which I{self} - I{other}, i.e. the items + in I{self} which are not also in I{other}. + + @param other: the other set + @type other: Set object + @rtype: the same type as I{self} + """ + + obj = self._clone() + obj.difference_update(other) + return obj + + def __or__(self, other): + return self.union(other) + + def __and__(self, other): + return self.intersection(other) + + def __add__(self, other): + return self.union(other) + + def __sub__(self, other): + return self.difference(other) + + def __ior__(self, other): + self.union_update(other) + return self + + def __iand__(self, other): + self.intersection_update(other) + return self + + def __iadd__(self, other): + self.union_update(other) + return self + + def __isub__(self, other): + self.difference_update(other) + return self + + def update(self, other): + """Update the set, adding any elements from other which are not + already in the set. + @param other: the collection of items with which to update the set + @type other: any iterable type""" + for item in other: + self.add(item) + + def clear(self): + """Make the set empty.""" + self.items = [] + + def __eq__(self, other): + # Yes, this is inefficient but the sets we're dealing with are + # usually quite small, so it shouldn't hurt too much. + for item in self.items: + if not item in other.items: + return False + for item in other.items: + if not item in self.items: + return False + return True + + def __ne__(self, other): + return not self.__eq__(other) + + def __len__(self): + return len(self.items) + + def __iter__(self): + return iter(self.items) + + def __getitem__(self, i): + return self.items[i] + + def __delitem__(self, i): + del self.items[i] + + def __getslice__(self, i, j): + return self.items[i:j] + + def __delslice__(self, i, j): + del self.items[i:j] + + def issubset(self, other): + """Is I{self} a subset of I{other}? + + @rtype: bool + """ + + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + for item in self.items: + if not item in other.items: + return False + return True + + def issuperset(self, other): + """Is I{self} a superset of I{other}? + + @rtype: bool + """ + + if not isinstance(other, Set): + raise ValueError('other must be a Set instance') + for item in other.items: + if not item in self.items: + return False + return True diff --git a/source4/scripting/python/samba_external/dnspython/dns/tokenizer.py b/source4/scripting/python/samba_external/dnspython/dns/tokenizer.py new file mode 100644 index 0000000000..4f68a2a495 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/tokenizer.py @@ -0,0 +1,547 @@ +# 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. + +"""Tokenize DNS master file format""" + +import cStringIO +import sys + +import dns.exception +import dns.name +import dns.ttl + +_DELIMITERS = { + ' ' : True, + '\t' : True, + '\n' : True, + ';' : True, + '(' : True, + ')' : True, + '"' : True } + +_QUOTING_DELIMITERS = { '"' : True } + +EOF = 0 +EOL = 1 +WHITESPACE = 2 +IDENTIFIER = 3 +QUOTED_STRING = 4 +COMMENT = 5 +DELIMITER = 6 + +class UngetBufferFull(dns.exception.DNSException): + """Raised when an attempt is made to unget a token when the unget + buffer is full.""" + pass + +class Token(object): + """A DNS master file format token. + + @ivar ttype: The token type + @type ttype: int + @ivar value: The token value + @type value: string + @ivar has_escape: Does the token value contain escapes? + @type has_escape: bool + """ + + def __init__(self, ttype, value='', has_escape=False): + """Initialize a token instance. + + @param ttype: The token type + @type ttype: int + @ivar value: The token value + @type value: string + @ivar has_escape: Does the token value contain escapes? + @type has_escape: bool + """ + self.ttype = ttype + self.value = value + self.has_escape = has_escape + + def is_eof(self): + return self.ttype == EOF + + def is_eol(self): + return self.ttype == EOL + + def is_whitespace(self): + return self.ttype == WHITESPACE + + def is_identifier(self): + return self.ttype == IDENTIFIER + + def is_quoted_string(self): + return self.ttype == QUOTED_STRING + + def is_comment(self): + return self.ttype == COMMENT + + def is_delimiter(self): + return self.ttype == DELIMITER + + def is_eol_or_eof(self): + return (self.ttype == EOL or self.ttype == EOF) + + def __eq__(self, other): + if not isinstance(other, Token): + return False + return (self.ttype == other.ttype and + self.value == other.value) + + def __ne__(self, other): + if not isinstance(other, Token): + return True + return (self.ttype != other.ttype or + self.value != other.value) + + def __str__(self): + return '%d "%s"' % (self.ttype, self.value) + + def unescape(self): + if not self.has_escape: + return self + unescaped = '' + l = len(self.value) + i = 0 + while i < l: + c = self.value[i] + i += 1 + if c == '\\': + if i >= l: + raise dns.exception.UnexpectedEnd + c = self.value[i] + i += 1 + if c.isdigit(): + if i >= l: + raise dns.exception.UnexpectedEnd + c2 = self.value[i] + i += 1 + if i >= l: + raise dns.exception.UnexpectedEnd + c3 = self.value[i] + i += 1 + if not (c2.isdigit() and c3.isdigit()): + raise dns.exception.SyntaxError + c = chr(int(c) * 100 + int(c2) * 10 + int(c3)) + unescaped += c + return Token(self.ttype, unescaped) + + # compatibility for old-style tuple tokens + + def __len__(self): + return 2 + + def __iter__(self): + return iter((self.ttype, self.value)) + + def __getitem__(self, i): + if i == 0: + return self.ttype + elif i == 1: + return self.value + else: + raise IndexError + +class Tokenizer(object): + """A DNS master file format tokenizer. + + A token is a (type, value) tuple, where I{type} is an int, and + I{value} is a string. The valid types are EOF, EOL, WHITESPACE, + IDENTIFIER, QUOTED_STRING, COMMENT, and DELIMITER. + + @ivar file: The file to tokenize + @type file: file + @ivar ungotten_char: The most recently ungotten character, or None. + @type ungotten_char: string + @ivar ungotten_token: The most recently ungotten token, or None. + @type ungotten_token: (int, string) token tuple + @ivar multiline: The current multiline level. This value is increased + by one every time a '(' delimiter is read, and decreased by one every time + a ')' delimiter is read. + @type multiline: int + @ivar quoting: This variable is true if the tokenizer is currently + reading a quoted string. + @type quoting: bool + @ivar eof: This variable is true if the tokenizer has encountered EOF. + @type eof: bool + @ivar delimiters: The current delimiter dictionary. + @type delimiters: dict + @ivar line_number: The current line number + @type line_number: int + @ivar filename: A filename that will be returned by the L{where} method. + @type filename: string + """ + + def __init__(self, f=sys.stdin, filename=None): + """Initialize a tokenizer instance. + + @param f: The file to tokenize. The default is sys.stdin. + This parameter may also be a string, in which case the tokenizer + will take its input from the contents of the string. + @type f: file or string + @param filename: the name of the filename that the L{where} method + will return. + @type filename: string + """ + + if isinstance(f, str): + f = cStringIO.StringIO(f) + if filename is None: + filename = '<string>' + else: + if filename is None: + if f is sys.stdin: + filename = '<stdin>' + else: + filename = '<file>' + self.file = f + self.ungotten_char = None + self.ungotten_token = None + self.multiline = 0 + self.quoting = False + self.eof = False + self.delimiters = _DELIMITERS + self.line_number = 1 + self.filename = filename + + def _get_char(self): + """Read a character from input. + @rtype: string + """ + + if self.ungotten_char is None: + if self.eof: + c = '' + else: + c = self.file.read(1) + if c == '': + self.eof = True + elif c == '\n': + self.line_number += 1 + else: + c = self.ungotten_char + self.ungotten_char = None + return c + + def where(self): + """Return the current location in the input. + + @rtype: (string, int) tuple. The first item is the filename of + the input, the second is the current line number. + """ + + return (self.filename, self.line_number) + + def _unget_char(self, c): + """Unget a character. + + The unget buffer for characters is only one character large; it is + an error to try to unget a character when the unget buffer is not + empty. + + @param c: the character to unget + @type c: string + @raises UngetBufferFull: there is already an ungotten char + """ + + if not self.ungotten_char is None: + raise UngetBufferFull + self.ungotten_char = c + + def skip_whitespace(self): + """Consume input until a non-whitespace character is encountered. + + The non-whitespace character is then ungotten, and the number of + whitespace characters consumed is returned. + + If the tokenizer is in multiline mode, then newlines are whitespace. + + @rtype: int + """ + + skipped = 0 + while True: + c = self._get_char() + if c != ' ' and c != '\t': + if (c != '\n') or not self.multiline: + self._unget_char(c) + return skipped + skipped += 1 + + def get(self, want_leading = False, want_comment = False): + """Get the next token. + + @param want_leading: If True, return a WHITESPACE token if the + first character read is whitespace. The default is False. + @type want_leading: bool + @param want_comment: If True, return a COMMENT token if the + first token read is a comment. The default is False. + @type want_comment: bool + @rtype: Token object + @raises dns.exception.UnexpectedEnd: input ended prematurely + @raises dns.exception.SyntaxError: input was badly formed + """ + + if not self.ungotten_token is None: + token = self.ungotten_token + self.ungotten_token = None + if token.is_whitespace(): + if want_leading: + return token + elif token.is_comment(): + if want_comment: + return token + else: + return token + skipped = self.skip_whitespace() + if want_leading and skipped > 0: + return Token(WHITESPACE, ' ') + token = '' + ttype = IDENTIFIER + has_escape = False + while True: + c = self._get_char() + if c == '' or c in self.delimiters: + if c == '' and self.quoting: + raise dns.exception.UnexpectedEnd + if token == '' and ttype != QUOTED_STRING: + if c == '(': + self.multiline += 1 + self.skip_whitespace() + continue + elif c == ')': + if not self.multiline > 0: + raise dns.exception.SyntaxError + self.multiline -= 1 + self.skip_whitespace() + continue + elif c == '"': + if not self.quoting: + self.quoting = True + self.delimiters = _QUOTING_DELIMITERS + ttype = QUOTED_STRING + continue + else: + self.quoting = False + self.delimiters = _DELIMITERS + self.skip_whitespace() + continue + elif c == '\n': + return Token(EOL, '\n') + elif c == ';': + while 1: + c = self._get_char() + if c == '\n' or c == '': + break + token += c + if want_comment: + self._unget_char(c) + return Token(COMMENT, token) + elif c == '': + if self.multiline: + raise dns.exception.SyntaxError('unbalanced parentheses') + return Token(EOF) + elif self.multiline: + self.skip_whitespace() + token = '' + continue + else: + return Token(EOL, '\n') + else: + # This code exists in case we ever want a + # delimiter to be returned. It never produces + # a token currently. + token = c + ttype = DELIMITER + else: + self._unget_char(c) + break + elif self.quoting: + if c == '\\': + c = self._get_char() + if c == '': + raise dns.exception.UnexpectedEnd + if c.isdigit(): + c2 = self._get_char() + if c2 == '': + raise dns.exception.UnexpectedEnd + c3 = self._get_char() + if c == '': + raise dns.exception.UnexpectedEnd + if not (c2.isdigit() and c3.isdigit()): + raise dns.exception.SyntaxError + c = chr(int(c) * 100 + int(c2) * 10 + int(c3)) + elif c == '\n': + raise dns.exception.SyntaxError('newline in quoted string') + elif c == '\\': + # + # It's an escape. Put it and the next character into + # the token; it will be checked later for goodness. + # + token += c + has_escape = True + c = self._get_char() + if c == '' or c == '\n': + raise dns.exception.UnexpectedEnd + token += c + if token == '' and ttype != QUOTED_STRING: + if self.multiline: + raise dns.exception.SyntaxError('unbalanced parentheses') + ttype = EOF + return Token(ttype, token, has_escape) + + def unget(self, token): + """Unget a token. + + The unget buffer for tokens is only one token large; it is + an error to try to unget a token when the unget buffer is not + empty. + + @param token: the token to unget + @type token: Token object + @raises UngetBufferFull: there is already an ungotten token + """ + + if not self.ungotten_token is None: + raise UngetBufferFull + self.ungotten_token = token + + def next(self): + """Return the next item in an iteration. + @rtype: (int, string) + """ + + token = self.get() + if token.is_eof(): + raise StopIteration + return token + + def __iter__(self): + return self + + # Helpers + + def get_int(self): + """Read the next token and interpret it as an integer. + + @raises dns.exception.SyntaxError: + @rtype: int + """ + + token = self.get().unescape() + if not token.is_identifier(): + raise dns.exception.SyntaxError('expecting an identifier') + if not token.value.isdigit(): + raise dns.exception.SyntaxError('expecting an integer') + return int(token.value) + + def get_uint8(self): + """Read the next token and interpret it as an 8-bit unsigned + integer. + + @raises dns.exception.SyntaxError: + @rtype: int + """ + + value = self.get_int() + if value < 0 or value > 255: + raise dns.exception.SyntaxError('%d is not an unsigned 8-bit integer' % value) + return value + + def get_uint16(self): + """Read the next token and interpret it as a 16-bit unsigned + integer. + + @raises dns.exception.SyntaxError: + @rtype: int + """ + + value = self.get_int() + if value < 0 or value > 65535: + raise dns.exception.SyntaxError('%d is not an unsigned 16-bit integer' % value) + return value + + def get_uint32(self): + """Read the next token and interpret it as a 32-bit unsigned + integer. + + @raises dns.exception.SyntaxError: + @rtype: int + """ + + token = self.get().unescape() + if not token.is_identifier(): + raise dns.exception.SyntaxError('expecting an identifier') + if not token.value.isdigit(): + raise dns.exception.SyntaxError('expecting an integer') + value = long(token.value) + if value < 0 or value > 4294967296L: + raise dns.exception.SyntaxError('%d is not an unsigned 32-bit integer' % value) + return value + + def get_string(self, origin=None): + """Read the next token and interpret it as a string. + + @raises dns.exception.SyntaxError: + @rtype: string + """ + + token = self.get().unescape() + if not (token.is_identifier() or token.is_quoted_string()): + raise dns.exception.SyntaxError('expecting a string') + return token.value + + def get_identifier(self, origin=None): + """Read the next token and raise an exception if it is not an identifier. + + @raises dns.exception.SyntaxError: + @rtype: string + """ + + token = self.get().unescape() + if not token.is_identifier(): + raise dns.exception.SyntaxError('expecting an identifier') + return token.value + + def get_name(self, origin=None): + """Read the next token and interpret it as a DNS name. + + @raises dns.exception.SyntaxError: + @rtype: dns.name.Name object""" + + token = self.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError('expecting an identifier') + return dns.name.from_text(token.value, origin) + + def get_eol(self): + """Read the next token and raise an exception if it isn't EOL or + EOF. + + @raises dns.exception.SyntaxError: + @rtype: string + """ + + token = self.get() + if not token.is_eol_or_eof(): + raise dns.exception.SyntaxError('expected EOL or EOF, got %d "%s"' % (token.ttype, token.value)) + return token.value + + def get_ttl(self): + token = self.get().unescape() + if not token.is_identifier(): + raise dns.exception.SyntaxError('expecting an identifier') + return dns.ttl.from_text(token.value) diff --git a/source4/scripting/python/samba_external/dnspython/dns/tsig.py b/source4/scripting/python/samba_external/dnspython/dns/tsig.py new file mode 100644 index 0000000000..b4deeca859 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/tsig.py @@ -0,0 +1,216 @@ +# 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 TSIG support.""" + +import hmac +import struct + +import dns.exception +import dns.rdataclass +import dns.name + +class BadTime(dns.exception.DNSException): + """Raised if the current time is not within the TSIG's validity time.""" + pass + +class BadSignature(dns.exception.DNSException): + """Raised if the TSIG signature fails to verify.""" + pass + +class PeerError(dns.exception.DNSException): + """Base class for all TSIG errors generated by the remote peer""" + pass + +class PeerBadKey(PeerError): + """Raised if the peer didn't know the key we used""" + pass + +class PeerBadSignature(PeerError): + """Raised if the peer didn't like the signature we sent""" + pass + +class PeerBadTime(PeerError): + """Raised if the peer didn't like the time we sent""" + pass + +class PeerBadTruncation(PeerError): + """Raised if the peer didn't like amount of truncation in the TSIG we sent""" + pass + +default_algorithm = "HMAC-MD5.SIG-ALG.REG.INT" + +BADSIG = 16 +BADKEY = 17 +BADTIME = 18 +BADTRUNC = 22 + +def sign(wire, keyname, secret, time, fudge, original_id, error, + other_data, request_mac, ctx=None, multi=False, first=True, + algorithm=default_algorithm): + """Return a (tsig_rdata, mac, ctx) tuple containing the HMAC TSIG rdata + for the input parameters, the HMAC MAC calculated by applying the + TSIG signature algorithm, and the TSIG digest context. + @rtype: (string, string, hmac.HMAC object) + @raises ValueError: I{other_data} is too long + @raises NotImplementedError: I{algorithm} is not supported + """ + + (algorithm_name, digestmod) = get_algorithm(algorithm) + if first: + ctx = hmac.new(secret, digestmod=digestmod) + ml = len(request_mac) + if ml > 0: + ctx.update(struct.pack('!H', ml)) + ctx.update(request_mac) + id = struct.pack('!H', original_id) + ctx.update(id) + ctx.update(wire[2:]) + if first: + ctx.update(keyname.to_digestable()) + ctx.update(struct.pack('!H', dns.rdataclass.ANY)) + ctx.update(struct.pack('!I', 0)) + long_time = time + 0L + upper_time = (long_time >> 32) & 0xffffL + lower_time = long_time & 0xffffffffL + time_mac = struct.pack('!HIH', upper_time, lower_time, fudge) + pre_mac = algorithm_name + time_mac + ol = len(other_data) + if ol > 65535: + raise ValueError('TSIG Other Data is > 65535 bytes') + post_mac = struct.pack('!HH', error, ol) + other_data + if first: + ctx.update(pre_mac) + ctx.update(post_mac) + else: + ctx.update(time_mac) + mac = ctx.digest() + mpack = struct.pack('!H', len(mac)) + tsig_rdata = pre_mac + mpack + mac + id + post_mac + if multi: + ctx = hmac.new(secret) + ml = len(mac) + ctx.update(struct.pack('!H', ml)) + ctx.update(mac) + else: + ctx = None + return (tsig_rdata, mac, ctx) + +def hmac_md5(wire, keyname, secret, time, fudge, original_id, error, + other_data, request_mac, ctx=None, multi=False, first=True, + algorithm=default_algorithm): + return sign(wire, keyname, secret, time, fudge, original_id, error, + other_data, request_mac, ctx, multi, first, algorithm) + +def validate(wire, keyname, secret, now, request_mac, tsig_start, tsig_rdata, + tsig_rdlen, ctx=None, multi=False, first=True): + """Validate the specified TSIG rdata against the other input parameters. + + @raises FormError: The TSIG is badly formed. + @raises BadTime: There is too much time skew between the client and the + server. + @raises BadSignature: The TSIG signature did not validate + @rtype: hmac.HMAC object""" + + (adcount,) = struct.unpack("!H", wire[10:12]) + if adcount == 0: + raise dns.exception.FormError + adcount -= 1 + new_wire = wire[0:10] + struct.pack("!H", adcount) + wire[12:tsig_start] + current = tsig_rdata + (aname, used) = dns.name.from_wire(wire, current) + current = current + used + (upper_time, lower_time, fudge, mac_size) = \ + struct.unpack("!HIHH", wire[current:current + 10]) + time = ((upper_time + 0L) << 32) + (lower_time + 0L) + current += 10 + mac = wire[current:current + mac_size] + current += mac_size + (original_id, error, other_size) = \ + struct.unpack("!HHH", wire[current:current + 6]) + current += 6 + other_data = wire[current:current + other_size] + current += other_size + if current != tsig_rdata + tsig_rdlen: + raise dns.exception.FormError + if error != 0: + if error == BADSIG: + raise PeerBadSignature + elif error == BADKEY: + raise PeerBadKey + elif error == BADTIME: + raise PeerBadTime + elif error == BADTRUNC: + raise PeerBadTruncation + else: + raise PeerError('unknown TSIG error code %d' % error) + time_low = time - fudge + time_high = time + fudge + if now < time_low or now > time_high: + raise BadTime + (junk, our_mac, ctx) = sign(new_wire, keyname, secret, time, fudge, + original_id, error, other_data, + request_mac, ctx, multi, first, aname) + if (our_mac != mac): + raise BadSignature + return ctx + +def get_algorithm(algorithm): + """Returns the wire format string and the hash module to use for the + specified TSIG algorithm + + @rtype: (string, hash constructor) + @raises NotImplementedError: I{algorithm} is not supported + """ + + hashes = {} + try: + import hashlib + hashes[dns.name.from_text('hmac-sha224')] = hashlib.sha224 + hashes[dns.name.from_text('hmac-sha256')] = hashlib.sha256 + hashes[dns.name.from_text('hmac-sha384')] = hashlib.sha384 + hashes[dns.name.from_text('hmac-sha512')] = hashlib.sha512 + hashes[dns.name.from_text('hmac-sha1')] = hashlib.sha1 + hashes[dns.name.from_text('HMAC-MD5.SIG-ALG.REG.INT')] = hashlib.md5 + + import sys + if sys.hexversion < 0x02050000: + # hashlib doesn't conform to PEP 247: API for + # Cryptographic Hash Functions, which hmac before python + # 2.5 requires, so add the necessary items. + class HashlibWrapper: + def __init__(self, basehash): + self.basehash = basehash + self.digest_size = self.basehash().digest_size + + def new(self, *args, **kwargs): + return self.basehash(*args, **kwargs) + + for name in hashes: + hashes[name] = HashlibWrapper(hashes[name]) + + except ImportError: + import md5, sha + hashes[dns.name.from_text('HMAC-MD5.SIG-ALG.REG.INT')] = md5.md5 + hashes[dns.name.from_text('hmac-sha1')] = sha.sha + + if isinstance(algorithm, (str, unicode)): + algorithm = dns.name.from_text(algorithm) + + if algorithm in hashes: + return (algorithm.to_digestable(), hashes[algorithm]) + + raise NotImplementedError("TSIG algorithm " + str(algorithm) + + " is not supported") diff --git a/source4/scripting/python/samba_external/dnspython/dns/tsigkeyring.py b/source4/scripting/python/samba_external/dnspython/dns/tsigkeyring.py new file mode 100644 index 0000000000..4d68f96c85 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/tsigkeyring.py @@ -0,0 +1,44 @@ +# 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. + +"""A place to store TSIG keys.""" + +import base64 + +import dns.name + +def from_text(textring): + """Convert a dictionary containing (textual DNS name, base64 secret) pairs + into a binary keyring which has (dns.name.Name, binary secret) pairs. + @rtype: dict""" + + keyring = {} + for keytext in textring: + keyname = dns.name.from_text(keytext) + secret = base64.decodestring(textring[keytext]) + keyring[keyname] = secret + return keyring + +def to_text(keyring): + """Convert a dictionary containing (dns.name.Name, binary secret) pairs + into a text keyring which has (textual DNS name, base64 secret) pairs. + @rtype: dict""" + + textring = {} + for keyname in keyring: + keytext = dns.name.to_text(keyname) + secret = base64.encodestring(keyring[keyname]) + textring[keytext] = secret + return textring diff --git a/source4/scripting/python/samba_external/dnspython/dns/ttl.py b/source4/scripting/python/samba_external/dnspython/dns/ttl.py new file mode 100644 index 0000000000..f295300517 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/ttl.py @@ -0,0 +1,64 @@ +# 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 TTL conversion.""" + +import dns.exception + +class BadTTL(dns.exception.SyntaxError): + pass + +def from_text(text): + """Convert the text form of a TTL to an integer. + + The BIND 8 units syntax for TTLs (e.g. '1w6d4h3m10s') is supported. + + @param text: the textual TTL + @type text: string + @raises dns.ttl.BadTTL: the TTL is not well-formed + @rtype: int + """ + + if text.isdigit(): + total = long(text) + else: + if not text[0].isdigit(): + raise BadTTL + total = 0L + current = 0L + for c in text: + if c.isdigit(): + current *= 10 + current += long(c) + else: + c = c.lower() + if c == 'w': + total += current * 604800L + elif c == 'd': + total += current * 86400L + elif c == 'h': + total += current * 3600L + elif c == 'm': + total += current * 60L + elif c == 's': + total += current + else: + raise BadTTL("unknown unit '%s'" % c) + current = 0 + if not current == 0: + raise BadTTL("trailing integer") + if total < 0L or total > 2147483647L: + raise BadTTL("TTL should be between 0 and 2^31 - 1 (inclusive)") + return total diff --git a/source4/scripting/python/samba_external/dnspython/dns/update.py b/source4/scripting/python/samba_external/dnspython/dns/update.py new file mode 100644 index 0000000000..7d42636891 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/update.py @@ -0,0 +1,241 @@ +# 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 Dynamic Update Support""" + +import dns.message +import dns.name +import dns.opcode +import dns.rdata +import dns.rdataclass +import dns.rdataset + +class Update(dns.message.Message): + def __init__(self, zone, rdclass=dns.rdataclass.IN, keyring=None, + keyname=None, keyalgorithm=dns.tsig.default_algorithm): + """Initialize a new DNS Update object. + + @param zone: The zone which is being updated. + @type zone: A dns.name.Name or string + @param rdclass: The class of the zone; defaults to dns.rdataclass.IN. + @type rdclass: An int designating the class, or a string whose value + is the name of a class. + @param keyring: The TSIG keyring to use; defaults to None. + @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 keyalgorithm: The TSIG algorithm to use; defaults to + dns.tsig.default_algorithm + @type keyalgorithm: string + """ + super(Update, self).__init__() + self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE) + if isinstance(zone, (str, unicode)): + zone = dns.name.from_text(zone) + self.origin = zone + if isinstance(rdclass, str): + rdclass = dns.rdataclass.from_text(rdclass) + self.zone_rdclass = rdclass + self.find_rrset(self.question, self.origin, rdclass, dns.rdatatype.SOA, + create=True, force_unique=True) + if not keyring is None: + self.use_tsig(keyring, keyname, keyalgorithm) + + def _add_rr(self, name, ttl, rd, deleting=None, section=None): + """Add a single RR to the update section.""" + + if section is None: + section = self.authority + covers = rd.covers() + rrset = self.find_rrset(section, name, self.zone_rdclass, rd.rdtype, + covers, deleting, True, True) + rrset.add(rd, ttl) + + def _add(self, replace, section, name, *args): + """Add records. The first argument is the replace mode. If + false, RRs are added to an existing RRset; if true, the RRset + is replaced with the specified contents. The second + argument is the section to add to. The third argument + is always a name. The other arguments can be: + + - rdataset... + + - ttl, rdata... + + - ttl, rdtype, string...""" + + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + if isinstance(args[0], dns.rdataset.Rdataset): + for rds in args: + if replace: + self.delete(name, rds.rdtype) + for rd in rds: + self._add_rr(name, rds.ttl, rd, section=section) + else: + args = list(args) + ttl = int(args.pop(0)) + if isinstance(args[0], dns.rdata.Rdata): + if replace: + self.delete(name, args[0].rdtype) + for rd in args: + self._add_rr(name, ttl, rd, section=section) + else: + rdtype = args.pop(0) + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + if replace: + self.delete(name, rdtype) + for s in args: + rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, + self.origin) + self._add_rr(name, ttl, rd, section=section) + + def add(self, name, *args): + """Add records. The first argument is always a name. The other + arguments can be: + + - rdataset... + + - ttl, rdata... + + - ttl, rdtype, string...""" + self._add(False, self.authority, name, *args) + + def delete(self, name, *args): + """Delete records. The first argument is always a name. The other + arguments can be: + + - I{nothing} + + - rdataset... + + - rdata... + + - rdtype, [string...]""" + + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + if len(args) == 0: + rrset = self.find_rrset(self.authority, name, dns.rdataclass.ANY, + dns.rdatatype.ANY, dns.rdatatype.NONE, + dns.rdatatype.ANY, True, True) + elif isinstance(args[0], dns.rdataset.Rdataset): + for rds in args: + for rd in rds: + self._add_rr(name, 0, rd, dns.rdataclass.NONE) + else: + args = list(args) + if isinstance(args[0], dns.rdata.Rdata): + for rd in args: + self._add_rr(name, 0, rd, dns.rdataclass.NONE) + else: + rdtype = args.pop(0) + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + if len(args) == 0: + rrset = self.find_rrset(self.authority, name, + self.zone_rdclass, rdtype, + dns.rdatatype.NONE, + dns.rdataclass.ANY, + True, True) + else: + for s in args: + rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, + self.origin) + self._add_rr(name, 0, rd, dns.rdataclass.NONE) + + def replace(self, name, *args): + """Replace records. The first argument is always a name. The other + arguments can be: + + - rdataset... + + - ttl, rdata... + + - ttl, rdtype, string... + + Note that if you want to replace the entire node, you should do + a delete of the name followed by one or more calls to add.""" + + self._add(True, self.authority, name, *args) + + def present(self, name, *args): + """Require that an owner name (and optionally an rdata type, + or specific rdataset) exists as a prerequisite to the + execution of the update. The first argument is always a name. + The other arguments can be: + + - rdataset... + + - rdata... + + - rdtype, string...""" + + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + if len(args) == 0: + rrset = self.find_rrset(self.answer, name, + dns.rdataclass.ANY, dns.rdatatype.ANY, + dns.rdatatype.NONE, None, + True, True) + elif isinstance(args[0], dns.rdataset.Rdataset) or \ + isinstance(args[0], dns.rdata.Rdata) or \ + len(args) > 1: + if not isinstance(args[0], dns.rdataset.Rdataset): + # Add a 0 TTL + args = list(args) + args.insert(0, 0) + self._add(False, self.answer, name, *args) + else: + rdtype = args[0] + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + rrset = self.find_rrset(self.answer, name, + dns.rdataclass.ANY, rdtype, + dns.rdatatype.NONE, None, + True, True) + + def absent(self, name, rdtype=None): + """Require that an owner name (and optionally an rdata type) does + not exist as a prerequisite to the execution of the update.""" + + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + if rdtype is None: + rrset = self.find_rrset(self.answer, name, + dns.rdataclass.NONE, dns.rdatatype.ANY, + dns.rdatatype.NONE, None, + True, True) + else: + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + rrset = self.find_rrset(self.answer, name, + dns.rdataclass.NONE, rdtype, + dns.rdatatype.NONE, None, + True, True) + + def to_wire(self, origin=None, max_size=65535): + """Return a string containing the update in DNS compressed wire + format. + @rtype: string""" + if origin is None: + origin = self.origin + return super(Update, self).to_wire(origin, max_size) diff --git a/source4/scripting/python/samba_external/dnspython/dns/version.py b/source4/scripting/python/samba_external/dnspython/dns/version.py new file mode 100644 index 0000000000..7a36775180 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/version.py @@ -0,0 +1,34 @@ +# 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. + +"""dnspython release version information.""" + +MAJOR = 1 +MINOR = 8 +MICRO = 0 +RELEASELEVEL = 0x0f +SERIAL = 0 + +if RELEASELEVEL == 0x0f: + version = '%d.%d.%d' % (MAJOR, MINOR, MICRO) +elif RELEASELEVEL == 0x00: + version = '%d.%d.%dx%d' % \ + (MAJOR, MINOR, MICRO, SERIAL) +else: + version = '%d.%d.%d%x%d' % \ + (MAJOR, MINOR, MICRO, RELEASELEVEL, SERIAL) + +hexversion = MAJOR << 24 | MINOR << 16 | MICRO << 8 | RELEASELEVEL << 4 | \ + SERIAL diff --git a/source4/scripting/python/samba_external/dnspython/dns/zone.py b/source4/scripting/python/samba_external/dnspython/dns/zone.py new file mode 100644 index 0000000000..93c157d8f0 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/dns/zone.py @@ -0,0 +1,855 @@ +# 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 Zones.""" + +from __future__ import generators + +import sys + +import dns.exception +import dns.name +import dns.node +import dns.rdataclass +import dns.rdatatype +import dns.rdata +import dns.rrset +import dns.tokenizer +import dns.ttl + +class BadZone(dns.exception.DNSException): + """The zone is malformed.""" + pass + +class NoSOA(BadZone): + """The zone has no SOA RR at its origin.""" + pass + +class NoNS(BadZone): + """The zone has no NS RRset at its origin.""" + pass + +class UnknownOrigin(BadZone): + """The zone's origin is unknown.""" + pass + +class Zone(object): + """A DNS zone. + + A Zone is a mapping from names to nodes. The zone object may be + treated like a Python dictionary, e.g. zone[name] will retrieve + the node associated with that name. The I{name} may be a + dns.name.Name object, or it may be a string. In the either case, + if the name is relative it is treated as relative to the origin of + the zone. + + @ivar rdclass: The zone's rdata class; the default is class IN. + @type rdclass: int + @ivar origin: The origin of the zone. + @type origin: dns.name.Name object + @ivar nodes: A dictionary mapping the names of nodes in the zone to the + nodes themselves. + @type nodes: dict + @ivar relativize: should names in the zone be relativized? + @type relativize: bool + @cvar node_factory: the factory used to create a new node + @type node_factory: class or callable + """ + + node_factory = dns.node.Node + + __slots__ = ['rdclass', 'origin', 'nodes', 'relativize'] + + def __init__(self, origin, rdclass=dns.rdataclass.IN, relativize=True): + """Initialize a zone object. + + @param origin: The origin of the zone. + @type origin: dns.name.Name object + @param rdclass: The zone's rdata class; the default is class IN. + @type rdclass: int""" + + self.rdclass = rdclass + self.origin = origin + self.nodes = {} + self.relativize = relativize + + def __eq__(self, other): + """Two zones are equal if they have the same origin, class, and + nodes. + @rtype: bool + """ + + if not isinstance(other, Zone): + return False + if self.rdclass != other.rdclass or \ + self.origin != other.origin or \ + self.nodes != other.nodes: + return False + return True + + def __ne__(self, other): + """Are two zones not equal? + @rtype: bool + """ + + return not self.__eq__(other) + + def _validate_name(self, name): + if isinstance(name, (str, unicode)): + name = dns.name.from_text(name, None) + elif not isinstance(name, dns.name.Name): + raise KeyError("name parameter must be convertable to a DNS name") + if name.is_absolute(): + if not name.is_subdomain(self.origin): + raise KeyError("name parameter must be a subdomain of the zone origin") + if self.relativize: + name = name.relativize(self.origin) + return name + + def __getitem__(self, key): + key = self._validate_name(key) + return self.nodes[key] + + def __setitem__(self, key, value): + key = self._validate_name(key) + self.nodes[key] = value + + def __delitem__(self, key): + key = self._validate_name(key) + del self.nodes[key] + + def __iter__(self): + return self.nodes.iterkeys() + + def iterkeys(self): + return self.nodes.iterkeys() + + def keys(self): + return self.nodes.keys() + + def itervalues(self): + return self.nodes.itervalues() + + def values(self): + return self.nodes.values() + + def iteritems(self): + return self.nodes.iteritems() + + def items(self): + return self.nodes.items() + + def get(self, key): + key = self._validate_name(key) + return self.nodes.get(key) + + def __contains__(self, other): + return other in self.nodes + + def find_node(self, name, create=False): + """Find a node in the zone, possibly creating it. + + @param name: the name of the node to find + @type name: dns.name.Name object or string + @param create: should the node be created if it doesn't exist? + @type create: bool + @raises KeyError: the name is not known and create was not specified. + @rtype: dns.node.Node object + """ + + name = self._validate_name(name) + node = self.nodes.get(name) + if node is None: + if not create: + raise KeyError + node = self.node_factory() + self.nodes[name] = node + return node + + def get_node(self, name, create=False): + """Get a node in the zone, possibly creating it. + + This method is like L{find_node}, except it returns None instead + of raising an exception if the node does not exist and creation + has not been requested. + + @param name: the name of the node to find + @type name: dns.name.Name object or string + @param create: should the node be created if it doesn't exist? + @type create: bool + @rtype: dns.node.Node object or None + """ + + try: + node = self.find_node(name, create) + except KeyError: + node = None + return node + + def delete_node(self, name): + """Delete the specified node if it exists. + + It is not an error if the node does not exist. + """ + + name = self._validate_name(name) + if self.nodes.has_key(name): + del self.nodes[name] + + def find_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE, + create=False): + """Look for rdata with the specified name and type in the zone, + and return an rdataset encapsulating it. + + The I{name}, I{rdtype}, and I{covers} parameters may be + strings, in which case they will be converted to their proper + type. + + The rdataset returned is not a copy; changes to it will change + the zone. + + KeyError is raised if the name or type are not found. + Use L{get_rdataset} if you want to have None returned instead. + + @param name: the owner name to look for + @type name: DNS.name.Name object or string + @param rdtype: the rdata type desired + @type rdtype: int or string + @param covers: the covered type (defaults to None) + @type covers: int or string + @param create: should the node and rdataset be created if they do not + exist? + @type create: bool + @raises KeyError: the node or rdata could not be found + @rtype: dns.rrset.RRset object + """ + + name = self._validate_name(name) + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, str): + covers = dns.rdatatype.from_text(covers) + node = self.find_node(name, create) + return node.find_rdataset(self.rdclass, rdtype, covers, create) + + def get_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE, + create=False): + """Look for rdata with the specified name and type in the zone, + and return an rdataset encapsulating it. + + The I{name}, I{rdtype}, and I{covers} parameters may be + strings, in which case they will be converted to their proper + type. + + The rdataset returned is not a copy; changes to it will change + the zone. + + None is returned if the name or type are not found. + Use L{find_rdataset} if you want to have KeyError raised instead. + + @param name: the owner name to look for + @type name: DNS.name.Name object or string + @param rdtype: the rdata type desired + @type rdtype: int or string + @param covers: the covered type (defaults to None) + @type covers: int or string + @param create: should the node and rdataset be created if they do not + exist? + @type create: bool + @rtype: dns.rrset.RRset object + """ + + try: + rdataset = self.find_rdataset(name, rdtype, covers, create) + except KeyError: + rdataset = None + return rdataset + + def delete_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE): + """Delete the rdataset matching I{rdtype} and I{covers}, if it + exists at the node specified by I{name}. + + The I{name}, I{rdtype}, and I{covers} parameters may be + strings, in which case they will be converted to their proper + type. + + It is not an error if the node does not exist, or if there is no + matching rdataset at the node. + + If the node has no rdatasets after the deletion, it will itself + be deleted. + + @param name: the owner name to look for + @type name: DNS.name.Name object or string + @param rdtype: the rdata type desired + @type rdtype: int or string + @param covers: the covered type (defaults to None) + @type covers: int or string + """ + + name = self._validate_name(name) + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, str): + covers = dns.rdatatype.from_text(covers) + node = self.get_node(name) + if not node is None: + node.delete_rdataset(self.rdclass, rdtype, covers) + if len(node) == 0: + self.delete_node(name) + + def replace_rdataset(self, name, replacement): + """Replace an rdataset at name. + + It is not an error if there is no rdataset matching I{replacement}. + + Ownership of the I{replacement} object is transferred to the zone; + in other words, this method does not store a copy of I{replacement} + at the node, it stores I{replacement} itself. + + If the I{name} node does not exist, it is created. + + @param name: the owner name + @type name: DNS.name.Name object or string + @param replacement: the replacement rdataset + @type replacement: dns.rdataset.Rdataset + """ + + if replacement.rdclass != self.rdclass: + raise ValueError('replacement.rdclass != zone.rdclass') + node = self.find_node(name, True) + node.replace_rdataset(replacement) + + def find_rrset(self, name, rdtype, covers=dns.rdatatype.NONE): + """Look for rdata with the specified name and type in the zone, + and return an RRset encapsulating it. + + The I{name}, I{rdtype}, and I{covers} parameters may be + strings, in which case they will be converted to their proper + type. + + This method is less efficient than the similar + L{find_rdataset} because it creates an RRset instead of + returning the matching rdataset. It may be more convenient + for some uses since it returns an object which binds the owner + name to the rdata. + + This method may not be used to create new nodes or rdatasets; + use L{find_rdataset} instead. + + KeyError is raised if the name or type are not found. + Use L{get_rrset} if you want to have None returned instead. + + @param name: the owner name to look for + @type name: DNS.name.Name object or string + @param rdtype: the rdata type desired + @type rdtype: int or string + @param covers: the covered type (defaults to None) + @type covers: int or string + @raises KeyError: the node or rdata could not be found + @rtype: dns.rrset.RRset object + """ + + name = self._validate_name(name) + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, str): + covers = dns.rdatatype.from_text(covers) + rdataset = self.nodes[name].find_rdataset(self.rdclass, rdtype, covers) + rrset = dns.rrset.RRset(name, self.rdclass, rdtype, covers) + rrset.update(rdataset) + return rrset + + def get_rrset(self, name, rdtype, covers=dns.rdatatype.NONE): + """Look for rdata with the specified name and type in the zone, + and return an RRset encapsulating it. + + The I{name}, I{rdtype}, and I{covers} parameters may be + strings, in which case they will be converted to their proper + type. + + This method is less efficient than the similar L{get_rdataset} + because it creates an RRset instead of returning the matching + rdataset. It may be more convenient for some uses since it + returns an object which binds the owner name to the rdata. + + This method may not be used to create new nodes or rdatasets; + use L{find_rdataset} instead. + + None is returned if the name or type are not found. + Use L{find_rrset} if you want to have KeyError raised instead. + + @param name: the owner name to look for + @type name: DNS.name.Name object or string + @param rdtype: the rdata type desired + @type rdtype: int or string + @param covers: the covered type (defaults to None) + @type covers: int or string + @rtype: dns.rrset.RRset object + """ + + try: + rrset = self.find_rrset(name, rdtype, covers) + except KeyError: + rrset = None + return rrset + + def iterate_rdatasets(self, rdtype=dns.rdatatype.ANY, + covers=dns.rdatatype.NONE): + """Return a generator which yields (name, rdataset) tuples for + all rdatasets in the zone which have the specified I{rdtype} + and I{covers}. If I{rdtype} is dns.rdatatype.ANY, the default, + then all rdatasets will be matched. + + @param rdtype: int or string + @type rdtype: int or string + @param covers: the covered type (defaults to None) + @type covers: int or string + """ + + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, str): + covers = dns.rdatatype.from_text(covers) + for (name, node) in self.iteritems(): + for rds in node: + if rdtype == dns.rdatatype.ANY or \ + (rds.rdtype == rdtype and rds.covers == covers): + yield (name, rds) + + def iterate_rdatas(self, rdtype=dns.rdatatype.ANY, + covers=dns.rdatatype.NONE): + """Return a generator which yields (name, ttl, rdata) tuples for + all rdatas in the zone which have the specified I{rdtype} + and I{covers}. If I{rdtype} is dns.rdatatype.ANY, the default, + then all rdatas will be matched. + + @param rdtype: int or string + @type rdtype: int or string + @param covers: the covered type (defaults to None) + @type covers: int or string + """ + + if isinstance(rdtype, str): + rdtype = dns.rdatatype.from_text(rdtype) + if isinstance(covers, str): + covers = dns.rdatatype.from_text(covers) + for (name, node) in self.iteritems(): + for rds in node: + if rdtype == dns.rdatatype.ANY or \ + (rds.rdtype == rdtype and rds.covers == covers): + for rdata in rds: + yield (name, rds.ttl, rdata) + + def to_file(self, f, sorted=True, relativize=True, nl=None): + """Write a zone to a file. + + @param f: file or string. If I{f} is a string, it is treated + as the name of a file to open. + @param sorted: if True, the file will be written with the + names sorted in DNSSEC order from least to greatest. Otherwise + the names will be written in whatever order they happen to have + in the zone's dictionary. + @param relativize: if True, domain names in the output will be + relativized to the zone's origin (if possible). + @type relativize: bool + @param nl: The end of line string. If not specified, the + output will use the platform's native end-of-line marker (i.e. + LF on POSIX, CRLF on Windows, CR on Macintosh). + @type nl: string or None + """ + + if sys.hexversion >= 0x02030000: + # allow Unicode filenames + str_type = basestring + else: + str_type = str + if nl is None: + opts = 'w' + else: + opts = 'wb' + if isinstance(f, str_type): + f = file(f, opts) + want_close = True + else: + want_close = False + try: + if sorted: + names = self.keys() + names.sort() + else: + names = self.iterkeys() + for n in names: + l = self[n].to_text(n, origin=self.origin, + relativize=relativize) + if nl is None: + print >> f, l + else: + f.write(l) + f.write(nl) + finally: + if want_close: + f.close() + + def check_origin(self): + """Do some simple checking of the zone's origin. + + @raises dns.zone.NoSOA: there is no SOA RR + @raises dns.zone.NoNS: there is no NS RRset + @raises KeyError: there is no origin node + """ + if self.relativize: + name = dns.name.empty + else: + name = self.origin + if self.get_rdataset(name, dns.rdatatype.SOA) is None: + raise NoSOA + if self.get_rdataset(name, dns.rdatatype.NS) is None: + raise NoNS + + +class _MasterReader(object): + """Read a DNS master file + + @ivar tok: The tokenizer + @type tok: dns.tokenizer.Tokenizer object + @ivar ttl: The default TTL + @type ttl: int + @ivar last_name: The last name read + @type last_name: dns.name.Name object + @ivar current_origin: The current origin + @type current_origin: dns.name.Name object + @ivar relativize: should names in the zone be relativized? + @type relativize: bool + @ivar zone: the zone + @type zone: dns.zone.Zone object + @ivar saved_state: saved reader state (used when processing $INCLUDE) + @type saved_state: list of (tokenizer, current_origin, last_name, file) + tuples. + @ivar current_file: the file object of the $INCLUDed file being parsed + (None if no $INCLUDE is active). + @ivar allow_include: is $INCLUDE allowed? + @type allow_include: bool + @ivar check_origin: should sanity checks of the origin node be done? + The default is True. + @type check_origin: bool + """ + + def __init__(self, tok, origin, rdclass, relativize, zone_factory=Zone, + allow_include=False, check_origin=True): + if isinstance(origin, (str, unicode)): + origin = dns.name.from_text(origin) + self.tok = tok + self.current_origin = origin + self.relativize = relativize + self.ttl = 0 + self.last_name = None + self.zone = zone_factory(origin, rdclass, relativize=relativize) + self.saved_state = [] + self.current_file = None + self.allow_include = allow_include + self.check_origin = check_origin + + def _eat_line(self): + while 1: + token = self.tok.get() + if token.is_eol_or_eof(): + break + + def _rr_line(self): + """Process one line from a DNS master file.""" + # Name + if self.current_origin is None: + raise UnknownOrigin + token = self.tok.get(want_leading = True) + if not token.is_whitespace(): + self.last_name = dns.name.from_text(token.value, self.current_origin) + else: + token = self.tok.get() + if token.is_eol_or_eof(): + # treat leading WS followed by EOL/EOF as if they were EOL/EOF. + return + self.tok.unget(token) + name = self.last_name + if not name.is_subdomain(self.zone.origin): + self._eat_line() + return + if self.relativize: + name = name.relativize(self.zone.origin) + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError + # TTL + try: + ttl = dns.ttl.from_text(token.value) + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError + except dns.ttl.BadTTL: + ttl = self.ttl + # Class + try: + rdclass = dns.rdataclass.from_text(token.value) + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError + except dns.exception.SyntaxError: + raise dns.exception.SyntaxError + except: + rdclass = self.zone.rdclass + if rdclass != self.zone.rdclass: + raise dns.exception.SyntaxError("RR class is not zone's class") + # Type + try: + rdtype = dns.rdatatype.from_text(token.value) + except: + raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) + n = self.zone.nodes.get(name) + if n is None: + n = self.zone.node_factory() + self.zone.nodes[name] = n + try: + rd = dns.rdata.from_text(rdclass, rdtype, self.tok, + self.current_origin, False) + except dns.exception.SyntaxError: + # Catch and reraise. + (ty, va) = sys.exc_info()[:2] + raise va + except: + # All exceptions that occur in the processing of rdata + # are treated as syntax errors. This is not strictly + # correct, but it is correct almost all of the time. + # We convert them to syntax errors so that we can emit + # helpful filename:line info. + (ty, va) = sys.exc_info()[:2] + raise dns.exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) + + rd.choose_relativity(self.zone.origin, self.relativize) + covers = rd.covers() + rds = n.find_rdataset(rdclass, rdtype, covers, True) + rds.add(rd, ttl) + + def read(self): + """Read a DNS master file and build a zone object. + + @raises dns.zone.NoSOA: No SOA RR was found at the zone origin + @raises dns.zone.NoNS: No NS RRset was found at the zone origin + """ + + try: + while 1: + token = self.tok.get(True, True).unescape() + if token.is_eof(): + if not self.current_file is None: + self.current_file.close() + if len(self.saved_state) > 0: + (self.tok, + self.current_origin, + self.last_name, + self.current_file, + self.ttl) = self.saved_state.pop(-1) + continue + break + elif token.is_eol(): + continue + elif token.is_comment(): + self.tok.get_eol() + continue + elif token.value[0] == '$': + u = token.value.upper() + if u == '$TTL': + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError("bad $TTL") + self.ttl = dns.ttl.from_text(token.value) + self.tok.get_eol() + elif u == '$ORIGIN': + self.current_origin = self.tok.get_name() + self.tok.get_eol() + if self.zone.origin is None: + self.zone.origin = self.current_origin + elif u == '$INCLUDE' and self.allow_include: + token = self.tok.get() + if not token.is_quoted_string(): + raise dns.exception.SyntaxError("bad filename in $INCLUDE") + filename = token.value + token = self.tok.get() + if token.is_identifier(): + new_origin = dns.name.from_text(token.value, \ + self.current_origin) + self.tok.get_eol() + elif not token.is_eol_or_eof(): + raise dns.exception.SyntaxError("bad origin in $INCLUDE") + else: + new_origin = self.current_origin + self.saved_state.append((self.tok, + self.current_origin, + self.last_name, + self.current_file, + self.ttl)) + self.current_file = file(filename, 'r') + self.tok = dns.tokenizer.Tokenizer(self.current_file, + filename) + self.current_origin = new_origin + else: + raise dns.exception.SyntaxError("Unknown master file directive '" + u + "'") + continue + self.tok.unget(token) + self._rr_line() + except dns.exception.SyntaxError, detail: + (filename, line_number) = self.tok.where() + if detail is None: + detail = "syntax error" + raise dns.exception.SyntaxError("%s:%d: %s" % (filename, line_number, detail)) + + # Now that we're done reading, do some basic checking of the zone. + if self.check_origin: + self.zone.check_origin() + +def from_text(text, origin = None, rdclass = dns.rdataclass.IN, + relativize = True, zone_factory=Zone, filename=None, + allow_include=False, check_origin=True): + """Build a zone object from a master file format string. + + @param text: the master file format input + @type text: string. + @param origin: The origin of the zone; if not specified, the first + $ORIGIN statement in the master file will determine the origin of the + zone. + @type origin: dns.name.Name object or string + @param rdclass: The zone's rdata class; the default is class IN. + @type rdclass: int + @param relativize: should names be relativized? The default is True + @type relativize: bool + @param zone_factory: The zone factory to use + @type zone_factory: function returning a Zone + @param filename: The filename to emit when describing where an error + occurred; the default is '<string>'. + @type filename: string + @param allow_include: is $INCLUDE allowed? + @type allow_include: bool + @param check_origin: should sanity checks of the origin node be done? + The default is True. + @type check_origin: bool + @raises dns.zone.NoSOA: No SOA RR was found at the zone origin + @raises dns.zone.NoNS: No NS RRset was found at the zone origin + @rtype: dns.zone.Zone object + """ + + # 'text' can also be a file, but we don't publish that fact + # since it's an implementation detail. The official file + # interface is from_file(). + + if filename is None: + filename = '<string>' + tok = dns.tokenizer.Tokenizer(text, filename) + reader = _MasterReader(tok, origin, rdclass, relativize, zone_factory, + allow_include=allow_include, + check_origin=check_origin) + reader.read() + return reader.zone + +def from_file(f, origin = None, rdclass = dns.rdataclass.IN, + relativize = True, zone_factory=Zone, filename=None, + allow_include=True, check_origin=True): + """Read a master file and build a zone object. + + @param f: file or string. If I{f} is a string, it is treated + as the name of a file to open. + @param origin: The origin of the zone; if not specified, the first + $ORIGIN statement in the master file will determine the origin of the + zone. + @type origin: dns.name.Name object or string + @param rdclass: The zone's rdata class; the default is class IN. + @type rdclass: int + @param relativize: should names be relativized? The default is True + @type relativize: bool + @param zone_factory: The zone factory to use + @type zone_factory: function returning a Zone + @param filename: The filename to emit when describing where an error + occurred; the default is '<file>', or the value of I{f} if I{f} is a + string. + @type filename: string + @param allow_include: is $INCLUDE allowed? + @type allow_include: bool + @param check_origin: should sanity checks of the origin node be done? + The default is True. + @type check_origin: bool + @raises dns.zone.NoSOA: No SOA RR was found at the zone origin + @raises dns.zone.NoNS: No NS RRset was found at the zone origin + @rtype: dns.zone.Zone object + """ + + if sys.hexversion >= 0x02030000: + # allow Unicode filenames; turn on universal newline support + str_type = basestring + opts = 'rU' + else: + str_type = str + opts = 'r' + if isinstance(f, str_type): + if filename is None: + filename = f + f = file(f, opts) + want_close = True + else: + if filename is None: + filename = '<file>' + want_close = False + + try: + z = from_text(f, origin, rdclass, relativize, zone_factory, + filename, allow_include, check_origin) + finally: + if want_close: + f.close() + return z + +def from_xfr(xfr, zone_factory=Zone, relativize=True): + """Convert the output of a zone transfer generator into a zone object. + + @param xfr: The xfr generator + @type xfr: generator of dns.message.Message objects + @param relativize: should names be relativized? The default is True. + It is essential that the relativize setting matches the one specified + to dns.query.xfr(). + @type relativize: bool + @raises dns.zone.NoSOA: No SOA RR was found at the zone origin + @raises dns.zone.NoNS: No NS RRset was found at the zone origin + @rtype: dns.zone.Zone object + """ + + z = None + for r in xfr: + if z is None: + if relativize: + origin = r.origin + else: + origin = r.answer[0].name + rdclass = r.answer[0].rdclass + z = zone_factory(origin, rdclass, relativize=relativize) + for rrset in r.answer: + znode = z.nodes.get(rrset.name) + if not znode: + znode = z.node_factory() + z.nodes[rrset.name] = znode + zrds = znode.find_rdataset(rrset.rdclass, rrset.rdtype, + rrset.covers, True) + zrds.update_ttl(rrset.ttl) + for rd in rrset: + rd.choose_relativity(z.origin, relativize) + zrds.add(rd) + z.check_origin() + return z diff --git a/source4/scripting/python/samba_external/dnspython/examples/ddns.py b/source4/scripting/python/samba_external/dnspython/examples/ddns.py new file mode 100755 index 0000000000..84814b73cf --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/examples/ddns.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +# +# Use a TSIG-signed DDNS update to update our hostname-to-address +# mapping. +# +# usage: ddns.py <ip-address> +# +# On linux systems, you can automatically update your DNS any time an +# interface comes up by adding an ifup-local script that invokes this +# python code. +# +# E.g. on my systems I have this +# +# #!/bin/sh +# +# DEVICE=$1 +# +# if [ "X${DEVICE}" == "Xeth0" ]; then +# IPADDR=`LANG= LC_ALL= ifconfig ${DEVICE} | grep 'inet addr' | +# awk -F: '{ print $2 } ' | awk '{ print $1 }'` +# /usr/local/sbin/ddns.py $IPADDR +# fi +# +# in /etc/ifup-local. +# + +import sys + +import dns.update +import dns.query +import dns.tsigkeyring + +# +# Replace the keyname and secret with appropriate values for your +# configuration. +# +keyring = dns.tsigkeyring.from_text({ + 'keyname.' : 'NjHwPsMKjdN++dOfE5iAiQ==' + }) + +# +# Replace "example." with your domain, and "host" with your hostname. +# +update = dns.update.Update('example.', keyring=keyring) +update.replace('host', 300, 'A', sys.argv[1]) + +# +# Replace "10.0.0.1" with the IP address of your master server. +# +response = dns.query.tcp(update, '10.0.0.1', timeout=10) diff --git a/source4/scripting/python/samba_external/dnspython/examples/e164.py b/source4/scripting/python/samba_external/dnspython/examples/e164.py new file mode 100755 index 0000000000..ad40ccf84b --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/examples/e164.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +import dns.e164 +n = dns.e164.from_e164("+1 555 1212") +print n +print dns.e164.to_e164(n) diff --git a/source4/scripting/python/samba_external/dnspython/examples/mx.py b/source4/scripting/python/samba_external/dnspython/examples/mx.py new file mode 100755 index 0000000000..3036e70ddf --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/examples/mx.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +import dns.resolver + +answers = dns.resolver.query('nominum.com', 'MX') +for rdata in answers: + print 'Host', rdata.exchange, 'has preference', rdata.preference diff --git a/source4/scripting/python/samba_external/dnspython/examples/name.py b/source4/scripting/python/samba_external/dnspython/examples/name.py new file mode 100755 index 0000000000..b099c49d16 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/examples/name.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +import dns.name + +n = dns.name.from_text('www.dnspython.org') +o = dns.name.from_text('dnspython.org') +print n.is_subdomain(o) # True +print n.is_superdomain(o) # False +print n > o # True +rel = n.relativize(o) # rel is the relative name www +n2 = rel + o +print n2 == n # True +print n.labels # ['www', 'dnspython', 'org', ''] diff --git a/source4/scripting/python/samba_external/dnspython/examples/reverse.py b/source4/scripting/python/samba_external/dnspython/examples/reverse.py new file mode 100755 index 0000000000..8657baed44 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/examples/reverse.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Usage: reverse.py <zone_filename>... +# +# This demo script will load in all of the zones specified by the +# filenames on the command line, find all the A RRs in them, and +# construct a reverse mapping table that maps each IP address used to +# the list of names mapping to that address. The table is then sorted +# nicely and printed. +# +# Note! The zone name is taken from the basename of the filename, so +# you must use filenames like "/wherever/you/like/dnspython.org" and +# not something like "/wherever/you/like/foo.db" (unless you're +# working with the ".db" GTLD, of course :)). +# +# If this weren't a demo script, there'd be a way of specifying the +# origin for each zone instead of constructing it from the filename. + +import dns.zone +import dns.ipv4 +import os.path +import sys + +reverse_map = {} + +for filename in sys.argv[1:]: + zone = dns.zone.from_file(filename, os.path.basename(filename), + relativize=False) + for (name, ttl, rdata) in zone.iterate_rdatas('A'): + try: + reverse_map[rdata.address].append(name.to_text()) + except KeyError: + reverse_map[rdata.address] = [name.to_text()] + +keys = reverse_map.keys() +keys.sort(lambda a1, a2: cmp(dns.ipv4.inet_aton(a1), dns.ipv4.inet_aton(a2))) +for k in keys: + v = reverse_map[k] + v.sort() + print k, v diff --git a/source4/scripting/python/samba_external/dnspython/examples/reverse_name.py b/source4/scripting/python/samba_external/dnspython/examples/reverse_name.py new file mode 100755 index 0000000000..351896b015 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/examples/reverse_name.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +import dns.reversename +n = dns.reversename.from_address("127.0.0.1") +print n +print dns.reversename.to_address(n) diff --git a/source4/scripting/python/samba_external/dnspython/examples/xfr.py b/source4/scripting/python/samba_external/dnspython/examples/xfr.py new file mode 100755 index 0000000000..5cd6f55c06 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/examples/xfr.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import dns.query +import dns.zone + +z = dns.zone.from_xfr(dns.query.xfr('204.152.189.147', 'dnspython.org')) +names = z.nodes.keys() +names.sort() +for n in names: + print z[n].to_text(n) diff --git a/source4/scripting/python/samba_external/dnspython/setup.py b/source4/scripting/python/samba_external/dnspython/setup.py new file mode 100755 index 0000000000..12fd2f1dc6 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/setup.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# 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 sys +from distutils.core import setup + +version = '1.8.0' + +kwargs = { + 'name' : 'dnspython', + 'version' : version, + 'description' : 'DNS toolkit', + 'long_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.""", + 'author' : 'Bob Halley', + 'author_email' : 'halley@dnspython.org', + 'license' : 'BSD-like', + 'url' : 'http://www.dnspython.org', + 'packages' : ['dns', 'dns.rdtypes', 'dns.rdtypes.IN', 'dns.rdtypes.ANY'], + } + +if sys.hexversion >= 0x02020300: + kwargs['download_url'] = \ + 'http://www.dnspython.org/kits/%s/dnspython-%s.tar.gz' % (version, + version) + kwargs['classifiers'] = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "License :: Freeware", + "Operating System :: Microsoft :: Windows :: Windows 95/98/2000", + "Operating System :: POSIX", + "Programming Language :: Python", + "Topic :: Internet :: Name Service (DNS)", + "Topic :: Software Development :: Libraries :: Python Modules", + ] + +if sys.hexversion >= 0x02050000: + kwargs['requires'] = [] + kwargs['provides'] = ['dns'] + +setup(**kwargs) diff --git a/source4/scripting/python/samba_external/dnspython/tests/Makefile b/source4/scripting/python/samba_external/dnspython/tests/Makefile new file mode 100644 index 0000000000..584f6a7da7 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/Makefile @@ -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 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. + +# $Id: Makefile,v 1.5 2004/03/19 00:17:27 halley Exp $ + +PYTHON=python + +check: test + +test: + @for i in *.py; do \ + echo "Running $$i:"; \ + ${PYTHON} $$i || exit 1; \ + done diff --git a/source4/scripting/python/samba_external/dnspython/tests/bugs.py b/source4/scripting/python/samba_external/dnspython/tests/bugs.py new file mode 100644 index 0000000000..0896e3f02d --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/bugs.py @@ -0,0 +1,44 @@ +# Copyright (C) 2006, 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 unittest + +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.ttl + +class BugsTestCase(unittest.TestCase): + + def test_float_LOC(self): + rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.LOC, + "30 30 0.000 N 100 30 0.000 W 10.00m 20m 2000m 20m") + self.failUnless(rdata.float_latitude == 30.5) + self.failUnless(rdata.float_longitude == -100.5) + + def test_SOA_BIND8_TTL(self): + rdata1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + "a b 100 1s 1m 1h 1d") + rdata2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + "a b 100 1 60 3600 86400") + self.failUnless(rdata1 == rdata2) + + def test_TTL_bounds_check(self): + def bad(): + ttl = dns.ttl.from_text("2147483648") + self.failUnlessRaises(dns.ttl.BadTTL, bad) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/example b/source4/scripting/python/samba_external/dnspython/tests/example new file mode 100644 index 0000000000..d87c63a393 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/example @@ -0,0 +1,225 @@ +; Copyright (C) 2000, 2001 Internet Software Consortium. +; +; Permission to use, copy, modify, and distribute this software 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 INTERNET SOFTWARE CONSORTIUM +; DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +; INTERNET SOFTWARE CONSORTIUM 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. + +; $Id: example,v 1.13 2004/03/19 00:06:37 halley Exp $ + +$ORIGIN . +$TTL 300 ; 5 minutes +example IN SOA ns1.example. hostmaster.example. ( + 1 ; serial + 2000 ; refresh (2000 seconds) + 2000 ; retry (2000 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) +example. NS ns1.example. +ns1.example. A 10.53.0.1 +example. NS ns2.example. +ns2.example. A 10.53.0.2 + +$ORIGIN example. +* MX 10 mail +a TXT "foo foo foo" + PTR foo.net. +;; The next line not starting with ';;' is leading whitespace followed by +;; EOL. We want to treat that as if EOL had appeared alone. + +;; The next line not starting with ';;' is leading whitespace followed by +;; a comment followed by EOL. We want to treat that as if EOL had appeared +;; alone. + ; foo +$TTL 3600 ; 1 hour +a01 A 0.0.0.0 +a02 A 255.255.255.255 +;; +;; XXXRTH dnspython doesn't currently implement A6, and since +;; A6 records are effectively dead, it may never do so. +;; +;;a601 A6 0 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +;; A6 64 ::ffff:ffff:ffff:ffff foo. +;; A6 127 ::1 foo. +;; A6 128 . +aaaa01 AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +aaaa02 AAAA ::1 +afsdb01 AFSDB 0 hostname +afsdb02 AFSDB 65535 . +$TTL 300 ; 5 minutes +b CNAME foo.net. +c A 73.80.65.49 +$TTL 3600 ; 1 hour +cert01 CERT 65534 65535 PRIVATEOID ( + MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi + WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl + d80jEeC8aTrO+KKmCaY= ) +cname01 CNAME cname-target. +cname02 CNAME cname-target +cname03 CNAME . +$TTL 300 ; 5 minutes +d A 73.80.65.49 +$TTL 3600 ; 1 hour +dhcid01 DHCID ( AAIBY2/AuCccgoJbsaxcQc9TUapptP69l + OjxfNuVAA2kjEA= ) +dhcid02 DHCID ( AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdW + L3b/NaiUDlW2No= ) +dhcid03 DHCID ( AAABxLmlskllE0MVjd57zHcWmEH3pCQ6V + ytcKD//7es/deY= ) +dname01 DNAME dname-target. +dname02 DNAME dname-target +dname03 DNAME . +$TTL 300 ; 5 minutes +e MX 10 mail + TXT "one" + TXT "three" + TXT "two" + A 73.80.65.49 + A 73.80.65.50 + A 73.80.65.52 + A 73.80.65.51 +f A 73.80.65.52 +$TTL 3600 ; 1 hour +gpos01 GPOS "-22.6882" "116.8652" "250.0" +;; +;; XXXRTH I have commented out the following line because I don't think +;; it is a valid GPOS record. +;; +;;gpos02 GPOS "" "" "" +hinfo01 HINFO "Generic PC clone" "NetBSD-1.4" +hinfo02 HINFO "PC" "NetBSD" +isdn01 ISDN "isdn-address" +isdn02 ISDN "isdn-address" "subaddress" +isdn03 ISDN "isdn-address" +isdn04 ISDN "isdn-address" "subaddress" +key01 KEY 512 255 1 ( + AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR + yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 + GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o + jqf0BaqHT+8= ) +key02 KEY HOST|FLAG4 DNSSEC RSAMD5 ( + AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR + yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 + GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o + jqf0BaqHT+8= ) +kx01 KX 10 kdc +kx02 KX 10 . +loc01 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20m 2000m 20m +loc02 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20m 2000m 20m +loc03 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000m 20m +loc04 LOC 60 9 1.5 N 24 39 0.000 E 10.00m 20m 2000m 20m +loc05 LOC 60 9 1.51 N 24 39 0.000 E 10.00m 20m 2000m 20m +;; +;; XXXRTH These are all obsolete and unused. dnspython doesn't implement +;; them +;;mb01 MG madname +;;mb02 MG . +;;mg01 MG mgmname +;;mg02 MG . +;;minfo01 MINFO rmailbx emailbx +;;minfo02 MINFO . . +;;mr01 MR mrname +;;mr02 MR . +mx01 MX 10 mail +mx02 MX 10 . +naptr01 NAPTR 0 0 "" "" "" . +naptr02 NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo. +nsap-ptr01 NSAP-PTR foo. + NSAP-PTR . +nsap01 NSAP 0x47000580005a0000000001e133ffffff00016100 +nsap02 NSAP 0x47.000580005a0000000001e133ffffff000161.00 +nxt01 NXT a.secure ( NS SOA MX SIG KEY LOC NXT ) +nxt02 NXT . ( NSAP-PTR NXT ) +nxt03 NXT . ( A ) +nxt04 NXT . ( 127 ) +ptr01 PTR example. +px01 PX 65535 foo. bar. +px02 PX 65535 . . +rp01 RP mbox-dname txt-dname +rp02 RP . . +rt01 RT 0 intermediate-host +rt02 RT 65535 . +$TTL 300 ; 5 minutes +s NS ns.s +$ORIGIN s.example. +ns A 73.80.65.49 +$ORIGIN example. +$TTL 3600 ; 1 hour +sig01 SIG NXT 1 3 3600 ( + 20200101000000 20030101000000 2143 foo + MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi + WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl + d80jEeC8aTrO+KKmCaY= ) +srv01 SRV 0 0 0 . +srv02 SRV 65535 65535 65535 old-slow-box.example.com. +$TTL 301 ; 5 minutes 1 second +t A 73.80.65.49 +$TTL 3600 ; 1 hour +txt01 TXT "foo" +txt02 TXT "foo" "bar" +txt03 TXT "foo" +txt04 TXT "foo" "bar" +txt05 TXT "foo bar" +txt06 TXT "foo bar" +txt07 TXT "foo bar" +txt08 TXT "foo\010bar" +txt09 TXT "foo\010bar" +txt10 TXT "foo bar" +txt11 TXT "\"foo\"" +txt12 TXT "\"foo\"" +txt13 TXT foo +$TTL 300 ; 5 minutes +u TXT "txt-not-in-nxt" +$ORIGIN u.example. +a A 73.80.65.49 +b A 73.80.65.49 +$ORIGIN example. +$TTL 3600 ; 1 hour +wks01 WKS 10.0.0.1 6 ( 0 1 2 21 23 ) +wks02 WKS 10.0.0.1 17 ( 0 1 2 53 ) +wks03 WKS 10.0.0.2 6 ( 65535 ) +x2501 X25 "123456789" +dlv01 DLV 12345 3 1 123456789abcdef67890123456789abcdef67890 +ds01 DS 12345 3 1 123456789abcdef67890123456789abcdef67890 +apl01 APL 1:192.168.32.0/21 !1:192.168.38.0/28 +apl02 APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 +unknown2 TYPE999 \# 8 0a0000010a000001 +rrsig01 RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/ vILz45IkskceFGgiWCn/GxHhai6V AuHAoNUz4YoU1tVfSCSqQYn6//11 U6Nld80jEeC8aTrO+KKmCaY= +nsec01 NSEC a.secure. A MX RRSIG NSEC TYPE1234 +nsec02 NSEC . NSAP-PTR NSEC +nsec03 NSEC . NSEC TYPE65535 +dnskey01 DNSKEY 512 255 1 ( + AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR + yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 + GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o + jqf0BaqHT+8= ) +dnskey02 DNSKEY HOST|FLAG4 DNSSEC RSAMD5 ( + AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR + yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 + GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o + jqf0BaqHT+8= ) +; +; test known type using unknown RR syntax +; +unknown3 A \# 4 7f000002 +sshfp1 SSHFP 1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab +spf SPF "v=spf1 mx -all" +ipseckey01 IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== +ipseckey02 IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== +ipseckey03 IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== +ipseckey04 IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== +ipseckey05 IPSECKEY 10 3 2 mygateway2 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== +nsec301 NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG +nsec302 NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG +nsec3param01 NSEC3PARAM 1 1 12 aabbccdd +nsec3param02 NSEC3PARAM 1 1 12 - +hip01 HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2 diff --git a/source4/scripting/python/samba_external/dnspython/tests/example1.good b/source4/scripting/python/samba_external/dnspython/tests/example1.good new file mode 100644 index 0000000000..ca5ead6379 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/example1.good @@ -0,0 +1,121 @@ +@ 300 IN SOA ns1 hostmaster 1 2000 2000 1814400 3600 +@ 300 IN NS ns1 +@ 300 IN NS ns2 +* 300 IN MX 10 mail +a 300 IN TXT "foo foo foo" +a 300 IN PTR foo.net. +a01 3600 IN A 0.0.0.0 +a02 3600 IN A 255.255.255.255 +aaaa01 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +aaaa02 3600 IN AAAA ::1 +afsdb01 3600 IN AFSDB 0 hostname +afsdb02 3600 IN AFSDB 65535 . +apl01 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28 +apl02 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 +b 300 IN CNAME foo.net. +c 300 IN A 73.80.65.49 +cert01 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= +cname01 3600 IN CNAME cname-target. +cname02 3600 IN CNAME cname-target +cname03 3600 IN CNAME . +d 300 IN A 73.80.65.49 +dhcid01 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA= +dhcid02 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No= +dhcid03 3600 IN DHCID AAABxLmlskllE0MVjd57zHcWmEH3pCQ6 VytcKD//7es/deY= +dlv01 3600 IN DLV 12345 3 1 123456789abcdef67890123456789abcdef67890 +dname01 3600 IN DNAME dname-target. +dname02 3600 IN DNAME dname-target +dname03 3600 IN DNAME . +dnskey01 3600 IN DNSKEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +dnskey02 3600 IN DNSKEY 2560 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +ds01 3600 IN DS 12345 3 1 123456789abcdef67890123456789abcdef67890 +e 300 IN MX 10 mail +e 300 IN TXT "one" +e 300 IN TXT "three" +e 300 IN TXT "two" +e 300 IN A 73.80.65.49 +e 300 IN A 73.80.65.50 +e 300 IN A 73.80.65.52 +e 300 IN A 73.80.65.51 +f 300 IN A 73.80.65.52 +gpos01 3600 IN GPOS -22.6882 116.8652 250.0 +hinfo01 3600 IN HINFO "Generic PC clone" "NetBSD-1.4" +hinfo02 3600 IN HINFO "PC" "NetBSD" +hip01 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2 +ipseckey01 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +ipseckey02 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +ipseckey03 3600 IN IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +ipseckey04 3600 IN IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +ipseckey05 3600 IN IPSECKEY 10 3 2 mygateway2 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +isdn01 3600 IN ISDN "isdn-address" +isdn02 3600 IN ISDN "isdn-address" "subaddress" +isdn03 3600 IN ISDN "isdn-address" +isdn04 3600 IN ISDN "isdn-address" "subaddress" +key01 3600 IN KEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +key02 3600 IN KEY 2560 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +kx01 3600 IN KX 10 kdc +kx02 3600 IN KX 10 . +loc01 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m +loc02 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m +loc03 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m +loc04 3600 IN LOC 60 9 1.500 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m +loc05 3600 IN LOC 60 9 1.510 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m +mx01 3600 IN MX 10 mail +mx02 3600 IN MX 10 . +naptr01 3600 IN NAPTR 0 0 "" "" "" . +naptr02 3600 IN NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo. +ns1 300 IN A 10.53.0.1 +ns2 300 IN A 10.53.0.2 +nsap-ptr01 3600 IN NSAP-PTR foo. +nsap-ptr01 3600 IN NSAP-PTR . +nsap01 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 +nsap02 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 +nsec01 3600 IN NSEC a.secure. A MX RRSIG NSEC TYPE1234 +nsec02 3600 IN NSEC . NSAP-PTR NSEC +nsec03 3600 IN NSEC . NSEC TYPE65535 +nsec301 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM +nsec302 3600 IN NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM +nsec3param01 3600 IN NSEC3PARAM 1 1 12 aabbccdd +nsec3param02 3600 IN NSEC3PARAM 1 1 12 - +nxt01 3600 IN NXT a.secure NS SOA MX SIG KEY LOC NXT +nxt02 3600 IN NXT . NSAP-PTR NXT +nxt03 3600 IN NXT . A +nxt04 3600 IN NXT . TYPE127 +ptr01 3600 IN PTR @ +px01 3600 IN PX 65535 foo. bar. +px02 3600 IN PX 65535 . . +rp01 3600 IN RP mbox-dname txt-dname +rp02 3600 IN RP . . +rrsig01 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= +rt01 3600 IN RT 0 intermediate-host +rt02 3600 IN RT 65535 . +s 300 IN NS ns.s +ns.s 300 IN A 73.80.65.49 +sig01 3600 IN SIG NXT 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= +spf 3600 IN SPF "v=spf1 mx -all" +srv01 3600 IN SRV 0 0 0 . +srv02 3600 IN SRV 65535 65535 65535 old-slow-box.example.com. +sshfp1 3600 IN SSHFP 1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab +t 301 IN A 73.80.65.49 +txt01 3600 IN TXT "foo" +txt02 3600 IN TXT "foo" "bar" +txt03 3600 IN TXT "foo" +txt04 3600 IN TXT "foo" "bar" +txt05 3600 IN TXT "foo bar" +txt06 3600 IN TXT "foo bar" +txt07 3600 IN TXT "foo bar" +txt08 3600 IN TXT "foo\010bar" +txt09 3600 IN TXT "foo\010bar" +txt10 3600 IN TXT "foo bar" +txt11 3600 IN TXT "\"foo\"" +txt12 3600 IN TXT "\"foo\"" +txt13 3600 IN TXT "foo" +u 300 IN TXT "txt-not-in-nxt" +a.u 300 IN A 73.80.65.49 +b.u 300 IN A 73.80.65.49 +unknown2 3600 IN TYPE999 \# 8 0a0000010a000001 +unknown3 3600 IN A 127.0.0.2 +wks01 3600 IN WKS 10.0.0.1 6 0 1 2 21 23 +wks02 3600 IN WKS 10.0.0.1 17 0 1 2 53 +wks03 3600 IN WKS 10.0.0.2 6 65535 +x2501 3600 IN X25 "123456789" diff --git a/source4/scripting/python/samba_external/dnspython/tests/example2.good b/source4/scripting/python/samba_external/dnspython/tests/example2.good new file mode 100644 index 0000000000..c923c09b7c --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/example2.good @@ -0,0 +1,121 @@ +example. 300 IN SOA ns1.example. hostmaster.example. 1 2000 2000 1814400 3600 +example. 300 IN NS ns1.example. +example. 300 IN NS ns2.example. +*.example. 300 IN MX 10 mail.example. +a.example. 300 IN TXT "foo foo foo" +a.example. 300 IN PTR foo.net. +a01.example. 3600 IN A 0.0.0.0 +a02.example. 3600 IN A 255.255.255.255 +aaaa01.example. 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +aaaa02.example. 3600 IN AAAA ::1 +afsdb01.example. 3600 IN AFSDB 0 hostname.example. +afsdb02.example. 3600 IN AFSDB 65535 . +apl01.example. 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28 +apl02.example. 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 +b.example. 300 IN CNAME foo.net. +c.example. 300 IN A 73.80.65.49 +cert01.example. 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= +cname01.example. 3600 IN CNAME cname-target. +cname02.example. 3600 IN CNAME cname-target.example. +cname03.example. 3600 IN CNAME . +d.example. 300 IN A 73.80.65.49 +dhcid01.example. 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA= +dhcid02.example. 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No= +dhcid03.example. 3600 IN DHCID AAABxLmlskllE0MVjd57zHcWmEH3pCQ6 VytcKD//7es/deY= +dlv01.example. 3600 IN DLV 12345 3 1 123456789abcdef67890123456789abcdef67890 +dname01.example. 3600 IN DNAME dname-target. +dname02.example. 3600 IN DNAME dname-target.example. +dname03.example. 3600 IN DNAME . +dnskey01.example. 3600 IN DNSKEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +dnskey02.example. 3600 IN DNSKEY 2560 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +ds01.example. 3600 IN DS 12345 3 1 123456789abcdef67890123456789abcdef67890 +e.example. 300 IN MX 10 mail.example. +e.example. 300 IN TXT "one" +e.example. 300 IN TXT "three" +e.example. 300 IN TXT "two" +e.example. 300 IN A 73.80.65.49 +e.example. 300 IN A 73.80.65.50 +e.example. 300 IN A 73.80.65.52 +e.example. 300 IN A 73.80.65.51 +f.example. 300 IN A 73.80.65.52 +gpos01.example. 3600 IN GPOS -22.6882 116.8652 250.0 +hinfo01.example. 3600 IN HINFO "Generic PC clone" "NetBSD-1.4" +hinfo02.example. 3600 IN HINFO "PC" "NetBSD" +hip01.example. 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2.example. +ipseckey01.example. 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +ipseckey02.example. 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +ipseckey03.example. 3600 IN IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +ipseckey04.example. 3600 IN IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +ipseckey05.example. 3600 IN IPSECKEY 10 3 2 mygateway2.example. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== +isdn01.example. 3600 IN ISDN "isdn-address" +isdn02.example. 3600 IN ISDN "isdn-address" "subaddress" +isdn03.example. 3600 IN ISDN "isdn-address" +isdn04.example. 3600 IN ISDN "isdn-address" "subaddress" +key01.example. 3600 IN KEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +key02.example. 3600 IN KEY 2560 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= +kx01.example. 3600 IN KX 10 kdc.example. +kx02.example. 3600 IN KX 10 . +loc01.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m +loc02.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m +loc03.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m +loc04.example. 3600 IN LOC 60 9 1.500 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m +loc05.example. 3600 IN LOC 60 9 1.510 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m +mx01.example. 3600 IN MX 10 mail.example. +mx02.example. 3600 IN MX 10 . +naptr01.example. 3600 IN NAPTR 0 0 "" "" "" . +naptr02.example. 3600 IN NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo. +ns1.example. 300 IN A 10.53.0.1 +ns2.example. 300 IN A 10.53.0.2 +nsap-ptr01.example. 3600 IN NSAP-PTR foo. +nsap-ptr01.example. 3600 IN NSAP-PTR . +nsap01.example. 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 +nsap02.example. 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 +nsec01.example. 3600 IN NSEC a.secure. A MX RRSIG NSEC TYPE1234 +nsec02.example. 3600 IN NSEC . NSAP-PTR NSEC +nsec03.example. 3600 IN NSEC . NSEC TYPE65535 +nsec301.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM +nsec302.example. 3600 IN NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM +nsec3param01.example. 3600 IN NSEC3PARAM 1 1 12 aabbccdd +nsec3param02.example. 3600 IN NSEC3PARAM 1 1 12 - +nxt01.example. 3600 IN NXT a.secure.example. NS SOA MX SIG KEY LOC NXT +nxt02.example. 3600 IN NXT . NSAP-PTR NXT +nxt03.example. 3600 IN NXT . A +nxt04.example. 3600 IN NXT . TYPE127 +ptr01.example. 3600 IN PTR example. +px01.example. 3600 IN PX 65535 foo. bar. +px02.example. 3600 IN PX 65535 . . +rp01.example. 3600 IN RP mbox-dname.example. txt-dname.example. +rp02.example. 3600 IN RP . . +rrsig01.example. 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo.example. MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= +rt01.example. 3600 IN RT 0 intermediate-host.example. +rt02.example. 3600 IN RT 65535 . +s.example. 300 IN NS ns.s.example. +ns.s.example. 300 IN A 73.80.65.49 +sig01.example. 3600 IN SIG NXT 1 3 3600 20200101000000 20030101000000 2143 foo.example. MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= +spf.example. 3600 IN SPF "v=spf1 mx -all" +srv01.example. 3600 IN SRV 0 0 0 . +srv02.example. 3600 IN SRV 65535 65535 65535 old-slow-box.example.com. +sshfp1.example. 3600 IN SSHFP 1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab +t.example. 301 IN A 73.80.65.49 +txt01.example. 3600 IN TXT "foo" +txt02.example. 3600 IN TXT "foo" "bar" +txt03.example. 3600 IN TXT "foo" +txt04.example. 3600 IN TXT "foo" "bar" +txt05.example. 3600 IN TXT "foo bar" +txt06.example. 3600 IN TXT "foo bar" +txt07.example. 3600 IN TXT "foo bar" +txt08.example. 3600 IN TXT "foo\010bar" +txt09.example. 3600 IN TXT "foo\010bar" +txt10.example. 3600 IN TXT "foo bar" +txt11.example. 3600 IN TXT "\"foo\"" +txt12.example. 3600 IN TXT "\"foo\"" +txt13.example. 3600 IN TXT "foo" +u.example. 300 IN TXT "txt-not-in-nxt" +a.u.example. 300 IN A 73.80.65.49 +b.u.example. 300 IN A 73.80.65.49 +unknown2.example. 3600 IN TYPE999 \# 8 0a0000010a000001 +unknown3.example. 3600 IN A 127.0.0.2 +wks01.example. 3600 IN WKS 10.0.0.1 6 0 1 2 21 23 +wks02.example. 3600 IN WKS 10.0.0.1 17 0 1 2 53 +wks03.example. 3600 IN WKS 10.0.0.2 6 65535 +x2501.example. 3600 IN X25 "123456789" diff --git a/source4/scripting/python/samba_external/dnspython/tests/flags.py b/source4/scripting/python/samba_external/dnspython/tests/flags.py new file mode 100644 index 0000000000..7ee2d8e12e --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/flags.py @@ -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. + +import unittest + +import dns.flags +import dns.rcode +import dns.opcode + +class FlagsTestCase(unittest.TestCase): + + def test_rcode1(self): + self.failUnless(dns.rcode.from_text('FORMERR') == dns.rcode.FORMERR) + + def test_rcode2(self): + self.failUnless(dns.rcode.to_text(dns.rcode.FORMERR) == "FORMERR") + + def test_rcode3(self): + self.failUnless(dns.rcode.to_flags(dns.rcode.FORMERR) == (1, 0)) + + def test_rcode4(self): + self.failUnless(dns.rcode.to_flags(dns.rcode.BADVERS) == \ + (0, 0x01000000)) + + def test_rcode6(self): + self.failUnless(dns.rcode.from_flags(0, 0x01000000) == \ + dns.rcode.BADVERS) + + def test_rcode6(self): + self.failUnless(dns.rcode.from_flags(5, 0) == dns.rcode.REFUSED) + + def test_rcode7(self): + def bad(): + dns.rcode.to_flags(4096) + self.failUnlessRaises(ValueError, bad) + + def test_flags1(self): + self.failUnless(dns.flags.from_text("RA RD AA QR") == \ + dns.flags.QR|dns.flags.AA|dns.flags.RD|dns.flags.RA) + + def test_flags2(self): + flags = dns.flags.QR|dns.flags.AA|dns.flags.RD|dns.flags.RA + self.failUnless(dns.flags.to_text(flags) == "QR AA RD RA") + + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/message.py b/source4/scripting/python/samba_external/dnspython/tests/message.py new file mode 100644 index 0000000000..7134661d3a --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/message.py @@ -0,0 +1,179 @@ +# 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 os +import unittest + +import dns.exception +import dns.message + +query_text = """id 1234 +opcode QUERY +rcode NOERROR +flags RD +edns 0 +eflags DO +payload 4096 +;QUESTION +wwww.dnspython.org. IN A +;ANSWER +;AUTHORITY +;ADDITIONAL""" + +goodhex = '04d201000001000000000001047777777709646e73707974686f6e' \ + '036f726700000100010000291000000080000000' + +goodwire = goodhex.decode('hex_codec') + +answer_text = """id 1234 +opcode QUERY +rcode NOERROR +flags QR AA RD +;QUESTION +dnspython.org. IN SOA +;ANSWER +dnspython.org. 3600 IN SOA woof.dnspython.org. hostmaster.dnspython.org. 2003052700 3600 1800 604800 3600 +;AUTHORITY +dnspython.org. 3600 IN NS ns1.staff.nominum.org. +dnspython.org. 3600 IN NS ns2.staff.nominum.org. +dnspython.org. 3600 IN NS woof.play-bow.org. +;ADDITIONAL +woof.play-bow.org. 3600 IN A 204.152.186.150 +""" + +goodhex2 = '04d2 8500 0001 0001 0003 0001' \ + '09646e73707974686f6e036f726700 0006 0001' \ + 'c00c 0006 0001 00000e10 0028 ' \ + '04776f6f66c00c 0a686f73746d6173746572c00c' \ + '7764289c 00000e10 00000708 00093a80 00000e10' \ + 'c00c 0002 0001 00000e10 0014' \ + '036e7331057374616666076e6f6d696e756dc016' \ + 'c00c 0002 0001 00000e10 0006 036e7332c063' \ + 'c00c 0002 0001 00000e10 0010 04776f6f6608706c61792d626f77c016' \ + 'c091 0001 0001 00000e10 0004 cc98ba96' + + +goodwire2 = goodhex2.replace(' ', '').decode('hex_codec') + +query_text_2 = """id 1234 +opcode QUERY +rcode 4095 +flags RD +edns 0 +eflags DO +payload 4096 +;QUESTION +wwww.dnspython.org. IN A +;ANSWER +;AUTHORITY +;ADDITIONAL""" + +goodhex3 = '04d2010f0001000000000001047777777709646e73707974686f6e' \ + '036f726700000100010000291000ff0080000000' + +goodwire3 = goodhex3.decode('hex_codec') + +class MessageTestCase(unittest.TestCase): + + def test_comparison_eq1(self): + q1 = dns.message.from_text(query_text) + q2 = dns.message.from_text(query_text) + self.failUnless(q1 == q2) + + def test_comparison_ne1(self): + q1 = dns.message.from_text(query_text) + q2 = dns.message.from_text(query_text) + q2.id = 10 + self.failUnless(q1 != q2) + + def test_comparison_ne2(self): + q1 = dns.message.from_text(query_text) + q2 = dns.message.from_text(query_text) + q2.question = [] + self.failUnless(q1 != q2) + + def test_comparison_ne3(self): + q1 = dns.message.from_text(query_text) + self.failUnless(q1 != 1) + + def test_EDNS_to_wire1(self): + q = dns.message.from_text(query_text) + w = q.to_wire() + self.failUnless(w == goodwire) + + def test_EDNS_from_wire1(self): + m = dns.message.from_wire(goodwire) + self.failUnless(str(m) == query_text) + + def test_EDNS_to_wire2(self): + q = dns.message.from_text(query_text_2) + w = q.to_wire() + self.failUnless(w == goodwire3) + + def test_EDNS_from_wire2(self): + m = dns.message.from_wire(goodwire3) + self.failUnless(str(m) == query_text_2) + + def test_TooBig(self): + def bad(): + q = dns.message.from_text(query_text) + for i in xrange(0, 25): + rrset = dns.rrset.from_text('foo%d.' % i, 3600, + dns.rdataclass.IN, + dns.rdatatype.A, + '10.0.0.%d' % i) + q.additional.append(rrset) + w = q.to_wire(max_size=512) + self.failUnlessRaises(dns.exception.TooBig, bad) + + def test_answer1(self): + a = dns.message.from_text(answer_text) + wire = a.to_wire(want_shuffle=False) + self.failUnless(wire == goodwire2) + + def test_TrailingJunk(self): + def bad(): + badwire = goodwire + '\x00' + m = dns.message.from_wire(badwire) + self.failUnlessRaises(dns.message.TrailingJunk, bad) + + def test_ShortHeader(self): + def bad(): + badwire = '\x00' * 11 + m = dns.message.from_wire(badwire) + self.failUnlessRaises(dns.message.ShortHeader, bad) + + def test_RespondingToResponse(self): + def bad(): + q = dns.message.make_query('foo', 'A') + r1 = dns.message.make_response(q) + r2 = dns.message.make_response(r1) + self.failUnlessRaises(dns.exception.FormError, bad) + + def test_ExtendedRcodeSetting(self): + m = dns.message.make_query('foo', 'A') + m.set_rcode(4095) + self.failUnless(m.rcode() == 4095) + m.set_rcode(2) + self.failUnless(m.rcode() == 2) + + def test_EDNSVersionCoherence(self): + m = dns.message.make_query('foo', 'A') + m.use_edns(1) + self.failUnless((m.ednsflags >> 16) & 0xFF == 1) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/name.py b/source4/scripting/python/samba_external/dnspython/tests/name.py new file mode 100644 index 0000000000..a53ef9eac6 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/name.py @@ -0,0 +1,697 @@ +# 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 unittest + +import cStringIO +import socket + +import dns.name +import dns.reversename +import dns.e164 + +class NameTestCase(unittest.TestCase): + def setUp(self): + self.origin = dns.name.from_text('example.') + + def testFromTextRel1(self): + n = dns.name.from_text('foo.bar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testFromTextRel2(self): + n = dns.name.from_text('foo.bar', origin=self.origin) + self.failUnless(n.labels == ('foo', 'bar', 'example', '')) + + def testFromTextRel3(self): + n = dns.name.from_text('foo.bar', origin=None) + self.failUnless(n.labels == ('foo', 'bar')) + + def testFromTextRel4(self): + n = dns.name.from_text('@', origin=None) + self.failUnless(n == dns.name.empty) + + def testFromTextRel5(self): + n = dns.name.from_text('@', origin=self.origin) + self.failUnless(n == self.origin) + + def testFromTextAbs1(self): + n = dns.name.from_text('foo.bar.') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testTortureFromText(self): + good = [ + r'.', + r'a', + r'a.', + r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + r'\000.\008.\010.\032.\046.\092.\099.\255', + r'\\', + r'\..\.', + r'\\.\\', + r'!"#%&/()=+-', + r'\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255', + ] + bad = [ + r'..', + r'.a', + r'\\..', + '\\', # yes, we don't want the 'r' prefix! + r'\0', + r'\00', + r'\00Z', + r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + r'\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255', + ] + for t in good: + try: + n = dns.name.from_text(t) + except: + self.fail("good test '%s' raised an exception" % t) + for t in bad: + caught = False + try: + n = dns.name.from_text(t) + except: + caught = True + if not caught: + self.fail("bad test '%s' did not raise an exception" % t) + + def testImmutable1(self): + def bad(): + self.origin.labels = () + self.failUnlessRaises(TypeError, bad) + + def testImmutable2(self): + def bad(): + self.origin.labels[0] = 'foo' + self.failUnlessRaises(TypeError, bad) + + def testAbs1(self): + self.failUnless(dns.name.root.is_absolute()) + + def testAbs2(self): + self.failUnless(not dns.name.empty.is_absolute()) + + def testAbs3(self): + self.failUnless(self.origin.is_absolute()) + + def testAbs3(self): + n = dns.name.from_text('foo', origin=None) + self.failUnless(not n.is_absolute()) + + def testWild1(self): + n = dns.name.from_text('*.foo', origin=None) + self.failUnless(n.is_wild()) + + def testWild2(self): + n = dns.name.from_text('*a.foo', origin=None) + self.failUnless(not n.is_wild()) + + def testWild3(self): + n = dns.name.from_text('a.*.foo', origin=None) + self.failUnless(not n.is_wild()) + + def testWild4(self): + self.failUnless(not dns.name.root.is_wild()) + + def testWild5(self): + self.failUnless(not dns.name.empty.is_wild()) + + def testHash1(self): + n1 = dns.name.from_text('fOo.COM') + n2 = dns.name.from_text('foo.com') + self.failUnless(hash(n1) == hash(n2)) + + def testCompare1(self): + n1 = dns.name.from_text('a') + n2 = dns.name.from_text('b') + self.failUnless(n1 < n2) + self.failUnless(n2 > n1) + + def testCompare2(self): + n1 = dns.name.from_text('') + n2 = dns.name.from_text('b') + self.failUnless(n1 < n2) + self.failUnless(n2 > n1) + + def testCompare3(self): + self.failUnless(dns.name.empty < dns.name.root) + self.failUnless(dns.name.root > dns.name.empty) + + def testCompare4(self): + self.failUnless(dns.name.root != 1) + + def testCompare5(self): + self.failUnless(dns.name.root < 1 or dns.name.root > 1) + + def testSubdomain1(self): + self.failUnless(not dns.name.empty.is_subdomain(dns.name.root)) + + def testSubdomain2(self): + self.failUnless(not dns.name.root.is_subdomain(dns.name.empty)) + + def testSubdomain3(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(n.is_subdomain(self.origin)) + + def testSubdomain4(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(n.is_subdomain(dns.name.root)) + + def testSubdomain5(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(n.is_subdomain(n)) + + def testSuperdomain1(self): + self.failUnless(not dns.name.empty.is_superdomain(dns.name.root)) + + def testSuperdomain2(self): + self.failUnless(not dns.name.root.is_superdomain(dns.name.empty)) + + def testSuperdomain3(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(self.origin.is_superdomain(n)) + + def testSuperdomain4(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(dns.name.root.is_superdomain(n)) + + def testSuperdomain5(self): + n = dns.name.from_text('foo', origin=self.origin) + self.failUnless(n.is_superdomain(n)) + + def testCanonicalize1(self): + n = dns.name.from_text('FOO.bar', origin=self.origin) + c = n.canonicalize() + self.failUnless(c.labels == ('foo', 'bar', 'example', '')) + + def testToText1(self): + n = dns.name.from_text('FOO.bar', origin=self.origin) + t = n.to_text() + self.failUnless(t == 'FOO.bar.example.') + + def testToText2(self): + n = dns.name.from_text('FOO.bar', origin=self.origin) + t = n.to_text(True) + self.failUnless(t == 'FOO.bar.example') + + def testToText3(self): + n = dns.name.from_text('FOO.bar', origin=None) + t = n.to_text() + self.failUnless(t == 'FOO.bar') + + def testToText4(self): + t = dns.name.empty.to_text() + self.failUnless(t == '@') + + def testToText5(self): + t = dns.name.root.to_text() + self.failUnless(t == '.') + + def testToText6(self): + n = dns.name.from_text('FOO bar', origin=None) + t = n.to_text() + self.failUnless(t == r'FOO\032bar') + + def testToText7(self): + n = dns.name.from_text(r'FOO\.bar', origin=None) + t = n.to_text() + self.failUnless(t == r'FOO\.bar') + + def testToText8(self): + n = dns.name.from_text(r'\070OO\.bar', origin=None) + t = n.to_text() + self.failUnless(t == r'FOO\.bar') + + def testSlice1(self): + n = dns.name.from_text(r'a.b.c.', origin=None) + s = n[:] + self.failUnless(s == ('a', 'b', 'c', '')) + + def testSlice2(self): + n = dns.name.from_text(r'a.b.c.', origin=None) + s = n[:2] + self.failUnless(s == ('a', 'b')) + + def testSlice3(self): + n = dns.name.from_text(r'a.b.c.', origin=None) + s = n[2:] + self.failUnless(s == ('c', '')) + + def testEmptyLabel1(self): + def bad(): + n = dns.name.Name(['a', '', 'b']) + self.failUnlessRaises(dns.name.EmptyLabel, bad) + + def testEmptyLabel2(self): + def bad(): + n = dns.name.Name(['', 'b']) + self.failUnlessRaises(dns.name.EmptyLabel, bad) + + def testEmptyLabel3(self): + n = dns.name.Name(['b', '']) + self.failUnless(n) + + def testLongLabel(self): + n = dns.name.Name(['a' * 63]) + self.failUnless(n) + + def testLabelTooLong(self): + def bad(): + n = dns.name.Name(['a' * 64, 'b']) + self.failUnlessRaises(dns.name.LabelTooLong, bad) + + def testLongName(self): + n = dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 62]) + self.failUnless(n) + + def testNameTooLong(self): + def bad(): + n = dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 63]) + self.failUnlessRaises(dns.name.NameTooLong, bad) + + def testConcat1(self): + n1 = dns.name.Name(['a', 'b']) + n2 = dns.name.Name(['c', 'd']) + e = dns.name.Name(['a', 'b', 'c', 'd']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat2(self): + n1 = dns.name.Name(['a', 'b']) + n2 = dns.name.Name([]) + e = dns.name.Name(['a', 'b']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat2(self): + n1 = dns.name.Name([]) + n2 = dns.name.Name(['a', 'b']) + e = dns.name.Name(['a', 'b']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat3(self): + n1 = dns.name.Name(['a', 'b', '']) + n2 = dns.name.Name([]) + e = dns.name.Name(['a', 'b', '']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat4(self): + n1 = dns.name.Name(['a', 'b']) + n2 = dns.name.Name(['c', '']) + e = dns.name.Name(['a', 'b', 'c', '']) + r = n1 + n2 + self.failUnless(r == e) + + def testConcat5(self): + def bad(): + n1 = dns.name.Name(['a', 'b', '']) + n2 = dns.name.Name(['c']) + r = n1 + n2 + self.failUnlessRaises(dns.name.AbsoluteConcatenation, bad) + + def testBadEscape(self): + def bad(): + n = dns.name.from_text(r'a.b\0q1.c.') + print n + self.failUnlessRaises(dns.name.BadEscape, bad) + + def testDigestable1(self): + n = dns.name.from_text('FOO.bar') + d = n.to_digestable() + self.failUnless(d == '\x03foo\x03bar\x00') + + def testDigestable2(self): + n1 = dns.name.from_text('FOO.bar') + n2 = dns.name.from_text('foo.BAR.') + d1 = n1.to_digestable() + d2 = n2.to_digestable() + self.failUnless(d1 == d2) + + def testDigestable3(self): + d = dns.name.root.to_digestable() + self.failUnless(d == '\x00') + + def testDigestable4(self): + n = dns.name.from_text('FOO.bar', None) + d = n.to_digestable(dns.name.root) + self.failUnless(d == '\x03foo\x03bar\x00') + + def testBadDigestable(self): + def bad(): + n = dns.name.from_text('FOO.bar', None) + d = n.to_digestable() + self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) + + def testToWire1(self): + n = dns.name.from_text('FOO.bar') + f = cStringIO.StringIO() + compress = {} + n.to_wire(f, compress) + self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00') + + def testToWire2(self): + n = dns.name.from_text('FOO.bar') + f = cStringIO.StringIO() + compress = {} + n.to_wire(f, compress) + n.to_wire(f, compress) + self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\xc0\x00') + + def testToWire3(self): + n1 = dns.name.from_text('FOO.bar') + n2 = dns.name.from_text('foo.bar') + f = cStringIO.StringIO() + compress = {} + n1.to_wire(f, compress) + n2.to_wire(f, compress) + self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\xc0\x00') + + def testToWire4(self): + n1 = dns.name.from_text('FOO.bar') + n2 = dns.name.from_text('a.foo.bar') + f = cStringIO.StringIO() + compress = {} + n1.to_wire(f, compress) + n2.to_wire(f, compress) + self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\x01\x61\xc0\x00') + + def testToWire5(self): + n1 = dns.name.from_text('FOO.bar') + n2 = dns.name.from_text('a.foo.bar') + f = cStringIO.StringIO() + compress = {} + n1.to_wire(f, compress) + n2.to_wire(f, None) + self.failUnless(f.getvalue() == \ + '\x03FOO\x03bar\x00\x01\x61\x03foo\x03bar\x00') + + def testToWire6(self): + n = dns.name.from_text('FOO.bar') + v = n.to_wire() + self.failUnless(v == '\x03FOO\x03bar\x00') + + def testBadToWire(self): + def bad(): + n = dns.name.from_text('FOO.bar', None) + f = cStringIO.StringIO() + compress = {} + n.to_wire(f, compress) + self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) + + def testSplit1(self): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(2) + ep = dns.name.from_text('foo', None) + es = dns.name.from_text('bar.', None) + self.failUnless(prefix == ep and suffix == es) + + def testSplit2(self): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(1) + ep = dns.name.from_text('foo.bar', None) + es = dns.name.from_text('.', None) + self.failUnless(prefix == ep and suffix == es) + + def testSplit3(self): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(0) + ep = dns.name.from_text('foo.bar.', None) + es = dns.name.from_text('', None) + self.failUnless(prefix == ep and suffix == es) + + def testSplit4(self): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(3) + ep = dns.name.from_text('', None) + es = dns.name.from_text('foo.bar.', None) + self.failUnless(prefix == ep and suffix == es) + + def testBadSplit1(self): + def bad(): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(-1) + self.failUnlessRaises(ValueError, bad) + + def testBadSplit2(self): + def bad(): + n = dns.name.from_text('foo.bar.') + (prefix, suffix) = n.split(4) + self.failUnlessRaises(ValueError, bad) + + def testRelativize1(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('bar.', None) + e = dns.name.from_text('a.foo', None) + self.failUnless(n.relativize(o) == e) + + def testRelativize2(self): + n = dns.name.from_text('a.foo.bar.', None) + o = n + e = dns.name.empty + self.failUnless(n.relativize(o) == e) + + def testRelativize3(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('blaz.', None) + e = n + self.failUnless(n.relativize(o) == e) + + def testRelativize4(self): + n = dns.name.from_text('a.foo', None) + o = dns.name.root + e = n + self.failUnless(n.relativize(o) == e) + + def testDerelativize1(self): + n = dns.name.from_text('a.foo', None) + o = dns.name.from_text('bar.', None) + e = dns.name.from_text('a.foo.bar.', None) + self.failUnless(n.derelativize(o) == e) + + def testDerelativize2(self): + n = dns.name.empty + o = dns.name.from_text('a.foo.bar.', None) + e = o + self.failUnless(n.derelativize(o) == e) + + def testDerelativize3(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('blaz.', None) + e = n + self.failUnless(n.derelativize(o) == e) + + def testChooseRelativity1(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('bar.', None) + e = dns.name.from_text('a.foo', None) + self.failUnless(n.choose_relativity(o, True) == e) + + def testChooseRelativity2(self): + n = dns.name.from_text('a.foo.bar.', None) + o = dns.name.from_text('bar.', None) + e = n + self.failUnless(n.choose_relativity(o, False) == e) + + def testChooseRelativity3(self): + n = dns.name.from_text('a.foo', None) + o = dns.name.from_text('bar.', None) + e = dns.name.from_text('a.foo.bar.', None) + self.failUnless(n.choose_relativity(o, False) == e) + + def testChooseRelativity4(self): + n = dns.name.from_text('a.foo', None) + o = None + e = n + self.failUnless(n.choose_relativity(o, True) == e) + + def testChooseRelativity5(self): + n = dns.name.from_text('a.foo', None) + o = None + e = n + self.failUnless(n.choose_relativity(o, False) == e) + + def testChooseRelativity6(self): + n = dns.name.from_text('a.foo.', None) + o = None + e = n + self.failUnless(n.choose_relativity(o, True) == e) + + def testChooseRelativity7(self): + n = dns.name.from_text('a.foo.', None) + o = None + e = n + self.failUnless(n.choose_relativity(o, False) == e) + + def testFromWire1(self): + w = '\x03foo\x00\xc0\x00' + (n1, cused1) = dns.name.from_wire(w, 0) + (n2, cused2) = dns.name.from_wire(w, cused1) + en1 = dns.name.from_text('foo.') + en2 = en1 + ecused1 = 5 + ecused2 = 2 + self.failUnless(n1 == en1 and cused1 == ecused1 and \ + n2 == en2 and cused2 == ecused2) + + def testFromWire1(self): + w = '\x03foo\x00\x01a\xc0\x00\x01b\xc0\x05' + current = 0 + (n1, cused1) = dns.name.from_wire(w, current) + current += cused1 + (n2, cused2) = dns.name.from_wire(w, current) + current += cused2 + (n3, cused3) = dns.name.from_wire(w, current) + en1 = dns.name.from_text('foo.') + en2 = dns.name.from_text('a.foo.') + en3 = dns.name.from_text('b.a.foo.') + ecused1 = 5 + ecused2 = 4 + ecused3 = 4 + self.failUnless(n1 == en1 and cused1 == ecused1 and \ + n2 == en2 and cused2 == ecused2 and \ + n3 == en3 and cused3 == ecused3) + + def testBadFromWire1(self): + def bad(): + w = '\x03foo\xc0\x04' + (n, cused) = dns.name.from_wire(w, 0) + self.failUnlessRaises(dns.name.BadPointer, bad) + + def testBadFromWire2(self): + def bad(): + w = '\x03foo\xc0\x05' + (n, cused) = dns.name.from_wire(w, 0) + self.failUnlessRaises(dns.name.BadPointer, bad) + + def testBadFromWire3(self): + def bad(): + w = '\xbffoo' + (n, cused) = dns.name.from_wire(w, 0) + self.failUnlessRaises(dns.name.BadLabelType, bad) + + def testBadFromWire4(self): + def bad(): + w = '\x41foo' + (n, cused) = dns.name.from_wire(w, 0) + self.failUnlessRaises(dns.name.BadLabelType, bad) + + def testParent1(self): + n = dns.name.from_text('foo.bar.') + self.failUnless(n.parent() == dns.name.from_text('bar.')) + self.failUnless(n.parent().parent() == dns.name.root) + + def testParent2(self): + n = dns.name.from_text('foo.bar', None) + self.failUnless(n.parent() == dns.name.from_text('bar', None)) + self.failUnless(n.parent().parent() == dns.name.empty) + + def testParent3(self): + def bad(): + n = dns.name.root + n.parent() + self.failUnlessRaises(dns.name.NoParent, bad) + + def testParent4(self): + def bad(): + n = dns.name.empty + n.parent() + self.failUnlessRaises(dns.name.NoParent, bad) + + def testFromUnicode1(self): + n = dns.name.from_text(u'foo.bar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testFromUnicode2(self): + n = dns.name.from_text(u'foo\u1234bar.bar') + self.failUnless(n.labels == ('xn--foobar-r5z', 'bar', '')) + + def testFromUnicodeAlternateDot1(self): + n = dns.name.from_text(u'foo\u3002bar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testFromUnicodeAlternateDot2(self): + n = dns.name.from_text(u'foo\uff0ebar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testFromUnicodeAlternateDot3(self): + n = dns.name.from_text(u'foo\uff61bar') + self.failUnless(n.labels == ('foo', 'bar', '')) + + def testToUnicode1(self): + n = dns.name.from_text(u'foo.bar') + s = n.to_unicode() + self.failUnless(s == u'foo.bar.') + + def testToUnicode2(self): + n = dns.name.from_text(u'foo\u1234bar.bar') + s = n.to_unicode() + self.failUnless(s == u'foo\u1234bar.bar.') + + def testToUnicode3(self): + n = dns.name.from_text('foo.bar') + s = n.to_unicode() + self.failUnless(s == u'foo.bar.') + + def testReverseIPv4(self): + e = dns.name.from_text('1.0.0.127.in-addr.arpa.') + n = dns.reversename.from_address('127.0.0.1') + self.failUnless(e == n) + + def testReverseIPv6(self): + e = dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') + n = dns.reversename.from_address('::1') + self.failUnless(e == n) + + def testBadReverseIPv4(self): + def bad(): + n = dns.reversename.from_address('127.0.foo.1') + self.failUnlessRaises(socket.error, bad) + + def testBadReverseIPv6(self): + def bad(): + n = dns.reversename.from_address('::1::1') + self.failUnlessRaises(socket.error, bad) + + def testForwardIPv4(self): + n = dns.name.from_text('1.0.0.127.in-addr.arpa.') + e = '127.0.0.1' + text = dns.reversename.to_address(n) + self.failUnless(text == e) + + def testForwardIPv6(self): + n = dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') + e = '::1' + text = dns.reversename.to_address(n) + self.failUnless(text == e) + + def testE164ToEnum(self): + text = '+1 650 555 1212' + e = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') + n = dns.e164.from_e164(text) + self.failUnless(n == e) + + def testEnumToE164(self): + n = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') + e = '+16505551212' + text = dns.e164.to_e164(n) + self.failUnless(text == e) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/namedict.py b/source4/scripting/python/samba_external/dnspython/tests/namedict.py new file mode 100644 index 0000000000..0261142186 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/namedict.py @@ -0,0 +1,102 @@ +# 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 unittest + +import dns.name +import dns.namedict + +class NameTestCase(unittest.TestCase): + + def setUp(self): + self.ndict = dns.namedict.NameDict() + n1 = dns.name.from_text('foo.bar.') + n2 = dns.name.from_text('bar.') + self.ndict[n1] = 1 + self.ndict[n2] = 2 + self.rndict = dns.namedict.NameDict() + n1 = dns.name.from_text('foo.bar', None) + n2 = dns.name.from_text('bar', None) + self.rndict[n1] = 1 + self.rndict[n2] = 2 + + def testDepth(self): + self.failUnless(self.ndict.max_depth == 3) + + def testLookup1(self): + k = dns.name.from_text('foo.bar.') + self.failUnless(self.ndict[k] == 1) + + def testLookup2(self): + k = dns.name.from_text('foo.bar.') + self.failUnless(self.ndict.get_deepest_match(k)[1] == 1) + + def testLookup3(self): + k = dns.name.from_text('a.b.c.foo.bar.') + self.failUnless(self.ndict.get_deepest_match(k)[1] == 1) + + def testLookup4(self): + k = dns.name.from_text('a.b.c.bar.') + self.failUnless(self.ndict.get_deepest_match(k)[1] == 2) + + def testLookup5(self): + def bad(): + n = dns.name.from_text('a.b.c.') + (k, v) = self.ndict.get_deepest_match(n) + self.failUnlessRaises(KeyError, bad) + + def testLookup6(self): + def bad(): + (k, v) = self.ndict.get_deepest_match(dns.name.empty) + self.failUnlessRaises(KeyError, bad) + + def testLookup7(self): + self.ndict[dns.name.empty] = 100 + n = dns.name.from_text('a.b.c.') + (k, v) = self.ndict.get_deepest_match(n) + self.failUnless(v == 100) + + def testLookup8(self): + def bad(): + self.ndict['foo'] = 100 + self.failUnlessRaises(ValueError, bad) + + def testRelDepth(self): + self.failUnless(self.rndict.max_depth == 2) + + def testRelLookup1(self): + k = dns.name.from_text('foo.bar', None) + self.failUnless(self.rndict[k] == 1) + + def testRelLookup2(self): + k = dns.name.from_text('foo.bar', None) + self.failUnless(self.rndict.get_deepest_match(k)[1] == 1) + + def testRelLookup3(self): + k = dns.name.from_text('a.b.c.foo.bar', None) + self.failUnless(self.rndict.get_deepest_match(k)[1] == 1) + + def testRelLookup4(self): + k = dns.name.from_text('a.b.c.bar', None) + self.failUnless(self.rndict.get_deepest_match(k)[1] == 2) + + def testRelLookup7(self): + self.rndict[dns.name.empty] = 100 + n = dns.name.from_text('a.b.c', None) + (k, v) = self.rndict.get_deepest_match(n) + self.failUnless(v == 100) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/ntoaaton.py b/source4/scripting/python/samba_external/dnspython/tests/ntoaaton.py new file mode 100644 index 0000000000..77befd26e3 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/ntoaaton.py @@ -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 unittest + +import dns.exception +import dns.ipv6 + +class NtoAAtoNTestCase(unittest.TestCase): + + def test_aton1(self): + a = dns.ipv6.inet_aton('::') + self.failUnless(a == '\x00' * 16) + + def test_aton2(self): + a = dns.ipv6.inet_aton('::1') + self.failUnless(a == '\x00' * 15 + '\x01') + + def test_aton3(self): + a = dns.ipv6.inet_aton('::10.0.0.1') + self.failUnless(a == '\x00' * 12 + '\x0a\x00\x00\x01') + + def test_aton4(self): + a = dns.ipv6.inet_aton('abcd::dcba') + self.failUnless(a == '\xab\xcd' + '\x00' * 12 + '\xdc\xba') + + def test_aton5(self): + a = dns.ipv6.inet_aton('1:2:3:4:5:6:7:8') + self.failUnless(a == \ + '00010002000300040005000600070008'.decode('hex_codec')) + + def test_bad_aton1(self): + def bad(): + a = dns.ipv6.inet_aton('abcd:dcba') + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def test_bad_aton2(self): + def bad(): + a = dns.ipv6.inet_aton('abcd::dcba::1') + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def test_bad_aton3(self): + def bad(): + a = dns.ipv6.inet_aton('1:2:3:4:5:6:7:8:9') + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def test_aton1(self): + a = dns.ipv6.inet_aton('::') + self.failUnless(a == '\x00' * 16) + + def test_aton2(self): + a = dns.ipv6.inet_aton('::1') + self.failUnless(a == '\x00' * 15 + '\x01') + + def test_aton3(self): + a = dns.ipv6.inet_aton('::10.0.0.1') + self.failUnless(a == '\x00' * 12 + '\x0a\x00\x00\x01') + + def test_aton4(self): + a = dns.ipv6.inet_aton('abcd::dcba') + self.failUnless(a == '\xab\xcd' + '\x00' * 12 + '\xdc\xba') + + def test_ntoa1(self): + b = '00010002000300040005000600070008'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '1:2:3:4:5:6:7:8') + + def test_ntoa2(self): + b = '\x00' * 16 + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::') + + def test_ntoa3(self): + b = '\x00' * 15 + '\x01' + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::1') + + def test_ntoa4(self): + b = '\x80' + '\x00' * 15 + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '8000::') + + def test_ntoa5(self): + b = '\x01\xcd' + '\x00' * 12 + '\x03\xef' + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '1cd::3ef') + + def test_ntoa6(self): + b = 'ffff00000000ffff000000000000ffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == 'ffff:0:0:ffff::ffff') + + def test_ntoa7(self): + b = '00000000ffff000000000000ffffffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '0:0:ffff::ffff:ffff') + + def test_ntoa8(self): + b = 'ffff0000ffff00000000ffff00000000'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == 'ffff:0:ffff::ffff:0:0') + + def test_ntoa9(self): + b = '0000000000000000000000000a000001'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::10.0.0.1') + + def test_ntoa10(self): + b = '0000000000000000000000010a000001'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::1:a00:1') + + def test_ntoa11(self): + b = '00000000000000000000ffff0a000001'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::ffff:10.0.0.1') + + def test_ntoa12(self): + b = '000000000000000000000000ffffffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::255.255.255.255') + + def test_ntoa13(self): + b = '00000000000000000000ffffffffffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::ffff:255.255.255.255') + + def test_ntoa14(self): + b = '0000000000000000000000000001ffff'.decode('hex_codec') + t = dns.ipv6.inet_ntoa(b) + self.failUnless(t == '::0.1.255.255') + + def test_bad_ntoa1(self): + def bad(): + a = dns.ipv6.inet_ntoa('') + self.failUnlessRaises(ValueError, bad) + + def test_bad_ntoa2(self): + def bad(): + a = dns.ipv6.inet_ntoa('\x00' * 17) + self.failUnlessRaises(ValueError, bad) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/rdtypeandclass.py b/source4/scripting/python/samba_external/dnspython/tests/rdtypeandclass.py new file mode 100644 index 0000000000..edd7f7eae3 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/rdtypeandclass.py @@ -0,0 +1,123 @@ +# 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 unittest + +import dns.rdataclass +import dns.rdatatype + +class RdTypeAndClassTestCase(unittest.TestCase): + + # Classes + + def test_class_meta1(self): + self.failUnless(dns.rdataclass.is_metaclass(dns.rdataclass.ANY)) + + def test_class_meta2(self): + self.failUnless(not dns.rdataclass.is_metaclass(dns.rdataclass.IN)) + + def test_class_bytext1(self): + self.failUnless(dns.rdataclass.from_text('IN') == dns.rdataclass.IN) + + def test_class_bytext2(self): + self.failUnless(dns.rdataclass.from_text('CLASS1') == + dns.rdataclass.IN) + + def test_class_bytext_bounds1(self): + self.failUnless(dns.rdataclass.from_text('CLASS0') == 0) + self.failUnless(dns.rdataclass.from_text('CLASS65535') == 65535) + + def test_class_bytext_bounds2(self): + def bad(): + junk = dns.rdataclass.from_text('CLASS65536') + self.failUnlessRaises(ValueError, bad) + + def test_class_bytext_unknown(self): + def bad(): + junk = dns.rdataclass.from_text('XXX') + self.failUnlessRaises(dns.rdataclass.UnknownRdataclass, bad) + + def test_class_totext1(self): + self.failUnless(dns.rdataclass.to_text(dns.rdataclass.IN) == 'IN') + + def test_class_totext1(self): + self.failUnless(dns.rdataclass.to_text(999) == 'CLASS999') + + def test_class_totext_bounds1(self): + def bad(): + junk = dns.rdataclass.to_text(-1) + self.failUnlessRaises(ValueError, bad) + + def test_class_totext_bounds2(self): + def bad(): + junk = dns.rdataclass.to_text(65536) + self.failUnlessRaises(ValueError, bad) + + # Types + + def test_type_meta1(self): + self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.ANY)) + + def test_type_meta2(self): + self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.OPT)) + + def test_type_meta3(self): + self.failUnless(not dns.rdatatype.is_metatype(dns.rdatatype.A)) + + def test_type_singleton1(self): + self.failUnless(dns.rdatatype.is_singleton(dns.rdatatype.SOA)) + + def test_type_singleton2(self): + self.failUnless(not dns.rdatatype.is_singleton(dns.rdatatype.A)) + + def test_type_bytext1(self): + self.failUnless(dns.rdatatype.from_text('A') == dns.rdatatype.A) + + def test_type_bytext2(self): + self.failUnless(dns.rdatatype.from_text('TYPE1') == + dns.rdatatype.A) + + def test_type_bytext_bounds1(self): + self.failUnless(dns.rdatatype.from_text('TYPE0') == 0) + self.failUnless(dns.rdatatype.from_text('TYPE65535') == 65535) + + def test_type_bytext_bounds2(self): + def bad(): + junk = dns.rdatatype.from_text('TYPE65536') + self.failUnlessRaises(ValueError, bad) + + def test_type_bytext_unknown(self): + def bad(): + junk = dns.rdatatype.from_text('XXX') + self.failUnlessRaises(dns.rdatatype.UnknownRdatatype, bad) + + def test_type_totext1(self): + self.failUnless(dns.rdatatype.to_text(dns.rdatatype.A) == 'A') + + def test_type_totext1(self): + self.failUnless(dns.rdatatype.to_text(999) == 'TYPE999') + + def test_type_totext_bounds1(self): + def bad(): + junk = dns.rdatatype.to_text(-1) + self.failUnlessRaises(ValueError, bad) + + def test_type_totext_bounds2(self): + def bad(): + junk = dns.rdatatype.to_text(65536) + self.failUnlessRaises(ValueError, bad) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/resolver.py b/source4/scripting/python/samba_external/dnspython/tests/resolver.py new file mode 100644 index 0000000000..4cacbdc79d --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/resolver.py @@ -0,0 +1,105 @@ +# 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 sys +import time +import unittest + +import dns.name +import dns.message +import dns.name +import dns.rdataclass +import dns.rdatatype +import dns.resolver + +resolv_conf = """ + /t/t +# comment 1 +; comment 2 +domain foo +nameserver 10.0.0.1 +nameserver 10.0.0.2 +""" + +message_text = """id 1234 +opcode QUERY +rcode NOERROR +flags QR AA RD +;QUESTION +example. IN A +;ANSWER +example. 1 IN A 10.0.0.1 +;AUTHORITY +;ADDITIONAL +""" + +class ResolverTestCase(unittest.TestCase): + + if sys.platform != 'win32': + def testRead(self): + f = cStringIO.StringIO(resolv_conf) + r = dns.resolver.Resolver(f) + self.failUnless(r.nameservers == ['10.0.0.1', '10.0.0.2'] and + r.domain == dns.name.from_text('foo')) + + def testCacheExpiration(self): + message = dns.message.from_text(message_text) + name = dns.name.from_text('example.') + answer = dns.resolver.Answer(name, dns.rdatatype.A, dns.rdataclass.IN, + message) + cache = dns.resolver.Cache() + cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) + time.sleep(2) + self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) + is None) + + def testCacheCleaning(self): + message = dns.message.from_text(message_text) + name = dns.name.from_text('example.') + answer = dns.resolver.Answer(name, dns.rdatatype.A, dns.rdataclass.IN, + message) + cache = dns.resolver.Cache(cleaning_interval=1.0) + cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) + time.sleep(2) + self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) + is None) + + def testZoneForName1(self): + name = dns.name.from_text('www.dnspython.org.') + ezname = dns.name.from_text('dnspython.org.') + zname = dns.resolver.zone_for_name(name) + self.failUnless(zname == ezname) + + def testZoneForName2(self): + name = dns.name.from_text('a.b.www.dnspython.org.') + ezname = dns.name.from_text('dnspython.org.') + zname = dns.resolver.zone_for_name(name) + self.failUnless(zname == ezname) + + def testZoneForName3(self): + name = dns.name.from_text('dnspython.org.') + ezname = dns.name.from_text('dnspython.org.') + zname = dns.resolver.zone_for_name(name) + self.failUnless(zname == ezname) + + def testZoneForName4(self): + def bad(): + name = dns.name.from_text('dnspython.org', None) + zname = dns.resolver.zone_for_name(name) + self.failUnlessRaises(dns.resolver.NotAbsolute, bad) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/rrset.py b/source4/scripting/python/samba_external/dnspython/tests/rrset.py new file mode 100644 index 0000000000..740162b4c5 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/rrset.py @@ -0,0 +1,54 @@ +# 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 unittest + +import dns.rrset + +class RRsetTestCase(unittest.TestCase): + + def testEqual1(self): + r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') + r2 = dns.rrset.from_text('FOO', 300, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 == r2) + + def testEqual2(self): + r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') + r2 = dns.rrset.from_text('FOO', 600, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 == r2) + + def testNotEqual1(self): + r1 = dns.rrset.from_text('fooa', 30, 'in', 'a', '10.0.0.1', '10.0.0.2') + r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 != r2) + + def testNotEqual2(self): + r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.3') + r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 != r2) + + def testNotEqual3(self): + r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.2', + '10.0.0.3') + r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 != r2) + + def testNotEqual4(self): + r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1') + r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') + self.failUnless(r1 != r2) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/set.py b/source4/scripting/python/samba_external/dnspython/tests/set.py new file mode 100644 index 0000000000..6319eb821c --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/set.py @@ -0,0 +1,208 @@ +# 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 unittest + +import dns.set + +# for convenience +S = dns.set.Set + +class SimpleSetTestCase(unittest.TestCase): + + def testLen1(self): + s1 = S() + self.failUnless(len(s1) == 0) + + def testLen2(self): + s1 = S([1, 2, 3]) + self.failUnless(len(s1) == 3) + + def testLen3(self): + s1 = S([1, 2, 3, 3, 3]) + self.failUnless(len(s1) == 3) + + def testUnion1(self): + s1 = S([1, 2, 3]) + s2 = S([1, 2, 3]) + e = S([1, 2, 3]) + self.failUnless(s1 | s2 == e) + + def testUnion2(self): + s1 = S([1, 2, 3]) + s2 = S([]) + e = S([1, 2, 3]) + self.failUnless(s1 | s2 == e) + + def testUnion3(self): + s1 = S([1, 2, 3]) + s2 = S([3, 4]) + e = S([1, 2, 3, 4]) + self.failUnless(s1 | s2 == e) + + def testIntersection1(self): + s1 = S([1, 2, 3]) + s2 = S([1, 2, 3]) + e = S([1, 2, 3]) + self.failUnless(s1 & s2 == e) + + def testIntersection2(self): + s1 = S([0, 1, 2, 3]) + s2 = S([1, 2, 3, 4]) + e = S([1, 2, 3]) + self.failUnless(s1 & s2 == e) + + def testIntersection3(self): + s1 = S([1, 2, 3]) + s2 = S([]) + e = S([]) + self.failUnless(s1 & s2 == e) + + def testIntersection4(self): + s1 = S([1, 2, 3]) + s2 = S([5, 4]) + e = S([]) + self.failUnless(s1 & s2 == e) + + def testDifference1(self): + s1 = S([1, 2, 3]) + s2 = S([5, 4]) + e = S([1, 2, 3]) + self.failUnless(s1 - s2 == e) + + def testDifference2(self): + s1 = S([1, 2, 3]) + s2 = S([]) + e = S([1, 2, 3]) + self.failUnless(s1 - s2 == e) + + def testDifference3(self): + s1 = S([1, 2, 3]) + s2 = S([3, 2]) + e = S([1]) + self.failUnless(s1 - s2 == e) + + def testDifference4(self): + s1 = S([1, 2, 3]) + s2 = S([3, 2, 1]) + e = S([]) + self.failUnless(s1 - s2 == e) + + def testSubset1(self): + s1 = S([1, 2, 3]) + s2 = S([3, 2, 1]) + self.failUnless(s1.issubset(s2)) + + def testSubset2(self): + s1 = S([1, 2, 3]) + self.failUnless(s1.issubset(s1)) + + def testSubset3(self): + s1 = S([]) + s2 = S([1, 2, 3]) + self.failUnless(s1.issubset(s2)) + + def testSubset4(self): + s1 = S([1]) + s2 = S([1, 2, 3]) + self.failUnless(s1.issubset(s2)) + + def testSubset5(self): + s1 = S([]) + s2 = S([]) + self.failUnless(s1.issubset(s2)) + + def testSubset6(self): + s1 = S([1, 4]) + s2 = S([1, 2, 3]) + self.failUnless(not s1.issubset(s2)) + + def testSuperset1(self): + s1 = S([1, 2, 3]) + s2 = S([3, 2, 1]) + self.failUnless(s1.issuperset(s2)) + + def testSuperset2(self): + s1 = S([1, 2, 3]) + self.failUnless(s1.issuperset(s1)) + + def testSuperset3(self): + s1 = S([1, 2, 3]) + s2 = S([]) + self.failUnless(s1.issuperset(s2)) + + def testSuperset4(self): + s1 = S([1, 2, 3]) + s2 = S([1]) + self.failUnless(s1.issuperset(s2)) + + def testSuperset5(self): + s1 = S([]) + s2 = S([]) + self.failUnless(s1.issuperset(s2)) + + def testSuperset6(self): + s1 = S([1, 2, 3]) + s2 = S([1, 4]) + self.failUnless(not s1.issuperset(s2)) + + def testUpdate1(self): + s1 = S([1, 2, 3]) + u = (4, 5, 6) + e = S([1, 2, 3, 4, 5, 6]) + s1.update(u) + self.failUnless(s1 == e) + + def testUpdate2(self): + s1 = S([1, 2, 3]) + u = [] + e = S([1, 2, 3]) + s1.update(u) + self.failUnless(s1 == e) + + def testGetitem(self): + s1 = S([1, 2, 3]) + i0 = s1[0] + i1 = s1[1] + i2 = s1[2] + s2 = S([i0, i1, i2]) + self.failUnless(s1 == s2) + + def testGetslice(self): + s1 = S([1, 2, 3]) + slice = s1[0:2] + self.failUnless(len(slice) == 2) + item = s1[2] + slice.append(item) + s2 = S(slice) + self.failUnless(s1 == s2) + + def testDelitem(self): + s1 = S([1, 2, 3]) + del s1[0] + i1 = s1[0] + i2 = s1[1] + self.failUnless(i1 != i2) + self.failUnless(i1 == 1 or i1 == 2 or i1 == 3) + self.failUnless(i2 == 1 or i2 == 2 or i2 == 3) + + def testDelslice(self): + s1 = S([1, 2, 3]) + del s1[0:2] + i1 = s1[0] + self.failUnless(i1 == 1 or i1 == 2 or i1 == 3) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/tokenizer.py b/source4/scripting/python/samba_external/dnspython/tests/tokenizer.py new file mode 100644 index 0000000000..4f4a1bdc90 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/tokenizer.py @@ -0,0 +1,190 @@ +# 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 unittest + +import dns.exception +import dns.tokenizer + +Token = dns.tokenizer.Token + +class TokenizerTestCase(unittest.TestCase): + + def testQuotedString1(self): + tok = dns.tokenizer.Tokenizer(r'"foo"') + token = tok.get() + self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, 'foo')) + + def testQuotedString2(self): + tok = dns.tokenizer.Tokenizer(r'""') + token = tok.get() + self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, '')) + + def testQuotedString3(self): + tok = dns.tokenizer.Tokenizer(r'"\"foo\""') + token = tok.get() + self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, '"foo"')) + + def testQuotedString4(self): + tok = dns.tokenizer.Tokenizer(r'"foo\010bar"') + token = tok.get() + self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, 'foo\x0abar')) + + def testQuotedString5(self): + def bad(): + tok = dns.tokenizer.Tokenizer(r'"foo') + token = tok.get() + self.failUnlessRaises(dns.exception.UnexpectedEnd, bad) + + def testQuotedString6(self): + def bad(): + tok = dns.tokenizer.Tokenizer(r'"foo\01') + token = tok.get() + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def testQuotedString7(self): + def bad(): + tok = dns.tokenizer.Tokenizer('"foo\nbar"') + token = tok.get() + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def testEmpty1(self): + tok = dns.tokenizer.Tokenizer('') + token = tok.get() + self.failUnless(token.is_eof()) + + def testEmpty2(self): + tok = dns.tokenizer.Tokenizer('') + token1 = tok.get() + token2 = tok.get() + self.failUnless(token1.is_eof() and token2.is_eof()) + + def testEOL(self): + tok = dns.tokenizer.Tokenizer('\n') + token1 = tok.get() + token2 = tok.get() + self.failUnless(token1.is_eol() and token2.is_eof()) + + def testWS1(self): + tok = dns.tokenizer.Tokenizer(' \n') + token1 = tok.get() + self.failUnless(token1.is_eol()) + + def testWS2(self): + tok = dns.tokenizer.Tokenizer(' \n') + token1 = tok.get(want_leading=True) + self.failUnless(token1.is_whitespace()) + + def testComment1(self): + tok = dns.tokenizer.Tokenizer(' ;foo\n') + token1 = tok.get() + self.failUnless(token1.is_eol()) + + def testComment2(self): + tok = dns.tokenizer.Tokenizer(' ;foo\n') + token1 = tok.get(want_comment = True) + token2 = tok.get() + self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo') and + token2.is_eol()) + + def testComment3(self): + tok = dns.tokenizer.Tokenizer(' ;foo bar\n') + token1 = tok.get(want_comment = True) + token2 = tok.get() + self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo bar') and + token2.is_eol()) + + def testMultiline1(self): + tok = dns.tokenizer.Tokenizer('( foo\n\n bar\n)') + tokens = list(iter(tok)) + self.failUnless(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), + Token(dns.tokenizer.IDENTIFIER, 'bar')]) + + def testMultiline2(self): + tok = dns.tokenizer.Tokenizer('( foo\n\n bar\n)\n') + tokens = list(iter(tok)) + self.failUnless(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), + Token(dns.tokenizer.IDENTIFIER, 'bar'), + Token(dns.tokenizer.EOL, '\n')]) + def testMultiline3(self): + def bad(): + tok = dns.tokenizer.Tokenizer('foo)') + tokens = list(iter(tok)) + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def testMultiline4(self): + def bad(): + tok = dns.tokenizer.Tokenizer('((foo)') + tokens = list(iter(tok)) + self.failUnlessRaises(dns.exception.SyntaxError, bad) + + def testUnget1(self): + tok = dns.tokenizer.Tokenizer('foo') + t1 = tok.get() + tok.unget(t1) + t2 = tok.get() + self.failUnless(t1 == t2 and t1.ttype == dns.tokenizer.IDENTIFIER and \ + t1.value == 'foo') + + def testUnget2(self): + def bad(): + tok = dns.tokenizer.Tokenizer('foo') + t1 = tok.get() + tok.unget(t1) + tok.unget(t1) + self.failUnlessRaises(dns.tokenizer.UngetBufferFull, bad) + + def testGetEOL1(self): + tok = dns.tokenizer.Tokenizer('\n') + t = tok.get_eol() + self.failUnless(t == '\n') + + def testGetEOL2(self): + tok = dns.tokenizer.Tokenizer('') + t = tok.get_eol() + self.failUnless(t == '') + + def testEscapedDelimiter1(self): + tok = dns.tokenizer.Tokenizer(r'ch\ ld') + t = tok.get() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ ld') + + def testEscapedDelimiter2(self): + tok = dns.tokenizer.Tokenizer(r'ch\032ld') + t = tok.get() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\032ld') + + def testEscapedDelimiter3(self): + tok = dns.tokenizer.Tokenizer(r'ch\ild') + t = tok.get() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ild') + + def testEscapedDelimiter1u(self): + tok = dns.tokenizer.Tokenizer(r'ch\ ld') + t = tok.get().unescape() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch ld') + + def testEscapedDelimiter2u(self): + tok = dns.tokenizer.Tokenizer(r'ch\032ld') + t = tok.get().unescape() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == 'ch ld') + + def testEscapedDelimiter3u(self): + tok = dns.tokenizer.Tokenizer(r'ch\ild') + t = tok.get().unescape() + self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'child') + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/update.py b/source4/scripting/python/samba_external/dnspython/tests/update.py new file mode 100644 index 0000000000..5f7b31f23f --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/update.py @@ -0,0 +1,114 @@ +# 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 unittest + +import dns.update +import dns.rdata +import dns.rdataset + +goodhex = '0001 2800 0001 0005 0007 0000' \ + '076578616d706c6500 0006 0001' \ + '03666f6fc00c 00ff 00ff 00000000 0000' \ + 'c019 0001 00ff 00000000 0000' \ + '03626172c00c 0001 0001 00000000 0004 0a000005' \ + '05626c617a32c00c 00ff 00fe 00000000 0000' \ + 'c049 0001 00fe 00000000 0000' \ + 'c019 0001 00ff 00000000 0000' \ + 'c019 0001 0001 0000012c 0004 0a000001' \ + 'c019 0001 0001 0000012c 0004 0a000002' \ + 'c035 0001 0001 0000012c 0004 0a000003' \ + 'c035 0001 00fe 00000000 0004 0a000004' \ + '04626c617ac00c 0001 00ff 00000000 0000' \ + 'c049 00ff 00ff 00000000 0000' + +goodwire = goodhex.replace(' ', '').decode('hex_codec') + +update_text="""id 1 +opcode UPDATE +rcode NOERROR +;ZONE +example. IN SOA +;PREREQ +foo ANY ANY +foo ANY A +bar 0 IN A 10.0.0.5 +blaz2 NONE ANY +blaz2 NONE A +;UPDATE +foo ANY A +foo 300 IN A 10.0.0.1 +foo 300 IN A 10.0.0.2 +bar 300 IN A 10.0.0.3 +bar 0 NONE A 10.0.0.4 +blaz ANY A +blaz2 ANY ANY +""" + +class UpdateTestCase(unittest.TestCase): + + def test_to_wire1(self): + update = dns.update.Update('example') + update.id = 1 + update.present('foo') + update.present('foo', 'a') + update.present('bar', 'a', '10.0.0.5') + update.absent('blaz2') + update.absent('blaz2', 'a') + update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') + update.add('bar', 300, 'a', '10.0.0.3') + update.delete('bar', 'a', '10.0.0.4') + update.delete('blaz','a') + update.delete('blaz2') + self.failUnless(update.to_wire() == goodwire) + + def test_to_wire2(self): + update = dns.update.Update('example') + update.id = 1 + update.present('foo') + update.present('foo', 'a') + update.present('bar', 'a', '10.0.0.5') + update.absent('blaz2') + update.absent('blaz2', 'a') + update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') + update.add('bar', 300, dns.rdata.from_text(1, 1, '10.0.0.3')) + update.delete('bar', 'a', '10.0.0.4') + update.delete('blaz','a') + update.delete('blaz2') + self.failUnless(update.to_wire() == goodwire) + + def test_to_wire3(self): + update = dns.update.Update('example') + update.id = 1 + update.present('foo') + update.present('foo', 'a') + update.present('bar', 'a', '10.0.0.5') + update.absent('blaz2') + update.absent('blaz2', 'a') + update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') + update.add('bar', dns.rdataset.from_text(1, 1, 300, '10.0.0.3')) + update.delete('bar', 'a', '10.0.0.4') + update.delete('blaz','a') + update.delete('blaz2') + self.failUnless(update.to_wire() == goodwire) + + def test_from_text1(self): + update = dns.message.from_text(update_text) + w = update.to_wire(origin=dns.name.from_text('example'), + want_shuffle=False) + self.failUnless(w == goodwire) + +if __name__ == '__main__': + unittest.main() diff --git a/source4/scripting/python/samba_external/dnspython/tests/zone.py b/source4/scripting/python/samba_external/dnspython/tests/zone.py new file mode 100644 index 0000000000..a8d629c532 --- /dev/null +++ b/source4/scripting/python/samba_external/dnspython/tests/zone.py @@ -0,0 +1,389 @@ +# 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 filecmp +import os +import unittest + +import dns.exception +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset +import dns.zone + +example_text = """$TTL 3600 +$ORIGIN example. +@ soa foo bar 1 2 3 4 5 +@ ns ns1 +@ ns ns2 +ns1 a 10.0.0.1 +ns2 a 10.0.0.2 +$TTL 300 +$ORIGIN foo.example. +bar mx 0 blaz +""" + +example_text_output = """@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +""" + +something_quite_similar = """@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.3 +""" + +something_different = """@ 3600 IN SOA fooa bar 1 2 3 4 5 +@ 3600 IN NS ns11 +@ 3600 IN NS ns21 +bar.fooa 300 IN MX 0 blaz.fooa +ns11 3600 IN A 10.0.0.11 +ns21 3600 IN A 10.0.0.21 +""" + +ttl_example_text = """$TTL 1h +$ORIGIN example. +@ soa foo bar 1 2 3 4 5 +@ ns ns1 +@ ns ns2 +ns1 1d1s a 10.0.0.1 +ns2 1w1D1h1m1S a 10.0.0.2 +""" + +no_soa_text = """$TTL 1h +$ORIGIN example. +@ ns ns1 +@ ns ns2 +ns1 1d1s a 10.0.0.1 +ns2 1w1D1h1m1S a 10.0.0.2 +""" + +no_ns_text = """$TTL 1h +$ORIGIN example. +@ soa foo bar 1 2 3 4 5 +""" + +include_text = """$INCLUDE "example" +""" + +bad_directive_text = """$FOO bar +$ORIGIN example. +@ soa foo bar 1 2 3 4 5 +@ ns ns1 +@ ns ns2 +ns1 1d1s a 10.0.0.1 +ns2 1w1D1h1m1S a 10.0.0.2 +""" + +_keep_output = False + +class ZoneTestCase(unittest.TestCase): + + def testFromFile1(self): + z = dns.zone.from_file('example', 'example') + ok = False + try: + z.to_file('example1.out', nl='\x0a') + ok = filecmp.cmp('example1.out', 'example1.good') + finally: + if not _keep_output: + os.unlink('example1.out') + self.failUnless(ok) + + def testFromFile2(self): + z = dns.zone.from_file('example', 'example', relativize=False) + ok = False + try: + z.to_file('example2.out', relativize=False, nl='\x0a') + ok = filecmp.cmp('example2.out', 'example2.good') + finally: + if not _keep_output: + os.unlink('example2.out') + self.failUnless(ok) + + def testFromText(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + f = cStringIO.StringIO() + names = z.nodes.keys() + names.sort() + for n in names: + print >> f, z[n].to_text(n) + self.failUnless(f.getvalue() == example_text_output) + + def testTorture1(self): + # + # Read a zone containing all our supported RR types, and + # for each RR in the zone, convert the rdata into wire format + # and then back out, and see if we get equal rdatas. + # + f = cStringIO.StringIO() + o = dns.name.from_text('example.') + z = dns.zone.from_file('example', o) + for (name, node) in z.iteritems(): + for rds in node: + for rd in rds: + f.seek(0) + f.truncate() + rd.to_wire(f, origin=o) + wire = f.getvalue() + rd2 = dns.rdata.from_wire(rds.rdclass, rds.rdtype, + wire, 0, len(wire), + origin = o) + self.failUnless(rd == rd2) + + def testEqual(self): + z1 = dns.zone.from_text(example_text, 'example.', relativize=True) + z2 = dns.zone.from_text(example_text_output, 'example.', + relativize=True) + self.failUnless(z1 == z2) + + def testNotEqual1(self): + z1 = dns.zone.from_text(example_text, 'example.', relativize=True) + z2 = dns.zone.from_text(something_quite_similar, 'example.', + relativize=True) + self.failUnless(z1 != z2) + + def testNotEqual2(self): + z1 = dns.zone.from_text(example_text, 'example.', relativize=True) + z2 = dns.zone.from_text(something_different, 'example.', + relativize=True) + self.failUnless(z1 != z2) + + def testNotEqual3(self): + z1 = dns.zone.from_text(example_text, 'example.', relativize=True) + z2 = dns.zone.from_text(something_different, 'example2.', + relativize=True) + self.failUnless(z1 != z2) + + def testFindRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rds = z.find_rdataset('@', 'soa') + exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') + self.failUnless(rds == exrds) + + def testFindRdataset2(self): + def bad(): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rds = z.find_rdataset('@', 'loc') + self.failUnlessRaises(KeyError, bad) + + def testFindRRset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rrs = z.find_rrset('@', 'soa') + exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') + self.failUnless(rrs == exrrs) + + def testFindRRset2(self): + def bad(): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rrs = z.find_rrset('@', 'loc') + self.failUnlessRaises(KeyError, bad) + + def testGetRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rds = z.get_rdataset('@', 'soa') + exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') + self.failUnless(rds == exrds) + + def testGetRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rds = z.get_rdataset('@', 'loc') + self.failUnless(rds == None) + + def testGetRRset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rrs = z.get_rrset('@', 'soa') + exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') + self.failUnless(rrs == exrrs) + + def testGetRRset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rrs = z.get_rrset('@', 'loc') + self.failUnless(rrs == None) + + def testReplaceRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rdataset = dns.rdataset.from_text('in', 'ns', 300, 'ns3', 'ns4') + z.replace_rdataset('@', rdataset) + rds = z.get_rdataset('@', 'ns') + self.failUnless(rds is rdataset) + + def testReplaceRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + rdataset = dns.rdataset.from_text('in', 'txt', 300, '"foo"') + z.replace_rdataset('@', rdataset) + rds = z.get_rdataset('@', 'txt') + self.failUnless(rds is rdataset) + + def testDeleteRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + z.delete_rdataset('@', 'ns') + rds = z.get_rdataset('@', 'ns') + self.failUnless(rds is None) + + def testDeleteRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + z.delete_rdataset('ns1', 'a') + node = z.get_node('ns1') + self.failUnless(node is None) + + def testNodeFindRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') + self.failUnless(rds == exrds) + + def testNodeFindRdataset2(self): + def bad(): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + self.failUnlessRaises(KeyError, bad) + + def testNodeGetRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') + self.failUnless(rds == exrds) + + def testNodeGetRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + self.failUnless(rds == None) + + def testNodeDeleteRdataset1(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + self.failUnless(rds == None) + + def testNodeDeleteRdataset2(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + node = z['@'] + rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + self.failUnless(rds == None) + + def testIterateRdatasets(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + ns = [n for n, r in z.iterate_rdatasets('A')] + ns.sort() + self.failUnless(ns == [dns.name.from_text('ns1', None), + dns.name.from_text('ns2', None)]) + + def testIterateAllRdatasets(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + ns = [n for n, r in z.iterate_rdatasets()] + ns.sort() + self.failUnless(ns == [dns.name.from_text('@', None), + dns.name.from_text('@', None), + dns.name.from_text('bar.foo', None), + dns.name.from_text('ns1', None), + dns.name.from_text('ns2', None)]) + + def testIterateRdatas(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + l = list(z.iterate_rdatas('A')) + l.sort() + exl = [(dns.name.from_text('ns1', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2'))] + self.failUnless(l == exl) + + def testIterateAllRdatas(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2'))] + self.failUnless(l == exl) + + def testTTLs(self): + z = dns.zone.from_text(ttl_example_text, 'example.', relativize=True) + n = z['@'] + rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + self.failUnless(rds.ttl == 3600) + n = z['ns1'] + rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + self.failUnless(rds.ttl == 86401) + n = z['ns2'] + rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + self.failUnless(rds.ttl == 694861) + + def testNoSOA(self): + def bad(): + z = dns.zone.from_text(no_soa_text, 'example.', + relativize=True) + self.failUnlessRaises(dns.zone.NoSOA, bad) + + def testNoNS(self): + def bad(): + z = dns.zone.from_text(no_ns_text, 'example.', + relativize=True) + self.failUnlessRaises(dns.zone.NoNS, bad) + + def testInclude(self): + z1 = dns.zone.from_text(include_text, 'example.', relativize=True, + allow_include=True) + z2 = dns.zone.from_file('example', 'example.', relativize=True) + self.failUnless(z1 == z2) + + def testBadDirective(self): + def bad(): + z = dns.zone.from_text(bad_directive_text, 'example.', + relativize=True) + self.failUnlessRaises(dns.exception.SyntaxError, bad) + +if __name__ == '__main__': + unittest.main() |