netstack_test.go 31 KB

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