Improved receive.go
- Fixed configuration listen-port semantics - Improved receive.go code for updating listen port - Updated under load detection, how follows the kernel space implementation - Fixed trie bug accidentally introduced in last commit - Added interface name to log (format still subject to change) - Can now configure the logging level using the LOG_LEVEL variable - Begin porting netsh.sh tests - A number of smaller changes
This commit is contained in:
		
							parent
							
								
									cba1d6585a
								
							
						
					
					
						commit
						a4eff12d7f
					
				
					 16 changed files with 616 additions and 218 deletions
				
			
		|  | @ -28,6 +28,7 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { | |||
| 	// create lines
 | ||||
| 
 | ||||
| 	device.mutex.RLock() | ||||
| 	device.net.mutex.RLock() | ||||
| 
 | ||||
| 	lines := make([]string, 0, 100) | ||||
| 	send := func(line string) { | ||||
|  | @ -38,7 +39,9 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { | |||
| 		send("private_key=" + device.privateKey.ToHex()) | ||||
| 	} | ||||
| 
 | ||||
| 	send(fmt.Sprintf("listen_port=%d", device.net.addr.Port)) | ||||
| 	if device.net.addr != nil { | ||||
| 		send(fmt.Sprintf("listen_port=%d", device.net.addr.Port)) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, peer := range device.peers { | ||||
| 		func() { | ||||
|  | @ -68,6 +71,7 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { | |||
| 		}() | ||||
| 	} | ||||
| 
 | ||||
| 	device.net.mutex.RUnlock() | ||||
| 	device.mutex.RUnlock() | ||||
| 
 | ||||
| 	// send lines
 | ||||
|  | @ -84,38 +88,6 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func updateUDPConn(device *Device) error { | ||||
| 	var err error | ||||
| 	netc := &device.net | ||||
| 	netc.mutex.Lock() | ||||
| 
 | ||||
| 	// close existing connection
 | ||||
| 
 | ||||
| 	if netc.conn != nil { | ||||
| 		netc.conn.Close() | ||||
| 		netc.conn = nil | ||||
| 	} | ||||
| 
 | ||||
| 	// open new existing connection
 | ||||
| 
 | ||||
| 	conn, err := net.ListenUDP("udp", netc.addr) | ||||
| 	if err == nil { | ||||
| 		netc.conn = conn | ||||
| 		signalSend(device.signal.newUDPConn) | ||||
| 	} | ||||
| 
 | ||||
| 	netc.mutex.Unlock() | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func closeUDPConn(device *Device) { | ||||
| 	device.net.mutex.Lock() | ||||
| 	device.net.conn = nil | ||||
| 	device.net.mutex.Unlock() | ||||
| 	println("send signal") | ||||
| 	signalSend(device.signal.newUDPConn) | ||||
| } | ||||
| 
 | ||||
| func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { | ||||
| 	scanner := bufio.NewScanner(socket) | ||||
| 	logInfo := device.log.Info | ||||
|  | @ -166,13 +138,22 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { | |||
| 					logError.Println("Failed to set listen_port:", err) | ||||
| 					return &IPCError{Code: ipcErrorInvalid} | ||||
| 				} | ||||
| 
 | ||||
| 				addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) | ||||
| 				if err != nil { | ||||
| 					logError.Println("Failed to set listen_port:", err) | ||||
| 					return &IPCError{Code: ipcErrorInvalid} | ||||
| 				} | ||||
| 
 | ||||
| 				netc := &device.net | ||||
| 				netc.mutex.Lock() | ||||
| 				if netc.addr.Port != int(port) { | ||||
| 					netc.addr.Port = int(port) | ||||
| 				} | ||||
| 				netc.addr = addr | ||||
| 				netc.mutex.Unlock() | ||||
| 				updateUDPConn(device) | ||||
| 				err = updateUDPConn(device) | ||||
| 				if err != nil { | ||||
| 					logError.Println("Failed to set listen_port:", err) | ||||
| 					return &IPCError{Code: ipcErrorIO} | ||||
| 				} | ||||
| 
 | ||||
| 				// TODO: Clear source address of all peers
 | ||||
| 
 | ||||
|  | @ -298,7 +279,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { | |||
| 						logError.Println("Failed to get tun device status:", err) | ||||
| 						return &IPCError{Code: ipcErrorIO} | ||||
| 					} | ||||
| 					if atomic.LoadInt32(&device.isUp) == AtomicTrue && !dummy { | ||||
| 					if device.tun.isUp.Get() && !dummy { | ||||
| 						peer.SendKeepAlive() | ||||
| 					} | ||||
| 				} | ||||
|  |  | |||
							
								
								
									
										40
									
								
								src/conn.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/conn.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"net" | ||||
| ) | ||||
| 
 | ||||
| func updateUDPConn(device *Device) error { | ||||
| 	var err error | ||||
| 	netc := &device.net | ||||
| 	netc.mutex.Lock() | ||||
| 
 | ||||
| 	// close existing connection
 | ||||
| 
 | ||||
| 	if netc.conn != nil { | ||||
| 		netc.conn.Close() | ||||
| 	} | ||||
| 
 | ||||
| 	// open new connection
 | ||||
| 
 | ||||
| 	if device.tun.isUp.Get() { | ||||
| 		conn, err := net.ListenUDP("udp", netc.addr) | ||||
| 		if err == nil { | ||||
| 			netc.conn = conn | ||||
| 			signalSend(device.signal.newUDPConn) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	netc.mutex.Unlock() | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func closeUDPConn(device *Device) { | ||||
| 	netc := &device.net | ||||
| 	netc.mutex.Lock() | ||||
| 	if netc.conn != nil { | ||||
| 		netc.conn.Close() | ||||
| 	} | ||||
| 	netc.mutex.Unlock() | ||||
| 	signalSend(device.signal.newUDPConn) | ||||
| } | ||||
|  | @ -26,11 +26,15 @@ const ( | |||
| /* Implementation specific constants */ | ||||
| 
 | ||||
| const ( | ||||
| 	QueueOutboundSize      = 1024 | ||||
| 	QueueInboundSize       = 1024 | ||||
| 	QueueHandshakeSize     = 1024 | ||||
| 	QueueHandshakeBusySize = QueueHandshakeSize / 8 | ||||
| 	MinMessageSize         = MessageTransportSize // size of keep-alive
 | ||||
| 	MaxMessageSize         = ((1 << 16) - 1) + MessageTransportHeaderSize | ||||
| 	MaxPeers               = 1 << 16 | ||||
| 	QueueOutboundSize  = 1024 | ||||
| 	QueueInboundSize   = 1024 | ||||
| 	QueueHandshakeSize = 1024 | ||||
| 	MinMessageSize     = MessageTransportSize // size of keep-alive
 | ||||
| 	MaxMessageSize     = ((1 << 16) - 1) + MessageTransportHeaderSize | ||||
| 	MaxPeers           = 1 << 16 | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	UnderLoadQueueSize = QueueHandshakeSize / 8 | ||||
| 	UnderLoadAfterTime = time.Second // how long does the device remain under load after detected
 | ||||
| ) | ||||
|  |  | |||
|  | @ -5,20 +5,22 @@ import ( | |||
| 	"runtime" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type Device struct { | ||||
| 	mtu       int32 | ||||
| 	tun       TUNDevice | ||||
| 	log       *Logger // collection of loggers for levels
 | ||||
| 	idCounter uint    // for assigning debug ids to peers
 | ||||
| 	fwMark    uint32 | ||||
| 	pool      struct { | ||||
| 		// pools objects for reuse
 | ||||
| 	tun       struct { | ||||
| 		device TUNDevice | ||||
| 		isUp   AtomicBool | ||||
| 		mtu    int32 | ||||
| 	} | ||||
| 	pool struct { | ||||
| 		messageBuffers sync.Pool | ||||
| 	} | ||||
| 	net struct { | ||||
| 		// seperate for performance reasons
 | ||||
| 		mutex sync.RWMutex | ||||
| 		addr  *net.UDPAddr // UDP source address
 | ||||
| 		conn  *net.UDPConn // UDP "connection"
 | ||||
|  | @ -35,13 +37,12 @@ type Device struct { | |||
| 	} | ||||
| 	signal struct { | ||||
| 		stop       chan struct{} // halts all go routines
 | ||||
| 		newUDPConn chan struct{} // a net.conn was set
 | ||||
| 		newUDPConn chan struct{} // a net.conn was set (consumed by the receiver routine)
 | ||||
| 	} | ||||
| 	isUp        int32 // atomic bool: interface is up
 | ||||
| 	underLoad   int32 // atomic bool: device is under load
 | ||||
| 	ratelimiter Ratelimiter | ||||
| 	peers       map[NoisePublicKey]*Peer | ||||
| 	mac         MACStateDevice | ||||
| 	underLoadUntil atomic.Value | ||||
| 	ratelimiter    Ratelimiter | ||||
| 	peers          map[NoisePublicKey]*Peer | ||||
| 	mac            MACStateDevice | ||||
| } | ||||
| 
 | ||||
| /* Warning: | ||||
|  | @ -58,6 +59,23 @@ func removePeerUnsafe(device *Device, key NoisePublicKey) { | |||
| 	peer.Close() | ||||
| } | ||||
| 
 | ||||
| func (device *Device) IsUnderLoad() bool { | ||||
| 
 | ||||
| 	// check if currently under load
 | ||||
| 
 | ||||
| 	now := time.Now() | ||||
| 	underLoad := len(device.queue.handshake) >= UnderLoadQueueSize | ||||
| 	if underLoad { | ||||
| 		device.underLoadUntil.Store(now.Add(time.Second)) | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	// check if recently under load
 | ||||
| 
 | ||||
| 	until := device.underLoadUntil.Load().(time.Time) | ||||
| 	return until.After(now) | ||||
| } | ||||
| 
 | ||||
| func (device *Device) SetPrivateKey(sk NoisePrivateKey) error { | ||||
| 	device.mutex.Lock() | ||||
| 	defer device.mutex.Unlock() | ||||
|  | @ -115,20 +133,13 @@ func NewDevice(tun TUNDevice, logLevel int) *Device { | |||
| 	device.mutex.Lock() | ||||
| 	defer device.mutex.Unlock() | ||||
| 
 | ||||
| 	device.tun = tun | ||||
| 	device.log = NewLogger(logLevel) | ||||
| 	device.log = NewLogger(logLevel, "("+tun.Name()+") ") | ||||
| 	device.peers = make(map[NoisePublicKey]*Peer) | ||||
| 	device.tun.device = tun | ||||
| 	device.indices.Init() | ||||
| 	device.ratelimiter.Init() | ||||
| 	device.routingTable.Reset() | ||||
| 
 | ||||
| 	// listen
 | ||||
| 
 | ||||
| 	device.net.mutex.Lock() | ||||
| 	device.net.conn, _ = net.ListenUDP("udp", device.net.addr) | ||||
| 	addr := device.net.conn.LocalAddr() | ||||
| 	device.net.addr, _ = net.ResolveUDPAddr(addr.Network(), addr.String()) | ||||
| 	device.net.mutex.Unlock() | ||||
| 	device.underLoadUntil.Store(time.Time{}) | ||||
| 
 | ||||
| 	// setup pools
 | ||||
| 
 | ||||
|  | @ -157,42 +168,43 @@ func NewDevice(tun TUNDevice, logLevel int) *Device { | |||
| 		go device.RoutineHandshake() | ||||
| 	} | ||||
| 
 | ||||
| 	go device.RoutineBusyMonitor() | ||||
| 	go device.RoutineReadFromTUN() | ||||
| 	go device.RoutineTUNEventReader() | ||||
| 	go device.RoutineReceiveIncomming() | ||||
| 	go device.ratelimiter.RoutineGarbageCollector(device.signal.stop) | ||||
| 	go device.RoutineReadFromTUN() | ||||
| 	go device.RoutineReceiveIncomming() | ||||
| 
 | ||||
| 	return device | ||||
| } | ||||
| 
 | ||||
| func (device *Device) RoutineTUNEventReader() { | ||||
| 	events := device.tun.Events() | ||||
| 	logInfo := device.log.Info | ||||
| 	logError := device.log.Error | ||||
| 
 | ||||
| 	events := device.tun.device.Events() | ||||
| 
 | ||||
| 	for event := range events { | ||||
| 		if event&TUNEventMTUUpdate != 0 { | ||||
| 			mtu, err := device.tun.MTU() | ||||
| 			mtu, err := device.tun.device.MTU() | ||||
| 			if err != nil { | ||||
| 				logError.Println("Failed to load updated MTU of device:", err) | ||||
| 			} else { | ||||
| 				if mtu+MessageTransportSize > MaxMessageSize { | ||||
| 					mtu = MaxMessageSize - MessageTransportSize | ||||
| 				} | ||||
| 				atomic.StoreInt32(&device.mtu, int32(mtu)) | ||||
| 				atomic.StoreInt32(&device.tun.mtu, int32(mtu)) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if event&TUNEventUp != 0 { | ||||
| 			println("handle 1") | ||||
| 			atomic.StoreInt32(&device.isUp, AtomicTrue) | ||||
| 			device.tun.isUp.Set(true) | ||||
| 			updateUDPConn(device) | ||||
| 			println("handle 2", device.net.conn) | ||||
| 			logInfo.Println("Interface set up") | ||||
| 		} | ||||
| 
 | ||||
| 		if event&TUNEventDown != 0 { | ||||
| 			atomic.StoreInt32(&device.isUp, AtomicFalse) | ||||
| 			device.tun.isUp.Set(false) | ||||
| 			closeUDPConn(device) | ||||
| 			logInfo.Println("Interface set down") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -224,6 +236,7 @@ func (device *Device) RemoveAllPeers() { | |||
| func (device *Device) Close() { | ||||
| 	device.RemoveAllPeers() | ||||
| 	close(device.signal.stop) | ||||
| 	closeUDPConn(device) | ||||
| } | ||||
| 
 | ||||
| func (device *Device) WaitChannel() chan struct{} { | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ type DummyTUN struct { | |||
| 	name    string | ||||
| 	mtu     int | ||||
| 	packets chan []byte | ||||
| 	events  chan TUNEvent | ||||
| } | ||||
| 
 | ||||
| func (tun *DummyTUN) Name() string { | ||||
|  | @ -27,6 +28,14 @@ func (tun *DummyTUN) Write(d []byte) (int, error) { | |||
| 	return len(d), nil | ||||
| } | ||||
| 
 | ||||
| func (tun *DummyTUN) Close() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (tun *DummyTUN) Events() chan TUNEvent { | ||||
| 	return tun.events | ||||
| } | ||||
| 
 | ||||
| func (tun *DummyTUN) Read(d []byte) (int, error) { | ||||
| 	t := <-tun.packets | ||||
| 	copy(d, t) | ||||
|  |  | |||
|  | @ -2,8 +2,8 @@ package main | |||
| 
 | ||||
| import ( | ||||
| 	"crypto/rand" | ||||
| 	"encoding/binary" | ||||
| 	"sync" | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| /* Index=0 is reserved for unset indecies | ||||
|  | @ -24,7 +24,8 @@ type IndexTable struct { | |||
| func randUint32() (uint32, error) { | ||||
| 	var buff [4]byte | ||||
| 	_, err := rand.Read(buff[:]) | ||||
| 	return *((*uint32)(unsafe.Pointer(&buff))), err | ||||
| 	value := binary.LittleEndian.Uint32(buff[:]) | ||||
| 	return value, err | ||||
| } | ||||
| 
 | ||||
| func (table *IndexTable) Init() { | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ type Logger struct { | |||
| 	Error *log.Logger | ||||
| } | ||||
| 
 | ||||
| func NewLogger(level int) *Logger { | ||||
| func NewLogger(level int, prepend string) *Logger { | ||||
| 	output := os.Stdout | ||||
| 	logger := new(Logger) | ||||
| 
 | ||||
|  | @ -34,16 +34,16 @@ func NewLogger(level int) *Logger { | |||
| 	}() | ||||
| 
 | ||||
| 	logger.Debug = log.New(logDebug, | ||||
| 		"DEBUG: ", | ||||
| 		"DEBUG: "+prepend, | ||||
| 		log.Ldate|log.Ltime|log.Lshortfile, | ||||
| 	) | ||||
| 
 | ||||
| 	logger.Info = log.New(logInfo, | ||||
| 		"INFO: ", | ||||
| 		"INFO: "+prepend, | ||||
| 		log.Ldate|log.Ltime, | ||||
| 	) | ||||
| 	logger.Error = log.New(logErr, | ||||
| 		"ERROR: ", | ||||
| 		"ERROR: "+prepend, | ||||
| 		log.Ldate|log.Ltime, | ||||
| 	) | ||||
| 	return logger | ||||
|  |  | |||
|  | @ -13,8 +13,8 @@ func TestMAC1(t *testing.T) { | |||
| 	defer dev1.Close() | ||||
| 	defer dev2.Close() | ||||
| 
 | ||||
| 	peer1 := dev2.NewPeer(dev1.privateKey.publicKey()) | ||||
| 	peer2 := dev1.NewPeer(dev2.privateKey.publicKey()) | ||||
| 	peer1, _ := dev2.NewPeer(dev1.privateKey.publicKey()) | ||||
| 	peer2, _ := dev1.NewPeer(dev2.privateKey.publicKey()) | ||||
| 
 | ||||
| 	assertEqual(t, peer1.mac.keyMAC1[:], dev1.mac.keyMAC1[:]) | ||||
| 	assertEqual(t, peer2.mac.keyMAC1[:], dev2.mac.keyMAC1[:]) | ||||
|  | @ -45,8 +45,8 @@ func TestMACs(t *testing.T) { | |||
| 		defer device1.Close() | ||||
| 		defer device2.Close() | ||||
| 
 | ||||
| 		peer1 := device2.NewPeer(device1.privateKey.publicKey()) | ||||
| 		peer2 := device1.NewPeer(device2.privateKey.publicKey()) | ||||
| 		peer1, _ := device2.NewPeer(device1.privateKey.publicKey()) | ||||
| 		peer2, _ := device1.NewPeer(device2.privateKey.publicKey()) | ||||
| 
 | ||||
| 		if addr.Port < 0 { | ||||
| 			return true | ||||
|  |  | |||
							
								
								
									
										16
									
								
								src/main.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/main.go
									
									
									
									
									
								
							|  | @ -65,9 +65,23 @@ func main() { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// get log level (default: info)
 | ||||
| 
 | ||||
| 	logLevel := func() int { | ||||
| 		switch os.Getenv("LOG_LEVEL") { | ||||
| 		case "debug": | ||||
| 			return LogLevelDebug | ||||
| 		case "info": | ||||
| 			return LogLevelInfo | ||||
| 		case "error": | ||||
| 			return LogLevelError | ||||
| 		} | ||||
| 		return LogLevelInfo | ||||
| 	}() | ||||
| 
 | ||||
| 	// create wireguard device
 | ||||
| 
 | ||||
| 	device := NewDevice(tun, LogLevelDebug) | ||||
| 	device := NewDevice(tun, logLevel) | ||||
| 
 | ||||
| 	logInfo := device.log.Info | ||||
| 	logError := device.log.Error | ||||
|  |  | |||
							
								
								
									
										19
									
								
								src/misc.go
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/misc.go
									
									
									
									
									
								
							|  | @ -1,6 +1,7 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
|  | @ -8,10 +9,26 @@ import ( | |||
|  * (since booleans are not natively supported by sync/atomic) | ||||
|  */ | ||||
| const ( | ||||
| 	AtomicFalse = iota | ||||
| 	AtomicFalse = int32(iota) | ||||
| 	AtomicTrue | ||||
| ) | ||||
| 
 | ||||
| type AtomicBool struct { | ||||
| 	flag int32 | ||||
| } | ||||
| 
 | ||||
| func (a *AtomicBool) Get() bool { | ||||
| 	return atomic.LoadInt32(&a.flag) == AtomicTrue | ||||
| } | ||||
| 
 | ||||
| func (a *AtomicBool) Set(val bool) { | ||||
| 	flag := AtomicFalse | ||||
| 	if val { | ||||
| 		flag = AtomicTrue | ||||
| 	} | ||||
| 	atomic.StoreInt32(&a.flag, flag) | ||||
| } | ||||
| 
 | ||||
| func min(a uint, b uint) uint { | ||||
| 	if a > b { | ||||
| 		return b | ||||
|  |  | |||
|  | @ -31,8 +31,8 @@ func TestNoiseHandshake(t *testing.T) { | |||
| 	defer dev1.Close() | ||||
| 	defer dev2.Close() | ||||
| 
 | ||||
| 	peer1 := dev2.NewPeer(dev1.privateKey.publicKey()) | ||||
| 	peer2 := dev1.NewPeer(dev2.privateKey.publicKey()) | ||||
| 	peer1, _ := dev2.NewPeer(dev1.privateKey.publicKey()) | ||||
| 	peer2, _ := dev1.NewPeer(dev2.privateKey.publicKey()) | ||||
| 
 | ||||
| 	assertEqual( | ||||
| 		t, | ||||
|  |  | |||
							
								
								
									
										207
									
								
								src/receive.go
									
									
									
									
									
								
							
							
						
						
									
										207
									
								
								src/receive.go
									
									
									
									
									
								
							|  | @ -72,43 +72,6 @@ func (device *Device) addToHandshakeQueue( | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Routine determining the busy state of the interface | ||||
|  * | ||||
|  * TODO: Under load for some time | ||||
|  */ | ||||
| func (device *Device) RoutineBusyMonitor() { | ||||
| 	samples := 0 | ||||
| 	interval := time.Second | ||||
| 	for timer := time.NewTimer(interval); ; { | ||||
| 
 | ||||
| 		select { | ||||
| 		case <-device.signal.stop: | ||||
| 			return | ||||
| 		case <-timer.C: | ||||
| 		} | ||||
| 
 | ||||
| 		// compute busy heuristic
 | ||||
| 
 | ||||
| 		if len(device.queue.handshake) > QueueHandshakeBusySize { | ||||
| 			samples += 1 | ||||
| 		} else if samples > 0 { | ||||
| 			samples -= 1 | ||||
| 		} | ||||
| 		samples %= 30 | ||||
| 		busy := samples > 5 | ||||
| 
 | ||||
| 		// update busy state
 | ||||
| 
 | ||||
| 		if busy { | ||||
| 			atomic.StoreInt32(&device.underLoad, AtomicTrue) | ||||
| 		} else { | ||||
| 			atomic.StoreInt32(&device.underLoad, AtomicFalse) | ||||
| 		} | ||||
| 
 | ||||
| 		timer.Reset(interval) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (device *Device) RoutineReceiveIncomming() { | ||||
| 
 | ||||
| 	logDebug := device.log.Debug | ||||
|  | @ -118,117 +81,121 @@ func (device *Device) RoutineReceiveIncomming() { | |||
| 
 | ||||
| 		// wait for new conn
 | ||||
| 
 | ||||
| 		var conn *net.UDPConn | ||||
| 		logDebug.Println("Waiting for udp socket") | ||||
| 
 | ||||
| 		select { | ||||
| 		case <-device.signal.newUDPConn: | ||||
| 			device.net.mutex.RLock() | ||||
| 			conn = device.net.conn | ||||
| 			device.net.mutex.RUnlock() | ||||
| 
 | ||||
| 		case <-device.signal.stop: | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if conn == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		case <-device.signal.newUDPConn: | ||||
| 
 | ||||
| 		// receive datagrams until closed
 | ||||
| 			// fetch connection
 | ||||
| 
 | ||||
| 		buffer := device.GetMessageBuffer() | ||||
| 
 | ||||
| 		for { | ||||
| 
 | ||||
| 			// read next datagram
 | ||||
| 
 | ||||
| 			size, raddr, err := conn.ReadFromUDP(buffer[:]) // TODO: This is broken
 | ||||
| 
 | ||||
| 			if err != nil { | ||||
| 				break | ||||
| 			} | ||||
| 
 | ||||
| 			if size < MinMessageSize { | ||||
| 			device.net.mutex.RLock() | ||||
| 			conn := device.net.conn | ||||
| 			device.net.mutex.RUnlock() | ||||
| 			if conn == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// check size of packet
 | ||||
| 			logDebug.Println("Listening for inbound packets") | ||||
| 
 | ||||
| 			packet := buffer[:size] | ||||
| 			msgType := binary.LittleEndian.Uint32(packet[:4]) | ||||
| 			// receive datagrams until conn is closed
 | ||||
| 
 | ||||
| 			var okay bool | ||||
| 			buffer := device.GetMessageBuffer() | ||||
| 
 | ||||
| 			switch msgType { | ||||
| 			for { | ||||
| 
 | ||||
| 			// check if transport
 | ||||
| 				// read next datagram
 | ||||
| 
 | ||||
| 			case MessageTransportType: | ||||
| 				size, raddr, err := conn.ReadFromUDP(buffer[:]) // Blocks sometimes
 | ||||
| 
 | ||||
| 				// check size
 | ||||
| 				if err != nil { | ||||
| 					break | ||||
| 				} | ||||
| 
 | ||||
| 				if len(packet) < MessageTransportType { | ||||
| 				if size < MinMessageSize { | ||||
| 					continue | ||||
| 				} | ||||
| 
 | ||||
| 				// lookup key pair
 | ||||
| 				// check size of packet
 | ||||
| 
 | ||||
| 				receiver := binary.LittleEndian.Uint32( | ||||
| 					packet[MessageTransportOffsetReceiver:MessageTransportOffsetCounter], | ||||
| 				) | ||||
| 				value := device.indices.Lookup(receiver) | ||||
| 				keyPair := value.keyPair | ||||
| 				if keyPair == nil { | ||||
| 					continue | ||||
| 				} | ||||
| 				packet := buffer[:size] | ||||
| 				msgType := binary.LittleEndian.Uint32(packet[:4]) | ||||
| 
 | ||||
| 				// check key-pair expiry
 | ||||
| 				var okay bool | ||||
| 
 | ||||
| 				if keyPair.created.Add(RejectAfterTime).Before(time.Now()) { | ||||
| 					continue | ||||
| 				} | ||||
| 				switch msgType { | ||||
| 
 | ||||
| 				// create work element
 | ||||
| 				// check if transport
 | ||||
| 
 | ||||
| 				peer := value.peer | ||||
| 				elem := &QueueInboundElement{ | ||||
| 					packet:  packet, | ||||
| 					buffer:  buffer, | ||||
| 					keyPair: keyPair, | ||||
| 					dropped: AtomicFalse, | ||||
| 				} | ||||
| 				elem.mutex.Lock() | ||||
| 				case MessageTransportType: | ||||
| 
 | ||||
| 				// add to decryption queues
 | ||||
| 					// check size
 | ||||
| 
 | ||||
| 				device.addToInboundQueue(device.queue.decryption, elem) | ||||
| 				device.addToInboundQueue(peer.queue.inbound, elem) | ||||
| 				buffer = nil | ||||
| 				continue | ||||
| 					if len(packet) < MessageTransportType { | ||||
| 						continue | ||||
| 					} | ||||
| 
 | ||||
| 			// otherwise it is a handshake related packet
 | ||||
| 					// lookup key pair
 | ||||
| 
 | ||||
| 			case MessageInitiationType: | ||||
| 				okay = len(packet) == MessageInitiationSize | ||||
| 					receiver := binary.LittleEndian.Uint32( | ||||
| 						packet[MessageTransportOffsetReceiver:MessageTransportOffsetCounter], | ||||
| 					) | ||||
| 					value := device.indices.Lookup(receiver) | ||||
| 					keyPair := value.keyPair | ||||
| 					if keyPair == nil { | ||||
| 						continue | ||||
| 					} | ||||
| 
 | ||||
| 			case MessageResponseType: | ||||
| 				okay = len(packet) == MessageResponseSize | ||||
| 					// check key-pair expiry
 | ||||
| 
 | ||||
| 			case MessageCookieReplyType: | ||||
| 				okay = len(packet) == MessageCookieReplySize | ||||
| 			} | ||||
| 					if keyPair.created.Add(RejectAfterTime).Before(time.Now()) { | ||||
| 						continue | ||||
| 					} | ||||
| 
 | ||||
| 			if okay { | ||||
| 				device.addToHandshakeQueue( | ||||
| 					device.queue.handshake, | ||||
| 					QueueHandshakeElement{ | ||||
| 						msgType: msgType, | ||||
| 						buffer:  buffer, | ||||
| 					// create work element
 | ||||
| 
 | ||||
| 					peer := value.peer | ||||
| 					elem := &QueueInboundElement{ | ||||
| 						packet:  packet, | ||||
| 						source:  raddr, | ||||
| 					}, | ||||
| 				) | ||||
| 				buffer = device.GetMessageBuffer() | ||||
| 						buffer:  buffer, | ||||
| 						keyPair: keyPair, | ||||
| 						dropped: AtomicFalse, | ||||
| 					} | ||||
| 					elem.mutex.Lock() | ||||
| 
 | ||||
| 					// add to decryption queues
 | ||||
| 
 | ||||
| 					device.addToInboundQueue(device.queue.decryption, elem) | ||||
| 					device.addToInboundQueue(peer.queue.inbound, elem) | ||||
| 					buffer = device.GetMessageBuffer() | ||||
| 					continue | ||||
| 
 | ||||
| 				// otherwise it is a handshake related packet
 | ||||
| 
 | ||||
| 				case MessageInitiationType: | ||||
| 					okay = len(packet) == MessageInitiationSize | ||||
| 
 | ||||
| 				case MessageResponseType: | ||||
| 					okay = len(packet) == MessageResponseSize | ||||
| 
 | ||||
| 				case MessageCookieReplyType: | ||||
| 					okay = len(packet) == MessageCookieReplySize | ||||
| 				} | ||||
| 
 | ||||
| 				if okay { | ||||
| 					device.addToHandshakeQueue( | ||||
| 						device.queue.handshake, | ||||
| 						QueueHandshakeElement{ | ||||
| 							msgType: msgType, | ||||
| 							buffer:  buffer, | ||||
| 							packet:  packet, | ||||
| 							source:  raddr, | ||||
| 						}, | ||||
| 					) | ||||
| 					buffer = device.GetMessageBuffer() | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -326,10 +293,11 @@ func (device *Device) RoutineHandshake() { | |||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			busy := atomic.LoadInt32(&device.underLoad) == AtomicTrue | ||||
| 
 | ||||
| 			if busy { | ||||
| 			if device.IsUnderLoad() { | ||||
| 				if !device.mac.CheckMAC2(elem.packet, elem.source) { | ||||
| 
 | ||||
| 					// construct cookie reply
 | ||||
| 
 | ||||
| 					sender := binary.LittleEndian.Uint32(elem.packet[4:8]) // "sender" always follows "type"
 | ||||
| 					reply, err := device.CreateMessageCookieReply(elem.packet, sender, elem.source) | ||||
| 					if err != nil { | ||||
|  | @ -347,6 +315,7 @@ func (device *Device) RoutineHandshake() { | |||
| 					} | ||||
| 					continue | ||||
| 				} | ||||
| 
 | ||||
| 				if !device.ratelimiter.Allow(elem.source.IP) { | ||||
| 					continue | ||||
| 				} | ||||
|  | @ -577,7 +546,7 @@ func (peer *Peer) RoutineSequentialReceiver() { | |||
| 		// write to tun
 | ||||
| 
 | ||||
| 		atomic.AddUint64(&peer.stats.rxBytes, uint64(len(elem.packet))) | ||||
| 		_, err := device.tun.Write(elem.packet) | ||||
| 		_, err := device.tun.device.Write(elem.packet) | ||||
| 		device.PutMessageBuffer(elem.buffer) | ||||
| 		if err != nil { | ||||
| 			logError.Println("Failed to write packet to TUN device:", err) | ||||
|  |  | |||
|  | @ -137,10 +137,6 @@ func (peer *Peer) SendBuffer(buffer []byte) (int, error) { | |||
|  */ | ||||
| func (device *Device) RoutineReadFromTUN() { | ||||
| 
 | ||||
| 	if device.tun == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var elem *QueueOutboundElement | ||||
| 
 | ||||
| 	logDebug := device.log.Debug | ||||
|  | @ -155,9 +151,8 @@ func (device *Device) RoutineReadFromTUN() { | |||
| 			elem = device.NewOutboundElement() | ||||
| 		} | ||||
| 
 | ||||
| 		// TODO: THIS!
 | ||||
| 		elem.packet = elem.buffer[MessageTransportHeaderSize:] | ||||
| 		size, err := device.tun.Read(elem.packet) | ||||
| 		size, err := device.tun.device.Read(elem.packet) | ||||
| 		if err != nil { | ||||
| 			logError.Println("Failed to read packet from TUN device:", err) | ||||
| 			device.Close() | ||||
|  | @ -345,7 +340,7 @@ func (device *Device) RoutineEncryption() { | |||
| 
 | ||||
| 		// pad content to MTU size
 | ||||
| 
 | ||||
| 		mtu := int(atomic.LoadInt32(&device.mtu)) | ||||
| 		mtu := int(atomic.LoadInt32(&device.tun.mtu)) | ||||
| 		pad := len(elem.packet) % PaddingMultiple | ||||
| 		if pad > 0 { | ||||
| 			for i := 0; i < PaddingMultiple-pad && len(elem.packet) < mtu; i++ { | ||||
|  |  | |||
							
								
								
									
										350
									
								
								src/tests/netns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										350
									
								
								src/tests/netns.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,350 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. | ||||
| 
 | ||||
| # This script tests the below topology: | ||||
| # | ||||
| # ┌─────────────────────┐   ┌──────────────────────────────────┐   ┌─────────────────────┐ | ||||
| # │   $ns1 namespace    │   │          $ns0 namespace          │   │   $ns2 namespace    │ | ||||
| # │                     │   │                                  │   │                     │ | ||||
| # │┌────────┐           │   │            ┌────────┐            │   │           ┌────────┐│ | ||||
| # ││  wg1   │───────────┼───┼────────────│   lo   │────────────┼───┼───────────│  wg2   ││ | ||||
| # │├────────┴──────────┐│   │    ┌───────┴────────┴────────┐   │   │┌──────────┴────────┤│ | ||||
| # ││192.168.241.1/24   ││   │    │(ns1)         (ns2)      │   │   ││192.168.241.2/24   ││ | ||||
| # ││fd00::1/24         ││   │    │127.0.0.1:1   127.0.0.1:2│   │   ││fd00::2/24         ││ | ||||
| # │└───────────────────┘│   │    │[::]:1        [::]:2     │   │   │└───────────────────┘│ | ||||
| # └─────────────────────┘   │    └─────────────────────────┘   │   └─────────────────────┘ | ||||
| #                           └──────────────────────────────────┘ | ||||
| # | ||||
| # After the topology is prepared we run a series of TCP/UDP iperf3 tests between the | ||||
| # wireguard peers in $ns1 and $ns2. Note that $ns0 is the endpoint for the wg1 | ||||
| # interfaces in $ns1 and $ns2. See https://www.wireguard.com/netns/ for further | ||||
| # details on how this is accomplished. | ||||
| set -e | ||||
| 
 | ||||
| exec 3>&1 | ||||
| export WG_HIDE_KEYS=never | ||||
| netns0="wg-test-$$-0" | ||||
| netns1="wg-test-$$-1" | ||||
| netns2="wg-test-$$-2" | ||||
| program="../wireguard-go" | ||||
| export LOG_LEVEL="debug" | ||||
| 
 | ||||
| pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; } | ||||
| pp() { pretty "" "$*"; "$@"; } | ||||
| maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; } | ||||
| n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; } | ||||
| n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; } | ||||
| n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; } | ||||
| ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; } | ||||
| ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; } | ||||
| ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; } | ||||
| sleep() { read -t "$1" -N 0 || true; } | ||||
| waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; } | ||||
| waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } | ||||
| waitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; } | ||||
| 
 | ||||
| cleanup() { | ||||
|     n0 wg show | ||||
|     set +e | ||||
|     exec 2>/dev/null | ||||
|     printf "$orig_message_cost" > /proc/sys/net/core/message_cost | ||||
|     ip0 link del dev wg1 | ||||
|     ip1 link del dev wg1 | ||||
|     ip2 link del dev wg1 | ||||
|     local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)" | ||||
|     [[ -n $to_kill ]] && kill $to_kill | ||||
|     pp ip netns del $netns1 | ||||
|     pp ip netns del $netns2 | ||||
|     pp ip netns del $netns0 | ||||
|     exit | ||||
| } | ||||
| 
 | ||||
| orig_message_cost="$(< /proc/sys/net/core/message_cost)" | ||||
| trap cleanup EXIT | ||||
| printf 0 > /proc/sys/net/core/message_cost | ||||
| 
 | ||||
| ip netns del $netns0 2>/dev/null || true | ||||
| ip netns del $netns1 2>/dev/null || true | ||||
| ip netns del $netns2 2>/dev/null || true | ||||
| pp ip netns add $netns0 | ||||
| pp ip netns add $netns1 | ||||
| pp ip netns add $netns2 | ||||
| ip0 link set up dev lo | ||||
| 
 | ||||
| # ip0 link add dev wg1 type wireguard | ||||
| n0 $program -f wg1 & | ||||
| sleep 1 | ||||
| ip0 link set wg1 netns $netns1 | ||||
| 
 | ||||
| # ip0 link add dev wg1 type wireguard | ||||
| n0 $program -f wg2 & | ||||
| sleep 1 | ||||
| ip0 link set wg2 netns $netns2 | ||||
| 
 | ||||
| key1="$(pp wg genkey)" | ||||
| key2="$(pp wg genkey)" | ||||
| pub1="$(pp wg pubkey <<<"$key1")" | ||||
| pub2="$(pp wg pubkey <<<"$key2")" | ||||
| psk="$(pp wg genpsk)" | ||||
| [[ -n $key1 && -n $key2 && -n $psk ]] | ||||
| 
 | ||||
| configure_peers() { | ||||
| 
 | ||||
|     ip1 addr add 192.168.241.1/24 dev wg1 | ||||
|     ip1 addr add fd00::1/24 dev wg1 | ||||
| 
 | ||||
|     ip2 addr add 192.168.241.2/24 dev wg2 | ||||
|     ip2 addr add fd00::2/24 dev wg2 | ||||
| 
 | ||||
|     n0 wg set wg1 \ | ||||
|         private-key <(echo "$key1") \ | ||||
|         listen-port 10000 \ | ||||
|         peer "$pub2" \ | ||||
|             preshared-key <(echo "$psk") \ | ||||
|             allowed-ips 192.168.241.2/32,fd00::2/128 | ||||
|     n0 wg set wg2 \ | ||||
|         private-key <(echo "$key2") \ | ||||
|         listen-port 20000 \ | ||||
|         peer "$pub1" \ | ||||
|             preshared-key <(echo "$psk") \ | ||||
|             allowed-ips 192.168.241.1/32,fd00::1/128 | ||||
| 
 | ||||
|     n0 wg showconf wg1 | ||||
|     n0 wg showconf wg2 | ||||
| 
 | ||||
|     ip1 link set up dev wg1 | ||||
|     ip2 link set up dev wg2 | ||||
| } | ||||
| configure_peers | ||||
| 
 | ||||
| tests() { | ||||
|     # Ping over IPv4 | ||||
|     n2 ping -c 10 -f -W 1 192.168.241.1 | ||||
|     n1 ping -c 10 -f -W 1 192.168.241.2 | ||||
| 
 | ||||
|     # Ping over IPv6 | ||||
|     n2 ping6 -c 10 -f -W 1 fd00::1 | ||||
|     n1 ping6 -c 10 -f -W 1 fd00::2 | ||||
| 
 | ||||
|     # TCP over IPv4 | ||||
|     n2 iperf3 -s -1 -B 192.168.241.2 & | ||||
|     waitiperf $netns2 | ||||
|     n1 iperf3 -Z -n 1G -c 192.168.241.2 | ||||
| 
 | ||||
|     # TCP over IPv6 | ||||
|     n1 iperf3 -s -1 -B fd00::1 & | ||||
|     waitiperf $netns1 | ||||
|     n2 iperf3 -Z -n 1G -c fd00::1 | ||||
| 
 | ||||
|     # UDP over IPv4 | ||||
|     n1 iperf3 -s -1 -B 192.168.241.1 & | ||||
|     waitiperf $netns1 | ||||
|     n2 iperf3 -Z -n 1G -b 0 -u -c 192.168.241.1 | ||||
| 
 | ||||
|     # UDP over IPv6 | ||||
|     n2 iperf3 -s -1 -B fd00::2 & | ||||
|     waitiperf $netns2 | ||||
|     n1 iperf3 -Z -n 1G -b 0 -u -c fd00::2 | ||||
| } | ||||
| 
 | ||||
| [[ $(ip1 link show dev wg1) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}" | ||||
| big_mtu=$(( 34816 - 1500 + $orig_mtu )) | ||||
| 
 | ||||
| # Test using IPv4 as outer transport | ||||
| n0 wg set wg1 peer "$pub2" endpoint 127.0.0.1:20000 | ||||
| n0 wg set wg2 peer "$pub1" endpoint 127.0.0.1:10000 | ||||
| n0 wg show | ||||
| # Before calling tests, we first make sure that the stats counters are working | ||||
| n2 ping -c 10 -f -W 1 192.168.241.1 | ||||
| { read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg2) | ||||
| [[ $rx_bytes -ge 932 && $tx_bytes -ge 1516 && $rx_bytes -lt 2500 && $rx_bytes -lt 2500 ]] | ||||
| tests | ||||
| ip1 link set wg1 mtu $big_mtu | ||||
| ip2 link set wg2 mtu $big_mtu | ||||
| tests | ||||
| 
 | ||||
| ip1 link set wg1 mtu $orig_mtu | ||||
| ip2 link set wg2 mtu $orig_mtu | ||||
| 
 | ||||
| # Test using IPv6 as outer transport | ||||
| n0 wg set wg1 peer "$pub2" endpoint [::1]:20000 | ||||
| n0 wg set wg2 peer "$pub1" endpoint [::1]:10000 | ||||
| tests | ||||
| ip1 link set wg1 mtu $big_mtu | ||||
| ip2 link set wg2 mtu $big_mtu | ||||
| tests | ||||
| 
 | ||||
| ip1 link set wg1 mtu $orig_mtu | ||||
| ip2 link set wg2 mtu $orig_mtu | ||||
| 
 | ||||
| # Test using IPv4 that roaming works | ||||
| ip0 -4 addr del 127.0.0.1/8 dev lo | ||||
| ip0 -4 addr add 127.212.121.99/8 dev lo | ||||
| n0 wg set wg1 listen-port 9999 | ||||
| n0 wg set wg1 peer "$pub2" endpoint 127.0.0.1:20000 | ||||
| n1 ping6 -W 1 -c 1 fd00::20000 | ||||
| [[ $(n2 wg show wg2 endpoints) == "$pub1    127.212.121.99:9999" ]] | ||||
| 
 | ||||
| # Test using IPv6 that roaming works | ||||
| n1 wg set wg1 listen-port 9998 | ||||
| n1 wg set wg1 peer "$pub2" endpoint [::1]:20000 | ||||
| n1 ping -W 1 -c 1 192.168.241.2 | ||||
| [[ $(n2 wg show wg2 endpoints) == "$pub1    [::1]:9998" ]] | ||||
| 
 | ||||
| # Test that crypto-RP filter works | ||||
| n1 wg set wg1 peer "$pub2" allowed-ips 192.168.241.0/24 | ||||
| exec 4< <(n1 ncat -l -u -p 1111) | ||||
| nmap_pid=$! | ||||
| waitncatudp $netns1 | ||||
| n2 ncat -u 192.168.241.1 1111 <<<"X" | ||||
| read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]] | ||||
| kill $nmap_pid | ||||
| more_specific_key="$(pp wg genkey | pp wg pubkey)" | ||||
| n0 wg set wg1 peer "$more_specific_key" allowed-ips 192.168.241.2/32 | ||||
| n0 wg set wg2 listen-port 9997 | ||||
| exec 4< <(n1 ncat -l -u -p 1111) | ||||
| nmap_pid=$! | ||||
| waitncatudp $netns1 | ||||
| n2 ncat -u 192.168.241.1 1111 <<<"X" | ||||
| ! read -r -N 1 -t 1 out <&4 | ||||
| kill $nmap_pid | ||||
| n0 wg set wg1 peer "$more_specific_key" remove | ||||
| [[ $(n1 wg show wg1 endpoints) == "$pub2    [::1]:9997" ]] | ||||
| 
 | ||||
| ip1 link del wg1 | ||||
| ip2 link del wg2 | ||||
| 
 | ||||
| # Test using NAT. We now change the topology to this: | ||||
| # ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐ | ||||
| # │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │ | ||||
| # │                                        │    │                                                │     │                                        │ | ||||
| # │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │ | ||||
| # │  │ wg1 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg2 │            │ | ||||
| # │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │ | ||||
| # │  │192.168.241.1/24│  │192.168.1.100/24││    │    │192.168.1.100/24│    │10.0.0.1/24        │ │     │  │10.0.0.100/24   │ │192.168.241.2/24│ │ | ||||
| # │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │ | ||||
| # │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │ | ||||
| # └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘ | ||||
| 
 | ||||
| # ip1 link add dev wg1 type wireguard | ||||
| # ip2 link add dev wg1 type wireguard | ||||
| 
 | ||||
| n1 $program wg1 | ||||
| n2 $program wg2 | ||||
| 
 | ||||
| configure_peers | ||||
| 
 | ||||
| ip0 link add vethrc type veth peer name vethc | ||||
| ip0 link add vethrs type veth peer name veths | ||||
| ip0 link set vethc netns $netns1 | ||||
| ip0 link set veths netns $netns2 | ||||
| ip0 link set vethrc up | ||||
| ip0 link set vethrs up | ||||
| ip0 addr add 192.168.1.1/24 dev vethrc | ||||
| ip0 addr add 10.0.0.1/24 dev vethrs | ||||
| ip1 addr add 192.168.1.100/24 dev vethc | ||||
| ip1 link set vethc up | ||||
| ip1 route add default via 192.168.1.1 | ||||
| ip2 addr add 10.0.0.100/24 dev veths | ||||
| ip2 link set veths up | ||||
| waitiface $netns0 vethrc | ||||
| waitiface $netns0 vethrs | ||||
| waitiface $netns1 vethc | ||||
| waitiface $netns2 veths | ||||
| 
 | ||||
| n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward' | ||||
| n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout' | ||||
| n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream' | ||||
| n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1 | ||||
| 
 | ||||
| n0 wg set wg1 peer "$pub2" endpoint 10.0.0.100:20000 persistent-keepalive 1 | ||||
| n1 ping -W 1 -c 1 192.168.241.2 | ||||
| n2 ping -W 1 -c 1 192.168.241.1 | ||||
| [[ $(n2 wg show wg2 endpoints) == "$pub1    10.0.0.1:10000" ]] | ||||
| # Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`). | ||||
| pp sleep 3 | ||||
| n2 ping -W 1 -c 1 192.168.241.1 | ||||
| 
 | ||||
| n0 iptables -t nat -F | ||||
| ip0 link del vethrc | ||||
| ip0 link del vethrs | ||||
| ip1 link del wg1 | ||||
| ip2 link del wg2 | ||||
| 
 | ||||
| # Test that saddr routing is sticky but not too sticky, changing to this topology: | ||||
| # ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐ | ||||
| # │             $ns1 namespace             │    │             $ns2 namespace             │ | ||||
| # │                                        │    │                                        │ | ||||
| # │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │ | ||||
| # │  │ wg1 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg2 │            │ | ||||
| # │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │ | ||||
| # │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │ | ||||
| # │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │ | ||||
| # │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │ | ||||
| # └────────────────────────────────────────┘    └────────────────────────────────────────┘ | ||||
| 
 | ||||
| # ip1 link add dev wg1 type wireguard | ||||
| # ip2 link add dev wg1 type wireguard | ||||
| n1 $program wg1 | ||||
| n2 $program wg1 | ||||
| 
 | ||||
| configure_peers | ||||
| 
 | ||||
| ip1 link add veth1 type veth peer name veth2 | ||||
| ip1 link set veth2 netns $netns2 | ||||
| n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad' | ||||
| n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad' | ||||
| n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries' | ||||
| 
 | ||||
| # First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed | ||||
| ip1 addr add 10.0.0.1/24 dev veth1 | ||||
| ip1 addr add fd00:aa::1/96 dev veth1 | ||||
| ip2 addr add 10.0.0.2/24 dev veth2 | ||||
| ip2 addr add fd00:aa::2/96 dev veth2 | ||||
| ip1 link set veth1 up | ||||
| ip2 link set veth2 up | ||||
| waitiface $netns1 veth1 | ||||
| waitiface $netns2 veth2 | ||||
| n0 wg set wg1 peer "$pub2" endpoint 10.0.0.2:20000 | ||||
| n1 ping -W 1 -c 1 192.168.241.2 | ||||
| ip1 addr add 10.0.0.10/24 dev veth1 | ||||
| ip1 addr del 10.0.0.1/24 dev veth1 | ||||
| n1 ping -W 1 -c 1 192.168.241.2 | ||||
| n0 wg set wg1 peer "$pub2" endpoint [fd00:aa::2]:20000 | ||||
| n1 ping -W 1 -c 1 192.168.241.2 | ||||
| ip1 addr add fd00:aa::10/96 dev veth1 | ||||
| ip1 addr del fd00:aa::1/96 dev veth1 | ||||
| n1 ping -W 1 -c 1 192.168.241.2 | ||||
| 
 | ||||
| # Now we show that we can successfully do reply to sender routing | ||||
| ip1 link set veth1 down | ||||
| ip2 link set veth2 down | ||||
| ip1 addr flush dev veth1 | ||||
| ip2 addr flush dev veth2 | ||||
| ip1 addr add 10.0.0.1/24 dev veth1 | ||||
| ip1 addr add 10.0.0.2/24 dev veth1 | ||||
| ip1 addr add fd00:aa::1/96 dev veth1 | ||||
| ip1 addr add fd00:aa::2/96 dev veth1 | ||||
| ip2 addr add 10.0.0.3/24 dev veth2 | ||||
| ip2 addr add fd00:aa::3/96 dev veth2 | ||||
| ip1 link set veth1 up | ||||
| ip2 link set veth2 up | ||||
| waitiface $netns1 veth1 | ||||
| waitiface $netns2 veth2 | ||||
| n0 wg set wg2 peer "$pub1" endpoint 10.0.0.1:10000 | ||||
| n2 ping -W 1 -c 1 192.168.241.1 | ||||
| [[ $(n0 wg show wg2 endpoints) == "$pub1    10.0.0.1:10000" ]] | ||||
| n0 wg set wg2 peer "$pub1" endpoint [fd00:aa::1]:10000 | ||||
| n2 ping -W 1 -c 1 192.168.241.1 | ||||
| [[ $(n0 wg show wg2 endpoints) == "$pub1    [fd00:aa::1]:10000" ]] | ||||
| n0 wg set wg2 peer "$pub1" endpoint 10.0.0.2:10000 | ||||
| n2 ping -W 1 -c 1 192.168.241.1 | ||||
| [[ $(n0 wg show wg2 endpoints) == "$pub1    10.0.0.2:10000" ]] | ||||
| n0 wg set wg2 peer "$pub1" endpoint [fd00:aa::2]:10000 | ||||
| n2 ping -W 1 -c 1 192.168.241.1 | ||||
| [[ $(n0 wg show wg2 endpoints) == "$pub1    [fd00:aa::2]:10000" ]] | ||||
| 
 | ||||
| ip1 link del veth1 | ||||
| ip1 link del wg1 | ||||
| ip2 link del wg2 | ||||
|  | @ -38,7 +38,7 @@ type Trie struct { | |||
|  */ | ||||
| func commonBits(ip1 []byte, ip2 []byte) uint { | ||||
| 	var i uint | ||||
| 	size := uint(len(ip1)) / 4 | ||||
| 	size := uint(len(ip1)) | ||||
| 
 | ||||
| 	for i = 0; i < size; i++ { | ||||
| 		v := ip1[i] ^ ip2[i] | ||||
|  |  | |||
|  | @ -44,7 +44,12 @@ func (l *UAPIListener) Accept() (net.Conn, error) { | |||
| } | ||||
| 
 | ||||
| func (l *UAPIListener) Close() error { | ||||
| 	return l.listener.Close() | ||||
| 	err1 := unix.Close(l.inotifyFd) | ||||
| 	err2 := l.listener.Close() | ||||
| 	if err1 != nil { | ||||
| 		return err1 | ||||
| 	} | ||||
| 	return err2 | ||||
| } | ||||
| 
 | ||||
| func (l *UAPIListener) Addr() net.Addr { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue