Home | History | Annotate | Line # | Download | only in libnpftest
npf_rule_test.c revision 1.22
      1 /*
      2  * NPF ruleset tests.
      3  *
      4  * Public Domain.
      5  */
      6 
      7 #ifdef _KERNEL
      8 #include <sys/types.h>
      9 #endif
     10 
     11 #include "npf_impl.h"
     12 #include "npf_test.h"
     13 
     14 #define	RESULT_PASS	0
     15 #define	RESULT_BLOCK	ENETUNREACH
     16 
     17 static const struct test_case {
     18 	int		af;
     19 	const char *	src;
     20 	const char *	dst;
     21 	const char *	ifname;
     22 	int		di;
     23 	int		stateful_ret;
     24 	int		ret;
     25 } test_cases[] = {
     26 
     27 	/* Stateful pass. */
     28 	{
     29 		.af = AF_INET,
     30 		.src = "10.1.1.1",		.dst = "10.1.1.2",
     31 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
     32 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
     33 	},
     34 	{
     35 		.af = AF_INET,
     36 		.src = "10.1.1.2",		.dst = "10.1.1.1",
     37 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     38 		.stateful_ret = RESULT_PASS,	.ret = RESULT_BLOCK
     39 	},
     40 
     41 	/* Pass forwards stream only. */
     42 	{
     43 		.af = AF_INET,
     44 		.src = "10.1.1.1",		.dst = "10.1.1.3",
     45 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
     46 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
     47 	},
     48 	{
     49 		.af = AF_INET,
     50 		.src = "10.1.1.3",		.dst = "10.1.1.1",
     51 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     52 		.stateful_ret = RESULT_BLOCK,	.ret = RESULT_BLOCK
     53 	},
     54 
     55 	/*
     56 	 * Pass in any of the { fe80::1, fe80::2 } group.
     57 	 */
     58 	{
     59 		.af = AF_INET6,
     60 		.src = "fe80::1", .dst = "fe80::adec:c91c:d116:7592",
     61 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     62 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
     63 	},
     64 	{
     65 		.af = AF_INET6,
     66 		.src = "fe80::2", .dst = "fe80::adec:c91c:d116:7592",
     67 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     68 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
     69 	},
     70 	{
     71 		.af = AF_INET6,
     72 		.src = "fe80::3", .dst = "fe80::adec:c91c:d116:7592",
     73 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     74 		.stateful_ret = RESULT_BLOCK,	.ret = RESULT_BLOCK
     75 	},
     76 
     77 	/*
     78 	 * Pass in anything _not_ in the group { fe80::1, fe80::2 }, as
     79 	 * long as it is to that group.
     80 	 */
     81 	{
     82 		.af = AF_INET6,
     83 		.src = "fe80::adec:c91c:d116:7592", .dst = "fe80::1",
     84 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     85 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
     86 	},
     87 	{
     88 		.af = AF_INET6,
     89 		.src = "fe80::adec:c91c:d116:7592", .dst = "fe80::2",
     90 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     91 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
     92 	},
     93 	{
     94 		.af = AF_INET6,
     95 		.src = "fe80::adec:c91c:d116:7592", .dst = "fe80::3",
     96 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     97 		.stateful_ret = RESULT_BLOCK,	.ret = RESULT_BLOCK
     98 	},
     99 
    100 	/* Block. */
    101 	{
    102 		.af = AF_INET,
    103 		.src = "10.1.1.1",		.dst = "10.1.1.4",
    104 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
    105 		.stateful_ret = RESULT_BLOCK,	.ret = RESULT_BLOCK
    106 	},
    107 
    108 };
    109 
    110 static int
    111 run_raw_testcase(unsigned i)
    112 {
    113 	const struct test_case *t = &test_cases[i];
    114 	npf_t *npf = npf_getkernctx();
    115 	npf_cache_t *npc;
    116 	struct mbuf *m;
    117 	npf_rule_t *rl;
    118 	int slock, error;
    119 
    120 	m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, 9000, 9000);
    121 	npc = get_cached_pkt(m, t->ifname);
    122 
    123 	slock = npf_config_read_enter(npf);
    124 	rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_LAYER_3);
    125 	if (rl) {
    126 		npf_match_info_t mi;
    127 		error = npf_rule_conclude(rl, &mi);
    128 	} else {
    129 		error = ENOENT;
    130 	}
    131 	npf_config_read_exit(npf, slock);
    132 
    133 	put_cached_pkt(npc);
    134 	return error;
    135 }
    136 
    137 static int
    138 run_handler_testcase(unsigned i)
    139 {
    140 	const struct test_case *t = &test_cases[i];
    141 	ifnet_t *ifp = npf_test_getif(t->ifname);
    142 	npf_t *npf = npf_getkernctx();
    143 	struct mbuf *m;
    144 	int error;
    145 
    146 	m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, 9000, 9000);
    147 	error = npfk_packet_handler(npf, &m, ifp, t->di);
    148 	if (m) {
    149 		m_freem(m);
    150 	}
    151 	return error;
    152 }
    153 
    154 static npf_rule_t *
    155 npf_blockall_rule(void)
    156 {
    157 	npf_t *npf = npf_getkernctx();
    158 	nvlist_t *rule = nvlist_create(0);
    159 	npf_rule_t *rl;
    160 
    161 	nvlist_add_number(rule, "attr",
    162 	    NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC);
    163 	rl = npf_rule_alloc(npf, rule);
    164 	nvlist_destroy(rule);
    165 	return rl;
    166 }
    167 
    168 static bool
    169 test_static(bool verbose)
    170 {
    171 	for (unsigned i = 0; i < __arraycount(test_cases); i++) {
    172 		const struct test_case *t = &test_cases[i];
    173 		int error, serror;
    174 
    175 		if (npf_test_getif(t->ifname) == NULL) {
    176 			printf("Interface %s is not configured.\n", t->ifname);
    177 			return false;
    178 		}
    179 
    180 		error = run_raw_testcase(i);
    181 		serror = run_handler_testcase(i);
    182 
    183 		if (verbose) {
    184 			printf("rule test %d:\texpected %d (stateful) and %d\n"
    185 			    "\t\t-> returned %d and %d\n",
    186 			    i + 1, t->stateful_ret, t->ret, serror, error);
    187 		}
    188 		CHECK_TRUE(error == t->ret);
    189 		CHECK_TRUE(serror == t->stateful_ret)
    190 	}
    191 	return true;
    192 }
    193 
    194 static bool
    195 test_dynamic(void)
    196 {
    197 	npf_t *npf = npf_getkernctx();
    198 	npf_ruleset_t *rlset;
    199 	npf_rule_t *rl;
    200 	uint64_t id;
    201 	int error;
    202 
    203 	/*
    204 	 * Test dynamic NPF rules.
    205 	 */
    206 
    207 	error = run_raw_testcase(0);
    208 	CHECK_TRUE(error == RESULT_PASS);
    209 
    210 	npf_config_enter(npf);
    211 	rlset = npf_config_ruleset(npf);
    212 
    213 	rl = npf_blockall_rule();
    214 	error = npf_ruleset_add(rlset, "test-rules", rl);
    215 	CHECK_TRUE(error == 0);
    216 
    217 	error = run_raw_testcase(0);
    218 	CHECK_TRUE(error == RESULT_BLOCK);
    219 
    220 	id = npf_rule_getid(rl);
    221 	error = npf_ruleset_remove(rlset, "test-rules", id);
    222 	CHECK_TRUE(error == 0);
    223 
    224 	npf_config_exit(npf);
    225 
    226 	error = run_raw_testcase(0);
    227 	CHECK_TRUE(error == RESULT_PASS);
    228 
    229 	return true;
    230 }
    231 
    232 bool
    233 npf_rule_test(bool verbose)
    234 {
    235 	bool ok;
    236 
    237 	ok = test_static(verbose);
    238 	CHECK_TRUE(ok);
    239 
    240 	ok = test_dynamic();
    241 	CHECK_TRUE(ok);
    242 
    243 	return true;
    244 }
    245