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