pep8 and pylint clean-up
This commit is contained in:
parent
0700e76a2e
commit
4ad54e9e56
1 changed files with 182 additions and 158 deletions
330
traceroute.py
330
traceroute.py
|
|
@ -1,34 +1,54 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# traceroute.py - Multi-source traceroute with geolocation information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013 Addy Yeow Chin Heng <ayeowch@gmail.com>
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
traceroute - Get traceroute results with associated geolocation information
|
Multi-source traceroute with geolocation information.
|
||||||
for each hop for a specified host from geographically distant source(s).
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = 'Dazzlepod (info@dazzlepod.com)'
|
|
||||||
__copyright__ = 'Copyright (c) 2013 Dazzlepod'
|
|
||||||
__version__ = '$Revision: #20 $'
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import signal
|
import signal
|
||||||
import socket
|
|
||||||
import sys
|
import sys
|
||||||
import urllib
|
import urllib
|
||||||
import urllib2
|
import urllib2
|
||||||
from multiprocessing import Process
|
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
USER_AGENT = "traceroute/1.0 (+https://github.com/ayeowch/traceroute)"
|
||||||
|
|
||||||
|
|
||||||
class Traceroute(object):
|
class Traceroute(object):
|
||||||
"""Traceroute instance."""
|
"""
|
||||||
def __init__(self, ip_address='8.8.8.8', country='US', tmp_dir='/tmp', no_geo=False, timeout=120, debug=False):
|
Multi-source traceroute instance.
|
||||||
|
"""
|
||||||
|
def __init__(self, ip_address="8.8.8.8", country="US", tmp_dir="/tmp",
|
||||||
|
no_geo=False, timeout=120, debug=False):
|
||||||
super(Traceroute, self).__init__()
|
super(Traceroute, self).__init__()
|
||||||
|
|
||||||
self.ip_address = ip_address
|
self.ip_address = ip_address
|
||||||
self.country = country
|
self.country = country
|
||||||
self.tmp_dir = tmp_dir
|
self.tmp_dir = tmp_dir
|
||||||
|
|
@ -38,124 +58,133 @@ class Traceroute(object):
|
||||||
|
|
||||||
# Traceroute servers from traceroute.org
|
# Traceroute servers from traceroute.org
|
||||||
sources = {
|
sources = {
|
||||||
# 'LO' for localhost in which case 'url' will be used as the command to execute traceroute locally
|
|
||||||
'LO': {
|
'LO': {
|
||||||
'url': 'traceroute %s' % self.ip_address,
|
'url': "traceroute {}".format(ip_address),
|
||||||
'post_data': None,
|
|
||||||
},
|
},
|
||||||
'BY': {
|
'BY': {
|
||||||
'url': 'http://by104.activeby.net/lg/',
|
'url': "http://by104.activeby.net/lg/",
|
||||||
'post_data': {'method': 'trace', 'host': self.ip_address, 'router': 'http://by104.activeby.net/lg/'}
|
'post_data': {
|
||||||
|
'method': "trace",
|
||||||
|
'host': ip_address,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'CH': {
|
'CH': {
|
||||||
'url': 'http://www.switch.ch/cgi-bin/network/nph-traceroute-opencms?destination=%s' % self.ip_address,
|
'url': ("http://www.switch.ch/cgi-bin/network/nph-traceroute"
|
||||||
'post_data': None,
|
"-opencms?destination={}".format(ip_address)),
|
||||||
},
|
},
|
||||||
'JP': {
|
'JP': {
|
||||||
'url': 'http://www.harenet.ad.jp/cgi-bin/harenet/traceroute/traceroute.cgi',
|
'url': ("http://www.harenet.ad.jp/cgi-bin/harenet/traceroute/"
|
||||||
'post_data': {'host': self.ip_address},
|
"traceroute.cgi"),
|
||||||
|
'post_data': {
|
||||||
|
'host': ip_address,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'RU': {
|
'RU': {
|
||||||
'url': 'http://ipnoc.zenon.net/pcgi/trace.pl?IP=%s' % self.ip_address,
|
'url': "http://traceroute.rusnet.ru/?{}".format(ip_address)
|
||||||
'post_data': None
|
|
||||||
},
|
},
|
||||||
'UK': {
|
'UK': {
|
||||||
'url': 'http://ab.newnet.co.uk/cgi-bin/traceroute?%s' % self.ip_address,
|
'url': ("http://ab.newnet.co.uk/cgi-bin/traceroute?{}".format(
|
||||||
'post_data': None
|
ip_address)),
|
||||||
},
|
},
|
||||||
'US': {
|
'US': {
|
||||||
'url': 'http://www.net.princeton.edu/cgi-bin/traceroute.pl',
|
'url': "http://www.net.princeton.edu/cgi-bin/traceroute.pl",
|
||||||
'post_data': {'target': self.ip_address},
|
'post_data': {
|
||||||
|
'target': ip_address,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.source = sources[self.country]
|
self.source = sources[self.country]
|
||||||
|
self.locations = {} # Geo-coded locations
|
||||||
# cache geocoded IP addresses during the lifetime of this instance
|
|
||||||
self.locations = {}
|
|
||||||
|
|
||||||
def traceroute(self):
|
def traceroute(self):
|
||||||
"""Instead of running the actual traceroute command, we will fetch
|
"""
|
||||||
|
Instead of running the actual traceroute command, we will fetch
|
||||||
standard traceroute results from several publicly available webpages
|
standard traceroute results from several publicly available webpages
|
||||||
that are listed at traceroute.org. For each hop, we will then attach
|
that are listed at traceroute.org. For each hop, we will then attach
|
||||||
geolocation information to it."""
|
geolocation information to it.
|
||||||
self.print_debug("ip_address = %s" % self.ip_address)
|
"""
|
||||||
txt = os.path.join(self.tmp_dir, '%s.%s.txt' % (self.ip_address, self.country))
|
self.print_debug("ip_address={}".format(self.ip_address))
|
||||||
if not os.path.exists(txt):
|
|
||||||
if self.country == 'LO':
|
|
||||||
(status_code, traceroute) = self.execute_cmd(self.source['url'])
|
|
||||||
else:
|
|
||||||
(status_code, traceroute) = self.get_traceroute_output()
|
|
||||||
|
|
||||||
|
filename = "{}.{}.txt".format(self.ip_address, self.country)
|
||||||
|
filepath = os.path.join(self.tmp_dir, filename)
|
||||||
|
|
||||||
|
if not os.path.exists(filepath):
|
||||||
|
if self.country == "LO":
|
||||||
|
status_code, traceroute = self.execute_cmd(self.source['url'])
|
||||||
|
else:
|
||||||
|
status_code, traceroute = self.get_traceroute_output()
|
||||||
if status_code != 0 and status_code != 200:
|
if status_code != 0 and status_code != 200:
|
||||||
return {'error': status_code}
|
return {'error': status_code}
|
||||||
|
open(filepath, "w").write(traceroute)
|
||||||
|
traceroute = open(filepath, "r").read()
|
||||||
|
|
||||||
f = open(txt, 'w')
|
# hop_num, hosts
|
||||||
f.write(traceroute)
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
traceroute = open(txt, 'r').read()
|
|
||||||
|
|
||||||
# hops = dicts with keys: hop_num, hosts
|
|
||||||
hops = self.get_hops(traceroute)
|
hops = self.get_hops(traceroute)
|
||||||
|
|
||||||
# hops = dicts with keys: hop_num, hostname, ip_address, rtt
|
# hop_num, hostname, ip_address, rtt
|
||||||
hops = self.get_formatted_hops(hops)
|
hops = self.get_formatted_hops(hops)
|
||||||
|
|
||||||
if not self.no_geo:
|
if not self.no_geo:
|
||||||
# hops = dicts with keys: hop_num, hostname, ip_address, rtt, latitude, longitude
|
# hop_num, hostname, ip_address, rtt, latitude, longitude
|
||||||
hops = self.get_geocoded_hops(hops)
|
hops = self.get_geocoded_hops(hops)
|
||||||
|
|
||||||
return hops
|
return hops
|
||||||
|
|
||||||
def get_traceroute_output(self):
|
def get_traceroute_output(self):
|
||||||
"""Fetch traceroute output from a webpage."""
|
"""
|
||||||
|
Fetches traceroute output from a webpage.
|
||||||
|
"""
|
||||||
url = self.source['url']
|
url = self.source['url']
|
||||||
(status_code, content) = self.urlopen(url, context = self.source['post_data'])
|
if 'post_data' in self.source:
|
||||||
|
context = self.source['post_data']
|
||||||
|
else:
|
||||||
|
context = None
|
||||||
|
status_code, content = self.urlopen(url, context=context)
|
||||||
content = content.strip()
|
content = content.strip()
|
||||||
|
regex = r'<pre.*?>(?P<traceroute>.*?)</pre>'
|
||||||
pattern = re.compile(r'<pre.*?>(?P<traceroute>.*?)</pre>', re.DOTALL|re.IGNORECASE)
|
pattern = re.compile(regex, re.DOTALL | re.IGNORECASE)
|
||||||
try:
|
try:
|
||||||
traceroute = re.findall(pattern, content)[0].strip()
|
traceroute = re.findall(pattern, content)[0].strip()
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# Manually append closing </pre> for partially downloaded page
|
# Manually append closing </pre> for partially downloaded page
|
||||||
content = '%s</pre>' % content
|
content = "{}</pre>".format(content)
|
||||||
traceroute = re.findall(pattern, content)[0].strip()
|
traceroute = re.findall(pattern, content)[0].strip()
|
||||||
|
|
||||||
return (status_code, traceroute)
|
return (status_code, traceroute)
|
||||||
|
|
||||||
def get_hops(self, traceroute):
|
def get_hops(self, traceroute):
|
||||||
"""Get hops from a traceroute output and return the hops in an array
|
"""
|
||||||
of dicts each representing hop number and the associated hosts data."""
|
Returns hops from traceroute output in an array of dicts each
|
||||||
|
with hop number and the associated hosts data.
|
||||||
|
"""
|
||||||
hops = []
|
hops = []
|
||||||
|
regex = r'^(?P<hop_num>\d+)(?P<hosts>.*?)$'
|
||||||
lines = traceroute.split('\n')
|
lines = traceroute.split("\n")
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
hop = {}
|
hop = {}
|
||||||
if not line: continue
|
if not line:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
hop = re.match(r'^(?P<hop_num>\d+)(?P<hosts>.*?)$', line).groupdict()
|
hop = re.match(regex, line).groupdict()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
continue
|
continue
|
||||||
self.print_debug(hop)
|
self.print_debug(hop)
|
||||||
hops.append(hop)
|
hops.append(hop)
|
||||||
|
|
||||||
return hops
|
return hops
|
||||||
|
|
||||||
def get_formatted_hops(self, hops):
|
def get_formatted_hops(self, hops):
|
||||||
"""hosts data from get_hops() is represented in a single string.
|
"""
|
||||||
We use this function to better represent the hosts data in a dict."""
|
Hosts data from get_hops() is represented in a single string.
|
||||||
|
We use this function to better represent the hosts data in a dict.
|
||||||
|
"""
|
||||||
formatted_hops = []
|
formatted_hops = []
|
||||||
|
regex = r'(?P<h>[\w.-]+) \((?P<i>[\d.]+)\) (?P<r>\d{1,4}.\d{1,4} ms)'
|
||||||
for hop in hops:
|
for hop in hops:
|
||||||
hop_num = int(hop['hop_num'].strip())
|
hop_num = int(hop['hop_num'].strip())
|
||||||
hosts = hop['hosts'].replace(' ', ' ').strip()
|
hosts = hop['hosts'].replace(" ", " ").strip()
|
||||||
|
# Using re.findall(), we split the hosts, then for each host,
|
||||||
# Using re.findall(), first we split the hosts, then for each host we store a tuple containing hostname, IP address and the first round-trip time
|
# we store a tuple of hostname, IP address and the first RTT.
|
||||||
# [('<HOSTNAME>', '<IP_ADDRESS>', '<RTT1> ms'), ('<HOSTNAME_N>', '<IP_ADDRESS_N>', '<RTT1_N> ms')]
|
hosts = re.findall(regex, hosts)
|
||||||
hosts = re.findall(r'(?P<hostname>[\w.-]+) \((?P<ip_address>[\d.]+)\) (?P<rtt>\d{1,4}.\d{1,4} ms)', hosts)
|
|
||||||
|
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
hop_context = {
|
hop_context = {
|
||||||
'hop_num': hop_num,
|
'hop_num': hop_num,
|
||||||
|
|
@ -165,24 +194,22 @@ class Traceroute(object):
|
||||||
}
|
}
|
||||||
self.print_debug(hop_context)
|
self.print_debug(hop_context)
|
||||||
formatted_hops.append(hop_context)
|
formatted_hops.append(hop_context)
|
||||||
|
|
||||||
return formatted_hops
|
return formatted_hops
|
||||||
|
|
||||||
def get_geocoded_hops(self, hops):
|
def get_geocoded_hops(self, hops):
|
||||||
"""Return hops from get_formatted_hops() with geolocation information
|
"""
|
||||||
for each hop."""
|
Returns hops from get_formatted_hops() with geolocation information
|
||||||
|
for each hop.
|
||||||
|
"""
|
||||||
geocoded_hops = []
|
geocoded_hops = []
|
||||||
|
|
||||||
for hop in hops:
|
for hop in hops:
|
||||||
ip_address = hop['ip_address']
|
ip_address = hop['ip_address']
|
||||||
|
|
||||||
location = None
|
location = None
|
||||||
if self.locations.has_key(ip_address):
|
if ip_address in self.locations:
|
||||||
location = self.locations[ip_address]
|
location = self.locations[ip_address]
|
||||||
else:
|
else:
|
||||||
location = self.get_location(ip_address)
|
location = self.get_location(ip_address)
|
||||||
self.locations[ip_address] = location
|
self.locations[ip_address] = location
|
||||||
|
|
||||||
if location:
|
if location:
|
||||||
geocoded_hops.append({
|
geocoded_hops.append({
|
||||||
'hop_num': hop['hop_num'],
|
'hop_num': hop['hop_num'],
|
||||||
|
|
@ -192,127 +219,126 @@ class Traceroute(object):
|
||||||
'latitude': location['latitude'],
|
'latitude': location['latitude'],
|
||||||
'longitude': location['longitude'],
|
'longitude': location['longitude'],
|
||||||
})
|
})
|
||||||
|
|
||||||
return geocoded_hops
|
return geocoded_hops
|
||||||
|
|
||||||
def get_location(self, ip_address):
|
def get_location(self, ip_address):
|
||||||
"""Return geolocation information for the specified IP address, e.g.:
|
"""
|
||||||
{"ip": "75.126.24.77",
|
Returns geolocation information for the given IP address.
|
||||||
"hostname": "web365.webfaction.com",
|
|
||||||
"isp": "SoftLayer Technologies",
|
|
||||||
"organization": "Client Intellect",
|
|
||||||
"country": "United States",
|
|
||||||
"region": "Texas",
|
|
||||||
"city": "Dallas",
|
|
||||||
"latitude": 32.9299,
|
|
||||||
"longitude": -96.8353}
|
|
||||||
"""
|
"""
|
||||||
location = None
|
location = None
|
||||||
url = "http://dazzlepod.com/ip/%s.json" % ip_address
|
url = "http://dazzlepod.com/ip/{}.json".format(ip_address)
|
||||||
(status_code, json_data) = self.urlopen(url)
|
status_code, json_data = self.urlopen(url)
|
||||||
if status_code == 200 and json_data:
|
if status_code == 200 and json_data:
|
||||||
tmp_location = json.loads(json_data)
|
tmp_location = json.loads(json_data)
|
||||||
if tmp_location.has_key('latitude') and tmp_location.has_key('longitude'):
|
if 'latitude' in tmp_location and 'longitude' in tmp_location:
|
||||||
location = tmp_location
|
location = tmp_location
|
||||||
return location
|
return location
|
||||||
|
|
||||||
def execute_cmd(self, cmd):
|
def execute_cmd(self, cmd):
|
||||||
"""Execute the specified command locally and return the resultant
|
"""
|
||||||
return code and output."""
|
Executes given command using subprocess.Popen().
|
||||||
stdout = ''
|
"""
|
||||||
|
stdout = ""
|
||||||
returncode = -1
|
returncode = -1
|
||||||
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
process = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||||
try:
|
try:
|
||||||
signal.signal(signal.SIGALRM, self.signal_handler)
|
signal.signal(signal.SIGALRM, self.signal_handler)
|
||||||
signal.alarm(self.timeout)
|
signal.alarm(self.timeout)
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = process.communicate()
|
||||||
returncode = p.returncode
|
returncode = process.returncode
|
||||||
self.print_debug("cmd = %s, returncode = %d" % (cmd, returncode))
|
self.print_debug("cmd={}, returncode={}".format(cmd, returncode))
|
||||||
|
if returncode != 0:
|
||||||
|
self.print_debug("stderr={}".format(stderr))
|
||||||
signal.alarm(0)
|
signal.alarm(0)
|
||||||
except Exception, e:
|
except Exception as err:
|
||||||
self.print_debug("%s" % str(e))
|
self.print_debug(str(err))
|
||||||
return (returncode, stdout)
|
return (returncode, stdout)
|
||||||
|
|
||||||
def urlopen(self, url, context=None):
|
def urlopen(self, url, context=None):
|
||||||
"""Perform HTTP GET/POST on the specified URL and return the resultant
|
"""
|
||||||
status code and response."""
|
Fetches webpage.
|
||||||
|
"""
|
||||||
status_code = 200
|
status_code = 200
|
||||||
request = urllib2.Request(url = url)
|
request = urllib2.Request(url=url)
|
||||||
request.add_header('User-Agent', 'traceroute/1.0 (+https://github.com/ayeowch/traceroute')
|
request.add_header('User-Agent', USER_AGENT)
|
||||||
|
|
||||||
if context:
|
if context:
|
||||||
data = urllib.urlencode(context)
|
data = urllib.urlencode(context)
|
||||||
request.add_data(data)
|
request.add_data(data)
|
||||||
|
content = ""
|
||||||
content = ''
|
|
||||||
try:
|
try:
|
||||||
response = urllib2.urlopen(request)
|
response = urllib2.urlopen(request)
|
||||||
self.print_debug("url = %s\nheader = %s" % (response.geturl(), response.info()))
|
self.print_debug("url={}".format(response.geturl()))
|
||||||
content = self.chunked_read(response)
|
content = self.chunked_read(response)
|
||||||
except urllib2.HTTPError, e:
|
except urllib2.HTTPError as err:
|
||||||
status_code = e.code
|
status_code = err.code
|
||||||
except urllib2.URLError:
|
except urllib2.URLError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
|
||||||
self.urlopen_count += 1
|
|
||||||
except AttributeError:
|
|
||||||
self.urlopen_count = 1
|
|
||||||
self.print_debug("[%d] url = %s, status_code = %d" % (self.urlopen_count, url, status_code))
|
|
||||||
|
|
||||||
return (status_code, content)
|
return (status_code, content)
|
||||||
|
|
||||||
def chunked_read(self, response):
|
def chunked_read(self, response):
|
||||||
"""Read page response in chunks. A signal handler is attached to abort
|
|
||||||
reading after the set timeout.
|
|
||||||
Chunk size = 64 bytes, max. page size = 1MB
|
|
||||||
"""
|
"""
|
||||||
content = ''
|
Fetches response in chunks. A signal handler is attached to abort
|
||||||
max_bytes = 1 * 1024 * 1024
|
reading after set timeout.
|
||||||
completed_bytes = 0
|
"""
|
||||||
bytes_per_read = 64
|
content = ""
|
||||||
|
max_bytes = 1 * 1024 * 1024 # Max. page size = 1MB
|
||||||
|
read_bytes = 0
|
||||||
|
bytes_per_read = 64 # Chunk size = 64 bytes
|
||||||
try:
|
try:
|
||||||
signal.signal(signal.SIGALRM, self.signal_handler)
|
signal.signal(signal.SIGALRM, self.signal_handler)
|
||||||
signal.alarm(self.timeout)
|
signal.alarm(self.timeout)
|
||||||
while completed_bytes <= max_bytes:
|
while read_bytes <= max_bytes:
|
||||||
data = response.read(bytes_per_read)
|
data = response.read(bytes_per_read)
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
content += data
|
content += data
|
||||||
completed_bytes += bytes_per_read
|
read_bytes += bytes_per_read
|
||||||
self.print_debug("completed_bytes = %d, %s" % (completed_bytes, data))
|
self.print_debug("read_bytes={}, {}".format(read_bytes, data))
|
||||||
signal.alarm(0)
|
signal.alarm(0)
|
||||||
except Exception, e:
|
except Exception as err:
|
||||||
self.print_debug("%s" % str(e))
|
self.print_debug(str(err))
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
def signal_handler(self, signum, frame):
|
def signal_handler(self, signum):
|
||||||
"""Signal handler that simply raises an exception when triggered."""
|
"""
|
||||||
raise Exception("Caught signal %d" % signum)
|
Raises exception when signal is caught.
|
||||||
|
"""
|
||||||
|
raise Exception("Caught signal {}".format(signum))
|
||||||
|
|
||||||
def print_debug(self, msg):
|
def print_debug(self, msg):
|
||||||
"""Print debug message to standard output."""
|
"""
|
||||||
|
Prints debug message to standard output.
|
||||||
|
"""
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print "[DEBUG %s] %s" % (datetime.datetime.now(), msg)
|
print("[DEBUG {}] {}".format(datetime.datetime.now(), msg))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
usage = """%prog --ip_address=IP_ADDRESS"""
|
cmdparser = optparse.OptionParser("%prog --ip_address=IP_ADDRESS")
|
||||||
cmdparser = optparse.OptionParser(usage, version=("traceroute " + __version__))
|
cmdparser.add_option(
|
||||||
cmdparser.add_option("-i", "--ip_address", type="string", default="8.8.8.8", help="IP address of destination host (default: 8.8.8.8)")
|
"-i", "--ip_address", type="string", default="8.8.8.8",
|
||||||
cmdparser.add_option("-c", "--country", type="choice",
|
help="IP address of destination host (default: 8.8.8.8)")
|
||||||
choices=['LO', 'BY', 'CH', 'JP', 'RU', 'UK', 'US',],
|
cmdparser.add_option(
|
||||||
default="US",
|
"-c", "--country", type="choice", default="US",
|
||||||
help="Traceroute will be initiated from this country; choose 'LO' for localhost to run traceroute locally, 'BY' for Belarus, 'CH' for Switzerland, 'JP' for Japan, 'RU' for Russia, 'UK' for United Kingdom or 'US' for United States (default: US)")
|
choices=["LO", "BY", "CH", "JP", "RU", "UK", "US"],
|
||||||
cmdparser.add_option("-t", "--tmp_dir", type="string", default="/tmp", help="Temporary directory to store downloaded traceroute results (default: /tmp)")
|
help=("Traceroute will be initiated from this country; choose 'LO' "
|
||||||
cmdparser.add_option("-n", "--no_geo", action="store_true", default=False, help="No geolocation data (default: False)")
|
"for localhost to run traceroute locally, 'BY' for Belarus, "
|
||||||
cmdparser.add_option("-s", "--timeout", type="int", default=120, help="Timeout in seconds for all downloads (default: 120)")
|
"'CH' for Switzerland, 'JP' for Japan, 'RU' for Russia, 'UK' "
|
||||||
cmdparser.add_option("-d", "--debug", action="store_true", default=False, help="Show debug output (default: False)")
|
"for United Kingdom or 'US' for United States (default: US)"))
|
||||||
|
cmdparser.add_option(
|
||||||
(options, args) = cmdparser.parse_args()
|
"-t", "--tmp_dir", type="string", default="/tmp",
|
||||||
|
help=("Temporary directory to store downloaded traceroute results "
|
||||||
|
"(default: /tmp)"))
|
||||||
|
cmdparser.add_option(
|
||||||
|
"-n", "--no_geo", action="store_true", default=False,
|
||||||
|
help="No geolocation data (default: False)")
|
||||||
|
cmdparser.add_option(
|
||||||
|
"-s", "--timeout", type="int", default=120,
|
||||||
|
help="Timeout in seconds for all downloads (default: 120)")
|
||||||
|
cmdparser.add_option(
|
||||||
|
"-d", "--debug", action="store_true", default=False,
|
||||||
|
help="Show debug output (default: False)")
|
||||||
|
options, _ = cmdparser.parse_args()
|
||||||
if options.ip_address:
|
if options.ip_address:
|
||||||
traceroute = Traceroute(ip_address=options.ip_address,
|
traceroute = Traceroute(ip_address=options.ip_address,
|
||||||
country=options.country,
|
country=options.country,
|
||||||
|
|
@ -321,11 +347,9 @@ def main():
|
||||||
timeout=options.timeout,
|
timeout=options.timeout,
|
||||||
debug=options.debug)
|
debug=options.debug)
|
||||||
hops = traceroute.traceroute()
|
hops = traceroute.traceroute()
|
||||||
hops = json.dumps(hops, indent=4)
|
print(json.dumps(hops, indent=4))
|
||||||
print hops
|
|
||||||
else:
|
else:
|
||||||
cmdparser.print_usage()
|
cmdparser.print_usage()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue