2019-01-02 00:55:51 +00:00
|
|
|
/* SPDX-License-Identifier: MIT
|
2018-05-03 13:04:00 +00:00
|
|
|
*
|
2020-05-02 08:08:26 +00:00
|
|
|
* Copyright (C) 2017-2020 WireGuard LLC. All Rights Reserved.
|
2018-05-03 13:04:00 +00:00
|
|
|
*/
|
|
|
|
|
2019-03-03 03:04:41 +00:00
|
|
|
package device
|
2018-03-08 15:44:27 +00:00
|
|
|
|
2019-05-29 16:18:20 +00:00
|
|
|
import (
|
2019-10-12 16:44:05 +00:00
|
|
|
"bufio"
|
2019-05-29 16:18:20 +00:00
|
|
|
"bytes"
|
2020-07-30 16:20:49 +00:00
|
|
|
"fmt"
|
2019-10-12 16:44:05 +00:00
|
|
|
"net"
|
|
|
|
"strings"
|
2019-05-29 16:18:20 +00:00
|
|
|
"testing"
|
2019-10-12 16:44:05 +00:00
|
|
|
"time"
|
|
|
|
|
2020-01-07 15:43:17 +00:00
|
|
|
"golang.zx2c4.com/wireguard/tun/tuntest"
|
2019-05-29 16:18:20 +00:00
|
|
|
)
|
2018-03-08 15:44:27 +00:00
|
|
|
|
2020-07-30 16:20:49 +00:00
|
|
|
func getFreePort(t *testing.T) string {
|
|
|
|
l, err := net.ListenPacket("udp", "localhost:0")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
return fmt.Sprintf("%d", l.LocalAddr().(*net.UDPAddr).Port)
|
|
|
|
}
|
|
|
|
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
// genConfigs generates a pair of configs that connect to each other.
|
|
|
|
// The configs use distinct, probably-usable ports.
|
|
|
|
func genConfigs(t *testing.T) (cfgs [2]*bufio.Reader) {
|
|
|
|
const (
|
|
|
|
cfg1 = `private_key=481eb0d8113a4a5da532d2c3e9c14b53c8454b34ab109676f6b58c2245e37b58
|
2020-07-30 16:20:49 +00:00
|
|
|
listen_port={{PORT1}}
|
2019-10-12 16:44:05 +00:00
|
|
|
replace_peers=true
|
|
|
|
public_key=f70dbb6b1b92a1dde1c783b297016af3f572fef13b0abb16a2623d89a58e9725
|
|
|
|
protocol_version=1
|
|
|
|
replace_allowed_ips=true
|
|
|
|
allowed_ip=1.0.0.2/32
|
2020-07-30 16:20:49 +00:00
|
|
|
endpoint=127.0.0.1:{{PORT2}}`
|
2018-03-08 15:44:27 +00:00
|
|
|
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
cfg2 = `private_key=98c7989b1661a0d64fd6af3502000f87716b7c4bbcf00d04fc6073aa7b539768
|
2020-07-30 16:20:49 +00:00
|
|
|
listen_port={{PORT2}}
|
2019-10-12 16:44:05 +00:00
|
|
|
replace_peers=true
|
|
|
|
public_key=49e80929259cebdda4f322d6d2b1a6fad819d603acd26fd5d845e7a123036427
|
|
|
|
protocol_version=1
|
|
|
|
replace_allowed_ips=true
|
|
|
|
allowed_ip=1.0.0.1/32
|
2020-07-30 16:20:49 +00:00
|
|
|
endpoint=127.0.0.1:{{PORT1}}`
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
)
|
2020-07-30 16:20:49 +00:00
|
|
|
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
var port1, port2 string
|
|
|
|
for port1 == port2 {
|
|
|
|
port1 = getFreePort(t)
|
|
|
|
port2 = getFreePort(t)
|
|
|
|
}
|
|
|
|
for i, cfg := range []string{cfg1, cfg2} {
|
|
|
|
cfg = strings.ReplaceAll(cfg, "{{PORT1}}", port1)
|
|
|
|
cfg = strings.ReplaceAll(cfg, "{{PORT2}}", port2)
|
|
|
|
cfgs[i] = bufio.NewReader(strings.NewReader(cfg))
|
2019-10-12 16:44:05 +00:00
|
|
|
}
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// genChannelTUNs creates a usable pair of ChannelTUNs for use in a test.
|
|
|
|
func genChannelTUNs(t *testing.T) (tun [2]*tuntest.ChannelTUN) {
|
|
|
|
const maxAttempts = 10
|
|
|
|
NextAttempt:
|
|
|
|
for i := 0; i < maxAttempts; i++ {
|
|
|
|
cfg := genConfigs(t)
|
|
|
|
// Bring up a ChannelTun for each config.
|
|
|
|
for i := range tun {
|
|
|
|
tun[i] = tuntest.NewChannelTUN()
|
|
|
|
dev := NewDevice(tun[i].TUN(), NewLogger(LogLevelDebug, fmt.Sprintf("dev%d: ", i)))
|
|
|
|
dev.Up()
|
|
|
|
if err := dev.IpcSetOperation(cfg[i]); err != nil {
|
|
|
|
// genConfigs attempted to pick ports that were free.
|
|
|
|
// There's a tiny window between genConfigs closing the port
|
|
|
|
// and us opening it, during which another process could
|
|
|
|
// start using it. We probably just lost that race.
|
|
|
|
// Try again from the beginning.
|
|
|
|
// If there's something permanent wrong,
|
|
|
|
// we'll see that when we run out of attempts.
|
|
|
|
t.Logf("failed to configure device %d: %v", i, err)
|
|
|
|
continue NextAttempt
|
|
|
|
}
|
|
|
|
// The device might still not be up, e.g. due to an error
|
|
|
|
// in RoutineTUNEventReader's call to dev.Up that got swallowed.
|
|
|
|
// Assume it's due to a transient error (port in use), and retry.
|
|
|
|
if !dev.isUp.Get() {
|
|
|
|
t.Logf("%v did not come up, trying again", dev)
|
|
|
|
continue NextAttempt
|
|
|
|
}
|
|
|
|
// The device is up. Close it when the test completes.
|
|
|
|
t.Cleanup(dev.Close)
|
|
|
|
}
|
|
|
|
return // success
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Fatalf("genChannelTUNs: failed %d times", maxAttempts)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTwoDevicePing(t *testing.T) {
|
|
|
|
tun := genChannelTUNs(t)
|
2018-03-08 15:44:27 +00:00
|
|
|
|
2019-10-12 16:44:05 +00:00
|
|
|
t.Run("ping 1.0.0.1", func(t *testing.T) {
|
2020-01-07 15:43:17 +00:00
|
|
|
msg2to1 := tuntest.Ping(net.ParseIP("1.0.0.1"), net.ParseIP("1.0.0.2"))
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
tun[1].Outbound <- msg2to1
|
2019-10-12 16:44:05 +00:00
|
|
|
select {
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
case msgRecv := <-tun[0].Inbound:
|
2019-10-12 16:44:05 +00:00
|
|
|
if !bytes.Equal(msg2to1, msgRecv) {
|
|
|
|
t.Error("ping did not transit correctly")
|
|
|
|
}
|
2020-12-14 22:11:33 +00:00
|
|
|
case <-time.After(5 * time.Second):
|
2019-10-12 16:44:05 +00:00
|
|
|
t.Error("ping did not transit")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("ping 1.0.0.2", func(t *testing.T) {
|
2020-01-07 15:43:17 +00:00
|
|
|
msg1to2 := tuntest.Ping(net.ParseIP("1.0.0.2"), net.ParseIP("1.0.0.1"))
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
tun[0].Outbound <- msg1to2
|
2019-10-12 16:44:05 +00:00
|
|
|
select {
|
device: make test setup more robust
Picking two free ports to use for a test is difficult.
The free port we selected might no longer be free when we reach
for it a second time.
On my machine, this failure mode led to failures approximately
once per thousand test runs.
Since failures are rare, and threading through and checking for
all possible errors is complicated, fix this with a big hammer:
Retry if either device fails to come up.
Also, if you accidentally pick the same port twice, delightful confusion ensues.
The handshake failures manifest as crypto errors, which look scary.
Again, fix with retries.
To make these retries easier to implement, use testing.T.Cleanup
instead of defer to close devices. This requires Go 1.14.
Update go.mod accordingly. Go 1.13 is no longer supported anyway.
With these fixes, 'go test -race' ran 100,000 times without failure.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
2020-12-09 03:23:56 +00:00
|
|
|
case msgRecv := <-tun[1].Inbound:
|
2019-10-12 16:44:05 +00:00
|
|
|
if !bytes.Equal(msg1to2, msgRecv) {
|
|
|
|
t.Error("return ping did not transit correctly")
|
|
|
|
}
|
2020-12-14 22:11:33 +00:00
|
|
|
case <-time.After(5 * time.Second):
|
2019-10-12 16:44:05 +00:00
|
|
|
t.Error("return ping did not transit")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-03-08 15:44:27 +00:00
|
|
|
|
2019-05-29 16:18:20 +00:00
|
|
|
func assertNil(t *testing.T, err error) {
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-03 20:44:06 +00:00
|
|
|
func assertEqual(t *testing.T, a, b []byte) {
|
|
|
|
if !bytes.Equal(a, b) {
|
2019-05-29 16:18:20 +00:00
|
|
|
t.Fatal(a, "!=", b)
|
|
|
|
}
|
|
|
|
}
|
2019-10-12 16:44:05 +00:00
|
|
|
|
|
|
|
func randDevice(t *testing.T) *Device {
|
|
|
|
sk, err := newPrivateKey()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
tun := newDummyTUN("dummy")
|
|
|
|
logger := NewLogger(LogLevelError, "")
|
|
|
|
device := NewDevice(tun, logger)
|
|
|
|
device.SetPrivateKey(sk)
|
|
|
|
return device
|
|
|
|
}
|