Flylib.com

Books Software

 
 
 

DNS from Python


DNS from Python

Python also includes the gethostbyname and gethostbyaddr calls and puts them in the built-in socket module. The gethostbyname function returns a string containing the IP address of the host :

#!/usr/bin/python

from socket import *

...

"Look up the IP number of the given host"
try:
ip = gethostbyname(host)
except:
print host,"does not resolve"
else:
print "The address of",host,"is",ip

Other bindings also exist for Python. Please see the vaults of Parnassus at http://www.vex.net/parnassus/. There you can find bindings for the adns library for asynchronous DNS queries, a DNS server written in Python (!), and a DNS-only interface for resolving names . The latter is not documented, but the test suite documents it quite well. The following is an example :

#!/usr/bin/python

import DNS
# automatically load nameserver(s) from /etc/resolv.conf
# (works on unix - on others, YMMV)
DNS.ParseResolvConf()

r = DNS.DnsRequest(qtype='ANY')

res = r.req("http://www.microsoft.com",qtype='A')

# res.answers is a list of dictionaries of answers
print len(res.answers),'different A records'

# each of these has an entry for 'data', which is the result.
print map(lambda x:x['data'], res.answers)

DNS in Shell Scripts

Some of us still do shell scripting . Name lookups are seldom necessary in shell scripts, but sometimes you do need them. Of course, you can call Perl or some other script language that has gethostbyname (or gethostbyaddr as the case may be), but that is quite expensive. One of the easiest programs to use in shell scripts is the host program that is part of the BIND distribution. Unfortunately, it is not always installed. The reason host is the easiest to use is that its output format is the simplest. Dig and nslookup all provide copious output, most of which is irrelevant if you just want the address of a machine.

With PPP, you usually have an ip-up script, which is run when the PPP interface is configured and up. It is passed a number of parameters, such as the interface name, the device name, the uplink, and your own IP number. To obtain the name belonging to the address you have been assigned, use the following :

#!/bin/ksh
interface=""
device=""
speed=""
myip=""
upip=""

...

$myname = $(host $myip  awk '/name/i { print $(NF) }')

This should work with any Korn shell, Bash, and simple adaptations in standard Bourne shells as well. The problem with host is that some variants are available that have different output formats. This ip-up script is the best choice for performing DNS updates when you're getting dynamic addresses from your ISP.

Using Dig or nslookup to look up things in general can get tricky. Dig and nslookup both print many similar lines of output during a normal query :

$


nslookup www.amazon.com


Server:  smp.linpro.no
Address:  195.0.166.3

Name: www.amazon.com
Address:  208.202.218.15

Because nslookup is most likely to be available on any given host, it is preferable to Dig (if only for that reason). Detecting errors with nslookup is a bit complicated, however. One way to do this is to count how many Address: lines exist in the output. Another is to note the error message format. In the versions of nslookup I know, error messages always start in *** :

address=$(nslookup $host 2>&1  awk '
/^Address:/ { a=$(NF); }
/\*\*\*/    { exit 1; }
END         { print a; }')
case $address in
'') echo error looking up $host;;
*)  echo $host has address $address;;
esac

The approach is to exit at once if an error message of any kind occurs, and otherwise to print the contents of the last Address: line when the script terminates. In my personal opinion, however, Dig is better.

The Dig output format is quite machine friendly, and little reason should exist for any vendor to change it. Looking for the NOERROR string in its output to check for errors is easy, and adding +pfmin to the command line will take care of trimming down the output amount :

$

dig http://www.amazon.com +pfmin

;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49781
;; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2
;; QUERY SECTION:
;; www.amazon.com, type = A, class = IN

;; ANSWER SECTION:
www.amazon.com.         53S IN A        208.216.182.15

This output format reduces the work amount to something acceptable, compared to the following default Dig output format:

address=$(dig $host +pfmin 2>/dev/null  awk '
/IN A/ { print $(NF); exit 0; }
/NOERROR/ { next; }
/status:/ { exit 1; }')
case $address in
'') echo error looking up $host;;
*)  echo $host has address $address;;
esac