Home | History | Annotate | Line # | Download | only in npf
npf_ruleset.c revision 1.7.10.1
      1  1.7.10.1    mrg /*	$NetBSD: npf_ruleset.c,v 1.7.10.1 2012/02/18 07:35:38 mrg Exp $	*/
      2       1.1  rmind 
      3       1.1  rmind /*-
      4  1.7.10.1    mrg  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
      5       1.1  rmind  * All rights reserved.
      6       1.1  rmind  *
      7       1.1  rmind  * This material is based upon work partially supported by The
      8       1.1  rmind  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
      9       1.1  rmind  *
     10       1.1  rmind  * Redistribution and use in source and binary forms, with or without
     11       1.1  rmind  * modification, are permitted provided that the following conditions
     12       1.1  rmind  * are met:
     13       1.1  rmind  * 1. Redistributions of source code must retain the above copyright
     14       1.1  rmind  *    notice, this list of conditions and the following disclaimer.
     15       1.1  rmind  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  rmind  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  rmind  *    documentation and/or other materials provided with the distribution.
     18       1.1  rmind  *
     19       1.1  rmind  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1  rmind  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1  rmind  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1  rmind  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1  rmind  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1  rmind  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1  rmind  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1  rmind  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1  rmind  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1  rmind  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1  rmind  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1  rmind  */
     31       1.1  rmind 
     32       1.1  rmind /*
     33       1.1  rmind  * NPF ruleset module.
     34       1.1  rmind  */
     35       1.1  rmind 
     36       1.1  rmind #include <sys/cdefs.h>
     37  1.7.10.1    mrg __KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.7.10.1 2012/02/18 07:35:38 mrg Exp $");
     38       1.1  rmind 
     39       1.1  rmind #include <sys/param.h>
     40       1.1  rmind #include <sys/kernel.h>
     41       1.1  rmind 
     42       1.1  rmind #include <sys/kmem.h>
     43       1.1  rmind #include <sys/queue.h>
     44       1.1  rmind #include <sys/types.h>
     45       1.1  rmind 
     46       1.3  rmind #include <net/pfil.h>
     47       1.1  rmind #include <net/if.h>
     48       1.1  rmind 
     49       1.1  rmind #include "npf_ncode.h"
     50       1.1  rmind #include "npf_impl.h"
     51       1.1  rmind 
     52       1.4  rmind /* Ruleset structre (queue and default rule). */
     53       1.4  rmind struct npf_ruleset {
     54       1.4  rmind 	TAILQ_HEAD(, npf_rule)	rs_queue;
     55       1.4  rmind 	npf_rule_t *		rs_default;
     56       1.4  rmind };
     57       1.4  rmind 
     58       1.7  rmind #define	NPF_RNAME_LEN		16
     59       1.7  rmind 
     60       1.1  rmind /* Rule structure. */
     61       1.1  rmind struct npf_rule {
     62       1.7  rmind 	/* Rule name (optional) and list entry. */
     63       1.7  rmind 	char			r_name[NPF_RNAME_LEN];
     64       1.4  rmind 	TAILQ_ENTRY(npf_rule)	r_entry;
     65       1.1  rmind 	/* Optional: sub-ruleset, NAT policy. */
     66       1.4  rmind 	npf_ruleset_t		r_subset;
     67       1.4  rmind 	npf_natpolicy_t *	r_natp;
     68       1.1  rmind 	/* Rule priority: (highest) 0, 1, 2 ... n (lowest). */
     69       1.7  rmind 	pri_t			r_priority;
     70       1.1  rmind 	/* N-code to process. */
     71       1.4  rmind 	void *			r_ncode;
     72       1.4  rmind 	size_t			r_nc_size;
     73       1.1  rmind 	/* Attributes of this rule. */
     74       1.4  rmind 	uint32_t		r_attr;
     75       1.1  rmind 	/* Interface. */
     76       1.4  rmind 	u_int			r_ifid;
     77       1.6  rmind 	/* Rule procedure data. */
     78       1.4  rmind 	npf_rproc_t *		r_rproc;
     79       1.1  rmind };
     80       1.1  rmind 
     81       1.1  rmind npf_ruleset_t *
     82       1.1  rmind npf_ruleset_create(void)
     83       1.1  rmind {
     84       1.1  rmind 	npf_ruleset_t *rlset;
     85       1.1  rmind 
     86       1.1  rmind 	rlset = kmem_zalloc(sizeof(npf_ruleset_t), KM_SLEEP);
     87       1.1  rmind 	TAILQ_INIT(&rlset->rs_queue);
     88       1.1  rmind 	return rlset;
     89       1.1  rmind }
     90       1.1  rmind 
     91       1.1  rmind void
     92       1.1  rmind npf_ruleset_destroy(npf_ruleset_t *rlset)
     93       1.1  rmind {
     94       1.1  rmind 	npf_rule_t *rl;
     95       1.1  rmind 
     96       1.1  rmind 	while ((rl = TAILQ_FIRST(&rlset->rs_queue)) != NULL) {
     97       1.1  rmind 		TAILQ_REMOVE(&rlset->rs_queue, rl, r_entry);
     98       1.1  rmind 		npf_rule_free(rl);
     99       1.1  rmind 	}
    100       1.1  rmind 	kmem_free(rlset, sizeof(npf_ruleset_t));
    101       1.1  rmind }
    102       1.1  rmind 
    103       1.1  rmind /*
    104       1.1  rmind  * npf_ruleset_insert: insert the rule into the specified ruleset.
    105       1.1  rmind  *
    106       1.1  rmind  * Note: multiple rules at the same priority are allowed.
    107       1.1  rmind  */
    108       1.1  rmind void
    109       1.1  rmind npf_ruleset_insert(npf_ruleset_t *rlset, npf_rule_t *rl)
    110       1.1  rmind {
    111       1.1  rmind 	npf_rule_t *it;
    112       1.1  rmind 
    113       1.1  rmind 	if (rl->r_attr & NPF_RULE_DEFAULT) {
    114       1.1  rmind 		rlset->rs_default = rl;
    115       1.1  rmind 		return;
    116       1.1  rmind 	}
    117       1.1  rmind 	TAILQ_FOREACH(it, &rlset->rs_queue, r_entry) {
    118       1.1  rmind 		/* Rule priority: (highest) 0, 1, 2, 4 ... n (lowest). */
    119       1.1  rmind 		if (it->r_priority > rl->r_priority)
    120       1.1  rmind 			break;
    121       1.1  rmind 	}
    122       1.1  rmind 	if (it == NULL) {
    123       1.1  rmind 		TAILQ_INSERT_TAIL(&rlset->rs_queue, rl, r_entry);
    124       1.1  rmind 	} else {
    125       1.1  rmind 		TAILQ_INSERT_BEFORE(it, rl, r_entry);
    126       1.1  rmind 	}
    127       1.1  rmind }
    128       1.1  rmind 
    129       1.1  rmind /*
    130       1.4  rmind  * npf_ruleset_matchnat: find a matching NAT policy in the ruleset.
    131       1.1  rmind  */
    132       1.4  rmind npf_rule_t *
    133       1.4  rmind npf_ruleset_matchnat(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
    134       1.1  rmind {
    135       1.4  rmind 	npf_rule_t *rl;
    136       1.1  rmind 
    137       1.4  rmind 	/* Find a matching NAT policy in the old ruleset. */
    138       1.4  rmind 	TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
    139       1.4  rmind 		if (npf_nat_matchpolicy(rl->r_natp, mnp))
    140       1.4  rmind 			break;
    141       1.4  rmind 	}
    142       1.4  rmind 	return rl;
    143       1.1  rmind }
    144       1.1  rmind 
    145       1.6  rmind npf_rule_t *
    146       1.6  rmind npf_ruleset_sharepm(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
    147       1.6  rmind {
    148       1.6  rmind 	npf_natpolicy_t *np;
    149       1.6  rmind 	npf_rule_t *rl;
    150       1.6  rmind 
    151       1.6  rmind 	/* Find a matching NAT policy in the old ruleset. */
    152       1.6  rmind 	TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
    153       1.6  rmind 		/*
    154       1.6  rmind 		 * NAT policy might not yet be set during the creation of
    155       1.6  rmind 		 * the ruleset (in such case, rule is for our policy), or
    156       1.6  rmind 		 * policies might be equal due to rule exchange on reload.
    157       1.6  rmind 		 */
    158       1.6  rmind 		np = rl->r_natp;
    159       1.6  rmind 		if (np == NULL || np == mnp)
    160       1.6  rmind 			continue;
    161       1.6  rmind 		if (npf_nat_sharepm(np, mnp))
    162       1.6  rmind 			break;
    163       1.6  rmind 	}
    164       1.6  rmind 	return rl;
    165       1.6  rmind }
    166       1.6  rmind 
    167       1.1  rmind /*
    168       1.4  rmind  * npf_ruleset_natreload: minimum reload of NAT policies by maching
    169       1.6  rmind  * two (active and new) NAT rulesets.
    170       1.4  rmind  *
    171       1.4  rmind  * => Active ruleset should be exclusively locked.
    172       1.1  rmind  */
    173       1.4  rmind void
    174       1.4  rmind npf_ruleset_natreload(npf_ruleset_t *nrlset, npf_ruleset_t *arlset)
    175       1.1  rmind {
    176       1.4  rmind 	npf_natpolicy_t *np, *anp;
    177       1.4  rmind 	npf_rule_t *rl, *arl;
    178       1.4  rmind 
    179       1.4  rmind 	KASSERT(npf_core_locked());
    180       1.1  rmind 
    181       1.4  rmind 	/* Scan a new NAT ruleset against NAT policies in old ruleset. */
    182       1.4  rmind 	TAILQ_FOREACH(rl, &nrlset->rs_queue, r_entry) {
    183       1.4  rmind 		np = rl->r_natp;
    184       1.4  rmind 		arl = npf_ruleset_matchnat(arlset, np);
    185       1.4  rmind 		if (arl == NULL) {
    186       1.4  rmind 			continue;
    187       1.4  rmind 		}
    188       1.4  rmind 		/* On match - we exchange NAT policies. */
    189       1.4  rmind 		anp = arl->r_natp;
    190       1.4  rmind 		rl->r_natp = anp;
    191       1.4  rmind 		arl->r_natp = np;
    192       1.6  rmind 		/* Update other NAT policies to share portmap. */
    193       1.6  rmind 		(void)npf_ruleset_sharepm(nrlset, anp);
    194       1.1  rmind 	}
    195       1.4  rmind }
    196       1.4  rmind 
    197       1.1  rmind /*
    198       1.6  rmind  * npf_rule_alloc: allocate a rule and copy n-code from user-space.
    199       1.4  rmind  *
    200       1.4  rmind  * => N-code should be validated by the caller.
    201       1.1  rmind  */
    202       1.4  rmind npf_rule_t *
    203       1.6  rmind npf_rule_alloc(prop_dictionary_t rldict, npf_rproc_t *rp,
    204       1.6  rmind    void *nc, size_t nc_size)
    205       1.1  rmind {
    206       1.4  rmind 	npf_rule_t *rl;
    207       1.7  rmind 	const char *rname;
    208  1.7.10.1    mrg 	int errat __unused;
    209       1.1  rmind 
    210       1.4  rmind 	/* Allocate a rule structure. */
    211       1.4  rmind 	rl = kmem_alloc(sizeof(npf_rule_t), KM_SLEEP);
    212       1.4  rmind 	TAILQ_INIT(&rl->r_subset.rs_queue);
    213       1.4  rmind 	rl->r_natp = NULL;
    214       1.4  rmind 
    215       1.4  rmind 	/* N-code. */
    216       1.4  rmind 	KASSERT(nc == NULL || npf_ncode_validate(nc, nc_size, &errat) == 0);
    217       1.4  rmind 	rl->r_ncode = nc;
    218       1.4  rmind 	rl->r_nc_size = nc_size;
    219       1.4  rmind 
    220       1.7  rmind 	/* Name (string, optional) */
    221       1.7  rmind 	if (prop_dictionary_get_cstring_nocopy(rldict, "name", &rname)) {
    222       1.7  rmind 		strlcpy(rl->r_name, rname, NPF_RNAME_LEN);
    223       1.7  rmind 	} else {
    224       1.7  rmind 		rl->r_name[0] = '\0';
    225       1.7  rmind 	}
    226       1.7  rmind 
    227       1.7  rmind 	/* Attributes, priority and interface ID. */
    228       1.7  rmind 	prop_dictionary_get_uint32(rldict, "attributes", &rl->r_attr);
    229       1.7  rmind 	prop_dictionary_get_int32(rldict, "priority", &rl->r_priority);
    230       1.7  rmind 	prop_dictionary_get_uint32(rldict, "interface", &rl->r_ifid);
    231       1.4  rmind 
    232       1.6  rmind 	/* Rule procedure. */
    233       1.6  rmind 	if (rp) {
    234  1.7.10.1    mrg 		npf_rproc_acquire(rp);
    235       1.4  rmind 	}
    236       1.6  rmind 	rl->r_rproc = rp;
    237       1.6  rmind 
    238       1.4  rmind 	return rl;
    239       1.1  rmind }
    240       1.1  rmind 
    241       1.1  rmind /*
    242       1.1  rmind  * npf_rule_free: free the specified rule.
    243       1.1  rmind  */
    244       1.1  rmind void
    245       1.1  rmind npf_rule_free(npf_rule_t *rl)
    246       1.1  rmind {
    247       1.4  rmind 	npf_natpolicy_t *np = rl->r_natp;
    248       1.4  rmind 	npf_rproc_t *rp = rl->r_rproc;
    249       1.1  rmind 
    250       1.4  rmind 	if (np) {
    251       1.4  rmind 		/* Free NAT policy. */
    252       1.4  rmind 		npf_nat_freepolicy(np);
    253       1.4  rmind 	}
    254       1.4  rmind 	if (rp) {
    255       1.6  rmind 		/* Release rule procedure. */
    256       1.4  rmind 		npf_rproc_release(rp);
    257       1.4  rmind 	}
    258       1.1  rmind 	if (rl->r_ncode) {
    259       1.4  rmind 		/* Free n-code. */
    260       1.1  rmind 		npf_ncode_free(rl->r_ncode, rl->r_nc_size);
    261       1.1  rmind 	}
    262       1.4  rmind 	kmem_free(rl, sizeof(npf_rule_t));
    263       1.1  rmind }
    264       1.1  rmind 
    265       1.1  rmind /*
    266       1.1  rmind  * npf_rule_subset: return sub-ruleset, if any.
    267  1.7.10.1    mrg  * npf_rule_getrproc: acquire a reference and return rule procedure, if any.
    268       1.1  rmind  * npf_rule_getnat: get NAT policy assigned to the rule.
    269       1.1  rmind  */
    270       1.1  rmind 
    271       1.1  rmind npf_ruleset_t *
    272       1.1  rmind npf_rule_subset(npf_rule_t *rl)
    273       1.1  rmind {
    274       1.1  rmind 	return &rl->r_subset;
    275       1.1  rmind }
    276       1.1  rmind 
    277  1.7.10.1    mrg npf_rproc_t *
    278  1.7.10.1    mrg npf_rule_getrproc(npf_rule_t *rl)
    279  1.7.10.1    mrg {
    280  1.7.10.1    mrg 	npf_rproc_t *rp = rl->r_rproc;
    281  1.7.10.1    mrg 
    282  1.7.10.1    mrg 	KASSERT(npf_core_locked());
    283  1.7.10.1    mrg 	if (rp) {
    284  1.7.10.1    mrg 		npf_rproc_acquire(rp);
    285  1.7.10.1    mrg 	}
    286  1.7.10.1    mrg 	return rp;
    287  1.7.10.1    mrg }
    288  1.7.10.1    mrg 
    289       1.1  rmind npf_natpolicy_t *
    290       1.1  rmind npf_rule_getnat(const npf_rule_t *rl)
    291       1.1  rmind {
    292       1.4  rmind 	return rl->r_natp;
    293       1.1  rmind }
    294       1.1  rmind 
    295       1.4  rmind /*
    296       1.4  rmind  * npf_rule_setnat: assign NAT policy to the rule and insert into the
    297       1.4  rmind  * NAT policy list in the ruleset.
    298       1.4  rmind  */
    299       1.1  rmind void
    300       1.1  rmind npf_rule_setnat(npf_rule_t *rl, npf_natpolicy_t *np)
    301       1.1  rmind {
    302       1.3  rmind 
    303       1.4  rmind 	KASSERT(rl->r_natp == NULL);
    304       1.4  rmind 	rl->r_natp = np;
    305       1.1  rmind }
    306       1.1  rmind 
    307       1.7  rmind npf_rule_t *
    308       1.7  rmind npf_ruleset_replace(const char *name, npf_ruleset_t *rlset)
    309       1.7  rmind {
    310       1.7  rmind 	npf_ruleset_t orlset;
    311       1.7  rmind 	npf_rule_t *rl;
    312       1.7  rmind 
    313       1.7  rmind 	npf_core_enter(); /* XXX */
    314       1.7  rmind 	rlset = npf_core_ruleset();
    315       1.7  rmind 	TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
    316       1.7  rmind 		if (rl->r_name[0] == '\0')
    317       1.7  rmind 			continue;
    318       1.7  rmind 		if (strncmp(rl->r_name, name, NPF_RNAME_LEN))
    319       1.7  rmind 			continue;
    320       1.7  rmind 		memcpy(&orlset, &rl->r_subset, sizeof(npf_ruleset_t));
    321       1.7  rmind 		break;
    322       1.7  rmind 	}
    323       1.7  rmind 	npf_core_exit();
    324       1.7  rmind 	return rl;
    325       1.7  rmind }
    326       1.1  rmind 
    327       1.1  rmind /*
    328       1.7  rmind  * npf_ruleset_inspect: inspect the packet against the given ruleset.
    329       1.1  rmind  *
    330       1.7  rmind  * Loop through the rules in the set and run n-code processor of each rule
    331       1.7  rmind  * against the packet (nbuf chain).  If sub-ruleset is found, inspect it.
    332       1.7  rmind  *
    333  1.7.10.1    mrg  * => Caller is responsible for nbuf chain protection.
    334       1.1  rmind  */
    335       1.1  rmind npf_rule_t *
    336       1.7  rmind npf_ruleset_inspect(npf_cache_t *npc, nbuf_t *nbuf, npf_ruleset_t *mainrlset,
    337       1.6  rmind     ifnet_t *ifp, const int di, const int layer)
    338       1.1  rmind {
    339       1.7  rmind 	const int di_mask = (di & PFIL_IN) ? NPF_RULE_IN : NPF_RULE_OUT;
    340       1.7  rmind 	npf_ruleset_t *rlset = mainrlset;
    341       1.1  rmind 	npf_rule_t *final_rl = NULL, *rl;
    342       1.7  rmind 	bool defed = false;
    343       1.1  rmind 
    344       1.7  rmind 	KASSERT(npf_core_locked());
    345       1.1  rmind 	KASSERT(((di & PFIL_IN) != 0) ^ ((di & PFIL_OUT) != 0));
    346       1.7  rmind again:
    347       1.1  rmind 	TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
    348       1.1  rmind 		KASSERT(!final_rl || rl->r_priority >= final_rl->r_priority);
    349       1.1  rmind 
    350       1.1  rmind 		/* Match the interface. */
    351       1.1  rmind 		if (rl->r_ifid && rl->r_ifid != ifp->if_index) {
    352       1.1  rmind 			continue;
    353       1.1  rmind 		}
    354       1.1  rmind 		/* Match the direction. */
    355       1.1  rmind 		if ((rl->r_attr & NPF_RULE_DIMASK) != NPF_RULE_DIMASK) {
    356       1.1  rmind 			if ((rl->r_attr & di_mask) == 0)
    357       1.1  rmind 				continue;
    358       1.1  rmind 		}
    359       1.1  rmind 		/* Process the n-code, if any. */
    360       1.1  rmind 		const void *nc = rl->r_ncode;
    361       1.1  rmind 		if (nc && npf_ncode_process(npc, nc, nbuf, layer)) {
    362       1.1  rmind 			continue;
    363       1.1  rmind 		}
    364       1.1  rmind 		/* Set the matching rule and check for "final". */
    365       1.1  rmind 		final_rl = rl;
    366       1.1  rmind 		if (rl->r_attr & NPF_RULE_FINAL) {
    367       1.2  rmind 			break;
    368       1.1  rmind 		}
    369       1.1  rmind 	}
    370       1.2  rmind 
    371       1.2  rmind 	/* If no final rule, then - default. */
    372       1.7  rmind 	if (final_rl == NULL && !defed) {
    373       1.7  rmind 		final_rl = mainrlset->rs_default;
    374       1.2  rmind 		defed = true;
    375       1.2  rmind 	}
    376       1.2  rmind 	/* Inspect the sub-ruleset, if any. */
    377       1.7  rmind 	if (final_rl && !TAILQ_EMPTY(&final_rl->r_subset.rs_queue)) {
    378       1.7  rmind 		rlset = &final_rl->r_subset;
    379       1.7  rmind 		final_rl = NULL;
    380       1.7  rmind 		goto again;
    381       1.2  rmind 	}
    382       1.7  rmind 	return final_rl;
    383       1.1  rmind }
    384       1.1  rmind 
    385       1.1  rmind /*
    386  1.7.10.1    mrg  * npf_rule_apply: apply the rule and return appropriate value.
    387       1.1  rmind  *
    388       1.1  rmind  * => Returns ENETUNREACH if "block" and 0 if "pass".
    389       1.1  rmind  * => Releases the ruleset lock.
    390       1.1  rmind  */
    391       1.1  rmind int
    392       1.4  rmind npf_rule_apply(npf_cache_t *npc, nbuf_t *nbuf, npf_rule_t *rl, int *retfl)
    393       1.1  rmind {
    394       1.4  rmind 	int error;
    395       1.1  rmind 
    396       1.4  rmind 	KASSERT(npf_core_locked());
    397       1.1  rmind 
    398       1.1  rmind 	/* If not passing - drop the packet. */
    399  1.7.10.1    mrg 	error = (rl->r_attr & NPF_RULE_PASS) ? 0 : ENETUNREACH;
    400  1.7.10.1    mrg 
    401       1.4  rmind 	*retfl = rl->r_attr;
    402       1.4  rmind 	npf_core_exit();
    403  1.7.10.1    mrg 
    404       1.4  rmind 	return error;
    405       1.1  rmind }
    406       1.1  rmind 
    407       1.1  rmind #if defined(DDB) || defined(_NPF_TESTING)
    408       1.1  rmind 
    409       1.1  rmind void
    410       1.1  rmind npf_rulenc_dump(npf_rule_t *rl)
    411       1.1  rmind {
    412       1.1  rmind 	uint32_t *op = rl->r_ncode;
    413       1.1  rmind 	size_t n = rl->r_nc_size;
    414       1.1  rmind 
    415       1.2  rmind 	while (n) {
    416       1.1  rmind 		printf("\t> |0x%02x|\n", (uint32_t)*op);
    417       1.1  rmind 		op++;
    418       1.1  rmind 		n -= sizeof(*op);
    419       1.2  rmind 	}
    420       1.1  rmind 	printf("-> %s\n", (rl->r_attr & NPF_RULE_PASS) ? "pass" : "block");
    421       1.1  rmind }
    422       1.1  rmind 
    423       1.1  rmind #endif
    424