# Port forwards: named, ad hoc, --forward with a shell, port in use. config <<'EOF' resolver: strategies: [management_subnet, primary_ip] management_subnets: [10.231.1.0/24] ssh: default_user: ops forwards: web: {local: "18081:127.0.0.1:8081"} rules: - match: {kind: vm, instance: fsn} proxy_jump: ops@10.231.0.30 EOF tunnel_test() { # NAME PORT WANT ARGS... local name=$1 port=$2 want=$3 pid out shift 3 "$@" >"$HOME/tunnel.log" 2>&1 & pid=$! if wait_for 15 curl -sf "http://127.0.0.1:$port/"; then out=$(curl -s "http://127.0.0.1:$port/") [[ $out == *"$want"* ]] && ok "$name" || bad "$name" "curl: $out" else bad "$name" "tunnel did not open: $(cat "$HOME/tunnel.log")" fi kill "$pid" 2>/dev/null wait "$pid" 2>/dev/null } tunnel_test "named forward" 18081 "hello from fsn1-pve1" netssh tunnel fsn/fsn1-pve1.hoster.test web expect_out "tunnel notice" "forwarding -L 18081:127.0.0.1:8081 via fsn1-pve1.hoster.test" cat "$HOME/tunnel.log" tunnel_test "ad hoc spec through the bastion" 18082 "hello from web1" netssh tunnel fsn/web1 18082:127.0.0.1:8081 tunnel_test "--forward with a remote command" 18081 "hello from fsn1-pve2" netssh --forward web fsn/fsn1-pve2.hoster.test sleep 30 netssh tunnel fsn/fsn1-pve1.hoster.test web >/dev/null 2>&1 & holder=$! wait_for 15 curl -sf http://127.0.0.1:18081/ expect_fail "port in use fails instead of hanging" "Address in use" timeout 20 netssh tunnel fsn/fsn1-pve2.hoster.test web kill "$holder"; wait "$holder" 2>/dev/null expect_fail "unknown forward lists the configured ones" "available: web" netssh tunnel fsn/fsn1-pve1.hoster.test db expect_fail "tunnel without forward" "forwards for fsn/fsn1-pve1.hoster.test: web" netssh tunnel fsn/fsn1-pve1.hoster.test