from stem.control import Controller import stem.connection import paho.mqtt.client as mqtt import socks import ssl import socket import json import configparser import argparse from datetime import datetime from os import environ def main(): parser = argparse.ArgumentParser(description='Broadcast SSH hidden service hostname via MQTT') parser.add_argument('--config-dir', nargs='?', dest='configPath', default='/etc/torch', help='configuration directory (default: /etc/torch)') args = parser.parse_args() config_path = args.configPath if "TORCH_CONFIG_DIR" in environ: config_path = environ.get("TORCH_CONFIG_DIR") if not config_path.endswith("/"): config_path = config_path + "/" print("Using torch configuration path: " + config_path) config = configparser.ConfigParser() configuration_file_path = config_path + "torch.conf" print("Reading configuration file at '%s'" % (configuration_file_path)) config.read(configuration_file_path) tor_proxy_host = config['tor'].get('ProxyHost', fallback="127.0.0.1") tor_proxy_port = config['tor'].getint('ProxyPort', fallback=9050) tor_controller_port = config['tor'].getint('ControllerPort', fallback=9051) ssh_port = config['ssh'].getint('Port', fallback=22) mqtt_config = config['mqtt'] mqtt_broker_host = mqtt_config.get('BrokerHost', fallback="localhost") mqtt_broker_port = mqtt_config.getint('BrokerPort', fallback=1883) mqtt_broker_using_tor = mqtt_broker_host.endswith(".onion") client_id = mqtt_config.get('ClientID', fallback=socket.gethostname()) mqtt_topic = mqtt_config.get('Topic', fallback="torch/%s/onion_url" % client_id) mqtt_require_certificate = mqtt_config.getboolean( 'RequireCertificate', fallback=False) mqtt_ca_file = config_path + mqtt_config.get('CaFile') mqtt_cert_file = config_path + mqtt_config.get('CertFile') mqtt_key_file = config_path + mqtt_config.get('KeyFile') print("Connecting to local TOR controller on port %s" % tor_proxy_port) with Controller.from_port(port=tor_controller_port) as controller: protocol_info = stem.connection.get_protocolinfo(controller) stem.connection.authenticate_safecookie(controller, protocol_info.cookie_path) print("Creating TOR Hidden Service...") service = controller.create_ephemeral_hidden_service(ssh_port, detached=True) onion_address = "%s.onion" % service.service_id print("Created Tor Hidden Service for local service on port %s at %s" % (ssh_port, onion_address)) client = mqtt.Client() protocol = "mqtt" if mqtt_broker_using_tor: client.proxy_set(proxy_type=socks.SOCKS5, proxy_addr=tor_proxy_host, proxy_port=tor_proxy_port) else: if mqtt_require_certificate: protocol = "mqtts" client.tls_set( ca_certs=mqtt_ca_file, certfile=mqtt_cert_file, keyfile=mqtt_key_file, cert_reqs=ssl.CERT_REQUIRED) print("Connecting to MQTT broker: %s://%s:%s/%s" % (protocol, mqtt_broker_host, mqtt_broker_port, mqtt_topic)) if mqtt_broker_using_tor: print("--> Using TOR proxy: %s:%s" % (tor_proxy_host, tor_proxy_port)) client.connect(mqtt_broker_host, mqtt_broker_port, 60) print("Connected to MQTT Broker") payload = json.dumps({ 'clientId': client_id, 'timestamp': datetime.now().strftime("%d-%b-%Y (%H:%M:%S.%f)"), 'onionAddress': onion_address, 'sshPort': ssh_port }) print("Publishing payload: " + payload) client.publish(mqtt_topic, payload) print("Published payload!") client.disconnect() print("Disconnected from MQTT Broker")