Home | History | Annotate | Line # | Download | only in npf
npf_ruleset.c revision 1.5.2.1
      1  1.5.2.1  jruoho /*	$NetBSD: npf_ruleset.c,v 1.5.2.1 2011/06/06 09:09:53 jruoho Exp $	*/
      2      1.1   rmind 
      3      1.1   rmind /*-
      4  1.5.2.1  jruoho  * Copyright (c) 2009-2011 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.5.2.1  jruoho __KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.5.2.1 2011/06/06 09:09:53 jruoho 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/atomic.h>
     43      1.1   rmind #include <sys/kmem.h>
     44      1.1   rmind #include <sys/pool.h>
     45      1.1   rmind #include <sys/queue.h>
     46      1.1   rmind #include <sys/types.h>
     47      1.1   rmind 
     48      1.3   rmind #include <net/pfil.h>
     49      1.1   rmind #include <net/if.h>
     50      1.1   rmind 
     51      1.1   rmind #include "npf_ncode.h"
     52      1.1   rmind #include "npf_impl.h"
     53      1.1   rmind 
     54      1.4   rmind /* Ruleset structre (queue and default rule). */
     55      1.4   rmind struct npf_ruleset {
     56      1.4   rmind 	TAILQ_HEAD(, npf_rule)	rs_queue;
     57      1.4   rmind 	npf_rule_t *		rs_default;
     58      1.4   rmind };
     59      1.4   rmind 
     60      1.4   rmind /* Rule hook entry. */
     61      1.1   rmind struct npf_hook {
     62      1.3   rmind 	void			(*hk_fn)(npf_cache_t *, nbuf_t *, void *);
     63      1.3   rmind 	void *			hk_arg;
     64      1.3   rmind 	LIST_ENTRY(npf_hook)	hk_entry;
     65      1.1   rmind };
     66      1.1   rmind 
     67  1.5.2.1  jruoho #define	NPF_RNAME_LEN		16
     68  1.5.2.1  jruoho 
     69  1.5.2.1  jruoho /* Rule procedure structure. */
     70      1.4   rmind struct npf_rproc {
     71  1.5.2.1  jruoho 	/* Name. */
     72  1.5.2.1  jruoho 	char			rp_name[NPF_RNAME_LEN];
     73      1.4   rmind 	/* Reference count. */
     74      1.4   rmind 	u_int			rp_refcnt;
     75  1.5.2.1  jruoho 	uint32_t		rp_flags;
     76      1.4   rmind 	/* Normalization options. */
     77      1.4   rmind 	bool			rp_rnd_ipid;
     78      1.4   rmind 	bool			rp_no_df;
     79      1.4   rmind 	u_int			rp_minttl;
     80      1.4   rmind 	u_int			rp_maxmss;
     81      1.4   rmind 	/* Logging interface. */
     82      1.4   rmind 	u_int			rp_log_ifid;
     83      1.1   rmind };
     84      1.1   rmind 
     85      1.1   rmind /* Rule structure. */
     86      1.1   rmind struct npf_rule {
     87  1.5.2.1  jruoho 	/* Rule name (optional) and list entry. */
     88  1.5.2.1  jruoho 	char			r_name[NPF_RNAME_LEN];
     89      1.4   rmind 	TAILQ_ENTRY(npf_rule)	r_entry;
     90      1.1   rmind 	/* Optional: sub-ruleset, NAT policy. */
     91      1.4   rmind 	npf_ruleset_t		r_subset;
     92      1.4   rmind 	npf_natpolicy_t *	r_natp;
     93      1.1   rmind 	/* Rule priority: (highest) 0, 1, 2 ... n (lowest). */
     94  1.5.2.1  jruoho 	pri_t			r_priority;
     95      1.1   rmind 	/* N-code to process. */
     96      1.4   rmind 	void *			r_ncode;
     97      1.4   rmind 	size_t			r_nc_size;
     98      1.1   rmind 	/* Attributes of this rule. */
     99      1.4   rmind 	uint32_t		r_attr;
    100      1.1   rmind 	/* Interface. */
    101      1.4   rmind 	u_int			r_ifid;
    102  1.5.2.1  jruoho 	/* Rule procedure data. */
    103      1.4   rmind 	npf_rproc_t *		r_rproc;
    104      1.1   rmind 	/* List of hooks to process on match. */
    105      1.4   rmind 	kmutex_t		r_hooks_lock;
    106      1.4   rmind 	LIST_HEAD(, npf_hook)	r_hooks;
    107      1.1   rmind };
    108      1.1   rmind 
    109      1.1   rmind npf_ruleset_t *
    110      1.1   rmind npf_ruleset_create(void)
    111      1.1   rmind {
    112      1.1   rmind 	npf_ruleset_t *rlset;
    113      1.1   rmind 
    114      1.1   rmind 	rlset = kmem_zalloc(sizeof(npf_ruleset_t), KM_SLEEP);
    115      1.1   rmind 	TAILQ_INIT(&rlset->rs_queue);
    116      1.1   rmind 	return rlset;
    117      1.1   rmind }
    118      1.1   rmind 
    119      1.1   rmind void
    120      1.1   rmind npf_ruleset_destroy(npf_ruleset_t *rlset)
    121      1.1   rmind {
    122      1.1   rmind 	npf_rule_t *rl;
    123      1.1   rmind 
    124      1.1   rmind 	while ((rl = TAILQ_FIRST(&rlset->rs_queue)) != NULL) {
    125      1.1   rmind 		TAILQ_REMOVE(&rlset->rs_queue, rl, r_entry);
    126      1.1   rmind 		npf_rule_free(rl);
    127      1.1   rmind 	}
    128      1.1   rmind 	kmem_free(rlset, sizeof(npf_ruleset_t));
    129      1.1   rmind }
    130      1.1   rmind 
    131      1.1   rmind /*
    132      1.1   rmind  * npf_ruleset_insert: insert the rule into the specified ruleset.
    133      1.1   rmind  *
    134      1.1   rmind  * Note: multiple rules at the same priority are allowed.
    135      1.1   rmind  */
    136      1.1   rmind void
    137      1.1   rmind npf_ruleset_insert(npf_ruleset_t *rlset, npf_rule_t *rl)
    138      1.1   rmind {
    139      1.1   rmind 	npf_rule_t *it;
    140      1.1   rmind 
    141      1.1   rmind 	if (rl->r_attr & NPF_RULE_DEFAULT) {
    142      1.1   rmind 		rlset->rs_default = rl;
    143      1.1   rmind 		return;
    144      1.1   rmind 	}
    145      1.1   rmind 	TAILQ_FOREACH(it, &rlset->rs_queue, r_entry) {
    146      1.1   rmind 		/* Rule priority: (highest) 0, 1, 2, 4 ... n (lowest). */
    147      1.1   rmind 		if (it->r_priority > rl->r_priority)
    148      1.1   rmind 			break;
    149      1.1   rmind 	}
    150      1.1   rmind 	if (it == NULL) {
    151      1.1   rmind 		TAILQ_INSERT_TAIL(&rlset->rs_queue, rl, r_entry);
    152      1.1   rmind 	} else {
    153      1.1   rmind 		TAILQ_INSERT_BEFORE(it, rl, r_entry);
    154      1.1   rmind 	}
    155      1.1   rmind }
    156      1.1   rmind 
    157      1.1   rmind /*
    158      1.4   rmind  * npf_ruleset_matchnat: find a matching NAT policy in the ruleset.
    159      1.1   rmind  */
    160      1.4   rmind npf_rule_t *
    161      1.4   rmind npf_ruleset_matchnat(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
    162      1.1   rmind {
    163      1.4   rmind 	npf_rule_t *rl;
    164      1.1   rmind 
    165      1.4   rmind 	/* Find a matching NAT policy in the old ruleset. */
    166      1.4   rmind 	TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
    167      1.4   rmind 		if (npf_nat_matchpolicy(rl->r_natp, mnp))
    168      1.4   rmind 			break;
    169      1.4   rmind 	}
    170      1.4   rmind 	return rl;
    171      1.1   rmind }
    172      1.1   rmind 
    173  1.5.2.1  jruoho npf_rule_t *
    174  1.5.2.1  jruoho npf_ruleset_sharepm(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
    175  1.5.2.1  jruoho {
    176  1.5.2.1  jruoho 	npf_natpolicy_t *np;
    177  1.5.2.1  jruoho 	npf_rule_t *rl;
    178  1.5.2.1  jruoho 
    179  1.5.2.1  jruoho 	/* Find a matching NAT policy in the old ruleset. */
    180  1.5.2.1  jruoho 	TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
    181  1.5.2.1  jruoho 		/*
    182  1.5.2.1  jruoho 		 * NAT policy might not yet be set during the creation of
    183  1.5.2.1  jruoho 		 * the ruleset (in such case, rule is for our policy), or
    184  1.5.2.1  jruoho 		 * policies might be equal due to rule exchange on reload.
    185  1.5.2.1  jruoho 		 */
    186  1.5.2.1  jruoho 		np = rl->r_natp;
    187  1.5.2.1  jruoho 		if (np == NULL || np == mnp)
    188  1.5.2.1  jruoho 			continue;
    189  1.5.2.1  jruoho 		if (npf_nat_sharepm(np, mnp))
    190  1.5.2.1  jruoho 			break;
    191  1.5.2.1  jruoho 	}
    192  1.5.2.1  jruoho 	return rl;
    193  1.5.2.1  jruoho }
    194  1.5.2.1  jruoho 
    195      1.1   rmind /*
    196      1.4   rmind  * npf_ruleset_natreload: minimum reload of NAT policies by maching
    197  1.5.2.1  jruoho  * two (active and new) NAT rulesets.
    198      1.4   rmind  *
    199      1.4   rmind  * => Active ruleset should be exclusively locked.
    200      1.1   rmind  */
    201      1.4   rmind void
    202      1.4   rmind npf_ruleset_natreload(npf_ruleset_t *nrlset, npf_ruleset_t *arlset)
    203      1.1   rmind {
    204      1.4   rmind 	npf_natpolicy_t *np, *anp;
    205      1.4   rmind 	npf_rule_t *rl, *arl;
    206      1.4   rmind 
    207      1.4   rmind 	KASSERT(npf_core_locked());
    208      1.1   rmind 
    209      1.4   rmind 	/* Scan a new NAT ruleset against NAT policies in old ruleset. */
    210      1.4   rmind 	TAILQ_FOREACH(rl, &nrlset->rs_queue, r_entry) {
    211      1.4   rmind 		np = rl->r_natp;
    212      1.4   rmind 		arl = npf_ruleset_matchnat(arlset, np);
    213      1.4   rmind 		if (arl == NULL) {
    214      1.4   rmind 			continue;
    215      1.4   rmind 		}
    216      1.4   rmind 		/* On match - we exchange NAT policies. */
    217      1.4   rmind 		anp = arl->r_natp;
    218      1.4   rmind 		rl->r_natp = anp;
    219      1.4   rmind 		arl->r_natp = np;
    220  1.5.2.1  jruoho 		/* Update other NAT policies to share portmap. */
    221  1.5.2.1  jruoho 		(void)npf_ruleset_sharepm(nrlset, anp);
    222      1.1   rmind 	}
    223      1.4   rmind }
    224      1.4   rmind 
    225      1.4   rmind npf_rproc_t *
    226      1.4   rmind npf_rproc_create(prop_dictionary_t rpdict)
    227      1.4   rmind {
    228      1.4   rmind 	npf_rproc_t *rp;
    229  1.5.2.1  jruoho 	const char *rname;
    230      1.4   rmind 
    231  1.5.2.1  jruoho 	rp = kmem_zalloc(sizeof(npf_rproc_t), KM_SLEEP);
    232      1.4   rmind 	rp->rp_refcnt = 1;
    233      1.4   rmind 
    234  1.5.2.1  jruoho 	/* Name and flags. */
    235  1.5.2.1  jruoho 	prop_dictionary_get_cstring_nocopy(rpdict, "name", &rname);
    236  1.5.2.1  jruoho 	strlcpy(rp->rp_name, rname, NPF_RNAME_LEN);
    237  1.5.2.1  jruoho 	prop_dictionary_get_uint32(rpdict, "flags", &rp->rp_flags);
    238  1.5.2.1  jruoho 
    239      1.4   rmind 	/* Logging interface ID (integer). */
    240  1.5.2.1  jruoho 	prop_dictionary_get_uint32(rpdict, "log-interface", &rp->rp_log_ifid);
    241      1.4   rmind 
    242  1.5.2.1  jruoho 	/* IP ID randomization and IP_DF flag cleansing. */
    243  1.5.2.1  jruoho 	prop_dictionary_get_bool(rpdict, "randomize-id", &rp->rp_rnd_ipid);
    244  1.5.2.1  jruoho 	prop_dictionary_get_bool(rpdict, "no-df", &rp->rp_no_df);
    245  1.5.2.1  jruoho 
    246  1.5.2.1  jruoho 	/* Minimum IP TTL and maximum TCP MSS. */
    247  1.5.2.1  jruoho 	prop_dictionary_get_uint32(rpdict, "min-ttl", &rp->rp_minttl);
    248  1.5.2.1  jruoho 	prop_dictionary_get_uint32(rpdict, "max-mss", &rp->rp_maxmss);
    249      1.4   rmind 
    250      1.4   rmind 	return rp;
    251      1.4   rmind }
    252      1.4   rmind 
    253      1.4   rmind npf_rproc_t *
    254      1.4   rmind npf_rproc_return(npf_rule_t *rl)
    255      1.4   rmind {
    256      1.4   rmind 	npf_rproc_t *rp = rl->r_rproc;
    257      1.4   rmind 
    258  1.5.2.1  jruoho 	KASSERT(npf_core_locked());
    259      1.4   rmind 	if (rp) {
    260      1.4   rmind 		atomic_inc_uint(&rp->rp_refcnt);
    261      1.1   rmind 	}
    262      1.4   rmind 	return rp;
    263      1.4   rmind }
    264      1.3   rmind 
    265      1.4   rmind void
    266      1.4   rmind npf_rproc_release(npf_rproc_t *rp)
    267      1.4   rmind {
    268      1.3   rmind 
    269      1.4   rmind 	/* Destroy on last reference. */
    270      1.4   rmind 	if (atomic_dec_uint_nv(&rp->rp_refcnt) != 0) {
    271      1.4   rmind 		return;
    272      1.4   rmind 	}
    273      1.4   rmind 	kmem_free(rp, sizeof(npf_rproc_t));
    274      1.1   rmind }
    275      1.2   rmind 
    276      1.1   rmind void
    277  1.5.2.1  jruoho npf_rproc_run(npf_cache_t *npc, nbuf_t *nbuf, npf_rproc_t *rp, int error)
    278      1.1   rmind {
    279  1.5.2.1  jruoho 	const uint32_t flags = rp->rp_flags;
    280      1.1   rmind 
    281      1.4   rmind 	KASSERT(rp->rp_refcnt > 0);
    282      1.4   rmind 
    283      1.4   rmind 	/* Normalize the packet, if required. */
    284  1.5.2.1  jruoho 	if ((flags & NPF_RPROC_NORMALIZE) != 0 && !error) {
    285  1.5.2.1  jruoho 		(void)npf_normalize(npc, nbuf,
    286  1.5.2.1  jruoho 		    rp->rp_rnd_ipid, rp->rp_no_df,
    287  1.5.2.1  jruoho 		    rp->rp_minttl, rp->rp_maxmss);
    288  1.5.2.1  jruoho 		npf_stats_inc(NPF_STAT_RPROC_NORM);
    289  1.5.2.1  jruoho 	}
    290      1.4   rmind 
    291      1.4   rmind 	/* Log packet, if required. */
    292  1.5.2.1  jruoho 	if ((flags & NPF_RPROC_LOG) != 0) {
    293      1.4   rmind 		npf_log_packet(npc, nbuf, rp->rp_log_ifid);
    294  1.5.2.1  jruoho 		npf_stats_inc(NPF_STAT_RPROC_LOG);
    295      1.4   rmind 	}
    296      1.1   rmind }
    297      1.1   rmind 
    298      1.1   rmind /*
    299  1.5.2.1  jruoho  * npf_rule_alloc: allocate a rule and copy n-code from user-space.
    300      1.4   rmind  *
    301      1.4   rmind  * => N-code should be validated by the caller.
    302      1.1   rmind  */
    303      1.4   rmind npf_rule_t *
    304  1.5.2.1  jruoho npf_rule_alloc(prop_dictionary_t rldict, npf_rproc_t *rp,
    305  1.5.2.1  jruoho    void *nc, size_t nc_size)
    306      1.1   rmind {
    307      1.4   rmind 	npf_rule_t *rl;
    308  1.5.2.1  jruoho 	const char *rname;
    309      1.4   rmind 	int errat;
    310      1.1   rmind 
    311      1.4   rmind 	/* Allocate a rule structure. */
    312      1.4   rmind 	rl = kmem_alloc(sizeof(npf_rule_t), KM_SLEEP);
    313      1.4   rmind 	TAILQ_INIT(&rl->r_subset.rs_queue);
    314      1.4   rmind 	mutex_init(&rl->r_hooks_lock, MUTEX_DEFAULT, IPL_SOFTNET);
    315      1.4   rmind 	LIST_INIT(&rl->r_hooks);
    316      1.4   rmind 	rl->r_natp = NULL;
    317      1.4   rmind 
    318      1.4   rmind 	/* N-code. */
    319  1.5.2.1  jruoho 	(void)errat;
    320      1.4   rmind 	KASSERT(nc == NULL || npf_ncode_validate(nc, nc_size, &errat) == 0);
    321      1.4   rmind 	rl->r_ncode = nc;
    322      1.4   rmind 	rl->r_nc_size = nc_size;
    323      1.4   rmind 
    324  1.5.2.1  jruoho 	/* Name (string, optional) */
    325  1.5.2.1  jruoho 	if (prop_dictionary_get_cstring_nocopy(rldict, "name", &rname)) {
    326  1.5.2.1  jruoho 		strlcpy(rl->r_name, rname, NPF_RNAME_LEN);
    327      1.4   rmind 	} else {
    328  1.5.2.1  jruoho 		rl->r_name[0] = '\0';
    329      1.4   rmind 	}
    330  1.5.2.1  jruoho 
    331  1.5.2.1  jruoho 	/* Attributes, priority and interface ID. */
    332  1.5.2.1  jruoho 	prop_dictionary_get_uint32(rldict, "attributes", &rl->r_attr);
    333  1.5.2.1  jruoho 	prop_dictionary_get_int32(rldict, "priority", &rl->r_priority);
    334  1.5.2.1  jruoho 	prop_dictionary_get_uint32(rldict, "interface", &rl->r_ifid);
    335  1.5.2.1  jruoho 
    336  1.5.2.1  jruoho 	/* Rule procedure. */
    337  1.5.2.1  jruoho 	if (rp) {
    338  1.5.2.1  jruoho 		atomic_inc_uint(&rp->rp_refcnt);
    339  1.5.2.1  jruoho 	}
    340  1.5.2.1  jruoho 	rl->r_rproc = rp;
    341  1.5.2.1  jruoho 
    342      1.4   rmind 	return rl;
    343      1.1   rmind }
    344      1.1   rmind 
    345      1.1   rmind /*
    346      1.1   rmind  * npf_rule_free: free the specified rule.
    347      1.1   rmind  */
    348      1.1   rmind void
    349      1.1   rmind npf_rule_free(npf_rule_t *rl)
    350      1.1   rmind {
    351      1.4   rmind 	npf_natpolicy_t *np = rl->r_natp;
    352      1.4   rmind 	npf_rproc_t *rp = rl->r_rproc;
    353      1.1   rmind 
    354      1.4   rmind 	if (np) {
    355      1.4   rmind 		/* Free NAT policy. */
    356      1.4   rmind 		npf_nat_freepolicy(np);
    357      1.4   rmind 	}
    358      1.4   rmind 	if (rp) {
    359  1.5.2.1  jruoho 		/* Release rule procedure. */
    360      1.4   rmind 		npf_rproc_release(rp);
    361      1.4   rmind 	}
    362      1.1   rmind 	if (rl->r_ncode) {
    363      1.4   rmind 		/* Free n-code. */
    364      1.1   rmind 		npf_ncode_free(rl->r_ncode, rl->r_nc_size);
    365      1.1   rmind 	}
    366      1.4   rmind 	mutex_destroy(&rl->r_hooks_lock);
    367      1.4   rmind 	kmem_free(rl, sizeof(npf_rule_t));
    368      1.1   rmind }
    369      1.1   rmind 
    370      1.1   rmind /*
    371      1.1   rmind  * npf_rule_subset: return sub-ruleset, if any.
    372      1.1   rmind  * npf_rule_getnat: get NAT policy assigned to the rule.
    373      1.1   rmind  */
    374      1.1   rmind 
    375      1.1   rmind npf_ruleset_t *
    376      1.1   rmind npf_rule_subset(npf_rule_t *rl)
    377      1.1   rmind {
    378      1.1   rmind 	return &rl->r_subset;
    379      1.1   rmind }
    380      1.1   rmind 
    381      1.1   rmind npf_natpolicy_t *
    382      1.1   rmind npf_rule_getnat(const npf_rule_t *rl)
    383      1.1   rmind {
    384      1.4   rmind 	return rl->r_natp;
    385      1.1   rmind }
    386      1.1   rmind 
    387      1.4   rmind /*
    388      1.4   rmind  * npf_rule_setnat: assign NAT policy to the rule and insert into the
    389      1.4   rmind  * NAT policy list in the ruleset.
    390      1.4   rmind  */
    391      1.1   rmind void
    392      1.1   rmind npf_rule_setnat(npf_rule_t *rl, npf_natpolicy_t *np)
    393      1.1   rmind {
    394      1.3   rmind 
    395      1.4   rmind 	KASSERT(rl->r_natp == NULL);
    396      1.4   rmind 	rl->r_natp = np;
    397      1.1   rmind }
    398      1.1   rmind 
    399  1.5.2.1  jruoho #if 0
    400      1.1   rmind /*
    401      1.1   rmind  * npf_hook_register: register action hook in the rule.
    402      1.1   rmind  */
    403      1.1   rmind npf_hook_t *
    404      1.1   rmind npf_hook_register(npf_rule_t *rl,
    405      1.3   rmind     void (*fn)(npf_cache_t *, nbuf_t *, void *), void *arg)
    406      1.1   rmind {
    407      1.1   rmind 	npf_hook_t *hk;
    408      1.1   rmind 
    409      1.1   rmind 	hk = kmem_alloc(sizeof(npf_hook_t), KM_SLEEP);
    410      1.1   rmind 	if (hk != NULL) {
    411      1.1   rmind 		hk->hk_fn = fn;
    412      1.1   rmind 		hk->hk_arg = arg;
    413      1.4   rmind 		mutex_enter(&rl->r_hooks_lock);
    414      1.1   rmind 		LIST_INSERT_HEAD(&rl->r_hooks, hk, hk_entry);
    415      1.4   rmind 		mutex_exit(&rl->r_hooks_lock);
    416      1.1   rmind 	}
    417      1.1   rmind 	return hk;
    418      1.1   rmind }
    419      1.1   rmind 
    420      1.1   rmind /*
    421      1.1   rmind  * npf_hook_unregister: unregister a specified hook.
    422      1.1   rmind  *
    423      1.1   rmind  * => Hook should have been registered in the rule.
    424      1.1   rmind  */
    425      1.1   rmind void
    426      1.1   rmind npf_hook_unregister(npf_rule_t *rl, npf_hook_t *hk)
    427      1.1   rmind {
    428      1.1   rmind 
    429      1.4   rmind 	mutex_enter(&rl->r_hooks_lock);
    430      1.1   rmind 	LIST_REMOVE(hk, hk_entry);
    431      1.4   rmind 	mutex_exit(&rl->r_hooks_lock);
    432      1.1   rmind 	kmem_free(hk, sizeof(npf_hook_t));
    433      1.1   rmind }
    434  1.5.2.1  jruoho #endif
    435  1.5.2.1  jruoho 
    436  1.5.2.1  jruoho npf_rule_t *
    437  1.5.2.1  jruoho npf_ruleset_replace(const char *name, npf_ruleset_t *rlset)
    438  1.5.2.1  jruoho {
    439  1.5.2.1  jruoho 	npf_ruleset_t orlset;
    440  1.5.2.1  jruoho 	npf_rule_t *rl;
    441  1.5.2.1  jruoho 
    442  1.5.2.1  jruoho 	npf_core_enter(); /* XXX */
    443  1.5.2.1  jruoho 	rlset = npf_core_ruleset();
    444  1.5.2.1  jruoho 	TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
    445  1.5.2.1  jruoho 		if (rl->r_name[0] == '\0')
    446  1.5.2.1  jruoho 			continue;
    447  1.5.2.1  jruoho 		if (strncmp(rl->r_name, name, NPF_RNAME_LEN))
    448  1.5.2.1  jruoho 			continue;
    449  1.5.2.1  jruoho 		memcpy(&orlset, &rl->r_subset, sizeof(npf_ruleset_t));
    450  1.5.2.1  jruoho 		break;
    451  1.5.2.1  jruoho 	}
    452  1.5.2.1  jruoho 	npf_core_exit();
    453  1.5.2.1  jruoho 	return rl;
    454  1.5.2.1  jruoho }
    455      1.1   rmind 
    456      1.1   rmind /*
    457  1.5.2.1  jruoho  * npf_ruleset_inspect: inspect the packet against the given ruleset.
    458  1.5.2.1  jruoho  *
    459  1.5.2.1  jruoho  * Loop through the rules in the set and run n-code processor of each rule
    460  1.5.2.1  jruoho  * against the packet (nbuf chain).  If sub-ruleset is found, inspect it.
    461      1.1   rmind  *
    462  1.5.2.1  jruoho  * => If not found, core ruleset lock is released.
    463  1.5.2.1  jruoho  * => Caller should protect the nbuf chain.
    464      1.1   rmind  */
    465      1.1   rmind npf_rule_t *
    466  1.5.2.1  jruoho npf_ruleset_inspect(npf_cache_t *npc, nbuf_t *nbuf, npf_ruleset_t *mainrlset,
    467  1.5.2.1  jruoho     ifnet_t *ifp, const int di, const int layer)
    468      1.1   rmind {
    469  1.5.2.1  jruoho 	const int di_mask = (di & PFIL_IN) ? NPF_RULE_IN : NPF_RULE_OUT;
    470  1.5.2.1  jruoho 	npf_ruleset_t *rlset = mainrlset;
    471      1.1   rmind 	npf_rule_t *final_rl = NULL, *rl;
    472  1.5.2.1  jruoho 	bool defed = false;
    473      1.1   rmind 
    474  1.5.2.1  jruoho 	KASSERT(npf_core_locked());
    475      1.1   rmind 	KASSERT(((di & PFIL_IN) != 0) ^ ((di & PFIL_OUT) != 0));
    476  1.5.2.1  jruoho again:
    477      1.1   rmind 	TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
    478      1.1   rmind 		KASSERT(!final_rl || rl->r_priority >= final_rl->r_priority);
    479      1.1   rmind 
    480      1.1   rmind 		/* Match the interface. */
    481      1.1   rmind 		if (rl->r_ifid && rl->r_ifid != ifp->if_index) {
    482      1.1   rmind 			continue;
    483      1.1   rmind 		}
    484      1.1   rmind 		/* Match the direction. */
    485      1.1   rmind 		if ((rl->r_attr & NPF_RULE_DIMASK) != NPF_RULE_DIMASK) {
    486      1.1   rmind 			if ((rl->r_attr & di_mask) == 0)
    487      1.1   rmind 				continue;
    488      1.1   rmind 		}
    489      1.1   rmind 		/* Process the n-code, if any. */
    490      1.1   rmind 		const void *nc = rl->r_ncode;
    491      1.1   rmind 		if (nc && npf_ncode_process(npc, nc, nbuf, layer)) {
    492      1.1   rmind 			continue;
    493      1.1   rmind 		}
    494      1.1   rmind 		/* Set the matching rule and check for "final". */
    495      1.1   rmind 		final_rl = rl;
    496      1.1   rmind 		if (rl->r_attr & NPF_RULE_FINAL) {
    497      1.2   rmind 			break;
    498      1.1   rmind 		}
    499      1.1   rmind 	}
    500      1.2   rmind 
    501      1.2   rmind 	/* If no final rule, then - default. */
    502  1.5.2.1  jruoho 	if (final_rl == NULL && !defed) {
    503  1.5.2.1  jruoho 		final_rl = mainrlset->rs_default;
    504      1.2   rmind 		defed = true;
    505      1.2   rmind 	}
    506      1.2   rmind 	/* Inspect the sub-ruleset, if any. */
    507  1.5.2.1  jruoho 	if (final_rl && !TAILQ_EMPTY(&final_rl->r_subset.rs_queue)) {
    508  1.5.2.1  jruoho 		rlset = &final_rl->r_subset;
    509  1.5.2.1  jruoho 		final_rl = NULL;
    510  1.5.2.1  jruoho 		goto again;
    511      1.2   rmind 	}
    512  1.5.2.1  jruoho 	if (final_rl == NULL) {
    513      1.4   rmind 		npf_core_exit();
    514      1.1   rmind 	}
    515  1.5.2.1  jruoho 	return final_rl;
    516      1.1   rmind }
    517      1.1   rmind 
    518      1.1   rmind /*
    519      1.1   rmind  * npf_rule_apply: apply the rule i.e. run hooks and return appropriate value.
    520      1.1   rmind  *
    521      1.1   rmind  * => Returns ENETUNREACH if "block" and 0 if "pass".
    522      1.1   rmind  * => Releases the ruleset lock.
    523      1.1   rmind  */
    524      1.1   rmind int
    525      1.4   rmind npf_rule_apply(npf_cache_t *npc, nbuf_t *nbuf, npf_rule_t *rl, int *retfl)
    526      1.1   rmind {
    527      1.1   rmind 	npf_hook_t *hk;
    528      1.4   rmind 	int error;
    529      1.1   rmind 
    530      1.4   rmind 	KASSERT(npf_core_locked());
    531      1.1   rmind 
    532      1.1   rmind 	/* If not passing - drop the packet. */
    533      1.1   rmind 	if ((rl->r_attr & NPF_RULE_PASS) == 0) {
    534      1.4   rmind 		error = ENETUNREACH;
    535      1.4   rmind 		goto done;
    536      1.1   rmind 	}
    537      1.4   rmind 	error = 0;
    538      1.1   rmind 
    539      1.1   rmind 	/* Passing.  Run the hooks. */
    540      1.1   rmind 	LIST_FOREACH(hk, &rl->r_hooks, hk_entry) {
    541      1.1   rmind 		KASSERT(hk->hk_fn != NULL);
    542      1.3   rmind 		(*hk->hk_fn)(npc, nbuf, hk->hk_arg);
    543      1.3   rmind 	}
    544      1.4   rmind done:
    545      1.4   rmind 	*retfl = rl->r_attr;
    546      1.4   rmind 	npf_core_exit();
    547      1.4   rmind 	return error;
    548      1.1   rmind }
    549      1.1   rmind 
    550      1.1   rmind #if defined(DDB) || defined(_NPF_TESTING)
    551      1.1   rmind 
    552      1.1   rmind void
    553      1.1   rmind npf_rulenc_dump(npf_rule_t *rl)
    554      1.1   rmind {
    555      1.1   rmind 	uint32_t *op = rl->r_ncode;
    556      1.1   rmind 	size_t n = rl->r_nc_size;
    557      1.1   rmind 
    558      1.2   rmind 	while (n) {
    559      1.1   rmind 		printf("\t> |0x%02x|\n", (uint32_t)*op);
    560      1.1   rmind 		op++;
    561      1.1   rmind 		n -= sizeof(*op);
    562      1.2   rmind 	}
    563      1.1   rmind 	printf("-> %s\n", (rl->r_attr & NPF_RULE_PASS) ? "pass" : "block");
    564      1.1   rmind }
    565      1.1   rmind 
    566      1.1   rmind #endif
    567