diff --git a/bin/netvm-cdp-relay.py b/bin/netvm-cdp-relay.py new file mode 100755 index 0000000..883d866 --- /dev/null +++ b/bin/netvm-cdp-relay.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +"""TCP relay: listen on the netns veth IP:CDP_PORT, forward to 127.0.0.1:CDP_PORT. +Chromium binds DevTools to loopback only; this exposes it on the veth IP for +the host (and SSH-forwarded operators). Runs inside the netns. No dependencies. +Usage: netvm-cdp-relay.py +""" +import socket, threading, sys + +def pipe(src, dst): + try: + while True: + data = src.recv(65536) + if not data: + break + dst.sendall(data) + except OSError: + pass + finally: + for s in (src, dst): + try: s.shutdown(socket.SHUT_RDWR) + except OSError: pass + s.close() + +def handle(client, target): + try: + upstream = socket.create_connection(target, timeout=10) + except OSError: + client.close() + return + threading.Thread(target=pipe, args=(client, upstream), daemon=True).start() + pipe(upstream, client) + +def main(): + listen_ip, listen_port, target_ip, target_port = sys.argv[1], int(sys.argv[2]), sys.argv[3], int(sys.argv[4]) + srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + srv.bind((listen_ip, listen_port)) + srv.listen(16) + while True: + client, _ = srv.accept() + threading.Thread(target=handle, args=(client, (target_ip, target_port)), daemon=True).start() + +if __name__ == "__main__": + main() diff --git a/bin/netvm-node-down.sh b/bin/netvm-node-down.sh index 373b597..0e77682 100755 --- a/bin/netvm-node-down.sh +++ b/bin/netvm-node-down.sh @@ -5,6 +5,8 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" . "$SCRIPT_DIR/netvm-names.sh" netvm_names "${1:?usage: netvm-node-down.sh }" nsexec() { ip netns exec "$NETNS" "$@"; } +PIDFILE="/run/netvm-${NODE}-cdp-relay.pid" +if [ -f "$PIDFILE" ]; then kill "$(cat "$PIDFILE")" 2>/dev/null || true; rm -f "$PIDFILE"; fi nsexec ip link del "$WG" 2>/dev/null || true # inside netns first ip link del "$VETH" 2>/dev/null || true # also drops the netns-side peer ip link del "$WG" 2>/dev/null || true # stray host-side copy diff --git a/bin/netvm-node-up.sh b/bin/netvm-node-up.sh index 8787eda..3171bed 100755 --- a/bin/netvm-node-up.sh +++ b/bin/netvm-node-up.sh @@ -58,13 +58,18 @@ nsexec ip link set "$WG" up nsexec ip route replace default dev "$WG" nsexec ip -6 route replace default dev "$WG" 2>/dev/null || true -# CDP bridge: chromium binds DevTools to loopback only; redirect the veth -# IP:CDP_PORT there so the host (and SSH-forwarded operators) can reach it. -# (netns iptables is namespaced; rules vanish with the netns on down.) -nsexec sysctl -qw net.ipv4.conf.all.route_localnet=1 -nsexec sysctl -qw "net.ipv4.conf.${VPEER}.route_localnet=1" -nsexec iptables -t nat -C PREROUTING -d "$PEER_IP" -p tcp --dport "$CDP_PORT" -j REDIRECT --to-port "$CDP_PORT" 2>/dev/null || \ -nsexec iptables -t nat -A PREROUTING -d "$PEER_IP" -p tcp --dport "$CDP_PORT" -j REDIRECT --to-port "$CDP_PORT" +# CDP bridge: chromium binds DevTools to loopback only. A tiny TCP relay +# listens on the veth IP and forwards to loopback (empirically reliable; +# iptables REDIRECT to 127.0.0.1 did not establish). Supervised via pidfile. +PIDFILE="/run/netvm-${NODE}-cdp-relay.pid" +if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then + echo "cdp relay already running" +else + nsexec python3 "$SCRIPT_DIR/netvm-cdp-relay.py" "$PEER_IP" "$CDP_PORT" 127.0.0.1 "$CDP_PORT" \ + >/dev/null 2>&1 & + echo $! > "$PIDFILE" + echo "cdp relay started ($PEER_IP:$CDP_PORT -> 127.0.0.1:$CDP_PORT)" +fi # wait for handshake (first one can take ~10s) HS=""