dnspython
a powerful DNS toolkit for python
dnspython home page
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)
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)
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)
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 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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)