tests: disable some tests by default, added utils.go tests

- These tests require permissions for creating new namespaces.
  By default disable them for now.
- Added utils.go tests.
This commit is contained in:
Gustavo Iñiguez Goia 2023-06-29 16:19:47 +02:00
parent d3b40108c7
commit 78ac6c0f6b
Failed to generate hash of commit
3 changed files with 235 additions and 0 deletions

View file

@ -8,6 +8,8 @@ import (
)
func TestChains(t *testing.T) {
skipIfNotPrivileged(t)
conn, newNS = OpenSystemConn(t)
defer CleanupSystemConn(t, newNS)
nft.conn = conn
@ -68,6 +70,8 @@ func TestChains(t *testing.T) {
// 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) {
skipIfNotPrivileged(t)
if err := nft.addInterceptionTables(); err != nil {
t.Errorf("Error adding interception tables: %s", err)
}

View file

@ -1,6 +1,7 @@
package nftables
import (
"os"
"runtime"
"testing"
@ -20,6 +21,12 @@ func init() {
initMapsStore()
}
func skipIfNotPrivileged(t *testing.T) {
if os.Getenv("PRIVILEGED_TESTS") == "" {
t.Skip("Set PRIVILEGED_TESTS to 1 to launch these tests, and launch them as root, or as a user allowed to create new namespaces.")
}
}
// https://github.com/google/nftables/blob/8f2d395e1089dea4966c483fbeae7e336917c095/internal/nftest/system_conn.go#L15
func OpenSystemConn(t *testing.T) (*nftables.Conn, netns.NsHandle) {
t.Helper()
@ -66,6 +73,8 @@ func tableExists(t *testing.T, origtbl *nftables.Table, family string) bool {
}
func TestAddTable(t *testing.T) {
skipIfNotPrivileged(t)
conn, newNS = OpenSystemConn(t)
defer CleanupSystemConn(t, newNS)
nft.conn = conn
@ -119,6 +128,8 @@ func TestAddTable(t *testing.T) {
// 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) {
skipIfNotPrivileged(t)
conn, newNS = OpenSystemConn(t)
defer CleanupSystemConn(t, newNS)
nft.conn = conn

View file

@ -0,0 +1,220 @@
package nftables
import (
"testing"
"github.com/evilsocket/opensnitch/daemon/firewall/nftables/exprs"
"github.com/google/nftables"
)
type chainPrioT struct {
test string
errorReason string
family string
chain string
hook string
checkEqual bool
chainPrio *nftables.ChainPriority
chainType nftables.ChainType
}
// TestGetConntrackPriority test basic Conntrack chains priority configurations.
// https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks#Priority_within_hook
func TestGetConntrackPriority(t *testing.T) {
t.Run("hook-prerouting", func(t *testing.T) {
cprio, ctype := getConntrackPriority(exprs.NFT_HOOK_PREROUTING)
if cprio != nftables.ChainPriorityConntrack && ctype != nftables.ChainTypeFilter {
t.Errorf("invalid conntrack priority or type for hook PREROUTING: %+v, %+v", cprio, ctype)
}
})
t.Run("hook-output", func(t *testing.T) {
cprio, ctype := getConntrackPriority(exprs.NFT_HOOK_OUTPUT)
if cprio != nftables.ChainPriorityNATSource && ctype != nftables.ChainTypeFilter {
t.Errorf("invalid conntrack priority or type for hook OUTPUT: %+v, %+v", cprio, ctype)
}
})
t.Run("hook-postrouting", func(t *testing.T) {
cprio, ctype := getConntrackPriority(exprs.NFT_HOOK_POSTROUTING)
if cprio != nftables.ChainPriorityConntrackHelper && ctype != nftables.ChainTypeNAT {
t.Errorf("invalid conntrack priority or type for hook POSTROUTING: %+v, %+v", cprio, ctype)
}
})
t.Run("hook-input", func(t *testing.T) {
cprio, ctype := getConntrackPriority(exprs.NFT_HOOK_INPUT)
if cprio != nftables.ChainPriorityConntrackConfirm && ctype != nftables.ChainTypeFilter {
t.Errorf("invalid conntrack priority or type for hook INPUT: %+v, %+v", cprio, ctype)
}
})
}
// https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks#Priority_within_hook
// https://github.com/google/nftables/blob/master/chain.go#L48
// man nft (table 6.)
func TestGetChainPriority(t *testing.T) {
matrixTests := []chainPrioT{
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_types
// (...) equivalent semantics to the mangle table but only for the output hook (for other hooks use type filter instead).
// Despite of what is said on the wiki, mangle chains must be of filter type,
// otherwise on some kernels (4.19.x) table MANGLE hook OUTPUT chain is not created
{
"inet-mangle-output",
"invalid MANGLE chain priority or type: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_INET, exprs.NFT_CHAIN_MANGLE, exprs.NFT_HOOK_OUTPUT,
true,
nftables.ChainPriorityMangle, nftables.ChainTypeFilter,
},
{
"inet-natdest-output",
"invalid NATDest-output chain priority or type: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_INET, exprs.NFT_CHAIN_NATDEST, exprs.NFT_HOOK_OUTPUT,
true,
nftables.ChainPriorityNATSource, nftables.ChainTypeNAT,
},
{
"inet-natdest-prerouting",
"invalid NATDest-prerouting chain priority or type: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_INET, exprs.NFT_CHAIN_NATDEST, exprs.NFT_HOOK_PREROUTING,
true,
nftables.ChainPriorityNATDest, nftables.ChainTypeNAT,
},
{
"inet-natsource-postrouting",
"invalid NATSource-postrouting chain priority or type: %+v-%+v, %v-%v",
exprs.NFT_FAMILY_INET, exprs.NFT_CHAIN_NATSOURCE, exprs.NFT_HOOK_POSTROUTING,
true,
nftables.ChainPriorityNATSource, nftables.ChainTypeNAT,
},
// constraints
// https://www.netfilter.org/projects/nftables/manpage.html#lbAQ
{
"inet-natdest-forward",
"invalid natdest-forward chain: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_INET, exprs.NFT_CHAIN_NATDEST, exprs.NFT_HOOK_FORWARD,
true,
nil, nftables.ChainTypeFilter,
},
{
"inet-natsource-forward",
"invalid natsource-forward chain: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_INET, exprs.NFT_CHAIN_NATSOURCE, exprs.NFT_HOOK_FORWARD,
true,
nil, nftables.ChainTypeFilter,
},
{
"netdev-filter-ingress",
"invalid netdev chain prio or type: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_NETDEV, exprs.NFT_CHAIN_FILTER, exprs.NFT_HOOK_INGRESS,
true,
nftables.ChainPriorityFilter, nftables.ChainTypeFilter,
},
{
"arp-filter-input",
"invalid arp chain prio or type: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_ARP, exprs.NFT_CHAIN_FILTER, exprs.NFT_HOOK_INPUT,
true,
nftables.ChainPriorityFilter, nftables.ChainTypeFilter,
},
{
"bridge-filter-prerouting",
"invalid bridge-prerouting chain prio or type: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_BRIDGE, exprs.NFT_CHAIN_FILTER, exprs.NFT_HOOK_PREROUTING,
true,
nftables.ChainPriorityRaw, nftables.ChainTypeFilter,
},
{
"bridge-filter-output",
"invalid bridge-output chain prio or type: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_BRIDGE, exprs.NFT_CHAIN_FILTER, exprs.NFT_HOOK_OUTPUT,
true,
nftables.ChainPriorityNATSource, nftables.ChainTypeFilter,
},
{
"bridge-filter-postrouting",
"invalid bridge-postrouting chain prio or type: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_BRIDGE, exprs.NFT_CHAIN_FILTER, exprs.NFT_HOOK_POSTROUTING,
true,
nftables.ChainPriorityConntrackHelper, nftables.ChainTypeFilter,
},
}
for _, testChainPrio := range matrixTests {
t.Run(testChainPrio.test, func(t *testing.T) {
chainPrio, chainType := getChainPriority(testChainPrio.family, testChainPrio.chain, testChainPrio.hook)
if testChainPrio.checkEqual {
if chainPrio != testChainPrio.chainPrio && chainType != testChainPrio.chainType {
t.Errorf(testChainPrio.errorReason, chainPrio, chainType, testChainPrio.chainPrio, testChainPrio.chainType)
}
} else {
if chainPrio == testChainPrio.chainPrio && chainType == testChainPrio.chainType {
t.Errorf(testChainPrio.errorReason, chainPrio, chainType, testChainPrio.chainPrio, testChainPrio.chainType)
}
}
})
}
}
func TestInvalidChainPriority(t *testing.T) {
matrixTests := []chainPrioT{
{
"inet-natdest-forward",
"natdest-forward chain should be invalid: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_INET, exprs.NFT_CHAIN_NATDEST, exprs.NFT_HOOK_FORWARD,
true,
nil, nftables.ChainTypeFilter,
},
{
"inet-natsource-forward",
"natsource-forward chain should be invalid: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_INET, exprs.NFT_CHAIN_NATSOURCE, exprs.NFT_HOOK_FORWARD,
true,
nil, nftables.ChainTypeFilter,
},
{
"netdev-natsource-forward",
"netdev chain should be invalid: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_NETDEV, exprs.NFT_CHAIN_NATSOURCE, exprs.NFT_HOOK_FORWARD,
true,
nil,
nftables.ChainTypeFilter,
},
{
"arp-natsource-forward",
"arp chain should be invalid: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_ARP, exprs.NFT_CHAIN_NATSOURCE, exprs.NFT_HOOK_FORWARD,
true,
nil, nftables.ChainTypeFilter,
},
{
"bridge-natsource-forward",
"bridge chain should be invalid: %+v-%+v <-> %v-%v",
exprs.NFT_FAMILY_ARP, exprs.NFT_CHAIN_NATSOURCE, exprs.NFT_HOOK_FORWARD,
true,
nil, nftables.ChainTypeFilter,
},
}
for _, testChainPrio := range matrixTests {
t.Run(testChainPrio.test, func(t *testing.T) {
chainPrio, chainType := getChainPriority(testChainPrio.family, testChainPrio.chain, testChainPrio.hook)
if testChainPrio.checkEqual {
if chainPrio != testChainPrio.chainPrio && chainType != testChainPrio.chainType {
}
} else {
if chainPrio == testChainPrio.chainPrio && chainType == testChainPrio.chainType {
t.Errorf(testChainPrio.errorReason, chainPrio, chainType, testChainPrio.chainPrio, testChainPrio.chainType)
}
}
})
}
}