Home | History | Annotate | Line # | Download | only in libnpftest
npf_rule_test.c revision 1.17
      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 	const char *	src;
     19 	const char *	dst;
     20 	const char *	ifname;
     21 	int		di;
     22 	int		stateful_ret;
     23 	int		ret;
     24 } test_cases[] = {
     25 
     26 	/* Stateful pass. */
     27 	{
     28 		.src = "10.1.1.1",		.dst = "10.1.1.2",
     29 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
     30 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
     31 	},
     32 	{
     33 		.src = "10.1.1.2",		.dst = "10.1.1.1",
     34 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     35 		.stateful_ret = RESULT_PASS,	.ret = RESULT_BLOCK
     36 	},
     37 
     38 	/* Pass forwards stream only. */
     39 	{
     40 		.src = "10.1.1.1",		.dst = "10.1.1.3",
     41 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
     42 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
     43 	},
     44 	{
     45 		.src = "10.1.1.3",		.dst = "10.1.1.1",
     46 		.ifname = IFNAME_INT,		.di = PFIL_IN,
     47 		.stateful_ret = RESULT_BLOCK,	.ret = RESULT_BLOCK
     48 	},
     49 
     50 	/* Block. */
     51 	{	.src = "10.1.1.1",		.dst = "10.1.1.4",
     52 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
     53 		.stateful_ret = RESULT_BLOCK,	.ret = RESULT_BLOCK
     54 	},
     55 
     56 };
     57 
     58 static int
     59 run_raw_testcase(unsigned i)
     60 {
     61 	const struct test_case *t = &test_cases[i];
     62 	npf_t *npf = npf_getkernctx();
     63 	npf_cache_t *npc;
     64 	struct mbuf *m;
     65 	npf_rule_t *rl;
     66 	int slock, error;
     67 
     68 	m = mbuf_get_pkt(AF_INET, IPPROTO_UDP, t->src, t->dst, 9000, 9000);
     69 	npc = get_cached_pkt(m, t->ifname);
     70 
     71 	slock = npf_config_read_enter();
     72 	rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_LAYER_3);
     73 	if (rl) {
     74 		npf_match_info_t mi;
     75 		error = npf_rule_conclude(rl, &mi);
     76 	} else {
     77 		error = ENOENT;
     78 	}
     79 	npf_config_read_exit(slock);
     80 
     81 	put_cached_pkt(npc);
     82 	return error;
     83 }
     84 
     85 static int
     86 run_handler_testcase(unsigned i)
     87 {
     88 	const struct test_case *t = &test_cases[i];
     89 	ifnet_t *ifp = npf_test_getif(t->ifname);
     90 	npf_t *npf = npf_getkernctx();
     91 	struct mbuf *m;
     92 	int error;
     93 
     94 	m = mbuf_get_pkt(AF_INET, IPPROTO_UDP, t->src, t->dst, 9000, 9000);
     95 	error = npf_packet_handler(npf, &m, ifp, t->di);
     96 	if (m) {
     97 		m_freem(m);
     98 	}
     99 	return error;
    100 }
    101 
    102 static npf_rule_t *
    103 npf_blockall_rule(void)
    104 {
    105 	npf_t *npf = npf_getkernctx();
    106 	nvlist_t *rule = nvlist_create(0);
    107 	npf_rule_t *rl;
    108 
    109 	nvlist_add_number(rule, "attr",
    110 	    NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC);
    111 	rl = npf_rule_alloc(npf, rule);
    112 	nvlist_destroy(rule);
    113 	return rl;
    114 }
    115 
    116 static bool
    117 test_static(bool verbose)
    118 {
    119 	for (unsigned i = 0; i < __arraycount(test_cases); i++) {
    120 		const struct test_case *t = &test_cases[i];
    121 		int error, serror;
    122 
    123 		if (npf_test_getif(t->ifname) == NULL) {
    124 			printf("Interface %s is not configured.\n", t->ifname);
    125 			return false;
    126 		}
    127 
    128 		error = run_raw_testcase(i);
    129 		serror = run_handler_testcase(i);
    130 
    131 		if (verbose) {
    132 			printf("rule test %d:\texpected %d (stateful) and %d\n"
    133 			    "\t\t-> returned %d and %d\n",
    134 			    i + 1, t->stateful_ret, t->ret, serror, error);
    135 		}
    136 		CHECK_TRUE(error == t->ret);
    137 		CHECK_TRUE(serror == t->stateful_ret)
    138 	}
    139 	return true;
    140 }
    141 
    142 static bool
    143 test_dynamic(void)
    144 {
    145 	npf_t *npf = npf_getkernctx();
    146 	npf_ruleset_t *rlset;
    147 	npf_rule_t *rl;
    148 	uint64_t id;
    149 	int error;
    150 
    151 	/*
    152 	 * Test dynamic NPF rules.
    153 	 */
    154 
    155 	error = run_raw_testcase(0);
    156 	CHECK_TRUE(error == RESULT_PASS);
    157 
    158 	npf_config_enter(npf);
    159 	rlset = npf_config_ruleset(npf);
    160 
    161 	rl = npf_blockall_rule();
    162 	error = npf_ruleset_add(rlset, "test-rules", rl);
    163 	CHECK_TRUE(error == 0);
    164 
    165 	error = run_raw_testcase(0);
    166 	CHECK_TRUE(error == RESULT_BLOCK);
    167 
    168 	id = npf_rule_getid(rl);
    169 	error = npf_ruleset_remove(rlset, "test-rules", id);
    170 	CHECK_TRUE(error == 0);
    171 
    172 	npf_config_exit(npf);
    173 
    174 	error = run_raw_testcase(0);
    175 	CHECK_TRUE(error == RESULT_PASS);
    176 
    177 	return true;
    178 }
    179 
    180 bool
    181 npf_rule_test(bool verbose)
    182 {
    183 	bool ok;
    184 
    185 	ok = test_static(verbose);
    186 	CHECK_TRUE(ok);
    187 
    188 	ok = test_dynamic();
    189 	CHECK_TRUE(ok);
    190 
    191 	return true;
    192 }
    193