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:
@@ -2,16 +2,16 @@ import argparse
|
|||||||
import ipaddress
|
import ipaddress
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import shlex
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from clan_cli.async_run import AsyncRuntime
|
||||||
from clan_cli.cmd import run
|
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.nix import nix_shell
|
||||||
from clan_cli.ssh.host import Host, is_ssh_reachable
|
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__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -63,12 +63,13 @@ def parse_qr_code(picture_file: Path) -> DeployInfo:
|
|||||||
return DeployInfo.from_json(json.loads(data))
|
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):
|
if host := find_reachable_host(deploy_info):
|
||||||
host.connect_ssh_shell(password=deploy_info.pwd)
|
host.connect_ssh_shell(password=deploy_info.pwd)
|
||||||
else:
|
else:
|
||||||
log.info("Could not reach host via clearnet 'addrs'")
|
log.info("Could not reach host via clearnet 'addrs'")
|
||||||
log.info(f"Trying to reach host via tor '{deploy_info.tor}'")
|
log.info(f"Trying to reach host via tor '{deploy_info.tor}'")
|
||||||
|
spawn_tor(runtime)
|
||||||
if not deploy_info.tor:
|
if not deploy_info.tor:
|
||||||
msg = "No tor address provided, please provide a tor address."
|
msg = "No tor address provided, please provide a tor address."
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
@@ -98,15 +99,9 @@ def ssh_command(args: argparse.Namespace) -> None:
|
|||||||
if not deploy_info:
|
if not deploy_info:
|
||||||
msg = "No --json or --png data provided"
|
msg = "No --json or --png data provided"
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
try:
|
|
||||||
ssh_shell_from_deploy(deploy_info)
|
with AsyncRuntime() as runtime:
|
||||||
except TorSocksError as ex:
|
ssh_shell_from_deploy(deploy_info, runtime)
|
||||||
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.")
|
|
||||||
|
|
||||||
|
|
||||||
def register_parser(parser: argparse.ArgumentParser) -> None:
|
def register_parser(parser: argparse.ArgumentParser) -> None:
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ class Host:
|
|||||||
ssh_opts.extend(["-i", self.key])
|
ssh_opts.extend(["-i", self.key])
|
||||||
|
|
||||||
if tor_socks:
|
if tor_socks:
|
||||||
|
packages.append("nixpkgs#netcat")
|
||||||
ssh_opts.append("-o")
|
ssh_opts.append("-o")
|
||||||
ssh_opts.append("ProxyCommand=nc -x 127.0.0.1:9050 -X 5 %h %p")
|
ssh_opts.append("ProxyCommand=nc -x 127.0.0.1:9050 -X 5 %h %p")
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import argparse
|
|||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
import time
|
||||||
from dataclasses import dataclass
|
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.errors import TorConnectionError, TorSocksError
|
||||||
from clan_cli.nix import nix_shell
|
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")
|
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"]
|
|
||||||
packages = ["nixpkgs#tor"]
|
def start_tor() -> None:
|
||||||
cmd = nix_shell(packages, cmd_args)
|
"""Starts Tor process using nix-shell."""
|
||||||
run(cmd)
|
cmd_args = ["tor", "--HardwareAccel", "1"]
|
||||||
|
packages = ["nixpkgs#tor"]
|
||||||
|
cmd = nix_shell(packages, cmd_args)
|
||||||
|
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:
|
def tor_online_test() -> bool:
|
||||||
|
|||||||
Reference in New Issue
Block a user