From 69fe86edf0ba371b9b0a54e522ec20d33e0ae129 Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Tue, 14 Nov 2017 16:27:53 +0100 Subject: Initial working source caching --- src/tests/netns.sh | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'src/tests') diff --git a/src/tests/netns.sh b/src/tests/netns.sh index 043da3e..9124b80 100755 --- a/src/tests/netns.sh +++ b/src/tests/netns.sh @@ -28,7 +28,7 @@ netns0="wg-test-$$-0" netns1="wg-test-$$-1" netns2="wg-test-$$-2" program="../wireguard-go" -export LOG_LEVEL="error" +export LOG_LEVEL="debug" pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; } pp() { pretty "" "$*"; "$@"; } @@ -147,6 +147,8 @@ tests() { n1 iperf3 -Z -n 1G -b 0 -u -c fd00::2 } +echo "4" + [[ $(ip1 link show dev wg1) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}" big_mtu=$(( 34816 - 1500 + $orig_mtu )) @@ -185,14 +187,14 @@ 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" ]] +n1 ping6 -W 1 -c 1 fd00::2 +[[ $(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" ]] +[[ $(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 @@ -212,7 +214,7 @@ 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" ]] +[[ $(n1 wg show wg1 endpoints) == "$pub2 [::1]:9997" ]] ip1 link del wg1 ip2 link del wg2 @@ -232,8 +234,9 @@ ip2 link del wg2 # ip1 link add dev wg1 type wireguard # ip2 link add dev wg1 type wireguard -n1 $program wg1 -n2 $program wg2 +n1 $program -f wg1 & +n2 $program -f wg2 & +sleep 5 configure_peers @@ -263,7 +266,7 @@ n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 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" ]] +[[ $(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 @@ -288,8 +291,9 @@ ip2 link del wg2 # ip1 link add dev wg1 type wireguard # ip2 link add dev wg1 type wireguard -n1 $program wg1 -n2 $program wg1 +n1 $program -f wg1 & +n2 $program -f wg2 & +sleep 5 configure_peers @@ -336,17 +340,18 @@ 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 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 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 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" ]] +[[ $(n0 wg show wg2 endpoints) == "$pub1 [fd00:aa::2]:10000" ]] ip1 link del veth1 ip1 link del wg1 ip2 link del wg2 +echo "done" -- cgit v1.2.3 From 88801529fd4097993f7c448b1c3eee0abc8cb51c Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Tue, 14 Nov 2017 18:26:28 +0100 Subject: Moved TUN device creation to pre-fork --- src/daemon_linux.go | 11 +----- src/device.go | 4 +-- src/main.go | 102 +++++++++++++++++++++++++++++++++++----------------- src/tests/netns.sh | 21 +++++------ src/tun.go | 2 ++ src/tun_linux.go | 28 +++++++++++++++ 6 files changed, 110 insertions(+), 58 deletions(-) (limited to 'src/tests') diff --git a/src/daemon_linux.go b/src/daemon_linux.go index 730f89e..8210f8b 100644 --- a/src/daemon_linux.go +++ b/src/daemon_linux.go @@ -11,18 +11,9 @@ import ( * TODO: Use env variable to spawn in background */ -func Daemonize() error { +func Daemonize(attr *os.ProcAttr) error { argv := []string{os.Args[0], "--foreground"} argv = append(argv, os.Args[1:]...) - attr := &os.ProcAttr{ - Dir: ".", - Env: os.Environ(), - Files: []*os.File{ - os.Stdin, - nil, - nil, - }, - } process, err := os.StartProcess( argv[0], argv, diff --git a/src/device.go b/src/device.go index 9422d49..429ee46 100644 --- a/src/device.go +++ b/src/device.go @@ -126,13 +126,13 @@ func (device *Device) PutMessageBuffer(msg *[MaxMessageSize]byte) { device.pool.messageBuffers.Put(msg) } -func NewDevice(tun TUNDevice, logLevel int) *Device { +func NewDevice(tun TUNDevice, logger *Logger) *Device { device := new(Device) device.mutex.Lock() defer device.mutex.Unlock() - device.log = NewLogger(logLevel, "("+tun.Name()+") ") + device.log = logger device.peers = make(map[NoisePublicKey]*Peer) device.tun.device = tun diff --git a/src/main.go b/src/main.go index eb3c67f..3808c9c 100644 --- a/src/main.go +++ b/src/main.go @@ -2,10 +2,14 @@ package main import ( "fmt" - "log" "os" "os/signal" "runtime" + "strconv" +) + +const ( + EnvWGTunFD = "WG_TUN_FD" ) func printUsage() { @@ -43,28 +47,6 @@ func main() { interfaceName = os.Args[1] } - // daemonize the process - - if !foreground { - err := Daemonize() - if err != nil { - log.Println("Failed to daemonize:", err) - } - return - } - - // increase number of go workers (for Go <1.5) - - runtime.GOMAXPROCS(runtime.NumCPU()) - - // open TUN device - - tun, err := CreateTUN(interfaceName) - if err != nil { - log.Println("Failed to create tun device:", err) - return - } - // get log level (default: info) logLevel := func() int { @@ -79,22 +61,76 @@ func main() { return LogLevelInfo }() - // create wireguard device + logger := NewLogger( + logLevel, + fmt.Sprintf("(%s) ", interfaceName), + ) + logger.Debug.Println("Debug log enabled") - device := NewDevice(tun, logLevel) + // open TUN device - logInfo := device.log.Info - logError := device.log.Error - logDebug := device.log.Debug + tun, err := func() (TUNDevice, error) { + tunFdStr := os.Getenv(EnvWGTunFD) + if tunFdStr == "" { + return CreateTUN(interfaceName) + } - logInfo.Println("Device started") - logDebug.Println("Debug log enabled") + // construct tun device from supplied FD + + fd, err := strconv.ParseUint(tunFdStr, 10, 32) + if err != nil { + return nil, err + } + + file := os.NewFile(uintptr(fd), "/dev/net/tun") + return CreateTUNFromFile(interfaceName, file) + }() + + if err != nil { + logger.Error.Println("Failed to create TUN device:", err) + } + + // daemonize the process + + if !foreground { + env := os.Environ() + _, ok := os.LookupEnv(EnvWGTunFD) + if !ok { + kvp := fmt.Sprintf("%s=3", EnvWGTunFD) + env = append(env, kvp) + } + attr := &os.ProcAttr{ + Files: []*os.File{ + nil, // stdin + nil, // stdout + nil, // stderr + tun.File(), + }, + Dir: ".", + Env: env, + } + err = Daemonize(attr) + if err != nil { + logger.Error.Println("Failed to daemonize:", err) + } + return + } + + // increase number of go workers (for Go <1.5) + + runtime.GOMAXPROCS(runtime.NumCPU()) + + // create wireguard device + + device := NewDevice(tun, logger) + logger.Info.Println("Device started") // start configuration lister uapi, err := NewUAPIListener(interfaceName) if err != nil { - logError.Fatal("UAPI listen error:", err) + logger.Error.Println("UAPI listen error:", err) + return } errs := make(chan error) @@ -112,7 +148,7 @@ func main() { } }() - logInfo.Println("UAPI listener started") + logger.Info.Println("UAPI listener started") // wait for program to terminate @@ -129,5 +165,5 @@ func main() { uapi.Close() - logInfo.Println("Closing") + logger.Info.Println("Shutting down") } diff --git a/src/tests/netns.sh b/src/tests/netns.sh index 9124b80..b5c2f9c 100755 --- a/src/tests/netns.sh +++ b/src/tests/netns.sh @@ -28,7 +28,7 @@ netns0="wg-test-$$-0" netns1="wg-test-$$-1" netns2="wg-test-$$-2" program="../wireguard-go" -export LOG_LEVEL="debug" +export LOG_LEVEL="info" pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; } pp() { pretty "" "$*"; "$@"; } @@ -72,13 +72,11 @@ pp ip netns add $netns2 ip0 link set up dev lo # ip0 link add dev wg1 type wireguard -n0 $program -f wg1 & -sleep 1 +n0 $program wg1 ip0 link set wg1 netns $netns1 # ip0 link add dev wg1 type wireguard -n0 $program -f wg2 & -sleep 1 +n0 $program wg2 ip0 link set wg2 netns $netns2 key1="$(pp wg genkey)" @@ -147,8 +145,6 @@ tests() { n1 iperf3 -Z -n 1G -b 0 -u -c fd00::2 } -echo "4" - [[ $(ip1 link show dev wg1) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}" big_mtu=$(( 34816 - 1500 + $orig_mtu )) @@ -234,9 +230,8 @@ ip2 link del wg2 # ip1 link add dev wg1 type wireguard # ip2 link add dev wg1 type wireguard -n1 $program -f wg1 & -n2 $program -f wg2 & -sleep 5 +n1 $program wg1 +n2 $program wg2 configure_peers @@ -291,9 +286,8 @@ ip2 link del wg2 # ip1 link add dev wg1 type wireguard # ip2 link add dev wg1 type wireguard -n1 $program -f wg1 & -n2 $program -f wg2 & -sleep 5 +n1 $program wg1 +n2 $program wg2 configure_peers @@ -354,4 +348,5 @@ n2 ping -W 1 -c 1 192.168.241.1 ip1 link del veth1 ip1 link del wg1 ip2 link del wg2 + echo "done" diff --git a/src/tun.go b/src/tun.go index 9eed987..5bdac0e 100644 --- a/src/tun.go +++ b/src/tun.go @@ -1,6 +1,7 @@ package main import ( + "os" "sync/atomic" ) @@ -15,6 +16,7 @@ const ( ) type TUNDevice interface { + File() *os.File // returns the file descriptor of the device Read([]byte) (int, error) // read a packet from the device (without any additional headers) Write([]byte) (int, error) // writes a packet to the device (without any additional headers) MTU() (int, error) // returns the MTU of the device diff --git a/src/tun_linux.go b/src/tun_linux.go index accc6c6..ce6304c 100644 --- a/src/tun_linux.go +++ b/src/tun_linux.go @@ -56,6 +56,11 @@ type NativeTun struct { events chan TUNEvent // device related events } +func (tun *NativeTun) File() *os.File { + println(tun.fd.Name()) + return tun.fd +} + func (tun *NativeTun) RoutineNetlinkListener() { sock := int(C.bind_rtmgrp()) if sock < 0 { @@ -248,6 +253,29 @@ func (tun *NativeTun) Close() error { return nil } +func CreateTUNFromFile(name string, fd *os.File) (TUNDevice, error) { + device := &NativeTun{ + fd: fd, + name: name, + events: make(chan TUNEvent, 5), + errors: make(chan error, 5), + } + + // start event listener + + var err error + device.index, err = getIFIndex(device.name) + if err != nil { + return nil, err + } + + go device.RoutineNetlinkListener() + + // set default MTU + + return device, device.setMTU(DefaultMTU) +} + func CreateTUN(name string) (TUNDevice, error) { // open clone device -- cgit v1.2.3 From fa399a91d5da9874cbf248e00db8dbd87b587e91 Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Fri, 17 Nov 2017 17:25:45 +0100 Subject: Ported remaining netns.sh - Ported remaining netns.sh tests - Begin work on generic implementation of bind interface --- src/conn.go | 16 +++++++++++ src/conn_default.go | 35 ++++++++++++++++++++++++ src/conn_linux.go | 2 +- src/cookie_test.go | 7 +++-- src/daemon_linux.go | 13 ++++++--- src/device.go | 8 ++++-- src/helper_test.go | 8 +++++- src/misc.go | 8 ++++++ src/noise_test.go | 8 +++--- src/receive.go | 27 +++++++++++++------ src/tests/netns.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/tun_linux.go | 1 - src/uapi.go | 13 ++++++++- 13 files changed, 194 insertions(+), 28 deletions(-) (limited to 'src/tests') diff --git a/src/conn.go b/src/conn.go index a047bb6..3cf00ab 100644 --- a/src/conn.go +++ b/src/conn.go @@ -15,6 +15,22 @@ type UDPBind interface { Close() error } +/* An Endpoint maintains the source/destination caching for a peer + * + * dst : the remote address of a peer + * src : the local address from which datagrams originate going to the peer + * + */ +type UDPEndpoint interface { + ClearSrc() // clears the source address + ClearDst() // clears the destination address + SrcToString() string // returns the local source address (ip:port) + DstToString() string // returns the destination address (ip:port) + DstToBytes() []byte // used for mac2 cookie calculations + DstIP() net.IP + SrcIP() net.IP +} + func parseEndpoint(s string) (*net.UDPAddr, error) { // ensure that the host is an IP address diff --git a/src/conn_default.go b/src/conn_default.go index 279643e..31cab5c 100644 --- a/src/conn_default.go +++ b/src/conn_default.go @@ -6,6 +6,41 @@ import ( "net" ) +/* This code is meant to be a temporary solution + * on platforms for which the sticky socket / source caching behavior + * has not yet been implemented. + * + * See conn_linux.go for an implementation on the linux platform. + */ + +type Endpoint *net.UDPAddr + +type NativeBind *net.UDPConn + +func CreateUDPBind(port uint16) (UDPBind, uint16, error) { + + // listen + + addr := UDPAddr{ + Port: int(port), + } + conn, err := net.ListenUDP("udp", &addr) + if err != nil { + return nil, 0, err + } + + // retrieve port + + laddr := conn.LocalAddr() + uaddr, _ = net.ResolveUDPAddr( + laddr.Network(), + laddr.String(), + ) + return uaddr.Port +} + +func (_ Endpoint) ClearSrc() {} + func SetMark(conn *net.UDPConn, value uint32) error { return nil } diff --git a/src/conn_linux.go b/src/conn_linux.go index 383ff7e..fb576b1 100644 --- a/src/conn_linux.go +++ b/src/conn_linux.go @@ -168,7 +168,7 @@ func (end *Endpoint) DstIP() net.IP { } } -func (end *Endpoint) SrcToBytes() []byte { +func (end *Endpoint) DstToBytes() []byte { ptr := unsafe.Pointer(&end.src) arr := (*[unix.SizeofSockaddrInet6]byte)(ptr) return arr[:] diff --git a/src/cookie_test.go b/src/cookie_test.go index 193a76e..d745fe7 100644 --- a/src/cookie_test.go +++ b/src/cookie_test.go @@ -1,7 +1,6 @@ package main import ( - "net" "testing" ) @@ -25,7 +24,7 @@ func TestCookieMAC1(t *testing.T) { // check mac1 - src, _ := net.ResolveUDPAddr("udp", "192.168.13.37:4000") + src := []byte{192, 168, 13, 37, 10, 10, 10} checkMAC1 := func(msg []byte) { generator.AddMacs(msg) @@ -128,12 +127,12 @@ func TestCookieMAC1(t *testing.T) { msg[5] ^= 0x20 - srcBad1, _ := net.ResolveUDPAddr("udp", "192.168.13.37:4001") + srcBad1 := []byte{192, 168, 13, 37, 40, 01} if checker.CheckMAC2(msg, srcBad1) { t.Fatal("MAC2 generation/verification failed") } - srcBad2, _ := net.ResolveUDPAddr("udp", "192.168.13.38:4000") + srcBad2 := []byte{192, 168, 13, 38, 40, 01} if checker.CheckMAC2(msg, srcBad2) { t.Fatal("MAC2 generation/verification failed") } diff --git a/src/daemon_linux.go b/src/daemon_linux.go index 8210f8b..e1aaede 100644 --- a/src/daemon_linux.go +++ b/src/daemon_linux.go @@ -2,20 +2,25 @@ package main import ( "os" + "os/exec" ) /* Daemonizes the process on linux * * This is done by spawning and releasing a copy with the --foreground flag - * - * TODO: Use env variable to spawn in background */ - func Daemonize(attr *os.ProcAttr) error { + // I would like to use os.Executable, + // however this means dropping support for Go <1.8 + path, err := exec.LookPath(os.Args[0]) + if err != nil { + return err + } + argv := []string{os.Args[0], "--foreground"} argv = append(argv, os.Args[1:]...) process, err := os.StartProcess( - argv[0], + path, argv, attr, ) diff --git a/src/device.go b/src/device.go index 429ee46..0085cee 100644 --- a/src/device.go +++ b/src/device.go @@ -8,8 +8,9 @@ import ( ) type Device struct { - log *Logger // collection of loggers for levels - idCounter uint // for assigning debug ids to peers + closed AtomicBool // device is closed? (acting as guard) + log *Logger // collection of loggers for levels + idCounter uint // for assigning debug ids to peers fwMark uint32 tun struct { device TUNDevice @@ -203,6 +204,9 @@ func (device *Device) RemoveAllPeers() { } func (device *Device) Close() { + if device.closed.Swap(true) { + return + } device.log.Info.Println("Closing device") device.RemoveAllPeers() close(device.signal.stop) diff --git a/src/helper_test.go b/src/helper_test.go index fc171e8..8548121 100644 --- a/src/helper_test.go +++ b/src/helper_test.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "os" "testing" ) @@ -15,6 +16,10 @@ type DummyTUN struct { events chan TUNEvent } +func (tun *DummyTUN) File() *os.File { + return nil +} + func (tun *DummyTUN) Name() string { return tun.name } @@ -67,7 +72,8 @@ func randDevice(t *testing.T) *Device { t.Fatal(err) } tun, _ := CreateDummyTUN("dummy") - device := NewDevice(tun, LogLevelError) + logger := NewLogger(LogLevelError, "") + device := NewDevice(tun, logger) device.SetPrivateKey(sk) return device } diff --git a/src/misc.go b/src/misc.go index bbe0d68..b43e97e 100644 --- a/src/misc.go +++ b/src/misc.go @@ -21,6 +21,14 @@ func (a *AtomicBool) Get() bool { return atomic.LoadInt32(&a.flag) == AtomicTrue } +func (a *AtomicBool) Swap(val bool) bool { + flag := AtomicFalse + if val { + flag = AtomicTrue + } + return atomic.SwapInt32(&a.flag, flag) == AtomicTrue +} + func (a *AtomicBool) Set(val bool) { flag := AtomicFalse if val { diff --git a/src/noise_test.go b/src/noise_test.go index 48408f9..0d7f0e9 100644 --- a/src/noise_test.go +++ b/src/noise_test.go @@ -117,8 +117,8 @@ func TestNoiseHandshake(t *testing.T) { var err error var out []byte var nonce [12]byte - out = key1.send.aead.Seal(out, nonce[:], testMsg, nil) - out, err = key2.receive.aead.Open(out[:0], nonce[:], out, nil) + out = key1.send.Seal(out, nonce[:], testMsg, nil) + out, err = key2.receive.Open(out[:0], nonce[:], out, nil) assertNil(t, err) assertEqual(t, out, testMsg) }() @@ -128,8 +128,8 @@ func TestNoiseHandshake(t *testing.T) { var err error var out []byte var nonce [12]byte - out = key2.send.aead.Seal(out, nonce[:], testMsg, nil) - out, err = key1.receive.aead.Open(out[:0], nonce[:], out, nil) + out = key2.send.Seal(out, nonce[:], testMsg, nil) + out, err = key1.receive.Open(out[:0], nonce[:], out, nil) assertNil(t, err) assertEqual(t, out, testMsg) }() diff --git a/src/receive.go b/src/receive.go index ff3b7bd..b8b06f7 100644 --- a/src/receive.go +++ b/src/receive.go @@ -311,7 +311,10 @@ func (device *Device) RoutineHandshake() { return } - srcBytes := elem.endpoint.SrcToBytes() + // endpoints destination address is the source of the datagram + + srcBytes := elem.endpoint.DstToBytes() + if device.IsUnderLoad() { // verify MAC2 field @@ -320,8 +323,12 @@ func (device *Device) RoutineHandshake() { // construct cookie reply - logDebug.Println("Sending cookie reply to:", elem.endpoint.SrcToString()) - sender := binary.LittleEndian.Uint32(elem.packet[4:8]) // "sender" always follows "type" + logDebug.Println( + "Sending cookie reply to:", + elem.endpoint.DstToString(), + ) + + sender := binary.LittleEndian.Uint32(elem.packet[4:8]) reply, err := device.mac.CreateReply(elem.packet, sender, srcBytes) if err != nil { logError.Println("Failed to create cookie reply:", err) @@ -555,8 +562,10 @@ func (peer *Peer) RoutineSequentialReceiver() { src := elem.packet[IPv4offsetSrc : IPv4offsetSrc+net.IPv4len] if device.routingTable.LookupIPv4(src) != peer { - logInfo.Println(src) - logInfo.Println("Packet with unallowed source IPv4 from", peer.String()) + logInfo.Println( + "IPv4 packet with unallowed source address from", + peer.String(), + ) continue } @@ -581,8 +590,10 @@ func (peer *Peer) RoutineSequentialReceiver() { src := elem.packet[IPv6offsetSrc : IPv6offsetSrc+net.IPv6len] if device.routingTable.LookupIPv6(src) != peer { - logInfo.Println(src) - logInfo.Println("Packet with unallowed source IPv6 from", peer.String()) + logInfo.Println( + "IPv6 packet with unallowed source address from", + peer.String(), + ) continue } @@ -591,7 +602,7 @@ func (peer *Peer) RoutineSequentialReceiver() { continue } - // write to tun + // write to tun device atomic.AddUint64(&peer.stats.rxBytes, uint64(len(elem.packet))) _, err := device.tun.device.Write(elem.packet) diff --git a/src/tests/netns.sh b/src/tests/netns.sh index b5c2f9c..22abea8 100755 --- a/src/tests/netns.sh +++ b/src/tests/netns.sh @@ -20,6 +20,14 @@ # 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. + +# This code is ported to the WireGuard-Go directly from the kernel project. +# +# Please ensure that you have installed the newest version of the WireGuard +# tools from the WireGuard project and before running these tests as: +# +# ./netns.sh + set -e exec 3>&1 @@ -27,7 +35,7 @@ export WG_HIDE_KEYS=never netns0="wg-test-$$-0" netns1="wg-test-$$-1" netns2="wg-test-$$-2" -program="../wireguard-go" +program=$1 export LOG_LEVEL="info" pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; } @@ -349,4 +357,68 @@ ip1 link del veth1 ip1 link del wg1 ip2 link del wg2 -echo "done" +# Test that Netlink/IPC is working properly by doing things that usually cause split responses + +n0 $program wg0 +sleep 5 +config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" ) +for a in {1..255}; do + for b in {0..255}; do + config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" ) + done +done +n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") +i=0 +for ip in $(n0 wg show wg0 allowed-ips); do + ((++i)) +done +((i == 255*256*2+1)) +ip0 link del wg0 + +n0 $program wg0 +config=( "[Interface]" "PrivateKey=$(wg genkey)" ) +for a in {1..40}; do + config+=( "[Peer]" "PublicKey=$(wg genkey)" ) + for b in {1..52}; do + config+=( "AllowedIPs=$a.$b.0.0/16" ) + done +done +n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") +i=0 +while read -r line; do + j=0 + for ip in $line; do + ((++j)) + done + ((j == 53)) + ((++i)) +done < <(n0 wg show wg0 allowed-ips) +((i == 40)) +ip0 link del wg0 + +n0 $program wg0 +config=( ) +for i in {1..29}; do + config+=( "[Peer]" "PublicKey=$(wg genkey)" ) +done +config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" ) +n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") +n0 wg showconf wg0 > /dev/null +ip0 link del wg0 + +! n0 wg show doesnotexist || false + +declare -A objects +while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do + [[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ [0-9]+)\ .*(created|destroyed).* ]] || continue + objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}" +done < /dev/kmsg +alldeleted=1 +for object in "${!objects[@]}"; do + if [[ ${objects["$object"]} != *createddestroyed ]]; then + echo "Error: $object: merely ${objects["$object"]}" >&3 + alldeleted=0 + fi +done +[[ $alldeleted -eq 1 ]] +pretty "" "Objects that were created were also destroyed." diff --git a/src/tun_linux.go b/src/tun_linux.go index 2a5b276..a728a48 100644 --- a/src/tun_linux.go +++ b/src/tun_linux.go @@ -57,7 +57,6 @@ type NativeTun struct { } func (tun *NativeTun) File() *os.File { - println(tun.fd.Name()) return tun.fd } diff --git a/src/uapi.go b/src/uapi.go index 5e40939..e1d0929 100644 --- a/src/uapi.go +++ b/src/uapi.go @@ -145,11 +145,22 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { } case "fwmark": - fwmark, err := strconv.ParseUint(value, 10, 32) + + // parse fwmark field + + fwmark, err := func() (uint32, error) { + if value == "" { + return 0, nil + } + mark, err := strconv.ParseUint(value, 10, 32) + return uint32(mark), err + }() + if err != nil { logError.Println("Invalid fwmark", err) return &IPCError{Code: ipcErrorInvalid} } + device.net.mutex.Lock() device.net.fwmark = uint32(fwmark) device.net.mutex.Unlock() -- cgit v1.2.3