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