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
|
@ -28,6 +28,7 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||||
// create lines
|
// create lines
|
||||||
|
|
||||||
device.mutex.RLock()
|
device.mutex.RLock()
|
||||||
|
device.net.mutex.RLock()
|
||||||
|
|
||||||
lines := make([]string, 0, 100)
|
lines := make([]string, 0, 100)
|
||||||
send := func(line string) {
|
send := func(line string) {
|
||||||
|
@ -38,7 +39,9 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||||
send("private_key=" + device.privateKey.ToHex())
|
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 {
|
for _, peer := range device.peers {
|
||||||
func() {
|
func() {
|
||||||
|
@ -68,6 +71,7 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device.net.mutex.RUnlock()
|
||||||
device.mutex.RUnlock()
|
device.mutex.RUnlock()
|
||||||
|
|
||||||
// send lines
|
// send lines
|
||||||
|
@ -84,38 +88,6 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||||
return nil
|
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 {
|
func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||||
scanner := bufio.NewScanner(socket)
|
scanner := bufio.NewScanner(socket)
|
||||||
logInfo := device.log.Info
|
logInfo := device.log.Info
|
||||||
|
@ -166,13 +138,22 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||||
logError.Println("Failed to set listen_port:", err)
|
logError.Println("Failed to set listen_port:", err)
|
||||||
return &IPCError{Code: ipcErrorInvalid}
|
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 := &device.net
|
||||||
netc.mutex.Lock()
|
netc.mutex.Lock()
|
||||||
if netc.addr.Port != int(port) {
|
netc.addr = addr
|
||||||
netc.addr.Port = int(port)
|
|
||||||
}
|
|
||||||
netc.mutex.Unlock()
|
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
|
// 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)
|
logError.Println("Failed to get tun device status:", err)
|
||||||
return &IPCError{Code: ipcErrorIO}
|
return &IPCError{Code: ipcErrorIO}
|
||||||
}
|
}
|
||||||
if atomic.LoadInt32(&device.isUp) == AtomicTrue && !dummy {
|
if device.tun.isUp.Get() && !dummy {
|
||||||
peer.SendKeepAlive()
|
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 */
|
/* Implementation specific constants */
|
||||||
|
|
||||||
const (
|
const (
|
||||||
QueueOutboundSize = 1024
|
QueueOutboundSize = 1024
|
||||||
QueueInboundSize = 1024
|
QueueInboundSize = 1024
|
||||||
QueueHandshakeSize = 1024
|
QueueHandshakeSize = 1024
|
||||||
QueueHandshakeBusySize = QueueHandshakeSize / 8
|
MinMessageSize = MessageTransportSize // size of keep-alive
|
||||||
MinMessageSize = MessageTransportSize // size of keep-alive
|
MaxMessageSize = ((1 << 16) - 1) + MessageTransportHeaderSize
|
||||||
MaxMessageSize = ((1 << 16) - 1) + MessageTransportHeaderSize
|
MaxPeers = 1 << 16
|
||||||
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"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
mtu int32
|
|
||||||
tun TUNDevice
|
|
||||||
log *Logger // collection of loggers for levels
|
log *Logger // collection of loggers for levels
|
||||||
idCounter uint // for assigning debug ids to peers
|
idCounter uint // for assigning debug ids to peers
|
||||||
fwMark uint32
|
fwMark uint32
|
||||||
pool struct {
|
tun struct {
|
||||||
// pools objects for reuse
|
device TUNDevice
|
||||||
|
isUp AtomicBool
|
||||||
|
mtu int32
|
||||||
|
}
|
||||||
|
pool struct {
|
||||||
messageBuffers sync.Pool
|
messageBuffers sync.Pool
|
||||||
}
|
}
|
||||||
net struct {
|
net struct {
|
||||||
// seperate for performance reasons
|
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
addr *net.UDPAddr // UDP source address
|
addr *net.UDPAddr // UDP source address
|
||||||
conn *net.UDPConn // UDP "connection"
|
conn *net.UDPConn // UDP "connection"
|
||||||
|
@ -35,13 +37,12 @@ type Device struct {
|
||||||
}
|
}
|
||||||
signal struct {
|
signal struct {
|
||||||
stop chan struct{} // halts all go routines
|
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
|
underLoadUntil atomic.Value
|
||||||
underLoad int32 // atomic bool: device is under load
|
ratelimiter Ratelimiter
|
||||||
ratelimiter Ratelimiter
|
peers map[NoisePublicKey]*Peer
|
||||||
peers map[NoisePublicKey]*Peer
|
mac MACStateDevice
|
||||||
mac MACStateDevice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Warning:
|
/* Warning:
|
||||||
|
@ -58,6 +59,23 @@ func removePeerUnsafe(device *Device, key NoisePublicKey) {
|
||||||
peer.Close()
|
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 {
|
func (device *Device) SetPrivateKey(sk NoisePrivateKey) error {
|
||||||
device.mutex.Lock()
|
device.mutex.Lock()
|
||||||
defer device.mutex.Unlock()
|
defer device.mutex.Unlock()
|
||||||
|
@ -115,20 +133,13 @@ func NewDevice(tun TUNDevice, logLevel int) *Device {
|
||||||
device.mutex.Lock()
|
device.mutex.Lock()
|
||||||
defer device.mutex.Unlock()
|
defer device.mutex.Unlock()
|
||||||
|
|
||||||
device.tun = tun
|
device.log = NewLogger(logLevel, "("+tun.Name()+") ")
|
||||||
device.log = NewLogger(logLevel)
|
|
||||||
device.peers = make(map[NoisePublicKey]*Peer)
|
device.peers = make(map[NoisePublicKey]*Peer)
|
||||||
|
device.tun.device = tun
|
||||||
device.indices.Init()
|
device.indices.Init()
|
||||||
device.ratelimiter.Init()
|
device.ratelimiter.Init()
|
||||||
device.routingTable.Reset()
|
device.routingTable.Reset()
|
||||||
|
device.underLoadUntil.Store(time.Time{})
|
||||||
// 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()
|
|
||||||
|
|
||||||
// setup pools
|
// setup pools
|
||||||
|
|
||||||
|
@ -157,42 +168,43 @@ func NewDevice(tun TUNDevice, logLevel int) *Device {
|
||||||
go device.RoutineHandshake()
|
go device.RoutineHandshake()
|
||||||
}
|
}
|
||||||
|
|
||||||
go device.RoutineBusyMonitor()
|
|
||||||
go device.RoutineReadFromTUN()
|
|
||||||
go device.RoutineTUNEventReader()
|
go device.RoutineTUNEventReader()
|
||||||
go device.RoutineReceiveIncomming()
|
|
||||||
go device.ratelimiter.RoutineGarbageCollector(device.signal.stop)
|
go device.ratelimiter.RoutineGarbageCollector(device.signal.stop)
|
||||||
|
go device.RoutineReadFromTUN()
|
||||||
|
go device.RoutineReceiveIncomming()
|
||||||
|
|
||||||
return device
|
return device
|
||||||
}
|
}
|
||||||
|
|
||||||
func (device *Device) RoutineTUNEventReader() {
|
func (device *Device) RoutineTUNEventReader() {
|
||||||
events := device.tun.Events()
|
logInfo := device.log.Info
|
||||||
logError := device.log.Error
|
logError := device.log.Error
|
||||||
|
|
||||||
|
events := device.tun.device.Events()
|
||||||
|
|
||||||
for event := range events {
|
for event := range events {
|
||||||
if event&TUNEventMTUUpdate != 0 {
|
if event&TUNEventMTUUpdate != 0 {
|
||||||
mtu, err := device.tun.MTU()
|
mtu, err := device.tun.device.MTU()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logError.Println("Failed to load updated MTU of device:", err)
|
logError.Println("Failed to load updated MTU of device:", err)
|
||||||
} else {
|
} else {
|
||||||
if mtu+MessageTransportSize > MaxMessageSize {
|
if mtu+MessageTransportSize > MaxMessageSize {
|
||||||
mtu = MaxMessageSize - MessageTransportSize
|
mtu = MaxMessageSize - MessageTransportSize
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&device.mtu, int32(mtu))
|
atomic.StoreInt32(&device.tun.mtu, int32(mtu))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if event&TUNEventUp != 0 {
|
if event&TUNEventUp != 0 {
|
||||||
println("handle 1")
|
device.tun.isUp.Set(true)
|
||||||
atomic.StoreInt32(&device.isUp, AtomicTrue)
|
|
||||||
updateUDPConn(device)
|
updateUDPConn(device)
|
||||||
println("handle 2", device.net.conn)
|
logInfo.Println("Interface set up")
|
||||||
}
|
}
|
||||||
|
|
||||||
if event&TUNEventDown != 0 {
|
if event&TUNEventDown != 0 {
|
||||||
atomic.StoreInt32(&device.isUp, AtomicFalse)
|
device.tun.isUp.Set(false)
|
||||||
closeUDPConn(device)
|
closeUDPConn(device)
|
||||||
|
logInfo.Println("Interface set down")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,6 +236,7 @@ func (device *Device) RemoveAllPeers() {
|
||||||
func (device *Device) Close() {
|
func (device *Device) Close() {
|
||||||
device.RemoveAllPeers()
|
device.RemoveAllPeers()
|
||||||
close(device.signal.stop)
|
close(device.signal.stop)
|
||||||
|
closeUDPConn(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (device *Device) WaitChannel() chan struct{} {
|
func (device *Device) WaitChannel() chan struct{} {
|
||||||
|
|
|
@ -12,6 +12,7 @@ type DummyTUN struct {
|
||||||
name string
|
name string
|
||||||
mtu int
|
mtu int
|
||||||
packets chan []byte
|
packets chan []byte
|
||||||
|
events chan TUNEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *DummyTUN) Name() string {
|
func (tun *DummyTUN) Name() string {
|
||||||
|
@ -27,6 +28,14 @@ func (tun *DummyTUN) Write(d []byte) (int, error) {
|
||||||
return len(d), nil
|
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) {
|
func (tun *DummyTUN) Read(d []byte) (int, error) {
|
||||||
t := <-tun.packets
|
t := <-tun.packets
|
||||||
copy(d, t)
|
copy(d, t)
|
||||||
|
|
|
@ -2,8 +2,8 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Index=0 is reserved for unset indecies
|
/* Index=0 is reserved for unset indecies
|
||||||
|
@ -24,7 +24,8 @@ type IndexTable struct {
|
||||||
func randUint32() (uint32, error) {
|
func randUint32() (uint32, error) {
|
||||||
var buff [4]byte
|
var buff [4]byte
|
||||||
_, err := rand.Read(buff[:])
|
_, err := rand.Read(buff[:])
|
||||||
return *((*uint32)(unsafe.Pointer(&buff))), err
|
value := binary.LittleEndian.Uint32(buff[:])
|
||||||
|
return value, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (table *IndexTable) Init() {
|
func (table *IndexTable) Init() {
|
||||||
|
|
|
@ -19,7 +19,7 @@ type Logger struct {
|
||||||
Error *log.Logger
|
Error *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogger(level int) *Logger {
|
func NewLogger(level int, prepend string) *Logger {
|
||||||
output := os.Stdout
|
output := os.Stdout
|
||||||
logger := new(Logger)
|
logger := new(Logger)
|
||||||
|
|
||||||
|
@ -34,16 +34,16 @@ func NewLogger(level int) *Logger {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
logger.Debug = log.New(logDebug,
|
logger.Debug = log.New(logDebug,
|
||||||
"DEBUG: ",
|
"DEBUG: "+prepend,
|
||||||
log.Ldate|log.Ltime|log.Lshortfile,
|
log.Ldate|log.Ltime|log.Lshortfile,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.Info = log.New(logInfo,
|
logger.Info = log.New(logInfo,
|
||||||
"INFO: ",
|
"INFO: "+prepend,
|
||||||
log.Ldate|log.Ltime,
|
log.Ldate|log.Ltime,
|
||||||
)
|
)
|
||||||
logger.Error = log.New(logErr,
|
logger.Error = log.New(logErr,
|
||||||
"ERROR: ",
|
"ERROR: "+prepend,
|
||||||
log.Ldate|log.Ltime,
|
log.Ldate|log.Ltime,
|
||||||
)
|
)
|
||||||
return logger
|
return logger
|
||||||
|
|
|
@ -13,8 +13,8 @@ func TestMAC1(t *testing.T) {
|
||||||
defer dev1.Close()
|
defer dev1.Close()
|
||||||
defer dev2.Close()
|
defer dev2.Close()
|
||||||
|
|
||||||
peer1 := dev2.NewPeer(dev1.privateKey.publicKey())
|
peer1, _ := dev2.NewPeer(dev1.privateKey.publicKey())
|
||||||
peer2 := dev1.NewPeer(dev2.privateKey.publicKey())
|
peer2, _ := dev1.NewPeer(dev2.privateKey.publicKey())
|
||||||
|
|
||||||
assertEqual(t, peer1.mac.keyMAC1[:], dev1.mac.keyMAC1[:])
|
assertEqual(t, peer1.mac.keyMAC1[:], dev1.mac.keyMAC1[:])
|
||||||
assertEqual(t, peer2.mac.keyMAC1[:], dev2.mac.keyMAC1[:])
|
assertEqual(t, peer2.mac.keyMAC1[:], dev2.mac.keyMAC1[:])
|
||||||
|
@ -45,8 +45,8 @@ func TestMACs(t *testing.T) {
|
||||||
defer device1.Close()
|
defer device1.Close()
|
||||||
defer device2.Close()
|
defer device2.Close()
|
||||||
|
|
||||||
peer1 := device2.NewPeer(device1.privateKey.publicKey())
|
peer1, _ := device2.NewPeer(device1.privateKey.publicKey())
|
||||||
peer2 := device1.NewPeer(device2.privateKey.publicKey())
|
peer2, _ := device1.NewPeer(device2.privateKey.publicKey())
|
||||||
|
|
||||||
if addr.Port < 0 {
|
if addr.Port < 0 {
|
||||||
return true
|
return true
|
||||||
|
|
16
src/main.go
16
src/main.go
|
@ -65,9 +65,23 @@ func main() {
|
||||||
return
|
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
|
// create wireguard device
|
||||||
|
|
||||||
device := NewDevice(tun, LogLevelDebug)
|
device := NewDevice(tun, logLevel)
|
||||||
|
|
||||||
logInfo := device.log.Info
|
logInfo := device.log.Info
|
||||||
logError := device.log.Error
|
logError := device.log.Error
|
||||||
|
|
19
src/misc.go
19
src/misc.go
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,10 +9,26 @@ import (
|
||||||
* (since booleans are not natively supported by sync/atomic)
|
* (since booleans are not natively supported by sync/atomic)
|
||||||
*/
|
*/
|
||||||
const (
|
const (
|
||||||
AtomicFalse = iota
|
AtomicFalse = int32(iota)
|
||||||
AtomicTrue
|
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 {
|
func min(a uint, b uint) uint {
|
||||||
if a > b {
|
if a > b {
|
||||||
return b
|
return b
|
||||||
|
|
|
@ -31,8 +31,8 @@ func TestNoiseHandshake(t *testing.T) {
|
||||||
defer dev1.Close()
|
defer dev1.Close()
|
||||||
defer dev2.Close()
|
defer dev2.Close()
|
||||||
|
|
||||||
peer1 := dev2.NewPeer(dev1.privateKey.publicKey())
|
peer1, _ := dev2.NewPeer(dev1.privateKey.publicKey())
|
||||||
peer2 := dev1.NewPeer(dev2.privateKey.publicKey())
|
peer2, _ := dev1.NewPeer(dev2.privateKey.publicKey())
|
||||||
|
|
||||||
assertEqual(
|
assertEqual(
|
||||||
t,
|
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() {
|
func (device *Device) RoutineReceiveIncomming() {
|
||||||
|
|
||||||
logDebug := device.log.Debug
|
logDebug := device.log.Debug
|
||||||
|
@ -118,117 +81,121 @@ func (device *Device) RoutineReceiveIncomming() {
|
||||||
|
|
||||||
// wait for new conn
|
// wait for new conn
|
||||||
|
|
||||||
var conn *net.UDPConn
|
logDebug.Println("Waiting for udp socket")
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-device.signal.newUDPConn:
|
|
||||||
device.net.mutex.RLock()
|
|
||||||
conn = device.net.conn
|
|
||||||
device.net.mutex.RUnlock()
|
|
||||||
|
|
||||||
case <-device.signal.stop:
|
case <-device.signal.stop:
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
if conn == nil {
|
case <-device.signal.newUDPConn:
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// receive datagrams until closed
|
// fetch connection
|
||||||
|
|
||||||
buffer := device.GetMessageBuffer()
|
device.net.mutex.RLock()
|
||||||
|
conn := device.net.conn
|
||||||
for {
|
device.net.mutex.RUnlock()
|
||||||
|
if conn == nil {
|
||||||
// read next datagram
|
|
||||||
|
|
||||||
size, raddr, err := conn.ReadFromUDP(buffer[:]) // TODO: This is broken
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if size < MinMessageSize {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// check size of packet
|
logDebug.Println("Listening for inbound packets")
|
||||||
|
|
||||||
packet := buffer[:size]
|
// receive datagrams until conn is closed
|
||||||
msgType := binary.LittleEndian.Uint32(packet[:4])
|
|
||||||
|
|
||||||
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookup key pair
|
// check size of packet
|
||||||
|
|
||||||
receiver := binary.LittleEndian.Uint32(
|
packet := buffer[:size]
|
||||||
packet[MessageTransportOffsetReceiver:MessageTransportOffsetCounter],
|
msgType := binary.LittleEndian.Uint32(packet[:4])
|
||||||
)
|
|
||||||
value := device.indices.Lookup(receiver)
|
|
||||||
keyPair := value.keyPair
|
|
||||||
if keyPair == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// check key-pair expiry
|
var okay bool
|
||||||
|
|
||||||
if keyPair.created.Add(RejectAfterTime).Before(time.Now()) {
|
switch msgType {
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// create work element
|
// check if transport
|
||||||
|
|
||||||
peer := value.peer
|
case MessageTransportType:
|
||||||
elem := &QueueInboundElement{
|
|
||||||
packet: packet,
|
|
||||||
buffer: buffer,
|
|
||||||
keyPair: keyPair,
|
|
||||||
dropped: AtomicFalse,
|
|
||||||
}
|
|
||||||
elem.mutex.Lock()
|
|
||||||
|
|
||||||
// add to decryption queues
|
// check size
|
||||||
|
|
||||||
device.addToInboundQueue(device.queue.decryption, elem)
|
if len(packet) < MessageTransportType {
|
||||||
device.addToInboundQueue(peer.queue.inbound, elem)
|
continue
|
||||||
buffer = nil
|
}
|
||||||
continue
|
|
||||||
|
|
||||||
// otherwise it is a handshake related packet
|
// lookup key pair
|
||||||
|
|
||||||
case MessageInitiationType:
|
receiver := binary.LittleEndian.Uint32(
|
||||||
okay = len(packet) == MessageInitiationSize
|
packet[MessageTransportOffsetReceiver:MessageTransportOffsetCounter],
|
||||||
|
)
|
||||||
|
value := device.indices.Lookup(receiver)
|
||||||
|
keyPair := value.keyPair
|
||||||
|
if keyPair == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
case MessageResponseType:
|
// check key-pair expiry
|
||||||
okay = len(packet) == MessageResponseSize
|
|
||||||
|
|
||||||
case MessageCookieReplyType:
|
if keyPair.created.Add(RejectAfterTime).Before(time.Now()) {
|
||||||
okay = len(packet) == MessageCookieReplySize
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if okay {
|
// create work element
|
||||||
device.addToHandshakeQueue(
|
|
||||||
device.queue.handshake,
|
peer := value.peer
|
||||||
QueueHandshakeElement{
|
elem := &QueueInboundElement{
|
||||||
msgType: msgType,
|
|
||||||
buffer: buffer,
|
|
||||||
packet: packet,
|
packet: packet,
|
||||||
source: raddr,
|
buffer: buffer,
|
||||||
},
|
keyPair: keyPair,
|
||||||
)
|
dropped: AtomicFalse,
|
||||||
buffer = device.GetMessageBuffer()
|
}
|
||||||
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
busy := atomic.LoadInt32(&device.underLoad) == AtomicTrue
|
if device.IsUnderLoad() {
|
||||||
|
|
||||||
if busy {
|
|
||||||
if !device.mac.CheckMAC2(elem.packet, elem.source) {
|
if !device.mac.CheckMAC2(elem.packet, elem.source) {
|
||||||
|
|
||||||
|
// construct cookie reply
|
||||||
|
|
||||||
sender := binary.LittleEndian.Uint32(elem.packet[4:8]) // "sender" always follows "type"
|
sender := binary.LittleEndian.Uint32(elem.packet[4:8]) // "sender" always follows "type"
|
||||||
reply, err := device.CreateMessageCookieReply(elem.packet, sender, elem.source)
|
reply, err := device.CreateMessageCookieReply(elem.packet, sender, elem.source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -347,6 +315,7 @@ func (device *Device) RoutineHandshake() {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !device.ratelimiter.Allow(elem.source.IP) {
|
if !device.ratelimiter.Allow(elem.source.IP) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -577,7 +546,7 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||||
// write to tun
|
// write to tun
|
||||||
|
|
||||||
atomic.AddUint64(&peer.stats.rxBytes, uint64(len(elem.packet)))
|
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)
|
device.PutMessageBuffer(elem.buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logError.Println("Failed to write packet to TUN device:", err)
|
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() {
|
func (device *Device) RoutineReadFromTUN() {
|
||||||
|
|
||||||
if device.tun == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var elem *QueueOutboundElement
|
var elem *QueueOutboundElement
|
||||||
|
|
||||||
logDebug := device.log.Debug
|
logDebug := device.log.Debug
|
||||||
|
@ -155,9 +151,8 @@ func (device *Device) RoutineReadFromTUN() {
|
||||||
elem = device.NewOutboundElement()
|
elem = device.NewOutboundElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: THIS!
|
|
||||||
elem.packet = elem.buffer[MessageTransportHeaderSize:]
|
elem.packet = elem.buffer[MessageTransportHeaderSize:]
|
||||||
size, err := device.tun.Read(elem.packet)
|
size, err := device.tun.device.Read(elem.packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logError.Println("Failed to read packet from TUN device:", err)
|
logError.Println("Failed to read packet from TUN device:", err)
|
||||||
device.Close()
|
device.Close()
|
||||||
|
@ -345,7 +340,7 @@ func (device *Device) RoutineEncryption() {
|
||||||
|
|
||||||
// pad content to MTU size
|
// pad content to MTU size
|
||||||
|
|
||||||
mtu := int(atomic.LoadInt32(&device.mtu))
|
mtu := int(atomic.LoadInt32(&device.tun.mtu))
|
||||||
pad := len(elem.packet) % PaddingMultiple
|
pad := len(elem.packet) % PaddingMultiple
|
||||||
if pad > 0 {
|
if pad > 0 {
|
||||||
for i := 0; i < PaddingMultiple-pad && len(elem.packet) < mtu; i++ {
|
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 {
|
func commonBits(ip1 []byte, ip2 []byte) uint {
|
||||||
var i uint
|
var i uint
|
||||||
size := uint(len(ip1)) / 4
|
size := uint(len(ip1))
|
||||||
|
|
||||||
for i = 0; i < size; i++ {
|
for i = 0; i < size; i++ {
|
||||||
v := ip1[i] ^ ip2[i]
|
v := ip1[i] ^ ip2[i]
|
||||||
|
|
|
@ -44,7 +44,12 @@ func (l *UAPIListener) Accept() (net.Conn, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *UAPIListener) Close() 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 {
|
func (l *UAPIListener) Addr() net.Addr {
|
||||||
|
|
Loading…
Reference in a new issue