#!/usr/bin/env python3 """Run Wifi-Otantik provision against the live RB4011 via Tailscale jump host.""" from __future__ import annotations import time import paramiko JUMP = ("100.80.255.113", "otantik", "DeararbsFr2@") MK = ("172.30.0.1", "admin", "demopass") RSC_URL = "https://wifi.otantik.cm/provision/test.rsc" BOOT = ( '/tool fetch mode=https url="https://wifi.otantik.cm/provision/test.rsc" ' "dst-path=wifi-otantik.rsc" ) def wait_prompt(shell, timeout=20) -> str: buf = b"" end = time.time() + timeout while time.time() < end: time.sleep(0.15) if shell.recv_ready(): buf += shell.recv(65535) end = time.time() + 3.0 if b"> " in buf[-200:]: break return buf.decode("utf-8", "replace") def cmd(shell, line: str, timeout=25) -> str: shell.send(line + "\r") out = wait_prompt(shell, timeout) print("\n===== " + line + " =====") print(out[-4000:]) return out def main() -> None: jump = paramiko.SSHClient() jump.set_missing_host_key_policy(paramiko.AutoAddPolicy()) jump.connect( JUMP[0], username=JUMP[1], password=JUMP[2], timeout=25, allow_agent=False, look_for_keys=False, ) stdin, stdout, stderr = jump.exec_command( "curl -sS -L --max-time 30 " + RSC_URL, timeout=40 ) rsc = stdout.read() err = stderr.read().decode("utf-8", "replace") if not rsc.startswith(b"#") and b"Wifi-Otantik" not in rsc: raise SystemExit("bad rsc from jump: " + err[:500] + rsc[:300].decode("utf-8", "replace")) print("downloaded rsc via jump", len(rsc), "bytes") chan = jump.get_transport().open_channel("direct-tcpip", (MK[0], 22), ("127.0.0.1", 0)) mk = paramiko.SSHClient() mk.set_missing_host_key_policy(paramiko.AutoAddPolicy()) mk.connect( MK[0], username=MK[1], password=MK[2], sock=chan, timeout=25, allow_agent=False, look_for_keys=False, ) shell = mk.invoke_shell(width=240, height=80) wait_prompt(shell, 15) cmd(shell, "/system identity print") cmd(shell, "/system resource print") cmd(shell, "/system package print where name~\"wireguard\"") cmd(shell, "/ip dns print") cmd(shell, ":put [:resolve wifi.otantik.cm]") cmd(shell, ":put [:resolve portal.otantik.cm]") cmd(shell, BOOT, timeout=40) cmd(shell, "/file print where name~\"wifi-otantik\"") cmd(shell, "/tool fetch mode=https url=\"https://wifi.otantik.cm/provision/test.rsc\" dst-path=wifi-otantik.rsc check-certificate=no", timeout=40) cmd(shell, "/file print where name~\"wifi-otantik\"") # Upload RSC via SFTP so we can test import even if fetch/DNS fails. sftp = mk.open_sftp() with sftp.file("wifi-otantik-direct.rsc", "w") as f: f.write(rsc.decode("utf-8")) sftp.close() cmd(shell, "/file print where name~\"wifi-otantik\"") cmd(shell, "/import file-name=wifi-otantik-direct.rsc", timeout=60) cmd(shell, "/interface wireguard print") cmd(shell, "/interface wireguard peers print") cmd(shell, "/ip address print where comment=wifi-otantik") cmd(shell, "/ip route print where comment=wifi-otantik-wg") cmd(shell, "/ping 10.88.0.1 count=3") mk.close() jump.close() if __name__ == "__main__": main()