torch-agent/torch_agent/torch_agent.py

128 lines
4.2 KiB
Python
Executable File

import argparse
import configparser
import json
import socket
import ssl
from datetime import datetime
from os import environ
import paho.mqtt.publish as publish
import socks
import stem.connection
from stem.control import Controller
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")
mqtt_client_id = mqtt_config.get('ClientID', fallback=socket.gethostname())
mqtt_topic = mqtt_config.get('Topic', fallback="torch/%s/onion_url" % mqtt_client_id)
mqtt_require_certificate = mqtt_config.getboolean(
'RequireCertificate',
fallback=False)
mqtt_ca_file = mqtt_config.get('CaFile', fallback=None)
mqtt_ca_file = config_path + mqtt_ca_file
mqtt_cert_file = mqtt_config.get('CertFile', fallback=None)
mqtt_cert_file = config_path + mqtt_cert_file
mqtt_key_file = mqtt_config.get('KeyFile', fallback=None)
mqtt_key_file = config_path + mqtt_key_file
mqtt_use_tls = \
mqtt_ca_file is not None and \
mqtt_cert_file is not None and \
mqtt_key_file is not None
print("Connecting to local TOR controller on port %s" % tor_controller_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))
protocol = "mqtt"
tls_args = None
proxy_args = None
cert_required = ssl.CERT_OPTIONAL
if mqtt_require_certificate:
cert_required = ssl.CERT_REQUIRED
if mqtt_broker_using_tor:
cert_required = ssl.CERT_OPTIONAL
proxy_args = {
'proxy_type': socks.SOCKS5,
'proxy_addr': tor_proxy_host,
'proxy_port': tor_proxy_port
}
if mqtt_use_tls:
protocol = "mqtts"
tls_args = {
'ca_certs': mqtt_ca_file,
'certfile': mqtt_cert_file,
'keyfile': mqtt_key_file,
'cert_reqs': cert_required
}
print("Publishing 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))
payload = json.dumps({
'clientId': mqtt_client_id,
'timestamp': datetime.now().strftime("%d-%b-%Y (%H:%M:%S.%f)"),
'onionAddress': onion_address,
'sshPort': ssh_port
})
publish.single(mqtt_topic,
payload,
qos=1,
hostname=mqtt_broker_host,
port=mqtt_broker_port,
client_id=mqtt_client_id,
tls=tls_args,
proxy_args=proxy_args)