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.