Merge pull request 'clan-cli: Make clan ssh automatically start tor' (#2623) from Qubasa/clan-core:Qubasa-main into main

This commit is contained in:
clan-bot
2024-12-17 11:19:21 +00:00
3 changed files with 46 additions and 20 deletions

View File

@@ -2,16 +2,16 @@ import argparse
import ipaddress
import json
import logging
import shlex
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from clan_cli.async_run import AsyncRuntime
from clan_cli.cmd import run
from clan_cli.errors import ClanError, TorConnectionError, TorSocksError
from clan_cli.errors import ClanError
from clan_cli.nix import nix_shell
from clan_cli.ssh.host import Host, is_ssh_reachable
from clan_cli.ssh.tor import TorTarget, ssh_tor_reachable
from clan_cli.ssh.tor import TorTarget, spawn_tor, ssh_tor_reachable
log = logging.getLogger(__name__)
@@ -63,12 +63,13 @@ def parse_qr_code(picture_file: Path) -> DeployInfo:
return DeployInfo.from_json(json.loads(data))
def ssh_shell_from_deploy(deploy_info: DeployInfo) -> None:
def ssh_shell_from_deploy(deploy_info: DeployInfo, runtime: AsyncRuntime) -> None:
if host := find_reachable_host(deploy_info):
host.connect_ssh_shell(password=deploy_info.pwd)
else:
log.info("Could not reach host via clearnet 'addrs'")
log.info(f"Trying to reach host via tor '{deploy_info.tor}'")
spawn_tor(runtime)
if not deploy_info.tor:
msg = "No tor address provided, please provide a tor address."
raise ClanError(msg)
@@ -98,15 +99,9 @@ def ssh_command(args: argparse.Namespace) -> None:
if not deploy_info:
msg = "No --json or --png data provided"
raise ClanError(msg)
try:
ssh_shell_from_deploy(deploy_info)
except TorSocksError as ex:
log.error(ex)
tor_cmd = nix_shell(["nixpkgs#tor"], ["tor"])
log.error("Is Tor running? If not, you can start it by running:")
log.error(f"{' '.join(shlex.quote(arg) for arg in tor_cmd)}")
except TorConnectionError:
log.error("The onion address is not reachable via Tor.")
with AsyncRuntime() as runtime:
ssh_shell_from_deploy(deploy_info, runtime)
def register_parser(parser: argparse.ArgumentParser) -> None:

View File

@@ -185,6 +185,7 @@ class Host:
ssh_opts.extend(["-i", self.key])
if tor_socks:
packages.append("nixpkgs#netcat")
ssh_opts.append("-o")
ssh_opts.append("ProxyCommand=nc -x 127.0.0.1:9050 -X 5 %h %p")

View File

@@ -4,9 +4,11 @@ import argparse
import logging
import socket
import struct
import time
from dataclasses import dataclass
from clan_cli.cmd import run
from clan_cli.async_run import AsyncRuntime
from clan_cli.cmd import Log, RunOpts, run
from clan_cli.errors import TorConnectionError, TorSocksError
from clan_cli.nix import nix_shell
@@ -96,14 +98,42 @@ def fetch_onion_content(target: TorTarget) -> str:
return response.decode("utf-8", errors="replace")
def spawn_tor() -> None:
def is_tor_running() -> bool:
"""Checks if Tor is online."""
try:
tor_online_test()
except TorSocksError:
return False
else:
return True
def spawn_tor(runtime: AsyncRuntime) -> None:
"""
Spawns a Tor process using `nix-shell`.
Spawns a Tor process using `nix-shell` if Tor is not already running.
"""
cmd_args = ["tor"]
def start_tor() -> None:
"""Starts Tor process using nix-shell."""
cmd_args = ["tor", "--HardwareAccel", "1"]
packages = ["nixpkgs#tor"]
cmd = nix_shell(packages, cmd_args)
run(cmd)
runtime.async_run(None, run, cmd, RunOpts(log=Log.BOTH))
log.debug("Attempting to start Tor")
# Check if Tor is already running
if is_tor_running():
log.info("Tor is running")
return
# Attempt to start Tor
start_tor()
# Continuously check if Tor has started
while not is_tor_running():
log.debug("Waiting for Tor to start...")
time.sleep(0.2)
log.info("Tor is now running")
def tor_online_test() -> bool: