2021-06-18 15:55:01 +01:00
|
|
|
//go:build linux
|
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
package ipset
|
2021-06-18 15:55:01 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"net"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/AdguardTeam/golibs/errors"
|
|
|
|
"github.com/digineo/go-ipset/v2"
|
|
|
|
"github.com/mdlayher/netlink"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/ti-mo/netfilter"
|
|
|
|
)
|
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
// fakeConn is a fake ipsetConn for tests.
|
|
|
|
type fakeConn struct {
|
2021-06-18 15:55:01 +01:00
|
|
|
ipv4Header *ipset.HeaderPolicy
|
|
|
|
ipv4Entries *[]*ipset.Entry
|
|
|
|
ipv6Header *ipset.HeaderPolicy
|
|
|
|
ipv6Entries *[]*ipset.Entry
|
2023-10-24 12:17:14 +01:00
|
|
|
sets []props
|
2021-06-18 15:55:01 +01:00
|
|
|
}
|
|
|
|
|
2023-10-24 12:17:14 +01:00
|
|
|
// type check
|
|
|
|
var _ ipsetConn = (*fakeConn)(nil)
|
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
// Add implements the [ipsetConn] interface for *fakeConn.
|
|
|
|
func (c *fakeConn) Add(name string, entries ...*ipset.Entry) (err error) {
|
2021-06-18 15:55:01 +01:00
|
|
|
if strings.Contains(name, "ipv4") {
|
|
|
|
*c.ipv4Entries = append(*c.ipv4Entries, entries...)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
} else if strings.Contains(name, "ipv6") {
|
|
|
|
*c.ipv6Entries = append(*c.ipv6Entries, entries...)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return errors.Error("test: ipset not found")
|
|
|
|
}
|
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
// Close implements the [ipsetConn] interface for *fakeConn.
|
|
|
|
func (c *fakeConn) Close() (err error) {
|
2021-06-18 15:55:01 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-10-24 12:17:14 +01:00
|
|
|
// listAll implements the [ipsetConn] interface for *fakeConn.
|
|
|
|
func (c *fakeConn) listAll() (sets []props, err error) {
|
|
|
|
return c.sets, nil
|
2021-06-18 15:55:01 +01:00
|
|
|
}
|
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
func TestManager_Add(t *testing.T) {
|
2021-06-18 15:55:01 +01:00
|
|
|
ipsetConf := []string{
|
|
|
|
"example.com,example.net/ipv4set",
|
|
|
|
"example.org,example.biz/ipv6set",
|
|
|
|
}
|
|
|
|
|
|
|
|
var ipv4Entries []*ipset.Entry
|
|
|
|
var ipv6Entries []*ipset.Entry
|
|
|
|
|
|
|
|
fakeDial := func(
|
|
|
|
pf netfilter.ProtoFamily,
|
|
|
|
conf *netlink.Config,
|
|
|
|
) (conn ipsetConn, err error) {
|
2023-10-06 11:16:39 +01:00
|
|
|
return &fakeConn{
|
2021-06-18 15:55:01 +01:00
|
|
|
ipv4Header: &ipset.HeaderPolicy{
|
|
|
|
Family: ipset.NewUInt8Box(uint8(netfilter.ProtoIPv4)),
|
|
|
|
},
|
|
|
|
ipv4Entries: &ipv4Entries,
|
|
|
|
ipv6Header: &ipset.HeaderPolicy{
|
|
|
|
Family: ipset.NewUInt8Box(uint8(netfilter.ProtoIPv6)),
|
|
|
|
},
|
|
|
|
ipv6Entries: &ipv6Entries,
|
2023-10-24 12:17:14 +01:00
|
|
|
sets: []props{{
|
|
|
|
name: "ipv4set",
|
|
|
|
family: netfilter.ProtoIPv4,
|
|
|
|
}, {
|
|
|
|
name: "ipv6set",
|
|
|
|
family: netfilter.ProtoIPv6,
|
|
|
|
}},
|
2021-06-18 15:55:01 +01:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
m, err := newManagerWithDialer(ipsetConf, fakeDial)
|
2021-06-18 15:55:01 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ip4 := net.IP{1, 2, 3, 4}
|
|
|
|
ip6 := net.IP{
|
|
|
|
0x12, 0x34, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x56, 0x78,
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err := m.Add("example.net", []net.IP{ip4}, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, 1, n)
|
|
|
|
|
|
|
|
require.Len(t, ipv4Entries, 1)
|
|
|
|
|
|
|
|
gotIP4 := ipv4Entries[0].IP.Value
|
|
|
|
assert.Equal(t, ip4, gotIP4)
|
|
|
|
|
|
|
|
n, err = m.Add("example.biz", nil, []net.IP{ip6})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, 1, n)
|
|
|
|
|
|
|
|
require.Len(t, ipv6Entries, 1)
|
|
|
|
|
|
|
|
gotIP6 := ipv6Entries[0].IP.Value
|
|
|
|
assert.Equal(t, ip6, gotIP6)
|
|
|
|
|
|
|
|
err = m.Close()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2023-10-09 11:15:51 +01:00
|
|
|
// ipsetPropsSink is the typed sink for benchmark results.
|
2023-10-06 11:16:39 +01:00
|
|
|
var ipsetPropsSink []props
|
2021-06-18 15:55:01 +01:00
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
func BenchmarkManager_LookupHost(b *testing.B) {
|
|
|
|
propsLong := []props{{
|
2021-06-18 15:55:01 +01:00
|
|
|
name: "example.com",
|
|
|
|
family: netfilter.ProtoIPv4,
|
|
|
|
}}
|
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
propsShort := []props{{
|
2021-06-18 15:55:01 +01:00
|
|
|
name: "example.net",
|
|
|
|
family: netfilter.ProtoIPv4,
|
|
|
|
}}
|
|
|
|
|
2023-10-06 11:16:39 +01:00
|
|
|
m := &manager{
|
|
|
|
domainToIpsets: map[string][]props{
|
2021-06-18 15:55:01 +01:00
|
|
|
"": propsLong,
|
|
|
|
"example.net": propsShort,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
b.Run("long", func(b *testing.B) {
|
|
|
|
const name = "a.very.long.domain.name.inside.the.domain.example.com"
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
ipsetPropsSink = m.lookupHost(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
require.Equal(b, propsLong, ipsetPropsSink)
|
|
|
|
})
|
|
|
|
|
|
|
|
b.Run("short", func(b *testing.B) {
|
|
|
|
const name = "example.net"
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
ipsetPropsSink = m.lookupHost(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
require.Equal(b, propsShort, ipsetPropsSink)
|
|
|
|
})
|
|
|
|
}
|