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  }