wgengine/netstack: deliver self-addressed packets via loopback
When a tsnet.Server dials its own Tailscale IP, TCP SYN packets are silently dropped. In inject(), outbound packets with dst=self fail the shouldSendToHost check and fall through to WireGuard, which has no peer for the node's own address. Fix this by detecting self-addressed packets in inject() using isLocalIP and delivering them back into gVisor's network stack as inbound packets via a new DeliverLoopback method on linkEndpoint. The outbound packet must be re-serialized into a new PacketBuffer because outbound packets have their headers parsed into separate views, but DeliverNetworkPacket expects raw unparsed data. Updates #18829 Signed-off-by: James Tucker <james@tailscale.com>
This commit is contained in:
committed by
James Tucker
parent
30e12310f1
commit
0fb207c3d0
@@ -1037,6 +1037,16 @@ func (ns *Impl) inject() {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Self-addressed packet: deliver back into gVisor directly
|
||||
// via the link endpoint's dispatcher, but only if the packet is not
|
||||
// earmarked for the host. Neither the inbound path (fakeTUN Write is a
|
||||
// no-op) nor the outbound path (WireGuard has no peer for our own IP)
|
||||
// can handle these.
|
||||
if ns.isSelfDst(pkt) {
|
||||
ns.linkEP.DeliverLoopback(pkt)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := ns.tundev.InjectOutboundPacketBuffer(pkt); err != nil {
|
||||
ns.logf("netstack inject outbound: %v", err)
|
||||
return
|
||||
@@ -1116,6 +1126,20 @@ func (ns *Impl) shouldSendToHost(pkt *stack.PacketBuffer) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isSelfDst reports whether pkt's destination IP is a local Tailscale IP
|
||||
// assigned to this node. This is used by inject() to detect self-addressed
|
||||
// packets that need loopback delivery.
|
||||
func (ns *Impl) isSelfDst(pkt *stack.PacketBuffer) bool {
|
||||
hdr := pkt.Network()
|
||||
switch v := hdr.(type) {
|
||||
case header.IPv4:
|
||||
return ns.isLocalIP(netip.AddrFrom4(v.DestinationAddress().As4()))
|
||||
case header.IPv6:
|
||||
return ns.isLocalIP(netip.AddrFrom16(v.DestinationAddress().As16()))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isLocalIP reports whether ip is a Tailscale IP assigned to this
|
||||
// node directly (but not a subnet-routed IP).
|
||||
func (ns *Impl) isLocalIP(ip netip.Addr) bool {
|
||||
|
||||
Reference in New Issue
Block a user