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