Files
SpotiFLAC-Mobile/go_backend/dns_doh_security_test.go
T

130 lines
3.2 KiB
Go

package gobackend
import (
"context"
"errors"
"net"
"strings"
"testing"
"time"
)
func TestDialWithDoHFallbackRejectsPrivateLiteral(t *testing.T) {
SetAllowPrivateNetwork(false)
dialer := &net.Dialer{Timeout: 50 * time.Millisecond}
for _, address := range []string{
"127.0.0.1:443",
"10.0.0.1:443",
"[::1]:443",
"[fe80::1]:443",
} {
if _, err := dialWithDoHFallback(context.Background(), dialer, "tcp", address); err == nil ||
!strings.Contains(err.Error(), "private/local") {
t.Fatalf("address %q was not rejected as private/local: %v", address, err)
}
}
}
func TestFilterDialableIPsDropsEveryPrivateAnswer(t *testing.T) {
SetAllowPrivateNetwork(false)
filtered := filterDialableIPs([]net.IP{
net.ParseIP("127.0.0.1"),
net.ParseIP("192.168.1.4"),
net.ParseIP("169.254.1.2"),
net.ParseIP("::1"),
net.ParseIP("203.0.113.10"),
})
if len(filtered) != 1 || !filtered[0].Equal(net.ParseIP("203.0.113.10")) {
t.Fatalf("unexpected filtered addresses: %v", filtered)
}
}
func TestInterleaveDialIPsAlternatesAddressFamilies(t *testing.T) {
ordered := interleaveDialIPs([]net.IP{
net.ParseIP("2001:db8::1"),
net.ParseIP("2001:db8::2"),
net.ParseIP("192.0.2.1"),
net.ParseIP("192.0.2.2"),
}, "tcp")
want := []string{"2001:db8::1", "192.0.2.1", "2001:db8::2", "192.0.2.2"}
if len(ordered) != len(want) {
t.Fatalf("ordered addresses = %v, want %v", ordered, want)
}
for i, ip := range ordered {
if ip.String() != want[i] {
t.Fatalf("ordered[%d] = %s, want %s", i, ip, want[i])
}
}
}
func TestRaceResolvedIPsFallsBackWithoutWaitingForPreferredFamilyTimeout(t *testing.T) {
preferredStarted := make(chan struct{})
clientPeerClosed := make(chan struct{})
dial := func(ctx context.Context, _ string, address string) (net.Conn, error) {
host, _, err := net.SplitHostPort(address)
if err != nil {
return nil, err
}
if net.ParseIP(host).To4() == nil {
close(preferredStarted)
<-ctx.Done()
return nil, ctx.Err()
}
client, peer := net.Pipe()
go func() {
<-ctx.Done()
peer.Close()
close(clientPeerClosed)
}()
return client, nil
}
startedAt := time.Now()
conn, err := raceResolvedIPs(
context.Background(),
"tcp",
"dual-stack.example",
"443",
[]net.IP{net.ParseIP("2001:db8::1"), net.ParseIP("192.0.2.1")},
nil,
10*time.Millisecond,
dial,
)
if err != nil {
t.Fatalf("raceResolvedIPs returned error: %v", err)
}
defer conn.Close()
if elapsed := time.Since(startedAt); elapsed > 100*time.Millisecond {
t.Fatalf("fallback took %v, want <100ms", elapsed)
}
select {
case <-preferredStarted:
default:
t.Fatal("preferred address family was not attempted first")
}
select {
case <-clientPeerClosed:
case <-time.After(time.Second):
t.Fatal("losing dial was not cancelled")
}
}
func TestRaceResolvedIPsReturnsLastErrorAfterFastFailures(t *testing.T) {
wantErr := errors.New("refused")
conn, err := raceResolvedIPs(
context.Background(),
"tcp",
"failed.example",
"443",
[]net.IP{net.ParseIP("192.0.2.1"), net.ParseIP("192.0.2.2")},
nil,
time.Second,
func(context.Context, string, string) (net.Conn, error) {
return nil, wantErr
},
)
if conn != nil || !errors.Is(err, wantErr) {
t.Fatalf("result = (%v, %v), want (nil, %v)", conn, err, wantErr)
}
}