tun_disabled.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package overlay
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "log/slog"
  7. "net/netip"
  8. "strings"
  9. "github.com/rcrowley/go-metrics"
  10. "github.com/slackhq/nebula/iputil"
  11. "github.com/slackhq/nebula/overlay/tio"
  12. "github.com/slackhq/nebula/routing"
  13. )
  14. type disabledTun struct {
  15. read chan []byte
  16. vpnNetworks []netip.Prefix
  17. // Track these metrics since we don't have the tun device to do it for us
  18. tx metrics.Counter
  19. rx metrics.Counter
  20. l *slog.Logger
  21. numReaders int
  22. }
  23. // disabledQueue is one tio.Queue view onto a shared disabledTun. Each queue
  24. // owns a private batchRet so concurrent Read calls from different reader
  25. // goroutines do not race on the returned slice.
  26. type disabledQueue struct {
  27. parent *disabledTun
  28. batchRet [1]tio.Packet
  29. }
  30. func (q *disabledQueue) Read() ([]tio.Packet, error) {
  31. r, ok := <-q.parent.read
  32. if !ok {
  33. return nil, io.EOF
  34. }
  35. q.parent.tx.Inc(1)
  36. if q.parent.l.Enabled(context.Background(), slog.LevelDebug) {
  37. q.parent.l.Debug("Write payload", "raw", prettyPacket(r))
  38. }
  39. q.batchRet[0] = tio.Packet{Bytes: r}
  40. return q.batchRet[:], nil
  41. }
  42. // Write on a queue forwards to the underlying disabledTun. All queues share
  43. // one ICMP-handling/log path so this is a thin pass-through.
  44. func (q *disabledQueue) Write(b []byte) (int, error) {
  45. return q.parent.Write(b)
  46. }
  47. // Close on a queue is a no-op. The shared channel and metrics are owned by
  48. // the disabledTun; Close on the device tears them down once for everybody.
  49. func (q *disabledQueue) Close() error {
  50. return nil
  51. }
  52. func newDisabledTun(vpnNetworks []netip.Prefix, queueLen int, metricsEnabled bool, l *slog.Logger) *disabledTun {
  53. tun := &disabledTun{
  54. vpnNetworks: vpnNetworks,
  55. read: make(chan []byte, queueLen),
  56. l: l,
  57. numReaders: 1,
  58. }
  59. if metricsEnabled {
  60. tun.tx = metrics.GetOrRegisterCounter("messages.tx.message", nil)
  61. tun.rx = metrics.GetOrRegisterCounter("messages.rx.message", nil)
  62. } else {
  63. tun.tx = &metrics.NilCounter{}
  64. tun.rx = &metrics.NilCounter{}
  65. }
  66. return tun
  67. }
  68. func (*disabledTun) Activate() error {
  69. return nil
  70. }
  71. func (*disabledTun) RoutesFor(addr netip.Addr) routing.Gateways {
  72. return routing.Gateways{}
  73. }
  74. func (t *disabledTun) Networks() []netip.Prefix {
  75. return t.vpnNetworks
  76. }
  77. func (*disabledTun) Name() string {
  78. return "disabled"
  79. }
  80. func (t *disabledTun) handleICMPEchoRequest(b []byte) bool {
  81. out := make([]byte, len(b))
  82. out = iputil.CreateICMPEchoResponse(b, out)
  83. if out == nil {
  84. return false
  85. }
  86. // attempt to write it, but don't block
  87. select {
  88. case t.read <- out:
  89. default:
  90. t.l.Debug("tun_disabled: dropped ICMP Echo Reply response")
  91. }
  92. return true
  93. }
  94. func (t *disabledTun) Write(b []byte) (int, error) {
  95. t.rx.Inc(1)
  96. // Check for ICMP Echo Request before spending time doing the full parsing
  97. if t.handleICMPEchoRequest(b) {
  98. if t.l.Enabled(context.Background(), slog.LevelDebug) {
  99. t.l.Debug("Disabled tun responded to ICMP Echo Request", "raw", prettyPacket(b))
  100. }
  101. } else if t.l.Enabled(context.Background(), slog.LevelDebug) {
  102. t.l.Debug("Disabled tun received unexpected payload", "raw", prettyPacket(b))
  103. }
  104. return len(b), nil
  105. }
  106. func (t *disabledTun) SupportsMultiqueue() bool {
  107. return true
  108. }
  109. func (t *disabledTun) NewMultiQueueReader() error {
  110. t.numReaders++
  111. return nil
  112. }
  113. func (t *disabledTun) Readers() []tio.Queue {
  114. out := make([]tio.Queue, t.numReaders)
  115. for i := range t.numReaders {
  116. out[i] = &disabledQueue{parent: t}
  117. }
  118. return out
  119. }
  120. func (t *disabledTun) Close() error {
  121. if t.read != nil {
  122. close(t.read)
  123. t.read = nil
  124. }
  125. return nil
  126. }
  127. type prettyPacket []byte
  128. func (p prettyPacket) String() string {
  129. var s strings.Builder
  130. for i, b := range p {
  131. if i > 0 && i%8 == 0 {
  132. s.WriteString(" ")
  133. }
  134. s.WriteString(fmt.Sprintf("%02x ", b))
  135. }
  136. return s.String()
  137. }