#!/usr/bin/env python from twisted.names import client, error, dns from twisted.internet import reactor, defer def rdns(ip, resolver=client): d = defer.Deferred() def gotPtr ((ans, auth, add), recurse=[]): lookups = len(recurse) + 1 try: ptr = str(ans[0].payload.name) except IndexError: d.callback((ip, None, lookups)) return else: if (ans[0].type == dns.CNAME or ptr.endswith(".in-addr.arpa")) and not ptr in recurse: # recurse! recurse.append(ptr) resolver.lookupPointer(ptr).addErrback(_catchDNSNameError).addCallbacks(gotPtr, d.errback, [recurse]) else: d.callback((ip, ptr, lookups)) resolver.lookupPointer(".".join(ip.split(".")[::-1]) + ".in-addr.arpa").addErrback(_catchDNSNameError).addCallbacks(gotPtr, d.errback) return d def _catchDNSNameError(ex): if not isinstance(ex.value, error.DNSNameError): raise ex return ([], None, None) @defer.deferredGenerator def main(nets, resolver=client, concurrent=64): import time numaddrs = sum(map(len, nets)) if numaddrs > 1: sys.stderr.write("looking up %d addresses (%s)\n\n" % (numaddrs, ', '.join(map(str, nets)))) addrs = [] for net in nets: addrs.extend([socket.inet_ntoa(ip.packed_address) for ip in net]) starttime = time.time() totallookups = 0 while len(addrs) > 0: addrslice = addrs[:concurrent] addrs = addrs[concurrent:] d = defer.waitForDeferred(defer.DeferredList([rdns(addr, resolver=resolver) for addr in addrslice])) yield d results = d.getResult() for (success, result) in results: if success: (ip, ptr, lookups) = result totallookups += lookups print "%s\t%s" % (ip, ptr or "") else: print "# missing %s" % (success,) endtime = time.time() sys.stderr.write("\n%d hosts (%d lookups) in %.2f seconds\n" % (numaddrs, totallookups, endtime-starttime)) reactor.callLater(0, reactor.stop) # twisted udp is broken. haack. #reactor.stop() if __name__ == '__main__': import sys, ipv4, socket resolver = client if len(sys.argv) > 1 and sys.argv[1][0] == '@': host = sys.argv.pop(1)[1:] port = 53 if ':' in host: (host, port) = host.split(':') port = int(port) if sum(map(lambda char: char not in '0123456789.', host)) > 1: try: host = socket.gethostbyname(host) except socket.gaierror, e: sys.exit('%s: cannot lookup dns server %s' % (sys.argv[0], host)) sys.stderr.write("using server %s:%d for reverse lookup\n\n" % (host, port)) resolver = client.Resolver(servers=[(host, port)]) if len(sys.argv) < 2: sys.exit("%s: nothing to look up" % (sys.argv[0],)) nets = [] for arg in sys.argv[1:]: try: addr = ipv4.CIDR(arg) except ValueError: segments = arg.split('/') try: segments[0] = socket.gethostbyname(segments[0]) addr = ipv4.CIDR('/'.join(segments)) except socket.gaierror, e: sys.stderr.write("DNS lookup failed for %s: %s\n" % (arg.split('/')[0], e)) continue nets.append(addr) if len(nets) > 0: main(nets, resolver) reactor.run()