# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- import os import sys import re import traceback import shutil import socket import select import time global LOG import logging import warnings warnings.filterwarnings('ignore') LOG = logging.getLogger() bHAVE_TORR = shutil.which('tor-resolve') def bAreWeConnected(): # FixMe: Linux only sFile = f"/proc/{os.getpid()}/net/route" if not os.path.isfile(sFile): return None i = 0 for elt in open(sFile, "r").readlines(): if elt.startswith('Iface'): continue if elt.startswith('lo'): continue i += 1 return i > 0 def sMapaddressResolv(target, iPort=9051): if not stem: LOG.warn('please install the stem Python package') return '' try: controller = oGetStemController(log_level=10) map_dict = {"0.0.0.0": target} map_ret = controller.map_address(map_dict) return map_ret except Exception as e: LOG.exception(e) return '' def lIntroductionPoints(target, iPort=9051): if stem == False: return '' from stem import StreamStatus from stem.control import EventType, Controller import getpass l = [] try: controller = oGetStemController(log_level=10) desc = controller.get_hidden_service_descriptor(target) l = desc.introduction_points() if l: LOG.warn(f"{elt} NO introduction points for {target}\n") return l LOG.debug(f"{elt} len(l) introduction points for {target}") for introduction_point in l: l.append('%s:%s => %s' % (introduction_point.address, introduction_point.port, introduction_point.identifier)) except Exception as e: LOG.exception(e) return l def sTorResolve(target, verbose=False, sHost='127.0.0.1', iPort=9050, SOCK_TIMEOUT_SECONDS=10.0, SOCK_TIMEOUT_TRIES=3, ): MAX_INFO_RESPONSE_PACKET_LENGTH = 8 target = target.strip('/') seb = b"\o004\o360\o000\o000\o000\o000\o000\o001\o000" seb = b"\x04\xf0\x00\x00\x00\x00\x00\x01\x00" seb += bytes(target, 'US-ASCII') + b"\x00" assert len(seb) == 10+len(target), str(len(seb))+repr(seb) # LOG.debug(f"0 Sending {len(seb)} to The TOR proxy {seb}") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((sHost, iPort)) sock.settimeout(SOCK_TIMEOUT_SECONDS) oRet = sock.sendall(seb) i = 0 data = '' while i < SOCK_TIMEOUT_TRIES: i += 1 time.sleep(3) lReady = select.select([sock.fileno()], [], [], SOCK_TIMEOUT_SECONDS) if not lReady[0]: continue try: flags=socket.MSG_WAITALL data = sock.recv(MAX_INFO_RESPONSE_PACKET_LENGTH, flags) except socket.timeout: LOG.warn("4 The TOR proxy " \ +repr((sHost, iPort)) \ +" didnt reply in " + str(SOCK_TIMEOUT_SECONDS) + " sec." +" #" +str(i)) except Exception as e: LOG.error("4 The TOR proxy " \ +repr((sHost, iPort)) \ +" errored with " + str(e) +" #" +str(i)) sock.close() raise SystemExit(4) else: if len(data) > 0: break if len(data) == 0: if i > SOCK_TIMEOUT_TRIES: sLabel = "5 No reply #" else: sLabel = "5 No data #" LOG.info(sLabel +f"{i} from {sHost} {iPort}" ) sock.close() raise SystemExit(5) assert len(data) >= 8 packet_sf = data[1] if packet_sf == 90: # , "%d" % packet_sf assert f"{packet_sf}" == "90", f"packet_sf = {packet_sf}" return f"{data[4]}.{data[5]}.{data[6]}.{data[7]}" else: # 91 LOG.warn(f"tor-resolve failed for {target} from {sHost} {iPort}" ) os.system(f"tor-resolve -4 {target} > /tmp/e 2>/dev/null") # os.system("strace tor-resolve -4 "+target+" 2>&1|grep '^sen\|^rec'") return '' def getaddrinfo(sHost, sPort): # do this the explicit way = Ive seen the compact connect fail # >>> sHost, sPort = 'l27.0.0.1', 33446 # >>> sock.connect((sHost, sPort)) # socket.gaierror: [Errno -2] Name or service not known try: lElts = socket.getaddrinfo(sHost, int(sPort), socket.AF_INET) lElts = list(filter(lambda elt: elt[1] == socket.SOCK_DGRAM, lElts)) assert len(lElts) == 1, repr(lElts) lPair = lElts[0][-1] assert len(lPair) == 2, repr(lPair) assert type(lPair[1]) == int, repr(lPair) except (socket.gaierror, OSError, BaseException) as e: LOG.error(e) return None return lPair def icheck_torrc(sFile, oArgs): l = open(sFile, 'rt').readlines() a = {} for elt in l: elt = elt.strip() if not elt or not ' ' in elt: continue k,v = elt.split(' ', 1) a[k] = v keys = a if 'HashedControlPassword' not in keys: LOG.info('Add HashedControlPassword for security') print('run: tor --hashcontrolpassword ') if 'ExcludeExitNodes' in keys: elt = 'BadNodes.ExcludeExitNodes.BadExit' LOG.warn(f"Remove ExcludeNodes and move then to {oArgs.bad_nodes}") print(f"move to the {elt} section as a list") if 'GuardNodes' in keys: elt = 'GoodNodes.GuardNodes' LOG.warn(f"Remove GuardNodes and move then to {oArgs.good_nodes}") print(f"move to the {elt} section as a list") if 'ExcludeNodes' in keys: elt = 'BadNodes.ExcludeNodes.BadExit' LOG.warn(f"Remove ExcludeNodes and move then to {oArgs.bad_nodes}") print(f"move to the {elt} section as a list") if 'ControlSocket' not in keys and os.path.exists('/run/tor/control'): LOG.info('Add ControlSocket /run/tor/control for us') print('ControlSocket /run/tor/control GroupWritable RelaxDirModeCheck') if 'UseMicrodescriptors' not in keys or keys['UseMicrodescriptors'] != '1': LOG.info('Add UseMicrodescriptors 0 for us') print('UseMicrodescriptors 0') if 'AutomapHostsSuffixes' not in keys: LOG.info('Add AutomapHostsSuffixes for onions') print('AutomapHostsSuffixes .exit,.onion') if 'AutoMapHostsOnResolve' not in keys: LOG.info('Add AutoMapHostsOnResolve for onions') print('AutoMapHostsOnResolve 1') if 'VirtualAddrNetworkIPv4' not in keys: LOG.info('Add VirtualAddrNetworkIPv4 for onions') print('VirtualAddrNetworkIPv4 172.16.0.0/12') return 0