fix(dialer): correct inverted setMark on FreeBSD/OpenBSD
Fix setMark early-return conditions that were inverted relative to Linux: on FreeBSD (SO_USER_COOKIE) and OpenBSD (SO_RTABLE), a non-zero mark was short-circuited instead of applied, disabling socket marking entirely. Also fix GetClientIP to trim leading whitespace from X-Forwarded-For entries (per RFC 7239), and fix Body.Read to subtract len(b) instead of n from recordSize when a single read exceeds the remaining quota. Add unit tests for internal/net/ (addr, dialer, http, ip, net, pipe, transport, resolve, proxyproto, udp).
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPortRange_Parse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantMin int
|
||||
wantMax int
|
||||
wantErr bool
|
||||
}{
|
||||
{"single port", "8080", 8080, 8080, false},
|
||||
{"range", "8000-9000", 8000, 9000, false},
|
||||
{"zero", "0", 0, 0, false},
|
||||
{"max port", "65535", 65535, 65535, false},
|
||||
{"negative", "-1", 0, 0, true},
|
||||
{"too large", "65536", 0, 0, true},
|
||||
{"three parts", "1-2-3", 0, 0, true},
|
||||
{"invalid string", "abc", 0, 0, true},
|
||||
{"invalid min", "abc-123", 0, 0, true},
|
||||
{"invalid max", "123-abc", 0, 0, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var pr PortRange
|
||||
err := pr.Parse(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !tt.wantErr {
|
||||
if pr.Min != tt.wantMin || pr.Max != tt.wantMax {
|
||||
t.Errorf("Parse() got Min=%d Max=%d, want Min=%d Max=%d", pr.Min, pr.Max, tt.wantMin, tt.wantMax)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPortRange_Contains(t *testing.T) {
|
||||
pr := PortRange{Min: 8000, Max: 9000}
|
||||
if !pr.Contains(8000) {
|
||||
t.Error("should contain min")
|
||||
}
|
||||
if !pr.Contains(9000) {
|
||||
t.Error("should contain max")
|
||||
}
|
||||
if !pr.Contains(8500) {
|
||||
t.Error("should contain middle")
|
||||
}
|
||||
if pr.Contains(7999) {
|
||||
t.Error("should not contain below min")
|
||||
}
|
||||
if pr.Contains(9001) {
|
||||
t.Error("should not contain above max")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPRange_Parse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantMin string
|
||||
wantMax string
|
||||
wantErr bool
|
||||
}{
|
||||
{"single ipv4", "192.168.1.1", "192.168.1.1", "192.168.1.1", false},
|
||||
{"ipv4 range", "192.168.1.1-192.168.1.254", "192.168.1.1", "192.168.1.254", false},
|
||||
{"single ipv6", "::1", "::1", "::1", false},
|
||||
{"ipv6 range", "::1-::2", "::1", "::2", false},
|
||||
{"three parts", "1-2-3", "", "", true},
|
||||
{"invalid single", "not-an-ip", "", "", true},
|
||||
{"invalid min", "not-ip-192.168.1.2", "", "", true},
|
||||
{"invalid max", "192.168.1.1-not-ip", "", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var r IPRange
|
||||
err := r.Parse(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !tt.wantErr {
|
||||
wantMin := netip.MustParseAddr(tt.wantMin)
|
||||
wantMax := netip.MustParseAddr(tt.wantMax)
|
||||
if r.Min != wantMin || r.Max != wantMax {
|
||||
t.Errorf("Parse() got Min=%v Max=%v, want Min=%v Max=%v", r.Min, r.Max, wantMin, wantMax)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPRange_Contains(t *testing.T) {
|
||||
r := IPRange{
|
||||
Min: netip.MustParseAddr("192.168.1.0"),
|
||||
Max: netip.MustParseAddr("192.168.1.255"),
|
||||
}
|
||||
if !r.Contains(netip.MustParseAddr("192.168.1.0")) {
|
||||
t.Error("should contain min")
|
||||
}
|
||||
if !r.Contains(netip.MustParseAddr("192.168.1.255")) {
|
||||
t.Error("should contain max")
|
||||
}
|
||||
if !r.Contains(netip.MustParseAddr("192.168.1.100")) {
|
||||
t.Error("should contain middle")
|
||||
}
|
||||
if r.Contains(netip.MustParseAddr("192.168.0.255")) {
|
||||
t.Error("should not contain below min")
|
||||
}
|
||||
if r.Contains(netip.MustParseAddr("192.168.2.0")) {
|
||||
t.Error("should not contain above max")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddrPortRange_Addrs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
apr AddrPortRange
|
||||
want []string
|
||||
}{
|
||||
{"with scheme", "http://192.168.1.1:8080", nil},
|
||||
{"tls scheme", "tls://192.168.1.1:8080", nil},
|
||||
{"invalid format", "not-a-valid-address", nil},
|
||||
{"single port", "192.168.1.1:8080", []string{"192.168.1.1:8080"}},
|
||||
{"port range", "192.168.1.1:8080-8082", []string{"192.168.1.1:8080", "192.168.1.1:8081", "192.168.1.1:8082"}},
|
||||
{"ipv6 single", "[::1]:8080", []string{"[::1]:8080"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.apr.Addrs()
|
||||
if len(got) != len(tt.want) {
|
||||
t.Errorf("Addrs() = %v, want %v", got, tt.want)
|
||||
return
|
||||
}
|
||||
for i := range got {
|
||||
if got[i] != tt.want[i] {
|
||||
t.Errorf("Addrs()[%d] = %s, want %s", i, got[i], tt.want[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ipToAddr(t *testing.T) {
|
||||
ip := net.ParseIP("192.168.1.1")
|
||||
tests := []struct {
|
||||
network string
|
||||
want net.Addr
|
||||
}{
|
||||
{"tcp", &net.TCPAddr{IP: ip, Port: 0}},
|
||||
{"tcp4", &net.TCPAddr{IP: ip, Port: 0}},
|
||||
{"tcp6", &net.TCPAddr{IP: ip, Port: 0}},
|
||||
{"udp", &net.UDPAddr{IP: ip, Port: 0}},
|
||||
{"udp4", &net.UDPAddr{IP: ip, Port: 0}},
|
||||
{"udp6", &net.UDPAddr{IP: ip, Port: 0}},
|
||||
{"ip", &net.IPAddr{IP: ip}},
|
||||
{"other", &net.IPAddr{IP: ip}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.network, func(t *testing.T) {
|
||||
got := ipToAddr(ip, tt.network)
|
||||
if got.Network() != tt.want.Network() || got.String() != tt.want.String() {
|
||||
t.Errorf("ipToAddr() = %#v, want %#v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findInterfaceByIP(t *testing.T) {
|
||||
// Test with localhost IP
|
||||
ip := net.ParseIP("127.0.0.1")
|
||||
name, err := findInterfaceByIP(ip)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 127.0.0.1 should be on the loopback interface
|
||||
if name == "" {
|
||||
t.Log("127.0.0.1 not found on any interface (may happen in containers)")
|
||||
}
|
||||
|
||||
// Test with an IP that shouldn't be assigned
|
||||
ip2 := net.ParseIP("203.0.113.1")
|
||||
name2, err2 := findInterfaceByIP(ip2)
|
||||
if err2 != nil {
|
||||
t.Fatal(err2)
|
||||
}
|
||||
if name2 != "" {
|
||||
t.Errorf("expected empty name for unassigned IP, got %s", name2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInterfaceAddr(t *testing.T) {
|
||||
// Empty interface name
|
||||
ifce, addrs, err := ParseInterfaceAddr("", "tcp")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if ifce != "" {
|
||||
t.Errorf("expected empty ifce, got %s", ifce)
|
||||
}
|
||||
if len(addrs) != 1 || addrs[0] != nil {
|
||||
t.Errorf("expected [nil], got %v", addrs)
|
||||
}
|
||||
|
||||
// Non-existent interface
|
||||
_, _, err = ParseInterfaceAddr("nonexistent_interface_xyz", "tcp")
|
||||
if err == nil {
|
||||
t.Error("expected error for non-existent interface")
|
||||
}
|
||||
|
||||
// IP string as interface name
|
||||
ifce, addrs, err = ParseInterfaceAddr("127.0.0.1", "tcp")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if ifce == "" {
|
||||
t.Log("127.0.0.1 not found on any interface (may happen in containers)")
|
||||
} else if len(addrs) != 1 {
|
||||
t.Errorf("expected 1 addr, got %d", len(addrs))
|
||||
}
|
||||
|
||||
// IP that doesn't exist on any interface
|
||||
ifce, addrs, err = ParseInterfaceAddr("203.0.113.1", "udp")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if ifce != "" {
|
||||
t.Errorf("expected empty ifce for unassigned IP, got %s", ifce)
|
||||
}
|
||||
if len(addrs) != 1 {
|
||||
t.Errorf("expected 1 addr, got %d", len(addrs))
|
||||
}
|
||||
|
||||
// Test UDP network specific returns
|
||||
ifce, addrs, err = ParseInterfaceAddr("127.0.0.1", "udp")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if ifce != "" {
|
||||
if len(addrs) != 1 {
|
||||
t.Errorf("expected 1 addr, got %d", len(addrs))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user