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