mirror of https://github.com/vishvananda/netlink
567 lines
14 KiB
Go
567 lines
14 KiB
Go
package netlink
|
|
|
|
import (
|
|
"bytes"
|
|
"io/ioutil"
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/vishvananda/netlink/nl"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func TestParseIpsetProtocolResult(t *testing.T) {
|
|
msgBytes, err := ioutil.ReadFile("testdata/ipset_protocol_result")
|
|
if err != nil {
|
|
t.Fatalf("reading test fixture failed: %v", err)
|
|
}
|
|
|
|
msg := ipsetUnserialize([][]byte{msgBytes})
|
|
if msg.Protocol != 6 {
|
|
t.Errorf("expected msg.Protocol to equal 6, got %d", msg.Protocol)
|
|
}
|
|
}
|
|
|
|
func TestParseIpsetListResult(t *testing.T) {
|
|
msgBytes, err := ioutil.ReadFile("testdata/ipset_list_result")
|
|
if err != nil {
|
|
t.Fatalf("reading test fixture failed: %v", err)
|
|
}
|
|
|
|
msg := ipsetUnserialize([][]byte{msgBytes})
|
|
if msg.SetName != "clients" {
|
|
t.Errorf(`expected SetName to equal "clients", got %q`, msg.SetName)
|
|
}
|
|
if msg.TypeName != "hash:mac" {
|
|
t.Errorf(`expected TypeName to equal "hash:mac", got %q`, msg.TypeName)
|
|
}
|
|
if msg.Protocol != 6 {
|
|
t.Errorf("expected Protocol to equal 6, got %d", msg.Protocol)
|
|
}
|
|
if msg.References != 0 {
|
|
t.Errorf("expected References to equal 0, got %d", msg.References)
|
|
}
|
|
if msg.NumEntries != 2 {
|
|
t.Errorf("expected NumEntries to equal 2, got %d", msg.NumEntries)
|
|
}
|
|
if msg.HashSize != 1024 {
|
|
t.Errorf("expected HashSize to equal 1024, got %d", msg.HashSize)
|
|
}
|
|
if *msg.Timeout != 3600 {
|
|
t.Errorf("expected Timeout to equal 3600, got %d", *msg.Timeout)
|
|
}
|
|
if msg.MaxElements != 65536 {
|
|
t.Errorf("expected MaxElements to equal 65536, got %d", msg.MaxElements)
|
|
}
|
|
if msg.CadtFlags != nl.IPSET_FLAG_WITH_COMMENT|nl.IPSET_FLAG_WITH_COUNTERS {
|
|
t.Error("expected CadtFlags to be IPSET_FLAG_WITH_COMMENT and IPSET_FLAG_WITH_COUNTERS")
|
|
}
|
|
if len(msg.Entries) != 2 {
|
|
t.Fatalf("expected 2 Entries, got %d", len(msg.Entries))
|
|
}
|
|
|
|
// first entry
|
|
ent := msg.Entries[0]
|
|
if int(*ent.Timeout) != 3577 {
|
|
t.Errorf("expected Timeout for first entry to equal 3577, got %d", *ent.Timeout)
|
|
}
|
|
if int(*ent.Bytes) != 4121 {
|
|
t.Errorf("expected Bytes for first entry to equal 4121, got %d", *ent.Bytes)
|
|
}
|
|
if int(*ent.Packets) != 42 {
|
|
t.Errorf("expected Packets for first entry to equal 42, got %d", *ent.Packets)
|
|
}
|
|
if ent.Comment != "foo bar" {
|
|
t.Errorf("unexpected Comment for first entry: %q", ent.Comment)
|
|
}
|
|
expectedMAC := net.HardwareAddr{0xde, 0xad, 0x0, 0x0, 0xbe, 0xef}
|
|
if !bytes.Equal(ent.MAC, expectedMAC) {
|
|
t.Errorf("expected MAC for first entry to be %s, got %s", expectedMAC.String(), ent.MAC.String())
|
|
}
|
|
|
|
// second entry
|
|
ent = msg.Entries[1]
|
|
expectedMAC = net.HardwareAddr{0x1, 0x2, 0x3, 0x0, 0x1, 0x2}
|
|
if !bytes.Equal(ent.MAC, expectedMAC) {
|
|
t.Errorf("expected MAC for second entry to be %s, got %s", expectedMAC.String(), ent.MAC.String())
|
|
}
|
|
}
|
|
|
|
func TestIpsetCreateListAddDelDestroy(t *testing.T) {
|
|
tearDown := setUpNetlinkTest(t)
|
|
defer tearDown()
|
|
timeout := uint32(3)
|
|
err := IpsetCreate("my-test-ipset-1", "hash:ip", IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: true,
|
|
Comments: false,
|
|
Skbinfo: false,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = IpsetCreate("my-test-ipset-2", "hash:net", IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: false,
|
|
Comments: true,
|
|
Skbinfo: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
results, err := IpsetListAll()
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(results) != 2 {
|
|
t.Fatalf("expected 2 IPSets to be created, got %d", len(results))
|
|
}
|
|
|
|
if results[0].SetName != "my-test-ipset-1" {
|
|
t.Errorf("expected name to be 'my-test-ipset-1', but got '%s'", results[0].SetName)
|
|
}
|
|
|
|
if results[1].SetName != "my-test-ipset-2" {
|
|
t.Errorf("expected name to be 'my-test-ipset-2', but got '%s'", results[1].SetName)
|
|
}
|
|
|
|
if results[0].TypeName != "hash:ip" {
|
|
t.Errorf("expected type to be 'hash:ip', but got '%s'", results[0].TypeName)
|
|
}
|
|
|
|
if results[1].TypeName != "hash:net" {
|
|
t.Errorf("expected type to be 'hash:net', but got '%s'", results[1].TypeName)
|
|
}
|
|
|
|
if *results[0].Timeout != 3 {
|
|
t.Errorf("expected timeout to be 3, but got '%d'", *results[0].Timeout)
|
|
}
|
|
|
|
err = IpsetAdd("my-test-ipset-1", &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.99").To4(),
|
|
Replace: false,
|
|
})
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result, err := IpsetList("my-test-ipset-1")
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(result.Entries) != 1 {
|
|
t.Fatalf("expected 1 entry be created, got '%d'", len(result.Entries))
|
|
}
|
|
if result.Entries[0].IP.String() != "10.99.99.99" {
|
|
t.Fatalf("expected entry to be '10.99.99.99', got '%s'", result.Entries[0].IP.String())
|
|
}
|
|
|
|
if result.Entries[0].Comment != "test comment" {
|
|
// This is only supported in the kernel module from revision 2 or 4, so comments may be ignored.
|
|
t.Logf("expected comment to be 'test comment', got '%s'", result.Entries[0].Comment)
|
|
}
|
|
|
|
err = IpsetDel("my-test-ipset-1", &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.99").To4(),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result, err = IpsetList("my-test-ipset-1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(result.Entries) != 0 {
|
|
t.Fatalf("expected 0 entries to exist, got %d", len(result.Entries))
|
|
}
|
|
|
|
err = IpsetDestroy("my-test-ipset-1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = IpsetDestroy("my-test-ipset-2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestIpsetCreateListAddDelDestroyWithTestCases(t *testing.T) {
|
|
timeout := uint32(3)
|
|
protocalTCP := uint8(unix.IPPROTO_TCP)
|
|
port := uint16(80)
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
setname string
|
|
typename string
|
|
options IpsetCreateOptions
|
|
entry *IPSetEntry
|
|
}{
|
|
{
|
|
desc: "Type-hash:ip",
|
|
setname: "my-test-ipset-1",
|
|
typename: "hash:ip",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: true,
|
|
Comments: false,
|
|
Skbinfo: false,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.99").To4(),
|
|
Replace: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "Type-hash:net",
|
|
setname: "my-test-ipset-2",
|
|
typename: "hash:net",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: false,
|
|
Comments: true,
|
|
Skbinfo: true,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.0").To4(),
|
|
CIDR: 24,
|
|
Replace: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "Type-hash:net,net",
|
|
setname: "my-test-ipset-4",
|
|
typename: "hash:net,net",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: false,
|
|
Comments: true,
|
|
Skbinfo: true,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.0").To4(),
|
|
CIDR: 24,
|
|
IP2: net.ParseIP("10.99.0.0").To4(),
|
|
CIDR2: 24,
|
|
Replace: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "Type-hash:ip,ip",
|
|
setname: "my-test-ipset-5",
|
|
typename: "hash:net,net",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: false,
|
|
Comments: true,
|
|
Skbinfo: true,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.0").To4(),
|
|
IP2: net.ParseIP("10.99.0.0").To4(),
|
|
Replace: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "Type-hash:ip,port",
|
|
setname: "my-test-ipset-6",
|
|
typename: "hash:ip,port",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: false,
|
|
Comments: true,
|
|
Skbinfo: true,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.1").To4(),
|
|
Protocol: &protocalTCP,
|
|
Port: &port,
|
|
Replace: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "Type-hash:net,port,net",
|
|
setname: "my-test-ipset-7",
|
|
typename: "hash:net,port,net",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: false,
|
|
Comments: true,
|
|
Skbinfo: true,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.0").To4(),
|
|
CIDR: 24,
|
|
IP2: net.ParseIP("10.99.0.0").To4(),
|
|
CIDR2: 24,
|
|
Protocol: &protocalTCP,
|
|
Port: &port,
|
|
Replace: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "Type-hash:mac",
|
|
setname: "my-test-ipset-8",
|
|
typename: "hash:mac",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: true,
|
|
Comments: false,
|
|
Skbinfo: false,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
MAC: net.HardwareAddr{0x26, 0x6f, 0x0d, 0x5b, 0xc1, 0x9d},
|
|
Replace: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "Type-hash:net,iface",
|
|
setname: "my-test-ipset-9",
|
|
typename: "hash:net,iface",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: true,
|
|
Comments: false,
|
|
Skbinfo: false,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.0").To4(),
|
|
CIDR: 24,
|
|
IFace: "eth0",
|
|
Replace: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "Type-hash:ip,mark",
|
|
setname: "my-test-ipset-10",
|
|
typename: "hash:ip,mark",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: true,
|
|
Comments: false,
|
|
Skbinfo: false,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.0").To4(),
|
|
Mark: &timeout,
|
|
Replace: false,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tC := range testCases {
|
|
t.Run(tC.desc, func(t *testing.T) {
|
|
tearDown := setUpNetlinkTest(t)
|
|
defer tearDown()
|
|
|
|
err := IpsetCreate(tC.setname, tC.typename, tC.options)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result, err := IpsetList(tC.setname)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if result.SetName != tC.setname {
|
|
t.Errorf("expected name to be '%s', but got '%s'", tC.setname, result.SetName)
|
|
}
|
|
|
|
if result.TypeName != tC.typename {
|
|
t.Errorf("expected type to be '%s', but got '%s'", tC.typename, result.TypeName)
|
|
}
|
|
|
|
if *result.Timeout != timeout {
|
|
t.Errorf("expected timeout to be %d, but got '%d'", timeout, *result.Timeout)
|
|
}
|
|
|
|
err = IpsetAdd(tC.setname, tC.entry)
|
|
|
|
if err != nil {
|
|
t.Error(result.Protocol, result.Family)
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result, err = IpsetList(tC.setname)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(result.Entries) != 1 {
|
|
t.Fatalf("expected 1 entry be created, got '%d'", len(result.Entries))
|
|
}
|
|
|
|
if tC.entry.IP != nil {
|
|
if !tC.entry.IP.Equal(result.Entries[0].IP) {
|
|
t.Fatalf("expected entry to be '%v', got '%v'", tC.entry.IP, result.Entries[0].IP)
|
|
}
|
|
}
|
|
|
|
if tC.entry.CIDR > 0 {
|
|
if result.Entries[0].CIDR != tC.entry.CIDR {
|
|
t.Fatalf("expected cidr to be '%d', got '%d'", tC.entry.CIDR, result.Entries[0].CIDR)
|
|
}
|
|
}
|
|
|
|
if tC.entry.IP2 != nil {
|
|
if !tC.entry.IP2.Equal(result.Entries[0].IP2) {
|
|
t.Fatalf("expected entry.ip2 to be '%v', got '%v'", tC.entry.IP2, result.Entries[0].IP2)
|
|
}
|
|
}
|
|
|
|
if tC.entry.CIDR2 > 0 {
|
|
if result.Entries[0].CIDR2 != tC.entry.CIDR2 {
|
|
t.Fatalf("expected cidr2 to be '%d', got '%d'", tC.entry.CIDR2, result.Entries[0].CIDR2)
|
|
}
|
|
}
|
|
|
|
if tC.entry.Port != nil {
|
|
if *result.Entries[0].Protocol != *tC.entry.Protocol {
|
|
t.Fatalf("expected protocol to be '%d', got '%d'", *tC.entry.Protocol, *result.Entries[0].Protocol)
|
|
}
|
|
if *result.Entries[0].Port != *tC.entry.Port {
|
|
t.Fatalf("expected port to be '%d', got '%d'", *tC.entry.Port, *result.Entries[0].Port)
|
|
}
|
|
}
|
|
|
|
if tC.entry.MAC != nil {
|
|
if result.Entries[0].MAC.String() != tC.entry.MAC.String() {
|
|
t.Fatalf("expected mac to be '%v', got '%v'", tC.entry.MAC, result.Entries[0].MAC)
|
|
}
|
|
}
|
|
|
|
if tC.entry.IFace != "" {
|
|
if result.Entries[0].IFace != tC.entry.IFace {
|
|
t.Fatalf("expected iface to be '%v', got '%v'", tC.entry.IFace, result.Entries[0].IFace)
|
|
}
|
|
}
|
|
|
|
if tC.entry.Mark != nil {
|
|
if *result.Entries[0].Mark != *tC.entry.Mark {
|
|
t.Fatalf("expected mark to be '%v', got '%v'", *tC.entry.Mark, *result.Entries[0].Mark)
|
|
}
|
|
}
|
|
|
|
if result.Entries[0].Comment != tC.entry.Comment {
|
|
// This is only supported in the kernel module from revision 2 or 4, so comments may be ignored.
|
|
t.Logf("expected comment to be '%s', got '%s'", tC.entry.Comment, result.Entries[0].Comment)
|
|
}
|
|
|
|
err = IpsetDel(tC.setname, tC.entry)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result, err = IpsetList(tC.setname)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(result.Entries) != 0 {
|
|
t.Fatalf("expected 0 entries to exist, got %d", len(result.Entries))
|
|
}
|
|
|
|
err = IpsetDestroy(tC.setname)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIpsetBitmapCreateListWithTestCases(t *testing.T) {
|
|
timeout := uint32(3)
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
setname string
|
|
typename string
|
|
options IpsetCreateOptions
|
|
entry *IPSetEntry
|
|
}{
|
|
{
|
|
desc: "Type-bitmap:port",
|
|
setname: "my-test-ipset-11",
|
|
typename: "bitmap:port",
|
|
options: IpsetCreateOptions{
|
|
Replace: true,
|
|
Timeout: &timeout,
|
|
Counters: true,
|
|
Comments: false,
|
|
Skbinfo: false,
|
|
PortFrom: 100,
|
|
PortTo: 600,
|
|
},
|
|
entry: &IPSetEntry{
|
|
Comment: "test comment",
|
|
IP: net.ParseIP("10.99.99.0").To4(),
|
|
CIDR: 26,
|
|
Mark: &timeout,
|
|
Replace: false,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tC := range testCases {
|
|
t.Run(tC.desc, func(t *testing.T) {
|
|
tearDown := setUpNetlinkTest(t)
|
|
defer tearDown()
|
|
|
|
err := IpsetCreate(tC.setname, tC.typename, tC.options)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result, err := IpsetList(tC.setname)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if tC.typename == "bitmap:port" {
|
|
if result.PortFrom != tC.options.PortFrom || result.PortTo != tC.options.PortTo {
|
|
t.Fatalf("expected port range %d-%d, got %d-%d", tC.options.PortFrom, tC.options.PortTo, result.PortFrom, result.PortTo)
|
|
}
|
|
} else if tC.typename == "bitmap:ip" {
|
|
if result.IPFrom == nil || result.IPTo == nil || result.IPFrom.Equal(tC.options.IPFrom) || result.IPTo.Equal(tC.options.IPTo) {
|
|
t.Fatalf("expected ip range %v-%v, got %v-%v", tC.options.IPFrom, tC.options.IPTo, result.IPFrom, result.IPTo)
|
|
}
|
|
}
|
|
|
|
})
|
|
}
|
|
}
|