[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1003629: Updated debdiff



Attached the wrong debdiff.  The only difference is the debian/changelog entry:

+python-dnslib (0.9.18-0deb11u1) bullseye; urgency=medium
+
+  * Remove d/patches/0001-Only-run-tests-for-python3.patch and set test
+    versions in d/rules instead
+  * New upstream security release (CVE-2022-22846)
+
+ -- Scott Kitterman <scott@kitterman.com>  Wed, 12 Jan 2022 15:41:12 -0500

Correct one attached.

Scott K
diff -Nru python-dnslib-0.9.16/debian/changelog python-dnslib-0.9.18/debian/changelog
--- python-dnslib-0.9.16/debian/changelog	2021-12-05 15:05:46.000000000 -0500
+++ python-dnslib-0.9.18/debian/changelog	2022-01-12 15:41:12.000000000 -0500
@@ -1,3 +1,11 @@
+python-dnslib (0.9.18-0deb11u1) bullseye; urgency=medium
+
+  * Remove d/patches/0001-Only-run-tests-for-python3.patch and set test
+    versions in d/rules instead
+  * New upstream security release (CVE-2022-22846)
+
+ -- Scott Kitterman <scott@kitterman.com>  Wed, 12 Jan 2022 15:41:12 -0500
+
 python-dnslib (0.9.16-1) unstable; urgency=medium
 
   [ Ondřej Nový ]
diff -Nru python-dnslib-0.9.16/debian/patches/0001-Only-run-tests-for-python3.patch python-dnslib-0.9.18/debian/patches/0001-Only-run-tests-for-python3.patch
--- python-dnslib-0.9.16/debian/patches/0001-Only-run-tests-for-python3.patch	2021-12-05 14:52:29.000000000 -0500
+++ python-dnslib-0.9.18/debian/patches/0001-Only-run-tests-for-python3.patch	1969-12-31 19:00:00.000000000 -0500
@@ -1,21 +0,0 @@
-From: Scott Kitterman <scott@kitterman.com>
-Date: Mon, 6 Jan 2020 02:40:47 -0500
-Subject: Only run tests for python3
-
----
- run_tests.sh | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/run_tests.sh b/run_tests.sh
-index 16bc398..3e22f06 100755
---- a/run_tests.sh
-+++ b/run_tests.sh
-@@ -2,7 +2,7 @@
- 
- export PYTHONPATH=$(pwd)
- 
--: ${VERSIONS:="python python3"}
-+: ${VERSIONS:="python3"}
- 
- for src in __init__.py bimap.py bit.py buffer.py label.py dns.py lex.py server.py digparser.py ranges.py test_decode.py
- do
diff -Nru python-dnslib-0.9.16/debian/patches/series python-dnslib-0.9.18/debian/patches/series
--- python-dnslib-0.9.16/debian/patches/series	2021-12-05 14:52:29.000000000 -0500
+++ python-dnslib-0.9.18/debian/patches/series	1969-12-31 19:00:00.000000000 -0500
@@ -1 +0,0 @@
-0001-Only-run-tests-for-python3.patch
diff -Nru python-dnslib-0.9.16/debian/rules python-dnslib-0.9.18/debian/rules
--- python-dnslib-0.9.16/debian/rules	2021-12-05 14:45:18.000000000 -0500
+++ python-dnslib-0.9.18/debian/rules	2022-01-12 15:37:44.000000000 -0500
@@ -6,4 +6,4 @@
 	dh $@ --with python3 --buildsystem=pybuild
 
 override_dh_auto_test:
-	./run_tests.sh
+	VERSIONS="python3" ./run_tests.sh
diff -Nru python-dnslib-0.9.16/dnslib/client.py python-dnslib-0.9.18/dnslib/client.py
--- python-dnslib-0.9.16/dnslib/client.py	2020-06-09 04:01:28.000000000 -0400
+++ python-dnslib-0.9.18/dnslib/client.py	2022-01-09 18:07:12.000000000 -0500
@@ -76,6 +76,9 @@
         a_pkt = q.send(address,port,tcp=args.tcp)
         a = DNSRecord.parse(a_pkt)
 
+        if q.header.id != a.header.id:
+            raise DNSError('Response transaction id does not match query transaction id')
+
         if a.header.tc and args.noretry == False:
             # Truncated - retry in TCP mode
             a_pkt = q.send(address,port,tcp=True)
diff -Nru python-dnslib-0.9.16/dnslib/__init__.py python-dnslib-0.9.18/dnslib/__init__.py
--- python-dnslib-0.9.16/dnslib/__init__.py	2021-05-07 12:08:33.000000000 -0400
+++ python-dnslib-0.9.18/dnslib/__init__.py	2022-01-09 18:17:03.000000000 -0500
@@ -274,6 +274,14 @@
     ;; OPT PSEUDOSECTION
     ; EDNS: version: 0, flags: do; udp: 4096
 
+Note that when using the library you should always validate the received TXID 
+
+    q = DNSRecord.question("abc.com")
+    a_pkt = q.send(address,port,tcp=args.tcp)
+    a = DNSRecord.parse(a_pkt)
+    if q.header.id != a.header.id:
+        raise DNSError('Response transaction id does not match query transaction id')
+
 The library also includes a simple framework for generating custom DNS
 resolvers in dnslib.server (see module docs). In most cases this just
 requires implementing a custom 'resolve' method which receives a question
@@ -359,6 +367,8 @@
                             Add support for all RR types to NSEC type bitmap
                          Merge pull request #17 from sunds/issue_16
                             Issue 16: uncaught exceptions leak open sockets
+ *   0.9.18  2022-01-09  Validate TXID in client.py (Issue #30 - thanks to @daniel4x)
+                       
 
 License:
 --------
@@ -381,7 +391,7 @@
 
 from dnslib.dns import *
 
-version = "0.9.16"
+version = "0.9.18"
 
 if __name__ == '__main__':
     import doctest,sys,textwrap
diff -Nru python-dnslib-0.9.16/dnslib/server.py python-dnslib-0.9.18/dnslib/server.py
--- python-dnslib-0.9.16/dnslib/server.py	2021-05-07 11:20:19.000000000 -0400
+++ python-dnslib-0.9.18/dnslib/server.py	2022-01-09 18:05:47.000000000 -0500
@@ -302,7 +302,7 @@
         print("\n",dnsobj.toZone("    "),"\n",sep="")
 
 
-class UDPServer(socketserver.UDPServer,socketserver.ThreadingMixIn,object):
+class UDPServer(socketserver.ThreadingMixIn,socketserver.UDPServer,object):
     def __init__(self, server_address, handler):
         self.allow_reuse_address = True
         self.daemon_threads = True
@@ -310,7 +310,7 @@
             self.address_family = socket.AF_INET6
         super(UDPServer,self).__init__(server_address, handler)
 
-class TCPServer(socketserver.TCPServer,socketserver.ThreadingMixIn,object):
+class TCPServer(socketserver.ThreadingMixIn,socketserver.TCPServer,object):
     def __init__(self, server_address, handler):
         self.allow_reuse_address = True
         self.daemon_threads = True
diff -Nru python-dnslib-0.9.16/dnslib.egg-info/PKG-INFO python-dnslib-0.9.18/dnslib.egg-info/PKG-INFO
--- python-dnslib-0.9.16/dnslib.egg-info/PKG-INFO	2021-05-07 12:16:39.000000000 -0400
+++ python-dnslib-0.9.18/dnslib.egg-info/PKG-INFO	2022-01-09 18:18:36.000000000 -0500
@@ -1,389 +1,402 @@
 Metadata-Version: 2.1
 Name: dnslib
-Version: 0.9.16
+Version: 0.9.18
 Summary: Simple library to encode/decode DNS wire-format packets
 Home-page: https://github.com/paulc/dnslib
 Author: PaulC
 License: BSD
-Description: 
-        
-        ## From Version 0.9.12 the master repository for _dnslib_ has been moved to GitHub (https://github.com/paulc/dnslib). Please update any links to the original BitBucket repository as this will no longer be maintained.
-        
-        
-        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.
-        
-        To send a DNSSEC request (EDNS OPT record with DO flag & header AD flag):
-        
-            >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.A))
-            >>> q.add_ar(EDNS0(flags="do",udp_len=4096))
-            >>> q.header.ad = 1
-            >>> print(q)
-            ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
-            ;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
-            ;; QUESTION SECTION:
-            ;abc.com.                       IN      A
-            ;; ADDITIONAL SECTION:
-            ;; OPT PSEUDOSECTION
-            ; EDNS: version: 0, flags: do; udp: 4096
-        
-        The library also includes a simple framework for generating custom DNS
-        resolvers in dnslib.server (see module docs). In most 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@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 Torbjorn Lonnemark (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@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
-         *   0.9.8   2019-02-25  Force DNSKEY key to be bytes object
-                                 Catch Bimap __wrapped__ attr (used by inspect module in 3.7)
-         *   0.9.9   2019-03-19  Add support for DNSSEC flag getters/setters (from <raul@dinosec.com> - thanks)
-                                 Added --dnssec flags to dnslib.client & dnslib.test_decode (sets EDNS0 DO flag)
-                                 Added EDNS0 support to dnslib.digparser
-         *   0.9.10  2019-03-24  Fixes to DNSSEC support
-                                 Add NSEC RR support
-                                 Add --dnssec flag to dnslib.client & dnslib.test_decode
-                                 Quote/unquote non-printable characters in DNS labels
-                                 Update test data
-                                 (Thanks to <raul@dinosec.com> for help)
-         *   0.9.11  2019-12-17  Encode NOTIFY Opcode (Issue #26)
-         *   0.9.12  2019-12-17  Transition master repository to Github (Bitbucket shutting down hg)
-         *   0.9.13  2020-06-01  Handle truncated requests in server.py (Issue #9)
-                                 Replace thred.isAlive with thread.is_alive (Deprecated in Py3.9)
-                                 Merged Pull Request #4 (Extra options for intercept.py) - thanks to @nolanl
-         *   0.9.14  2020-06-09  Merged Pull Request #10 (Return doctest status via exit code)
-                                 Thanks to @mgorny
-         *   0.9.15  2021-05-07  DNSServer fixes - support IPv6 (from Pull Request #21) - thanks to @mikma
-                                                 - deamon threads (Pull Request #19) - thanks to @wojons
-                                 Add unsupported RR types (Issue #27)
-         *   0.9.16  2021-05-07  Merge pull request #23 from Tugzrida/patch-1
-                                    Add support for all RR types to NSEC type bitmap
-                                 Merge pull request #17 from sunds/issue_16
-                                    Issue 16: uncaught exceptions leak open sockets
-        
-        License:
-        --------
-        
-        BSD
-        
-        Author:
-        -------
-        
-         *   PaulC
-        
-        Master Repository/Issues:
-        -------------------------
-        
-         *   https://github.com/paulc/dnslib
-        
-         (Note: https://bitbucket.org/paulc/dnslib has been deprecated and will not be updated)
-        
 Platform: UNKNOWN
 Classifier: Topic :: Internet :: Name Service (DNS)
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 3
 Description-Content-Type: text/markdown
+License-File: LICENSE
+
+
+
+## From Version 0.9.12 the master repository for _dnslib_ has been moved to GitHub (https://github.com/paulc/dnslib). Please update any links to the original BitBucket repository as this will no longer be maintained.
+
+
+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.
+
+To send a DNSSEC request (EDNS OPT record with DO flag & header AD flag):
+
+    >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.A))
+    >>> q.add_ar(EDNS0(flags="do",udp_len=4096))
+    >>> q.header.ad = 1
+    >>> print(q)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      A
+    ;; ADDITIONAL SECTION:
+    ;; OPT PSEUDOSECTION
+    ; EDNS: version: 0, flags: do; udp: 4096
+
+Note that when using the library you should always validate the received TXID 
+
+    q = DNSRecord.question("abc.com")
+    a_pkt = q.send(address,port,tcp=args.tcp)
+    a = DNSRecord.parse(a_pkt)
+    if q.header.id != a.header.id:
+        raise DNSError('Response transaction id does not match query transaction id')
+
+The library also includes a simple framework for generating custom DNS
+resolvers in dnslib.server (see module docs). In most 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@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 Torbjorn Lonnemark (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@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
+ *   0.9.8   2019-02-25  Force DNSKEY key to be bytes object
+                         Catch Bimap __wrapped__ attr (used by inspect module in 3.7)
+ *   0.9.9   2019-03-19  Add support for DNSSEC flag getters/setters (from <raul@dinosec.com> - thanks)
+                         Added --dnssec flags to dnslib.client & dnslib.test_decode (sets EDNS0 DO flag)
+                         Added EDNS0 support to dnslib.digparser
+ *   0.9.10  2019-03-24  Fixes to DNSSEC support
+                         Add NSEC RR support
+                         Add --dnssec flag to dnslib.client & dnslib.test_decode
+                         Quote/unquote non-printable characters in DNS labels
+                         Update test data
+                         (Thanks to <raul@dinosec.com> for help)
+ *   0.9.11  2019-12-17  Encode NOTIFY Opcode (Issue #26)
+ *   0.9.12  2019-12-17  Transition master repository to Github (Bitbucket shutting down hg)
+ *   0.9.13  2020-06-01  Handle truncated requests in server.py (Issue #9)
+                         Replace thred.isAlive with thread.is_alive (Deprecated in Py3.9)
+                         Merged Pull Request #4 (Extra options for intercept.py) - thanks to @nolanl
+ *   0.9.14  2020-06-09  Merged Pull Request #10 (Return doctest status via exit code)
+                         Thanks to @mgorny
+ *   0.9.15  2021-05-07  DNSServer fixes - support IPv6 (from Pull Request #21) - thanks to @mikma
+                                         - deamon threads (Pull Request #19) - thanks to @wojons
+                         Add unsupported RR types (Issue #27)
+ *   0.9.16  2021-05-07  Merge pull request #23 from Tugzrida/patch-1
+                            Add support for all RR types to NSEC type bitmap
+                         Merge pull request #17 from sunds/issue_16
+                            Issue 16: uncaught exceptions leak open sockets
+ *   0.9.18  2022-01-09  Validate TXID in client.py (Issue #30 - thanks to @daniel4x)
+                       
+
+License:
+--------
+
+BSD
+
+Author:
+-------
+
+ *   PaulC
+
+Master Repository/Issues:
+-------------------------
+
+ *   https://github.com/paulc/dnslib
+
+ (Note: https://bitbucket.org/paulc/dnslib has been deprecated and will not be updated)
+
+
diff -Nru python-dnslib-0.9.16/PKG-INFO python-dnslib-0.9.18/PKG-INFO
--- python-dnslib-0.9.16/PKG-INFO	2021-05-07 12:16:39.721066200 -0400
+++ python-dnslib-0.9.18/PKG-INFO	2022-01-09 18:18:36.210179600 -0500
@@ -1,389 +1,402 @@
 Metadata-Version: 2.1
 Name: dnslib
-Version: 0.9.16
+Version: 0.9.18
 Summary: Simple library to encode/decode DNS wire-format packets
 Home-page: https://github.com/paulc/dnslib
 Author: PaulC
 License: BSD
-Description: 
-        
-        ## From Version 0.9.12 the master repository for _dnslib_ has been moved to GitHub (https://github.com/paulc/dnslib). Please update any links to the original BitBucket repository as this will no longer be maintained.
-        
-        
-        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.
-        
-        To send a DNSSEC request (EDNS OPT record with DO flag & header AD flag):
-        
-            >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.A))
-            >>> q.add_ar(EDNS0(flags="do",udp_len=4096))
-            >>> q.header.ad = 1
-            >>> print(q)
-            ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
-            ;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
-            ;; QUESTION SECTION:
-            ;abc.com.                       IN      A
-            ;; ADDITIONAL SECTION:
-            ;; OPT PSEUDOSECTION
-            ; EDNS: version: 0, flags: do; udp: 4096
-        
-        The library also includes a simple framework for generating custom DNS
-        resolvers in dnslib.server (see module docs). In most 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@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 Torbjorn Lonnemark (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@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
-         *   0.9.8   2019-02-25  Force DNSKEY key to be bytes object
-                                 Catch Bimap __wrapped__ attr (used by inspect module in 3.7)
-         *   0.9.9   2019-03-19  Add support for DNSSEC flag getters/setters (from <raul@dinosec.com> - thanks)
-                                 Added --dnssec flags to dnslib.client & dnslib.test_decode (sets EDNS0 DO flag)
-                                 Added EDNS0 support to dnslib.digparser
-         *   0.9.10  2019-03-24  Fixes to DNSSEC support
-                                 Add NSEC RR support
-                                 Add --dnssec flag to dnslib.client & dnslib.test_decode
-                                 Quote/unquote non-printable characters in DNS labels
-                                 Update test data
-                                 (Thanks to <raul@dinosec.com> for help)
-         *   0.9.11  2019-12-17  Encode NOTIFY Opcode (Issue #26)
-         *   0.9.12  2019-12-17  Transition master repository to Github (Bitbucket shutting down hg)
-         *   0.9.13  2020-06-01  Handle truncated requests in server.py (Issue #9)
-                                 Replace thred.isAlive with thread.is_alive (Deprecated in Py3.9)
-                                 Merged Pull Request #4 (Extra options for intercept.py) - thanks to @nolanl
-         *   0.9.14  2020-06-09  Merged Pull Request #10 (Return doctest status via exit code)
-                                 Thanks to @mgorny
-         *   0.9.15  2021-05-07  DNSServer fixes - support IPv6 (from Pull Request #21) - thanks to @mikma
-                                                 - deamon threads (Pull Request #19) - thanks to @wojons
-                                 Add unsupported RR types (Issue #27)
-         *   0.9.16  2021-05-07  Merge pull request #23 from Tugzrida/patch-1
-                                    Add support for all RR types to NSEC type bitmap
-                                 Merge pull request #17 from sunds/issue_16
-                                    Issue 16: uncaught exceptions leak open sockets
-        
-        License:
-        --------
-        
-        BSD
-        
-        Author:
-        -------
-        
-         *   PaulC
-        
-        Master Repository/Issues:
-        -------------------------
-        
-         *   https://github.com/paulc/dnslib
-        
-         (Note: https://bitbucket.org/paulc/dnslib has been deprecated and will not be updated)
-        
 Platform: UNKNOWN
 Classifier: Topic :: Internet :: Name Service (DNS)
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 3
 Description-Content-Type: text/markdown
+License-File: LICENSE
+
+
+
+## From Version 0.9.12 the master repository for _dnslib_ has been moved to GitHub (https://github.com/paulc/dnslib). Please update any links to the original BitBucket repository as this will no longer be maintained.
+
+
+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.
+
+To send a DNSSEC request (EDNS OPT record with DO flag & header AD flag):
+
+    >>> q = DNSRecord(q=DNSQuestion("abc.com",QTYPE.A))
+    >>> q.add_ar(EDNS0(flags="do",udp_len=4096))
+    >>> q.header.ad = 1
+    >>> print(q)
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ...
+    ;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
+    ;; QUESTION SECTION:
+    ;abc.com.                       IN      A
+    ;; ADDITIONAL SECTION:
+    ;; OPT PSEUDOSECTION
+    ; EDNS: version: 0, flags: do; udp: 4096
+
+Note that when using the library you should always validate the received TXID 
+
+    q = DNSRecord.question("abc.com")
+    a_pkt = q.send(address,port,tcp=args.tcp)
+    a = DNSRecord.parse(a_pkt)
+    if q.header.id != a.header.id:
+        raise DNSError('Response transaction id does not match query transaction id')
+
+The library also includes a simple framework for generating custom DNS
+resolvers in dnslib.server (see module docs). In most 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@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 Torbjorn Lonnemark (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@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
+ *   0.9.8   2019-02-25  Force DNSKEY key to be bytes object
+                         Catch Bimap __wrapped__ attr (used by inspect module in 3.7)
+ *   0.9.9   2019-03-19  Add support for DNSSEC flag getters/setters (from <raul@dinosec.com> - thanks)
+                         Added --dnssec flags to dnslib.client & dnslib.test_decode (sets EDNS0 DO flag)
+                         Added EDNS0 support to dnslib.digparser
+ *   0.9.10  2019-03-24  Fixes to DNSSEC support
+                         Add NSEC RR support
+                         Add --dnssec flag to dnslib.client & dnslib.test_decode
+                         Quote/unquote non-printable characters in DNS labels
+                         Update test data
+                         (Thanks to <raul@dinosec.com> for help)
+ *   0.9.11  2019-12-17  Encode NOTIFY Opcode (Issue #26)
+ *   0.9.12  2019-12-17  Transition master repository to Github (Bitbucket shutting down hg)
+ *   0.9.13  2020-06-01  Handle truncated requests in server.py (Issue #9)
+                         Replace thred.isAlive with thread.is_alive (Deprecated in Py3.9)
+                         Merged Pull Request #4 (Extra options for intercept.py) - thanks to @nolanl
+ *   0.9.14  2020-06-09  Merged Pull Request #10 (Return doctest status via exit code)
+                         Thanks to @mgorny
+ *   0.9.15  2021-05-07  DNSServer fixes - support IPv6 (from Pull Request #21) - thanks to @mikma
+                                         - deamon threads (Pull Request #19) - thanks to @wojons
+                         Add unsupported RR types (Issue #27)
+ *   0.9.16  2021-05-07  Merge pull request #23 from Tugzrida/patch-1
+                            Add support for all RR types to NSEC type bitmap
+                         Merge pull request #17 from sunds/issue_16
+                            Issue 16: uncaught exceptions leak open sockets
+ *   0.9.18  2022-01-09  Validate TXID in client.py (Issue #30 - thanks to @daniel4x)
+                       
+
+License:
+--------
+
+BSD
+
+Author:
+-------
+
+ *   PaulC
+
+Master Repository/Issues:
+-------------------------
+
+ *   https://github.com/paulc/dnslib
+
+ (Note: https://bitbucket.org/paulc/dnslib has been deprecated and will not be updated)
+
+
diff -Nru python-dnslib-0.9.16/README python-dnslib-0.9.18/README
--- python-dnslib-0.9.16/README	2021-05-07 12:08:47.000000000 -0400
+++ python-dnslib-0.9.18/README	2022-01-09 18:17:21.000000000 -0500
@@ -272,6 +272,14 @@
     ;; OPT PSEUDOSECTION
     ; EDNS: version: 0, flags: do; udp: 4096
 
+Note that when using the library you should always validate the received TXID 
+
+    q = DNSRecord.question("abc.com")
+    a_pkt = q.send(address,port,tcp=args.tcp)
+    a = DNSRecord.parse(a_pkt)
+    if q.header.id != a.header.id:
+        raise DNSError('Response transaction id does not match query transaction id')
+
 The library also includes a simple framework for generating custom DNS
 resolvers in dnslib.server (see module docs). In most cases this just
 requires implementing a custom 'resolve' method which receives a question
@@ -357,6 +365,8 @@
                             Add support for all RR types to NSEC type bitmap
                          Merge pull request #17 from sunds/issue_16
                             Issue 16: uncaught exceptions leak open sockets
+ *   0.9.18  2022-01-09  Validate TXID in client.py (Issue #30 - thanks to @daniel4x)
+                       
 
 License:
 --------

Attachment: signature.asc
Description: This is a digitally signed message part.


Reply to: