From f39689ad35629263dff7172e0e93eccf2f987ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 5 Aug 2026 12:29:41 +0800 Subject: [PATCH] Fix input packets peer lookup InputPacket/InputPackets used the deprecated trie-only AllowedIPs.Lookup. With tailscale v1.102 a PeerByIPPacketFunc is installed and the trie is no longer populated, so every injected packet was unmatched. Use LookupFromPacket, and size the sequential sender scratch for full input batches instead of capping containers at the device batch size. --- device/send.go | 52 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/device/send.go b/device/send.go index 034aa95..d434788 100644 --- a/device/send.go +++ b/device/send.go @@ -403,8 +403,51 @@ func (device *Device) RoutineReadFromTUN() { // each), so without this cap a flood is buffered instead of dropped. const maxQueuedInputPackets = 2048 +func (device *Device) inputPacketPeer(destination []byte, packetSlices [][]byte) *Peer { + var src, dst netip.Addr + switch len(destination) { + case net.IPv4len: + dst = netip.AddrFrom4([4]byte(destination)) + var srcBytes [net.IPv4len]byte + if !gatherPacketBytes(packetSlices, IPv4offsetSrc, srcBytes[:]) { + return nil + } + src = netip.AddrFrom4(srcBytes) + case net.IPv6len: + dst = netip.AddrFrom16([16]byte(destination)) + var srcBytes [net.IPv6len]byte + if !gatherPacketBytes(packetSlices, IPv6offsetSrc, srcBytes[:]) { + return nil + } + src = netip.AddrFrom16(srcBytes) + default: + return nil + } + var ipPkt []byte + if len(packetSlices) == 1 { + ipPkt = packetSlices[0] + } + return device.allowedips.LookupFromPacket(src, dst, ipPkt) +} + +func gatherPacketBytes(packetSlices [][]byte, offset int, destination []byte) bool { + for _, packetSlice := range packetSlices { + if offset >= len(packetSlice) { + offset -= len(packetSlice) + continue + } + n := copy(destination, packetSlice[offset:]) + destination = destination[n:] + offset = 0 + if len(destination) == 0 { + return true + } + } + return false +} + func (device *Device) InputPacket(destination []byte, packetSlices [][]byte) { - peer := device.allowedips.Lookup(destination) + peer := device.inputPacketPeer(destination, packetSlices) if peer == nil { return } @@ -447,10 +490,9 @@ type InputPacketRef struct { func (device *Device) InputPackets(packets []*InputPacketRef) []*InputPacketRef { var unmatched []*InputPacketRef - batchSize := device.BatchSize() elemsByPeer := make(map[*Peer][]*QueueOutboundElementsContainer, len(packets)) for _, packetRef := range packets { - peer := device.allowedips.Lookup(packetRef.Destination) + peer := device.inputPacketPeer(packetRef.Destination, packetRef.PacketSlices) if peer == nil { unmatched = append(unmatched, packetRef) continue @@ -476,7 +518,7 @@ func (device *Device) InputPackets(packets []*InputPacketRef) []*InputPacketRef } elem.packet = packet[:n] containers := elemsByPeer[peer] - if len(containers) == 0 || len(containers[len(containers)-1].elems) >= batchSize { + if len(containers) == 0 || len(containers[len(containers)-1].elems) >= conn.IdealBatchSize { containers = append(containers, device.GetOutboundElementsContainer()) elemsByPeer[peer] = containers } @@ -678,7 +720,7 @@ func (peer *Peer) RoutineSequentialSender(maxBatchSize int) { }() device.log.Verbosef("%v - Routine: sequential sender - started", peer) - bufs := make([][]byte, 0, maxBatchSize) + bufs := make([][]byte, 0, max(maxBatchSize, conn.IdealBatchSize)) for elemsContainer := range peer.queue.outbound.c { if elemsContainer == nil {