parent
0b74fa93c7
commit
93d5fffbb9
5 changed files with 128 additions and 48 deletions
@ -1,8 +1,12 @@ |
||||
import dns.resolver |
||||
import dns.message |
||||
|
||||
class ExtendedAnswer(dns.resolver.Answer): |
||||
def __init__(self, initial_answer): |
||||
self.qname = initial_answer.qname |
||||
self.rrsets = [initial_answer.rrset,] |
||||
self.owner_name = initial_answer.rrset.name |
||||
|
||||
class ExtendedAnswer(dns.message.Message): |
||||
|
||||
def __init__(self, initial_msg): |
||||
#for field in initial_msg.__attr__: |
||||
# self.field = initial_msg.field |
||||
super(ExtendedAnswer, self).__init__() |
||||
self.nameserver = None |
||||
self.qname = None |
||||
|
||||
|
@ -0,0 +1,85 @@ |
||||
import copy |
||||
|
||||
import dns.message |
||||
import dns.resolver |
||||
import Answer |
||||
|
||||
class Timeout(Exception): |
||||
pass |
||||
|
||||
class NoSuchDomainName(Exception): |
||||
pass |
||||
|
||||
class UnknownError(Exception): |
||||
pass |
||||
|
||||
class Resolver(): |
||||
|
||||
def __init__(self, nameservers=None, maximum=3, timeout=0.5, |
||||
edns_version=0, edns_payload=4096): |
||||
# TODO CRIT: DNSSEC |
||||
# TODO: ednsflags such as NSID |
||||
""" A "None" value for the parameter nameservers means to use |
||||
the system's default resolver(s). Otherwise, this parameter |
||||
is an *array* of the IP addresses of the resolvers. |
||||
edns_version=0 means EDNS0, the original one. Use -1 for no EDNS """ |
||||
self.maximum = maximum |
||||
self.timeout = timeout |
||||
self.original_edns = edns_version |
||||
self.original_payload = edns_payload |
||||
if nameservers is None: |
||||
self.original_nameservers = dns.resolver.get_default_resolver().nameservers |
||||
else: |
||||
# TODO: test it is an iterable? And of length > 0? |
||||
self.original_nameservers = nameservers |
||||
self.edns = self.original_edns |
||||
self.payload = self.original_payload |
||||
self.nameservers = self.original_nameservers |
||||
|
||||
def query(self, name, type, tcp=False): |
||||
# TODO CRIT : TCP |
||||
""" The returned value is a DNSLG.Answer """ |
||||
for ns in self.nameservers: |
||||
try: |
||||
message = dns.message.make_query(name, type, |
||||
use_edns=self.edns, payload=self.payload, |
||||
want_dnssec=True) |
||||
except TypeError: # Old DNS Python... Code here just as long as it lingers in some places |
||||
message = dns.message.make_query(name, type, use_edns=0, |
||||
want_dnssec=True) |
||||
message.payload = 4096 |
||||
done = False |
||||
tests = 0 |
||||
while not done and tests < self.maximum: |
||||
try: |
||||
msg = dns.query.udp(message, ns, timeout=self.timeout) |
||||
if msg.rcode() == dns.rcode.NOERROR: |
||||
done = True |
||||
elif msg.rcode() == dns.rcode.NXDOMAIN: |
||||
raise NoSuchDomainName() |
||||
# TODO CRIT: if REFUSED or SERVFAIL, tries the next resolver? |
||||
else: |
||||
raise UnknownError(msg.rcode) |
||||
except dns.exception.Timeout: |
||||
tests += 1 |
||||
if done: |
||||
response = copy.copy(msg) |
||||
response.__class__ = Answer.ExtendedAnswer |
||||
response.nameserver = ns |
||||
response.qname = name |
||||
return response |
||||
# If we are still here, it means no name server answers |
||||
raise Timeout() |
||||
|
||||
def set_edns(self, version=0, payload=4096, dnssec=False): |
||||
""" version=0 means EDNS0, the original one. Use -1 for no EDNS """ |
||||
self.edns = version |
||||
self.payload = None |
||||
|
||||
def set_nameservers(self, nameservers): |
||||
self.nameservers = nameservers |
||||
|
||||
def reset(self): |
||||
self.edns = self.original_edns |
||||
self.payload = self.original_payload |
||||
self.nameservers = self.original_nameservers |
@ -0,0 +1,16 @@ |
||||
#!/usr/bin/python |
||||
|
||||
import DNSLG |
||||
import sys |
||||
|
||||
resolver = DNSLG.Resolver.Resolver(["127.0.0.1", "8.8.8.8"], maximum=2) |
||||
for name in sys.argv[1:]: |
||||
result = resolver.query(name, "ANY") |
||||
print result.answer |
||||
print "From %s: " % result.nameserver |
||||
rrsets = result.answer # There is also additional, authority, etc |
||||
for rrset in rrsets: |
||||
print "%s/%s ->" % (rrset.name, rrset.rdtype) |
||||
for rr in rrset: |
||||
print "\t%s" % rr |
||||
print "" |
Loading…
Reference in new issue