netstack_test.go 29 KB

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