203 lines
6.6 KiB
Python
203 lines
6.6 KiB
Python
# -*- 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 <TopSecretWord>')
|
|
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
|
|
|