Every now and then, there comes a time when you need to make DNS queries more complicated than
gethostbyname
and
gethostbyaddr
. Or 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
TXT
DNS 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.))