package aghnet import ( "net" "testing" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // fakeIface is a stub implementation of aghnet.NetIface to simplify testing. type fakeIface struct { err error addrs []net.Addr } // Addrs implements the NetIface interface for *fakeIface. func (iface *fakeIface) Addrs() (addrs []net.Addr, err error) { if iface.err != nil { return nil, iface.err } return iface.addrs, nil } func TestIfaceIPAddrs(t *testing.T) { const errTest errors.Error = "test error" ip4 := net.IP{1, 2, 3, 4} addr4 := &net.IPNet{IP: ip4} ip6 := net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6} addr6 := &net.IPNet{IP: ip6} testCases := []struct { iface NetIface name string wantErrMsg string want []net.IP ipv IPVersion }{{ iface: &fakeIface{addrs: []net.Addr{addr4}, err: nil}, name: "ipv4_success", wantErrMsg: "", want: []net.IP{ip4}, ipv: IPVersion4, }, { iface: &fakeIface{addrs: []net.Addr{addr6, addr4}, err: nil}, name: "ipv4_success_with_ipv6", wantErrMsg: "", want: []net.IP{ip4}, ipv: IPVersion4, }, { iface: &fakeIface{addrs: []net.Addr{addr4}, err: errTest}, name: "ipv4_error", wantErrMsg: errTest.Error(), want: nil, ipv: IPVersion4, }, { iface: &fakeIface{addrs: []net.Addr{addr6}, err: nil}, name: "ipv6_success", wantErrMsg: "", want: []net.IP{ip6}, ipv: IPVersion6, }, { iface: &fakeIface{addrs: []net.Addr{addr6, addr4}, err: nil}, name: "ipv6_success_with_ipv4", wantErrMsg: "", want: []net.IP{ip6}, ipv: IPVersion6, }, { iface: &fakeIface{addrs: []net.Addr{addr6}, err: errTest}, name: "ipv6_error", wantErrMsg: errTest.Error(), want: nil, ipv: IPVersion6, }, { iface: &fakeIface{addrs: nil, err: nil}, name: "bad_proto", wantErrMsg: "invalid ip version 10", want: nil, ipv: IPVersion6 + IPVersion4, }, { iface: &fakeIface{addrs: []net.Addr{&net.IPAddr{IP: ip4}}, err: nil}, name: "ipaddr_v4", wantErrMsg: "", want: []net.IP{ip4}, ipv: IPVersion4, }, { iface: &fakeIface{addrs: []net.Addr{&net.IPAddr{IP: ip6, Zone: ""}}, err: nil}, name: "ipaddr_v6", wantErrMsg: "", want: []net.IP{ip6}, ipv: IPVersion6, }, { iface: &fakeIface{addrs: []net.Addr{&net.UnixAddr{}}, err: nil}, name: "non-ipv4", wantErrMsg: "", want: nil, ipv: IPVersion4, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { got, err := IfaceIPAddrs(tc.iface, tc.ipv) testutil.AssertErrorMsg(t, tc.wantErrMsg, err) assert.Equal(t, tc.want, got) }) } } type waitingFakeIface struct { err error addrs []net.Addr n int } // Addrs implements the NetIface interface for *waitingFakeIface. func (iface *waitingFakeIface) Addrs() (addrs []net.Addr, err error) { if iface.err != nil { return nil, iface.err } if iface.n == 0 { return iface.addrs, nil } iface.n-- return nil, nil } func TestIfaceDNSIPAddrs(t *testing.T) { const errTest errors.Error = "test error" ip4 := net.IP{1, 2, 3, 4} addr4 := &net.IPNet{IP: ip4} ip6 := net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6} addr6 := &net.IPNet{IP: ip6} testCases := []struct { iface NetIface wantErr error name string want []net.IP ipv IPVersion }{{ name: "ipv4_success", iface: &fakeIface{addrs: []net.Addr{addr4}, err: nil}, ipv: IPVersion4, want: []net.IP{ip4, ip4}, wantErr: nil, }, { name: "ipv4_success_with_ipv6", iface: &fakeIface{addrs: []net.Addr{addr6, addr4}, err: nil}, ipv: IPVersion4, want: []net.IP{ip4, ip4}, wantErr: nil, }, { name: "ipv4_error", iface: &fakeIface{addrs: []net.Addr{addr4}, err: errTest}, ipv: IPVersion4, want: nil, wantErr: errTest, }, { name: "ipv4_wait", iface: &waitingFakeIface{addrs: []net.Addr{addr4}, err: nil, n: 1}, ipv: IPVersion4, want: []net.IP{ip4, ip4}, wantErr: nil, }, { name: "ipv6_success", iface: &fakeIface{addrs: []net.Addr{addr6}, err: nil}, ipv: IPVersion6, want: []net.IP{ip6, ip6}, wantErr: nil, }, { name: "ipv6_success_with_ipv4", iface: &fakeIface{addrs: []net.Addr{addr6, addr4}, err: nil}, ipv: IPVersion6, want: []net.IP{ip6, ip6}, wantErr: nil, }, { name: "ipv6_error", iface: &fakeIface{addrs: []net.Addr{addr6}, err: errTest}, ipv: IPVersion6, want: nil, wantErr: errTest, }, { name: "ipv6_wait", iface: &waitingFakeIface{addrs: []net.Addr{addr6}, err: nil, n: 1}, ipv: IPVersion6, want: []net.IP{ip6, ip6}, wantErr: nil, }, { name: "empty", iface: &fakeIface{addrs: nil, err: nil}, ipv: IPVersion4, want: nil, wantErr: nil, }, { name: "many", iface: &fakeIface{addrs: []net.Addr{addr4, addr4}}, ipv: IPVersion4, want: []net.IP{ip4, ip4}, wantErr: nil, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { got, err := IfaceDNSIPAddrs(tc.iface, tc.ipv, 2, 0) require.ErrorIs(t, err, tc.wantErr) assert.Equal(t, tc.want, got) }) } }