udp_tester.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. //go:build e2e_testing
  2. // +build e2e_testing
  3. package udp
  4. import (
  5. "context"
  6. "io"
  7. "log/slog"
  8. "net/netip"
  9. "os"
  10. "sync"
  11. "github.com/slackhq/nebula/config"
  12. "github.com/slackhq/nebula/header"
  13. )
  14. type Packet struct {
  15. To netip.AddrPort
  16. From netip.AddrPort
  17. Data []byte
  18. }
  19. func (u *Packet) Copy() *Packet {
  20. n := &Packet{
  21. To: u.To,
  22. From: u.From,
  23. Data: make([]byte, len(u.Data)),
  24. }
  25. copy(n.Data, u.Data)
  26. return n
  27. }
  28. type TesterConn struct {
  29. Addr netip.AddrPort
  30. RxPackets chan *Packet // Packets to receive into nebula
  31. TxPackets chan *Packet // Packets transmitted outside by nebula
  32. // done is closed exactly once by Close. Senders select on it so they
  33. // never race with a channel close; readers exit when it fires. The
  34. // packet channels are intentionally never closed - that was the source
  35. // of `send on closed channel` panics when a WriteTo/Send from another
  36. // goroutine passed the close check and reached the send just after
  37. // Close ran.
  38. done chan struct{}
  39. closeOnce sync.Once
  40. l *slog.Logger
  41. }
  42. func NewListener(l *slog.Logger, ip netip.Addr, port int, _ bool, _ int) (Conn, error) {
  43. return &TesterConn{
  44. Addr: netip.AddrPortFrom(ip, uint16(port)),
  45. RxPackets: make(chan *Packet, 10),
  46. TxPackets: make(chan *Packet, 10),
  47. done: make(chan struct{}),
  48. l: l,
  49. }, nil
  50. }
  51. // Send will place a UdpPacket onto the receive queue for nebula to consume
  52. // this is an encrypted packet or a handshake message in most cases
  53. // packets were transmitted from another nebula node, you can send them with Tun.Send
  54. func (u *TesterConn) Send(packet *Packet) {
  55. h := &header.H{}
  56. if err := h.Parse(packet.Data); err != nil {
  57. panic(err)
  58. }
  59. if u.l.Enabled(context.Background(), slog.LevelDebug) {
  60. u.l.Debug("UDP receiving injected packet",
  61. "header", h,
  62. "udpAddr", packet.From,
  63. "dataLen", len(packet.Data),
  64. )
  65. }
  66. select {
  67. case <-u.done:
  68. case u.RxPackets <- packet:
  69. }
  70. }
  71. // Get will pull a UdpPacket from the transmit queue
  72. // nebula meant to send this message on the network, it will be encrypted
  73. // packets were ingested from the tun side (in most cases), you can send them with Tun.Send
  74. func (u *TesterConn) Get(block bool) *Packet {
  75. if block {
  76. select {
  77. case <-u.done:
  78. return nil
  79. case p := <-u.TxPackets:
  80. return p
  81. }
  82. }
  83. select {
  84. case p := <-u.TxPackets:
  85. return p
  86. default:
  87. return nil
  88. }
  89. }
  90. //********************************************************************************************************************//
  91. // Below this is boilerplate implementation to make nebula actually work
  92. //********************************************************************************************************************//
  93. func (u *TesterConn) WriteTo(b []byte, addr netip.AddrPort) error {
  94. p := &Packet{
  95. Data: make([]byte, len(b), len(b)),
  96. From: u.Addr,
  97. To: addr,
  98. }
  99. copy(p.Data, b)
  100. select {
  101. case <-u.done:
  102. return io.ErrClosedPipe
  103. case u.TxPackets <- p:
  104. return nil
  105. }
  106. }
  107. func (u *TesterConn) ListenOut(r EncReader) error {
  108. for {
  109. select {
  110. case <-u.done:
  111. return os.ErrClosed
  112. case p := <-u.RxPackets:
  113. r(p.From, p.Data)
  114. }
  115. }
  116. }
  117. func (u *TesterConn) ReloadConfig(*config.C) {}
  118. func NewUDPStatsEmitter(_ []Conn) func() {
  119. // No UDP stats for non-linux
  120. return func() {}
  121. }
  122. func (u *TesterConn) LocalAddr() (netip.AddrPort, error) {
  123. return u.Addr, nil
  124. }
  125. func (u *TesterConn) SupportsMultipleReaders() bool {
  126. return false
  127. }
  128. func (u *TesterConn) Rebind() error {
  129. return nil
  130. }
  131. func (u *TesterConn) EnablePathMTUDiscovery() error {
  132. return nil
  133. }
  134. func (u *TesterConn) Close() error {
  135. u.closeOnce.Do(func() {
  136. close(u.done)
  137. })
  138. return nil
  139. }