mirror of
https://github.com/rscmbbng/Border-Check.git
synced 2024-12-28 06:41:34 +01:00
added feature to import traces from XML template, fixed some LFT subprocess errors on Unix based systems, more clean non-debug mode, added 'localhost' filter to target parser
This commit is contained in:
parent
1c8a3f799e
commit
a6c3115ca6
@ -2,9 +2,19 @@
|
||||
Changelog: Border-Check
|
||||
==============================
|
||||
|
||||
|
||||
=================
|
||||
October 4, 2013:
|
||||
=================
|
||||
|
||||
- added feature to import traces from XML template
|
||||
- fixed some LFT subprocess errors on Unix based systems
|
||||
- more clean non-debug mode
|
||||
- added 'localhost' filter to target parser
|
||||
|
||||
=================
|
||||
September 27, 2013:
|
||||
=================
|
||||
|
||||
- Public release: Border Check v0.1
|
||||
- public release: Border Check v0.1
|
||||
|
||||
|
@ -30,7 +30,11 @@ BC runs on OSx and Unix systems. It requires the following libraries/dependencie
|
||||
|
||||
sudo apt-get install python-pip
|
||||
|
||||
and then run pip install lxml and pip install pygeoip
|
||||
and then run:
|
||||
|
||||
pip install lxml
|
||||
|
||||
pip install pygeoip
|
||||
- biplist:
|
||||
|
||||
https://pypi.python.org/pypi/biplist/0.5
|
||||
|
@ -22,6 +22,7 @@ Options:
|
||||
-h, --help show this help message and exit
|
||||
-d, --debug debug mode
|
||||
--xml=EXPORT_XML export traces to xml (ex: --xml foo.xml)
|
||||
--load=IMPORT_XML import traces to show (ex: --load bar.xml)
|
||||
--bh=BROWSER_HISTORY set browser's history path
|
||||
-b BROWSER set browser manually: F = Firefox / C = Chrome / S = Safari / Ch = Chromium
|
||||
|
||||
@ -64,4 +65,8 @@ $ python bc --bh "Library/Safari/History.plist"
|
||||
|
||||
$ python bc --bh "Library/Safari/History.plist"
|
||||
-------------------
|
||||
* Import 'traces' from xml:
|
||||
|
||||
$ python bc --load "mytravel.xml"
|
||||
-------------------
|
||||
|
||||
|
183
main.py
183
main.py
@ -23,9 +23,6 @@ from webserver import BorderCheckWebserver
|
||||
from xml_exporter import xml_reporting
|
||||
import webbrowser
|
||||
|
||||
# set to emit debug messages about errors (0 = off).
|
||||
DEBUG = 1
|
||||
|
||||
class bc(object):
|
||||
"""
|
||||
BC main Class
|
||||
@ -96,17 +93,21 @@ class bc(object):
|
||||
try:
|
||||
return func(*args)
|
||||
except Exception as e:
|
||||
print("\n[Error] - Something wrong fetching urls. Aborting..."), "\n"
|
||||
if DEBUG:
|
||||
if not options.debug:
|
||||
print("[Error] - Something wrong happens!. Try to run again with --debug option to see more detailed information about the error on a Traceback output."), "\n"
|
||||
else:
|
||||
print("[Error] - Something wrong happens!. You have the reason at the end of the Traceback. If you don't understand what's happen, try to contact with project contributors."), "\n"
|
||||
if options.debug == 1:
|
||||
traceback.print_exc()
|
||||
sys.exit(2)
|
||||
print "" # \n after traceback ouput
|
||||
sys.exit(2)
|
||||
|
||||
def check_root(self):
|
||||
"""
|
||||
Check root permissions
|
||||
"""
|
||||
if not os.geteuid()==0:
|
||||
sys.exit("\nOnly root can run this script...\n")
|
||||
sys.exit("Warning: Only root can launch traceroutes. (Try: 'sudo ./bc')\n")
|
||||
|
||||
def check_browser(self):
|
||||
"""
|
||||
@ -384,7 +385,10 @@ class bc(object):
|
||||
print "Can't get Safari version information, you'll have to look it up manually \n"
|
||||
else:
|
||||
print "Version:", self.browser_version
|
||||
print "History:", self.browser_history_path, "\n"
|
||||
if self.options.import_xml: # history not needed on xml importing
|
||||
pass
|
||||
else:
|
||||
print "History:", self.browser_history_path, "\n"
|
||||
|
||||
def getURL(self):
|
||||
"""
|
||||
@ -429,6 +433,9 @@ class bc(object):
|
||||
"""
|
||||
Run an LFT
|
||||
"""
|
||||
# LFT needs root
|
||||
root = self.try_running(self.check_root, "\nInternal error checking root permissions.")
|
||||
|
||||
#try:
|
||||
if self.operating_system == 'darwin':
|
||||
try:
|
||||
@ -438,19 +445,19 @@ class bc(object):
|
||||
self.content = a.stdout.read()
|
||||
|
||||
if self.operating_system == 'linux':
|
||||
if self.method == '-e':
|
||||
if self.method == '-e': # tcp probes
|
||||
self.method = '-E'
|
||||
try:
|
||||
self.content = subprocess.check_output(['lft', '-S', '-n', self.destination_ip])
|
||||
self.content = subprocess.check_output(['lft', '-S', '-n', self.method, self.destination_ip])
|
||||
# support for older python versions (<2.75) that don't support subprocess.check_output
|
||||
except:
|
||||
a = subprocess.Popen(['lft', '-S', '-n', self.destination_ip], stdout=subprocess.PIPE)
|
||||
a = subprocess.Popen(['lft', '-S', '-n', self.method, self.destination_ip], stdout=subprocess.PIPE)
|
||||
self.content = a.stdout.read()
|
||||
self.attempts += 1
|
||||
if self.options.debug == True:
|
||||
print "Tracing:", self.destination_ip, "with method:", self.method, 'attempt:', self.attempts, '\n'
|
||||
self.lft_parse()
|
||||
|
||||
|
||||
def lft_parse(self):
|
||||
"""
|
||||
Parse the lft to see if it produced any results, if not, run another LFT using a different method
|
||||
@ -524,7 +531,7 @@ class bc(object):
|
||||
for ip in line:
|
||||
if re.match(r'\d{1,4}\.\dms$', ip):
|
||||
self.timestamp = ip.replace('ms', '')
|
||||
if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', ip) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', ip):
|
||||
if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', ip) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', ip) or re.match('localhost', ip):
|
||||
pass
|
||||
else:
|
||||
if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$",ip):
|
||||
@ -639,6 +646,45 @@ class bc(object):
|
||||
os.remove('GeoIPASNum.gz')
|
||||
print "Database: GeoIPASNum \n"
|
||||
|
||||
def importXML(self):
|
||||
"""
|
||||
Import travels data directly from XML file (no root needed) and launch a web browser on a thread with a map showing them.
|
||||
"""
|
||||
try:
|
||||
xml_results = xml_reporting(self)
|
||||
xml_imported = xml_results.read_xml_results() # read xml directly from file
|
||||
except:
|
||||
print("[Error] - Something wrong importing data from XML file. Aborting..."), "\n"
|
||||
sys.exit(2)
|
||||
|
||||
# Set the maxmind geo databases
|
||||
self.geoip = pygeoip.GeoIP('GeoLiteCity.dat')
|
||||
self.geoasn = pygeoip.GeoIP('GeoIPASNum.dat')
|
||||
match_ip = xml_imported[0].strip('http://').strip(':8080')
|
||||
#regex for filtering local network IPs
|
||||
if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', match_ip) or match_ip.startswith('file://') or match_ip.startswith('localhost'):
|
||||
print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
|
||||
print "URL:", self.options.import_xml, "\n"
|
||||
print "Warning: This target is not valid!.\n"
|
||||
sys.exit(2)
|
||||
else:
|
||||
if xml_imported[0].startswith('file://'):
|
||||
print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
|
||||
print "URL:", self.options.import_xml, "\n"
|
||||
print "Warning: This target is not valid!.\n"
|
||||
sys.exit(2)
|
||||
else:
|
||||
print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
|
||||
print "URL:", self.options.import_xml, "\n"
|
||||
print "Host:", xml_imported[0], "\n"
|
||||
os.system('cp -r ' + self.options.import_xml + ' data.xml') # copy XML data provided by user to data.xml template
|
||||
# start web mode (on a different thread)
|
||||
try:
|
||||
webbrowser.open('http://127.0.0.1:8080', new=1)
|
||||
BorderCheckWebserver(self)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
sys.exit()
|
||||
|
||||
def run(self, opts=None):
|
||||
"""
|
||||
Run BorderCheck
|
||||
@ -653,77 +699,78 @@ class bc(object):
|
||||
print('='*75)
|
||||
print(str(p.version))
|
||||
print('='*75)
|
||||
# root checker
|
||||
root = self.try_running(self.check_root, "\nInternal error checking root permissions.")
|
||||
# extract browser type and path
|
||||
browser = self.try_running(self.check_browser, "\nInternal error checking browser files path.")
|
||||
# extract url
|
||||
url = self.try_running(self.getURL, "\nInternal error getting urls from browser's database.")
|
||||
# set geoip database
|
||||
geo = self.try_running(self.getGEO, "\nInternal error setting geoIP database.")
|
||||
# run traceroutes
|
||||
match_ip = self.url[0].strip('http://').strip(':8080')
|
||||
#regex for filtering local network IPs
|
||||
if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', match_ip) or match_ip.startswith('file://'):
|
||||
print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
|
||||
print "URL:", self.url[0], "\n"
|
||||
print "Warning: This target is not valid!.\n"
|
||||
pass
|
||||
# read from XML or run traceroutes + stay latent mode
|
||||
if options.import_xml:
|
||||
import_xml = self.try_running(self.importXML, "\nInternal error importing XML data from file.")
|
||||
else:
|
||||
if self.url[0].startswith('file://'):
|
||||
match_ip = self.url[0].strip('http://').strip(':8080')
|
||||
#regex for filtering local network IPs
|
||||
if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', match_ip) or match_ip.startswith('file://') or match_ip.startswith('localhost'):
|
||||
print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
|
||||
print "URL:", self.url[0], "\n"
|
||||
print "Warning: This target is not valid!.\n"
|
||||
pass
|
||||
else:
|
||||
traces = self.try_running(self.traces, "\nInternal error tracerouting.")
|
||||
# start web mode (on a different thread)
|
||||
try:
|
||||
t = threading.Thread(target=BorderCheckWebserver, args=(self, ))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
time.sleep(2)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
t.join()
|
||||
sys.exit()
|
||||
# open same browser of history access on a new tab
|
||||
try:
|
||||
webbrowser.open('http://127.0.0.1:8080', new=1)
|
||||
except:
|
||||
print "Error: Browser is not responding correctly.\n"
|
||||
|
||||
print('='*75)
|
||||
print(str(p.version))
|
||||
print('='*75 + "\n")
|
||||
print "Status: Waiting for new urls ...\n"
|
||||
print "Type 'Control+C' to exit.\n"
|
||||
# stay latent waiting for new urls
|
||||
while True:
|
||||
url = urlparse(self.getURL()).netloc
|
||||
#url = url.replace('www.','')
|
||||
try:
|
||||
match_ip = url.strip('http://').strip(':8080')
|
||||
except:
|
||||
print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
|
||||
print "URL:", self.url[0], "\n"
|
||||
pass
|
||||
if url != self.old_url:
|
||||
if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', match_ip):
|
||||
if self.url[0].startswith('file://'):
|
||||
print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
|
||||
print "URL:", self.url[0], "\n"
|
||||
print "Warning: This target is not valid!.\n"
|
||||
pass
|
||||
else:
|
||||
if self.url[0].startswith('file://'):
|
||||
traces = self.try_running(self.traces, "\nInternal error tracerouting.")
|
||||
# start web mode (on a different thread)
|
||||
try:
|
||||
t = threading.Thread(target=BorderCheckWebserver, args=(self, ))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
time.sleep(2)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
t.join()
|
||||
sys.exit()
|
||||
# open same browser of history access on a new tab
|
||||
try:
|
||||
webbrowser.open('http://127.0.0.1:8080', new=1)
|
||||
except:
|
||||
print "Error: Browser is not responding correctly.\n"
|
||||
|
||||
print('='*75)
|
||||
print(str(p.version))
|
||||
print('='*75 + "\n")
|
||||
print "Status: Waiting for new urls ...\n"
|
||||
print "Type 'Control+C' to exit.\n"
|
||||
# stay latent waiting for new urls
|
||||
while True:
|
||||
url = urlparse(self.getURL()).netloc
|
||||
#url = url.replace('www.','')
|
||||
try:
|
||||
match_ip = url.strip('http://').strip(':8080')
|
||||
except:
|
||||
print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
|
||||
print "URL:", self.url[0], "\n"
|
||||
pass
|
||||
if url != self.old_url:
|
||||
if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', match_ip) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', match_ip) or match_ip.startswith('localhost'):
|
||||
pass
|
||||
else:
|
||||
if os.path.exists('data.xml'): # removing xml data to has a new map each time that bc is launched
|
||||
os.remove('data.xml')
|
||||
open('data.xml', 'w') # starting a new xml data container in write mode
|
||||
traces = self.try_running(self.traces, "\nInternal error tracerouting.")
|
||||
# open same browser of history access on a new tab
|
||||
# try:
|
||||
# webbrowser.open('http://127.0.0.1:8080', new=2) # open on same tab?
|
||||
# except:
|
||||
# print "Error: Browser is not responding correctly.\n"
|
||||
time.sleep(5) # free process time or goodbye :-)
|
||||
if self.url[0].startswith('file://'):
|
||||
pass
|
||||
else:
|
||||
if os.path.exists('data.xml'): # removing xml data to has a new map each time that bc is launched
|
||||
os.remove('data.xml')
|
||||
open('data.xml', 'w') # starting a new xml data container in write mode
|
||||
traces = self.try_running(self.traces, "\nInternal error tracerouting.")
|
||||
# open same browser of history access on a new tab
|
||||
# try:
|
||||
# webbrowser.open('http://127.0.0.1:8080', new=2) # open on same tab?
|
||||
# except:
|
||||
# print "Error: Browser is not responding correctly.\n"
|
||||
time.sleep(5) # free process time or goodbye :-)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = bc()
|
||||
|
@ -15,6 +15,7 @@ class BCOptions(optparse.OptionParser):
|
||||
|
||||
self.add_option("-d", "--debug", action="store_true", dest="debug", help="debug mode")
|
||||
self.add_option("--xml", action="store", dest="export_xml", help="export traces to xml (ex: --xml foo.xml)")
|
||||
self.add_option("--load", action="store", dest="import_xml", help="import traces to show (ex: --load bar.xml)")
|
||||
self.add_option("--bh", action="store", dest="browser_history", help="set browser's history path")
|
||||
self.add_option("-b", action="store", dest="browser", help="set browser manually: F = Firefox / C = Chrome / S = Safari / Ch = Chromium")
|
||||
#self.add_option("--proxy", action="store", dest="proxy", help="set proxy server")
|
||||
|
@ -4,8 +4,6 @@
|
||||
BC (Border-Check) is a tool to retrieve info of traceroute tests over website navigation routes.
|
||||
GPLv3 - 2013 by psy (epsylon@riseup.net)
|
||||
"""
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
class xml_reporting(object):
|
||||
"""
|
||||
Print results from a traceroute in an XML fashion
|
||||
@ -15,6 +13,7 @@ class xml_reporting(object):
|
||||
self.instance = bc
|
||||
|
||||
def print_xml_results(self, filename):
|
||||
import xml.etree.ElementTree as ET
|
||||
root = ET.Element("travel")
|
||||
i = 1
|
||||
for i in self.instance.result_list:
|
||||
@ -48,3 +47,37 @@ class xml_reporting(object):
|
||||
tree = ET.ElementTree(root)
|
||||
tree.write(filename)
|
||||
|
||||
def read_xml_results(self):
|
||||
from xml.dom.minidom import parseString
|
||||
file = open(self.instance.options.import_xml,'r')
|
||||
data = file.read()
|
||||
file.close()
|
||||
dom = parseString(data)
|
||||
travel_tag = dom.getElementsByTagName('travel')[0].toxml()
|
||||
travel_data = travel_tag.replace('<travel>','').replace('</travel>','').split('<')[0]
|
||||
hop_tag = dom.getElementsByTagName('hop')[0].toxml()
|
||||
hop_data = hop_tag.replace('<hop>','').replace('</hop>','')
|
||||
host_tag = dom.getElementsByTagName('host')[0].toxml()
|
||||
host_data = host_tag.replace('<host>','').replace('</host>','')
|
||||
hop_ip_tag = dom.getElementsByTagName('hop_ip')[0].toxml()
|
||||
hop_ip_data = hop_ip_tag.replace('<hop_ip>','').replace('</hop_ip>','')
|
||||
longitude_tag = dom.getElementsByTagName('longitude')[0].toxml()
|
||||
longitude_data = longitude_tag.replace('<longitude>','').replace('</longitude>','')
|
||||
latitude_tag = dom.getElementsByTagName('latitude')[0].toxml()
|
||||
latitude_data = hop_tag.replace('<latitude>','').replace('</latitude>','')
|
||||
city_tag = dom.getElementsByTagName('city')[0].toxml()
|
||||
city_data = city_tag.replace('<city>','').replace('</city>','')
|
||||
country_tag = dom.getElementsByTagName('country')[0].toxml()
|
||||
country_data = country_tag.replace('<country>','').replace('</country>','')
|
||||
server_name_tag = dom.getElementsByTagName('server_name')[0].toxml()
|
||||
server_name_data = server_name_tag.replace('<server_name>','').replace('</server_name>','')
|
||||
asn_tag = dom.getElementsByTagName('asn')[0].toxml()
|
||||
asn_data = asn_tag.replace('<asn>','').replace('</asn>','')
|
||||
timestamp_tag = dom.getElementsByTagName('timestamp')[0].toxml()
|
||||
timestamp_data = timestamp_tag.replace('<timestamp>','').replace('</timestamp>','')
|
||||
country_code_tag = dom.getElementsByTagName('country_code')[0].toxml()
|
||||
country_code_data = country_code_tag.replace('<country_code>','').replace('</country_code>','')
|
||||
meta_tag = dom.getElementsByTagName('meta')[0].toxml()
|
||||
meta_data = meta_tag.replace('<meta>','').replace('</meta>','')
|
||||
|
||||
return travel_data, hop_data, hop_ip_data, longitude_data, latitude_data, city_data, country_data, server_name_data, asn_data, timestamp_data, country_code_data, meta_data
|
||||
|
Loading…
Reference in New Issue
Block a user