EzDevInfo.com

dnspython

a powerful DNS toolkit for python dnspython home page

How do I use dnspython to query for a host pattern

Let us say that I want to count the number of hosts that match a simple pattern. For example:

host1.example.com host2.example.com ... host42.example.com

where I don't know ahead of time that there are 42 of these. What I would like to do is something like:

answers = dns.resolver.query('host*.example.com', 'A')

and then be able to get the length of answers for the count or iterate over answers for the actual hostnames.

Thanks,

Glenn


Source: (StackOverflow)

Tell urllib2 to use custom DNS

I'd like to tell urllib2.urlopen (or a custom opener) to use 127.0.0.1 (or ::1) to resolve addresses. I wouldn't change my /etc/resolv.conf, however.

One possible solution is to use a tool like dnspython to query addresses and httplib to build a custom url opener. I'd prefer telling urlopen to use a custom nameserver though. Any suggestions?


Source: (StackOverflow)

Advertisements

How can I find the authoritative DNS server for a domain using dnspython?

As part of a tool I'm writing I want to have a diagnostic that will tell the user whether they have configured their domain's DNS correctly for a particular service. I want to query the authoritative DNS server for their domain so that I can bypass any cached results.


Source: (StackOverflow)

How make dns queries in dns-python as dig (with aditional records section)?

I trying use dns python and want get all records with ANY type query:

import dns.name
import dns.message
import dns.query

domain = 'google.com'
name_server = '8.8.8.8'

domain = dns.name.from_text(domain)
if not domain.is_absolute():
    domain = domain.concatenate(dns.name.root)

request = dns.message.make_query(domain, dns.rdatatype.ANY)

response = dns.query.udp(request, name_server)
print response.answer
print response.additional
print response.authority

but it return me

[]
[]
[]

When I try make this request with dig:

$ dig @8.8.8.8  google.com -t ANY

; <<>> DiG 9.9.2-P1 <<>> @8.8.8.8 google.com -t ANY
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2848
;; flags: qr rd ra; QUERY: 1, ANSWER: 25, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;google.com.            IN  ANY

;; ANSWER SECTION:
google.com.     299 IN  A   173.194.40.14
google.com.     299 IN  A   173.194.40.1
google.com.     299 IN  A   173.194.40.7
google.com.     299 IN  A   173.194.40.4
google.com.     299 IN  A   173.194.40.3
google.com.     299 IN  A   173.194.40.0
google.com.     299 IN  A   173.194.40.8
google.com.     299 IN  A   173.194.40.6
google.com.     299 IN  A   173.194.40.5
google.com.     299 IN  A   173.194.40.2
google.com.     299 IN  A   173.194.40.9
google.com.     299 IN  AAAA    2a00:1450:4002:804::1000
google.com.     21599   IN  TYPE257 \# 23 0009697373756577696C6473796D616E7465632E636F6D
google.com.     21599   IN  TYPE257 \# 19 0005697373756573796D616E7465632E636F6D
google.com.     21599   IN  NS  ns2.google.com.
google.com.     21599   IN  NS  ns3.google.com.
google.com.     599 IN  MX  50 alt4.aspmx.l.google.com.
google.com.     599 IN  MX  10 aspmx.l.google.com.
google.com.     3599    IN  TXT "v=spf1 include:_spf.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all"
google.com.     599 IN  MX  20 alt1.aspmx.l.google.com.
google.com.     21599   IN  SOA ns1.google.com. dns-admin.google.com. 2013070800 7200 1800 1209600 300
google.com.     599 IN  MX  30 alt2.aspmx.l.google.com.
google.com.     21599   IN  NS  ns1.google.com.
google.com.     599 IN  MX  40 alt3.aspmx.l.google.com.
google.com.     21599   IN  NS  ns4.google.com.

;; Query time: 52 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Tue Jul 16 18:23:46 2013
;; MSG SIZE  rcvd: 623

When I check requests with wireshark then found that dig and dns python have different requests:

dig:

