handleLocalPackets is hooked into the tun datapath for packets leaving the host and arriving at tailscaled. This method returns filter.DropSilently to intercept a packet for handling, for instance traffic to quad-100. Caution: can be called before Start
(p *packet.Parsed, t *tstun.Wrapper, gro *gro.GRO)
| 840 | // to intercept a packet for handling, for instance traffic to quad-100. |
| 841 | // Caution: can be called before Start |
| 842 | func (ns *Impl) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper, gro *gro.GRO) (filter.Response, *gro.GRO) { |
| 843 | if !ns.ready.Load() || ns.ctx.Err() != nil { |
| 844 | return filter.DropSilently, gro |
| 845 | } |
| 846 | |
| 847 | // Determine if we care about this local packet. |
| 848 | dst := p.Dst.Addr() |
| 849 | serviceName, isVIPServiceIP := ns.atomicIPVIPServiceMap.Load()[dst] |
| 850 | switch { |
| 851 | case dst == serviceIP || dst == serviceIPv6: |
| 852 | // Traffic to the Tailscale service IP (100.100.100.100 / |
| 853 | // fd7a:115c:a1e0::53) is always terminated locally on this |
| 854 | // node; it must never be forwarded out over WireGuard to a |
| 855 | // peer. Netstack's TCP/UDP acceptors handle the ports we |
| 856 | // actually serve (UDP 53 MagicDNS, TCP 53/80/8080 for DNS, |
| 857 | // the web client, and Taildrive, plus any debug loopback |
| 858 | // port). Other ports are rejected cleanly by netstack: UDP |
| 859 | // closes the endpoint in acceptUDP, and TCP is RST'd by |
| 860 | // acceptTCP's hittingServiceIP guard. |
| 861 | // |
| 862 | // Previously we returned filter.Accept for TCP/UDP on any |
| 863 | // other port, which let the packet fall through to the ACL |
| 864 | // filter and ultimately wireguard-go, where no peer owns the |
| 865 | // quad-100 AllowedIP. That produced noisy "open-conn-track: |
| 866 | // timeout opening ...; no associated peer node" log lines |
| 867 | // (e.g. for stray traffic to 100.100.100.100:853 / DoT) and |
| 868 | // leaked quad-100 packets onto the tailnet. |
| 869 | // |
| 870 | // We now unconditionally absorb quad-100 into netstack here, |
| 871 | // regardless of IP protocol or port, so such traffic never |
| 872 | // reaches the conntrack / peer-routing layers. |
| 873 | case isVIPServiceIP: |
| 874 | // returns all active VIP services in a set, since the IPVIPServiceMap |
| 875 | // contains inactive service IPs when node hosts the service, we need to |
| 876 | // check the service is active or not before dropping the packet. |
| 877 | activeServices := ns.atomicActiveVIPServices.Load() |
| 878 | if !activeServices.Contains(serviceName) { |
| 879 | // Other host might have the service active, so we let the packet go through. |
| 880 | return filter.Accept, gro |
| 881 | } |
| 882 | if p.IPProto != ipproto.TCP { |
| 883 | // We currenly only support VIP services over TCP. If service is in Tun mode, |
| 884 | // it's up to the service host to set up local packet handling which shouldn't |
| 885 | // arrive here. |
| 886 | return filter.DropSilently, gro |
| 887 | } |
| 888 | if debugNetstack() { |
| 889 | ns.logf("netstack: intercepting local VIP service packet: proto=%v dst=%v src=%v", |
| 890 | p.IPProto, p.Dst, p.Src) |
| 891 | } |
| 892 | case viaRange.Contains(dst): |
| 893 | // We need to handle 4via6 packets leaving the host if the via |
| 894 | // route is for this host; otherwise the packet will be dropped |
| 895 | // because nothing will translate it. |
| 896 | var shouldHandle bool |
| 897 | if p.IPVersion == 6 && !ns.isLocalIP(dst) { |
| 898 | shouldHandle = ns.lb != nil && ns.lb.ShouldHandleViaIP(dst) |
| 899 | } |