Home | History | Annotate | Line # | Download | only in libnpftest
      1 /*
      2  * NPF layer 2 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 	uint16_t    etype;
     21 	const char *ifname;
     22 	int	    di;
     23 	int	    ret;
     24 } test_cases[] = {
     25 	{
     26 		/* pass ether in final from $mac1 to $mac2 type $E_IPv6 */
     27 		.src = "00:00:5E:00:53:00",	.dst = "00:00:5E:00:53:01",
     28 		.ifname = IFNAME_INT,		.etype = ETHERTYPE_IPV6,
     29 		.di = PFIL_IN,			.ret = RESULT_PASS
     30 	},
     31 	{
     32 		/* block ether in final from $mac2 */
     33 		.src = "00:00:5E:00:53:01",	.dst = "00:00:5E:00:53:02",
     34 		.ifname = IFNAME_INT,		.etype = ETHERTYPE_IP,
     35 		.di = PFIL_IN,			.ret = RESULT_BLOCK
     36 	},
     37 
     38 		/* pass ether out final to $mac3 $Apple talk */
     39 	{
     40 		.src = "00:00:5E:00:53:00",	.dst = "00:00:5E:00:53:02",
     41 		.ifname = IFNAME_INT,		.etype = ETHERTYPE_ATALK,
     42 		.di = PFIL_OUT,			.ret = RESULT_PASS
     43 	},
     44 	{
     45 		/* goto default: block all (since direction is not matching ) */
     46 		.src = "00:00:5E:00:53:00",	.dst = "00:00:5E:00:53:02",
     47 		.ifname = IFNAME_INT,		.etype = ETHERTYPE_IP,
     48 		.di = PFIL_IN,			.ret = RESULT_BLOCK
     49 	},
     50 	{
     51 		/* pass from nested options : 03 */
     52 		.src = "00:00:5E:00:53:03",	.dst = "00:00:5E:00:53:5A",
     53 		.ifname = IFNAME_INT,		.etype = ETHERTYPE_IP,
     54 		.di = PFIL_IN,			.ret = RESULT_PASS
     55 	},
     56 	{
     57 		/* pass from nested options : 04 */
     58 		.src = "00:00:5E:00:53:04",	.dst = "00:00:5E:00:53:5A",
     59 		.ifname = IFNAME_INT,		.etype = ETHERTYPE_IP,
     60 		.di = PFIL_IN,			.ret = RESULT_PASS
     61 	},
     62 	{
     63 		/* pass from nested options : 04 */
     64 		.src = "00:00:5E:00:53:05",	.dst = "00:00:5E:00:53:5A",
     65 		.ifname = IFNAME_INT,		.etype = ETHERTYPE_IP,
     66 		.di = PFIL_IN,			.ret = RESULT_PASS
     67 	},
     68 };
     69 
     70 static int
     71 run_raw_testcase(unsigned i)
     72 {
     73 	const struct test_case *t = &test_cases[i];
     74 	npf_t *npf = npf_getkernctx();
     75 	npf_cache_t *npc;
     76 	struct mbuf *m;
     77 	npf_rule_t *rl;
     78 	int slock, error;
     79 
     80 	m = mbuf_get_frame(t->src, t->dst, htons(t->etype));
     81 	npc = get_cached_pkt(m, t->ifname, NPF_RULE_LAYER_2);
     82 
     83 	slock = npf_config_read_enter(npf);
     84 	rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_RULE_LAYER_2);
     85 	if (rl) {
     86 		npf_match_info_t mi;
     87 		error = npf_rule_conclude(rl, &mi);
     88 	} else {
     89 		error = ENOENT;
     90 	}
     91 	npf_config_read_exit(npf, slock);
     92 
     93 	put_cached_pkt(npc);
     94 	return error;
     95 }
     96 
     97 /* for dynamic testing */
     98 static int
     99 run_handler_testcase(unsigned i)
    100 {
    101 	const struct test_case *t = &test_cases[i];
    102 	ifnet_t *ifp = npf_test_getif(t->ifname);
    103 	npf_t *npf = npf_getkernctx();
    104 	struct mbuf *m;
    105 	int error;
    106 
    107 	m = mbuf_get_frame(t->src, t->dst, htons(t->etype));
    108 	error = npfk_layer2_handler(npf, &m, ifp, t->di);
    109 	if (m) {
    110 		m_freem(m);
    111 	}
    112 	return error;
    113 }
    114 
    115 static npf_rule_t *
    116 npf_blockall_rule(void)
    117 {
    118 	npf_t *npf = npf_getkernctx();
    119 	nvlist_t *rule = nvlist_create(0);
    120 	npf_rule_t *rl;
    121 
    122 	nvlist_add_number(rule, "attr",
    123 		NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC | NPF_RULE_LAYER_2);
    124 	rl = npf_rule_alloc(npf, rule);
    125 	nvlist_destroy(rule);
    126 	return rl;
    127 }
    128 
    129 static bool
    130 test_static(bool verbose)
    131 {
    132 	for (unsigned i = 0; i < __arraycount(test_cases); i++) {
    133 		const struct test_case *t = &test_cases[i];
    134 		int error;
    135 
    136 		if (npf_test_getif(t->ifname) == NULL) {
    137 			printf("Interface %s is not configured.\n", t->ifname);
    138 			return false;
    139 		}
    140 
    141 		error = run_handler_testcase(i);
    142 
    143 		if (verbose) {
    144 			printf("rule test %d:\texpected %d\n"
    145 				"\t\t-> returned %d\n",
    146 				i + 1, t->ret, error);
    147 		}
    148 		CHECK_TRUE(error == t->ret);
    149 	}
    150 	return true;
    151 }
    152 
    153 static bool
    154 test_dynamic(void)
    155 {
    156 	npf_t *npf = npf_getkernctx();
    157 	npf_ruleset_t *rlset;
    158 	npf_rule_t *rl;
    159 	uint64_t id;
    160 	int error;
    161 
    162 	/*
    163 	* Test dynamic NPF rules.
    164 	*/
    165 
    166 	error = run_raw_testcase(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, "l2-ruleset", rl);
    174 	CHECK_TRUE(error == 0);
    175 
    176 	error = run_raw_testcase(0);
    177 	CHECK_TRUE(error == RESULT_BLOCK);
    178 
    179 	id = npf_rule_getid(rl);
    180 	error = npf_ruleset_remove(rlset, "l2-ruleset", id);
    181 	CHECK_TRUE(error == 0);
    182 
    183 	npf_config_exit(npf);
    184 
    185 	error = run_raw_testcase(0);
    186 	CHECK_TRUE(error == RESULT_PASS);
    187 
    188 	return true;
    189 }
    190 
    191 bool
    192 npf_layer2_rule_test(bool verbose)
    193 {
    194 	bool ok;
    195 
    196 	ok = test_static(verbose);
    197 	CHECK_TRUE(ok);
    198 
    199 	ok = test_dynamic();
    200 	CHECK_TRUE(ok);
    201 
    202 	return true;
    203 }
    204