router.go 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. //go:build e2e_testing
  2. package router
  3. import (
  4. "context"
  5. "fmt"
  6. "maps"
  7. "net/netip"
  8. "os"
  9. "path/filepath"
  10. "reflect"
  11. "regexp"
  12. "slices"
  13. "sort"
  14. "sync"
  15. "sync/atomic"
  16. "testing"
  17. "time"
  18. "github.com/google/gopacket"
  19. "github.com/google/gopacket/layers"
  20. "github.com/slackhq/nebula"
  21. "github.com/slackhq/nebula/header"
  22. "github.com/slackhq/nebula/udp"
  23. )
  24. // outNatKey is the (from, to) pair used by outNat. Comparable struct, so it works as a map key without the
  25. // allocation cost of a string-concat key.
  26. type outNatKey struct {
  27. from, to netip.AddrPort
  28. }
  29. // fannedPacket pairs a UDP TX packet with its source control so the router can route it after popping from
  30. // the fan-in channel.
  31. type fannedPacket struct {
  32. from *nebula.Control
  33. pkt *udp.Packet
  34. }
  35. type R struct {
  36. // Simple map of the ip:port registered on a control to the control
  37. // Basically a router, right?
  38. controls map[netip.AddrPort]*nebula.Control
  39. // A map for inbound packets for a control that doesn't know about this address
  40. inNat map[netip.AddrPort]*nebula.Control
  41. // A last used map, if an inbound packet hit the inNat map then
  42. // all return packets should use the same last used inbound address for the outbound sender
  43. outNat map[outNatKey]netip.AddrPort
  44. // A map of vpn ip to the nebula control it belongs to
  45. vpnControls map[netip.Addr]*nebula.Control
  46. // Cached select infrastructure for RouteForAllUntilTxTun.
  47. // The controls map is immutable after NewR so the cases are good for the test lifetime.
  48. // We only rebuild if a different receiver is asked.
  49. selRecvCtl *nebula.Control
  50. selCases []reflect.SelectCase
  51. selCtls []*nebula.Control
  52. // Optional fan-in mode for hot-path benchmarks: one forwarder goroutine per control drains UDP TX into udpFanIn,
  53. // so RouteForAllUntilTxTun can do a fixed 2-way native select instead of paying reflect.Select per call.
  54. // Off by default (would otherwise interleave with tests that use GetFromUDP directly on the same control).
  55. // Enabled by EnableFanIn.
  56. udpFanIn chan fannedPacket
  57. stopFanIn chan struct{}
  58. fanInWG sync.WaitGroup
  59. fanInMu sync.Mutex
  60. fanInOn atomic.Bool
  61. ignoreFlows []ignoreFlow
  62. flow []flowEntry
  63. // A set of additional mermaid graphs to draw in the flow log markdown file
  64. // Currently consisting only of hostmap renders
  65. additionalGraphs []mermaidGraph
  66. // All interactions are locked to help serialize behavior
  67. sync.Mutex
  68. fn string
  69. cancelRender context.CancelFunc
  70. t testing.TB
  71. }
  72. type ignoreFlow struct {
  73. tun NullBool
  74. messageType header.MessageType
  75. subType header.MessageSubType
  76. //from
  77. //to
  78. }
  79. type mermaidGraph struct {
  80. title string
  81. content string
  82. }
  83. type NullBool struct {
  84. HasValue bool
  85. IsTrue bool
  86. }
  87. type flowEntry struct {
  88. note string
  89. packet *packet
  90. }
  91. type packet struct {
  92. from *nebula.Control
  93. to *nebula.Control
  94. packet *udp.Packet
  95. tun bool // a packet pulled off a tun device
  96. rx bool // the packet was received by a udp device
  97. // h is the nebula header, parsed once when the packet is recorded. parseErr says why there isn't one, which
  98. // the flow log reports rather than hiding. Punchy sends a single byte, so an unparseable packet is normal.
  99. h header.H
  100. parseErr error
  101. }
  102. // fromAddr and toAddr are the addresses this packet actually travelled between. Reading them off the control
  103. // instead would misreport the whole history once a test moves a node. Tun packets are synthesized without
  104. // addresses, so they fall back to the control.
  105. func (p *packet) fromAddr() netip.AddrPort {
  106. if p.tun || !p.packet.From.IsValid() {
  107. return p.from.GetUDPAddr()
  108. }
  109. return p.packet.From
  110. }
  111. func (p *packet) toAddr() netip.AddrPort {
  112. if p.tun || !p.packet.To.IsValid() {
  113. return p.to.GetUDPAddr()
  114. }
  115. return p.packet.To
  116. }
  117. func (p *packet) WasReceived() {
  118. if p != nil {
  119. p.rx = true
  120. }
  121. }
  122. type ExitType int
  123. const (
  124. // KeepRouting the function will get called again on the next packet
  125. KeepRouting ExitType = 0
  126. // ExitNow does not route this packet and exits immediately
  127. ExitNow ExitType = 1
  128. // RouteAndExit routes this packet and exits immediately afterwards
  129. RouteAndExit ExitType = 2
  130. // Drop discards this packet without delivering it and keeps routing. Use it to simulate a blackhole, such as
  131. // a restrictive NAT refusing traffic from an address it has not seen.
  132. Drop ExitType = 3
  133. )
  134. type ExitFunc func(packet *udp.Packet, receiver *nebula.Control) ExitType
  135. // NewR creates a new router to pass packets in a controlled fashion between the provided controllers.
  136. // The packet flow will be recorded in a file within the mermaid directory under the same name as the test.
  137. // Renders will occur automatically, roughly every 100ms, until a call to RenderFlow() is made
  138. func NewR(t testing.TB, controls ...*nebula.Control) *R {
  139. ctx, cancel := context.WithCancel(context.Background())
  140. // t.Name() contains a slash for subtests, so the flow log can land in a nested directory
  141. fn := filepath.Join("mermaid", fmt.Sprintf("%s.md", t.Name()))
  142. if err := os.MkdirAll(filepath.Dir(fn), 0755); err != nil {
  143. panic(err)
  144. }
  145. r := &R{
  146. controls: make(map[netip.AddrPort]*nebula.Control),
  147. vpnControls: make(map[netip.Addr]*nebula.Control),
  148. inNat: make(map[netip.AddrPort]*nebula.Control),
  149. outNat: make(map[outNatKey]netip.AddrPort),
  150. flow: []flowEntry{},
  151. ignoreFlows: []ignoreFlow{},
  152. fn: fn,
  153. t: t,
  154. cancelRender: cancel,
  155. }
  156. // Try to remove our render file
  157. os.Remove(r.fn)
  158. for _, c := range controls {
  159. addr := c.GetUDPAddr()
  160. if _, ok := r.controls[addr]; ok {
  161. panic("Duplicate listen address: " + addr.String())
  162. }
  163. for _, vpnAddr := range c.GetVpnAddrs() {
  164. r.vpnControls[vpnAddr] = c
  165. }
  166. r.controls[addr] = c
  167. }
  168. // Spin the renderer in case we go nuts and the test never completes
  169. go func() {
  170. clockSource := time.NewTicker(time.Millisecond * 100)
  171. defer clockSource.Stop()
  172. for {
  173. select {
  174. case <-ctx.Done():
  175. return
  176. case <-clockSource.C:
  177. r.Lock()
  178. r.renderHostmaps("clock tick")
  179. r.renderFlow()
  180. r.Unlock()
  181. }
  182. }
  183. }()
  184. return r
  185. }
  186. // AddRoute will place the nebula controller at the ip and port specified.
  187. // It does not look at the addr attached to the instance.
  188. // If a route is used, this will behave like a NAT for the return path.
  189. // Rewriting the source ip:port to what was last sent to from the origin
  190. func (r *R) AddRoute(ip netip.Addr, port uint16, c *nebula.Control) {
  191. r.Lock()
  192. defer r.Unlock()
  193. inAddr := netip.AddrPortFrom(ip, port)
  194. if _, ok := r.inNat[inAddr]; ok {
  195. panic("Duplicate listen address inNat: " + inAddr.String())
  196. }
  197. r.inNat[inAddr] = c
  198. }
  199. // RenderFlow renders the packet flow seen up until now and stops further automatic renders from happening.
  200. func (r *R) RenderFlow() {
  201. r.cancelRender()
  202. r.Lock()
  203. defer r.Unlock()
  204. r.renderFlow()
  205. }
  206. // CancelFlowLogs stops flow logs from being tracked and destroys any logs already collected
  207. func (r *R) CancelFlowLogs() {
  208. r.cancelRender()
  209. r.Lock()
  210. r.flow = nil
  211. r.Unlock()
  212. }
  213. // renderFlow writes the flow log to disk. Caller must hold r.Lock. renderFlow reads r.flow / r.additionalGraphs and
  214. // the *packet pointers stashed inside, all of which are mutated under the same lock by routing paths.
  215. func (r *R) renderFlow() {
  216. if r.flow == nil {
  217. return
  218. }
  219. f, err := os.OpenFile(r.fn, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
  220. if err != nil {
  221. panic(err)
  222. }
  223. var participants = map[netip.AddrPort]struct{}{}
  224. var participantsVals []string
  225. fmt.Fprintln(f, "```mermaid")
  226. fmt.Fprintln(f, "sequenceDiagram")
  227. // Assemble participants
  228. for _, e := range r.flow {
  229. if e.packet == nil {
  230. continue
  231. }
  232. addr := e.packet.fromAddr()
  233. if _, ok := participants[addr]; ok {
  234. continue
  235. }
  236. participants[addr] = struct{}{}
  237. sanAddr := normalizeName(addr.String())
  238. participantsVals = append(participantsVals, sanAddr)
  239. fmt.Fprintf(
  240. f, " participant %s as Nebula: %s<br/>UDP: %s\n",
  241. sanAddr, e.packet.from.GetVpnAddrs(), sanAddr,
  242. )
  243. }
  244. if len(participantsVals) > 2 {
  245. // Get the first and last participantVals for notes
  246. participantsVals = []string{participantsVals[0], participantsVals[len(participantsVals)-1]}
  247. }
  248. // Print packets
  249. for _, e := range r.flow {
  250. if e.packet == nil {
  251. //fmt.Fprintf(f, " note over %s: %s\n", strings.Join(participantsVals, ", "), e.note)
  252. continue
  253. }
  254. p := e.packet
  255. if p.tun {
  256. fmt.Fprintln(f, r.formatUdpPacket(p))
  257. } else {
  258. line := "--x"
  259. if p.rx {
  260. line = "->>"
  261. }
  262. detail := fmt.Sprintf("%s(%s), index %v, counter: %v",
  263. p.h.TypeName(), p.h.SubTypeName(), p.h.RemoteIndex, p.h.MessageCounter)
  264. if p.parseErr != nil {
  265. detail = fmt.Sprintf("unparsed, %v (%d bytes)", p.parseErr, len(p.packet.Data))
  266. }
  267. fmt.Fprintf(f, " %s%s%s: %s\n",
  268. normalizeName(p.fromAddr().String()),
  269. line,
  270. normalizeName(p.toAddr().String()),
  271. detail,
  272. )
  273. }
  274. }
  275. fmt.Fprintln(f, "```")
  276. for _, g := range r.additionalGraphs {
  277. fmt.Fprintf(f, "## %s\n", g.title)
  278. fmt.Fprintln(f, "```mermaid")
  279. fmt.Fprintln(f, g.content)
  280. fmt.Fprintln(f, "```")
  281. }
  282. }
  283. func normalizeName(s string) string {
  284. rx := regexp.MustCompile("[\\[\\]\\:]")
  285. return rx.ReplaceAllLiteralString(s, "_")
  286. }
  287. // IgnoreFlow tells the router to stop recording future flows that matches the provided criteria.
  288. // messageType and subType will target nebula underlay packets while tun will target nebula overlay packets
  289. // NOTE: This is a very broad system, if you set tun to true then no more tun traffic will be rendered
  290. func (r *R) IgnoreFlow(messageType header.MessageType, subType header.MessageSubType, tun NullBool) {
  291. r.Lock()
  292. defer r.Unlock()
  293. r.ignoreFlows = append(r.ignoreFlows, ignoreFlow{
  294. tun,
  295. messageType,
  296. subType,
  297. })
  298. }
  299. func (r *R) RenderHostmaps(title string, controls ...*nebula.Control) {
  300. r.Lock()
  301. defer r.Unlock()
  302. s := renderHostmaps(controls...)
  303. if len(r.additionalGraphs) > 0 {
  304. lastGraph := r.additionalGraphs[len(r.additionalGraphs)-1]
  305. if lastGraph.content == s && lastGraph.title == title {
  306. // Ignore this rendering if it matches the last rendering added
  307. // This is useful if you want to track rendering changes
  308. return
  309. }
  310. }
  311. r.additionalGraphs = append(r.additionalGraphs, mermaidGraph{
  312. title: title,
  313. content: s,
  314. })
  315. }
  316. func (r *R) renderHostmaps(title string) {
  317. c := slices.AppendSeq(make([]*nebula.Control, 0, len(r.controls)), maps.Values(r.controls))
  318. sort.SliceStable(c, func(i, j int) bool {
  319. return c[i].GetVpnAddrs()[0].Compare(c[j].GetVpnAddrs()[0]) > 0
  320. })
  321. s := renderHostmaps(c...)
  322. if len(r.additionalGraphs) > 0 {
  323. lastGraph := r.additionalGraphs[len(r.additionalGraphs)-1]
  324. if lastGraph.content == s {
  325. // Ignore this rendering if it matches the last rendering added
  326. // This is useful if you want to track rendering changes
  327. return
  328. }
  329. }
  330. r.additionalGraphs = append(r.additionalGraphs, mermaidGraph{
  331. title: title,
  332. content: s,
  333. })
  334. }
  335. // InjectFlow can be used to record packet flow if the test is handling the routing on its own.
  336. // The packet is assumed to have been received
  337. func (r *R) InjectFlow(from, to *nebula.Control, p *udp.Packet) {
  338. r.Lock()
  339. defer r.Unlock()
  340. r.unlockedInjectFlow(from, to, p, false)
  341. }
  342. func (r *R) Log(arg ...any) {
  343. if r.flow == nil {
  344. return
  345. }
  346. r.Lock()
  347. r.flow = append(r.flow, flowEntry{note: fmt.Sprint(arg...)})
  348. r.t.Log(arg...)
  349. r.Unlock()
  350. }
  351. func (r *R) Logf(format string, arg ...any) {
  352. if r.flow == nil {
  353. return
  354. }
  355. r.Lock()
  356. r.flow = append(r.flow, flowEntry{note: fmt.Sprintf(format, arg...)})
  357. r.t.Logf(format, arg...)
  358. r.Unlock()
  359. }
  360. // unlockedInjectFlow is used by the router to record a packet has been transmitted, the packet is returned and
  361. // should be marked as received AFTER it has been placed on the receivers channel.
  362. // If flow logs have been disabled this function will return nil
  363. func (r *R) unlockedInjectFlow(from, to *nebula.Control, p *udp.Packet, tun bool) *packet {
  364. if r.flow == nil {
  365. return nil
  366. }
  367. r.renderHostmaps(fmt.Sprintf("Packet %v", len(r.flow)))
  368. var h header.H
  369. var parseErr error
  370. if !tun {
  371. parseErr = h.Parse(p.Data)
  372. }
  373. // Decide before copying, the copy comes from a freelist and an ignored packet would never be released
  374. for _, i := range r.ignoreFlows {
  375. if tun {
  376. if i.tun.HasValue && i.tun.IsTrue {
  377. return nil
  378. }
  379. continue
  380. }
  381. // A packet we could not parse has no type to match against, so no rule can ignore it
  382. if parseErr == nil && i.messageType == h.Type && i.subType == h.Subtype {
  383. return nil
  384. }
  385. }
  386. fp := &packet{
  387. from: from,
  388. to: to,
  389. packet: p.Copy(),
  390. tun: tun,
  391. h: h,
  392. parseErr: parseErr,
  393. }
  394. r.flow = append(r.flow, flowEntry{packet: fp})
  395. return fp
  396. }
  397. // OnceFrom will route a single packet from sender then return
  398. // If the router doesn't have the nebula controller for that address, we panic
  399. func (r *R) OnceFrom(sender *nebula.Control) {
  400. r.RouteExitFunc(sender, func(*udp.Packet, *nebula.Control) ExitType {
  401. return RouteAndExit
  402. })
  403. }
  404. // RouteUntilTxTun will route for sender and return when a packet is seen on receivers tun
  405. // If the router doesn't have the nebula controller for that address, we panic
  406. func (r *R) RouteUntilTxTun(sender *nebula.Control, receiver *nebula.Control) []byte {
  407. tunTx := receiver.GetTunTxChan()
  408. udpTx := sender.GetUDPTxChan()
  409. for {
  410. select {
  411. // Maybe we already have something on the tun for us
  412. case b := <-tunTx:
  413. r.Lock()
  414. np := udp.Packet{Data: make([]byte, len(b))}
  415. copy(np.Data, b)
  416. r.unlockedInjectFlow(receiver, receiver, &np, true)
  417. r.Unlock()
  418. return b
  419. // Nope, lets push the sender along
  420. case p := <-udpTx:
  421. r.Lock()
  422. a := sender.GetUDPAddr()
  423. c := r.getControl(a, p.To, p)
  424. if c == nil {
  425. r.Unlock()
  426. panic("No control for udp tx " + a.String())
  427. }
  428. fp := r.unlockedInjectFlow(sender, c, p, false)
  429. c.InjectUDPPacket(p) // copies internally; original is ours to release
  430. fp.WasReceived()
  431. r.Unlock()
  432. p.Release()
  433. }
  434. }
  435. }
  436. // RouteForAllUntilTxTun will route for everyone and return when a packet is seen on the receiver's tun.
  437. // If a control's UDP TX address can't be matched to a registered control, we panic.
  438. //
  439. // For allocation-sensitive callers (hot-path benchmarks, in particular relay
  440. // benches with 3+ controls), call EnableFanIn() first.
  441. func (r *R) RouteForAllUntilTxTun(receiver *nebula.Control) []byte {
  442. if r.fanInOn.Load() {
  443. return r.routeFanIn(receiver)
  444. }
  445. return r.routeReflect(receiver)
  446. }
  447. // routeFanIn is the alloc-free path used when EnableFanIn is in effect.
  448. func (r *R) routeFanIn(receiver *nebula.Control) []byte {
  449. tunTx := receiver.GetTunTxChan()
  450. for {
  451. select {
  452. case p := <-tunTx:
  453. r.Lock()
  454. if r.flow != nil {
  455. np := udp.Packet{Data: make([]byte, len(p))}
  456. copy(np.Data, p)
  457. r.unlockedInjectFlow(receiver, receiver, &np, true)
  458. }
  459. r.Unlock()
  460. return p
  461. case fp := <-r.udpFanIn:
  462. r.routeUDP(fp.from, fp.pkt)
  463. }
  464. }
  465. }
  466. // routeReflect is the default reflect.Select-based path. Pays the boxing allocation per call but doesn't interfere
  467. // with tests that pull packets directly from controls' UDP TX channels via GetFromUDP.
  468. func (r *R) routeReflect(receiver *nebula.Control) []byte {
  469. sc, cm := r.selectCasesFor(receiver)
  470. for {
  471. x, rx, _ := reflect.Select(sc)
  472. if x == 0 {
  473. p := rx.Interface().([]byte)
  474. r.Lock()
  475. if r.flow != nil {
  476. np := udp.Packet{Data: make([]byte, len(p))}
  477. copy(np.Data, p)
  478. r.unlockedInjectFlow(cm[x], cm[x], &np, true)
  479. }
  480. r.Unlock()
  481. return p
  482. }
  483. r.routeUDP(cm[x], rx.Interface().(*udp.Packet))
  484. }
  485. }
  486. // EnableFanIn switches RouteForAllUntilTxTun to the alloc-free fan-in path.
  487. // One forwarder goroutine per registered control drains UDP TX into a shared channel that RouteForAllUntilTxTun selects
  488. // on alongside the receiver's TUN TX channel.
  489. func (r *R) EnableFanIn() {
  490. r.fanInMu.Lock()
  491. defer r.fanInMu.Unlock()
  492. if r.fanInOn.Load() {
  493. return
  494. }
  495. r.udpFanIn = make(chan fannedPacket, 32)
  496. r.stopFanIn = make(chan struct{})
  497. for _, c := range r.controls {
  498. r.startFanInWorker(c)
  499. }
  500. r.fanInOn.Store(true)
  501. r.t.Cleanup(r.stopFanInWorkers)
  502. }
  503. // startFanInWorker spawns a goroutine that drains c's UDP TX into r.udpFanIn.
  504. func (r *R) startFanInWorker(c *nebula.Control) {
  505. r.fanInWG.Add(1)
  506. udpTx := c.GetUDPTxChan()
  507. go func() {
  508. defer r.fanInWG.Done()
  509. for {
  510. select {
  511. case <-r.stopFanIn:
  512. return
  513. case p := <-udpTx:
  514. select {
  515. case <-r.stopFanIn:
  516. p.Release()
  517. return
  518. case r.udpFanIn <- fannedPacket{from: c, pkt: p}:
  519. }
  520. }
  521. }
  522. }()
  523. }
  524. // stopFanInWorkers signals the fan-in goroutines to exit and waits for them.
  525. func (r *R) stopFanInWorkers() {
  526. r.fanInMu.Lock()
  527. wasOn := r.fanInOn.Swap(false)
  528. r.fanInMu.Unlock()
  529. if !wasOn {
  530. return
  531. }
  532. close(r.stopFanIn)
  533. r.fanInWG.Wait()
  534. }
  535. // routeUDP forwards a UDP TX packet from the named source control to the destination control derived from p.To,
  536. // releasing the source packet after InjectUDPPacket has copied its bytes into a fresh pool slot.
  537. func (r *R) routeUDP(from *nebula.Control, p *udp.Packet) {
  538. r.Lock()
  539. defer r.Unlock()
  540. a := from.GetUDPAddr()
  541. c := r.getControl(a, p.To, p)
  542. if c == nil {
  543. panic(fmt.Sprintf("No control for udp tx %s", p.To))
  544. }
  545. fp := r.unlockedInjectFlow(from, c, p, false)
  546. c.InjectUDPPacket(p) // copies internally; original is ours to release
  547. fp.WasReceived()
  548. p.Release()
  549. }
  550. // selectCasesFor returns the SelectCase array used by routeReflect: one slot for the receiver's TUN TX channel followed
  551. // by one per control's UDP TX channel. Cached for the test lifetime, only rebuilt if the receiver changes.
  552. func (r *R) selectCasesFor(receiver *nebula.Control) ([]reflect.SelectCase, []*nebula.Control) {
  553. r.Lock()
  554. defer r.Unlock()
  555. if r.selRecvCtl == receiver && r.selCases != nil {
  556. return r.selCases, r.selCtls
  557. }
  558. sc := make([]reflect.SelectCase, len(r.controls)+1)
  559. cm := make([]*nebula.Control, len(r.controls)+1)
  560. sc[0] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(receiver.GetTunTxChan())}
  561. cm[0] = receiver
  562. i := 1
  563. for _, c := range r.controls {
  564. sc[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(c.GetUDPTxChan())}
  565. cm[i] = c
  566. i++
  567. }
  568. r.selRecvCtl = receiver
  569. r.selCases = sc
  570. r.selCtls = cm
  571. return sc, cm
  572. }
  573. // RouteExitFunc will call the whatDo func with each udp packet from sender.
  574. // whatDo can return:
  575. // - exitNow: the packet will not be routed and this call will return immediately
  576. // - routeAndExit: this call will return immediately after routing the last packet from sender
  577. // - keepRouting: the packet will be routed and whatDo will be called again on the next packet from sender
  578. func (r *R) RouteExitFunc(sender *nebula.Control, whatDo ExitFunc) {
  579. h := &header.H{}
  580. for {
  581. p := sender.GetFromUDP(true)
  582. r.Lock()
  583. if err := h.Parse(p.Data); err != nil {
  584. panic(err)
  585. }
  586. receiver := r.getControl(sender.GetUDPAddr(), p.To, p)
  587. if receiver == nil {
  588. r.Unlock()
  589. panic("Can't RouteExitFunc for host: " + p.To.String())
  590. }
  591. e := whatDo(p, receiver)
  592. switch e {
  593. case ExitNow:
  594. r.Unlock()
  595. p.Release()
  596. return
  597. case RouteAndExit:
  598. fp := r.unlockedInjectFlow(sender, receiver, p, false)
  599. receiver.InjectUDPPacket(p)
  600. fp.WasReceived()
  601. r.Unlock()
  602. p.Release()
  603. return
  604. case Drop:
  605. // Record it so the flow log shows the attempt, but never hand it to the receiver
  606. r.unlockedInjectFlow(sender, receiver, p, false)
  607. case KeepRouting:
  608. fp := r.unlockedInjectFlow(sender, receiver, p, false)
  609. receiver.InjectUDPPacket(p)
  610. fp.WasReceived()
  611. default:
  612. panic(fmt.Sprintf("Unknown exitFunc return: %v", e))
  613. }
  614. r.Unlock()
  615. p.Release()
  616. }
  617. }
  618. // RouteUntilAfterMsgType will route for sender until a message type is seen and sent from sender
  619. // If the router doesn't have the nebula controller for that address, we panic
  620. func (r *R) RouteUntilAfterMsgType(sender *nebula.Control, msgType header.MessageType, subType header.MessageSubType) {
  621. h := &header.H{}
  622. r.RouteExitFunc(sender, func(p *udp.Packet, r *nebula.Control) ExitType {
  623. if err := h.Parse(p.Data); err != nil {
  624. panic(err)
  625. }
  626. if h.Type == msgType && h.Subtype == subType {
  627. return RouteAndExit
  628. }
  629. return KeepRouting
  630. })
  631. }
  632. // RouteFor routes everything that shows up for the given duration and then returns. Use it to let a test settle
  633. // deterministically rather than sleeping and hoping: a single FlushAll races a completing handshake, which queues
  634. // more packets right behind it.
  635. func (r *R) RouteFor(d time.Duration) {
  636. r.RouteForAllExitFuncOrTimeout(d, func(*udp.Packet, *nebula.Control) ExitType {
  637. return KeepRouting
  638. })
  639. }
  640. // RouteForAllExitFuncOrTimeout is RouteForAllExitFunc with a deadline, reporting whether whatDo asked to exit
  641. // before time ran out. The unbounded version blocks forever on a quiet network, so this is what a test needs to
  642. // assert that something does NOT happen, or to route for a fixed settling period.
  643. func (r *R) RouteForAllExitFuncOrTimeout(timeout time.Duration, whatDo ExitFunc) bool {
  644. sc := make([]reflect.SelectCase, 0, len(r.controls)+1)
  645. cm := make([]*nebula.Control, 0, len(r.controls))
  646. for _, c := range r.controls {
  647. sc = append(sc, reflect.SelectCase{
  648. Dir: reflect.SelectRecv,
  649. Chan: reflect.ValueOf(c.GetUDPTxChan()),
  650. Send: reflect.Value{},
  651. })
  652. cm = append(cm, c)
  653. }
  654. timer := time.NewTimer(timeout)
  655. defer timer.Stop()
  656. sc = append(sc, reflect.SelectCase{
  657. Dir: reflect.SelectRecv,
  658. Chan: reflect.ValueOf(timer.C),
  659. Send: reflect.Value{},
  660. })
  661. for {
  662. x, rx, _ := reflect.Select(sc)
  663. if x == len(cm) {
  664. return false
  665. }
  666. r.Lock()
  667. p := rx.Interface().(*udp.Packet)
  668. receiver := r.getControl(cm[x].GetUDPAddr(), p.To, p)
  669. if receiver == nil {
  670. r.Unlock()
  671. panic("Can't RouteForAllExitFuncOrTimeout for host: " + p.To.String())
  672. }
  673. e := whatDo(p, receiver)
  674. switch e {
  675. case ExitNow:
  676. r.Unlock()
  677. p.Release()
  678. return true
  679. case RouteAndExit:
  680. fp := r.unlockedInjectFlow(cm[x], receiver, p, false)
  681. receiver.InjectUDPPacket(p)
  682. fp.WasReceived()
  683. r.Unlock()
  684. p.Release()
  685. return true
  686. case Drop:
  687. // Record it so the flow log shows the attempt, but never hand it to the receiver
  688. r.unlockedInjectFlow(cm[x], receiver, p, false)
  689. case KeepRouting:
  690. fp := r.unlockedInjectFlow(cm[x], receiver, p, false)
  691. receiver.InjectUDPPacket(p)
  692. fp.WasReceived()
  693. default:
  694. panic(fmt.Sprintf("Unknown exitFunc return: %v", e))
  695. }
  696. r.Unlock()
  697. p.Release()
  698. }
  699. }
  700. func (r *R) RouteForAllUntilAfterMsgTypeTo(receiver *nebula.Control, msgType header.MessageType, subType header.MessageSubType) {
  701. h := &header.H{}
  702. r.RouteForAllExitFunc(func(p *udp.Packet, r *nebula.Control) ExitType {
  703. if r != receiver {
  704. return KeepRouting
  705. }
  706. if err := h.Parse(p.Data); err != nil {
  707. panic(err)
  708. }
  709. if h.Type == msgType && h.Subtype == subType {
  710. return RouteAndExit
  711. }
  712. return KeepRouting
  713. })
  714. }
  715. func (r *R) InjectUDPPacket(sender, receiver *nebula.Control, packet *udp.Packet) {
  716. r.Lock()
  717. defer r.Unlock()
  718. fp := r.unlockedInjectFlow(sender, receiver, packet, false)
  719. receiver.InjectUDPPacket(packet)
  720. fp.WasReceived()
  721. }
  722. // RouteForUntilAfterToAddr will route for sender and return only after it sees and sends a packet destined for toAddr
  723. // finish can be any of the exitType values except `keepRouting`, the default value is `routeAndExit`
  724. // If the router doesn't have the nebula controller for that address, we panic
  725. func (r *R) RouteForUntilAfterToAddr(sender *nebula.Control, toAddr netip.AddrPort, finish ExitType) {
  726. if finish == KeepRouting {
  727. finish = RouteAndExit
  728. }
  729. r.RouteExitFunc(sender, func(p *udp.Packet, r *nebula.Control) ExitType {
  730. if p.To == toAddr {
  731. return finish
  732. }
  733. return KeepRouting
  734. })
  735. }
  736. // RouteForAllExitFunc will route for every registered controller and calls the whatDo func with each udp packet from
  737. // whatDo can return:
  738. // - exitNow: the packet will not be routed and this call will return immediately
  739. // - routeAndExit: this call will return immediately after routing the last packet from sender
  740. // - keepRouting: the packet will be routed and whatDo will be called again on the next packet from sender
  741. func (r *R) RouteForAllExitFunc(whatDo ExitFunc) {
  742. sc := make([]reflect.SelectCase, len(r.controls))
  743. cm := make([]*nebula.Control, len(r.controls))
  744. i := 0
  745. for _, c := range r.controls {
  746. sc[i] = reflect.SelectCase{
  747. Dir: reflect.SelectRecv,
  748. Chan: reflect.ValueOf(c.GetUDPTxChan()),
  749. Send: reflect.Value{},
  750. }
  751. cm[i] = c
  752. i++
  753. }
  754. for {
  755. x, rx, _ := reflect.Select(sc)
  756. r.Lock()
  757. p := rx.Interface().(*udp.Packet)
  758. receiver := r.getControl(cm[x].GetUDPAddr(), p.To, p)
  759. if receiver == nil {
  760. r.Unlock()
  761. panic("Can't RouteForAllExitFunc for host: " + p.To.String())
  762. }
  763. e := whatDo(p, receiver)
  764. switch e {
  765. case ExitNow:
  766. r.Unlock()
  767. p.Release()
  768. return
  769. case RouteAndExit:
  770. fp := r.unlockedInjectFlow(cm[x], receiver, p, false)
  771. receiver.InjectUDPPacket(p)
  772. fp.WasReceived()
  773. r.Unlock()
  774. p.Release()
  775. return
  776. case Drop:
  777. // Record it so the flow log shows the attempt, but never hand it to the receiver
  778. r.unlockedInjectFlow(cm[x], receiver, p, false)
  779. case KeepRouting:
  780. fp := r.unlockedInjectFlow(cm[x], receiver, p, false)
  781. receiver.InjectUDPPacket(p)
  782. fp.WasReceived()
  783. default:
  784. panic(fmt.Sprintf("Unknown exitFunc return: %v", e))
  785. }
  786. r.Unlock()
  787. p.Release()
  788. }
  789. }
  790. // FlushAll will route for every registered controller, exiting once there are no packets left to route
  791. func (r *R) FlushAll() {
  792. sc := make([]reflect.SelectCase, len(r.controls))
  793. cm := make([]*nebula.Control, len(r.controls))
  794. i := 0
  795. for _, c := range r.controls {
  796. sc[i] = reflect.SelectCase{
  797. Dir: reflect.SelectRecv,
  798. Chan: reflect.ValueOf(c.GetUDPTxChan()),
  799. Send: reflect.Value{},
  800. }
  801. cm[i] = c
  802. i++
  803. }
  804. // Add a default case to exit when nothing is left to send
  805. sc = append(sc, reflect.SelectCase{
  806. Dir: reflect.SelectDefault,
  807. Chan: reflect.Value{},
  808. Send: reflect.Value{},
  809. })
  810. for {
  811. x, rx, ok := reflect.Select(sc)
  812. if !ok {
  813. return
  814. }
  815. r.Lock()
  816. p := rx.Interface().(*udp.Packet)
  817. receiver := r.getControl(cm[x].GetUDPAddr(), p.To, p)
  818. if receiver == nil {
  819. r.Unlock()
  820. panic("Can't FlushAll for host: " + p.To.String())
  821. }
  822. receiver.InjectUDPPacket(p)
  823. r.Unlock()
  824. p.Release()
  825. }
  826. }
  827. // getControl performs or seeds NAT translation and returns the control for toAddr, p from fields may change
  828. // This is an internal router function, the caller must hold the lock
  829. func (r *R) getControl(fromAddr, toAddr netip.AddrPort, p *udp.Packet) *nebula.Control {
  830. if newAddr, ok := r.outNat[outNatKey{from: fromAddr, to: toAddr}]; ok {
  831. p.From = newAddr
  832. }
  833. c, ok := r.inNat[toAddr]
  834. if ok {
  835. r.outNat[outNatKey{from: c.GetUDPAddr(), to: fromAddr}] = toAddr
  836. return c
  837. }
  838. return r.controls[toAddr]
  839. }
  840. func (r *R) formatUdpPacket(p *packet) string {
  841. var packet gopacket.Packet
  842. var srcAddr netip.Addr
  843. packet = gopacket.NewPacket(p.packet.Data, layers.LayerTypeIPv6, gopacket.Lazy)
  844. if packet.ErrorLayer() == nil {
  845. v6 := packet.Layer(layers.LayerTypeIPv6).(*layers.IPv6)
  846. if v6 == nil {
  847. panic("not an ipv6 packet")
  848. }
  849. srcAddr, _ = netip.AddrFromSlice(v6.SrcIP)
  850. } else {
  851. packet = gopacket.NewPacket(p.packet.Data, layers.LayerTypeIPv4, gopacket.Lazy)
  852. v6 := packet.Layer(layers.LayerTypeIPv4).(*layers.IPv4)
  853. if v6 == nil {
  854. panic("not an ipv6 packet")
  855. }
  856. srcAddr, _ = netip.AddrFromSlice(v6.SrcIP)
  857. }
  858. from := "unknown"
  859. if c, ok := r.vpnControls[srcAddr]; ok {
  860. from = c.GetUDPAddr().String()
  861. }
  862. udpLayer := packet.Layer(layers.LayerTypeUDP).(*layers.UDP)
  863. if udpLayer == nil {
  864. panic("not a udp packet")
  865. }
  866. data := packet.ApplicationLayer()
  867. return fmt.Sprintf(
  868. " %s-->>%s: src port: %v<br/>dest port: %v<br/>data: \"%v\"\n",
  869. normalizeName(from),
  870. normalizeName(p.to.GetUDPAddr().String()),
  871. udpLayer.SrcPort,
  872. udpLayer.DstPort,
  873. string(data.Payload()),
  874. )
  875. }