]> git.ipfire.org Git - thirdparty/wireguard-go.git/commitdiff
Ported remaining netns.sh
authorMathias Hall-Andersen <mathias@hall-andersen.dk>
Fri, 17 Nov 2017 16:25:45 +0000 (17:25 +0100)
committerMathias Hall-Andersen <mathias@hall-andersen.dk>
Fri, 17 Nov 2017 16:25:58 +0000 (17:25 +0100)
- Ported remaining netns.sh tests
- Begin work on generic implementation of bind interface

13 files changed:
src/conn.go
src/conn_default.go
src/conn_linux.go
src/cookie_test.go
src/daemon_linux.go
src/device.go
src/helper_test.go
src/misc.go
src/noise_test.go
src/receive.go
src/tests/netns.sh
src/tun_linux.go
src/uapi.go

index a047bb66f49bfbbacbc7903497f60287698e1a48..3cf00ab5d5f52da0be66c63690f295ee672066bb 100644 (file)
@@ -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
index 279643e3105719f9c1225e580a2f8ca37891e2f4..31cab5c07a075782f90f847a49fe02a3bfd11d58 100644 (file)
@@ -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
 }
index 383ff7eee41f9034d6b4768f170f0a46d801d929..fb576b1f9aed352b774ff4a972a9955ceeeb28c6 100644 (file)
@@ -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[:]
index 193a76ede9065e046d2c188827cea0bfa9b08cae..d745fe7bdc5526df4d4ae2d54215da92469dbe46 100644 (file)
@@ -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")
                }
index 8210f8b8b281fd04fdc5d809482faa356602fc99..e1aaede3806624ea1a5c84cd3bdf4fa13d38734f 100644 (file)
@@ -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,
        )
index 429ee463d6effd2fc1d1a1a00023d85bddc56df6..0085ceea298266f35a25907dccf28a98ec51032b 100644 (file)
@@ -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)
index fc171e875b4a20c9dfb6ca54ea497a1ed92f4da3..85481219d62d07be80c09f3ef83284dd1c8500a3 100644 (file)
@@ -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
 }
index bbe0d6841748f6194c0ee9f1dcf8dbc46e743901..b43e97ec20ac7c778adcd26aa56bf3be300acdd2 100644 (file)
@@ -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 {
index 48408f9ad960ad83955fad2b80ac59cbe0cca4f4..0d7f0e933fadc28765f6b804e7647f6f0b54e4a3 100644 (file)
@@ -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)
        }()
index ff3b7bd1b58d4acc12996b918f17b82bfbc88977..b8b06f722409797502f86c43ed5f239653f841e2 100644 (file)
@@ -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)
index b5c2f9c28b17f000bdc8a403c51fe820437bdb08..22abea8d6f4526347e080ec4207af03f8fbbfd4c 100755 (executable)
 # 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 <path to wireguard-go>
+
 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."
index 2a5b276531b6fe56c8026e8b7fc9afd572cb979e..a728a488f83616ed2d346ab7553a7d7417d0eff5 100644 (file)
@@ -57,7 +57,6 @@ type NativeTun struct {
 }
 
 func (tun *NativeTun) File() *os.File {
-       println(tun.fd.Name())
        return tun.fd
 }
 
index 5e409390328e127441aec50bd63b653b1a68a9aa..e1d092953fea020a286526811885ac40be164b69 100644 (file)
@@ -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()