0000  c8 64 c7 3a e3 40 50 46  5d a5 70 99 08 00 45 00   .d.:.@PF ].p...E.
0010  00 43 9f 60 00 00 40 11  09 8f c0 a8 01 03 08 08   .C.`..@. ........
0020  08 08 8e 9e 00 35 00 2f  71 cf ef 49 01 20 00 01   .....5./ q..I. ..
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                

dns python:

0000  c8 64 c7 3a e3 40 50 46  5d a5 70 99 08 00 45 00   .d.:.@PF ].p...E.
0010  00 38 00 00 40 00 40 11  68 fa c0 a8 01 03 08 08   .8..@.@. h.......
0020  08 08 b8 62 00 35 00 24  23 6b 3d 31 01 00 00 01   ...b.5.$ #k=1....
0030  00 00 00 00 00 00 06 67  6f 6f 67 6c 65 03 63 6f   .......g oogle.co
0040  6d 00 00 ff 00 01                                  m.....           

For DNS query section:

dig have AD bit: Set flag:

002C-002D: 01 20 for dig and 01 00 for dns python

and this Additional records section that except for dns-python:

0046-0050: 00 00 29 10 00 00 00 00 00 00 00.

This actual also not only for google.com also for logitech.com mayby other.

So how can I make requests with dns python as dig with this additional section?


Source: (StackOverflow)

Is it reasonable in Python to check for a specific type of exception using isinstance?

Is it reasonable in Python to catch a generic exception, then use isinstance() to detect the specific type of exception in order to handle it appropriately?

I'm playing around with the dnspython toolkit at the moment, which has a range of exceptions for things like a timeout, an NXDOMAIN response, etc. These exceptions are subclasses of dns.exception.DNSException, so I am wondering if it's reasonable, or pythonic, to catch DNSException then check for a specific exception with isinstance().

e.g.

try:
    answers = dns.resolver.query(args.host)
except dns.exception.DNSException as e:
    if isinstance(e, dns.resolver.NXDOMAIN):
        print "No such domain %s" % args.host
    elif isinstance(e, dns.resolver.Timeout):
        print "Timed out while resolving %s" % args.host
    else:
        print "Unhandled exception"

I'm new to Python so be gentle!


Source: (StackOverflow)

dnspython - get AAAA, A, NS and other records with one query

I'm trying to build fast script for parsing all DNS records for a single domain name. The 'ANY' command seems to do the trick, but I have strange problems with TTLs. When using ANY like this

domain = dns.name.from_text(domain)
nameserver = '127.0.0.1'
query = dns.message.make_query(domain, dns.rdatatype.ANY)
response = dns.query.udp(query, nameserver, timeout = 2)
print response

The returned data is what I need, but when the TTLs expire the script just don't return the expired records. The 'DIG domain ANY' command seems to have this problem too.

So my question is what is the fastest way to get all DNS records for a single domain?


Source: (StackOverflow)

How do we get TXT, CNAME and SOA records from dnspython?

I have a requirement to have a dns query function to query a server for various records. I figured out how to get the MX record (most of the examples show this), A record and NS record. How do I get the TXT, CNAME and SOA records?

Sample code snippet:

   import dns.resolver
   answer=dns.resolver.query("google.com", "A")
       for data in answer:
           print data.address

I tried replacing the query type with TXT and the data.address object with data.text, data.data etc, but ended up with attribute errors. What are the references for the data types I mentioned earlier?


Source: (StackOverflow)

Dnspython: Setting query timeout/lifetime

I have a small script that checks a large list of domains for their MX records, everything works fine but when the script finds a domain with no record, it takes quite a long time to skip to the next one.

I have tried adding:

query.lifetime = 1.0
or
query.timeout = 1.0

but this doesn't seem to do anything. Does anyone know how this setting is configured?

My script is below, thanks for your time.

import dns.resolver
from dns.exception import DNSException
import dns.query
import csv

domains = csv.reader(open('domains.csv', 'rU'))
output = open('output.txt', 'w')
for row in domains:
    try:
        domain = row[0]
        query = dns.resolver.query(domain,'MX')
        query.lifetime = 1.0
    except DNSException:
        print "nothing here"
    for rdata in query:
            print domain, " ", rdata.exchange, 'has preference', rdata.preference
            output.writelines(domain)
            output.writelines(",")
            output.writelines(rdata.exchange.to_text())
            output.writelines("\n")

Source: (StackOverflow)

TXT records in dnsPython

I have implemented a simple DNS server. It simply responds with a TXT record. I am hosting the script as the NS server for example.com. The NS server is x.y.z.k. It works fine when I issue something like:

$ dig demo.example.com @x.y.z.k

; <<>> DiG 9.3.6-P1-RedHat-9.3.6-4.P1.el5_4.1 <<>> demo.example.com @x.y.z.k
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10028
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2

;; QUESTION SECTION:
;demo.example.com. IN A

;; ANSWER SECTION:
demo.example.com. 1000 IN TXT "test message"

but it does not work when I ask the very same question from one of the public name servers (For example Sun's DNS at 4.2.2.1):

$ dig demo.example.com @4.2.2.1 (I get the same thing when I issue $ dig demo.example.com @4.2.2.1 TXT)

; <<>> DiG 9.3.6-P1-RedHat-9.3.6-4.P1.el5_4.1 <<>> demo.example.com
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 10905
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;demo.example.com. IN A

;; Query time: 5837 msec
;; SERVER: 172.16.1.1#53(172.16.1.1)
;; WHEN: Tue Jul 20 04:01:27 2010
;; MSG SIZE  rcvd: 75

Do you guys have any idea what is wrong? Interestingly if I change the response type to something like CNAME, instead of TXT, it works fine.

def dns_respond(resp, q, data_type):
    rrset = dns.rrset.from_text(q.name, 1000,
           dns.rdataclass.IN, dns.rdatatype.TXT, 'test message')
    resp.answer.append(rrset)
    return resp

def dns_ok(resp, q, data = None, msg = ''):
    return dns_respond(resp = resp, q = q, data_type = 'OK')

def dns_error(resp, q):
    return dns_respond(resp = resp, q = q, data_type = 'Error')

def requestHandler(address, message):
    resp = None
    message_id = ord(message[0]) * 256 + ord(message[1])
    logging.debug('msg id = ' + str(message_id))
    if message_id in serving_ids:
        # the request is already taken, drop this message
        logging.debug('I am already serving this request.')
        return
    serving_ids.append(message_id)
    msg = dns.message.from_wire(message)
    op = msg.opcode()
    if op == 0:
        # standard and inverse query
        qs = msg.question
        if len(qs) > 0:
            q = qs[0]
            logging.debug('request is ' + str(q))
            if q.rdtype == dns.rdatatype.A:
                resp = std_qry(msg)
            else:
                # not implemented
                #resp = std_qry(msg)
                resp = make_response(qry=msg, RCODE=4)   
    else:
        # not implemented
        resp = make_response(qry=msg, RCODE=4)   

    if resp:
        s.sendto(resp.to_wire(), address)

def std_qry(msg):
    qs = msg.question
    logging.debug(str(len(qs)) + ' questions.')

    answers = []
    nxdomain = False
    for q in qs:
        resp = make_response(qry=msg)
        logging.critical('Sending...')
        return dns_ok(resp, q)

def make_response(qry=None, id=None, RCODE=0):
    if qry is None and id is None:
        raise Exception, 'bad use of make_response'
    if qry is None:
        resp = dns.message.Message(id)
        # QR = 1
        resp.flags |= dns.flags.QR
        if RCODE != 1:
            raise Exception, 'bad use of make_response'
    else:
        resp = dns.message.make_response(qry)
    #resp.flags |= dns.flags.AA
    resp.flags |= dns.flags.RA
    resp.set_rcode(RCODE)
    return resp
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 53))
logging.debug('binded to UDP port 53.')
serving_ids = []

while True:
    logging.debug('waiting requests.')
    message, address = s.recvfrom(1024)
    logging.debug('serving a request.')
    requestHandler(address, message)

Source: (StackOverflow)

DNSSEC Sign RRSET using DNSPython

I'm trying to DNSSEC Sign a RRSET, however I am not able finding any references to how to do so using DNSPython. Yes it has dns.dnssec.validate_rrsig(), but I want to DNSSEC sign a rrset, how can this be done?

I've been pooring over the RFC's however I'm obviously lacking something in order to make it work.


Source: (StackOverflow)

dnspython and python objects

I'm trying to use the dnspython library, and am a little confused by their example for querying MX records on this page: www.dnspython.org/examples.html:

import dns.resolver

answers = dns.resolver.query('dnspython.org', 'MX')
for rdata in answers:
    print 'Host', rdata.exchange, 'has preference', rdata.preference

In the python CLI, a dir(answers) gives me:

['__class__', '__delattr__', '__delitem__', '__delslice__', '__dict__', '__doc__', '__getattr__', '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__', '__iter__', '__len__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'expiration', 'qname', 'rdclass', 'rdtype', 'response', 'rrset']

Two things are confusing to me (which are related):

  • Iteration over the answers object. What is rdata in the example?
  • None of the attributes or methods of answers matches exchange or preference. Clearly rdata is not just a simple alias of answers, but I don't understand where those attributes are coming from.

  • Source: (StackOverflow)

    dnspython and '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


    Source: (StackOverflow)

    dnspython dynamic TXT record update with spaces?

    I have the following simple Python script utilising the dnspython library:

    import dns.query
    import dns.tsigkeyring
    import dns.update
    import dns.rdatatype
    import datetime
    import sys
    
    # Get data
    current_ip = '1.2.3.4'
    
    # Update DNS server
    keyring = dns.tsigkeyring.from_text({
        'my.key.name' : 'xxxxxxxxxxxxxxxxxxxx=='
    })
    
    update = dns.update.Update('dyn.example.com', keyring=keyring)
    update.replace('myhost', 60, dns.rdatatype.A, current_ip)
    update.replace('myhost', 60, dns.rdatatype.TXT, "xxx yyy zzz")
    
    response = dns.query.tcp(update, 'ns.example.com')
    

    It works reasonably well as evidenced by the output of the host command, but for some reason my TXT value seems to be split on each space and each segment quoted. So the output from the host command looks like the following:

    $ host -t ANY myhost.dyn.example.com
    myhost.dyn.example.com descriptive text "xxx" "yyy" "zzz"
    myhost.dyn.example.com has address 1.2.3.4
    

    Can anyone tell me why this is happening, and how to have it do the proper thing, which would be this:

    $ host -t ANY myhost.dyn.example.com
    myhost.dyn.example.com descriptive text "xxx yyy zzz"
    myhost.dyn.example.com has address 1.2.3.4
    

    I must be missing something pretty obvious, but the documentation for dnspython is a little short on examples and much Googling has not revealed anything thus far. All help gratefully received.


    Source: (StackOverflow)

    How do you map an email address onto a SOA RNAME field?

    Is there an existing/standard algorithm for mapping an email address onto a RNAME field of a SOA record (and its inverse)? I'm using the dnspython package but I don't see anything in their source tree to handle this. I ran into the edge case of having a period '.' in the username that needs to be escaped and wondering if there are any other edge cases that I am missing. RFC 1035 simply states:

    A <domain-name> which specifies the mailbox of the person responsible for this zone.

    None of the RFCs that update 1035 expand upon RNAME field aside from a brief mention in RFC 1183.


    Source: (StackOverflow)

    Read zone file with dnspython SOA error

    I am really battling to get dnspython to read a zone file, I always get stuck with SOA and I have tried combinations of different zones files and python scripts.

    Zone file(From http://agiletesting.blogspot.com/2005/08/managing-dns-zone-files-with-dnspython.html):

    $TTL 36000
    example.com. IN      SOA     ns1.example.com. hostmaster.example.com. (
                   2005081201      ; serial
                   28800   ; refresh (8 hours)
                   1800    ; retry (30 mins)
                   2592000 ; expire (30 days)
                   86400 ) ; minimum (1 day)
    
    example.com.     86400   NS      ns1.example.com.
    example.com.     86400   NS      ns2.example.com.
    example.com.     86400   MX 10   mail.example.com.
    example.com.     86400   MX 20   mail2.example.com.
    example.com.     86400   A       192.168.10.10
    ns1.example.com.        86400   A       192.168.1.10
    ns2.example.com.        86400   A       192.168.1.20
    mail.example.com.       86400   A       192.168.2.10
    mail2.example.com.      86400   A       192.168.2.20
    www2.example.com.       86400   A    192.168.10.20
    www.example.com.        86400 CNAME     example.com.
    ftp.example.com.        86400 CNAME     example.com.
    webmail.example.com.    86400 CNAME     example.com.
    

    Script 1(From http://agiletesting.blogspot.com/2005/08/managing-dns-zone-files-with-dnspython.html):

    import dns.zone
    from dns.exception import DNSException
    import dns.ipv4
    import os.path
    import sys
    
    zone_file = sys.argv[1]
    print "Command line argument: " + str(zone_file)
    
    domain = os.path.basename(zone_file).replace(".hosts","")
    print "Domain - "+domain
    
    try:
            zone = dns.zone.from_file(zone_file, domain)
            print "Zone origin:", zone.origin
    
            for name, node in zone.nodes.items():
                    rdatasets = node.rdatasets
                    print "\n**** BEGIN NODE ****"
                    print "node name:", name
                    for rdataset in rdatasets:
                            print "--- BEGIN RDATASET ---"
                            print "rdataset string representation:", rdataset
                            print "rdataset rdclass:", rdataset.rdclass
                            print "rdataset rdtype:", rdataset.rdtype
                            print "rdataset ttl:", rdataset.ttl
                            print "rdataset has following rdata:"
                            for rdata in rdataset:
                                    print "-- BEGIN RDATA --"
                                    print "rdata string representation:", rdata
                                    if rdataset.rdtype == SOA:
                                            print "** SOA-specific rdata **"
                                            print "expire:", rdata.expire
                                            print "minimum:", rdata.minimum
                                            print "mname:", rdata.mname
                                            print "refresh:", rdata.refresh
                                            print "retry:", rdata.retry
                                            print "rname:", rdata.rname
                                            print "serial:", rdata.serial
                                    if rdataset.rdtype == MX:
                                            print "** MX-specific rdata **"
                                            print "exchange:", rdata.exchange
                                            print "preference:", rdata.preference
                                    if rdataset.rdtype == NS:
                                            print "** NS-specific rdata **"
                                            print "target:", rdata.target
                                    if rdataset.rdtype == CNAME:
                                            print "** CNAME-specific rdata **"
                                            print "target:", rdata.target
                                    if rdataset.rdtype == A:
                                            print "** A-specific rdata **"
                                            print "address:", rdata.address
    
    except DNSException, e:
            print e.__class__, e
    

    The Error:

    python read_zonefile.py example.com.hosts

    Command line argument: example.com.hosts

    Domain - example.com

    Zone origin: example.com.

    ** BEGIN NODE **

    node name: @

    --- BEGIN RDATASET ---

    rdataset string representation: 36000 IN SOA ns1 hostmaster 2005081201 28800 1800 2592000 86400

    rdataset rdclass: 1

    rdataset rdtype: 6

    rdataset ttl: 36000

    rdataset has following rdata:

    -- BEGIN RDATA --

    rdata string representation: ns1 hostmaster 2005081201 28800 1800 2592000 86400

    Traceback (most recent call last):

    File "read_zonefile.py", line 31, in

    if rdataset.rdtype == SOA:
    

    NameError: name 'SOA' is not defined

    Script 2:

    import dns.zone
    import dns.ipv4
    import os.path
    import sys
    reverse_map Olivia Munn= {}
    for filename in sys.argv[1:]:
            zone = dns.zone.from_file(filename, os.path.basename(filename),relativize=False)
            for (name, ttl, rdata) in zone.iterate_rdatas('A'):
                    try:
                            reverse_map[rdata.address].append(name.to_text())
                    except KeyError:
                            reverse_map[rdata.address] = [name.to_text()]
    keys = reverse_map.keys()
    keys.sort(lambda a1, a2: cmp(dns.ipv4.inet_aton(a1), dns.ipv4.inet_aton(a2)))
    for k in keys:
            v = reverse_map[k]
            v.sort()
            print k, v
    

    Error:

    python create_rev_dns.py example.com.hosts

    Traceback (most recent call last):

    File "create_rev_dns.py", line 7, in

    zone = dns.zone.from_file(filename, os.path.basename(filename),relativize=False)
    

    File "/usr/lib64/python2.6/site-packages/dns/zone.py", line 977, in from_file

    filename, allow_include, check_origin)
    

    File "/usr/lib64/python2.6/site-packages/dns/zone.py", line 924, in from_text

    reader.read()
    

    File "/usr/lib64/python2.6/site-packages/dns/zone.py", line 882, in read

    self.zone.check_origin()
    

    File "/usr/lib64/python2.6/site-packages/dns/zone.py", line 521, in check_origin

    raise NoSOA
    

    dns.zone.NoSOA

    As for the Zone file I have downloaded a zone file from Godaddy.com, the same issue. I have taken a zone file from a PRODUCTION Bind server(Secondary Zone), same error.

    So I am really stumped, any assistance will greatly be appropriated.


    Source: (StackOverflow)