2015-10-15 10:25:28 +02:00

185 lines
3.7 KiB
C

/* $NetBSD: npf_rule_test.c,v 1.12 2014/08/10 19:09:43 rmind Exp $ */
/*
* NPF ruleset test.
*
* Public Domain.
*/
#include <sys/types.h>
#include "npf_impl.h"
#include "npf_test.h"
#define RESULT_PASS 0
#define RESULT_BLOCK ENETUNREACH
static const struct test_case {
const char * src;
const char * dst;
const char * ifname;
int di;
int stateful_ret;
int ret;
} test_cases[] = {
/* Stateful pass. */
{
.src = "10.1.1.1", .dst = "10.1.1.2",
.ifname = IFNAME_INT, .di = PFIL_OUT,
.stateful_ret = RESULT_PASS, .ret = RESULT_PASS
},
{
.src = "10.1.1.2", .dst = "10.1.1.1",
.ifname = IFNAME_INT, .di = PFIL_IN,
.stateful_ret = RESULT_PASS, .ret = RESULT_BLOCK
},
/* Pass forwards stream only. */
{
.src = "10.1.1.1", .dst = "10.1.1.3",
.ifname = IFNAME_INT, .di = PFIL_OUT,
.stateful_ret = RESULT_PASS, .ret = RESULT_PASS
},
{
.src = "10.1.1.3", .dst = "10.1.1.1",
.ifname = IFNAME_INT, .di = PFIL_IN,
.stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK
},
/* Block. */
{ .src = "10.1.1.1", .dst = "10.1.1.4",
.ifname = IFNAME_INT, .di = PFIL_OUT,
.stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK
},
};
static struct mbuf *
fill_packet(const struct test_case *t)
{
struct mbuf *m;
struct ip *ip;
struct udphdr *uh;
m = mbuf_construct(IPPROTO_UDP);
uh = mbuf_return_hdrs(m, false, &ip);
ip->ip_src.s_addr = inet_addr(t->src);
ip->ip_dst.s_addr = inet_addr(t->dst);
uh->uh_sport = htons(9000);
uh->uh_dport = htons(9000);
return m;
}
static int
npf_rule_raw_test(bool verbose, struct mbuf *m, ifnet_t *ifp, int di)
{
npf_cache_t npc = { .npc_info = 0 };
nbuf_t nbuf;
npf_rule_t *rl;
int retfl, error;
nbuf_init(&nbuf, m, ifp);
npc.npc_nbuf = &nbuf;
npf_cache_all(&npc);
int slock = npf_config_read_enter();
rl = npf_ruleset_inspect(&npc, npf_config_ruleset(),
di, NPF_LAYER_3);
if (rl) {
error = npf_rule_conclude(rl, &retfl);
} else {
error = ENOENT;
}
npf_config_read_exit(slock);
return error;
}
static int
npf_test_case(u_int i, bool verbose)
{
const struct test_case *t = &test_cases[i];
ifnet_t *ifp = ifunit(t->ifname);
int error;
struct mbuf *m = fill_packet(t);
error = npf_rule_raw_test(verbose, m, ifp, t->di);
m_freem(m);
return error;
}
static npf_rule_t *
npf_blockall_rule(void)
{
prop_dictionary_t rldict;
rldict = prop_dictionary_create();
prop_dictionary_set_uint32(rldict, "attr",
NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC);
return npf_rule_alloc(rldict);
}
bool
npf_rule_test(bool verbose)
{
npf_ruleset_t *rlset;
npf_rule_t *rl;
bool fail = false;
uint64_t id;
int error;
for (unsigned i = 0; i < __arraycount(test_cases); i++) {
const struct test_case *t = &test_cases[i];
ifnet_t *ifp = ifunit(t->ifname);
int serror;
if (ifp == NULL) {
printf("Interface %s is not configured.\n", t->ifname);
return false;
}
struct mbuf *m = fill_packet(t);
error = npf_rule_raw_test(verbose, m, ifp, t->di);
serror = npf_packet_handler(NULL, &m, ifp, t->di);
if (m) {
m_freem(m);
}
if (verbose) {
printf("Rule test %d, expected %d (stateful) and %d \n"
"-> returned %d and %d.\n",
i + 1, t->stateful_ret, t->ret, serror, error);
}
fail |= (serror != t->stateful_ret || error != t->ret);
}
/*
* Test dynamic NPF rules.
*/
error = npf_test_case(0, verbose);
assert(error == RESULT_PASS);
npf_config_enter();
rlset = npf_config_ruleset();
rl = npf_blockall_rule();
error = npf_ruleset_add(rlset, "test-rules", rl);
fail |= error != 0;
error = npf_test_case(0, verbose);
fail |= (error != RESULT_BLOCK);
id = npf_rule_getid(rl);
error = npf_ruleset_remove(rlset, "test-rules", id);
fail |= error != 0;
npf_config_exit();
error = npf_test_case(0, verbose);
fail |= (error != RESULT_PASS);
return !fail;
}