Doing DNS queries in Python
Every now and then, there comes a time when you need to make DNS
queries more complicated than
at least, that's what happens to me.
When this happens, my best Python tool is the dnspython module, a pure Python module for doing all sorts of DNS manipulation. But dnspython is a little bit obscure to use, so here's a sample program.
This program looks up IP addresses on the command line that are in the SBL and reports the URLs to their SBL records, so you can see exactly why something is listed. (If an IP address isn't actually in the SBL, nothing gets printed.)
#!/usr/bin/python import sys from dns.resolver import query from dns.exception import DNSException def revip(ip): n = ip.split('.') n.reverse() return '.'.join(n) sstr = '%s.sbl.spamhaus.org.' def sblip(ip): qstr = sstr % revip(ip) try: qa = query(qstr, 'TXT') except DNSException: return for rr in qa: for s in rr.strings: print s def process(args): for ip in args: sblip(ip) if __name__ == '__main__': process(sys.argv[1:])
The SBL DNS blocklist zone lists the SBL record URLs as
records, so all we have to do is to make a TXT query against the
proper zone. dns.resolver.query is the easiest interface for most
simple query operations, so that's what we use. There are two tricky
bits having to do with how DNS and
TXT DNS records work.
First, a DNS reply can include more than one record in the answer; for
example, a single IP address might be in several SBL records. So we
have to iterate over the answer to get every
rr (which I believe is
short for 'resource record', and is a standard DNS thing).
Second, a single
TXT record can include multiple pieces of text. I
don't believe the SBL uses this, but other places do; for example, the
routeviews.org DNS-queryable database
of IP to ASN mappings does. So in this program, we iterate over all
the strings in each
rr and print that.
(Perhaps next I'll do a version of this program in perl for comparison purposes. (Feel free to beat me to it in comments.))