stem_examples/src/stem_examples/introduction_points.py

135 lines
5.5 KiB
Python
Executable File

#!/usr/local/bin/python3.sh
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
# https://stem.torproject.org/tutorials/over_the_river.html
__doc__ = """
Hidden services give you a way of providing a service without exposing your address. These services are only accessible through Tor or Tor2web, and useful for a surprising number of things...
Hosting an anonymized site. This is usually the first thing that comes to mind, and something we'll demonstrate in a sec.
Providing an endpoint Tor users can reach without exiting the Tor network. This eliminates the risk of an unreliable or malicious exit getting in the way. Great examples of this are Facebook (facebookcorewwwi.onion) and DuckDuckGo (3g2upl4pq6kufc4m.onion).
Personal services. For instance you can host your home SSH server as a hidden service to prevent eavesdroppers from knowing where you live while traveling abroad.
Tor2web provides a quick and easy way of seeing if your hidden service is working. To use it simply replace the .onion of your address with .tor2web.org...
This script tests if you can reach a hidden service, passed as an onion address
as an argument. If no argument is given, 3 common onion sites are tested:
Facebook, DuckDuckGo.
"""
import sys
import os
import getpass
import logging
import binascii
import stem
from stem.control import Controller
from stem import Timeout
from stem.client.datatype import LinkByFingerprint
from stem.descriptor.hidden_service import HiddenServiceDescriptorV3
from stem_examples.tor_controller import get_controller
from stem.descriptor.hidden_service import HiddenServiceDescriptorV3
LOG = logging.getLogger()
TIMEOUT = 60
lKNOWN_ONIONS = [
'facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd', # facebook
'duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad', # ddg
'zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad', # keys.openpgp.org
'libera75jm6of4wxpxt4aynol3xjmbtxgfyjpu34ss4d7r7q2v5zrpyd',
'oftcnet6xg6roj6d7id4y4cu6dchysacqj2ldgea73qzdagufflqxrid',
]
def bin_to_hex(raw_id:int, length: int|None = None) -> str:
if length is None: length = len(raw_id)
res = ''.join('{:02x}'.format(raw_id[i]) for i in range(length))
return res.upper()
def iMain(lArgs=None):
lRetval = lMain(lArgs)
if lRetval is None:
return -1
return 0
def lMain(lArgs=None, timeout=TIMEOUT) -> list:
lRetval = []
if not lArgs:
lArgs = lKNOWN_ONIONS
try:
password = os.environ.get('TOR_CONTROLLER_PASSWORD', '')
if os.path.exists('/run/tor/control'):
controller = get_controller(password=password, unix='/run/tor/control')
else:
controller = get_controller(password=password, port=9051)
for elt in lArgs:
LOG.info(f"onion: {elt}")
try:
desc = controller.get_hidden_service_descriptor(elt,
await_result=True,
timeout=timeout)
except Exception as e:
LOG.warn (f"{elt} EXCEPTION {e}")
continue
if desc.descriptor_id is None or desc.version is None:
# reparse as HSv3
inner_layer = HiddenServiceDescriptorV3.from_str(str(desc)).decrypt(elt)
if hasattr(inner_layer, 'introduction_points'):
LOG.info (f"{elt} reparsed desc.decrypt len={len(desc.introduction_points())}")
l = inner_layer.introduction_points
else:
LOG.warn (f"{elt} reparsed desc.decrypt={dir(inner_layer)}")
sys.exit(1)
#LOG.info(f"version: {desc.version}\n")
#LOG.info(f"lifetime: {desc.lifetime}\n")
else:
LOG.info(f"published: {desc.published}\n")
l = desc.introduction_points()
if not l:
LOG.warn(f"{elt} NO introduction points {l}\n")
continue
lp = []
for introduction_point in l:
for linkspecifier in introduction_point.link_specifiers:
# if isinstance(linkspecifier, LinkByFingerprint):
# LOG.log(40, f"Getting fingerprint for {linkspecifier}")
if hasattr(linkspecifier, 'fingerprint') and \
len(linkspecifier.value) == 20:
lp += [bin_to_hex(linkspecifier.value)]
elif hasattr(introduction_point, 'address'):
LOG.info('IP: %s:%s => %s' % (introduction_point.address,
introduction_point.port,
introduction_point.identifier))
else:
pass # LOG.warn(f"{elt} introduction_point type={type(linkspecifier)}")
LOG.info(f"{elt} {len(lp)} introduction points {lp}")
except Exception as e:
LOG.exception(f"Exception: {e}")
finally:
del controller
return lRetval
if __name__ == '__main__':
from stem_examples.stem_utils import vsetup_logging
if os.environ.get('DEBUG', ''):
log_level = 10
else:
log_level = 20
vsetup_logging(LOG, log_level)
try:
l = lMain(sys.argv[1:])
if l: print('IPs: ', l)
i = 0
except KeyboardInterrupt as e:
LOG.exception(f"Exception {e}")
i = 0
except Exception as e:
i = 1
sys.exit(i)