router.go 27 KB

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