main.py 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. #!/usr/bin/env python2
  2. # -*- coding: iso-8859-15 -*-
  3. """
  4. BC (Border-Check) is a tool to retrieve info of traceroute tests over website navigation routes.
  5. GPLv3 - 2013-2014-2015 by psy (epsylon@riseup.net)
  6. """
  7. import os, sys, time, re, traceback
  8. from urlparse import urlparse
  9. try:
  10. import pygeoip
  11. except:
  12. print "\nError importing: pygeoip lib. \n\n On Debian based systems:\n\n $ apt-get install python-pip and $ pip install pygeoip \n"
  13. sys.exit(2)
  14. try:
  15. import sqlite3
  16. except: #this should be a standard package of python 2.5+
  17. print "\nError importing: sqlite3 lib. \n\nOn Debian based systems, please try like root:\n\n $ apt-get install sqlite3\n"
  18. sys.exit(2)
  19. import subprocess, socket, threading
  20. import shlex, getpass, urllib
  21. from options import BCOptions
  22. from webserver import BorderCheckWebserver
  23. from xml_exporter import xml_reporting
  24. import webbrowser
  25. class bc(object):
  26. """
  27. BC main Class
  28. """
  29. def __init__(self):
  30. """
  31. Init defaults
  32. """
  33. # Global variables organised by the function in which they first occur.
  34. # check_browser():
  35. self.operating_system = '' #The operating system being used. Either darwin/linux
  36. self.browser = "N" # "F" Firefox / "C" Chrome / "S" Safari / "CHROMIUM" Chromium / "None"
  37. self.browser_path = "" #the path to the browser application
  38. self.browser_history_path = "" # the path to the browser history file
  39. self.browser_version = "" # the version of the browser
  40. # lft():
  41. self.content = '' # the un-parsed results of a traceroute
  42. self.attempts = 0 # the number of attempts at a traceroute
  43. self.method = '-e' # the tracing method, -e to use TCP packets, -u for UDP packets
  44. # traces():
  45. self.url = "" # the last visited url from the history file, type is tuple
  46. self.old_url = "" # the before last url from the history file
  47. self.destination_ip = "" #the ip adress of self.url
  48. self.hop_ip = "" #the ip of the servers/router on a hop
  49. self.timestamp = "1" #the time it took to go to a hop in miliseconds.
  50. # these variables are all the result of Maxmind DB lookups
  51. self.longitude = "" # the lat/long that corresponds the an ip as per Maxmind DB
  52. self.latitude = "" # idem
  53. self.asn = '' #ASN number of a server
  54. self.hop_host_name = "" #hostname of server/router on a hop
  55. self.city = "" #
  56. self.country = "" #
  57. self.server_name = "" # same as self.hop_host_name. perhaps good to clean this.
  58. self.hop_count = 1 # number of the current hop in a trace
  59. self.result_list = [] #list to collect all the variables of a trace
  60. self.vardict ={} #dict to store all the variables of a hop
  61. self.last_travel = time.time()
  62. self.new_travel = False
  63. if os.path.exists('data.xml'): # removing xml data to has a new map each time that bc is launched
  64. os.remove('data.xml')
  65. open('data.xml', 'w') # starting a new xml data container in write mode
  66. def set_options(self, options):
  67. """
  68. Set program options
  69. """
  70. self.options = options
  71. def create_options(self, args=None):
  72. """
  73. Create options for OptionParser
  74. """
  75. self.optionParser = BCOptions()
  76. self.options = self.optionParser.get_options(args)
  77. if not self.options:
  78. return False
  79. return self.options
  80. def try_running(self, func, error, args=None):
  81. """
  82. Try running a function and print some error if it fails and exists with a fatal error.
  83. """
  84. options = self.options
  85. args = args or []
  86. try:
  87. return func(*args)
  88. except Exception as e:
  89. if not options.debug:
  90. print("[Error] - Something went wrong! Try to run again with the '--debug' argument for more info via the a traceback output."), "\n"
  91. else:
  92. print("[Error] - Something went wrong! Have a look the traceback."), "\n"
  93. if options.debug == 1:
  94. traceback.print_exc()
  95. print "" # \n after traceback ouput
  96. sys.exit(2)
  97. def check_root(self):
  98. """
  99. Check root permissions
  100. """
  101. if not os.geteuid()==0:
  102. sys.exit("Error: You need more permissions to make traceroutes. Try to launch BC as root (ex: 'sudo ./bc')\n")
  103. def check_browser(self):
  104. """
  105. Check browsers used by system
  106. """
  107. # make browser set manually by user
  108. if self.options.browser:
  109. if self.options.browser == "F" or self.options.browser == "f": # Firefox
  110. if sys.platform == 'darwin': # on darwin
  111. self.operating_system = 'darwin'
  112. f_his_osx = os.path.join(os.path.expanduser('~'), 'Library/Application Support/Firefox/Profiles')
  113. f_osx = '/Applications/Firefox.app/Contents/MacOS/firefox'
  114. try:
  115. if os.path.exists(f_his_osx):
  116. if len(os.listdir(f_his_osx)) > 2:
  117. print 'You have multiple profiles, choosing the last one used'
  118. # filter to use the directory that was last modified.
  119. all_subdirs = [os.path.join(f_his_osx,d)for d in os.listdir(f_his_osx)]
  120. try:
  121. all_subdirs.remove(os.path.join(f_his_osx,'.DS_Store')) # throwing out .DS_store
  122. except:
  123. pass
  124. latest_subdir = max(all_subdirs, key=os.path.getmtime)
  125. osx_profile = os.path.join(f_his_osx, latest_subdir)
  126. if self.options.browser_history: # if exists, extract user browser's history path
  127. self.browser_history_path = self.options.browser_history
  128. else:
  129. self.browser_history_path = os.path.join(osx_profile, 'places.sqlite')
  130. else:
  131. for folder in os.listdir(f_his_osx):
  132. if folder.endswith('.default'):
  133. osx_default = os.path.join(f_his_osx, folder)
  134. if self.options.browser_history: # if exists, extract user browser's history path
  135. self.browser_history_path = self.options.browser_history
  136. else:
  137. self.browser_history_path = os.path.join(osx_default, 'places.sqlite')
  138. self.browser = "F"
  139. self.browser_path = f_osx
  140. except:
  141. print "Warning: Firefox hasn't been detected on your Darwin system.\n"
  142. sys.exit(2)
  143. elif sys.platform.startswith('linux'): # on unix
  144. self.operating_system = 'linux'
  145. f_lin = os.path.join(os.path.expanduser('~'), '.mozilla/firefox/') #add the next folder
  146. if os.path.exists(f_lin):
  147. #missing multiple profile support
  148. for folder in os.listdir(f_lin):
  149. if folder.endswith('.default'):
  150. lin_default = os.path.join(f_lin, folder)
  151. if self.options.browser_history: # if exists, extract user browser's history path
  152. self.browser_history_path = self.options.browser_history
  153. else:
  154. self.browser_history_path = os.path.join(lin_default, 'places.sqlite')
  155. self.browser = "F"
  156. else:
  157. print "Warning: Firefox hasn't been detected on your Unix system.\n"
  158. sys.exit(2)
  159. else:
  160. print "Warning: Only GNU/Linux or Darwin operating systems supported.\n"
  161. sys.exit(2)
  162. elif self.options.browser == "C" or self.options.browser == "c": # Chrome
  163. if sys.platform == 'darwin': # on darwin
  164. self.operating_system = 'darwin'
  165. c_his_osx = os.path.join(os.path.expanduser('~'), 'Library/Application Support/Google/Chrome/Default/History')
  166. c_osx = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
  167. try:
  168. if os.path.exists(c_his_osx):
  169. self.browser = "C"
  170. if self.options.browser_history: # if exists, extract user browser's history path
  171. self.browser_history_path = self.options.browser_history
  172. else:
  173. self.browser_history_path = c_his_osx
  174. self.browser_path = c_osx
  175. except:
  176. print "Warning: Chrome hasn't been detected on your Darwin system.\n"
  177. sys.exit(2)
  178. elif sys.platform.startswith('linux'): # on unix
  179. self.operating_system = 'linux'
  180. c_lin = os.path.join(os.path.expanduser('~'), '.config/google-chrome/History')
  181. if os.path.exists(c_lin):
  182. self.browser = "C"
  183. if self.options.browser_history: # if exists, extract user browser's history path
  184. self.browser_history_path = self.options.browser_history
  185. else:
  186. self.browser_history_path = c_lin
  187. else:
  188. print "Warning: Chrome hasn't been detected on your Unix system.\n"
  189. sys.exit(2)
  190. else:
  191. print "Warning: Only GNU/Linux or Darwin operating systems supported.\n"
  192. sys.exit(2)
  193. elif self.options.browser == "Ch" or self.options.browser == "CH" or self.options.browser == "ch": # Chromium
  194. if sys.platform == 'darwin': # on darwin
  195. self.operating_system = 'darwin'
  196. chromium_his_osx = os.path.join(os.path.expanduser('~'), 'Library/Application Support/Chromium/Default/History')
  197. chromium_osx = '/Applications/Chromium.app/Contents/MacOS/Chromium'
  198. try:
  199. if os.path.exists(chromium_his_osx):
  200. self.browser = "CHROMIUM"
  201. if self.options.browser_history: # if exists, extract user browser's history path
  202. self.browser_history_path = self.options.browser_history
  203. else:
  204. self.browser_history_path = chromium_his_osx
  205. self.browser_path = chromium_osx
  206. except:
  207. print "Warning: Chromium hasn't been detected on your Darwin system.\n"
  208. sys.exit(2)
  209. elif sys.platform.startswith('linux'): # on unix
  210. self.operating_system = 'linux'
  211. chromium_lin = os.path.join(os.path.expanduser('~'), '.config/chromium/Default/History')
  212. if os.path.exists(chromium_lin):
  213. self.browser = "CHROMIUM"
  214. if self.options.browser_history: # if exists, extract user browser's history path
  215. self.browser_history_path = self.options.browser_history
  216. else:
  217. self.browser_history_path = chromium_lin
  218. else:
  219. print "Warning: Chromium hasn't been detected on your Unix system.\n"
  220. sys.exit(2)
  221. else:
  222. print "Warning: Only GNU/Linux or Darwin operating systems supported.\n"
  223. sys.exit(2)
  224. elif self.options.browser == "S" or self.options.browser == "s": # Safari
  225. if sys.platform == 'darwin': # on darwin
  226. self.operating_system = 'darwin'
  227. s_his_osx = os.path.join(os.path.expanduser('~'), 'Library/Safari/History.plist')
  228. s_osx = '/Applications/Safari.app/Contents/MacOS/Safari'
  229. try:
  230. if os.path.exists(s_his_osx):
  231. self.browser = "S"
  232. if self.options.browser_history: # if exists, extract user browser's history path
  233. self.browser_history_path = self.options.browser_history
  234. else:
  235. self.browser_history_path = s_his_osx
  236. self.browser_path = s_osx
  237. except:
  238. print "Warning: Safari hasn't been detected on your Darwin system.\n"
  239. sys.exit(2)
  240. elif sys.platform.startswith('linux'): # on unix
  241. self.operating_system = 'linux'
  242. safari_lin = os.path.join(os.path.expanduser('~'), 'Library/Safari/History.plist') # check needed
  243. if os.path.exists(safari_lin):
  244. self.browser = "S"
  245. if self.options.browser_history: # if exists, extract user browser's history path
  246. self.browser_history_path = self.options.browser_history
  247. else:
  248. self.browser_history_path = safari_lin
  249. else:
  250. print "Warning: Safari hasn't been detected on your Unix system.\n"
  251. sys.exit(2)
  252. else:
  253. print "Warning: Only GNU/Linux or Darwin operating systems supported.\n"
  254. sys.exit(2)
  255. elif self.options.browser == "N" or self.options.browser == "n": # None
  256. self.last_travel # force load of last submitted hostname
  257. if sys.platform == 'darwin': # on darwin
  258. self.operating_system = 'darwin'
  259. elif sys.platform.startswith('linux'): # on unix
  260. self.operating_system = 'linux'
  261. else:
  262. print "Warning: Only GNU/Linux or Darwin operating systems supported.\n"
  263. sys.exit(2)
  264. self.browser = "N"
  265. else: # browser not supported error
  266. print "You must enter a correct input to set your browser manually: F = Firefox / C = Chrome / S = Safari / Ch = Chromium\n"
  267. sys.exit(2)
  268. # make browser set, automatically
  269. else:
  270. # if config file exits, take browser type and history path from there
  271. if os.path.exists('config.py'):
  272. with open('config.py') as f:
  273. for line in f:
  274. c = line.split(":")
  275. self.browser = c[2]
  276. self.browser_history_path = c[3]
  277. else: # if not, check it from system
  278. if sys.platform == 'darwin':
  279. self.operating_system = 'darwin'
  280. # paths to the browsing history db's
  281. f_his_osx = os.path.join(os.path.expanduser('~'), 'Library/Application Support/Firefox/Profiles')
  282. c_his_osx = os.path.join(os.path.expanduser('~'), 'Library/Application Support/Google/Chrome/Default/History')
  283. chromium_his_osx = os.path.join(os.path.expanduser('~'), 'Library/Application Support/Chromium/Default/History')
  284. s_his_osx = os.path.join(os.path.expanduser('~'), 'Library/Safari/History.plist')
  285. # path to the browser executables
  286. f_osx = '/Applications/Firefox.app/Contents/MacOS/firefox'
  287. c_osx = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
  288. chromium_osx = '/Applications/Chromium.app/Contents/MacOS/Chromium'
  289. s_osx = '/Applications/Safari.app/Contents/MacOS/Safari'
  290. try:
  291. if os.path.exists(f_his_osx):
  292. if len(os.listdir(f_his_osx)) > 2:
  293. print 'You have multiple profiles, choosing the last one used'
  294. # filter to use the directory that was last modified.
  295. all_subdirs = [os.path.join(f_his_osx,d)for d in os.listdir(f_his_osx)]
  296. try:
  297. all_subdirs.remove(os.path.join(f_his_osx,'.DS_Store')) # throwing out .DS_store
  298. except:
  299. pass
  300. latest_subdir = max(all_subdirs, key=os.path.getmtime)
  301. osx_profile = os.path.join(f_his_osx, latest_subdir)
  302. if self.options.browser_history: # if exists, extract user browser's history path
  303. self.browser_history_path = self.options.browser_history
  304. else:
  305. self.browser_history_path = os.path.join(osx_profile, 'places.sqlite')
  306. else:
  307. for folder in os.listdir(f_his_osx):
  308. if folder.endswith('.default'):
  309. osx_default = os.path.join(f_his_osx, folder)
  310. if self.options.browser_history: # if exists, extract user browser's history path
  311. self.browser_history_path = self.options.browser_history
  312. else:
  313. self.browser_history_path = os.path.join(osx_default, 'places.sqlite')
  314. self.browser = "F"
  315. self.browser_path = f_osx
  316. elif os.path.exists(c_his_osx):
  317. self.browser = "C"
  318. if self.options.browser_history: # if exists, extract user browser's history path
  319. self.browser_history_path = self.options.browser_history
  320. else:
  321. self.browser_history_path = c_his_osx
  322. self.browser_path = c_osx
  323. elif os.path.exists(chromium_his_osx):
  324. self.browser = "CHROMIUM"
  325. if self.options.browser_history: # if exists, extract user browser's history path
  326. self.browser_history_path = self.options.browser_history
  327. else:
  328. self.browser_history_path = chromium_his_osx
  329. self.browser_path = chromium_osx
  330. elif os.path.exists(s_his_osx):
  331. self.browser = "S"
  332. if self.options.browser_history: # if exists, extract user browser's history path
  333. self.browser_history_path = self.options.browser_history
  334. else:
  335. self.browser_history_path = s_his_osx
  336. self.browser_path = s_osx
  337. except:
  338. print "Warning: None of the currently supported browsers (Firefox, Chrome, Chromium, Safari) are installed."
  339. elif sys.platform.startswith('linux'):
  340. self.operating_system = 'linux'
  341. f_lin = os.path.join(os.path.expanduser('~'), '.mozilla/firefox/') #add the next folder
  342. c_lin = os.path.join(os.path.expanduser('~'), '.config/google-chrome/History')
  343. chromium_lin = os.path.join(os.path.expanduser('~'), '.config/chromium/Default/History')
  344. if os.path.exists(f_lin):
  345. #missing multiple profile support
  346. for folder in os.listdir(f_lin):
  347. if folder.endswith('.default'):
  348. lin_default = os.path.join(f_lin, folder)
  349. if self.options.browser_history: # if exists, extract user browser's history path
  350. self.browser_history_path = self.options.browser_history
  351. else:
  352. self.browser_history_path = os.path.join(lin_default, 'places.sqlite')
  353. self.browser = "F"
  354. elif os.path.exists(c_lin):
  355. self.browser = "C"
  356. if self.options.browser_history: # if exists, extract user browser's history path
  357. self.browser_history_path = self.options.browser_history
  358. else:
  359. self.browser_history_path = c_lin
  360. elif os.path.exists(chromium_lin):
  361. self.browser = "CHROMIUM"
  362. if self.options.browser_history: # if exists, extract user browser's history path
  363. self.browser_history_path = self.options.browser_history
  364. else:
  365. self.browser_history_path = chromium_lin
  366. if not os.path.exists('config.py'):
  367. pass
  368. else:
  369. # output browser used on different platforms
  370. print "Browser Options:\n" + '='*45 + "\n"
  371. if sys.platform.startswith('linux'):
  372. if self.browser == "F":
  373. print "Using: Firefox\n"
  374. if self.browser == "C":
  375. print "Using: Chrome\n"
  376. if self.browser == "CHROMIUM":
  377. print "Using: Chromium\n"
  378. else:
  379. print "Using:", self.browser_path.split('/')[-1], "\n"
  380. if self.options.debug == True:
  381. if sys.platform == 'darwin':
  382. if self.browser == "F" or self.browser == "C" or self.browser == "CHROMIUM":
  383. try:
  384. self.browser_version = subprocess.check_output([self.browser_path, '--version']).strip('\n')
  385. except:
  386. a = subprocess.Popen(['firefox', '--version'], stdout=subprocess.PIPE)
  387. self.browser_version = a.stdout.read()
  388. elif sys.platform.startswith('linux') and self.browser == "F":
  389. try:
  390. self.browser_version = subprocess.check_output(['firefox', '--version']).strip('\n')
  391. except:
  392. a = subprocess.Popen(['firefox', '--version'], stdout=subprocess.PIPE)
  393. self.browser_version = a.stdout.read()
  394. if self.browser == "S":
  395. print "Can't get Safari version information, you'll have to look it up manually \n"
  396. else:
  397. print "Version:", self.browser_version
  398. if self.options.import_xml: # history not needed on xml importing
  399. pass
  400. else:
  401. print "History:", self.browser_history_path, "\n"
  402. def loadOptions(self):
  403. # todo: save file modification time & reload only if file changed
  404. try:
  405. if os.path.exists('config.py'):
  406. with open('config.py') as f:
  407. for line in f:
  408. c = line.split(":")
  409. self.system_user = c[0]
  410. self.operating_system = c[1]
  411. self.browser = c[2]
  412. self.browser_history_path = c[3]
  413. except:
  414. print "Error in the configuration file !\n\nplease modify config.py or delete it.\n\n"
  415. sys.exit(2)
  416. def saveOptions(self):
  417. fn = 'config.py'
  418. with open(fn, 'w') as fout:
  419. fout.write(self.system_user + ":" + self.operating_system + ":" + self.browser + ":" + self.browser_history_path)
  420. def setStatus(self,status):
  421. with open('bc.status', 'w') as file:
  422. file.write(status)
  423. def getURL(self):
  424. """
  425. Set urls to visit
  426. Called frequently to check for new URLs
  427. """
  428. url=None
  429. self.loadOptions()
  430. if self.browser == "F":
  431. conn = sqlite3.connect(self.browser_history_path)
  432. c = conn.cursor()
  433. c.execute("select url, last_visit_date from moz_places where url not like 'http%://127.0.0.1%' and url not like 'http%://localhost%' ORDER BY last_visit_date DESC limit 4;");
  434. #select url, last_visit_date from moz_places ORDER BY last_visit_date DESCselect url, last_visit_date from moz_places ORDER BY last_visit_date DESC')
  435. url = c.fetchone()
  436. elif self.browser == "C" or self.browser == "CHROMIUM": # Chrome/Chromium history database
  437. # Hack that makes a copy of the locked database to access it while Chrome is running.
  438. # Removes the copied database afterwards
  439. import filecmp # is this a standard module?
  440. a = self.browser_history_path + 'Copy'
  441. if os.path.exists(a):
  442. if filecmp.cmp(self.browser_history_path, a) == False:
  443. os.system('rm "' + a+'"')
  444. os.system('cp "' + self.browser_history_path + '" "' + a + '"')
  445. else:
  446. os.system('cp "' + self.browser_history_path + '" "' + a + '"')
  447. conn = sqlite3.connect(a)
  448. c = conn.cursor()
  449. c.execute('select urls.url, urls.last_visit_time FROM urls ORDER BY urls.last_visit_time DESC')
  450. url = c.fetchone()
  451. os.system('rm "' + a + '"')
  452. elif self.browser == "S": #Safari history database
  453. try:
  454. from biplist import readPlist
  455. except:
  456. print "\nError importing: biplist lib. \n\nTo run BC with Safari you need the biplist Python library:\n\n $ pip install biplist\n"
  457. plist = readPlist(self.browser_history_path)
  458. url = [plist['WebHistoryDates'][0][''], '']
  459. elif self.browser == "N": #no browser specified, getting host from file/webserver
  460. self.new_travel = True
  461. self.last_travel=0
  462. # New travel
  463. try:
  464. if os.path.exists('hostname.submit'):
  465. if url != None:
  466. try:
  467. if url[1] == None: # no history feature on browser enabled, try use hostname.submit
  468. hostname_path = open('hostname.submit')
  469. url = [str(hostname_path.read())]
  470. self.last_travel=0
  471. else:
  472. if url[1]/1000000 < os.path.getmtime('hostname.submit') :
  473. url = None
  474. self.last_travel=0
  475. except:
  476. print "\nError reading history: try to enable feature on your browser.\n"
  477. sys.exit(2)
  478. if url == None:
  479. if self.last_travel< os.path.getmtime('hostname.submit'):
  480. self.last_travel = time.time()
  481. hostname_path = open('hostname.submit')
  482. url = [str(hostname_path.read())]
  483. self.url=url[0]
  484. else:
  485. # starting a hostname.submit with a default value (ex: http://bordercheck.org)
  486. bc = "http://bordercheck.org"
  487. if self.options.debug >= 1:
  488. print "hostname.submit not found..."
  489. with open('hostname.submit', 'w') as fout:
  490. fout.write(bc)
  491. hostname_path = open('hostname.submit')
  492. url = [str(hostname_path.read())]
  493. self.url=url[0]
  494. except:
  495. print "\nfailed to read file\n"
  496. traceback.print_exc()
  497. exit(2)
  498. if url != None:
  499. self.url = url
  500. if self.options.debug >= 1:
  501. print "geturl : "+urlparse(url[0]).netloc
  502. return urlparse(url[0]).netloc
  503. print "\nError: Sorry, you don't have a compatible browser\n"
  504. exit(2)
  505. def lft(self):
  506. """
  507. Run an LFT
  508. """
  509. #LFT (traceroutes) needs root
  510. root = self.try_running(self.check_root, "\nInternal error checking root permissions.")
  511. self.setStatus('running lft')
  512. if self.operating_system == 'darwin':
  513. try:
  514. self.content = subprocess.check_output([self.options.lft_path, self.method, '-n', '-S', self.destination_ip])
  515. except:
  516. a = subprocess.Popen([self.options.lft_path, self.method, '-S', '-n', self.destination_ip], stdout=subprocess.PIPE)
  517. self.content = a.stdout.read()
  518. if self.operating_system == 'linux':
  519. if self.method == '-e': # tcp probes
  520. self.method = '-E'
  521. try:
  522. self.content = subprocess.check_output([self.options.lft_path, '-S', '-n', self.method, self.destination_ip])
  523. # support for older python versions (<2.75) that don't support subprocess.check_output
  524. except:
  525. a = subprocess.Popen([self.options.lft_path, '-S', '-n', self.method, self.destination_ip], stdout=subprocess.PIPE)
  526. self.content = a.stdout.read()
  527. self.attempts += 1
  528. if self.options.debug == True:
  529. print "Tracing:", self.destination_ip, "with method:", self.method, 'attempt:', self.attempts, '\n'
  530. self.lft_parse()
  531. def lft_parse(self):
  532. """
  533. Parse the lft to see if it produced any results, if not, run another LFT using a different method
  534. """
  535. output = self.content.splitlines()
  536. if output[-1] == "** [80/tcp no reply from target] Try advanced options (use -VV to see packets).":
  537. if self.options.debug == True:
  538. print 'TCP method doesn''t work, switching to UDP \n'
  539. self.method = '-u'
  540. time.sleep(2)
  541. self.lft()
  542. if '[target closed]' in output[-1] and self.method == '-e' or self.method == '-E':
  543. if self.options.debug == True:
  544. print 'Target closed, retrying with UDP \n'
  545. self.method = '-u'
  546. time.sleep(2)
  547. self.lft()
  548. if '[target open]' in output[-1] and len(output) < 5:
  549. if self.options.debug == True:
  550. print 'Target open, but filtered. Retrying with UDP \n'
  551. self.method = '-u'
  552. time.sleep(2)
  553. self.lft()
  554. if 'udp no reply from target] Use -VV to see packets.' in output[-1] and len(output) > 5:
  555. if self.options.debug == True:
  556. print 'Trace ended with results \n'
  557. return
  558. if '[port unreachable]' in output[-1]:
  559. if self.options.debug == True:
  560. print 'Port unreachable \n'
  561. return
  562. if '[target open]' in output[-1] and len(output) > 5:
  563. if self.options.debug == True:
  564. print 'Target open, with results \n'
  565. return
  566. if '[prohibited]' in output[-1]:
  567. if self.options.debug == True:
  568. print 'prohibited'
  569. def traces(self):
  570. '''
  571. call LFT to traceroute target and pass data to webserver
  572. '''
  573. # Set the maxmind geo databases
  574. #self.geoip = pygeoip.GeoIP('GeoLiteCity.dat')
  575. #self.geoasn = pygeoip.GeoIP('GeoIPASNum.dat')
  576. self.geoip = pygeoip.GeoIP('maps/GeoLiteCity.dat')
  577. self.geoasn = pygeoip.GeoIP('maps/GeoIPASNum.dat')
  578. print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
  579. print "URL:", self.url[0], "\n"
  580. url = urlparse(self.url[0]).netloc #changed this for prototyping
  581. if url == "":
  582. print "Error: Not traffic connection available. Aborting...\n"
  583. sys.exit(2)
  584. #url = url.replace('www.','') #--> doing a tracert to example.com and www.example.com yields different results.
  585. if not re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,4}$",url):
  586. try:
  587. url_ip = socket.gethostbyname(url.split(':')[0])
  588. except:
  589. print "Error: Not traffic connection available or invalid host. Aborting...\n"
  590. sys.exit(2)
  591. else:
  592. try:
  593. url_ip = url.split(':')[0]
  594. pass
  595. except:
  596. print "Error: Not traffic available or invalid ip. Aborting...\n"
  597. sys.exit(2)
  598. self.destination_ip = url_ip
  599. print "Host:", url, "\n\nIP:",url_ip, "\n"
  600. if url != self.old_url:
  601. self.hop_count = 0
  602. self.attempts = 0
  603. self.result_list = []
  604. self.lft()
  605. if self.options.debug == True:
  606. logfile = open('tracelogfile', 'a')
  607. thingstolog = ['='*45 + "\n",
  608. "Browser: ",self.browser_path.split('/')[-1], "\n",
  609. "Version: ", self.browser_version, "\n",
  610. "Path to browser: ", self.browser_path, "\n",
  611. "History db: ", self.browser_history_path, "\n",
  612. "URL: ", self.url[0], "\n",
  613. "Host: ",url, "\n",
  614. "Host ip: ", url_ip, "\n",
  615. '='*45, "\n"]
  616. for item in thingstolog:
  617. logfile.write(item)
  618. print '='*45 + "\n" + "Packages Route:\n" + '='*45
  619. output = self.content.splitlines()
  620. for line in output:
  621. if self.options.debug == True:
  622. logfile.write(line+'\n')
  623. line = line.split()
  624. for ip in line:
  625. if re.match(r'\d{1,4}\.\dms$', ip):
  626. self.timestamp = ip.replace('ms', '')
  627. 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):
  628. pass
  629. else:
  630. if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$",ip):
  631. self.hop_ip = ip
  632. record = self.geoip.record_by_addr(ip)
  633. try:
  634. self.asn = self.geoasn.org_by_addr(ip)
  635. except:
  636. self.asn = 'No ASN provided'
  637. #print record
  638. try:
  639. self.hop_host_name = socket.gethostbyaddr(ip)[0]
  640. except:
  641. self.hop_host_name = 'No hostname'
  642. try:
  643. longitude = str(record['longitude'])
  644. self.longitude = longitude
  645. latitude = str(record['latitude'])
  646. self.latitude = latitude
  647. except:
  648. self.longitude = '-'
  649. self.latitude = '-'
  650. try:
  651. if record.has_key('country_name') and record['city'] is not '':
  652. country = record['country_name']
  653. city = record['city']
  654. if self.options.debug:
  655. print "\nTrace:", self.hop_count, "->", ip, "->", longitude + ":" + latitude, "->", city, "->", country, "->", self.hop_host_name, "->", self.asn, '->', self.timestamp+'ms'
  656. #self.hop_count +=1
  657. self.city = city
  658. self.country = country
  659. self.server_name = self.hop_host_name
  660. cc = record['country_code'].lower()
  661. elif record.has_key('country_name'):
  662. country = record['country_name']
  663. if self.options.debug:
  664. print "\nTrace:", self.hop_count, "->", ip, "->", longitude + ":" + latitude, "->", country, "->", self.hop_host_name, "->", self.asn, '->', self.timestamp+'ms'
  665. self.country = country
  666. self.city = '-'
  667. self.server_name = self.hop_host_name
  668. cc = record['country_code'].lower()
  669. #self.hop_count+=1
  670. self.vardict = {'url': url, 'destination_ip': self.destination_ip, 'hop_count': self.hop_count,'hop_ip': self.hop_ip, 'server_name': self.server_name, 'country': self.country, 'city': self.city, 'longitude': self.longitude, 'latitude': self.latitude, 'asn' : self.asn, 'timestamp' : self.timestamp, 'country_code': cc }
  671. except:
  672. #pass
  673. if self.options.debug:
  674. print "\nTrace:", self.hop_count, "->", "Not allowed", ip
  675. self.vardict = {'url': url, 'destination_ip': self.destination_ip, 'hop_count': self.hop_count,'hop_ip': self.hop_ip, 'server_name': self.server_name, 'country': '-', 'city': '-', 'longitude': '-', 'latitude': '-', 'asn' : self.asn, 'timestamp' : self.timestamp, 'country_code': '-' }
  676. self.hop_count+=1
  677. # write xml data to file
  678. self.result_list.append(self.vardict)
  679. xml_results = xml_reporting(self)
  680. xml_results.print_xml_results('data.xml')
  681. if self.options.export_xml:
  682. open(self.options.export_xml, 'w') # starting a new xml data container in write mode
  683. xml_results.print_xml_results(self.options.export_xml)
  684. if self.options.debug == True:
  685. logfile.close()
  686. self.old_url = url
  687. #print "\n"
  688. self.hop_count = 0 # to start a new map
  689. self.setStatus("fresh")
  690. return
  691. def getGEO(self):
  692. """
  693. Get Geolocation database (http://dev.maxmind.com/geoip/legacy/geolite/)
  694. """
  695. if self.options.debug == True:
  696. print "="*45 + "\n", "GeoIP Options:\n" + '='*45 + "\n"
  697. # Extract and set geoipdatabase
  698. #if not os.path.exists('GeoLiteCity.dat'):
  699. if os.path.exists('maps/GeoLiteCity.dat'):
  700. if self.options.debug == True:
  701. print("Map: GeoLiteCity"), "\n"
  702. else:
  703. self.try_running(self.fetch_maps, "\nInternal error fetching geoIP database.")
  704. if os.path.exists('maps/GeoIPASNum.dat'):
  705. if self.options.debug == True:
  706. print("Database: GeoIPASNum"), "\n"
  707. else:
  708. self.try_running(self.fetch_maps, "\nInternal error fetching geoIP database.")
  709. def importXML(self):
  710. """
  711. Import travels data directly from XML file (no root needed) and launch a web browser on a thread with a map showing them.
  712. """
  713. try:
  714. xml_results = xml_reporting(self)
  715. xml_imported = xml_results.read_xml_results() # read xml directly from file
  716. except:
  717. print("[Error] - Something wrong importing data from XML file. Aborting..."), "\n"
  718. sys.exit(2)
  719. # Set geo databases
  720. self.geoip = pygeoip.GeoIP('maps/GeoLiteCity.dat')
  721. self.geoasn = pygeoip.GeoIP('maps/GeoIPASNum.dat')
  722. match_ip = xml_imported[0].strip('http://').strip(':8080')
  723. #regex for filtering local network IPs
  724. 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'):
  725. print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
  726. print "URL:", self.options.import_xml, "\n"
  727. print "Warning: This target is not valid!.\n"
  728. sys.exit(2)
  729. else:
  730. if xml_imported[0].startswith('file://'):
  731. print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
  732. print "URL:", self.options.import_xml, "\n"
  733. print "Warning: This target is not valid!.\n"
  734. sys.exit(2)
  735. else:
  736. print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
  737. print "URL:", self.options.import_xml, "\n"
  738. print "Host:", xml_imported[0], "\n"
  739. os.system('cp -r ' + self.options.import_xml + ' data.xml') # copy XML data provided by user to data.xml template
  740. # start web mode (on a different thread)(non root)
  741. try:
  742. webbrowser.open('http://127.0.0.1:8080', new=1)
  743. BorderCheckWebserver(self)
  744. except (KeyboardInterrupt, SystemExit):
  745. sys.exit()
  746. def fetch_lft(self):
  747. import gzip, tarfile
  748. # download scripts folder
  749. scripts_db_mirror1 = 'http://37.187.22.48/bordercheck/scripts.tar.gz'#BC Server
  750. scripts_db_mirror2 = 'http://176.28.23.46/bordercheck/scripts.tar.gz'#Turina Server
  751. scripts_db_mirror3 = 'http://83.163.232.95/bordercheck/scripts.tar.gz'#Mirror
  752. try: # mirror 1
  753. print "\n[Info] - Fetching scripts from 'Mirror 1':", scripts_db_mirror1 + "\n"
  754. response = urllib.urlretrieve(scripts_db_mirror1, 'scripts.tar.gz')
  755. except:
  756. try: # mirror 2
  757. print "[Error] - Mirror 1':", scripts_db_mirror1 + " Failed!\n"
  758. print "[Info] - Fetching scripts from 'Mirror 2':", scripts_db_mirror2 + "\n"
  759. response = urllib.urlretrieve(scripts_db_mirror2, 'scripts.tar.gz')
  760. except:
  761. try: # mirror 3
  762. print "[Error] - Mirror 2':", scripts_db_mirror2 + " Failed!\n"
  763. print "[Info] - Fetching scripts from 'Mirror 3':", scripts_db_mirror3 + "\n"
  764. response = urllib.urlretrieve(scripts_db_mirror3, 'scripts.tar.gz')
  765. except:
  766. print("[Error] - Something wrong fetching scripts from all mirrors ...Aborting!"), "\n"
  767. sys.exit(2)
  768. subprocess.call(shlex.split('tar zxfv scripts.tar.gz'))
  769. print ""
  770. os.remove('scripts.tar.gz')
  771. def fetch_maps(self):
  772. # download maps folder
  773. geo_db_mirror1 = 'http://37.187.22.48/bordercheck/maps.tar.gz'#BC Server
  774. geo_db_mirror2 = 'http://176.28.23.46/bordercheck/maps.tar.gz'#Turina Server
  775. geo_db_mirror3 = 'http://83.163.232.95/bordercheck/maps.tar.gz'#Mirror
  776. try: # mirror 1
  777. print "\n[Info] - Fetching maps from 'Mirror 1':", geo_db_mirror1 + "\n"
  778. response = urllib.urlretrieve(geo_db_mirror1, 'maps.tar.gz')
  779. except:
  780. try: # mirror 2
  781. print "[Error] - Mirror 1':", geo_db_mirror1 + " Failed!\n"
  782. print "[Info] - Fetching maps from 'Mirror 2':", geo_db_mirror2 + "\n"
  783. response = urllib.urlretrieve(geo_db_mirror2, 'maps.tar.gz')
  784. except:
  785. try: # mirror 3
  786. print "[Error] - Mirror 2':", geo_db_mirror2 + " Failed!\n"
  787. print "[Info] - Fetching maps from 'Mirror 3':", geo_db_mirror3 + "\n"
  788. response = urllib.urlretrieve(geo_db_mirror3, 'maps.tar.gz')
  789. except:
  790. print("[Error] - Something wrong fetching maps from mirrors ...Aborting!"), "\n"
  791. sys.exit(2)
  792. subprocess.call(shlex.split('tar zxfv maps.tar.gz'))
  793. print ""
  794. os.remove('maps.tar.gz')
  795. def get_username(self):
  796. import pwd
  797. self.system_user = pwd.getpwuid( os.getuid() )[ 0 ]
  798. return
  799. def wizard(self):
  800. if not os.path.exists('config.py'):
  801. # warn if is launched as root
  802. if os.geteuid()==0:
  803. print("\nWait, is better if you don't launch this wizard as root to discover your $USER system configuration.\n\nBC will ask you permissions if is needed.\n")
  804. print("Type *yes* if you are sure you want to continue [yes/*No*] ?")
  805. rep=os.read(0,36)
  806. if rep[0:3] != 'yes':
  807. sys.exit("See you soon!\n")
  808. # get system user
  809. user = self.try_running(self.get_username, "\nInternal error checking user system.")
  810. # extract browser type and path
  811. browser = self.try_running(self.check_browser, "\nInternal error checking browser files path.")
  812. if self.browser == "F":
  813. self.browser_type = "Firefox"
  814. if self.browser == "C":
  815. self.browser_type = "Chrome"
  816. if self.browser == "CHROMIUM":
  817. self.browser_type = "Chromium"
  818. if self.browser == "S":
  819. self.browser_type = "Safari"
  820. if self.browser == "N":
  821. self.browser_type = "None"
  822. print "Let's try to auto-configure your BC:\n"
  823. print "+ System user:", self.system_user
  824. print "+ OS detected:", self.operating_system
  825. print "+ Browser detected:", self.browser_type
  826. print "+ Navigation history detected:", self.browser_history_path + "\n"
  827. print "----"*15
  828. print "\nNow is time to detect if you have all the libs/packages required:\n"
  829. # check for required libs
  830. lib_sqlite3_required = False
  831. lib_geoip_required = False
  832. lib_lxml_required = False
  833. lib_libpcap_required = False
  834. lib_biplist_required = False
  835. lft_required = False
  836. maps_required = False
  837. try:
  838. import sqlite3
  839. print "+ Is sqlite3 installed?... YES"
  840. except:
  841. print "+ Is sqlite3 installed?... NO"
  842. lib_sqlite3_required = True
  843. try:
  844. import pygeoip
  845. print "+ Is python-geoip installed?... YES"
  846. except:
  847. print "+ Is python-geoip installed?... NO"
  848. lib_geoip_required = True
  849. try:
  850. import lxml
  851. print "+ Is python-lxml installed?... YES"
  852. except:
  853. print "+ Is python-lxml installed?... NO"
  854. lib_lxml_required = True
  855. try:
  856. import pcap
  857. print "+ Is python-libpcap installed?... YES"
  858. except:
  859. print "+ Is python-libpcap installed?... NO"
  860. lib_libpcap_required = True
  861. if self.browser == "Safari":
  862. try:
  863. import biplist
  864. print "+ Is python-biplist installed?... YES"
  865. except:
  866. print "+ Is python-biplist installed?... NO"
  867. lib_biplist_required = True
  868. print "\nChecking for correct version of lft required..."
  869. proc = subprocess.check_output([self.options.lft_path+' -v'], stderr=subprocess.STDOUT, shell=True)
  870. if "3.73" in proc:
  871. print "\n+ Is correct lft (~3.73v) version installed?... YES"
  872. else:
  873. print "\n+ Is correct lft (~3.73v) version installed?... NO"
  874. lft_required = True
  875. if os.path.isdir('maps'):
  876. print "\n+ Are GeoIP maps and databases installed?... YES\n"
  877. else:
  878. print "\n+ Are GeoIP maps and databases installed?... NO\n"
  879. maps_required = True
  880. if (lib_sqlite3_required or lib_geoip_required or lib_lxml_required or lib_libpcap_required or lib_biplist_required or lft_required or maps_required) == True:
  881. print "----"*15
  882. print "\nYou have some libs/packages missing. BC will download and install them for you.\n\nWarning: In some cases you will need to to enter your root credentials...\n"
  883. print "----"*15 + "\n"
  884. # download/install required libs as root (ONLY Linux)
  885. if sys.platform.startswith('linux'): # Linux
  886. if lib_sqlite3_required == True:
  887. try:
  888. subprocess.call(shlex.split('sudo apt-get install sqlite3'))
  889. lib_sqlite3_required = False
  890. except:
  891. print "\nError: installing sqlite3... Please try it manually\n"
  892. print "Aborting...\n"
  893. sys.exit()
  894. if lib_geoip_required == True:
  895. try:
  896. subprocess.call(shlex.split('sudo apt-get install python-geoip'))
  897. lib_geoip_required = False
  898. except:
  899. print "\nError: installing python-geoip... Please try it manually\n"
  900. print "Aborting...\n"
  901. sys.exit()
  902. if lib_lxml_required == True:
  903. try:
  904. subprocess.call(shlex.split('sudo apt-get install python-lxml'))
  905. lib_lxml_required = False
  906. except:
  907. print "\nError: installing python-lxml... Please try it manually\n"
  908. print "Aborting...\n"
  909. sys.exit()
  910. if lib_libpcap_required == True:
  911. try:
  912. subprocess.call(shlex.split('sudo apt-get install python-libpcap'))
  913. lib_libpcap_required = False
  914. except:
  915. print "\nError: installing python-libpcap... Please try it manually\n"
  916. print "Aborting...\n"
  917. sys.exit()
  918. if lib_biplist_required == True:
  919. try:
  920. subprocess.call(shlex.split('sudo apt-get install python-biplist'))
  921. lib_biplist_required = False
  922. except:
  923. print "\nError: installing python-biplist... Please try it manually\n"
  924. print "Aborting...\n"
  925. sys.exit()
  926. if lft_required == True:
  927. try:
  928. # download/install lft version required
  929. self.try_running(self.fetch_lft, "\nInternal error fetching lft required package.")
  930. print "\nScripts (lft-3.73) has been correctly downloaded. Please take a look to README file to install it on your system."
  931. except:
  932. print "\nError: downloading scripts... Please try it manually\n"
  933. print "Aborting...\n"
  934. sys.exit()
  935. if maps_required == True:
  936. try:
  937. # download maps package from mirrors, extract them and create maps folder
  938. self.try_running(self.fetch_maps, "\nInternal error fetching geoIP database.")
  939. maps_required = False
  940. print "----"*15
  941. except:
  942. print "\nError: downloading maps... Please try it manually\n"
  943. print "Aborting...\n"
  944. self.saveOptions()
  945. print "\nCongratulations!. BC has been correctly configurated.\n\nTry: './bc' or 'python bc' (as root)\n"
  946. sys.exit()
  947. else: # TODO:self-installation in other platforms (win32, Osx)
  948. print "\nError: self-installation of required libs is not supported on your platform... Please try to install packages manually\n"
  949. print "Aborting...\n"
  950. sys.exit()
  951. else:
  952. print "----"*15
  953. # all checks passed... now, create config.py file with $user's browser type and path
  954. self.saveOptions()
  955. print "\nCongratulations!. BC has been correctly configurated.\n\nTry: './bc' or 'python bc' (as root)\n"
  956. sys.exit(2)
  957. else: # if config.py file exists (wizard correctly passed), run BC normally
  958. print "\nWarning: You have a 'config.py' file with a configuration.\n"
  959. print("Type *yes* if you want to remove it [yes/*No*] ?")
  960. rep=os.read(0,36)
  961. if rep[0:3] != 'yes':
  962. try:
  963. subprocess.call(shlex.split('sudo rm config.py'))
  964. except:
  965. try:
  966. subprocess.call(shlex.split('su -c rm config.py'))
  967. except:
  968. print "Unable to remove configuration file (config.py)"
  969. print("Configuration file removed!.\n\n Try 'Wizard installer' again. Type: './bc -w' (non root required). Aborting...\n")
  970. else:
  971. sys.exit("See you soon!\n")
  972. sys.exit(2)
  973. def run(self, opts=None):
  974. """
  975. Run BorderCheck
  976. """
  977. # set options
  978. if opts:
  979. options = self.create_options(opts)
  980. self.set_options(options)
  981. options = self.options
  982. if self.options.lft_path == None:
  983. try:
  984. self.options.lft_path = "./bin/lft.linux" # try patched lft
  985. except:
  986. self.options.lft_path = "/usr/local/bin/lft" # try lft from system
  987. p = self.optionParser
  988. # banner
  989. print('='*75)
  990. print(str(p.version))
  991. print('='*75)
  992. # no config file, start wizard by user selection
  993. if not os.path.exists('config.py'):
  994. print("\nInfo: You BC haven't a configuration.")
  995. print("\nType *yes* if you want to generate one [no/*yes*]")
  996. rep=os.read(0,36)
  997. if rep[0:3] == 'yes':
  998. self.options.wizard = True
  999. # wizard configuration
  1000. if self.options.wizard == True:
  1001. wizard = self.wizard()
  1002. if not options.import_xml and not os.geteuid()==0: # if user is not importing XML (non root required), BC needs root for tracerouting
  1003. sys.exit("\nError: You cannot make traceroutes with your permissions. Try to launch BC as root (ex: 'sudo ./bc')\n")
  1004. # extract browser type and path
  1005. browser = self.try_running(self.check_browser, "\nInternal error checking browser files path.")
  1006. # extract url
  1007. url = self.try_running(self.getURL, "\nInternal error getting urls from browser's database.")
  1008. # set geoip database
  1009. geo = self.try_running(self.getGEO, "\nInternal error setting geoIP database.")
  1010. # read from XML or run traceroutes + stay latent mode
  1011. if options.import_xml:
  1012. import_xml = self.try_running(self.importXML, "\nInternal error importing XML data from file.")
  1013. else:
  1014. match_ip = url.strip('http://').strip(':8080')
  1015. #regex for filtering local network IPs
  1016. 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'):
  1017. print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
  1018. print "URL:", self.url, "\n"
  1019. print "Warning: This target is not valid!.\n"
  1020. pass
  1021. else:
  1022. if url.startswith('file://'):
  1023. print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
  1024. print "URL:", url, "\n"
  1025. print "Warning: This target is not valid!.\n"
  1026. pass
  1027. else:
  1028. traces = self.try_running(self.traces, "\nInternal error tracerouting.")
  1029. # start web mode (on a different thread)
  1030. try:
  1031. t = threading.Thread(target=BorderCheckWebserver, args=(self, ))
  1032. t.daemon = True
  1033. t.start()
  1034. time.sleep(2)
  1035. except (KeyboardInterrupt, SystemExit):
  1036. t.join()
  1037. sys.exit()
  1038. # open same browser of history access on a new tab
  1039. try:
  1040. if sys.platform.startswith('linux'): # *Unix magic to try 'non root navigation'
  1041. try: # try to open on a different browser (user): patch for version 0.2v
  1042. try:
  1043. subprocess.call(shlex.split("su - "+self.system_user+" -c 'DISPLAY=:0.0 /usr/bin/xdg-open http://127.0.0.1:8080'")) # standard
  1044. except:
  1045. try:
  1046. subprocess.call(shlex.split("su - "+self.system_user+" /usr/bin/gnome-open http://127.0.0.1:8080")) # gnome
  1047. except:
  1048. try:
  1049. subprocess.call(shlex.split("su - "+self.system_user+" /usr/bin/x-www-browser http://127.0.0.1:8080")) # x-www-browser
  1050. except:
  1051. subprocess.call(shlex.split("su - "+self.system_user+" -c 'python -mwebbrowser http://127.0.0.1:8080'")) # python/webbro
  1052. exit
  1053. except: # not possible auto-open window with "non root navigation' on *Unix
  1054. webbrowser.open('http://127.0.0.1:8080', new=1)
  1055. else:
  1056. try: # try to open with su + python/browser on other systems
  1057. subprocess.call(shlex.split("su - "+self.system_user+" -c 'python -mwebbrowser http://127.0.0.1:8080'")) # python/webbroser
  1058. except:
  1059. webbrowser.open('http://127.0.0.1:8080', new=1) # not possible auto-open window with "non root navigation' on other systems
  1060. except:
  1061. print "Error: Browser is not responding correctly. Try to open it manually.\n"
  1062. print('='*75 + "\n")
  1063. print "Status: Waiting for new urls ...\n"
  1064. print "Type 'Control+C' to exit.\n"
  1065. # stay latent waiting for new urls
  1066. while True:
  1067. url = self.getURL()
  1068. #url = url.replace('www.','')
  1069. try:
  1070. match_ip = url.strip('http://').strip(':8080')
  1071. except:
  1072. print '='*45 + "\n", "Target:\n" + '='*45 + "\n"
  1073. print "URL:", self.url, "\n"
  1074. pass
  1075. if url != self.old_url:
  1076. 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'):
  1077. pass
  1078. else:
  1079. if url.startswith('file://'):
  1080. pass
  1081. else:
  1082. if os.path.exists('data.xml'): # removing xml data to has a new map each time that bc is launched
  1083. os.remove('data.xml')
  1084. open('data.xml', 'w') # starting a new xml data container in write mode
  1085. traces = self.try_running(self.traces, "\nInternal error tracerouting.")
  1086. time.sleep(5) # To free up process time or goodbye :-)
  1087. if __name__ == "__main__":
  1088. app = bc()
  1089. options = app.create_options()
  1090. if options:
  1091. app.set_options(options)
  1092. app.run()