You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.5 KiB

package identify
// This test lives in the identify package, not the identify_test package, so it
// can access internal types.
import (
"fmt"
"testing"
ma "github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/require"
)
func TestObservedAddrGroupKey(t *testing.T) {
oa1 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/tcp/2345")}
oa2 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/tcp/1231")}
oa3 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.5/tcp/1231")}
oa4 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/udp/1231")}
oa5 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/udp/1531")}
oa6 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/udp/1531/quic-v1")}
oa7 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/udp/1111/quic-v1")}
oa8 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.5/udp/1111/quic-v1")}
// different ports, same IP => same key
require.Equal(t, oa1.groupKey(), oa2.groupKey())
// different IPs => different key
require.NotEqual(t, oa2.groupKey(), oa3.groupKey())
// same port, different protos => different keys
require.NotEqual(t, oa3.groupKey(), oa4.groupKey())
// same port, same address, different protos => different keys
require.NotEqual(t, oa2.groupKey(), oa4.groupKey())
// udp works as well
require.Equal(t, oa4.groupKey(), oa5.groupKey())
// udp and quic are different
require.NotEqual(t, oa5.groupKey(), oa6.groupKey())
// quic works as well
require.Equal(t, oa6.groupKey(), oa7.groupKey())
require.NotEqual(t, oa7.groupKey(), oa8.groupKey())
}
type mockHost struct {
addrs []ma.Multiaddr
listenAddrs []ma.Multiaddr
ifaceListenAddrs []ma.Multiaddr
}
// InterfaceListenAddresses implements listenAddrsProvider
func (h *mockHost) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
return h.ifaceListenAddrs, nil
}
// ListenAddresses implements listenAddrsProvider
func (h *mockHost) ListenAddresses() []ma.Multiaddr {
return h.listenAddrs
}
// Addrs implements addrsProvider
func (h *mockHost) Addrs() []ma.Multiaddr {
return h.addrs
}
// NormalizeMultiaddr implements normalizeMultiaddrer
func (h *mockHost) NormalizeMultiaddr(m ma.Multiaddr) ma.Multiaddr {
original := m
for {
rest, tail := ma.SplitLast(m)
if rest == nil {
return original
}
if tail.Protocol().Code == ma.P_WEBTRANSPORT {
return m
}
m = rest
}
}
type mockConn struct {
local, remote ma.Multiaddr
}
// LocalMultiaddr implements connMultiaddrProvider
func (c *mockConn) LocalMultiaddr() ma.Multiaddr {
return c.local
}
// RemoteMultiaddr implements connMultiaddrProvider
func (c *mockConn) RemoteMultiaddr() ma.Multiaddr {
return c.remote
}
func TestShouldRecordObservationWithWebTransport(t *testing.T) {
listenAddr := ma.StringCast("/ip4/0.0.0.0/udp/0/quic-v1/webtransport/certhash/uEgNmb28")
ifaceAddr := ma.StringCast("/ip4/10.0.0.2/udp/9999/quic-v1/webtransport/certhash/uEgNmb28")
h := &mockHost{
listenAddrs: []ma.Multiaddr{listenAddr},
ifaceListenAddrs: []ma.Multiaddr{ifaceAddr},
addrs: []ma.Multiaddr{listenAddr},
}
c := &mockConn{
local: listenAddr,
remote: ma.StringCast("/ip4/1.2.3.6/udp/1236/quic-v1/webtransport"),
}
observedAddr := ma.StringCast("/ip4/1.2.3.4/udp/1231/quic-v1/webtransport")
require.True(t, shouldRecordObservation(h, h, c, observedAddr))
}
func TestShouldRecordObservationWithNAT64Addr(t *testing.T) {
listenAddr1 := ma.StringCast("/ip4/0.0.0.0/tcp/1234")
ifaceAddr1 := ma.StringCast("/ip4/10.0.0.2/tcp/4321")
listenAddr2 := ma.StringCast("/ip6/::/tcp/1234")
ifaceAddr2 := ma.StringCast("/ip6/1::1/tcp/4321")
h := &mockHost{
listenAddrs: []ma.Multiaddr{listenAddr1, listenAddr2},
ifaceListenAddrs: []ma.Multiaddr{ifaceAddr1, ifaceAddr2},
addrs: []ma.Multiaddr{listenAddr1, listenAddr2},
}
c := &mockConn{
local: listenAddr1,
remote: ma.StringCast("/ip4/1.2.3.6/tcp/4321"),
}
cases := []struct {
addr ma.Multiaddr
want bool
failureReason string
}{
{
addr: ma.StringCast("/ip4/1.2.3.4/tcp/1234"),
want: true,
failureReason: "IPv4 should be observed",
},
{
addr: ma.StringCast("/ip6/1::4/tcp/1234"),
want: true,
failureReason: "public IPv6 address should be observed",
},
{
addr: ma.StringCast("/ip6/64:ff9b::192.0.1.2/tcp/1234"),
want: false,
failureReason: "NAT64 IPv6 address shouldn't be observed",
},
}
for i, tc := range cases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
if shouldRecordObservation(h, h, c, tc.addr) != tc.want {
t.Fatalf("%s %s", tc.addr, tc.failureReason)
}
})
}
}