== Doing DNS queries in Python 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|http://www.dnspython.org/]], 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|http://www.spamhaus.org]] 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|http://www.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.))