Git Product home page Git Product logo

dnspython's Introduction

dnspython

Build Status Documentation Status PyPI version License: ISC Coverage Code style: black

INTRODUCTION

dnspython is a DNS toolkit for Python. It supports almost all record types. It can be used for queries, zone transfers, and dynamic updates. It supports TSIG authenticated messages and EDNS0.

dnspython provides both high and low level access to DNS. The high level classes perform queries for data of a given name, type, and class, and return an answer set. The low level classes allow direct manipulation of DNS zones, messages, names, and records.

To see a few of the ways dnspython can be used, look in the examples/ directory.

dnspython is a utility to work with DNS, /etc/hosts is thus not used. For simple forward DNS lookups, it's better to use socket.getaddrinfo() or socket.gethostbyname().

dnspython originated at Nominum where it was developed to facilitate the testing of DNS software.

ABOUT THIS RELEASE

This is the development version of dnspython 2.7.0. Please read What's New for information about the changes in this release.

INSTALLATION

  • Many distributions have dnspython packaged for you, so you should check there first.

  • To use a wheel downloaded from PyPi, run:

    pip install dnspython

  • To install from the source code, go into the top-level of the source code and run:

    pip install --upgrade pip build
    python -m build
    pip install dist/*.whl
  • To install the latest from the master branch, run pip install git+https://github.com/rthalley/dnspython.git

Dnspython's default installation does not depend on any modules other than those in the Python standard library. To use some features, additional modules must be installed. For convenience, pip options are defined for the requirements.

If you want to use DNS-over-HTTPS, run pip install dnspython[doh].

If you want to use DNSSEC functionality, run pip install dnspython[dnssec].

If you want to use internationalized domain names (IDNA) functionality, you must run pip install dnspython[idna]

If you want to use the Trio asynchronous I/O package, run pip install dnspython[trio].

If you want to use WMI on Windows to determine the active DNS settings instead of the default registry scanning method, run pip install dnspython[wmi].

If you want to try the experimental DNS-over-QUIC code, run pip install dnspython[doq].

Note that you can install any combination of the above, e.g.: pip install dnspython[doh,dnssec,idna]

Notices

Python 2.x support ended with the release of 1.16.0. Dnspython 2.0.0 through 2.2.x support Python 3.6 and later. For dnspython 2.3.x, the minimum supported Python version is 3.7, and for 2.4.x the minimum supported verison is 3.8. We plan to align future support with the lifetime of the Python 3 versions.

Documentation has moved to dnspython.readthedocs.io.

dnspython's People

Contributors

avylove avatar bdrung avatar bictorv avatar bwelling avatar cdeccio avatar crhan avatar dependabot[bot] avatar dlenski avatar dns-leo avatar filips123 avatar hugovk avatar jschlyter avatar kalou avatar kimbo avatar m3047 avatar martinbasti avatar mathiasertl avatar nicki-krizek avatar nils-wisiol avatar nrhall avatar paulehoffman avatar peterthomassen avatar pspacek avatar rthalley avatar rwe avatar sebix avatar tacaswell avatar teward avatar tjroger avatar tmerila avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dnspython's Issues

Zones with certain record types are not parsed correctly

BIND9 test suite contains a script for generating zone files. Zones from this script are valid (BIND is able to load and serve them correctly), but zone parser in python-dns blows up on some zones.

Steps to Reproduce:

  1. Generate a zone with attached script (script came from BIND 9 test suite):
    $ genzone.sh 2 3 4 > master2.db
  1. Try to load the zone with following Python snippet:
    import dns.zone
    dns.zone.from_file('master2.db', origin='master2.')

Actual results:

    Traceback (most recent call last):
      File "test.py", line 2, in <module>
        dns.zone.from_file('master2.db', origin='master2.')
      File "/usr/lib/python2.7/site-packages/dns/zone.py", line 814, in from_file
        filename, allow_include, check_origin)
      File "/usr/lib/python2.7/site-packages/dns/zone.py", line 761, in from_text
        reader.read()
      File "/usr/lib/python2.7/site-packages/dns/zone.py", line 715, in read
        raise dns.exception.SyntaxError("%s:%d: %s" % (filename, line_number, detail))
    dns.exception.SyntaxError: master2.db:41: generic rdata does not start with \#

Additional info:
line 41 from generated zone:

    mb02                    MG      .

Also, I hit exactly same problem with KEY records. Attached zone was generated by BIND scripts in bind-9.9.2-P1/bin/tests/system/tsiggss/ns1.

dnssec.py tests fail with Python 3

Some tests from dnssec.py fail with Python 3. All tests from other files pass with Python 3.

$ cd tests
$ PYTHONPATH=".." python3.2 dnssec.py
..EE...EE
======================================================================
ERROR: testAbsoluteRSABad (__main__.DNSSECValidatorTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "dnssec.py", line 102, in testAbsoluteRSABad
    self.assertRaises(dns.dnssec.ValidationFailure, bad)
  File "/usr/lib64/python3.2/unittest/case.py", line 557, in assertRaises
    callableObj(*args, **kwargs)
  File "dnssec.py", line 101, in bad
    when)
  File "/tmp/dnspython3-1.10.0/dns/dnssec.py", line 356, in _validate
    _validate_rrsig(rrset, rrsig, keys, origin, now)
  File "/tmp/dnspython3-1.10.0/dns/dnssec.py", line 303, in _validate_rrsig
    digest = bytes(0) + bytes(1) + bytes(0xFF) * padlen + bytes(0) + \
TypeError: 'int' object is not callable

======================================================================
ERROR: testAbsoluteRSAGood (__main__.DNSSECValidatorTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "dnssec.py", line 96, in testAbsoluteRSAGood
    dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when)
  File "/tmp/dnspython3-1.10.0/dns/dnssec.py", line 356, in _validate
    _validate_rrsig(rrset, rrsig, keys, origin, now)
  File "/tmp/dnspython3-1.10.0/dns/dnssec.py", line 303, in _validate_rrsig
    digest = bytes(0) + bytes(1) + bytes(0xFF) * padlen + bytes(0) + \
TypeError: 'int' object is not callable

======================================================================
ERROR: testRelativeRSABad (__main__.DNSSECValidatorTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "dnssec.py", line 112, in testRelativeRSABad
    self.assertRaises(dns.dnssec.ValidationFailure, bad)
  File "/usr/lib64/python3.2/unittest/case.py", line 557, in assertRaises
    callableObj(*args, **kwargs)
  File "dnssec.py", line 111, in bad
    abs_dnspython_org, when)
  File "/tmp/dnspython3-1.10.0/dns/dnssec.py", line 356, in _validate
    _validate_rrsig(rrset, rrsig, keys, origin, now)
  File "/tmp/dnspython3-1.10.0/dns/dnssec.py", line 303, in _validate_rrsig
    digest = bytes(0) + bytes(1) + bytes(0xFF) * padlen + bytes(0) + \
TypeError: 'int' object is not callable

======================================================================
ERROR: testRelativeRSAGood (__main__.DNSSECValidatorTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "dnssec.py", line 106, in testRelativeRSAGood
    abs_dnspython_org, when)
  File "/tmp/dnspython3-1.10.0/dns/dnssec.py", line 356, in _validate
    _validate_rrsig(rrset, rrsig, keys, origin, now)
  File "/tmp/dnspython3-1.10.0/dns/dnssec.py", line 303, in _validate_rrsig
    digest = bytes(0) + bytes(1) + bytes(0xFF) * padlen + bytes(0) + \
TypeError: 'int' object is not callable

----------------------------------------------------------------------
Ran 9 tests in 0.014s

FAILED (errors=4)

BadSignature during XFR

Multimessage AXFR via dns.query.xfr using TSIG with algorithm DIFFERENT from hmac-md5 always gives BadSignature.

dnspython3-1.11.0:

File "/usr/local/lib/python3.3/dist-packages/dns/query.py", line 438, in xfr
one_rr_per_rrset=(rdtype==dns.rdatatype.IXFR))
File "/usr/local/lib/python3.3/dist-packages/dns/message.py", line 787, in from_wire
reader.read()
File "/usr/local/lib/python3.3/dist-packages/dns/message.py", line 728, in read
self._get_section(self.message.additional, adcount)
File "/usr/local/lib/python3.3/dist-packages/dns/message.py", line 680, in _get_section
self.message.first)
File "/usr/local/lib/python3.3/dist-packages/dns/tsig.py", line 178, in validate
raise BadSignature

Empty APL parsing

Hi,
it seems that dnspython can't process an empty APL record. Although this isn't a big problem, in fact, this case is useful for testing because APL is the only record I know which allows empty rdata (RFC 3123 sec. 5: "The data consists of zero or more strings...").

dnspython3-1.11.1

EOFError in dns.query._net_read

Hmm, maybe catch this exception and raise something more meaningful?

Traceback (most recent call last):
[...]
update_ns(fqdn, 'A', '0.0.0.0', action='add')
File "/srv/nsupdate.info/repo/nsupdate/main/dnstools.py", line 304, in update_ns
response = dns.query.tcp(upd, nameserver, timeout=UPDATE_TIMEOUT)
File "/srv/nsupdate.info/env/local/lib/python2.7/site-packages/dns/query.py", line 317, in tcp
ldata = _net_read(s, 2, expiration)
File "/srv/nsupdate.info/env/local/lib/python2.7/site-packages/dns/query.py", line 246, in _net_read
raise EOFError
EOFError

Extend DNSExceptions with human-readable messages

Hello!

I wonder if you are open to accepting patches which would add human-readable messages to DNSException messsages.

The motivation is that currently dnspython users have to implement own logic which catches exceptions e.g. from resolver.query and translates them to meanigful messages for users. I had to do that myself several time.

I propose to add generic but explanatory text messages like 'YXDOMAIN from 192.0.2.1 when querying for x.y.z.example.' to DNSExceptions so dnspython users could simply do str(e) and be done with it.

Are you okay with the idea?

Different Unicode behaviour in Python 2 and 3

In Python 2.7 dns.rrset.from_text does not allow a Unicode string as rdata:

In [13]: dns.rrset.from_text("test.com", 123,
                    dns.rdataclass.IN, dns.rdatatype.PTR,
                    u"fóó.bar").to_text()
[...]
AttributeError: 'unicode' object has no attribute 'get'

while it does accept an IDNA encoded string:

In [12]: dns.rrset.from_text("test.com", 123,
                    dns.rdataclass.IN, dns.rdatatype.PTR,
                    u"fóó.bar".encode("idna")).to_text()
Out[12]: 'test.com 123 IN PTR xn--f-vgaa.bar'

In the Python3 version this behaviour is exactly reversed: An Unicode string is accepted, while a pre-IDNA'd string is not, making it difficult to support both Py2 and 3 in client code.

In [20]: dns.rrset.from_text("test.com", 123,
   ....:                     dns.rdataclass.IN, dns.rdatatype.PTR,
   ....:                     u"fóó.bar").to_text()
Out[20]: 'test.com 123 IN PTR xn--f-vgaa.bar'
In [21]: dns.rrset.from_text("test.com", 123,
   ....:                     dns.rdataclass.IN, dns.rdatatype.PTR,
   ....:                     u"fóó.bar".encode("idna")).to_text()
[...]
AttributeError: 'bytes' object has no attribute 'get'

I suspect this is not intended behaviour...

zone.to_text (and maybe others) want to be stringified in Python 3

!/usr/bin/python3

import dns.query, dns.zone
ThisXFERedZone = dns.zone.from_xfr(dns.query.xfr("192.228.79.201", "."))
ThisPrintableZone = ThisXFERedZone.to_text()

yields:

Traceback (most recent call last):
File "./FindRootserverAddresses.py", line 4, in
ThisPrintableZone = ThisXFERedZone.to_text()
File "/usr/local/lib/python3.4/site-packages/dns/zone.py", line 511, in to_text
self.to_file(temp_buffer, sorted, relativize, nl)
File "/usr/local/lib/python3.4/site-packages/dns/zone.py", line 487, in to_file
print(l, file=f)
TypeError: 'str' does not support the buffer interface

raise KeyError in dns/message.py

Let's try this in python3

>>> import dns
>>> import dns.name
>>> parent = 'afnic.fr'
>>> child = 'www.afnic.fr'
>>> p = dns.name.from_text(parent)
>>> c = dns.name.from_text(child)
>>> c.is_subdomain(p)
True
>>> c.relativize(p)
<DNS name www>
>>> answers = dns.resolver.query(parent, 'NS')
(-- no problem here --)
>>> answers = dns.resolver.query(child, 'NS')
Traceback (most recent call last):
  File "dns/resolver.py", line 126, in __init__
    rdclass, rdtype)
  File "dns/message.py", line 340, in find_rrset
    raise KeyError
KeyError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "dns/resolver.py", line 136, in __init__
    dns.rdatatype.CNAME)
  File "dns/message.py", line 340, in find_rrset
    raise KeyError
KeyError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "dns/resolver.py", line 979, in query
    raise_on_no_answer, source_port)
  File "dns/resolver.py", line 910, in query
    raise_on_no_answer)
  File "dns/resolver.py", line 145, in __init__
    raise NoAnswer

Multi-message IXFR timeout problem

Hi,
If I try to list multi-message IXFR response (dns.query.xfr output), I always get timeout exception no matter which dns server I query. One message responses are processed without problems.

    for msg in response:
  File "/usr/local/lib/python3.3/dist-packages/dns/query.py", line 432, in xfr
    ldata = _net_read(s, 2, mexpiration)
  File "/usr/local/lib/python3.3/dist-packages/dns/query.py", line 243, in _net_read
    _wait_for_readable(sock, expiration)
  File "/usr/local/lib/python3.3/dist-packages/dns/query.py", line 140, in _wait_for_readable
    _wait_for(s, True, False, True, expiration)
  File "/usr/local/lib/python3.3/dist-packages/dns/query.py", line 117, in _wait_for
    raise dns.exception.Timeout

dnspython3 (1.11.1)

Dan

CERT Resolver Support?

I was looking for a python DNS library that handled CERT records. Although this is defined as dns.rdtypes.ANY.CERT, it the following code does not work:

import dns.resolve
for rdata in dns.resolver.query('alan.direct.transparenthealth.org', 'CERT')
   print rdata.target

I get:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/dns/resolver.py", line 770, in query
   raise_on_no_answer)
File "/usr/lib/python2.7/dist-packages/dns/resolver.py", line 709, in query
    raise_on_no_answer)
File "/usr/lib/python2.7/dist-packages/dns/resolver.py", line 129, in __init__
    raise NoAnswer
dns.resolver.NoAnswer

If I do it using the command line utility, I do indeed get the certificate back.

>dig alan.direct.transparenthealth.org CERT

dig alan.direct.transparenthealth.org CERT +noall +answer
;; Truncated, retrying in TCP mode.

; <<>> DiG 9.8.1-P1 <<>> alan.direct.transparenthealth.org CERT +noall +answer
;; global options: +cmd
alan.direct.transparenthealth.org. 83828 IN CERT PKIX 38725 RSASHA1
MIIDtzCCAyCgAwIBAgIIexSV8b464C8wDQYJKoZIhvcNAQEFBQAwgaEx
MDAuBgkqhkiG9w0BCQEWIXJvb3RAZGlyZWN0LnRyYW5zcGFyZW50aGVh
.
.
.

Is this functionality possible with this library? Am I doing it wrong? I couldn’t find any examples of doing this in Python

LOC records are parsed incorrectly

Hello!

I have found that LOC records have incorrect default values for size, horizontal and vertical precision. Also the explicit value for vertical precision is not parsed correctly if there is no 'm' (unit) at the end of input.

I have patches for both problems so I will create pull request. The third patch adds unit tests for LOC records so you can try it yourself that it really doesn't work with current master :-)

Have a nice day!

how to get the query time

q = dns.query.udp(msg, server, timeout=2)
help( q )

i think i can not found anything about query time?

DNS TXT records without quotes are read incorrectly

This may be incorrect to begin with, but it's in our zone files and bind appears to handle it.

When you enter a TXT record with as content a b c, bind will return it to the end client as "a b c" while dnspython returns it as `"a" "b" "c"``. Or in code:

zone_content = '''$ORIGIN example.com.
@ IN SOA ns.example.com. username.example.com. ( 2007120710 1d 2h 4w 1h )
@ NS ns1.example.com.
@ TXT b c d'''
zone = dns.zone.from_text(zone_content)
zone.get_rdataset('@', 'TXT').to_text()

Returns a string `0 IN TXT "b" "c" "d"``.

This is with dnspython 1.11.1.

CNAME when asking for A leads to syntax error

I discovered that a SyntaxError exception is being raised when asking a authoritative nameserver for an A record when there is only an CNAME record available for this very subdomain.

Working example:
See dig ghs.google.com SOA @ns1.google.com for simple copy'n'paste verification

import dns.resolver
query = dns.message.make_query("ghs.google.com", dns.rdatatype.A)
answers = dns.query.udp(query,"ns1.google.com", timeout=2).answer

I guess a meaningful dnspython exception would be more fitting. Maybe the resulting CNAME information could be included within the exception as well, so programmers wouldn't need to perform two new lookups again to get the CNAME record of the subdomain again. A proper workflow could be like this:

try: 
    query = dns.message.make_query("ghs.google.com", dns.rdatatype.A)
    answers = dns.query.udp(query,"ns1.google.com", timeout=2).answer

except SomeCnameException as e: # we already received the CNAME data, right?
    query = dns.message.make_query(e.returned_rdatatype.cname_value, dns.rdatatype.A)
    answers = dns.query.udp(query,"ns1.google.com", timeout=2).answer

Is dnspython support malformed packet?

I have next request identical to dig @8.8.8.8 -t ANY google.com:

import dns.flags
import dns.name
import dns.message
import dns.rdatatype
import dns.query

TIMEOUT = 2
ADDITIONAL_RDCLASS = 4096

domain = 'google.com.'
name_server = '8.8.8.8'
record_type = dns.rdatatype.ANY

request = dns.message.make_query(domain, record_type)
request.flags |= dns.flags.AD
request.find_rrset(request.additional, dns.name.root, ADDITIONAL_RDCLASS,
                          dns.rdatatype.OPT, create=True, force_unique=True)

response = dns.query.udp(request, name_server, timeout=TIMEOUT)

For me this request return malformed packet and throw socket.error:

File "/home/tbicr/Projects/cspw-ui.env/local/lib/python2.7/site-packages/dns/query.py", line 218, in udp
    (wire, from_address) = s.recvfrom(65535)
None: [Errno 11] Resource temporarily unavailable

Dig handle this behaviour and send packet again, that take about 5 seconds, but take result with two requests:

first request:

0000  c8 be 19 aa 83 58 50 46  5d a5 70 99 08 00 45 00   .....XPF ].p...E.
0010  00 43 ff 18 00 00 40 11  a9 fc c0 a8 00 dd 08 08   .C....@. ........
0020  08 08 a8 4b 00 35 00 2f  eb c8 5b c9 01 20 00 01   ...K.5./ ..[.. ..
0030  00 00 00 00 00 01 06 67  6f 6f 67 6c 65 03 63 6f   .......g oogle.co
0040  6d 00 00 ff 00 01 00 00  29 10 00 00 00 00 00 00   m....... ).......
0050  00                                                 .                

first response:

0000  50 46 5d a5 70 99 c8 be  19 aa 83 58 08 00 45 00   PF].p... ...X..E.
0010  02 8b d1 d8 00 00 30 11  e4 f4 08 08 08 08 c0 a8   ......0. ........
0020  00 dd 00 35 a8 4b 02 77  9d 64 5b c9 81 80 00 01   ...5.K.w .d[.....
0030  00 19 00 00 00 01 06 67  6f 6f 67 6c 65 03 63 6f   .......g oogle.co
0040  6d 00 00 ff 00 01 c0 0c  00 01 00 01 00 00 00 83   m....... ........
0050  00 04 ad c2 70 41 c0 0c  00 01 00 01 00 00 00 83   ....pA.. ........
0060  00 04 ad c2 70 44 c0 0c  00 01 00 01 00 00 00 83   ....pD.. ........
0070  00 04 ad c2 70 4e c0 0c  00 01 00 01 00 00 00 83   ....pN.. ........
0080  00 04 ad c2 70 48 c0 0c  00 01 00 01 00 00 00 83   ....pH.. ........
0090  00 04 ad c2 70 43 c0 0c  00 01 00 01 00 00 00 83   ....pC.. ........
00a0  00 04 ad c2 70 40 c0 0c  00 01 00 01 00 00 00 83   ....p@.. ........
00b0  00 04 ad c2 70 46 c0 0c  00 01 00 01 00 00 00 83   ....pF.. ........
00c0  00 c0 a8 00 01 47 c0 0c  00 01 00 01 00 00 00 83   .....G.. ........
00d0  00 04 ad c2 70 45 c0 0c  00 01 00 01 00 00 00 83   ....pE.. ........
00e0  00 04 ad c2 70 49 c0 0c  00 01 00 01 00 00 00 83   ....pI.. ........
00f0  00 04 ad c2 70 42 c0 0c  00 1c 00 01 00 00 00 83   ....pB.. ........
0100  00 10 2a 00 14 50 40 01  08 02 00 00 00 00 00 00   ..*..P@. ........
0110  10 08 c0 0c 00 0f 00 01  00 00 01 af 00 11 00 1e   ........ ........
0120  04 61 6c 74 32 05 61 73  70 6d 78 01 6c c0 0c c0   .alt2.as pmx.l...
0130  0c 00 0f 00 01 00 00 01  af 00 04 00 0a c0 fb c0   ........ ........
0140  0c 01 01 00 01 00 00 53  b7 00 13 00 05 69 73 73   .......S .....iss
0150  75 65 73 79 6d 61 6e 74  65 63 2e 63 6f 6d c0 0c   uesymant ec.com..
0160  00 0f 00 01 00 00 01 af  00 09 00 14 04 61 6c 74   ........ .....alt
0170  31 c0 fb c0 0c 00 06 00  01 00 00 53 b7 00 26 03   1....... ...S..&.
0180  6e 73 31 c0 0c 09 64 6e  73 2d 61 64 6d 69 6e c0   ns1...dn s-admin.
0190  0c 77 fd 35 14 00 00 1c  20 00 00 07 08 00 12 75   .w.5....  ......u
01a0  00 00 00 01 2c c0 0c 00  02 00 01 00 00 53 b7 00   ....,... .....S..
01b0  06 03 6e 73 32 c0 0c c0  0c 00 0f 00 01 00 00 01   ..ns2... ........
01c0  af 00 09 00 32 04 61 6c  74 34 c0 fb c0 0c 00 10   ....2.al t4......
01d0  00 01 00 00 0d 67 00 4c  4b 76 3d 73 70 66 31 20   .....g.L Kv=spf1 
01e0  69 6e 63 6c 75 64 65 3a  5f 73 70 66 2e 67 6f 6f   include: _spf.goo
01f0  67 6c 65 2e 63 6f 6d 20  69 70 34 3a 32 31 36 2e   gle.com  ip4:216.
0200  37 33 2e 39 33 2e 37 30  2f 33 31 20 69 70 34 3a   73.93.70 /31 ip4:
0210  32 31 36 2e 37 33 2e 39  33 2e 37 32 2f 33 31 20   216.73.9 3.72/31 
0220  7e 61 6c 6c c0 0c 00 02  00 01 00 00 53 b7 00 06   ~all.... ....S...
0230  03 6e 73 33 c0 0c c0 0c  00 0f 00 01 00 00 01 af   .ns3.... ........
0240  00 09 00 28 04 61 6c 74  33 c0 fb c0 0c 00 02 00   ...(.alt 3.......
0250  01 00 00 53 b7 00 02 c1  55 c0 0c 01 01 00 01 00   ...S.... U.......
0260  00 53 b7 00 17 00 09 69  73 73 75 65 77 69 6c 64   .S.....i ssuewild
0270  73 79 6d 61 6e 74 65 63  2e 63 6f 6d c0 0c 00 02   symantec .com....
0280  00 01 00 00 53 b7 00 06  03 6e 73 34 c0 0c 00 00   ....S... .ns4....
0290  29 02 00 00 00 00 00 00  00                        )....... .       

second request:

0000  c8 be 19 aa 83 58 50 46  5d a5 70 99 08 00 45 00   .....XPF ].p...E.
0010  00 43 ff 19 00 00 40 11  a9 fb c0 a8 00 dd 08 08   .C....@. ........
0020  08 08 a8 4b 00 35 00 2f  eb c8 5b c9 01 20 00 01   ...K.5./ ..[.. ..
0030  00 00 00 00 00 01 06 67  6f 6f 67 6c 65 03 63 6f   .......g oogle.co
0040  6d 00 00 ff 00 01 00 00  29 10 00 00 00 00 00 00   m....... ).......
0050  00                                                 .                

second response:

0000  50 46 5d a5 70 99 c8 be  19 aa 83 58 08 00 45 00   PF].p... ...X..E.
0010  02 8b e7 39 00 00 31 11  ce 93 08 08 08 08 c0 a8   ...9..1. ........
0020  00 dd 00 35 a8 4b 02 77  c0 be 5b c9 81 80 00 01   ...5.K.w ..[.....
0030  00 19 00 00 00 01 06 67  6f 6f 67 6c 65 03 63 6f   .......g oogle.co
0040  6d 00 00 ff 00 01 c0 0c  00 01 00 01 00 00 00 7e   m....... .......~
0050  00 04 ad c2 70 41 c0 0c  00 01 00 01 00 00 00 7e   ....pA.. .......~
0060  00 04 ad c2 70 44 c0 0c  00 01 00 01 00 00 00 7e   ....pD.. .......~
0070  00 04 ad c2 70 4e c0 0c  00 01 00 01 00 00 00 7e   ....pN.. .......~
0080  00 04 ad c2 70 48 c0 0c  00 01 00 01 00 00 00 7e   ....pH.. .......~
0090  00 04 ad c2 70 43 c0 0c  00 01 00 01 00 00 00 7e   ....pC.. .......~
00a0  00 04 ad c2 70 40 c0 0c  00 01 00 01 00 00 00 7e   ....p@.. .......~
00b0  00 04 ad c2 70 46 c0 0c  00 01 00 01 00 00 00 7e   ....pF.. .......~
00c0  00 04 ad c2 70 47 c0 0c  00 01 00 01 00 00 00 7e   ....pG.. .......~
00d0  00 04 ad c2 70 45 c0 0c  00 01 00 01 00 00 00 7e   ....pE.. .......~
00e0  00 04 ad c2 70 49 c0 0c  00 01 00 01 00 00 00 7e   ....pI.. .......~
00f0  00 04 ad c2 70 42 c0 0c  00 1c 00 01 00 00 00 7e   ....pB.. .......~
0100  00 10 2a 00 14 50 40 01  08 02 00 00 00 00 00 00   ..*..P@. ........
0110  10 08 c0 0c 00 0f 00 01  00 00 01 aa 00 11 00 1e   ........ ........
0120  04 61 6c 74 32 05 61 73  70 6d 78 01 6c c0 0c c0   .alt2.as pmx.l...
0130  0c 00 0f 00 01 00 00 01  aa 00 04 00 0a c0 fb c0   ........ ........
0140  0c 01 01 00 01 00 00 53  b2 00 13 00 05 69 73 73   .......S .....iss
0150  75 65 73 79 6d 61 6e 74  65 63 2e 63 6f 6d c0 0c   uesymant ec.com..
0160  00 0f 00 01 00 00 01 aa  00 09 00 14 04 61 6c 74   ........ .....alt
0170  31 c0 fb c0 0c 00 06 00  01 00 00 53 b2 00 26 03   1....... ...S..&.
0180  6e 73 31 c0 0c 09 64 6e  73 2d 61 64 6d 69 6e c0   ns1...dn s-admin.
0190  0c 77 fd 35 14 00 00 1c  20 00 00 07 08 00 12 75   .w.5....  ......u
01a0  00 00 00 01 2c c0 0c 00  02 00 01 00 00 53 b2 00   ....,... .....S..
01b0  06 03 6e 73 32 c0 0c c0  0c 00 0f 00 01 00 00 01   ..ns2... ........
01c0  aa 00 09 00 32 04 61 6c  74 34 c0 fb c0 0c 00 10   ....2.al t4......
01d0  00 01 00 00 0d 62 00 4c  4b 76 3d 73 70 66 31 20   .....b.L Kv=spf1 
01e0  69 6e 63 6c 75 64 65 3a  5f 73 70 66 2e 67 6f 6f   include: _spf.goo
01f0  67 6c 65 2e 63 6f 6d 20  69 70 34 3a 32 31 36 2e   gle.com  ip4:216.
0200  37 33 2e 39 33 2e 37 30  2f 33 31 20 69 70 34 3a   73.93.70 /31 ip4:
0210  32 31 36 2e 37 33 2e 39  33 2e 37 32 2f 33 31 20   216.73.9 3.72/31 
0220  7e 61 6c 6c c0 0c 00 02  00 01 00 00 53 b2 00 06   ~all.... ....S...
0230  03 6e 73 33 c0 0c c0 0c  00 0f 00 01 00 00 01 aa   .ns3.... ........
0240  00 09 00 28 04 61 6c 74  33 c0 fb c0 0c 00 02 00   ...(.alt 3.......
0250  01 00 00 53 b2 00 02 c1  55 c0 0c 01 01 00 01 00   ...S.... U.......
0260  00 53 b2 00 17 00 09 69  73 73 75 65 77 69 6c 64   .S.....i ssuewild
0270  73 79 6d 61 6e 74 65 63  2e 63 6f 6d c0 0c 00 02   symantec .com....
0280  00 01 00 00 53 b2 00 06  03 6e 73 34 c0 0c 00 00   ....S... .ns4....
0290  29 02 00 00 00 00 00 00  00                        )....... .       

So is dnspython support malformed packet processing like dig?

Response with status YXDOMAIN is not handled correctly

Imagine DNS zone with following record:
toolong.example.com. 324 IN DNAME xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

Following Python snippet throws NoNameservers exception. I would expect something like YXDOMAIN exception or something similar.

import dns.resolver
resolver = dns.resolver.Resolver(configure=False)
resolver.nameservers = ["127.0.0.1"]
resolver.edns = 0
resolver.payload = 4096
resolver.query('hell.toolong.example.com','txt')
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python2.7/site-packages/dns/resolver.py", line 772, in query
raise NoNameservers

Relevant output from dig:

dig @127.0.0.1 -t TXT hell.toolong.example.com

; <<>> DiG 9.9.2-P1-RedHat-9.9.2-3.P1.fc17 <<>> @127.0.0.1 -t TXT hell.toolong.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: YXDOMAIN, id: 43662
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hell.toolong.example.com. IN TXT

;; ANSWER SECTION:
toolong.example.com. 324 IN DNAME xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Feb 21 14:14:12 2013
;; MSG SIZE rcvd: 316

Host dnspython on PyPi

Currently dnspython is hosted off of PyPi, this presents security and performance challenges. If you could upload the releases to PyPi and then follow the instructions at pypi-externals.caremad.io/help/what/ it'd be great!

TXT records have no "string" attribute on win32

On windows the 'string` attribute does not exists.
I created a workaround for that:

            for txt in dns.resolver.query(domain, 'TXT'):
                if hasattr(txt, 'strings'):
                    strings = txt.strings
                else:
                    strings = [txt.data[1:]]

Exception when no TXT record exists

When querying the TXT record of a domain that has no the following exception occours:

Traceback (most recent call last):
  File ".\client\patch.py", line 838, in _update
  File ".\lib.bin\dns\resolver.py", line 974, in query
  File ".\lib.bin\dns\resolver.py", line 905, in query
  File ".\lib.bin\dns\resolver.py", line 137, in __init__
AttributeError: 'GenericRdata' object has no attribute 'target'

On Linux (Ubuntu) I don't see such an error, I don't know if it exists on Mac but it defInitely exists on Windows. Testet with the current stable and master.

'Lookup timed out'

I'm using Django, Celery, Eventlet and dnspython to asynchronous parse about 500 rss feeds.

Using dnspython causes 'lookup timed out' error when I try to parse more than 20 feeds at the same time. When I uninstall dnspython all works great, but I lose some time because dns lookups are blocking celery pool. Do you have any ideas how can it be fixed?

this is my celery task code:

import eventlet
feedparser = eventlet.import_patched('feedparser')
from celery import group

@task(ignore_result=True)
def update_feeds():
    group(update_feed.s(feed) for feed in Feed.objects.filter(active=True)).apply_async()

@task(ignore_result=True)
def update_feed(feed):
    parsed_feed = feedparser.parse(feed.feed_url, etag=feed.etag, modified=feed.modified)
    # It fails when I have dnspython installed returning <urlopen error (-3, 'Lookup timed out')> error

I'm using Ubuntu 12.04 LTS

Invalid wireformat of APL

Hi,
I have discovered that some special APL records (having prefix with trailing zeroes) are in a bad wireformat. RFC 3123 says: "sender MUST NOT include trailing zero octets in the AFDPART regardless of the value of PREFIX".

dnspython3-1.11.0

cls = dns.rdataclass.IN
tpe = dns.rdatatype.from_text("APL")

in4 = "!1:127.0.0.0/1"
rd4 = dns.rdata.from_text(cls, tpe, in4)
out4 = rd4.to_digestable(dns.name.from_text("test"))
print(binascii.hexlify(out4).decode('ascii'))

in6 = "!2:::1000/1"
rd6 = dns.rdata.from_text(cls, tpe, in6)
out6 = rd6.to_digestable(dns.name.from_text("test"))
print(binascii.hexlify(out6).decode('ascii'))
000101847f000000
should be:
000101817f

0002019000000000000000000000000000001000
should be:
0002018f000000000000000000000000000010

Regards,
Dan

Python 3 Errors

Even though it is marketed as such, it is not working properly on Python 3. I get:

AttributeError: 'dict' object has no attribute 'iteritems'

I will address Python 2/3 compatibility in my fork. I will aim for Python 2.7 an Python 3.3.

dns/node.py TypeError in to_text

zone.example file:
@ IN SOA dns.example.com. admin.example.com. (
2010042671 ; serial
3600 ; refresh
1200 ; retry
86400 ; expire
360 ; minimum
)
@ NS dns
test A 127.0.0.1

test.py

#!/usr/bin/python

import dns.zone, dns.name, dns.rdtypes

z = dns.zone.from_file('zone.example','example.com')
name = dns.name.from_text('test.example.com')
a = dns.rdtypes.IN.A.A(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.2')
z.replace_rdataset(name, a)
z.to_file('zone.output')

output:

Traceback (most recent call last):
File "./test.py", line 9, in
z.to_file('zone.output')
File "/usr/lib64/python2.7/site-packages/dns/zone.py", line 496, in to_file
relativize=relativize)
File "/usr/lib64/python2.7/site-packages/dns/node.py", line 52, in to_text
print >> s, rds.to_text(name, **kw)
TypeError: to_text() got multiple values for keyword argument 'origin'

Fails to resolve MX records inside a VirtualBox VM

Steps to reproduce:

  1. virtualenv env
  2. env/bin/pip install dnspython==1.11.1
  3. env/bin/python -c 'import dns.resolver; print dns.resolver.query("pov.lt", "MX")'

This works fine if I run it directly on my laptop (running Ubuntu 13.04). It fails (raises dns.resolver.NoAnswer) if I run it inside a VirtualBox VM (running Ubuntu 12.04).

I've captured network traffic when dns.resolver is doing its job, and I see this in Wireshark:

14 2.416588 10.0.2.15 10.0.2.3 DNS 66 Standard query 0x33bb MX pov.lt
15 2.419498 10.0.2.3 10.0.2.15 DNS 82 Standard query response 0x33bb A 213.133.64.220

I'm not a networking expert, but it seems to me there was an answer, and the correct one in fact (213.133.64.220 is the primary MX for pov.lt).

If I change the query type to 'A' instead of 'MX', DNS resolution succeeds.

NameError: global name 'retry_servfail' is not defined

it raises here:
dns/resolver.py in query

                    #

                    # We got a response, but we're not happy with the

                    # rcode in it.  Remove the server from the mix if

                    # the rcode isn't SERVFAIL.

                    #

                    if rcode != dns.rcode.SERVFAIL or not retry_servfail:

SyntaxError: invalid syntax, line 874

File "/lib/python3.2/site-packages/dns/zone.py", line 874
    except dns.exception.SyntaxError, detail:
                                    ^
SyntaxError: invalid syntax

shouldn't be?

except dns.exception.SyntaxError as detail:

IP addresses with leading zeros are not accepted in /etc/resolv.conf

IP addresses with leading zeros are not accepted in /etc/resolv.conf.
Content of /etc/resolv.conf:

nameserver 127.0.0.01

This doesn't work with python-dns from master branch (commit 0b2b985):

>>> import dns.resolver
>>> dns.resolver.query('test.')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "dns/resolver.py", line 974, in query
    raise_on_no_answer, source_port)
  File "dns/resolver.py", line 830, in query
    source_port=source_port)
  File "dns/query.py", line 219, in udp
    if _addresses_equal(af, from_address, destination) or \
  File "dns/query.py", line 150, in _addresses_equal
    n2 = dns.inet.inet_pton(af, a2[0])
  File "dns/inet.py", line 50, in inet_pton
    return dns.ipv4.inet_aton(text)
  File "dns/ipv4.py", line 43, in inet_aton
    raise dns.exception.SyntaxError
dns.exception.SyntaxError

I think that we could use standard inet_aton and inet_ntoa methods from Python for this. I will send a pull request.

IDNA encoding/decoding issue

Hello,

I have trouble with decoding punycoded IDN domain back to Unicode, here is example (python 2.7):

>>> n = dns.name.from_unicode(u'ee tč')

>>> n.to_text()
'xn--ee\\032t-jua.'

>>> print n.to_text()
xn--ee\032t-jua.

>>> n.to_unicode()
---------------------------------------------------------------------------
UnicodeError                              Traceback (most recent call last)
<ipython-input-66-38cdd9f34ab1> in <module>()
----> 1 n.to_unicode()

/usr/lib/python2.7/site-packages/dns/name.pyc in to_unicode(self, omit_final_dot)
    346         else:
    347             l = self.labels
--> 348         s = u'.'.join([encodings.idna.ToUnicode(_escapify(x)) for x in l])
    349         return s
    350 

/usr/lib64/python2.7/encodings/idna.pyc in ToUnicode(label)
    137     # label2 will already be in lower case.
    138     if label.lower() != label2:
--> 139         raise UnicodeError("IDNA does not round-trip", label, label2)
    140 
    141     # Step 8: return the result of step 5

UnicodeError: ('IDNA does not round-trip', 'xn--ee\\032t-jua', 'xn--ee\\032t-u1a')

But when I use standard library, it works:

>>> a = encodings.idna.ToASCII(u'ee tč')

>>> a
'xn--ee t-jua.'      

>>> u = encodings.idna.ToUnicode(a)

>>> u
>>> u'ee t\u010d'

>>> print u
ee 

When I substitute space with \032, it works with encoding module, but it is giving me different punycoded value:

>>> a = encodings.idna.ToASCII(u'ee\\032tč')

>>> a
'xn--ee\\032t-p6a'

>>> u = encodings.idna.ToUnicode(a)

>>> u
u'ee\\032t\u010d'

>>> print u
ee\032

unicode ipaddr crashes Update.add and Update.replace

If one uses python 2.7 and gives a unicode ipaddr to these methods, they crash.

It is because of some wrong isinstance(x, str) [not: isinstance(x, (str, unicode))] that just checks for str.

Maybe you want to check these isinstance(str) in general, that bug might be at multiple places.

Race condition inside of the cache

See the bottom of the stack trace below. This happens under load, when multiple threads are invoking query()

return dns_resolver.query(hostname, record_type)
File "build/bdist.linux-x86_64/egg/dns/resolver.py", line 591, in query
answer = self.cache.get((qname, rdtype, rdclass))
File "build/bdist.linux-x86_64/egg/dns/resolver.py", line 208, in get
self.maybe_clean()
File "build/bdist.linux-x86_64/egg/dns/resolver.py", line 195, in maybe_clean
del self.data[k]
KeyError: (, 15, 1)

dns.zone.from_text() raise AttributeError with empty record name

Hi,

When I try to import from text a DNS entry with an empty name, it raise the following AttributeError:

  File "/usr/lib/python2.7/dist-packages/dns/zone.py", line 924, in from_text
    reader.read()
  File "/usr/lib/python2.7/dist-packages/dns/zone.py", line 873, in read
    self._rr_line()
  File "/usr/lib/python2.7/dist-packages/dns/zone.py", line 589, in _rr_line
    if not name.is_subdomain(self.zone.origin):
AttributeError: 'NoneType' object has no attribute 'is_subdomain'

You could reproduce it with:

import dns.zone
dns.zone.from_text(' IN NS foo.bar.oni.', origin='foo.bar.oni.', check_origin=False)

self.last_name isn't updated in _MasterReader._rr_line() if token is a whitespace and keep None as value.
I'm not sure if this is really a syntax error, but if this is the case, add

if name is None:
    raise dns.exception.SyntaxError

before https://github.com/rthalley/dnspython/blob/master/dns/zone.py#L589 should be enough.

Python 3 support in the next release ?

I've just tested the Python3 branch, which seems to be working. Is it ready to be merged into master for the next release ? OpenStack could really use a Python3 compatible version of dnspython :)

Running tests

Tests are currently run via a Makefile. Each test file is executed separately, which makes the test summary line a bit useless.

Also, it's not easily runnable via nose or sniffer.

I have created a fork and will move the tests over to dns/tests and rename them so nose will discover them automatically. This should also make it runnable via sniffer.

At the same time, I am considering skipping tests which are not runnable due to missing pycrypto for example. This will report an "S" in the status instead of raising an exception. If pycrypto is available they will be run as expected.

query is vulnerable to DNS hijacking when hostname is a second-level domain

Here's a DNS hijacking exploit with dnspython.
The host name of this host is "sitetruth.com", running CentOS 6, 64 bit, Python 2.7 and dnspython 1.9.4.

Here, we look up "noexample.com", which is a nonexistent domain.

>>> import dns
>>> resolv = dns.resolver.Resolver()
>>> resolv.domain
<DNS name com.>
>>> resolv.query("noexample.com")
<dns.resolver.Answer object at 0x2984b90>
>>> result = resolv.query("noexample.com")
>>> result
<dns.resolver.Answer object at 0x2984e10>
>>> result[0]
<DNS IN A rdata: 64.30.224.112>

64.30.224.112 is "search.com", an ad-heavy search site. We've had a DNS hijacking.

Compare what the Linux "host" command returns:

> host noexample.com
Host noexample.com not found: 3(NXDOMAIN)

So "host" gets it right, and dnspython gets hijacked. So this isn't a problem out in DNS; it's local. Really. This is not a problem with a bad DNS server. It's a client side problem.

Here's what's going on. Notice "resolv.domain" above, with a value "com". The host name is "sitetruth.com", so the "domain" of the host is "com". If the initial lookup fails, the "domain" is appended to the query and the query is retried. So the second lookup is "noexample.com.com", and the query has thus been hijacked to "com.com".

The proprietors of "com.com" have their DNS server set up to accept all queries for any unknown subdomain under "com.com" and divert it to the IP address of "search.com", a fake search engine which returns mostly ads.

The bug is that there should never be a second search with the "domain" appended when "domain" is a top-level domain. If "domain" doesn't have at least 2 components, it should not be used.

Most hosts have longer primary names such as "gator123.hostgator.com"; web sites they host are aliased. They don't hit this problem. But hosts where the host name is a primary domain name in ".com" are vulnerable.

It's possible to work around this bug by assigning

resolv2.domain = dns.name.from_text("")

This prevents such hijacking.

The same bug exists in glibc's "getaddrinfo". See that report for more detail, and how this interacts with the relevant RFC.
Ref: "http://sourceware.org/bugzilla/show_bug.cgi?id=13935"

AttributeError: 'GenericRdata' object has no attribute 'target'

python-dns 1.11.1

Hit this once but not always reproducible. Unfortunately don't have data what domain was actually queried.

Exception in thread Thread-5:
Traceback (most recent call last):
File "/usr/share/python3.3/threading.py", line 901, in _bootstrap_inner
self.run()
File "/usr/share/python3.3/threading.py", line 858, in run
self._target(_self._args, *_self._kwargs)
File "report_unused_domains.py", line 241, in _tFilterByDns
new_domain_list, not_used_domain_list, nxdomains, nonameservers, noanswer = self.filterByDns([domain_data])
File "report_unused_domains.py", line 342, in filterByDns
resolver_answer = dns.resolver.query(domain_data['domain_name'], 'NS')
File "/usr/share/python3.3/site-packages/dns/resolver.py", line 972, in query
raise_on_no_answer, source_port)
File "/usr/share/python3.3/site-packages/dns/resolver.py", line 827, in query
source_port=source_port)
File "/usr/share/python3.3/site-packages/dns/query.py", line 230, in udp
one_rr_per_rrset=one_rr_per_rrset)
File "/usr/share/python3.3/site-packages/dns/message.py", line 787, in from_wire
reader.read()
File "/usr/share/python3.3/site-packages/dns/message.py", line 726, in read
self._get_section(self.message.answer, ancount)
File "/usr/share/python3.3/site-packages/dns/message.py", line 708, in _get_section
rrset.add(rd, ttl)
File "/usr/share/python3.3/site-packages/dns/rdataset.py", line 124, in add
super(Rdataset, self).add(rd)
File "/usr/share/python3.3/site-packages/dns/set.py", line 46, in add
if not item in self.items:
File "/usr/share/python3.3/site-packages/dns/rdata.py", line 218, in eq
return self._cmp(other) == 0
File "/usr/share/python3.3/site-packages/dns/rdtypes/nsbase.py", line 68, in _cmp
return dns.util.cmp(self.target, other.target)
AttributeError: 'GenericRdata' object has no attribute 'target'

Indexation of older versions on PyPI

It looks like it's impossible to install dnspython 1.10.0 from PyPI, probably since 1.11.0 went out:

$ pip install dnspython==1.10.0
Downloading/unpacking dnspython==1.10.0
  Could not find a version that satisfies the requirement dnspython==1.10.0 (from versions: 1.11.0)
Cleaning up...
No distributions matching the version for dnspython==1.10.0

The index page doesn't list older versions, although the release page for 1.10.0 is visible on PyPI.

Is there an option or something that was unchecked?

Export results to JSON

Hi,

I'd like to be able to export the results of a Message to JSON format, for integration with other tools, such as client-side Ajax requests for DNS lookups, etc.

I wrote some code that does this, but I think a native solution as part of the framework would be ideal, by adding to_json() methods in rdata types, etc. Has anyone considered working on this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.