2
0

netstack_test.go 29 KB

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