Home | History | Annotate | Line # | Download | only in npf
npf_ruleset.c revision 1.10
      1  1.10  rmind /*	$NetBSD: npf_ruleset.c,v 1.10 2012/02/06 23:30:14 rmind Exp $	*/
      2   1.1  rmind 
      3   1.1  rmind /*-
      4  1.10  rmind  * 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.10  rmind __KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.10 2012/02/06 23:30:14 rmind 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.8  rmind 	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.10  rmind 		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.10  rmind  * 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.10  rmind npf_rproc_t *
    278  1.10  rmind npf_rule_getrproc(npf_rule_t *rl)
    279  1.10  rmind {
    280  1.10  rmind 	npf_rproc_t *rp = rl->r_rproc;
    281  1.10  rmind 
    282  1.10  rmind 	KASSERT(npf_core_locked());
    283  1.10  rmind 	if (rp) {
    284  1.10  rmind 		npf_rproc_acquire(rp);
    285  1.10  rmind 	}
    286  1.10  rmind 	return rp;
    287  1.10  rmind }
    288  1.10  rmind 
    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.9  rmind  * => 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.10  rmind  * 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.10  rmind 	error = (rl->r_attr & NPF_RULE_PASS) ? 0 : ENETUNREACH;
    400  1.10  rmind 
    401   1.4  rmind 	*retfl = rl->r_attr;
    402   1.4  rmind 	npf_core_exit();
    403  1.10  rmind 
    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