ceremonyclient/go-multiaddr/net/net_test.go

694 lines
16 KiB
Go

package manet
import (
"bytes"
"fmt"
"net"
"os"
"path/filepath"
"sync"
"testing"
"time"
ma "github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/require"
)
func newMultiaddr(t *testing.T, m string) ma.Multiaddr {
maddr, err := ma.NewMultiaddr(m)
if err != nil {
t.Fatal("failed to construct multiaddr:", m, err)
}
return maddr
}
func TestDial(t *testing.T) {
listener, err := net.Listen("tcp", "127.0.0.1:4321")
if err != nil {
t.Fatal("failed to listen")
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
cB, err := listener.Accept()
if err != nil {
t.Error("failed to accept")
}
// echo out
buf := make([]byte, 1024)
for {
_, err := cB.Read(buf)
if err != nil {
break
}
cB.Write(buf)
}
wg.Done()
}()
maddr := newMultiaddr(t, "/ip4/127.0.0.1/tcp/4321")
cA, err := Dial(maddr)
if err != nil {
t.Fatal("failed to dial")
}
buf := make([]byte, 1024)
if _, err := cA.Write([]byte("beep boop")); err != nil {
t.Fatal("failed to write:", err)
}
if _, err := cA.Read(buf); err != nil {
t.Fatal("failed to read:", buf, err)
}
if !bytes.Equal(buf[:9], []byte("beep boop")) {
t.Fatal("failed to echo:", buf)
}
maddr2 := cA.RemoteMultiaddr()
if !maddr2.Equal(maddr) {
t.Fatal("remote multiaddr not equal:", maddr, maddr2)
}
cA.Close()
wg.Wait()
}
func TestUnixSockets(t *testing.T) {
dir, err := os.MkdirTemp(os.TempDir(), "manettest")
if err != nil {
t.Fatal(err)
}
path := filepath.Join(dir, "listen.sock")
maddr := newMultiaddr(t, "/unix/"+path)
listener, err := Listen(maddr)
if err != nil {
t.Fatal(err)
}
payload := []byte("hello")
// listen
done := make(chan struct{}, 1)
go func() {
conn, err := listener.Accept()
if err != nil {
t.Error(err)
}
defer conn.Close()
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
t.Error(err)
}
if n != len(payload) {
t.Error("failed to read appropriate number of bytes")
}
if !bytes.Equal(buf[0:n], payload) {
t.Error("payload did not match")
}
done <- struct{}{}
}()
// dial
conn, err := Dial(maddr)
if err != nil {
t.Fatal(err)
}
n, err := conn.Write(payload)
if err != nil {
t.Fatal(err)
}
if n != len(payload) {
t.Fatal("failed to write appropriate number of bytes")
}
select {
case <-done:
case <-time.After(1 * time.Second):
t.Fatal("timed out waiting for read")
}
}
func TestListen(t *testing.T) {
maddr := newMultiaddr(t, "/ip4/127.0.0.1/tcp/4322")
listener, err := Listen(maddr)
if err != nil {
t.Fatal("failed to listen")
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
cB, err := listener.Accept()
if err != nil {
t.Error("failed to accept")
}
if !cB.LocalMultiaddr().Equal(maddr) {
t.Error("local multiaddr not equal:", maddr, cB.LocalMultiaddr())
}
// echo out
buf := make([]byte, 1024)
for {
_, err := cB.Read(buf)
if err != nil {
break
}
cB.Write(buf)
}
wg.Done()
}()
cA, err := net.Dial("tcp", "127.0.0.1:4322")
if err != nil {
t.Fatal("failed to dial")
}
buf := make([]byte, 1024)
if _, err := cA.Write([]byte("beep boop")); err != nil {
t.Fatal("failed to write:", err)
}
if _, err := cA.Read(buf); err != nil {
t.Fatal("failed to read:", buf, err)
}
if !bytes.Equal(buf[:9], []byte("beep boop")) {
t.Fatal("failed to echo:", buf)
}
maddr2, err := FromNetAddr(cA.RemoteAddr())
if err != nil {
t.Fatal("failed to convert", err)
}
if !maddr2.Equal(maddr) {
t.Fatal("remote multiaddr not equal:", maddr, maddr2)
}
cA.Close()
wg.Wait()
}
func TestListenAddrs(t *testing.T) {
test := func(addr, resaddr string, succeed bool) {
if resaddr == "" {
resaddr = addr
}
maddr := newMultiaddr(t, addr)
l, err := Listen(maddr)
if !succeed {
if err == nil {
t.Fatal("succeeded in listening", addr)
}
return
}
if succeed && err != nil {
t.Error("failed to listen", addr, err)
}
if l == nil {
t.Error("failed to listen", addr, succeed, err)
}
if l.Multiaddr().String() != resaddr {
t.Error("listen addr did not resolve properly", l.Multiaddr().String(), resaddr, succeed, err)
}
if err = l.Close(); err != nil {
t.Fatal("failed to close listener", addr, err)
}
}
test("/ip4/127.0.0.1/tcp/4324", "", true)
test("/ip4/127.0.0.1/udp/4325", "", false)
test("/ip4/127.0.0.1/udp/4326/udt", "", false)
if len(os.Getenv("CI")) > 0 {
test("/ip4/0.0.0.0/tcp/4324", "", true)
test("/ip4/0.0.0.0/udp/4325", "", false)
test("/ip4/0.0.0.0/udp/4326/udt", "", false)
test("/ip6/::1/tcp/4324", "", true)
test("/ip6/::1/udp/4325", "", false)
test("/ip6/::1/udp/4326/udt", "", false)
test("/ip6/::/tcp/4324", "", true)
test("/ip6/::/udp/4325", "", false)
test("/ip6/::/udp/4326/udt", "", false)
/* "An implementation should also support the concept of a "default"
* zone for each scope. And, when supported, the index value zero
* at each scope SHOULD be reserved to mean "use the default zone"."
* -- rfc4007. So, this _should_ work everywhere(?). */
test("/ip6zone/0/ip6/::1/tcp/4324", "/ip6/::1/tcp/4324", true)
test("/ip6zone/0/ip6/::1/udp/4324", "", false)
} else {
t.Skip("all tests only run on CI")
}
}
func TestListenAndDial(t *testing.T) {
maddr := newMultiaddr(t, "/ip4/127.0.0.1/tcp/4323")
listener, err := Listen(maddr)
if err != nil {
t.Fatal("failed to listen")
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
cB, err := listener.Accept()
if err != nil {
t.Error("failed to accept")
}
if !cB.LocalMultiaddr().Equal(maddr) {
t.Error("local multiaddr not equal:", maddr, cB.LocalMultiaddr())
}
// echo out
buf := make([]byte, 1024)
for {
_, err := cB.Read(buf)
if err != nil {
break
}
cB.Write(buf)
}
wg.Done()
}()
cA, err := Dial(newMultiaddr(t, "/ip4/127.0.0.1/tcp/4323"))
if err != nil {
t.Fatal("failed to dial")
}
buf := make([]byte, 1024)
if _, err := cA.Write([]byte("beep boop")); err != nil {
t.Fatal("failed to write:", err)
}
if _, err := cA.Read(buf); err != nil {
t.Fatal("failed to read:", buf, err)
}
if !bytes.Equal(buf[:9], []byte("beep boop")) {
t.Fatal("failed to echo:", buf)
}
maddr2 := cA.RemoteMultiaddr()
if !maddr2.Equal(maddr) {
t.Fatal("remote multiaddr not equal:", maddr, maddr2)
}
cA.Close()
wg.Wait()
}
func TestListenPacketAndDial(t *testing.T) {
maddr := newMultiaddr(t, "/ip4/127.0.0.1/udp/4324")
pc, err := ListenPacket(maddr)
if err != nil {
t.Fatal("failed to listen", err)
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
if !pc.LocalMultiaddr().Equal(maddr) {
t.Error("connection multiaddr not equal:", maddr, pc.LocalMultiaddr())
}
buffer := make([]byte, 1024)
_, addr, err := pc.ReadFrom(buffer)
if err != nil {
t.Error("failed to read into buffer", err)
}
pc.WriteTo(buffer, addr)
wg.Done()
}()
cn, err := Dial(maddr)
if err != nil {
t.Fatal("failed to dial", err)
}
buf := make([]byte, 1024)
if _, err := cn.Write([]byte("beep boop")); err != nil {
t.Fatal("failed to write", err)
}
if _, err := cn.Read(buf); err != nil {
t.Fatal("failed to read:", buf, err)
}
if !bytes.Equal(buf[:9], []byte("beep boop")) {
t.Fatal("failed to echk:", buf)
}
maddr2 := cn.RemoteMultiaddr()
if !maddr2.Equal(maddr) {
t.Fatal("remote multiaddr not equal:", maddr, maddr2)
}
cn.Close()
pc.Close()
wg.Wait()
}
func TestIPLoopback(t *testing.T) {
if IP4Loopback.String() != "/ip4/127.0.0.1" {
t.Error("IP4Loopback incorrect:", IP4Loopback)
}
if IP6Loopback.String() != "/ip6/::1" {
t.Error("IP6Loopback incorrect:", IP6Loopback)
}
if IP4MappedIP6Loopback.String() != "/ip6/::ffff:127.0.0.1" {
t.Error("IP4MappedIP6Loopback incorrect:", IP4MappedIP6Loopback)
}
if !IsIPLoopback(IP4Loopback) {
t.Error("IsIPLoopback failed (IP4Loopback)")
}
if !IsIPLoopback(newMultiaddr(t, "/ip4/127.1.80.9")) {
t.Error("IsIPLoopback failed (/ip4/127.1.80.9)")
}
if IsIPLoopback(newMultiaddr(t, "/ip4/112.123.11.1")) {
t.Error("IsIPLoopback false positive (/ip4/112.123.11.1)")
}
if IsIPLoopback(newMultiaddr(t, "/ip4/192.168.0.1/ip6/::1")) {
t.Error("IsIPLoopback false positive (/ip4/192.168.0.1/ip6/::1)")
}
if !IsIPLoopback(IP6Loopback) {
t.Error("IsIPLoopback failed (IP6Loopback)")
}
if !IsIPLoopback(newMultiaddr(t, "/ip6/127.0.0.1")) {
t.Error("IsIPLoopback failed (/ip6/127.0.0.1)")
}
if !IsIPLoopback(newMultiaddr(t, "/ip6/127.99.3.2")) {
t.Error("IsIPLoopback failed (/ip6/127.99.3.2)")
}
if IsIPLoopback(newMultiaddr(t, "/ip6/::fffa:127.99.3.2")) {
t.Error("IsIPLoopback false positive (/ip6/::fffa:127.99.3.2)")
}
if !IsIPLoopback(newMultiaddr(t, "/ip6zone/0/ip6/::1")) {
t.Error("IsIPLoopback failed (/ip6zone/0/ip6/::1)")
}
if !IsIPLoopback(newMultiaddr(t, "/ip6zone/xxx/ip6/::1")) {
t.Error("IsIPLoopback failed (/ip6zone/xxx/ip6/::1)")
}
if IsIPLoopback(newMultiaddr(t, "/ip6zone/0/ip6/1::1")) {
t.Errorf("IsIPLoopback false positive (/ip6zone/0/ip6/1::1)")
}
}
func TestIPUnspecified(t *testing.T) {
if IP4Unspecified.String() != "/ip4/0.0.0.0" {
t.Error("IP4Unspecified incorrect:", IP4Unspecified)
}
if IP6Unspecified.String() != "/ip6/::" {
t.Error("IP6Unspecified incorrect:", IP6Unspecified)
}
if !IsIPUnspecified(IP4Unspecified) {
t.Error("IsIPUnspecified failed (IP4Unspecified)")
}
if !IsIPUnspecified(IP6Unspecified) {
t.Error("IsIPUnspecified failed (IP6Unspecified)")
}
if !IsIPUnspecified(newMultiaddr(t, "/ip6zone/xxx/ip6/::")) {
t.Error("IsIPUnspecified failed (/ip6zone/xxx/ip6/::)")
}
}
func TestIP6LinkLocal(t *testing.T) {
for a := 0; a < 65536; a++ {
isLinkLocal := a&0xffc0 == 0xfe80 || a&0xff0f == 0xff02
m := newMultiaddr(t, fmt.Sprintf("/ip6/%x::1", a))
if IsIP6LinkLocal(m) != isLinkLocal {
t.Errorf("IsIP6LinkLocal failed (%s != %v)", m, isLinkLocal)
}
}
if !IsIP6LinkLocal(newMultiaddr(t, "/ip6zone/hello/ip6/fe80::9999")) {
t.Error("IsIP6LinkLocal failed (/ip6/fe80::9999)")
}
bad := []ma.Multiaddr{
newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), // link local
newMultiaddr(t, "/ip6/fe80::100/tcp/1234"), // link local
}
good := []ma.Multiaddr{
newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
newMultiaddr(t, "/ip6/::1/tcp/1234"),
newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/utp"),
}
for _, addr := range bad {
require.True(t, IsIP6LinkLocal(addr), "%s is a link local addr", addr)
}
for _, addr := range good {
require.False(t, IsIP6LinkLocal(addr), "%s is not a link local addr", addr)
}
}
func TestConvertNetAddr(t *testing.T) {
m1 := newMultiaddr(t, "/ip4/1.2.3.4/tcp/4001")
n1, err := ToNetAddr(m1)
if err != nil {
t.Fatal(err)
}
m2, err := FromNetAddr(n1)
if err != nil {
t.Fatal(err)
}
if m1.String() != m2.String() {
t.Fatal("ToNetAddr + FromNetAddr did not work")
}
}
func TestWrapNetConn(t *testing.T) {
// test WrapNetConn nil
if _, err := WrapNetConn(nil); err == nil {
t.Error("WrapNetConn(nil) should return an error")
}
checkErr := func(err error, s string) {
if err != nil {
t.Fatal(s, err)
}
}
listener, err := net.Listen("tcp", "127.0.0.1:0")
checkErr(err, "failed to listen")
var wg sync.WaitGroup
defer wg.Wait()
wg.Add(1)
go func() {
defer wg.Done()
cB, err := listener.Accept()
checkErr(err, "failed to accept")
_ = cB.(halfOpen)
cB.Close()
}()
cA, err := net.Dial("tcp", listener.Addr().String())
checkErr(err, "failed to dial")
defer cA.Close()
_ = cA.(halfOpen)
lmaddr, err := FromNetAddr(cA.LocalAddr())
checkErr(err, "failed to get local addr")
rmaddr, err := FromNetAddr(cA.RemoteAddr())
checkErr(err, "failed to get remote addr")
mcA, err := WrapNetConn(cA)
checkErr(err, "failed to wrap conn")
_ = mcA.(halfOpen)
if mcA.LocalAddr().String() != cA.LocalAddr().String() {
t.Error("wrapped conn local addr differs")
}
if mcA.RemoteAddr().String() != cA.RemoteAddr().String() {
t.Error("wrapped conn remote addr differs")
}
if mcA.LocalMultiaddr().String() != lmaddr.String() {
t.Error("wrapped conn local maddr differs")
}
if mcA.RemoteMultiaddr().String() != rmaddr.String() {
t.Error("wrapped conn remote maddr differs")
}
}
func TestAddrMatch(t *testing.T) {
test := func(m ma.Multiaddr, input, expect []ma.Multiaddr) {
actual := AddrMatch(m, input)
testSliceEqual(t, expect, actual)
}
a := []ma.Multiaddr{
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/2345"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"),
newMultiaddr(t, "/ip6/::1/tcp/1234"),
newMultiaddr(t, "/ip6/::1/tcp/2345"),
newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"),
newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"),
newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"),
newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"),
newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"),
newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"),
}
test(a[0], a, []ma.Multiaddr{
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/2345"),
})
test(a[2], a, []ma.Multiaddr{
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"),
})
test(a[4], a, []ma.Multiaddr{
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"),
})
test(a[6], a, []ma.Multiaddr{
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"),
newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"),
})
test(a[8], a, []ma.Multiaddr{
newMultiaddr(t, "/ip6/::1/tcp/1234"),
newMultiaddr(t, "/ip6/::1/tcp/2345"),
})
test(a[10], a, []ma.Multiaddr{
newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"),
newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"),
})
test(a[12], a, []ma.Multiaddr{
newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"),
newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"),
})
test(a[14], a, []ma.Multiaddr{
newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"),
newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"),
})
}
func testSliceEqual(t *testing.T, a, b []ma.Multiaddr) {
if len(a) != len(b) {
t.Error("differ", a, b)
}
for i, addrA := range a {
if !addrA.Equal(b[i]) {
t.Error("differ", a, b)
}
}
}
func TestInterfaceAddressesWorks(t *testing.T) {
_, err := InterfaceMultiaddrs()
if err != nil {
t.Fatal(err)
}
}
func TestNetListener(t *testing.T) {
listener, err := net.Listen("tcp", "127.0.0.1:1234")
if err != nil {
t.Fatal(err)
}
defer listener.Close()
malist, err := WrapNetListener(listener)
if err != nil {
t.Fatal(err)
}
if !malist.Multiaddr().Equal(newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234")) {
t.Fatal("unexpected multiaddr")
}
go func() {
c, err := Dial(malist.Multiaddr())
if err != nil {
t.Error("failed to dial")
}
if !c.RemoteMultiaddr().Equal(malist.Multiaddr()) {
t.Error("dialed wrong target")
}
c.Close()
c, err = Dial(malist.Multiaddr())
if err != nil {
t.Error("failed to dial")
}
c.Close()
}()
c, err := malist.Accept()
if err != nil {
t.Fatal(err)
}
c.Close()
netList := NetListener(malist)
malist2, err := WrapNetListener(netList)
if err != nil {
t.Fatal(err)
}
if malist2 != malist {
t.Fatal("expected WrapNetListener(NetListener(malist)) == malist")
}
nc, err := netList.Accept()
if err != nil {
t.Fatal(err)
}
if !nc.(Conn).LocalMultiaddr().Equal(malist.Multiaddr()) {
t.Fatal("wrong multiaddr on conn")
}
nc.Close()
}
func BenchmarkResolveUnspecifiedAddress(b *testing.B) {
b.ReportAllocs()
a, _ := ma.StringCast("/ip4/0.0.0.0/udp/42/quic-v1")
iaddrs, _ := interfaceAddresses()
for i := 0; i < b.N; i++ {
ResolveUnspecifiedAddress(a, iaddrs)
}
}