diff --git a/tests/mesh/run.sh b/tests/mesh/run.sh index d34abec7..ca4bb251 100755 --- a/tests/mesh/run.sh +++ b/tests/mesh/run.sh @@ -503,6 +503,10 @@ start_vms() { sleep 1 done done + # Each node's Tailscale client advertises the endpoints it finds for itself: its interface addresses, and the address a STUN server on a public DERP region sees it come from, which on a hosted runner is the runner's public address. That address hairpins back through the runner's NAT, and magicsock picks between it and the test network address by measured latency, with a bonus for a private address that sub-millisecond jitter can outweigh (betterAddr in wgengine/magicsock/endpoint.go of the pinned Tailscale), so which one a node uses varied between runs. STUN is UDP to port 3478, so it is dropped in every VM, as on a LAN whose NAT does not hairpin: a node then advertises only addresses of its own VM's interfaces (see assert_direct_paths), and DERP, over TCP, still carries the disco messages that set a direct path up. + for index in $(seq 1 "$node_count"); do + docker exec "$(vm "$index")" iptables -I OUTPUT 1 -p udp --dport 3478 -j DROP + done } # A Headscale server on this machine's Docker, at a fixed address on the test network, with a policy that lets the nodes register, reach each other and route pods; prints the API key and a join key on two lines. @@ -562,7 +566,7 @@ write_host_network_inventory() { # With host networking, every node's Tailscale client must reach every other node directly at that node's daemon's own address (its stand-in LAN address), not through a relay, and the node container must publish no port. assert_direct_paths() { - local index other status deadline + local index other status deadline own outside for index in $(seq 1 "$node_count"); do [ "$(docker_on "$index" inspect --format '{{.HostConfig.NetworkMode}}' "$(container "$index")")" = host ] || fail "$(container "$index") is not on the host network" [ -z "$(docker_on "$index" port "$(container "$index")")" ] || fail "$(container "$index") publishes ports: $(docker_on "$index" port "$(container "$index")")" @@ -577,6 +581,15 @@ assert_direct_paths() { echo " $(node_name "$index") -> $(node_name "$other"): $(echo "$status" | tail -n 1)" done done + # Every endpoint each node advertises for itself is an address of its own VM's interfaces (the test network address, and the bridges its Docker and k3s create): none is an address learnt over STUN, which belongs to the runner's NAT and would let its peers pick a path through it instead (see start_vms). tailscale status lists a node's own endpoints under Self.Addrs, and none for its peers (UpdateStatus in wgengine/magicsock/magicsock.go of the pinned Tailscale fills Self only). The node container is on its VM's host network, so the VM's interfaces are the node's. + for index in $(seq 1 "$node_count"); do + own=$(docker exec "$(vm "$index")" ip -o addr show | awk '{ split($4, parts, "/"); print parts[1] }') + status=$(docker_on "$index" exec "$(container "$index")" tailscale status --json