tests: added sys fw basic tables/chains tests

This commit is contained in:
Gustavo Iñiguez Goia 2023-06-29 11:27:18 +02:00
parent 5a0bd3bc27
commit d3b40108c7
Failed to generate hash of commit
2 changed files with 228 additions and 0 deletions

View file

@ -0,0 +1,80 @@
package nftables
import (
"testing"
"github.com/evilsocket/opensnitch/daemon/firewall/nftables/exprs"
"github.com/google/nftables"
)
func TestChains(t *testing.T) {
conn, newNS = OpenSystemConn(t)
defer CleanupSystemConn(t, newNS)
nft.conn = conn
if nft.addInterceptionTables() != nil {
t.Error("Error adding interception tables")
}
t.Run("AddChain", func(t *testing.T) {
filterPolicy := nftables.ChainPolicyAccept
chn := nft.AddChain(
exprs.NFT_HOOK_INPUT,
exprs.NFT_CHAIN_FILTER,
exprs.NFT_FAMILY_INET,
nftables.ChainPriorityFilter,
nftables.ChainTypeFilter,
nftables.ChainHookInput,
filterPolicy)
if chn == nil {
t.Error("chain input-filter-inet not created")
}
if !nft.Commit() {
t.Error("error adding input-filter-inet chain")
}
})
t.Run("getChain", func(t *testing.T) {
tblfilter := nft.getTable(exprs.NFT_CHAIN_FILTER, exprs.NFT_FAMILY_INET)
if tblfilter == nil {
t.Error("table filter-inet not created")
}
chn := nft.getChain(exprs.NFT_HOOK_INPUT, tblfilter, exprs.NFT_FAMILY_INET)
if chn == nil {
t.Error("chain input-filter-inet not added")
}
})
t.Run("delChain", func(t *testing.T) {
tblfilter := nft.getTable(exprs.NFT_CHAIN_FILTER, exprs.NFT_FAMILY_INET)
if tblfilter == nil {
t.Error("table filter-inet not created")
}
chn := nft.getChain(exprs.NFT_HOOK_INPUT, tblfilter, exprs.NFT_FAMILY_INET)
if chn == nil {
t.Error("chain input-filter-inet not added")
}
if err := nft.delChain(chn); err != nil {
t.Error("error deleting chain input-filter-inet")
}
})
nft.delSystemTables()
}
// TestAddInterceptionChains checks if the needed tables and chains have been created.
// We use 2: output-mangle-inet for intercepting outbound connections, and input-filter-inet for DNS responses interception
func TestAddInterceptionChains(t *testing.T) {
if err := nft.addInterceptionTables(); err != nil {
t.Errorf("Error adding interception tables: %s", err)
}
if err := nft.addInterceptionChains(); err != nil {
t.Errorf("Error adding interception chains: %s", err)
}
nft.delSystemTables()
}

View file

@ -0,0 +1,148 @@
package nftables
import (
"runtime"
"testing"
"github.com/evilsocket/opensnitch/daemon/firewall/nftables/exprs"
"github.com/google/nftables"
"github.com/vishvananda/netns"
)
var (
conn *nftables.Conn
newNS netns.NsHandle
nft, _ = Fw()
)
func init() {
initMapsStore()
}
// https://github.com/google/nftables/blob/8f2d395e1089dea4966c483fbeae7e336917c095/internal/nftest/system_conn.go#L15
func OpenSystemConn(t *testing.T) (*nftables.Conn, netns.NsHandle) {
t.Helper()
// We lock the goroutine into the current thread, as namespace operations
// such as those invoked by `netns.New()` are thread-local. This is undone
// in nftest.CleanupSystemConn().
runtime.LockOSThread()
ns, err := netns.New()
if err != nil {
t.Fatalf("netns.New() failed: %v", err)
}
t.Log("OpenSystemConn() with NS:", ns)
c, err := nftables.New(nftables.WithNetNSFd(int(ns)))
if err != nil {
t.Fatalf("nftables.New() failed: %v", err)
}
return c, ns
}
func CleanupSystemConn(t *testing.T, newNS netns.NsHandle) {
defer runtime.UnlockOSThread()
if err := newNS.Close(); err != nil {
t.Fatalf("newNS.Close() failed: %v", err)
}
}
func tableExists(t *testing.T, origtbl *nftables.Table, family string) bool {
tables, err := conn.ListTablesOfFamily(
getFamilyCode(family),
)
if err != nil {
return false
}
found := false
for _, tbl := range tables {
if origtbl != nil && tbl.Name == origtbl.Name {
found = true
break
}
}
return found
}
func TestAddTable(t *testing.T) {
conn, newNS = OpenSystemConn(t)
defer CleanupSystemConn(t, newNS)
nft.conn = conn
t.Run("inet family", func(t *testing.T) {
tblxxx, err := nft.AddTable("xxx", exprs.NFT_FAMILY_INET)
if err != nil {
t.Error("table xxx-inet not added:", err)
}
if tableExists(t, tblxxx, exprs.NFT_FAMILY_INET) == false {
t.Error("table xxx-inet not in the list")
}
nft.delSystemTables()
if tableExists(t, tblxxx, exprs.NFT_FAMILY_INET) {
t.Errorf("table xxx-inet still exists: %+v", sysTables)
}
})
t.Run("ip family", func(t *testing.T) {
tblxxx, err := nft.AddTable("xxx", exprs.NFT_FAMILY_IP)
if err != nil {
t.Error("table xxx-ip not added:", err)
}
if tableExists(t, tblxxx, exprs.NFT_FAMILY_IP) == false {
t.Error("table xxx-ip not in the list")
}
nft.delSystemTables()
if tableExists(t, tblxxx, exprs.NFT_FAMILY_IP) {
t.Errorf("table xxx-ip still exists: %+v", sysTables)
}
})
t.Run("ip6 family", func(t *testing.T) {
tblxxx, err := nft.AddTable("xxx", exprs.NFT_FAMILY_IP6)
if err != nil {
t.Error("table xxx-ip6 not added:", err)
}
if tableExists(t, tblxxx, exprs.NFT_FAMILY_IP6) == false {
t.Error("table xxx-ip6 not in the list")
}
nft.delSystemTables()
if tableExists(t, tblxxx, exprs.NFT_FAMILY_IP6) {
t.Errorf("table xxx-ip6 still exists: %+v", sysTables)
}
})
}
// TestAddInterceptionTables checks if the needed tables have been created.
// We use 2: mangle-inet for intercepting outbound connections, and filter-inet for DNS responses interception
func TestAddInterceptionTables(t *testing.T) {
conn, newNS = OpenSystemConn(t)
defer CleanupSystemConn(t, newNS)
nft.conn = conn
if err := nft.addInterceptionTables(); err != nil {
t.Errorf("addInterceptionTables() error: %s", err)
}
t.Run("mangle-inet", func(t *testing.T) {
tblmangle := nft.getTable(exprs.NFT_CHAIN_MANGLE, exprs.NFT_FAMILY_INET)
if tblmangle == nil {
t.Error("interception table mangle-inet not in the list")
}
if tableExists(t, tblmangle, exprs.NFT_FAMILY_INET) == false {
t.Error("table mangle-inet not in the list")
}
})
t.Run("filter-inet", func(t *testing.T) {
tblfilter := nft.getTable(exprs.NFT_CHAIN_FILTER, exprs.NFT_FAMILY_INET)
if tblfilter == nil {
t.Error("interception table filter-inet not in the list")
}
if tableExists(t, tblfilter, exprs.NFT_FAMILY_INET) == false {
t.Error("table filter-inet not in the list")
}
})
}