python3 <<'PY'
import os
import pty
import select
import subprocess
import sys
import time
import signal
USER = "user"
PASS = "user"
REMOTE_CMD = "systemctl poweroff"
def sh(cmd):
return subprocess.check_output(cmd, shell=True, text=True, stderr=subprocess.DEVNULL).strip()
# Все локальные IP, чтобы не выключить машину, с которой запускаете
local_ips = set()
try:
out = sh("ip -o -4 addr show | awk '{split($4,a,\"/\"); print a[1]}'")
local_ips = set(x.strip() for x in out.splitlines() if x.strip())
except Exception:
pass
# Основной IP и подсеть
myip = sh("ip -4 route get 1.1.1.1 | awk '{for(i=1;i<=NF;i++) if($i==\"src\"){print $(i+1); exit}}'")
net = ".".join(myip.split(".")[:3])
prompts = [
"password:",
"password for",
"пароль",
"authentication is required",
"authenticate",
"polkit",
]
def run_host(ip):
print(f"\n=== POWER OFF {ip} ===", flush=True)
cmd = [
"ssh",
"-tt",
"-o", "ConnectTimeout=3",
"-o", "ConnectionAttempts=1",
"-o", "StrictHostKeyChecking=accept-new",
"-o", "NumberOfPasswordPrompts=5",
"-o", "PreferredAuthentications=password,keyboard-interactive",
"-o", "PubkeyAuthentication=no",
f"{USER}@{ip}",
REMOTE_CMD,
]
pid, fd = pty.fork()
if pid == 0:
os.execvp("ssh", cmd)
buffer = ""
last_send = 0
sent_count = 0
deadline = time.time() + 35
while True:
if time.time() > deadline:
print(f"\nTIMEOUT: {ip}", flush=True)
try:
os.kill(pid, signal.SIGKILL)
except ProcessLookupError:
pass
break
r, _, _ = select.select([fd], [], [], 0.5)
if fd in r:
try:
data = os.read(fd, 4096)
except OSError:
break
if not data:
break
text = data.decode(errors="ignore")
sys.stdout.write(text)
sys.stdout.flush()
buffer = (buffer + text).lower()[-3000:]
if "continue connecting" in buffer:
os.write(fd, b"yes\n")
buffer = ""
continue
if any(p in buffer for p in prompts):
now = time.time()
# защита от слишком частой отправки
if now - last_send > 0.7:
os.write(fd, (PASS + "\n").encode())
last_send = now
sent_count += 1
buffer = ""
if sent_count > 10:
print(f"\nTOO MANY PASSWORD PROMPTS: {ip}", flush=True)
break
try:
done, status = os.waitpid(pid, os.WNOHANG)
if done == pid:
break
except ChildProcessError:
break
try:
os.close(fd)
except OSError:
pass
for i in range(1, 255):
ip = f"{net}.{i}"
if ip in local_ips:
print(f"SKIP LOCAL: {ip}", flush=True)
continue
run_host(ip)
print("\nDONE")
PY