netstack_test.go 29 KB

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