[Python-modules-commits] [python-dnslib] 01/03: import python-dnslib_0.9.7+hg20170303.orig.tar.gz

Scott Kitterman kitterman at moszumanska.debian.org
Fri Mar 3 19:50:07 UTC 2017


This is an automated email from the git hooks/post-receive script.

kitterman pushed a commit to branch master
in repository python-dnslib.

commit 3875f6f69b7c83ca346a479aa12e7b6cb018ac21
Author: Scott Kitterman <scott at kitterman.com>
Date:   Fri Mar 3 13:58:29 2017 -0500

    import python-dnslib_0.9.7+hg20170303.orig.tar.gz
---
 .hg_archival.txt                               |    6 +
 .hgignore                                      |   11 +
 .hgtags                                        |   18 +
 LICENSE                                        |   22 +
 MANIFEST.in                                    |    5 +
 README                                         |  334 +++++
 README.github                                  |    7 +
 dnslib/__init__.py                             |  347 +++++
 dnslib/bimap.py                                |   78 ++
 dnslib/bit.py                                  |   89 ++
 dnslib/buffer.py                               |  114 ++
 dnslib/client.py                               |  129 ++
 dnslib/digparser.py                            |  214 +++
 dnslib/dns.py                                  | 1732 ++++++++++++++++++++++++
 dnslib/fixedresolver.py                        |   98 ++
 dnslib/intercept.py                            |  163 +++
 dnslib/label.py                                |  292 ++++
 dnslib/lex.py                                  |  356 +++++
 dnslib/proxy.py                                |  158 +++
 dnslib/ranges.py                               |  141 ++
 dnslib/server.py                               |  363 +++++
 dnslib/shellresolver.py                        |  116 ++
 dnslib/test/20120113._domainkey.gmail.com.-TXT |   16 +
 dnslib/test/_sip._udp.sipgate.co.uk-SRV        |   16 +
 dnslib/test/dig/google.com-A.dig               |   40 +
 dnslib/test/dig/google.com-ANY.dig             |   27 +
 dnslib/test/e164.org-NAPTR                     |   16 +
 dnslib/test/example.com-ANY                    |   33 +
 dnslib/test/facebook.com-AAAA                  |   16 +
 dnslib/test/google.com-A                       |   31 +
 dnslib/test/google.com-AAAA                    |   16 +
 dnslib/test/google.com-ANY                     |   29 +
 dnslib/test/google.com-MX                      |   20 +
 dnslib/test/google.com-SOA                     |   16 +
 dnslib/test/google.com-TXT                     |   16 +
 dnslib/test/iana.org-ANY                       |   43 +
 dnslib/test/in-addr.arpa-PTR                   |   16 +
 dnslib/test/microsoft.com-ANY                  |   26 +
 dnslib/test/sip2sip.info-ANY                   |   23 +
 dnslib/test/sip2sip.info-NAPTR                 |   18 +
 dnslib/test/sipgate.co.uk-ANY                  |   27 +
 dnslib/test_decode.py                          |  275 ++++
 dnslib/zoneresolver.py                         |  118 ++
 fuzz.py                                        |   98 ++
 hgrc                                           |    4 +
 run_tests.sh                                   |   21 +
 setup.py                                       |   35 +
 47 files changed, 5789 insertions(+)

