[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