Fix traceroute

This commit is contained in:
Itay Mizeretz 2018-11-11 17:13:30 +02:00
parent 9812dcd77d
commit f79629819e
1 changed files with 76 additions and 51 deletions

View File

@ -5,12 +5,11 @@ import select
import socket import socket
import struct import struct
import time import time
import re
from six import text_type
import ipaddress
DEFAULT_TIMEOUT = 10 DEFAULT_TIMEOUT = 10
BANNER_READ = 1024 BANNER_READ = 1024
IP_ADDR_RE = r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
SLEEP_BETWEEN_POLL = 0.5 SLEEP_BETWEEN_POLL = 0.5
@ -176,56 +175,82 @@ def tcp_port_to_service(port):
def traceroute(target_ip, ttl): def traceroute(target_ip, ttl):
""" """
Traceroute for a specific IP. Traceroute for a specific IP/name.
:param target_ip: Destination :param target_ip: IP/name of target
:param ttl: Max TTL :param ttl: Max TTL
:return: Sequence of IPs in the way :return: Sequence of IPs in the way
""" """
if sys.platform == "win32": if sys.platform == "win32":
try: return _traceroute_windows(target_ip, ttl)
# we'll just use tracert because that's always there
cli = ["tracert",
"-d",
"-w", "250",
"-h", str(ttl),
target_ip]
proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE)
stdout, stderr = proc_obj.communicate()
ip_lines = stdout.split('\r\n')[3:-3]
trace_list = []
for line in ip_lines:
tokens = line.split()
last_token = tokens[-1]
try:
ip_addr = ipaddress.ip_address(text_type(last_token))
except ValueError:
ip_addr = ""
trace_list.append(ip_addr)
return trace_list
except:
return []
else: # linux based hopefully else: # linux based hopefully
# implementation note: We're currently going to just use ping. return _traceroute_linux(target_ip, ttl)
# reason is, implementing a non root requiring user is complicated (see traceroute(8) code)
# while this is just ugly
# we can't use traceroute because it's not always installed def _traceroute_windows(target_ip, ttl):
current_ttl = 1 """
trace_list = [] Traceroute for a specific IP/name - Windows implementation
while current_ttl <= ttl: """
try: # we'll just use tracert because that's always there
cli = ["ping", cli = ["tracert",
"-c", "1", "-d",
"-w", "1", "-w", "250",
"-t", str(current_ttl), "-h", str(ttl),
target_ip] target_ip]
proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE) proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE)
stdout, stderr = proc_obj.communicate() stdout, stderr = proc_obj.communicate()
ip_line = stdout.split('\n') ip_lines = stdout.split('\r\n')
ip_line = ip_line[1] trace_list = []
ip = ip_line.split()[1]
trace_list.append(ipaddress.ip_address(text_type(ip))) first_line_index = None
except (IndexError, ValueError): for i in range(len(ip_lines)):
# assume we failed parsing output if re.search(r'^\s*1', ip_lines[i]) is not None:
trace_list.append("") first_line_index = i
current_ttl += 1 break
return trace_list
for i in range(first_line_index, first_line_index + ttl):
if re.search(r'^\s*' + str(i - first_line_index + 1), ip_lines[i]) is None: # If trace is finished
break
re_res = re.search(IP_ADDR_RE, ip_lines[i])
if re_res is None:
ip_addr = None
else:
ip_addr = re_res.group()
trace_list.append(ip_addr)
return trace_list
def _traceroute_linux(target_ip, ttl):
"""
Traceroute for a specific IP/name - Linux implementation
"""
# implementation note: We're currently going to just use ping.
# reason is, implementing a non root requiring user is complicated (see traceroute(8) code)
# while this is just ugly
# we can't use traceroute because it's not always installed
current_ttl = 1
trace_list = []
while current_ttl <= ttl:
cli = ["ping",
"-c", "1",
"-w", "1",
"-t", str(current_ttl),
target_ip]
proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE)
stdout, stderr = proc_obj.communicate()
ips = re.findall(IP_ADDR_RE, stdout)
if len(ips) < 2:
raise Exception("Unexpected output")
elif ips[-1] in trace_list: # Failed getting this hop
trace_list.append(None)
else:
trace_list.append(ips[-1])
dest_ip = ips[0] # first ip is dest ip. must be parsed here since it can change between pings
if dest_ip == ips[-1]:
break
current_ttl += 1
return trace_list