diff --git a/.hg_archival.txt b/.hg_archival.txt
new file mode 100644
index 0000000..6cbcca4
--- /dev/null
+++ b/.hg_archival.txt
@@ -0,0 +1,6 @@
+repo: d355b90ca65b2ded0ce7eb1cc05b56fb52188fca
+node: d2c17b8b154de94deabd981dda84f65c1e084565
+branch: default
+latesttag: 0.9.7
+latesttagdistance: 8
+changessincelatesttag: 8
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..cbedc9e
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,11 @@
+syntax: glob
+
+*.swp
+*.pyc
+*~
+*egg-info
+.DS_Store
+build
+dist
+MANIFEST
+PKG-INFO
diff --git a/.hgtags b/.hgtags
new file mode 100644
index 0000000..08d44be
--- /dev/null
+++ b/.hgtags
@@ -0,0 +1,18 @@
+5d1c34b512568beea78225a0ce0b14d31e63695a py3-release
+6622f8dfda7196c992c548c6cb3204dac0a099c8 0.8.3
+5a67733005e02cf59cdec44f5f8a0289295178ad py2
+78b64356f780269694d12b86e86d206c918c49fe 0.9.3
+78b64356f780269694d12b86e86d206c918c49fe 0.9.3
+b8d4bd109949da943c03363606cd98d971bebcc5 0.9.3
+a248c72d340fd80ec8164a9f9d0ff1ab887f327a 0.9.4
+ef31508b35d5cf7b83b76743d2f7ef94efce818f 0.9.5
+ef31508b35d5cf7b83b76743d2f7ef94efce818f 0.9.5
+0000000000000000000000000000000000000000 0.9.5
+0000000000000000000000000000000000000000 0.9.5
+12c05da42f9cf151579642e28496f8bd9e7194a3 0.9.5
+13d7ed4d6c62bcb23cbd8792b86b873c64d774c0 0.9.6
+13d7ed4d6c62bcb23cbd8792b86b873c64d774c0 0.9.6
+0000000000000000000000000000000000000000 0.9.6
+0000000000000000000000000000000000000000 0.9.6
+c6871d81b4f85c2028a2a2665633698e37321c40 0.9.6
+f303b7091b8bcc4f07ed46c5364992a20b5fc405 0.9.7
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ebcb003
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2010 - 2017 Paul Chakravarti.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..6fd08b3
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,5 @@
+include README.github
+include run_tests.sh
+include fuzz.py
+include LICENSE
+recursive-include dnslib/test *
diff --git a/README b/README
new file mode 100644
index 0000000..d90d97d
--- /dev/null
+++ b/README
@@ -0,0 +1,334 @@
+
+dnslib
+------
+
+A library to encode/decode DNS wire-format packets supporting both 
+Python 2.7 and Python 3.2+.
+
+The library provides:
+
+ * Support for encoding/decoding DNS packets between wire format,
+   python objects, and Zone/DiG textual representation (dnslib.dns)
+
+ * A server framework allowing the simple creation of custom DNS 
+   resolvers (dnslib.server) and a number of example servers 
+   created using this framework
+
+ * A number of utilities for testing (dnslib.client, dnslib.proxy,
+   dnslib.intercept)
+
+Python 3 support was added in Version 0.9.0 which represented a fairly
+major update to the library - the key changes include:
+
+ * Python 2.7/3.2+ support (the last version supporting Python 2.6 
+   or earlier was version 0.8.3)
+
+ * The 'Bimap' interface was changed significantly to explicitly 
+   split forward (value->text) lookups via __getitem__ and 
+   reverse (text->value) lookups via __getattr__. Applications
+   using the old interface will need to be updated.
+
+ * Hostnames are now returned with a trailing dot by default (in
+   line with RFC)
+
+ * Most object attributes are now typed in line with the record
+   definitions to make it harder to generate invalid packets 
+
+ * Support for encoding/decoding resource records in 'Zone' (BIND) 
+   file format 
+
+ * Support for encoding/decoding packets in 'DiG' format
+
+ * Server framework allowing (in most cases) custom resolvers to
+   be created by just subclassing the DNSResolver class and 
+   overriding the 'resolve' method
+
+ * A lot of fixes to error detection/handling which should make 
+   the library much more robust to invalid/unsupported data. The
+   library should now either return a valid DNSRecord instance
+   when parsing a packet or raise DNSError (tested via fuzzing)
+
+ * Improved utilities (dnslib.client, dnslib.proxy, dnslib.intercept)
+
+ * Improvements to encoding/decoding tests including the ability
+   to generate test data automatically in test_decode.py (comparing
+   outputs against DiG)
+
+ * Ability to compare and diff DNSRecords
+
+Classes
+-------
+
+The key DNS packet handling classes are in dnslib.dns and map to the 
+standard DNS packet sections:
+
+ * DNSRecord - container for DNS packet. Contains:
+    - DNSHeader 
+    - Question section containing zero or more DNSQuestion objects 
+    - Answer section containing zero or more RR objects 
+    - Authority section containing zero or more RR objects 
+    - Additional section containing zero or more RR objects 
+ * DNS RRs (resource records) contain an RR header and an RD object)
+ * Specific RD types are implemented as subclasses of RD
+ * DNS labels are represented by a DNSLabel class - in most cases
+   this handles conversion to/from textual representation however
+   does support arbitatry labels via a tuple of bytes objects
+
+Usage
+-----
+
+To decode a DNS packet:
+
+    >>> packet = binascii.unhexlify(b'd5ad818000010005000000000377777706676f6f676c6503636f6d0000010001c00c0005000100000005000803777777016cc010c02c0001000100000005000442f95b68c02c0001000100000005000442f95b63c02c0001000100000005000442f95b67c02c0001000100000005000442f95b93')
+    >>> d = DNSRecord.parse(packet)
+    >>> d
+    <DNS Header: id=0xd5ad type=RESPONSE opcode=QUERY flags=RD,RA rcode='NOERROR' q=1 a=5 ns=0 ar=0>
+    <DNS Question: 'www.google.com.' qtype=A qclass=IN>
+    <DNS RR: 'www.google.com.' rtype=CNAME rclass=IN ttl=5 rdata='www.l.google.com.'>
+    <DNS RR: 'www.l.google.com.' rtype=A rclass=IN ttl=5 rdata='66.249.91.104'>
+    <DNS RR: 'www.l.google.com.' rtype=A rclass=IN ttl=5 rdata='66.249.91.99'>
+    <DNS RR: 'www.l.google.com.' rtype=A rclass=IN ttl=5 rdata='66.249.91.103'>
+    <DNS RR: 'www.l.google.com.' rtype=A rclass=IN ttl=5 rdata='66.249.91.147'>
+
+The default text representation of the DNSRecord is in zone file format:
+
+    >>> print(d)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54701
+    ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;www.google.com.                IN      A
+    ;; ANSWER SECTION:
+    www.google.com.         5       IN      CNAME   www.l.google.com.
+    www.l.google.com.       5       IN      A       66.249.91.104
+    www.l.google.com.       5       IN      A       66.249.91.99
+    www.l.google.com.       5       IN      A       66.249.91.103
+    www.l.google.com.       5       IN      A       66.249.91.147
+
+To create a DNS Request Packet:
+
+    >>> d = DNSRecord.question("google.com")
+
+(This is equivalent to: d = DNSRecord(q=DNSQuestion("google.com") )
+
+    >>> d
+    <DNS Header: id=... type=QUERY opcode=QUERY flags=RD rcode='NOERROR' q=1 a=0 ns=0 ar=0>
+    <DNS Question: 'google.com.' qtype=A qclass=IN>
+
+    >>> str(DNSRecord.parse(d.pack())) == str(d)
+    True
+
+    >>> print(d)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;google.com.                    IN      A
+
+    >>> d = DNSRecord.question("google.com","MX")
+
+(This is equivalent to: d = DNSRecord(q=DNSQuestion("google.com",QTYPE.MX) )
+
+    >>> str(DNSRecord.parse(d.pack())) == str(d)
+    True
+
+    >>> print(d)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;google.com.                    IN      MX
+
+To create a DNS Response Packet:
+
+    >>> d = DNSRecord(DNSHeader(qr=1,aa=1,ra=1),
+    ...               q=DNSQuestion("abc.com"),
+    ...               a=RR("abc.com",rdata=A("1.2.3.4")))
+    >>> d
+    <DNS Header: id=... type=RESPONSE opcode=QUERY flags=AA,RD,RA rcode='NOERROR' q=1 a=1 ns=0 ar=0>
+    <DNS Question: 'abc.com.' qtype=A qclass=IN>
+    <DNS RR: 'abc.com.' rtype=A rclass=IN ttl=0 rdata='1.2.3.4'>
+    >>> str(DNSRecord.parse(d.pack())) == str(d)
+    True
+
+    >>> print(d)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      A
+    ;; ANSWER SECTION:
+    abc.com.                0       IN      A       1.2.3.4
+
+It is also possible to create RRs from a string in zone file format
+
+    >>> RR.fromZone("abc.com IN A 1.2.3.4")
+    [<DNS RR: 'abc.com.' rtype=A rclass=IN ttl=0 rdata='1.2.3.4'>]
+
+(Note: this produces a list of RRs which should be unpacked if being
+    passed to add_answer/add_auth/add_ar etc)
+
+    >>> q = DNSRecord.question("abc.com")
+    >>> a = q.reply()
+    >>> a.add_answer(*RR.fromZone("abc.com 60 A 1.2.3.4"))
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      A
+    ;; ANSWER SECTION:
+    abc.com.                60      IN      A       1.2.3.4
+
+The zone file can contain multiple entries and supports most of the normal
+format defined in RFC1035 (specifically not $INCLUDE)
+
+    >>> z = '''
+    ...         $TTL 300
+    ...         $ORIGIN abc.com
+    ...
+    ...         @       IN      MX      10  mail.abc.com.
+    ...         www     IN      A       1.2.3.4
+    ...                 IN      TXT     "Some Text"
+    ...         mail    IN      CNAME   www.abc.com.
+    ... '''
+    >>> for rr in RR.fromZone(textwrap.dedent(z)):
+    ...     print(rr)
+    abc.com.                300     IN      MX      10 mail.abc.com.
+    www.abc.com.            300     IN      A       1.2.3.4
+    www.abc.com.            300     IN      TXT     "Some Text"
+    mail.abc.com.           300     IN      CNAME   www.abc.com.
+
+To create a skeleton reply to a DNS query:
+
+    >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.ANY)) 
+    >>> a = q.reply()
+    >>> a.add_answer(RR("abc.com",QTYPE.A,rdata=A("1.2.3.4"),ttl=60))
+    >>> str(DNSRecord.parse(a.pack())) == str(a)
+    True
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      ANY
+    ;; ANSWER SECTION:
+    abc.com.                60      IN      A       1.2.3.4
+
+Add additional RRs:
+
+    >>> a.add_answer(RR("xxx.abc.com",QTYPE.A,rdata=A("1.2.3.4")))
+    >>> a.add_answer(RR("xxx.abc.com",QTYPE.AAAA,rdata=AAAA("1234:5678::1")))
+    >>> str(DNSRecord.parse(a.pack())) == str(a)
+    True
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      ANY
+    ;; ANSWER SECTION:
+    abc.com.                60      IN      A       1.2.3.4
+    xxx.abc.com.            0       IN      A       1.2.3.4
+    xxx.abc.com.            0       IN      AAAA    1234:5678::1
+
+
+It is also possible to create a reply from a string in zone file format:
+
+    >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.ANY)) 
+    >>> a = q.replyZone("abc.com 60 IN CNAME xxx.abc.com")
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      ANY
+    ;; ANSWER SECTION:
+    abc.com.                60      IN      CNAME   xxx.abc.com.
+
+    >>> str(DNSRecord.parse(a.pack())) == str(a)
+    True
+
+    >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.ANY)) 
+    >>> a = q.replyZone(textwrap.dedent(z))
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      ANY
+    ;; ANSWER SECTION:
+    abc.com.                300     IN      MX      10 mail.abc.com.
+    www.abc.com.            300     IN      A       1.2.3.4
+    www.abc.com.            300     IN      TXT     "Some Text"
+    mail.abc.com.           300     IN      CNAME   www.abc.com.
+
+
+The library also includes a simple framework for generating custom DNS
+resolvers in dnslib.server (see module docs). In post cases this just 
+requires implementing a custom 'resolve' method which receives a question 
+object and returns a response.
+
+A number of sample resolvers are provided as examples (see CLI --help):
+
+ * dnslib.fixedresolver    - Respond to all requests with fixed response
+ * dnslib.zoneresolver     - Respond from Zone file 
+ * dnslib.shellresolver    - Call shell script to generate response
+
+The library includes a number of client utilities:
+
+ * DiG like client library 
+
+        # python -m dnslib.client --help
+
+ * DNS Proxy Server
+
+        # python -m dnslib.proxy --help
+
+ * Intercepting DNS Proxy Server (replace proxy responses for specified domains)
+
+        # python -m dnslib.intercept --help
+
+
+Changelog:
+----------
+
+ *   0.1     2010-09-19  Initial Release
+ *   0.2     2010-09-22  Minor fixes
+ *   0.3     2010-10-02  Add DNSLabel class to support arbitrary labels (embedded '.')
+ *   0.4     2012-02-26  Merge with dbslib-circuits
+ *   0.5     2012-09-13  Add support for RFC2136 DDNS updates
+                         Patch provided by Wesley Shields <wxs at FreeBSD.org> - thanks
+ *   0.6     2012-10-20  Basic AAAA support
+ *   0.7     2012-10-20  Add initial EDNS0 support (untested)
+ *   0.8     2012-11-04  Add support for NAPTR, Authority RR and additional RR
+                         Patch provided by Stefan Andersson (https://bitbucket.org/norox) - thanks
+ *   0.8.1   2012-11-05  Added NAPTR test case and fixed logic error
+                         Patch provided by Stefan Andersson (https://bitbucket.org/norox) - thanks
+ *   0.8.2   2012-11-11  Patch to fix IPv6 formatting
+                         Patch provided by Torbjörn Lönnemark (https://bitbucket.org/tobbezz) - thanks
+ *   0.8.3   2013-04-27  Don't parse rdata if rdlength is 0
+                         Patch provided by Wesley Shields <wxs at FreeBSD.org> - thanks
+ *   0.9.0   2014-05-05  Major update including Py3 support (see docs)
+ *   0.9.1   2014-05-05  Minor fixes
+ *   0.9.2   2014-08-26  Fix Bimap handling of unknown mappings to avoid exception in printing
+                         Add typed attributes to classes
+                         Misc fixes from James Mills - thanks
+ *   0.9.3   2014-08-26  Workaround for argparse bug which raises AssertionError if [] is
+                         present in option text (really?)
+ *   0.9.4   2015-04-10  Fix to support multiple strings in TXT record 
+                         Patch provided by James Cherry (https://bitbucket.org/james_cherry) - thanks
+                         NOTE: For consistency this patch changes the 'repr' output for
+                               TXT records to always be quoted
+ *   0.9.5   2015-10-27  Add threading & timeout handling to DNSServer
+ *   0.9.6   2015-10-28  Replace strftime in RRSIG formatting to avoid possible locale issues
+                         Identified by Bryan Everly - thanks
+ *   0.9.7   2017-01-15  Sort out CAA/TYPE257 DiG parsing mismatch 
+
+License:
+--------
+
+BSD
+
+Author:
+-------
+
+ *   Paul Chakravarti (paul.chakravarti at gmail.com)
+
+Master Repository/Issues:
+-------------------------
+
+ *   https://bitbucket.org/paulc/dnslib
+     (Cloned on GitHub: https://github.com/paulchakravarti/dnslib)
+
diff --git a/README.github b/README.github
new file mode 100644
index 0000000..cdd9693
--- /dev/null
+++ b/README.github
@@ -0,0 +1,7 @@
+
+This repository is a clone of the master repository at:
+
+	https://bitbucket.org/paulc/dnslib
+
+For any issues please use the Bitbucket repository
+
diff --git a/dnslib/__init__.py b/dnslib/__init__.py
new file mode 100644
index 0000000..75c58ed
--- /dev/null
+++ b/dnslib/__init__.py
@@ -0,0 +1,347 @@
+# -*- coding: utf-8 -*-
+
+"""
+dnslib
+------
+
+A library to encode/decode DNS wire-format packets supporting both 
+Python 2.7 and Python 3.2+.
+
+The library provides:
+
+ * Support for encoding/decoding DNS packets between wire format,
+   python objects, and Zone/DiG textual representation (dnslib.dns)
+
+ * A server framework allowing the simple creation of custom DNS 
+   resolvers (dnslib.server) and a number of example servers 
+   created using this framework
+
+ * A number of utilities for testing (dnslib.client, dnslib.proxy,
+   dnslib.intercept)
+
+Python 3 support was added in Version 0.9.0 which represented a fairly
+major update to the library - the key changes include:
+
+ * Python 2.7/3.2+ support (the last version supporting Python 2.6 
+   or earlier was version 0.8.3)
+
+ * The 'Bimap' interface was changed significantly to explicitly 
+   split forward (value->text) lookups via __getitem__ and 
+   reverse (text->value) lookups via __getattr__. Applications
+   using the old interface will need to be updated.
+
+ * Hostnames are now returned with a trailing dot by default (in
+   line with RFC)
+
+ * Most object attributes are now typed in line with the record
+   definitions to make it harder to generate invalid packets 
+
+ * Support for encoding/decoding resource records in 'Zone' (BIND) 
+   file format 
+
+ * Support for encoding/decoding packets in 'DiG' format
+
+ * Server framework allowing (in most cases) custom resolvers to
+   be created by just subclassing the DNSResolver class and 
+   overriding the 'resolve' method
+
+ * A lot of fixes to error detection/handling which should make 
+   the library much more robust to invalid/unsupported data. The
+   library should now either return a valid DNSRecord instance
+   when parsing a packet or raise DNSError (tested via fuzzing)
+
+ * Improved utilities (dnslib.client, dnslib.proxy, dnslib.intercept)
+
+ * Improvements to encoding/decoding tests including the ability
+   to generate test data automatically in test_decode.py (comparing
+   outputs against DiG)
+
+ * Ability to compare and diff DNSRecords
+
+Classes
+-------
+
+The key DNS packet handling classes are in dnslib.dns and map to the 
+standard DNS packet sections:
+
+ * DNSRecord - container for DNS packet. Contains:
+    - DNSHeader 
+    - Question section containing zero or more DNSQuestion objects 
+    - Answer section containing zero or more RR objects 
+    - Authority section containing zero or more RR objects 
+    - Additional section containing zero or more RR objects 
+ * DNS RRs (resource records) contain an RR header and an RD object)
+ * Specific RD types are implemented as subclasses of RD
+ * DNS labels are represented by a DNSLabel class - in most cases
+   this handles conversion to/from textual representation however
+   does support arbitatry labels via a tuple of bytes objects
+
+Usage
+-----
+
+To decode a DNS packet:
+
+    >>> packet = binascii.unhexlify(b'd5ad818000010005000000000377777706676f6f676c6503636f6d0000010001c00c0005000100000005000803777777016cc010c02c0001000100000005000442f95b68c02c0001000100000005000442f95b63c02c0001000100000005000442f95b67c02c0001000100000005000442f95b93')
+    >>> d = DNSRecord.parse(packet)
+    >>> d
+    <DNS Header: id=0xd5ad type=RESPONSE opcode=QUERY flags=RD,RA rcode='NOERROR' q=1 a=5 ns=0 ar=0>
+    <DNS Question: 'www.google.com.' qtype=A qclass=IN>
+    <DNS RR: 'www.google.com.' rtype=CNAME rclass=IN ttl=5 rdata='www.l.google.com.'>
+    <DNS RR: 'www.l.google.com.' rtype=A rclass=IN ttl=5 rdata='66.249.91.104'>
+    <DNS RR: 'www.l.google.com.' rtype=A rclass=IN ttl=5 rdata='66.249.91.99'>
+    <DNS RR: 'www.l.google.com.' rtype=A rclass=IN ttl=5 rdata='66.249.91.103'>
+    <DNS RR: 'www.l.google.com.' rtype=A rclass=IN ttl=5 rdata='66.249.91.147'>
+
+The default text representation of the DNSRecord is in zone file format:
+
+    >>> print(d)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54701
+    ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;www.google.com.                IN      A
+    ;; ANSWER SECTION:
+    www.google.com.         5       IN      CNAME   www.l.google.com.
+    www.l.google.com.       5       IN      A       66.249.91.104
+    www.l.google.com.       5       IN      A       66.249.91.99
+    www.l.google.com.       5       IN      A       66.249.91.103
+    www.l.google.com.       5       IN      A       66.249.91.147
+
+To create a DNS Request Packet:
+
+    >>> d = DNSRecord.question("google.com")
+
+(This is equivalent to: d = DNSRecord(q=DNSQuestion("google.com") )
+
+    >>> d
+    <DNS Header: id=... type=QUERY opcode=QUERY flags=RD rcode='NOERROR' q=1 a=0 ns=0 ar=0>
+    <DNS Question: 'google.com.' qtype=A qclass=IN>
+
+    >>> str(DNSRecord.parse(d.pack())) == str(d)
+    True
+
+    >>> print(d)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;google.com.                    IN      A
+
+    >>> d = DNSRecord.question("google.com","MX")
+
+(This is equivalent to: d = DNSRecord(q=DNSQuestion("google.com",QTYPE.MX) )
+
+    >>> str(DNSRecord.parse(d.pack())) == str(d)
+    True
+
+    >>> print(d)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;google.com.                    IN      MX
+
+To create a DNS Response Packet:
+
+    >>> d = DNSRecord(DNSHeader(qr=1,aa=1,ra=1),
+    ...               q=DNSQuestion("abc.com"),
+    ...               a=RR("abc.com",rdata=A("1.2.3.4")))
+    >>> d
+    <DNS Header: id=... type=RESPONSE opcode=QUERY flags=AA,RD,RA rcode='NOERROR' q=1 a=1 ns=0 ar=0>
+    <DNS Question: 'abc.com.' qtype=A qclass=IN>
+    <DNS RR: 'abc.com.' rtype=A rclass=IN ttl=0 rdata='1.2.3.4'>
+    >>> str(DNSRecord.parse(d.pack())) == str(d)
+    True
+
+    >>> print(d)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      A
+    ;; ANSWER SECTION:
+    abc.com.                0       IN      A       1.2.3.4
+
+It is also possible to create RRs from a string in zone file format
+
+    >>> RR.fromZone("abc.com IN A 1.2.3.4")
+    [<DNS RR: 'abc.com.' rtype=A rclass=IN ttl=0 rdata='1.2.3.4'>]
+
+(Note: this produces a list of RRs which should be unpacked if being
+    passed to add_answer/add_auth/add_ar etc)
+
+    >>> q = DNSRecord.question("abc.com")
+    >>> a = q.reply()
+    >>> a.add_answer(*RR.fromZone("abc.com 60 A 1.2.3.4"))
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      A
+    ;; ANSWER SECTION:
+    abc.com.                60      IN      A       1.2.3.4
+
+The zone file can contain multiple entries and supports most of the normal
+format defined in RFC1035 (specifically not $INCLUDE)
+
+    >>> z = '''
+    ...         $TTL 300
+    ...         $ORIGIN abc.com
+    ...
+    ...         @       IN      MX      10  mail.abc.com.
+    ...         www     IN      A       1.2.3.4
+    ...                 IN      TXT     "Some Text"
+    ...         mail    IN      CNAME   www.abc.com.
+    ... '''
+    >>> for rr in RR.fromZone(textwrap.dedent(z)):
+    ...     print(rr)
+    abc.com.                300     IN      MX      10 mail.abc.com.
+    www.abc.com.            300     IN      A       1.2.3.4
+    www.abc.com.            300     IN      TXT     "Some Text"
+    mail.abc.com.           300     IN      CNAME   www.abc.com.
+
+To create a skeleton reply to a DNS query:
+
+    >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.ANY)) 
+    >>> a = q.reply()
+    >>> a.add_answer(RR("abc.com",QTYPE.A,rdata=A("1.2.3.4"),ttl=60))
+    >>> str(DNSRecord.parse(a.pack())) == str(a)
+    True
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      ANY
+    ;; ANSWER SECTION:
+    abc.com.                60      IN      A       1.2.3.4
+
+Add additional RRs:
+
+    >>> a.add_answer(RR("xxx.abc.com",QTYPE.A,rdata=A("1.2.3.4")))
+    >>> a.add_answer(RR("xxx.abc.com",QTYPE.AAAA,rdata=AAAA("1234:5678::1")))
+    >>> str(DNSRecord.parse(a.pack())) == str(a)
+    True
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      ANY
+    ;; ANSWER SECTION:
+    abc.com.                60      IN      A       1.2.3.4
+    xxx.abc.com.            0       IN      A       1.2.3.4
+    xxx.abc.com.            0       IN      AAAA    1234:5678::1
+
+
+It is also possible to create a reply from a string in zone file format:
+
+    >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.ANY)) 
+    >>> a = q.replyZone("abc.com 60 IN CNAME xxx.abc.com")
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      ANY
+    ;; ANSWER SECTION:
+    abc.com.                60      IN      CNAME   xxx.abc.com.
+
+    >>> str(DNSRecord.parse(a.pack())) == str(a)
+    True
+
+    >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.ANY)) 
+    >>> a = q.replyZone(textwrap.dedent(z))
+    >>> print(a)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      ANY
+    ;; ANSWER SECTION:
+    abc.com.                300     IN      MX      10 mail.abc.com.
+    www.abc.com.            300     IN      A       1.2.3.4
+    www.abc.com.            300     IN      TXT     "Some Text"
+    mail.abc.com.           300     IN      CNAME   www.abc.com.
+
+
+The library also includes a simple framework for generating custom DNS
+resolvers in dnslib.server (see module docs). In post cases this just 
+requires implementing a custom 'resolve' method which receives a question 
+object and returns a response.
+
+A number of sample resolvers are provided as examples (see CLI --help):
+
+ * dnslib.fixedresolver    - Respond to all requests with fixed response
+ * dnslib.zoneresolver     - Respond from Zone file 
+ * dnslib.shellresolver    - Call shell script to generate response
+
+The library includes a number of client utilities:
+
+ * DiG like client library 
+
+        # python -m dnslib.client --help
+
+ * DNS Proxy Server
+
+        # python -m dnslib.proxy --help
+
+ * Intercepting DNS Proxy Server (replace proxy responses for specified domains)
+
+        # python -m dnslib.intercept --help
+
+
+Changelog:
+----------
+
+ *   0.1     2010-09-19  Initial Release
+ *   0.2     2010-09-22  Minor fixes
+ *   0.3     2010-10-02  Add DNSLabel class to support arbitrary labels (embedded '.')
+ *   0.4     2012-02-26  Merge with dbslib-circuits
+ *   0.5     2012-09-13  Add support for RFC2136 DDNS updates
+                         Patch provided by Wesley Shields <wxs at FreeBSD.org> - thanks
+ *   0.6     2012-10-20  Basic AAAA support
+ *   0.7     2012-10-20  Add initial EDNS0 support (untested)
+ *   0.8     2012-11-04  Add support for NAPTR, Authority RR and additional RR
+                         Patch provided by Stefan Andersson (https://bitbucket.org/norox) - thanks
+ *   0.8.1   2012-11-05  Added NAPTR test case and fixed logic error
+                         Patch provided by Stefan Andersson (https://bitbucket.org/norox) - thanks
+ *   0.8.2   2012-11-11  Patch to fix IPv6 formatting
+                         Patch provided by Torbjörn Lönnemark (https://bitbucket.org/tobbezz) - thanks
+ *   0.8.3   2013-04-27  Don't parse rdata if rdlength is 0
+                         Patch provided by Wesley Shields <wxs at FreeBSD.org> - thanks
+ *   0.9.0   2014-05-05  Major update including Py3 support (see docs)
+ *   0.9.1   2014-05-05  Minor fixes
+ *   0.9.2   2014-08-26  Fix Bimap handling of unknown mappings to avoid exception in printing
+                         Add typed attributes to classes
+                         Misc fixes from James Mills - thanks
+ *   0.9.3   2014-08-26  Workaround for argparse bug which raises AssertionError if [] is
+                         present in option text (really?)
+ *   0.9.4   2015-04-10  Fix to support multiple strings in TXT record 
+                         Patch provided by James Cherry (https://bitbucket.org/james_cherry) - thanks
+                         NOTE: For consistency this patch changes the 'repr' output for
+                               TXT records to always be quoted
+ *   0.9.5   2015-10-27  Add threading & timeout handling to DNSServer
+ *   0.9.6   2015-10-28  Replace strftime in RRSIG formatting to avoid possible locale issues
+                         Identified by Bryan Everly - thanks
+ *   0.9.7   2017-01-15  Sort out CAA/TYPE257 DiG parsing mismatch 
+
+
+License:
+--------
+
+BSD
+
+Author:
+-------
+
+ *   Paul Chakravarti (paul.chakravarti at gmail.com)
+
+Master Repository/Issues:
+-------------------------
+
+ *   https://bitbucket.org/paulc/dnslib
+     (Cloned on GitHub: https://github.com/paulchakravarti/dnslib)
+
+"""
+
+from dnslib.dns import *
+
+version = "0.9.7"
+
+if __name__ == '__main__':
+    import doctest,textwrap
+    doctest.testmod(optionflags=doctest.ELLIPSIS)
+
diff --git a/dnslib/bimap.py b/dnslib/bimap.py
new file mode 100644
index 0000000..4cf9d37
--- /dev/null
+++ b/dnslib/bimap.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+
+"""
+    Bimap - bidirectional mapping between code/value
+"""
+
+class BimapError(Exception):
+    pass
+
+class Bimap(object):
+
+    """
+        Bi-directional mapping between code/text. 
+
+        Initialised using:
+
+            name:   Used for exceptions
+            dict:   Dict mapping from code (numeric) to text
+            error:  Error type to raise if key not found
+
+        The class provides:
+        
+            * A 'forward' map (code->text) which is accessed through 
+              __getitem__ (bimap[code]) 
+            * A 'reverse' map (code>value) which is accessed through 
+              __getattr__ (bimap.text)
+            * A 'get' method which does a forward lookup (code->text)
+              and returns a textual version of code if there is no
+              explicit mapping (or default provided)
+        
+        >>> class TestError(Exception):
+        ...     pass
+
+        >>> TEST = Bimap('TEST',{1:'A', 2:'B', 3:'C'},TestError)
+        >>> TEST[1]
+        'A'
+        >>> TEST.A
+        1
+        >>> TEST.X
+        Traceback (most recent call last):
+        ...
+        TestError: TEST: Invalid reverse lookup: [X]
+        >>> TEST[99]
+        Traceback (most recent call last):
+        ...
+        TestError: TEST: Invalid forward lookup: [99]
+        >>> TEST.get(99)
+        '99'
+    
+    """
+
+    def __init__(self,name,forward,error=KeyError):
+        self.name = name
+        self.error = error
+        self.forward = forward.copy()
+        self.reverse = dict([(v,k) for (k,v) in list(forward.items())])
+
+    def get(self,k,default=None):
+        try:
+            return self.forward[k]
+        except KeyError as e:
+            return default or str(k)
+
+    def __getitem__(self,k):
+        try:
+            return self.forward[k]
+        except KeyError as e:
+            raise self.error("%s: Invalid forward lookup: [%s]" % (self.name,k))
+
+    def __getattr__(self,k):
+        try:
+            return self.reverse[k]
+        except KeyError as e:
+            raise self.error("%s: Invalid reverse lookup: [%s]" % (self.name,k))
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod()
diff --git a/dnslib/bit.py b/dnslib/bit.py
new file mode 100644
index 0000000..8a9f5fe
--- /dev/null
+++ b/dnslib/bit.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+
+"""
+    Some basic bit mainpulation utilities
+"""
+from __future__ import print_function
+
+FILTER = bytearray([ (i < 32 or i > 127) and 46 or i for i in range(256) ])
+
+def hexdump(src, length=16, prefix=''):
+    """
+    Print hexdump of string
+
+    >>> print(hexdump(b"abcd" * 4))
+    0000  61 62 63 64 61 62 63 64  61 62 63 64 61 62 63 64  abcdabcd abcdabcd
+
+    >>> print(hexdump(bytearray(range(48))))
+    0000  00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f  ........ ........
+    0010  10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f  ........ ........
+    0020  20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f   !"#$%&' ()*+,-./
+
+    """
+    n = 0
+    left = length // 2 
+    right = length - left
+    result= []
+    src = bytearray(src)
+    while src:
+        s,src = src[:length],src[length:]
+        l,r = s[:left],s[left:]
+        hexa = "%-*s" % (left*3,' '.join(["%02x"%x for x in l]))
+        hexb = "%-*s" % (right*3,' '.join(["%02x"%x for x in r]))
+        lf = l.translate(FILTER)
+        rf = r.translate(FILTER)
+        result.append("%s%04x  %s %s %s %s" % (prefix, n, hexa, hexb, 
+                                               lf.decode(), rf.decode()))
+        n += length
+    return "\n".join(result)
+
+def get_bits(data,offset,bits=1):
+    """
+        Get specified bits from integer
+
+        >>> bin(get_bits(0b0011100,2))
+        '0b1'
+        >>> bin(get_bits(0b0011100,0,4))
+        '0b1100'
+        
+    """
+    mask = ((1 << bits) - 1) << offset
+    return (data & mask) >> offset 
+
+def set_bits(data,value,offset,bits=1):
+    """
+        Set specified bits in integer
+
+        >>> bin(set_bits(0,0b1010,0,4))
... 5126 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-dnslib.git



More information about the Python-modules-commits mailing list