I recycled an old PC yesterday, which afforded me the chance to go back through the code that I had on it and integrate it into my subversion tree. I got that pc 10 years ago, so it had some fairly atrocious code. Taking advantage of python, I decided to rewrite a script that did a reverse DNS lookup on a supplied range of IP addresses.

Instead of serially querying, this version parallelizes using python's threading module and enforces the MAX_THREADS count with Queue instance (because we want to be nice to our DNS servers ;).

Update 2007-05-08
I decided to make the threading a bit easier by creating a Manager class by extending Queue.Queue. I also dumped the ipv4 routines to their own module.

class Manager(Queue.Queue): def __init__(self, function, report, max_threads): # set up threadsafe limit on concurrent threads Queue.Queue.__init__(self, max_threads) # save what we're supposed to do self.function = function self.report = report class Thread(threading.Thread): def __init__(self, manager, *args): threading.Thread.__init__(self) self.args = args self.manager = manager # tell management I exist self.manager.put(self.getName) def run(self): # do work, then resign assert self.manager.qsize() <= self.manager.maxsize self.manager.report( self.manager.function(self.args) ) self.manager.get(self.getName)
import string """ IPv4 routines """ def ip_to_int(ip): ip = string.split(ip, r'.') for i,j in enumerate(ip): ip[i] = int(ip[i]) return ip[0] * 256**3 + ip[1] * 256**2 + ip[2] * 256 + ip[3] def int_to_ip(int): int = [ (int // 256**3) % 256, (int // 256**2) % 256, (int // 256) % 256, int % 256 ] for i,j in enumerate(int): int[i] = str(int[i]) return r'.'.join( int ) def iter(start, end): for i in range( ip_to_int(start), ip_to_int(end) + 1 ): yield int_to_ip(i)
import sys, socket sys.path.append("/home/phaller/lib/") import ThreadManager, IPv4 # given an IP range, get the reverse DNS entries MAX_THREADS = 5 # no cleanup necessary, just run the lookup (hope the implementation is threadsafe. ;) def Reverse_DNS(var_args): ip = var_args[0] ret = "" try: ret = [ ip, socket.gethostbyaddr(ip)[0] ] except socket.herror, e: ret = [ ip, e[1] ] return ret def Report(var_args): print "%-15s => %s" % tuple(var_args) sys.stderr.write( "converting '%s' - '%s'\n" % (sys.argv[1], sys.argv[2]) ) # start managed threads m = ThreadManager.Manager(Reverse_DNS, Report, MAX_THREADS) for ip in IPv4.iter( sys.argv[1], sys.argv[2] ): ThreadManager.Thread( m, ip ).start()

While I am not huge fan of Python, I can read your Python better than I can your Perl :) - Nathan
Yeah, "one way to do things" seems quite useful in that regard. The standard library hasn't sucked out too much, either (the lack of ip_to_int() and int_to_ip() irks ISP tards like me, though ;). -- Patrick.