diff --git a/nikovpn.py b/nikovpn.py index cf48b17..7266eb2 100644 --- a/nikovpn.py +++ b/nikovpn.py @@ -65,7 +65,7 @@ class Router: def __init__(self, host, user="root", port=22, password=None, key=None): self.host, self.user, self.port = host, user, port opts = ["-o", "StrictHostKeyChecking=accept-new", - "-o", "ConnectTimeout=10", "-o", "BatchMode=yes"] + "-o", "ConnectTimeout=10"] pre = [] if password is not None: if not shutil_which("sshpass"): @@ -73,10 +73,16 @@ class Router: pre = ["sshpass", "-p", password] opts += ["-o", "PreferredAuthentications=password", "-o", "PubkeyAuthentication=no"] + else: + opts += ["-o", "BatchMode=yes"] if key: opts += ["-i", str(key)] + self.pre, self.opts = pre, opts self.base = pre + ["ssh", "-p", str(port)] + opts + [f"{user}@{host}"] + def ssh_args(self, *extra): + return self.pre + ["ssh", "-p", str(self.port)] + self.opts + list(extra) + def run(self, cmd, timeout=180, input_bytes=None, check=False): r = subprocess.run(self.base + [cmd], capture_output=True, timeout=timeout, @@ -287,7 +293,7 @@ def choose_candidates(rt: Router, links_text: bytes, naive_ok: bool) -> list: rest = [l for l in group if not host_alive(l)] picked += alive + rest for l in picked: - l["protocol"] = proto + l["protocol"] = l["scheme"].split("+")[0] l["sni"] = qp(l, "sni") or l["host"] return picked @@ -721,6 +727,16 @@ def human(n): def stop_service(rt: Router): if rt.exists("/etc/init.d/nikovpn"): rt.run("/etc/init.d/nikovpn stop >/dev/null 2>&1") + # процессы, запущенные в обход procd, держат бинарники (Text file busy) + rt.run("kill $(pgrep sing-box) 2>/dev/null; " + "kill $(pgrep ipt2socks) 2>/dev/null") + for _ in range(5): + _, out, _ = rt.run("pgrep sing-box; pgrep ipt2socks") + if not out.strip(): + break + rt.run("kill -9 $(pgrep sing-box) 2>/dev/null; " + "kill -9 $(pgrep ipt2socks) 2>/dev/null") + time.sleep(1) def verify_tunnel(rt: Router, local_port: int) -> str | None: @@ -733,9 +749,9 @@ def verify_tunnel(rt: Router, local_port: int) -> str | None: t.bind(("127.0.0.1", 0)) local_port = t.getsockname()[1] fwd = subprocess.Popen( - ["ssh", "-p", str(rt.port), "-o", "StrictHostKeyChecking=accept-new", - "-o", "BatchMode=yes", "-f", "-N", "-L", - f"{local_port}:127.0.0.1:{SOCKS_PORT}", f"{rt.user}@{rt.host}"], + rt.ssh_args("-f", "-N", "-L", + f"{local_port}:127.0.0.1:{SOCKS_PORT}", + f"{rt.user}@{rt.host}"), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) time.sleep(1.5) r = subprocess.run( @@ -832,7 +848,7 @@ def do_install(rt: Router, args, update=False): if code != 200 or not links.strip(): die(f"не удалось получить список серверов (код {code})") - cands = choose_candidates(rt, links, naive_ok) + cands = choose_candidates(rt, links, bool(naive_ok)) if not cands: die("пустой список кандидатов")