Home | History | Annotate | Line # | Download | only in libnpftest
npf_rule_test.c revision 1.11
      1 /*	$NetBSD: npf_rule_test.c,v 1.11 2014/07/20 00:37:41 rmind Exp $	*/
      2 
      3 /*
      4  * NPF ruleset test.
      5  *
      6  * Public Domain.
      7  */
      8 
      9 #include <sys/types.h>
     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 struct mbuf *
     59 fill_packet(const struct test_case *t)
     60 {
     61 	struct mbuf *m;
     62 	struct ip *ip;
     63 	struct udphdr *uh;
     64 
     65 	m = mbuf_construct(IPPROTO_UDP);
     66 	uh = mbuf_return_hdrs(m, false, &ip);
     67 	ip->ip_src.s_addr = inet_addr(t->src);
     68 	ip->ip_dst.s_addr = inet_addr(t->dst);
     69 	uh->uh_sport = htons(9000);
     70 	uh->uh_dport = htons(9000);
     71 	return m;
     72 }
     73 
     74 static int
     75 npf_rule_raw_test(bool verbose, struct mbuf *m, ifnet_t *ifp, int di)
     76 {
     77 	npf_cache_t npc = { .npc_info = 0 };
     78 	nbuf_t nbuf;
     79 	npf_rule_t *rl;
     80 	int retfl, error;
     81 
     82 	nbuf_init(&nbuf, m, ifp);
     83 	npc.npc_nbuf = &nbuf;
     84 	npf_cache_all(&npc);
     85 
     86 	int slock = npf_config_read_enter();
     87 	rl = npf_ruleset_inspect(&npc, npf_config_ruleset(),
     88 	    di, NPF_LAYER_3);
     89 	if (rl) {
     90 		error = npf_rule_conclude(rl, &retfl);
     91 	} else {
     92 		error = ENOENT;
     93 	}
     94 	npf_config_read_exit(slock);
     95 	return error;
     96 }
     97 
     98 static int
     99 npf_test_case(u_int i, bool verbose)
    100 {
    101 	const struct test_case *t = &test_cases[i];
    102 	ifnet_t *ifp = ifunit(t->ifname);
    103 	int error;
    104 
    105 	struct mbuf *m = fill_packet(t);
    106 	error = npf_rule_raw_test(verbose, m, ifp, t->di);
    107 	m_freem(m);
    108 	return error;
    109 }
    110 
    111 static npf_rule_t *
    112 npf_blockall_rule(void)
    113 {
    114 	prop_dictionary_t rldict;
    115 
    116 	rldict = prop_dictionary_create();
    117 	prop_dictionary_set_uint32(rldict, "attributes",
    118 	    NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC);
    119 	return npf_rule_alloc(rldict);
    120 }
    121 
    122 bool
    123 npf_rule_test(bool verbose)
    124 {
    125 	npf_ruleset_t *rlset;
    126 	npf_rule_t *rl;
    127 	bool fail = false;
    128 	uint64_t id;
    129 	int error;
    130 
    131 	for (unsigned i = 0; i < __arraycount(test_cases); i++) {
    132 		const struct test_case *t = &test_cases[i];
    133 		ifnet_t *ifp = ifunit(t->ifname);
    134 		int serror;
    135 
    136 		if (ifp == NULL) {
    137 			printf("Interface %s is not configured.\n", t->ifname);
    138 			return false;
    139 		}
    140 
    141 		struct mbuf *m = fill_packet(t);
    142 		error = npf_rule_raw_test(verbose, m, ifp, t->di);
    143 		serror = npf_packet_handler(NULL, &m, ifp, t->di);
    144 
    145 		if (m) {
    146 			m_freem(m);
    147 		}
    148 
    149 		if (verbose) {
    150 			printf("Rule test %d, expected %d (stateful) and %d \n"
    151 			    "-> returned %d and %d.\n",
    152 			    i + 1, t->stateful_ret, t->ret, serror, error);
    153 		}
    154 		fail |= (serror != t->stateful_ret || error != t->ret);
    155 	}
    156 
    157 	/*
    158 	 * Test dynamic NPF rules.
    159 	 */
    160 
    161 	error = npf_test_case(0, verbose);
    162 	assert(error == RESULT_PASS);
    163 
    164 	npf_config_enter();
    165 	rlset = npf_config_ruleset();
    166 
    167 	rl = npf_blockall_rule();
    168 	error = npf_ruleset_add(rlset, "test-rules", rl);
    169 	fail |= error != 0;
    170 
    171 	error = npf_test_case(0, verbose);
    172 	fail |= (error != RESULT_BLOCK);
    173 
    174 	id = npf_rule_getid(rl);
    175 	error = npf_ruleset_remove(rlset, "test-rules", id);
    176 	fail |= error != 0;
    177 
    178 	npf_config_exit();
    179 
    180 	error = npf_test_case(0, verbose);
    181 	fail |= (error != RESULT_PASS);
    182 
    183 	return !fail;
    184 }
    185