User can specify source address (Fixes #46)
- also respect resolver port number (if specified by user)
This commit is contained in:
parent
1b9849c224
commit
e3ddfff88e
@ -133,6 +133,7 @@ def usage():
|
|||||||
print(' -a --asn Turn on AS# lookups for each hop encountered')
|
print(' -a --asn Turn on AS# lookups for each hop encountered')
|
||||||
print(' -s --server DNS server to use (default: first system resolver)')
|
print(' -s --server DNS server to use (default: first system resolver)')
|
||||||
print(' -p --port DNS server port number (default: 53)')
|
print(' -p --port DNS server port number (default: 53)')
|
||||||
|
print(' -S --srcip Query source IP address (default: default interface address)')
|
||||||
print(' -c --count Maximum number of hops (default: 30)')
|
print(' -c --count Maximum number of hops (default: 30)')
|
||||||
print(' -w --wait Maximum wait time for a reply (default: 2)')
|
print(' -w --wait Maximum wait time for a reply (default: 2)')
|
||||||
print(' -t --type DNS request record type (default: A)')
|
print(' -t --type DNS request record type (default: A)')
|
||||||
@ -182,7 +183,7 @@ def expert_report(trace_path, color_mode):
|
|||||||
print(" %s[*]%s No expert hint available for this trace" % (color.G, color.N))
|
print(" %s[*]%s No expert hint available for this trace" % (color.G, color.N))
|
||||||
|
|
||||||
|
|
||||||
def ping(resolver, hostname, dnsrecord, ttl, use_edns=False):
|
def ping(resolver, hostname, dnsrecord, ttl, src_ip, use_edns=False):
|
||||||
global _ttl
|
global _ttl
|
||||||
|
|
||||||
reached = False
|
reached = False
|
||||||
@ -193,7 +194,7 @@ def ping(resolver, hostname, dnsrecord, ttl, use_edns=False):
|
|||||||
resolver.use_edns(edns=0, payload=8192, ednsflags=dns.flags.edns_from_text('DO'))
|
resolver.use_edns(edns=0, payload=8192, ednsflags=dns.flags.edns_from_text('DO'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resolver.query(hostname, dnsrecord, raise_on_no_answer=False)
|
resolver.query(hostname, dnsrecord, source=src_ip, raise_on_no_answer=False)
|
||||||
|
|
||||||
except dns.resolver.NoNameservers as e:
|
except dns.resolver.NoNameservers as e:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
@ -237,6 +238,7 @@ def main():
|
|||||||
timeout = 2
|
timeout = 2
|
||||||
dnsserver = dns.resolver.get_default_resolver().nameservers[0]
|
dnsserver = dns.resolver.get_default_resolver().nameservers[0]
|
||||||
dest_port = 53
|
dest_port = 53
|
||||||
|
src_ip = None
|
||||||
hops = 0
|
hops = 0
|
||||||
as_lookup = False
|
as_lookup = False
|
||||||
expert_mode = False
|
expert_mode = False
|
||||||
@ -245,9 +247,9 @@ def main():
|
|||||||
color_mode = False
|
color_mode = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "aqhc:s:t:w:p:nexC",
|
opts, args = getopt.getopt(sys.argv[1:], "aqhc:s:S:t:w:p:nexC",
|
||||||
["help", "count=", "server=", "quiet", "type=", "wait=", "asn", "port", "expert",
|
["help", "count=", "server=", "quiet", "type=", "wait=", "asn", "port", "expert",
|
||||||
"color"])
|
"color", "srcip="])
|
||||||
except getopt.GetoptError as err:
|
except getopt.GetoptError as err:
|
||||||
# print help information and exit:
|
# print help information and exit:
|
||||||
print(err) # will print something like "option -a not recognized"
|
print(err) # will print something like "option -a not recognized"
|
||||||
@ -269,6 +271,8 @@ def main():
|
|||||||
dnsserver = a
|
dnsserver = a
|
||||||
elif o in ("-q", "--quiet"):
|
elif o in ("-q", "--quiet"):
|
||||||
quiet = True
|
quiet = True
|
||||||
|
elif o in ("-S", "--srcip"):
|
||||||
|
src_ip = a
|
||||||
elif o in ("-w", "--wait"):
|
elif o in ("-w", "--wait"):
|
||||||
timeout = int(a)
|
timeout = int(a)
|
||||||
elif o in ("-t", "--type"):
|
elif o in ("-t", "--type"):
|
||||||
@ -301,6 +305,7 @@ def main():
|
|||||||
resolver = dns.resolver.Resolver()
|
resolver = dns.resolver.Resolver()
|
||||||
resolver.nameservers = [dnsserver]
|
resolver.nameservers = [dnsserver]
|
||||||
resolver.timeout = timeout
|
resolver.timeout = timeout
|
||||||
|
resolver.port = dest_port
|
||||||
resolver.lifetime = timeout
|
resolver.lifetime = timeout
|
||||||
resolver.retry_servfail = 0
|
resolver.retry_servfail = 0
|
||||||
|
|
||||||
@ -337,7 +342,7 @@ def main():
|
|||||||
|
|
||||||
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool: # dispatch dns lookup to another thread
|
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool: # dispatch dns lookup to another thread
|
||||||
stime = time.perf_counter()
|
stime = time.perf_counter()
|
||||||
thr = pool.submit(ping, resolver, hostname, dnsrecord, ttl, use_edns=use_edns)
|
thr = pool.submit(ping, resolver, hostname, dnsrecord, ttl, src_ip=src_ip, use_edns=use_edns)
|
||||||
|
|
||||||
try: # expect ICMP response
|
try: # expect ICMP response
|
||||||
_, curr_addr = icmp_socket.recvfrom(512)
|
_, curr_addr = icmp_socket.recvfrom(512)
|
||||||
@ -353,8 +358,8 @@ def main():
|
|||||||
|
|
||||||
if reached:
|
if reached:
|
||||||
curr_addr = dnsserver
|
curr_addr = dnsserver
|
||||||
stime = time.perf_counter() # need to recalculate elapsed time for last hop without waiting for an icmp error reply
|
stime = time.perf_counter() # need to recalculate elapsed time for last hop asynchronously
|
||||||
ping(resolver, hostname, dnsrecord, ttl, use_edns=use_edns)
|
ping(resolver, hostname, dnsrecord, ttl, src_ip=src_ip, use_edns=use_edns)
|
||||||
etime = time.perf_counter()
|
etime = time.perf_counter()
|
||||||
|
|
||||||
elapsed = abs(etime - stime) * 1000 # convert to milliseconds
|
elapsed = abs(etime - stime) * 1000 # convert to milliseconds
|
||||||
@ -387,13 +392,16 @@ def main():
|
|||||||
|
|
||||||
c = color.N # default
|
c = color.N # default
|
||||||
if curr_addr != '*':
|
if curr_addr != '*':
|
||||||
IP = ipaddress.ip_address(curr_addr)
|
try:
|
||||||
if IP.is_private:
|
IP = ipaddress.ip_address(curr_addr)
|
||||||
c = color.R
|
if IP.is_private:
|
||||||
if IP.is_reserved:
|
c = color.R
|
||||||
c = color.B
|
if IP.is_reserved:
|
||||||
if curr_addr == dnsserver:
|
c = color.B
|
||||||
c = color.G
|
if curr_addr == dnsserver:
|
||||||
|
c = color.G
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
print("%d\t%s (%s%s%s) %s%.3f ms" % (ttl, curr_name, c, curr_addr, color.N, as_name, elapsed), flush=True)
|
print("%d\t%s (%s%s%s) %s%.3f ms" % (ttl, curr_name, c, curr_addr, color.N, as_name, elapsed), flush=True)
|
||||||
trace_path.append(curr_addr)
|
trace_path.append(curr_addr)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user