tun_tester.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //go:build e2e_testing
  2. // +build e2e_testing
  3. package overlay
  4. import (
  5. "context"
  6. "fmt"
  7. "io"
  8. "log/slog"
  9. "net/netip"
  10. "os"
  11. "sync/atomic"
  12. "github.com/gaissmai/bart"
  13. "github.com/slackhq/nebula/config"
  14. "github.com/slackhq/nebula/routing"
  15. )
  16. type TestTun struct {
  17. Device string
  18. vpnNetworks []netip.Prefix
  19. Routes []Route
  20. routeTree *bart.Table[routing.Gateways]
  21. l *slog.Logger
  22. closed atomic.Bool
  23. rxPackets chan []byte // Packets to receive into nebula
  24. TxPackets chan []byte // Packets transmitted outside by nebula
  25. }
  26. func newTun(c *config.C, l *slog.Logger, vpnNetworks []netip.Prefix, _ bool) (*TestTun, error) {
  27. _, routes, err := getAllRoutesFromConfig(c, vpnNetworks, true)
  28. if err != nil {
  29. return nil, err
  30. }
  31. routeTree, err := makeRouteTree(l, routes, false)
  32. if err != nil {
  33. return nil, err
  34. }
  35. return &TestTun{
  36. Device: c.GetString("tun.dev", ""),
  37. vpnNetworks: vpnNetworks,
  38. Routes: routes,
  39. routeTree: routeTree,
  40. l: l,
  41. rxPackets: make(chan []byte, 10),
  42. TxPackets: make(chan []byte, 10),
  43. }, nil
  44. }
  45. func newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (*TestTun, error) {
  46. return nil, fmt.Errorf("newTunFromFd not supported")
  47. }
  48. // Send will place a byte array onto the receive queue for nebula to consume
  49. // These are unencrypted ip layer frames destined for another nebula node.
  50. // packets should exit the udp side, capture them with udpConn.Get
  51. func (t *TestTun) Send(packet []byte) {
  52. if t.closed.Load() {
  53. return
  54. }
  55. if t.l.Enabled(context.Background(), slog.LevelDebug) {
  56. t.l.Debug("Tun receiving injected packet", "dataLen", len(packet))
  57. }
  58. t.rxPackets <- packet
  59. }
  60. // Get will pull an unencrypted ip layer frame from the transmit queue
  61. // nebula meant to send this message to some application on the local system
  62. // packets were ingested from the udp side, you can send them with udpConn.Send
  63. func (t *TestTun) Get(block bool) []byte {
  64. if block {
  65. return <-t.TxPackets
  66. }
  67. select {
  68. case p := <-t.TxPackets:
  69. return p
  70. default:
  71. return nil
  72. }
  73. }
  74. //********************************************************************************************************************//
  75. // Below this is boilerplate implementation to make nebula actually work
  76. //********************************************************************************************************************//
  77. func (t *TestTun) RoutesFor(ip netip.Addr) routing.Gateways {
  78. r, _ := t.routeTree.Lookup(ip)
  79. return r
  80. }
  81. func (t *TestTun) Activate() error {
  82. return nil
  83. }
  84. func (t *TestTun) Networks() []netip.Prefix {
  85. return t.vpnNetworks
  86. }
  87. func (t *TestTun) Name() string {
  88. return t.Device
  89. }
  90. func (t *TestTun) Write(b []byte) (n int, err error) {
  91. if t.closed.Load() {
  92. return 0, io.ErrClosedPipe
  93. }
  94. packet := make([]byte, len(b), len(b))
  95. copy(packet, b)
  96. t.TxPackets <- packet
  97. return len(b), nil
  98. }
  99. func (t *TestTun) Close() error {
  100. if t.closed.CompareAndSwap(false, true) {
  101. close(t.rxPackets)
  102. close(t.TxPackets)
  103. }
  104. return nil
  105. }
  106. func (t *TestTun) Read(b []byte) (int, error) {
  107. p, ok := <-t.rxPackets
  108. if !ok {
  109. return 0, os.ErrClosed
  110. }
  111. copy(b, p)
  112. return len(p), nil
  113. }
  114. func (t *TestTun) SupportsMultiqueue() bool {
  115. return false
  116. }
  117. func (t *TestTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
  118. return nil, fmt.Errorf("TODO: multiqueue not implemented")
  119. }