netstack_test.go 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package netstack
  4. import (
  5. "context"
  6. "fmt"
  7. "maps"
  8. "net"
  9. "net/netip"
  10. "runtime"
  11. "testing"
  12. "time"
  13. "gvisor.dev/gvisor/pkg/buffer"
  14. "gvisor.dev/gvisor/pkg/tcpip"
  15. "gvisor.dev/gvisor/pkg/tcpip/header"
  16. "gvisor.dev/gvisor/pkg/tcpip/stack"
  17. "tailscale.com/envknob"
  18. "tailscale.com/ipn"
  19. "tailscale.com/ipn/ipnlocal"
  20. "tailscale.com/ipn/store/mem"
  21. "tailscale.com/metrics"
  22. "tailscale.com/net/netx"
  23. "tailscale.com/net/packet"
  24. "tailscale.com/net/tsaddr"
  25. "tailscale.com/net/tsdial"
  26. "tailscale.com/net/tstun"
  27. "tailscale.com/tsd"
  28. "tailscale.com/tstest"
  29. "tailscale.com/types/ipproto"
  30. "tailscale.com/types/logid"
  31. "tailscale.com/wgengine"
  32. "tailscale.com/wgengine/filter"
  33. )
  34. // TestInjectInboundLeak tests that injectInbound doesn't leak memory.
  35. // See https://github.com/tailscale/tailscale/issues/3762
  36. func TestInjectInboundLeak(t *testing.T) {
  37. tunDev := tstun.NewFake()
  38. dialer := new(tsdial.Dialer)
  39. logf := func(format string, args ...any) {
  40. if !t.Failed() {
  41. t.Logf(format, args...)
  42. }
  43. }
  44. sys := tsd.NewSystem()
  45. eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
  46. Tun: tunDev,
  47. Dialer: dialer,
  48. SetSubsystem: sys.Set,
  49. HealthTracker: sys.HealthTracker.Get(),
  50. Metrics: sys.UserMetricsRegistry(),
  51. EventBus: sys.Bus.Get(),
  52. })
  53. if err != nil {
  54. t.Fatal(err)
  55. }
  56. defer eng.Close()
  57. sys.Set(eng)
  58. sys.Set(new(mem.Store))
  59. tunWrap := sys.Tun.Get()
  60. lb, err := ipnlocal.NewLocalBackend(logf, logid.PublicID{}, sys, 0)
  61. if err != nil {
  62. t.Fatal(err)
  63. }
  64. t.Cleanup(lb.Shutdown)
  65. ns, err := Create(logf, tunWrap, eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get(), sys.ProxyMapper())
  66. if err != nil {
  67. t.Fatal(err)
  68. }
  69. defer ns.Close()
  70. ns.ProcessLocalIPs = true
  71. if err := ns.Start(lb); err != nil {
  72. t.Fatalf("Start: %v", err)
  73. }
  74. ns.atomicIsLocalIPFunc.Store(func(netip.Addr) bool { return true })
  75. pkt := &packet.Parsed{}
  76. const N = 10_000
  77. ms0 := getMemStats()
  78. for range N {
  79. outcome, _ := ns.injectInbound(pkt, tunWrap, nil)
  80. if outcome != filter.DropSilently {
  81. t.Fatalf("got outcome %v; want DropSilently", outcome)
  82. }
  83. }
  84. ms1 := getMemStats()
  85. if grew := int64(ms1.HeapObjects) - int64(ms0.HeapObjects); grew >= N {
  86. t.Fatalf("grew by %v (which is too much and >= the %v packets we sent)", grew, N)
  87. }
  88. }
  89. func getMemStats() (ms runtime.MemStats) {
  90. runtime.GC()
  91. runtime.ReadMemStats(&ms)
  92. return
  93. }
  94. func makeNetstack(tb testing.TB, config func(*Impl)) *Impl {
  95. tunDev := tstun.NewFake()
  96. sys := tsd.NewSystem()
  97. sys.Set(new(mem.Store))
  98. dialer := new(tsdial.Dialer)
  99. logf := tstest.WhileTestRunningLogger(tb)
  100. eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
  101. Tun: tunDev,
  102. Dialer: dialer,
  103. SetSubsystem: sys.Set,
  104. HealthTracker: sys.HealthTracker.Get(),
  105. Metrics: sys.UserMetricsRegistry(),
  106. EventBus: sys.Bus.Get(),
  107. })
  108. if err != nil {
  109. tb.Fatal(err)
  110. }
  111. tb.Cleanup(func() { eng.Close() })
  112. sys.Set(eng)
  113. ns, err := Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get(), sys.ProxyMapper())
  114. if err != nil {
  115. tb.Fatal(err)
  116. }
  117. tb.Cleanup(func() { ns.Close() })
  118. lb, err := ipnlocal.NewLocalBackend(logf, logid.PublicID{}, sys, 0)
  119. if err != nil {
  120. tb.Fatalf("NewLocalBackend: %v", err)
  121. }
  122. tb.Cleanup(lb.Shutdown)
  123. ns.atomicIsLocalIPFunc.Store(func(netip.Addr) bool { return true })
  124. if config != nil {
  125. config(ns)
  126. }
  127. if err := ns.Start(lb); err != nil {
  128. tb.Fatalf("Start: %v", err)
  129. }
  130. return ns
  131. }
  132. func TestShouldHandlePing(t *testing.T) {
  133. srcIP := netip.AddrFrom4([4]byte{1, 2, 3, 4})
  134. t.Run("ICMP4", func(t *testing.T) {
  135. dst := netip.MustParseAddr("5.6.7.8")
  136. icmph := packet.ICMP4Header{
  137. IP4Header: packet.IP4Header{
  138. IPProto: ipproto.ICMPv4,
  139. Src: srcIP,
  140. Dst: dst,
  141. },
  142. Type: packet.ICMP4EchoRequest,
  143. Code: packet.ICMP4NoCode,
  144. }
  145. _, payload := packet.ICMPEchoPayload(nil)
  146. icmpPing := packet.Generate(icmph, payload)
  147. pkt := &packet.Parsed{}
  148. pkt.Decode(icmpPing)
  149. impl := makeNetstack(t, func(impl *Impl) {
  150. impl.ProcessSubnets = true
  151. })
  152. pingDst, ok := impl.shouldHandlePing(pkt)
  153. if !ok {
  154. t.Errorf("expected shouldHandlePing==true")
  155. }
  156. if pingDst != dst {
  157. t.Errorf("got dst %s; want %s", pingDst, dst)
  158. }
  159. })
  160. t.Run("ICMP6-no-via", func(t *testing.T) {
  161. dst := netip.MustParseAddr("2a09:8280:1::4169")
  162. icmph := packet.ICMP6Header{
  163. IP6Header: packet.IP6Header{
  164. IPProto: ipproto.ICMPv6,
  165. Src: srcIP,
  166. Dst: dst,
  167. },
  168. Type: packet.ICMP6EchoRequest,
  169. Code: packet.ICMP6NoCode,
  170. }
  171. _, payload := packet.ICMPEchoPayload(nil)
  172. icmpPing := packet.Generate(icmph, payload)
  173. pkt := &packet.Parsed{}
  174. pkt.Decode(icmpPing)
  175. impl := makeNetstack(t, func(impl *Impl) {
  176. impl.ProcessSubnets = true
  177. })
  178. pingDst, ok := impl.shouldHandlePing(pkt)
  179. // Expect that we handle this since it's going out onto the
  180. // network.
  181. if !ok {
  182. t.Errorf("expected shouldHandlePing==true")
  183. }
  184. if pingDst != dst {
  185. t.Errorf("got dst %s; want %s", pingDst, dst)
  186. }
  187. })
  188. t.Run("ICMP6-tailscale-addr", func(t *testing.T) {
  189. dst := netip.MustParseAddr("fd7a:115c:a1e0:ab12::1")
  190. icmph := packet.ICMP6Header{
  191. IP6Header: packet.IP6Header{
  192. IPProto: ipproto.ICMPv6,
  193. Src: srcIP,
  194. Dst: dst,
  195. },
  196. Type: packet.ICMP6EchoRequest,
  197. Code: packet.ICMP6NoCode,
  198. }
  199. _, payload := packet.ICMPEchoPayload(nil)
  200. icmpPing := packet.Generate(icmph, payload)
  201. pkt := &packet.Parsed{}
  202. pkt.Decode(icmpPing)
  203. impl := makeNetstack(t, func(impl *Impl) {
  204. impl.ProcessSubnets = true
  205. })
  206. _, ok := impl.shouldHandlePing(pkt)
  207. // We don't handle this because it's a Tailscale IP and not 4via6
  208. if ok {
  209. t.Errorf("expected shouldHandlePing==false")
  210. }
  211. })
  212. // Handle pings for 4via6 addresses regardless of ProcessSubnets
  213. for _, subnets := range []bool{true, false} {
  214. t.Run("ICMP6-4via6-ProcessSubnets-"+fmt.Sprint(subnets), func(t *testing.T) {
  215. // The 4via6 route 10.1.1.0/24 siteid 7, and then the IP
  216. // 10.1.1.9 within that route.
  217. dst := netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:7:a01:109")
  218. expectedPingDst := netip.MustParseAddr("10.1.1.9")
  219. icmph := packet.ICMP6Header{
  220. IP6Header: packet.IP6Header{
  221. IPProto: ipproto.ICMPv6,
  222. Src: srcIP,
  223. Dst: dst,
  224. },
  225. Type: packet.ICMP6EchoRequest,
  226. Code: packet.ICMP6NoCode,
  227. }
  228. _, payload := packet.ICMPEchoPayload(nil)
  229. icmpPing := packet.Generate(icmph, payload)
  230. pkt := &packet.Parsed{}
  231. pkt.Decode(icmpPing)
  232. impl := makeNetstack(t, func(impl *Impl) {
  233. impl.ProcessSubnets = subnets
  234. })
  235. pingDst, ok := impl.shouldHandlePing(pkt)
  236. // Handled due to being 4via6
  237. if !ok {
  238. t.Errorf("expected shouldHandlePing==true")
  239. } else if pingDst != expectedPingDst {
  240. t.Errorf("got dst %s; want %s", pingDst, expectedPingDst)
  241. }
  242. })
  243. }
  244. }
  245. // looksLikeATailscaleSelfAddress reports whether addr looks like
  246. // a Tailscale self address, for tests.
  247. func looksLikeATailscaleSelfAddress(addr netip.Addr) bool {
  248. return addr.Is4() && tsaddr.IsTailscaleIP(addr) ||
  249. addr.Is6() && tsaddr.Tailscale4To6Range().Contains(addr)
  250. }
  251. func TestShouldProcessInbound(t *testing.T) {
  252. testCases := []struct {
  253. name string
  254. pkt *packet.Parsed
  255. afterStart func(*Impl) // optional; after Impl.Start is called
  256. beforeStart func(*Impl) // optional; before Impl.Start is called
  257. want bool
  258. runOnGOOS string
  259. }{
  260. {
  261. name: "ipv6-via",
  262. pkt: &packet.Parsed{
  263. IPVersion: 6,
  264. IPProto: ipproto.TCP,
  265. Src: netip.MustParseAddrPort("100.101.102.103:1234"),
  266. // $ tailscale debug via 7 10.1.1.9/24
  267. // fd7a:115c:a1e0:b1a:0:7:a01:109/120
  268. Dst: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:7:a01:109]:5678"),
  269. TCPFlags: packet.TCPSyn,
  270. },
  271. afterStart: func(i *Impl) {
  272. prefs := ipn.NewPrefs()
  273. prefs.AdvertiseRoutes = []netip.Prefix{
  274. // $ tailscale debug via 7 10.1.1.0/24
  275. // fd7a:115c:a1e0:b1a:0:7:a01:100/120
  276. netip.MustParsePrefix("fd7a:115c:a1e0:b1a:0:7:a01:100/120"),
  277. }
  278. i.lb.Start(ipn.Options{
  279. UpdatePrefs: prefs,
  280. })
  281. i.atomicIsLocalIPFunc.Store(looksLikeATailscaleSelfAddress)
  282. },
  283. beforeStart: func(i *Impl) {
  284. // This should be handled even if we're
  285. // otherwise not processing local IPs or
  286. // subnets.
  287. i.ProcessLocalIPs = false
  288. i.ProcessSubnets = false
  289. },
  290. want: true,
  291. },
  292. {
  293. name: "ipv6-via-not-advertised",
  294. pkt: &packet.Parsed{
  295. IPVersion: 6,
  296. IPProto: ipproto.TCP,
  297. Src: netip.MustParseAddrPort("100.101.102.103:1234"),
  298. // $ tailscale debug via 7 10.1.1.9/24
  299. // fd7a:115c:a1e0:b1a:0:7:a01:109/120
  300. Dst: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:7:a01:109]:5678"),
  301. TCPFlags: packet.TCPSyn,
  302. },
  303. afterStart: func(i *Impl) {
  304. prefs := ipn.NewPrefs()
  305. prefs.AdvertiseRoutes = []netip.Prefix{
  306. // tailscale debug via 7 10.1.2.0/24
  307. // fd7a:115c:a1e0:b1a:0:7:a01:200/120
  308. netip.MustParsePrefix("fd7a:115c:a1e0:b1a:0:7:a01:200/120"),
  309. }
  310. i.lb.Start(ipn.Options{
  311. UpdatePrefs: prefs,
  312. })
  313. },
  314. want: false,
  315. },
  316. {
  317. name: "tailscale-ssh-enabled",
  318. pkt: &packet.Parsed{
  319. IPVersion: 4,
  320. IPProto: ipproto.TCP,
  321. Src: netip.MustParseAddrPort("100.101.102.103:1234"),
  322. Dst: netip.MustParseAddrPort("100.101.102.104:22"),
  323. TCPFlags: packet.TCPSyn,
  324. },
  325. afterStart: func(i *Impl) {
  326. prefs := ipn.NewPrefs()
  327. prefs.RunSSH = true
  328. i.lb.Start(ipn.Options{
  329. UpdatePrefs: prefs,
  330. })
  331. i.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
  332. return addr.String() == "100.101.102.104" // Dst, above
  333. })
  334. },
  335. want: true,
  336. runOnGOOS: "linux",
  337. },
  338. {
  339. name: "tailscale-ssh-disabled",
  340. pkt: &packet.Parsed{
  341. IPVersion: 4,
  342. IPProto: ipproto.TCP,
  343. Src: netip.MustParseAddrPort("100.101.102.103:1234"),
  344. Dst: netip.MustParseAddrPort("100.101.102.104:22"),
  345. TCPFlags: packet.TCPSyn,
  346. },
  347. afterStart: func(i *Impl) {
  348. prefs := ipn.NewPrefs()
  349. prefs.RunSSH = false // default, but to be explicit
  350. i.lb.Start(ipn.Options{
  351. UpdatePrefs: prefs,
  352. })
  353. i.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
  354. return addr.String() == "100.101.102.104" // Dst, above
  355. })
  356. },
  357. want: false,
  358. },
  359. {
  360. name: "process-local-ips",
  361. pkt: &packet.Parsed{
  362. IPVersion: 4,
  363. IPProto: ipproto.TCP,
  364. Src: netip.MustParseAddrPort("100.101.102.103:1234"),
  365. Dst: netip.MustParseAddrPort("100.101.102.104:4567"),
  366. TCPFlags: packet.TCPSyn,
  367. },
  368. afterStart: func(i *Impl) {
  369. i.ProcessLocalIPs = true
  370. i.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
  371. return addr.String() == "100.101.102.104" // Dst, above
  372. })
  373. },
  374. want: true,
  375. },
  376. {
  377. name: "process-subnets",
  378. pkt: &packet.Parsed{
  379. IPVersion: 4,
  380. IPProto: ipproto.TCP,
  381. Src: netip.MustParseAddrPort("100.101.102.103:1234"),
  382. Dst: netip.MustParseAddrPort("10.1.2.3:4567"),
  383. TCPFlags: packet.TCPSyn,
  384. },
  385. beforeStart: func(i *Impl) {
  386. i.ProcessSubnets = true
  387. },
  388. afterStart: func(i *Impl) {
  389. // For testing purposes, assume all Tailscale
  390. // IPs are local; the Dst above is something
  391. // not in that range.
  392. i.atomicIsLocalIPFunc.Store(looksLikeATailscaleSelfAddress)
  393. },
  394. want: true,
  395. },
  396. {
  397. name: "peerapi-port-subnet-router", // see #6235
  398. pkt: &packet.Parsed{
  399. IPVersion: 4,
  400. IPProto: ipproto.TCP,
  401. Src: netip.MustParseAddrPort("100.101.102.103:1234"),
  402. Dst: netip.MustParseAddrPort("10.0.0.23:5555"),
  403. TCPFlags: packet.TCPSyn,
  404. },
  405. beforeStart: func(i *Impl) {
  406. // As if we were running on Linux where netstack isn't used.
  407. i.ProcessSubnets = false
  408. i.atomicIsLocalIPFunc.Store(func(netip.Addr) bool { return false })
  409. },
  410. afterStart: func(i *Impl) {
  411. prefs := ipn.NewPrefs()
  412. prefs.AdvertiseRoutes = []netip.Prefix{
  413. netip.MustParsePrefix("10.0.0.1/24"),
  414. }
  415. i.lb.Start(ipn.Options{
  416. UpdatePrefs: prefs,
  417. })
  418. // Set the PeerAPI port to the Dst port above.
  419. i.peerapiPort4Atomic.Store(5555)
  420. i.peerapiPort6Atomic.Store(5555)
  421. },
  422. want: false,
  423. },
  424. // TODO(andrew): test PeerAPI
  425. // TODO(andrew): test TCP packets without the SYN flag set
  426. }
  427. for _, tc := range testCases {
  428. t.Run(tc.name, func(t *testing.T) {
  429. if tc.runOnGOOS != "" && runtime.GOOS != tc.runOnGOOS {
  430. t.Skipf("skipping on GOOS=%v", runtime.GOOS)
  431. }
  432. impl := makeNetstack(t, tc.beforeStart)
  433. if tc.afterStart != nil {
  434. tc.afterStart(impl)
  435. }
  436. got := impl.shouldProcessInbound(tc.pkt, nil)
  437. if got != tc.want {
  438. t.Errorf("got shouldProcessInbound()=%v; want %v", got, tc.want)
  439. } else {
  440. t.Logf("OK: shouldProcessInbound() = %v", got)
  441. }
  442. })
  443. }
  444. }
  445. func tcp4syn(tb testing.TB, src, dst netip.Addr, sport, dport uint16) []byte {
  446. ip := header.IPv4(make([]byte, header.IPv4MinimumSize+header.TCPMinimumSize))
  447. ip.Encode(&header.IPv4Fields{
  448. Protocol: uint8(header.TCPProtocolNumber),
  449. TotalLength: header.IPv4MinimumSize + header.TCPMinimumSize,
  450. TTL: 64,
  451. SrcAddr: tcpip.AddrFrom4Slice(src.AsSlice()),
  452. DstAddr: tcpip.AddrFrom4Slice(dst.AsSlice()),
  453. })
  454. ip.SetChecksum(^ip.CalculateChecksum())
  455. if !ip.IsChecksumValid() {
  456. tb.Fatal("test broken; packet has incorrect IP checksum")
  457. }
  458. tcp := header.TCP(ip[header.IPv4MinimumSize:])
  459. tcp.Encode(&header.TCPFields{
  460. SrcPort: sport,
  461. DstPort: dport,
  462. SeqNum: 0,
  463. DataOffset: header.TCPMinimumSize,
  464. Flags: header.TCPFlagSyn,
  465. WindowSize: 65535,
  466. Checksum: 0,
  467. })
  468. xsum := header.PseudoHeaderChecksum(
  469. header.TCPProtocolNumber,
  470. tcpip.AddrFrom4Slice(src.AsSlice()),
  471. tcpip.AddrFrom4Slice(dst.AsSlice()),
  472. uint16(header.TCPMinimumSize),
  473. )
  474. tcp.SetChecksum(^tcp.CalculateChecksum(xsum))
  475. if !tcp.IsChecksumValid(tcpip.AddrFrom4Slice(src.AsSlice()), tcpip.AddrFrom4Slice(dst.AsSlice()), 0, 0) {
  476. tb.Fatal("test broken; packet has incorrect TCP checksum")
  477. }
  478. return ip
  479. }
  480. // makeHangDialer returns a dialer that notifies the returned channel when a
  481. // connection is dialed and then hangs until the test finishes.
  482. func makeHangDialer(tb testing.TB) (netx.DialFunc, chan struct{}) {
  483. done := make(chan struct{})
  484. tb.Cleanup(func() {
  485. close(done)
  486. })
  487. gotConn := make(chan struct{}, 1)
  488. fn := func(ctx context.Context, network, address string) (net.Conn, error) {
  489. // Signal that we have a new connection
  490. tb.Logf("hangDialer: called with network=%q address=%q", network, address)
  491. select {
  492. case gotConn <- struct{}{}:
  493. default:
  494. }
  495. // Hang until the test is done.
  496. select {
  497. case <-ctx.Done():
  498. tb.Logf("context done")
  499. case <-done:
  500. tb.Logf("function completed")
  501. }
  502. return nil, fmt.Errorf("canceled")
  503. }
  504. return fn, gotConn
  505. }
  506. // TestTCPForwardLimits verifies that the limits on the TCP forwarder work in a
  507. // success case (i.e. when we don't hit the limit).
  508. func TestTCPForwardLimits(t *testing.T) {
  509. envknob.Setenv("TS_DEBUG_NETSTACK", "true")
  510. impl := makeNetstack(t, func(impl *Impl) {
  511. impl.ProcessSubnets = true
  512. })
  513. dialFn, gotConn := makeHangDialer(t)
  514. impl.forwardDialFunc = dialFn
  515. prefs := ipn.NewPrefs()
  516. prefs.AdvertiseRoutes = []netip.Prefix{
  517. // This is the TEST-NET-1 IP block for use in documentation,
  518. // and should never actually be routable.
  519. netip.MustParsePrefix("192.0.2.0/24"),
  520. }
  521. impl.lb.Start(ipn.Options{
  522. UpdatePrefs: prefs,
  523. })
  524. impl.atomicIsLocalIPFunc.Store(looksLikeATailscaleSelfAddress)
  525. // Inject an "outbound" packet that's going to an IP address that times
  526. // out. We need to re-parse from a byte slice so that the internal
  527. // buffer in the packet.Parsed type is filled out.
  528. client := netip.MustParseAddr("100.101.102.103")
  529. destAddr := netip.MustParseAddr("192.0.2.1")
  530. pkt := tcp4syn(t, client, destAddr, 1234, 4567)
  531. var parsed packet.Parsed
  532. parsed.Decode(pkt)
  533. // When injecting this packet, we want the outcome to be "drop
  534. // silently", which indicates that netstack is processing the
  535. // packet and not delivering it to the host system.
  536. if resp, _ := impl.injectInbound(&parsed, impl.tundev, nil); resp != filter.DropSilently {
  537. t.Errorf("got filter outcome %v, want filter.DropSilently", resp)
  538. }
  539. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  540. defer cancel()
  541. // Wait until we have an in-flight outgoing connection.
  542. select {
  543. case <-ctx.Done():
  544. t.Fatalf("timed out waiting for connection")
  545. case <-gotConn:
  546. t.Logf("got connection in progress")
  547. }
  548. // Inject another packet, which will be deduplicated and thus not
  549. // increment our counter.
  550. parsed.Decode(pkt)
  551. if resp, _ := impl.injectInbound(&parsed, impl.tundev, nil); resp != filter.DropSilently {
  552. t.Errorf("got filter outcome %v, want filter.DropSilently", resp)
  553. }
  554. // Verify that we now have a single in-flight address in our map.
  555. impl.mu.Lock()
  556. inFlight := maps.Clone(impl.connsInFlightByClient)
  557. impl.mu.Unlock()
  558. if got, ok := inFlight[client]; !ok || got != 1 {
  559. t.Errorf("expected 1 in-flight connection for %v, got: %v", client, inFlight)
  560. }
  561. // Get the expvar statistics and verify that we're exporting the
  562. // correct metric.
  563. metrics := impl.ExpVar().(*metrics.Set)
  564. const metricName = "gauge_tcp_forward_in_flight"
  565. if v := metrics.Get(metricName).String(); v != "1" {
  566. t.Errorf("got metric %q=%s, want 1", metricName, v)
  567. }
  568. }
  569. // TestTCPForwardLimits_PerClient verifies that the per-client limit for TCP
  570. // forwarding works.
  571. func TestTCPForwardLimits_PerClient(t *testing.T) {
  572. envknob.Setenv("TS_DEBUG_NETSTACK", "true")
  573. // Set our test override limits during this test.
  574. tstest.Replace(t, &maxInFlightConnectionAttemptsForTest, 2)
  575. tstest.Replace(t, &maxInFlightConnectionAttemptsPerClientForTest, 1)
  576. impl := makeNetstack(t, func(impl *Impl) {
  577. impl.ProcessSubnets = true
  578. })
  579. dialFn, gotConn := makeHangDialer(t)
  580. impl.forwardDialFunc = dialFn
  581. prefs := ipn.NewPrefs()
  582. prefs.AdvertiseRoutes = []netip.Prefix{
  583. // This is the TEST-NET-1 IP block for use in documentation,
  584. // and should never actually be routable.
  585. netip.MustParsePrefix("192.0.2.0/24"),
  586. }
  587. impl.lb.Start(ipn.Options{
  588. UpdatePrefs: prefs,
  589. })
  590. impl.atomicIsLocalIPFunc.Store(looksLikeATailscaleSelfAddress)
  591. // Inject an "outbound" packet that's going to an IP address that times
  592. // out. We need to re-parse from a byte slice so that the internal
  593. // buffer in the packet.Parsed type is filled out.
  594. client := netip.MustParseAddr("100.101.102.103")
  595. destAddr := netip.MustParseAddr("192.0.2.1")
  596. // Helpers
  597. var port uint16 = 1234
  598. mustInjectPacket := func() {
  599. pkt := tcp4syn(t, client, destAddr, port, 4567)
  600. port++ // to avoid deduplication based on endpoint
  601. var parsed packet.Parsed
  602. parsed.Decode(pkt)
  603. // When injecting this packet, we want the outcome to be "drop
  604. // silently", which indicates that netstack is processing the
  605. // packet and not delivering it to the host system.
  606. if resp, _ := impl.injectInbound(&parsed, impl.tundev, nil); resp != filter.DropSilently {
  607. t.Fatalf("got filter outcome %v, want filter.DropSilently", resp)
  608. }
  609. }
  610. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  611. defer cancel()
  612. waitPacket := func() {
  613. select {
  614. case <-ctx.Done():
  615. t.Fatalf("timed out waiting for connection")
  616. case <-gotConn:
  617. t.Logf("got connection in progress")
  618. }
  619. }
  620. // Inject the packet to start the TCP forward and wait until we have an
  621. // in-flight outgoing connection.
  622. mustInjectPacket()
  623. waitPacket()
  624. // Verify that we now have a single in-flight address in our map.
  625. impl.mu.Lock()
  626. inFlight := maps.Clone(impl.connsInFlightByClient)
  627. impl.mu.Unlock()
  628. if got, ok := inFlight[client]; !ok || got != 1 {
  629. t.Errorf("expected 1 in-flight connection for %v, got: %v", client, inFlight)
  630. }
  631. metrics := impl.ExpVar().(*metrics.Set)
  632. // One client should have reached the limit at this point.
  633. if v := metrics.Get("gauge_tcp_forward_in_flight_per_client_limit_reached").String(); v != "1" {
  634. t.Errorf("got limit reached expvar metric=%s, want 1", v)
  635. }
  636. // Inject another packet, and verify that we've incremented our
  637. // "dropped" metrics since this will have been dropped.
  638. mustInjectPacket()
  639. // expvar metric
  640. const metricName = "counter_tcp_forward_max_in_flight_per_client_drop"
  641. if v := metrics.Get(metricName).String(); v != "1" {
  642. t.Errorf("got expvar metric %q=%s, want 1", metricName, v)
  643. }
  644. // client metric
  645. if v := metricPerClientForwardLimit.Value(); v != 1 {
  646. t.Errorf("got clientmetric limit metric=%d, want 1", v)
  647. }
  648. }
  649. // TestHandleLocalPackets tests the handleLocalPackets function, ensuring that
  650. // we are properly deciding to handle packets that are destined for "local"
  651. // IPs–addresses that are either for this node, or that it is responsible for.
  652. //
  653. // See, e.g. #11304
  654. func TestHandleLocalPackets(t *testing.T) {
  655. var (
  656. selfIP4 = netip.MustParseAddr("100.64.1.2")
  657. selfIP6 = netip.MustParseAddr("fd7a:115c:a1e0::123")
  658. )
  659. impl := makeNetstack(t, func(impl *Impl) {
  660. impl.ProcessSubnets = false
  661. impl.ProcessLocalIPs = false
  662. impl.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
  663. return addr == selfIP4 || addr == selfIP6
  664. })
  665. })
  666. prefs := ipn.NewPrefs()
  667. prefs.AdvertiseRoutes = []netip.Prefix{
  668. // $ tailscale debug via 7 10.1.1.0/24
  669. // fd7a:115c:a1e0:b1a:0:7:a01:100/120
  670. netip.MustParsePrefix("fd7a:115c:a1e0:b1a:0:7:a01:100/120"),
  671. }
  672. _, err := impl.lb.EditPrefs(&ipn.MaskedPrefs{
  673. Prefs: *prefs,
  674. AdvertiseRoutesSet: true,
  675. })
  676. if err != nil {
  677. t.Fatalf("EditPrefs: %v", err)
  678. }
  679. t.Run("ShouldHandleServiceIP", func(t *testing.T) {
  680. pkt := &packet.Parsed{
  681. IPVersion: 4,
  682. IPProto: ipproto.TCP,
  683. Src: netip.MustParseAddrPort("127.0.0.1:9999"),
  684. Dst: netip.MustParseAddrPort("100.100.100.100:53"),
  685. TCPFlags: packet.TCPSyn,
  686. }
  687. resp, _ := impl.handleLocalPackets(pkt, impl.tundev, nil)
  688. if resp != filter.DropSilently {
  689. t.Errorf("got filter outcome %v, want filter.DropSilently", resp)
  690. }
  691. })
  692. t.Run("ShouldHandle4via6", func(t *testing.T) {
  693. pkt := &packet.Parsed{
  694. IPVersion: 6,
  695. IPProto: ipproto.TCP,
  696. Src: netip.MustParseAddrPort("[::1]:1234"),
  697. // This is an IP in the above 4via6 subnet that this node handles.
  698. // $ tailscale debug via 7 10.1.1.9/24
  699. // fd7a:115c:a1e0:b1a:0:7:a01:109/120
  700. Dst: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:7:a01:109]:5678"),
  701. TCPFlags: packet.TCPSyn,
  702. }
  703. resp, _ := impl.handleLocalPackets(pkt, impl.tundev, nil)
  704. // DropSilently is the outcome we expected, since we actually
  705. // handled this packet by injecting it into netstack, which
  706. // will handle creating the TCP forwarder. We drop it so we
  707. // don't process the packet outside of netstack.
  708. if resp != filter.DropSilently {
  709. t.Errorf("got filter outcome %v, want filter.DropSilently", resp)
  710. }
  711. })
  712. t.Run("OtherNonHandled", func(t *testing.T) {
  713. pkt := &packet.Parsed{
  714. IPVersion: 6,
  715. IPProto: ipproto.TCP,
  716. Src: netip.MustParseAddrPort("[::1]:1234"),
  717. // This IP is *not* in the above 4via6 route
  718. // $ tailscale debug via 99 10.1.1.9/24
  719. // fd7a:115c:a1e0:b1a:0:63:a01:109/120
  720. Dst: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:63:a01:109]:5678"),
  721. TCPFlags: packet.TCPSyn,
  722. }
  723. resp, _ := impl.handleLocalPackets(pkt, impl.tundev, nil)
  724. // Accept means that handleLocalPackets does not handle this
  725. // packet, we "accept" it to continue further processing,
  726. // instead of dropping because it was already handled.
  727. if resp != filter.Accept {
  728. t.Errorf("got filter outcome %v, want filter.Accept", resp)
  729. }
  730. })
  731. }
  732. func TestShouldSendToHost(t *testing.T) {
  733. var (
  734. selfIP4 = netip.MustParseAddr("100.64.1.2")
  735. selfIP6 = netip.MustParseAddr("fd7a:115c:a1e0::123")
  736. )
  737. makeTestNetstack := func(tb testing.TB) *Impl {
  738. impl := makeNetstack(tb, func(impl *Impl) {
  739. impl.ProcessSubnets = false
  740. impl.ProcessLocalIPs = false
  741. impl.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
  742. return addr == selfIP4 || addr == selfIP6
  743. })
  744. })
  745. prefs := ipn.NewPrefs()
  746. prefs.AdvertiseRoutes = []netip.Prefix{
  747. // $ tailscale debug via 7 10.1.1.0/24
  748. // fd7a:115c:a1e0:b1a:0:7:a01:100/120
  749. netip.MustParsePrefix("fd7a:115c:a1e0:b1a:0:7:a01:100/120"),
  750. }
  751. _, err := impl.lb.EditPrefs(&ipn.MaskedPrefs{
  752. Prefs: *prefs,
  753. AdvertiseRoutesSet: true,
  754. })
  755. if err != nil {
  756. tb.Fatalf("EditPrefs: %v", err)
  757. }
  758. return impl
  759. }
  760. testCases := []struct {
  761. name string
  762. src, dst netip.AddrPort
  763. want bool
  764. }{
  765. // Reply from service IP to localhost should be sent to host,
  766. // not over WireGuard.
  767. {
  768. name: "from_service_ip_to_localhost",
  769. src: netip.AddrPortFrom(serviceIP, 53),
  770. dst: netip.MustParseAddrPort("127.0.0.1:9999"),
  771. want: true,
  772. },
  773. {
  774. name: "from_service_ip_to_localhost_v6",
  775. src: netip.AddrPortFrom(serviceIPv6, 53),
  776. dst: netip.MustParseAddrPort("[::1]:9999"),
  777. want: true,
  778. },
  779. // A reply from the local IP to a remote host isn't sent to the
  780. // host, but rather over WireGuard.
  781. {
  782. name: "local_ip_to_remote",
  783. src: netip.AddrPortFrom(selfIP4, 12345),
  784. dst: netip.MustParseAddrPort("100.64.99.88:7777"),
  785. want: false,
  786. },
  787. {
  788. name: "local_ip_to_remote_v6",
  789. src: netip.AddrPortFrom(selfIP6, 12345),
  790. dst: netip.MustParseAddrPort("[fd7a:115:a1e0::99]:7777"),
  791. want: false,
  792. },
  793. // A reply from a 4via6 address to a remote host isn't sent to
  794. // the local host, but rather over WireGuard. See:
  795. // https://github.com/tailscale/tailscale/issues/12448
  796. {
  797. name: "4via6_to_remote",
  798. // $ tailscale debug via 7 10.1.1.99/24
  799. // fd7a:115c:a1e0:b1a:0:7:a01:163/120
  800. src: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:7:a01:163]:12345"),
  801. dst: netip.MustParseAddrPort("[fd7a:115:a1e0::99]:7777"),
  802. want: false,
  803. },
  804. // However, a reply from a 4via6 address to the local Tailscale
  805. // IP for this host *is* sent to the local host. See:
  806. // https://github.com/tailscale/tailscale/issues/11304
  807. {
  808. name: "4via6_to_local",
  809. // $ tailscale debug via 7 10.1.1.99/24
  810. // fd7a:115c:a1e0:b1a:0:7:a01:163/120
  811. src: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:7:a01:163]:12345"),
  812. dst: netip.AddrPortFrom(selfIP6, 7777),
  813. want: true,
  814. },
  815. // Traffic from a 4via6 address that we're not handling to
  816. // either the local Tailscale IP or a remote host is sent
  817. // outbound.
  818. //
  819. // In most cases, we won't see this type of traffic in the
  820. // shouldSendToHost function, but let's confirm.
  821. {
  822. name: "other_4via6_to_local",
  823. // $ tailscale debug via 4444 10.1.1.88/24
  824. // fd7a:115c:a1e0:b1a:0:7:a01:163/120
  825. src: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:115c:a01:158]:12345"),
  826. dst: netip.AddrPortFrom(selfIP6, 7777),
  827. want: false,
  828. },
  829. {
  830. name: "other_4via6_to_remote",
  831. // $ tailscale debug via 4444 10.1.1.88/24
  832. // fd7a:115c:a1e0:b1a:0:7:a01:163/120
  833. src: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:115c:a01:158]:12345"),
  834. dst: netip.MustParseAddrPort("[fd7a:115:a1e0::99]:7777"),
  835. want: false,
  836. },
  837. }
  838. for _, tt := range testCases {
  839. t.Run(tt.name, func(t *testing.T) {
  840. var pkt *stack.PacketBuffer
  841. if tt.src.Addr().Is4() {
  842. pkt = makeUDP4PacketBuffer(tt.src, tt.dst)
  843. } else {
  844. pkt = makeUDP6PacketBuffer(tt.src, tt.dst)
  845. }
  846. ns := makeTestNetstack(t)
  847. if got := ns.shouldSendToHost(pkt); got != tt.want {
  848. t.Errorf("shouldSendToHost returned %v, want %v", got, tt.want)
  849. }
  850. })
  851. }
  852. }
  853. func makeUDP4PacketBuffer(src, dst netip.AddrPort) *stack.PacketBuffer {
  854. if !src.Addr().Is4() || !dst.Addr().Is4() {
  855. panic("src and dst must be IPv4")
  856. }
  857. data := []byte("hello world\n")
  858. packetLen := header.IPv4MinimumSize + header.UDPMinimumSize
  859. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  860. ReserveHeaderBytes: packetLen,
  861. Payload: buffer.MakeWithData(data),
  862. })
  863. // Initialize the UDP header.
  864. udp := header.UDP(pkt.TransportHeader().Push(header.UDPMinimumSize))
  865. pkt.TransportProtocolNumber = header.UDPProtocolNumber
  866. length := uint16(pkt.Size())
  867. udp.Encode(&header.UDPFields{
  868. SrcPort: src.Port(),
  869. DstPort: dst.Port(),
  870. Length: length,
  871. })
  872. // Add IP header
  873. ipHdr := header.IPv4(pkt.NetworkHeader().Push(header.IPv4MinimumSize))
  874. pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber
  875. ipHdr.Encode(&header.IPv4Fields{
  876. TotalLength: uint16(packetLen),
  877. Protocol: uint8(header.UDPProtocolNumber),
  878. SrcAddr: tcpip.AddrFrom4(src.Addr().As4()),
  879. DstAddr: tcpip.AddrFrom4(dst.Addr().As4()),
  880. Checksum: 0,
  881. })
  882. return pkt
  883. }
  884. func makeUDP6PacketBuffer(src, dst netip.AddrPort) *stack.PacketBuffer {
  885. if !src.Addr().Is6() || !dst.Addr().Is6() {
  886. panic("src and dst must be IPv6")
  887. }
  888. data := []byte("hello world\n")
  889. packetLen := header.IPv6MinimumSize + header.UDPMinimumSize
  890. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  891. ReserveHeaderBytes: packetLen,
  892. Payload: buffer.MakeWithData(data),
  893. })
  894. srcAddr := tcpip.AddrFrom16(src.Addr().As16())
  895. dstAddr := tcpip.AddrFrom16(dst.Addr().As16())
  896. // Add IP header
  897. ipHdr := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize))
  898. pkt.NetworkProtocolNumber = header.IPv6ProtocolNumber
  899. ipHdr.Encode(&header.IPv6Fields{
  900. SrcAddr: srcAddr,
  901. DstAddr: dstAddr,
  902. PayloadLength: uint16(header.UDPMinimumSize + len(data)),
  903. TransportProtocol: header.UDPProtocolNumber,
  904. HopLimit: 64,
  905. })
  906. // Initialize the UDP header.
  907. udp := header.UDP(pkt.TransportHeader().Push(header.UDPMinimumSize))
  908. pkt.TransportProtocolNumber = header.UDPProtocolNumber
  909. length := uint16(pkt.Size())
  910. udp.Encode(&header.UDPFields{
  911. SrcPort: src.Port(),
  912. DstPort: dst.Port(),
  913. Length: length,
  914. })
  915. // Calculate the UDP pseudo-header checksum.
  916. xsum := header.PseudoHeaderChecksum(header.UDPProtocolNumber, srcAddr, dstAddr, uint16(len(udp)))
  917. udp.SetChecksum(^udp.CalculateChecksum(xsum))
  918. return pkt
  919. }