Skip to content

Commit 0b67a07

Browse files
committed
More work done on nameserver lookup, working better now
1 parent 199246f commit 0b67a07

File tree

1 file changed

+75
-46
lines changed

1 file changed

+75
-46
lines changed

dnslookup.py

+75-46
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
GOOGLE_DNS = ['8.8.8.8', '8.8.4.4']
1212

1313
DEFAULT_RESOLVER = dns.resolver.Resolver(configure=True)
14+
DEFAULT_RESOLVER.timeout, DEFAULT_RESOLVER.lifetime = 2, 2
1415

1516

1617
# Max length of four dot-separated octets (e.g. 255.255.255.255)
@@ -19,12 +20,12 @@
1920
IN_ADDR = '.in-addr.arpa.'
2021

2122

22-
def debug_print(text, arguments):
23+
def debug_print(text, *args):
2324
if DEBUG:
24-
print '[D] {}'.format(text).format(*arguments)
25+
print '[D] {}'.format(text).format(*args)
2526

2627

27-
def parse_args():
28+
def _parse_args():
2829

2930
parser = argparse.ArgumentParser(description="Perform DNS Queries.")
3031
parser.add_argument(
@@ -65,7 +66,7 @@ def print_response(ip, name, type, error_msg='', error_type=''):
6566
print response
6667

6768

68-
def get_host_type(query, query_type='A'):
69+
def _get_host_type(query, query_type='A'):
6970
'''
7071
Determine the type of host provided by user. Object will default to
7172
dns.name.Name as last resort.
@@ -81,29 +82,72 @@ def get_host_type(query, query_type='A'):
8182
try:
8283
return ipaddress.ip_address(query), 'PTR'
8384
except ValueError:
84-
debug_print('get_host_type: {} not an IPv4Address.', query)
85+
debug_print('_get_host_type: {} not an IPv4Address.', query)
8586

8687
try:
8788
return ipaddress.ip_network(query), 'PTR'
8889
except ValueError:
89-
debug_print('get_host_type: {} not an IPv4Network.', query)
90+
debug_print('_get_host_type: {} not an IPv4Network.', query)
9091

9192
# Sanity check - must be IP Address to use reversename PTR type
9293
if query_type is 'PTR':
9394
query_type = 'A'
9495

95-
debug_print('get_host_type: {} defaulted to Name type.', query)
96+
debug_print('_get_host_type: {} defaulted to Name type.', query)
9697
return dns.name.from_text(query), query_type
9798

9899

99-
def dns_lookup(query, query_type='A', resolver=DEFAULT_RESOLVER):
100+
def _parse_nameserver(nameserver):
101+
102+
nameserver = _get_host_type(nameserver)[0]
103+
debug_print('nameserver type: {}', (str(type(nameserver))))
104+
105+
if isinstance(nameserver, ipaddress.IPv4Address):
106+
return [nameserver.exploded]
107+
108+
if isinstance(nameserver, ipaddress.IPv4Network):
109+
return [ip.exploded for ip in nameserver]
110+
111+
if isinstance(nameserver, dns.name.Name):
112+
try:
113+
return [str(server) for server in nameserver_query(nameserver)]
114+
115+
except dns.resolver.NoAnswer:
116+
print '[x] Cannot resolve nameserver to IP address, ' \
117+
'exiting... [{}]'.format(nameserver)
118+
119+
return list()
120+
121+
122+
def _valid_nameservers(nameservers):
123+
124+
valid_servers = []
125+
resolver = dns.resolver.Resolver()
126+
resolver.timeout, resolver.lifetime = 2, 2
127+
128+
debug_print('_valid_nameservers nameservers: {}', nameservers)
129+
# Test if nameservers are valid using nameserver as query
130+
for nameserver in nameservers:
131+
resolver.nameservers = [nameserver]
132+
debug_print('\t_valid_nameservers resolver.nameservers: {}',
133+
resolver.nameservers)
134+
nameserver_query(_get_host_type(nameserver)[0], 'PTR', resolver)
135+
valid_servers.append(nameserver)
136+
137+
debug_print('\t_valid_nameservers valid_servers: {}', valid_servers)
138+
139+
return valid_servers
140+
141+
142+
def nameserver_query(query, query_type='A', my_resolver=DEFAULT_RESOLVER):
100143

101144
# Convert IP to reverse-map domain name
102145
if query_type is 'PTR':
103146
query = dns.reversename.from_address(query.exploded)
104147

105-
response = resolver.query(query, query_type)
106-
return [answer for answer in response]
148+
debug_print('nameserver_query query: {} query_type: {}', query, query_type)
149+
query_response = my_resolver.query(query, query_type)
150+
return [answer for answer in query_response]
107151

108152

109153
def dnslookup(hostname='', query_type='A', nameserver='', subnet=False,
@@ -118,51 +162,31 @@ def dnslookup(hostname='', query_type='A', nameserver='', subnet=False,
118162

119163
# Sanitize input host
120164
if hostname:
121-
host, host_type = get_host_type(hostname, query_type)
165+
debug_print('supplied hostname: {}', hostname)
166+
host, host_type = _get_host_type(hostname, query_type)
122167

123168
if isinstance(host, ipaddress.IPv4Network):
124169
if subnet:
125170
queries += [(ip, 'PTR') for ip in host]
126171
else:
127-
queries.append(get_host_type(hostname.partition('/')[0]))
172+
queries.append(_get_host_type(hostname.partition('/')[0]))
128173
else:
129174
queries.append((host, host_type))
130175

131-
debug_print('args.host: {} args.type: {}', (host, host_type))
176+
debug_print('host: {} host_type: {}', host, host_type)
132177

133178
# Parse nameserver argument to determine if valid
134179
if nameserver:
135-
136-
supplied_nameserver = get_host_type(nameserver)[0]
137-
debug_print('nameserver type: {}', type(supplied_nameserver))
138-
if isinstance(supplied_nameserver, ipaddress.IPv4Address):
139-
my_resolver.nameservers = [supplied_nameserver.exploded]
140-
141-
if isinstance(supplied_nameserver, dns.name.Name):
142-
try:
143-
my_resolver.nameservers = map(str, dns_lookup(supplied_nameserver))
144-
except dns.resolver.NoAnswer:
145-
print '[x] Cannot resolve nameserver to IP address, ' \
146-
'exiting... [{}]'.format(supplied_nameserver)
147-
quit()
148-
149-
# Test if nameserver is valid using nameserver as query
150-
reversename = dns.reversename.from_address(
151-
my_resolver.nameservers[0])
152-
try:
153-
dns_lookup(reversename, 'PTR')
154-
except dns.resolver.Timeout:
155-
print '[x] Connection timed out; no servers could be reached' \
156-
' [{}]'.format(supplied_nameserver)
180+
nameservers = _parse_nameserver(nameserver)
181+
my_resolver.nameservers = _valid_nameservers(nameservers)
182+
if not my_resolver.nameservers:
157183
quit()
158184

159-
debug_print('nameserver: {}', my_resolver.nameservers[0])
160-
161185
# Parse file if -f flag set
162186
if filename:
163187
with open(filename, 'r') as in_file:
164188
for line in in_file:
165-
query = get_host_type(line.strip())
189+
query = _get_host_type(line.strip())
166190

167191
if isinstance(query, ipaddress.IPv4Network):
168192
queries.append((query, 'PTR'))
@@ -175,23 +199,24 @@ def dnslookup(hostname='', query_type='A', nameserver='', subnet=False,
175199
debug_print('Entering query lookup loop... ', '')
176200
for items in queries:
177201
query, query_type = items
178-
debug_print('\tquery: {} query type: {} record type: {}', (
179-
query, type(query), query_type))
202+
debug_print('\tquery: {} query type: {} record type: {}',
203+
query, type(query), query_type)
180204

181205
try:
182-
response = dns_lookup(query, query_type)
206+
response = nameserver_query(query, query_type)
183207
except dns.resolver.NXDOMAIN:
184-
print 'NXDOMAIN [{}]'.format(query)
208+
response = ['NXDOMAIN']
209+
185210
for item in response:
186-
print item
187-
debug_print('\tdns_lookup.response: {}', (response))
211+
print '\tResponse: {}\t{}'.format(query, item)
188212

189213
return response
190214

191215
if __name__ == '__main__':
192216

193-
args = parse_args()
217+
args = _parse_args()
194218

219+
print args
195220
response = dnslookup(
196221
hostname=args.host,
197222
query_type=args.type,
@@ -201,9 +226,13 @@ def dnslookup(hostname='', query_type='A', nameserver='', subnet=False,
201226

202227

203228
""" To Do List:
204-
Work more on nameservers, stuff missing
229+
Work more on nameservers, add try statements
205230
Determine if reverse flag is still necessary
206231
Fix -f flag for ipv4networks
207232
Breakout functions into private helper functions
233+
Consider changing queries from tuple to an object
234+
Possibly rethink what _get_host_type returns to be more generic,
235+
deal with specifics outside the function
236+
Determine a better way to deal with resolvers
208237
209238
"""

0 commit comments

Comments
 (0)