Home | History | Annotate | Line # | Download | only in pfctl
pfctl_optimize.c revision 1.5.20.2
      1  1.5.20.2  peter /*	$NetBSD: pfctl_optimize.c,v 1.5.20.2 2008/04/26 12:54:34 peter Exp $	*/
      2  1.5.20.1   yamt /*	$OpenBSD: pfctl_optimize.c,v 1.13 2006/10/31 14:17:45 mcbride Exp $ */
      3       1.1   yamt 
      4       1.1   yamt /*
      5       1.1   yamt  * Copyright (c) 2004 Mike Frantzen <frantzen (at) openbsd.org>
      6       1.1   yamt  *
      7       1.1   yamt  * Permission to use, copy, modify, and distribute this software for any
      8       1.1   yamt  * purpose with or without fee is hereby granted, provided that the above
      9       1.1   yamt  * copyright notice and this permission notice appear in all copies.
     10       1.1   yamt  *
     11       1.1   yamt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12       1.1   yamt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13       1.1   yamt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14       1.1   yamt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15       1.1   yamt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16       1.1   yamt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17       1.1   yamt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18       1.1   yamt  */
     19       1.1   yamt 
     20       1.1   yamt #include <sys/types.h>
     21       1.1   yamt #include <sys/ioctl.h>
     22       1.1   yamt #include <sys/socket.h>
     23       1.1   yamt 
     24       1.1   yamt #include <net/if.h>
     25       1.1   yamt #include <net/pfvar.h>
     26       1.1   yamt 
     27  1.5.20.2  peter #include <netinet/in.h>
     28       1.1   yamt #include <arpa/inet.h>
     29       1.1   yamt 
     30       1.1   yamt #include <assert.h>
     31       1.1   yamt #include <ctype.h>
     32       1.1   yamt #include <err.h>
     33       1.1   yamt #include <errno.h>
     34       1.1   yamt #include <stddef.h>
     35       1.1   yamt #include <stdio.h>
     36       1.1   yamt #include <stdlib.h>
     37       1.1   yamt #include <string.h>
     38       1.1   yamt 
     39       1.1   yamt #include "pfctl_parser.h"
     40       1.1   yamt #include "pfctl.h"
     41       1.1   yamt 
     42       1.1   yamt /* The size at which a table becomes faster than individual rules */
     43       1.1   yamt #define TABLE_THRESHOLD		6
     44       1.1   yamt 
     45       1.1   yamt 
     46       1.1   yamt /* #define OPT_DEBUG	1 */
     47       1.1   yamt #ifdef OPT_DEBUG
     48       1.1   yamt # define DEBUG(str, v...) \
     49       1.1   yamt 	printf("%s: " str "\n", __FUNCTION__ , ## v)
     50       1.1   yamt #else
     51       1.1   yamt # define DEBUG(str, v...) ((void)0)
     52       1.1   yamt #endif
     53       1.1   yamt 
     54       1.1   yamt 
     55       1.1   yamt /*
     56       1.1   yamt  * A container that lets us sort a superblock to optimize the skip step jumps
     57       1.1   yamt  */
     58       1.1   yamt struct pf_skip_step {
     59       1.1   yamt 	int				ps_count;	/* number of items */
     60       1.1   yamt 	TAILQ_HEAD( , pf_opt_rule)	ps_rules;
     61       1.1   yamt 	TAILQ_ENTRY(pf_skip_step)	ps_entry;
     62       1.1   yamt };
     63       1.1   yamt 
     64       1.1   yamt 
     65       1.1   yamt /*
     66       1.1   yamt  * A superblock is a block of adjacent rules of similar action.  If there
     67       1.1   yamt  * are five PASS rules in a row, they all become members of a superblock.
     68       1.1   yamt  * Once we have a superblock, we are free to re-order any rules within it
     69       1.1   yamt  * in order to improve performance; if a packet is passed, it doesn't matter
     70       1.1   yamt  * who passed it.
     71       1.1   yamt  */
     72       1.1   yamt struct superblock {
     73       1.1   yamt 	TAILQ_HEAD( , pf_opt_rule)		 sb_rules;
     74       1.1   yamt 	TAILQ_ENTRY(superblock)			 sb_entry;
     75       1.1   yamt 	struct superblock			*sb_profiled_block;
     76       1.1   yamt 	TAILQ_HEAD(skiplist, pf_skip_step)	 sb_skipsteps[PF_SKIP_COUNT];
     77       1.1   yamt };
     78       1.1   yamt TAILQ_HEAD(superblocks, superblock);
     79       1.1   yamt 
     80       1.1   yamt 
     81       1.1   yamt /*
     82       1.1   yamt  * Description of the PF rule structure.
     83       1.1   yamt  */
     84       1.1   yamt enum {
     85       1.1   yamt     BARRIER,	/* the presence of the field puts the rule in it's own block */
     86       1.1   yamt     BREAK,	/* the field may not differ between rules in a superblock */
     87       1.1   yamt     NOMERGE,	/* the field may not differ between rules when combined */
     88       1.1   yamt     COMBINED,	/* the field may itself be combined with other rules */
     89       1.1   yamt     DC,		/* we just don't care about the field */
     90       1.1   yamt     NEVER};	/* we should never see this field set?!? */
     91       1.1   yamt struct pf_rule_field {
     92       1.1   yamt 	const char	*prf_name;
     93       1.1   yamt 	int		 prf_type;
     94       1.1   yamt 	size_t		 prf_offset;
     95       1.1   yamt 	size_t		 prf_size;
     96       1.1   yamt } pf_rule_desc[] = {
     97       1.1   yamt #define PF_RULE_FIELD(field, ty)	\
     98       1.1   yamt     {#field,				\
     99       1.1   yamt     ty,					\
    100       1.1   yamt     offsetof(struct pf_rule, field),	\
    101       1.1   yamt     sizeof(((struct pf_rule *)0)->field)}
    102       1.1   yamt 
    103       1.1   yamt 
    104       1.1   yamt     /*
    105       1.1   yamt      * The presence of these fields in a rule put the rule in it's own
    106       1.1   yamt      * superblock.  Thus it will not be optimized.  It also prevents the
    107       1.1   yamt      * rule from being re-ordered at all.
    108       1.1   yamt      */
    109       1.1   yamt     PF_RULE_FIELD(label,		BARRIER),
    110       1.1   yamt     PF_RULE_FIELD(prob,			BARRIER),
    111       1.1   yamt     PF_RULE_FIELD(max_states,		BARRIER),
    112       1.1   yamt     PF_RULE_FIELD(max_src_nodes,	BARRIER),
    113  1.5.20.1   yamt     PF_RULE_FIELD(max_src_states,	BARRIER),
    114  1.5.20.1   yamt     PF_RULE_FIELD(max_src_conn,		BARRIER),
    115  1.5.20.1   yamt     PF_RULE_FIELD(max_src_conn_rate,	BARRIER),
    116  1.5.20.1   yamt     PF_RULE_FIELD(anchor,		BARRIER),	/* for now */
    117       1.1   yamt 
    118       1.1   yamt     /*
    119       1.1   yamt      * These fields must be the same between all rules in the same superblock.
    120       1.1   yamt      * These rules are allowed to be re-ordered but only among like rules.
    121       1.1   yamt      * For instance we can re-order all 'tag "foo"' rules because they have the
    122       1.1   yamt      * same tag.  But we can not re-order between a 'tag "foo"' and a
    123       1.1   yamt      * 'tag "bar"' since that would change the meaning of the ruleset.
    124       1.1   yamt      */
    125       1.1   yamt     PF_RULE_FIELD(tagname,		BREAK),
    126       1.1   yamt     PF_RULE_FIELD(keep_state,		BREAK),
    127       1.1   yamt     PF_RULE_FIELD(qname,		BREAK),
    128  1.5.20.1   yamt     PF_RULE_FIELD(pqname,		BREAK),
    129       1.1   yamt     PF_RULE_FIELD(rt,			BREAK),
    130       1.1   yamt     PF_RULE_FIELD(allow_opts,		BREAK),
    131       1.1   yamt     PF_RULE_FIELD(rule_flag,		BREAK),
    132       1.1   yamt     PF_RULE_FIELD(action,		BREAK),
    133  1.5.20.1   yamt     PF_RULE_FIELD(log,			BREAK),
    134  1.5.20.1   yamt     PF_RULE_FIELD(quick,		BREAK),
    135  1.5.20.1   yamt     PF_RULE_FIELD(return_ttl,		BREAK),
    136  1.5.20.1   yamt     PF_RULE_FIELD(overload_tblname,	BREAK),
    137  1.5.20.1   yamt     PF_RULE_FIELD(flush,		BREAK),
    138  1.5.20.1   yamt     PF_RULE_FIELD(rpool,		BREAK),
    139  1.5.20.1   yamt     PF_RULE_FIELD(logif,		BREAK),
    140       1.1   yamt 
    141       1.1   yamt     /*
    142       1.1   yamt      * Any fields not listed in this structure act as BREAK fields
    143       1.1   yamt      */
    144       1.1   yamt 
    145       1.1   yamt 
    146       1.1   yamt     /*
    147       1.1   yamt      * These fields must not differ when we merge two rules together but
    148       1.1   yamt      * their difference isn't enough to put the rules in different superblocks.
    149       1.1   yamt      * There are no problems re-ordering any rules with these fields.
    150       1.1   yamt      */
    151       1.1   yamt     PF_RULE_FIELD(af,			NOMERGE),
    152       1.1   yamt     PF_RULE_FIELD(ifnot,		NOMERGE),
    153  1.5.20.1   yamt     PF_RULE_FIELD(ifname,		NOMERGE),	/* hack for IF groups */
    154       1.1   yamt     PF_RULE_FIELD(match_tag_not,	NOMERGE),
    155       1.1   yamt     PF_RULE_FIELD(match_tagname,	NOMERGE),
    156       1.1   yamt     PF_RULE_FIELD(os_fingerprint,	NOMERGE),
    157       1.1   yamt     PF_RULE_FIELD(timeout,		NOMERGE),
    158       1.1   yamt     PF_RULE_FIELD(return_icmp,		NOMERGE),
    159       1.1   yamt     PF_RULE_FIELD(return_icmp6,		NOMERGE),
    160       1.1   yamt     PF_RULE_FIELD(uid,			NOMERGE),
    161       1.1   yamt     PF_RULE_FIELD(gid,			NOMERGE),
    162       1.1   yamt     PF_RULE_FIELD(direction,		NOMERGE),
    163       1.1   yamt     PF_RULE_FIELD(proto,		NOMERGE),
    164       1.1   yamt     PF_RULE_FIELD(type,			NOMERGE),
    165       1.1   yamt     PF_RULE_FIELD(code,			NOMERGE),
    166       1.1   yamt     PF_RULE_FIELD(flags,		NOMERGE),
    167       1.1   yamt     PF_RULE_FIELD(flagset,		NOMERGE),
    168       1.1   yamt     PF_RULE_FIELD(tos,			NOMERGE),
    169       1.1   yamt     PF_RULE_FIELD(src.port,		NOMERGE),
    170       1.1   yamt     PF_RULE_FIELD(dst.port,		NOMERGE),
    171       1.1   yamt     PF_RULE_FIELD(src.port_op,		NOMERGE),
    172       1.1   yamt     PF_RULE_FIELD(dst.port_op,		NOMERGE),
    173       1.1   yamt     PF_RULE_FIELD(src.neg,		NOMERGE),
    174       1.1   yamt     PF_RULE_FIELD(dst.neg,		NOMERGE),
    175       1.1   yamt 
    176       1.1   yamt     /* These fields can be merged */
    177       1.1   yamt     PF_RULE_FIELD(src.addr,		COMBINED),
    178       1.1   yamt     PF_RULE_FIELD(dst.addr,		COMBINED),
    179       1.1   yamt 
    180       1.1   yamt     /* We just don't care about these fields.  They're set by the kernel */
    181       1.1   yamt     PF_RULE_FIELD(skip,			DC),
    182       1.1   yamt     PF_RULE_FIELD(evaluations,		DC),
    183       1.1   yamt     PF_RULE_FIELD(packets,		DC),
    184       1.1   yamt     PF_RULE_FIELD(bytes,		DC),
    185       1.1   yamt     PF_RULE_FIELD(kif,			DC),
    186       1.1   yamt     PF_RULE_FIELD(states,		DC),
    187       1.1   yamt     PF_RULE_FIELD(src_nodes,		DC),
    188       1.1   yamt     PF_RULE_FIELD(nr,			DC),
    189       1.1   yamt     PF_RULE_FIELD(entries,		DC),
    190       1.1   yamt     PF_RULE_FIELD(qid,			DC),
    191       1.1   yamt     PF_RULE_FIELD(pqid,			DC),
    192       1.1   yamt     PF_RULE_FIELD(anchor_relative,	DC),
    193       1.1   yamt     PF_RULE_FIELD(anchor_wildcard,	DC),
    194  1.5.20.1   yamt     PF_RULE_FIELD(tag,			DC),
    195  1.5.20.1   yamt     PF_RULE_FIELD(match_tag,		DC),
    196  1.5.20.1   yamt     PF_RULE_FIELD(overload_tbl,		DC),
    197       1.1   yamt 
    198       1.1   yamt     /* These fields should never be set in a PASS/BLOCK rule */
    199       1.1   yamt     PF_RULE_FIELD(natpass,		NEVER),
    200       1.1   yamt     PF_RULE_FIELD(max_mss,		NEVER),
    201       1.1   yamt     PF_RULE_FIELD(min_ttl,		NEVER),
    202       1.1   yamt };
    203       1.1   yamt 
    204       1.1   yamt 
    205       1.1   yamt 
    206       1.1   yamt int	add_opt_table(struct pfctl *, struct pf_opt_tbl **, sa_family_t,
    207       1.1   yamt 	    struct pf_rule_addr *);
    208       1.1   yamt int	addrs_combineable(struct pf_rule_addr *, struct pf_rule_addr *);
    209       1.1   yamt int	addrs_equal(struct pf_rule_addr *, struct pf_rule_addr *);
    210       1.1   yamt int	block_feedback(struct pfctl *, struct superblock *);
    211       1.1   yamt int	combine_rules(struct pfctl *, struct superblock *);
    212       1.1   yamt void	comparable_rule(struct pf_rule *, const struct pf_rule *, int);
    213       1.1   yamt int	construct_superblocks(struct pfctl *, struct pf_opt_queue *,
    214       1.1   yamt 	    struct superblocks *);
    215       1.1   yamt void	exclude_supersets(struct pf_rule *, struct pf_rule *);
    216  1.5.20.1   yamt int	interface_group(const char *);
    217       1.1   yamt int	load_feedback_profile(struct pfctl *, struct superblocks *);
    218       1.1   yamt int	optimize_superblock(struct pfctl *, struct superblock *);
    219       1.1   yamt int	pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *);
    220       1.1   yamt void	remove_from_skipsteps(struct skiplist *, struct superblock *,
    221       1.1   yamt 	    struct pf_opt_rule *, struct pf_skip_step *);
    222       1.1   yamt int	remove_identical_rules(struct pfctl *, struct superblock *);
    223       1.1   yamt int	reorder_rules(struct pfctl *, struct superblock *, int);
    224       1.1   yamt int	rules_combineable(struct pf_rule *, struct pf_rule *);
    225       1.1   yamt void	skip_append(struct superblock *, int, struct pf_skip_step *,
    226       1.1   yamt 	    struct pf_opt_rule *);
    227       1.1   yamt int	skip_compare(int, struct pf_skip_step *, struct pf_opt_rule *);
    228       1.1   yamt void	skip_init(void);
    229       1.1   yamt int	skip_cmp_af(struct pf_rule *, struct pf_rule *);
    230       1.1   yamt int	skip_cmp_dir(struct pf_rule *, struct pf_rule *);
    231       1.1   yamt int	skip_cmp_dst_addr(struct pf_rule *, struct pf_rule *);
    232       1.1   yamt int	skip_cmp_dst_port(struct pf_rule *, struct pf_rule *);
    233       1.1   yamt int	skip_cmp_ifp(struct pf_rule *, struct pf_rule *);
    234       1.1   yamt int	skip_cmp_proto(struct pf_rule *, struct pf_rule *);
    235       1.1   yamt int	skip_cmp_src_addr(struct pf_rule *, struct pf_rule *);
    236       1.1   yamt int	skip_cmp_src_port(struct pf_rule *, struct pf_rule *);
    237       1.1   yamt int	superblock_inclusive(struct superblock *, struct pf_opt_rule *);
    238       1.1   yamt void	superblock_free(struct pfctl *, struct superblock *);
    239       1.1   yamt 
    240       1.1   yamt 
    241       1.1   yamt int (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *, struct pf_rule *);
    242       1.1   yamt const char *skip_comparitors_names[PF_SKIP_COUNT];
    243       1.1   yamt #define PF_SKIP_COMPARITORS {				\
    244       1.1   yamt     { "ifp", PF_SKIP_IFP, skip_cmp_ifp },		\
    245       1.1   yamt     { "dir", PF_SKIP_DIR, skip_cmp_dir },		\
    246       1.1   yamt     { "af", PF_SKIP_AF, skip_cmp_af },			\
    247       1.1   yamt     { "proto", PF_SKIP_PROTO, skip_cmp_proto },		\
    248       1.1   yamt     { "saddr", PF_SKIP_SRC_ADDR, skip_cmp_src_addr },	\
    249       1.1   yamt     { "sport", PF_SKIP_SRC_PORT, skip_cmp_src_port },	\
    250       1.1   yamt     { "daddr", PF_SKIP_DST_ADDR, skip_cmp_dst_addr },	\
    251       1.1   yamt     { "dport", PF_SKIP_DST_PORT, skip_cmp_dst_port }	\
    252       1.1   yamt }
    253       1.1   yamt 
    254       1.1   yamt struct pfr_buffer table_buffer;
    255       1.1   yamt int table_identifier;
    256       1.1   yamt 
    257       1.1   yamt 
    258       1.1   yamt int
    259  1.5.20.1   yamt pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs)
    260       1.1   yamt {
    261       1.1   yamt 	struct superblocks superblocks;
    262  1.5.20.1   yamt 	struct pf_opt_queue opt_queue;
    263       1.1   yamt 	struct superblock *block;
    264       1.1   yamt 	struct pf_opt_rule *por;
    265  1.5.20.1   yamt 	struct pf_rule *r;
    266  1.5.20.1   yamt 	struct pf_rulequeue *old_rules;
    267       1.1   yamt 
    268       1.1   yamt 	DEBUG("optimizing ruleset");
    269       1.1   yamt 	memset(&table_buffer, 0, sizeof(table_buffer));
    270       1.1   yamt 	skip_init();
    271  1.5.20.1   yamt 	TAILQ_INIT(&opt_queue);
    272       1.1   yamt 
    273  1.5.20.1   yamt 	old_rules = rs->rules[PF_RULESET_FILTER].active.ptr;
    274  1.5.20.1   yamt 	rs->rules[PF_RULESET_FILTER].active.ptr =
    275  1.5.20.1   yamt 	    rs->rules[PF_RULESET_FILTER].inactive.ptr;
    276  1.5.20.1   yamt 	rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules;
    277  1.5.20.1   yamt 
    278  1.5.20.1   yamt 	/*
    279  1.5.20.1   yamt 	 * XXX expanding the pf_opt_rule format throughout pfctl might allow
    280  1.5.20.1   yamt 	 * us to avoid all this copying.
    281  1.5.20.1   yamt 	 */
    282  1.5.20.1   yamt 	while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr))
    283  1.5.20.1   yamt 	    != NULL) {
    284  1.5.20.1   yamt 		TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r,
    285  1.5.20.1   yamt 		    entries);
    286  1.5.20.1   yamt 		if ((por = calloc(1, sizeof(*por))) == NULL)
    287  1.5.20.1   yamt 			err(1, "calloc");
    288  1.5.20.1   yamt 		memcpy(&por->por_rule, r, sizeof(*r));
    289  1.5.20.1   yamt 		if (TAILQ_FIRST(&r->rpool.list) != NULL) {
    290  1.5.20.1   yamt 			TAILQ_INIT(&por->por_rule.rpool.list);
    291  1.5.20.1   yamt 			pfctl_move_pool(&r->rpool, &por->por_rule.rpool);
    292  1.5.20.1   yamt 		} else
    293  1.5.20.1   yamt 			bzero(&por->por_rule.rpool,
    294  1.5.20.1   yamt 			    sizeof(por->por_rule.rpool));
    295  1.5.20.1   yamt 
    296  1.5.20.1   yamt 
    297  1.5.20.1   yamt 		TAILQ_INSERT_TAIL(&opt_queue, por, por_entry);
    298  1.5.20.1   yamt 	}
    299       1.1   yamt 
    300       1.1   yamt 	TAILQ_INIT(&superblocks);
    301  1.5.20.1   yamt 	if (construct_superblocks(pf, &opt_queue, &superblocks))
    302       1.1   yamt 		goto error;
    303       1.1   yamt 
    304  1.5.20.1   yamt 	if (pf->optimize & PF_OPTIMIZE_PROFILE) {
    305       1.1   yamt 		if (load_feedback_profile(pf, &superblocks))
    306       1.1   yamt 			goto error;
    307       1.1   yamt 	}
    308       1.1   yamt 
    309       1.1   yamt 	TAILQ_FOREACH(block, &superblocks, sb_entry) {
    310       1.1   yamt 		if (optimize_superblock(pf, block))
    311       1.1   yamt 			goto error;
    312       1.1   yamt 	}
    313       1.1   yamt 
    314  1.5.20.1   yamt 	rs->anchor->refcnt = 0;
    315       1.1   yamt 	while ((block = TAILQ_FIRST(&superblocks))) {
    316       1.1   yamt 		TAILQ_REMOVE(&superblocks, block, sb_entry);
    317       1.1   yamt 
    318       1.1   yamt 		while ((por = TAILQ_FIRST(&block->sb_rules))) {
    319       1.1   yamt 			TAILQ_REMOVE(&block->sb_rules, por, por_entry);
    320  1.5.20.1   yamt 			por->por_rule.nr = rs->anchor->refcnt++;
    321  1.5.20.1   yamt 			if ((r = calloc(1, sizeof(*r))) == NULL)
    322  1.5.20.1   yamt 				err(1, "calloc");
    323  1.5.20.1   yamt 			memcpy(r, &por->por_rule, sizeof(*r));
    324  1.5.20.1   yamt 			TAILQ_INIT(&r->rpool.list);
    325  1.5.20.1   yamt 			pfctl_move_pool(&por->por_rule.rpool, &r->rpool);
    326  1.5.20.1   yamt 			TAILQ_INSERT_TAIL(
    327  1.5.20.1   yamt 			    rs->rules[PF_RULESET_FILTER].active.ptr,
    328  1.5.20.1   yamt 			    r, entries);
    329       1.1   yamt 			free(por);
    330       1.1   yamt 		}
    331       1.1   yamt 		free(block);
    332       1.1   yamt 	}
    333       1.1   yamt 
    334       1.1   yamt 	return (0);
    335       1.1   yamt 
    336       1.1   yamt error:
    337  1.5.20.1   yamt 	while ((por = TAILQ_FIRST(&opt_queue))) {
    338  1.5.20.1   yamt 		TAILQ_REMOVE(&opt_queue, por, por_entry);
    339       1.1   yamt 		if (por->por_src_tbl) {
    340       1.1   yamt 			pfr_buf_clear(por->por_src_tbl->pt_buf);
    341       1.1   yamt 			free(por->por_src_tbl->pt_buf);
    342       1.1   yamt 			free(por->por_src_tbl);
    343       1.1   yamt 		}
    344       1.1   yamt 		if (por->por_dst_tbl) {
    345       1.1   yamt 			pfr_buf_clear(por->por_dst_tbl->pt_buf);
    346       1.1   yamt 			free(por->por_dst_tbl->pt_buf);
    347       1.1   yamt 			free(por->por_dst_tbl);
    348       1.1   yamt 		}
    349       1.1   yamt 		free(por);
    350       1.1   yamt 	}
    351       1.1   yamt 	while ((block = TAILQ_FIRST(&superblocks))) {
    352       1.1   yamt 		TAILQ_REMOVE(&superblocks, block, sb_entry);
    353       1.1   yamt 		superblock_free(pf, block);
    354       1.1   yamt 	}
    355       1.1   yamt 	return (1);
    356       1.1   yamt }
    357       1.1   yamt 
    358       1.1   yamt 
    359       1.1   yamt /*
    360       1.1   yamt  * Go ahead and optimize a superblock
    361       1.1   yamt  */
    362       1.1   yamt int
    363       1.1   yamt optimize_superblock(struct pfctl *pf, struct superblock *block)
    364       1.1   yamt {
    365       1.1   yamt #ifdef OPT_DEBUG
    366       1.1   yamt 	struct pf_opt_rule *por;
    367       1.1   yamt #endif /* OPT_DEBUG */
    368       1.1   yamt 
    369       1.1   yamt 	/* We have a few optimization passes:
    370       1.1   yamt 	 *   1) remove duplicate rules or rules that are a subset of other
    371       1.1   yamt 	 *      rules
    372       1.1   yamt 	 *   2) combine otherwise identical rules with different IP addresses
    373       1.1   yamt 	 *      into a single rule and put the addresses in a table.
    374       1.1   yamt 	 *   3) re-order the rules to improve kernel skip steps
    375       1.1   yamt 	 *   4) re-order the 'quick' rules based on feedback from the
    376       1.1   yamt 	 *      active ruleset statistics
    377       1.1   yamt 	 *
    378       1.1   yamt 	 * XXX combine_rules() doesn't combine v4 and v6 rules.  would just
    379       1.1   yamt 	 *     have to keep af in the table container, make af 'COMBINE' and
    380       1.1   yamt 	 *     twiddle the af on the merged rule
    381       1.1   yamt 	 * XXX maybe add a weighting to the metric on skipsteps when doing
    382       1.1   yamt 	 *     reordering.  sometimes two sequential tables will be better
    383       1.1   yamt 	 *     that four consecutive interfaces.
    384       1.1   yamt 	 * XXX need to adjust the skipstep count of everything after PROTO,
    385       1.1   yamt 	 *     since they aren't actually checked on a proto mismatch in
    386       1.1   yamt 	 *     pf_test_{tcp, udp, icmp}()
    387       1.1   yamt 	 * XXX should i treat proto=0, af=0 or dir=0 special in skepstep
    388       1.1   yamt 	 *     calculation since they are a DC?
    389       1.1   yamt 	 * XXX keep last skiplist of last superblock to influence this
    390       1.1   yamt 	 *     superblock.  '5 inet6 log' should make '3 inet6' come before '4
    391       1.1   yamt 	 *     inet' in the next superblock.
    392       1.1   yamt 	 * XXX would be useful to add tables for ports
    393       1.1   yamt 	 * XXX we can also re-order some mutually exclusive superblocks to
    394       1.1   yamt 	 *     try merging superblocks before any of these optimization passes.
    395       1.1   yamt 	 *     for instance a single 'log in' rule in the middle of non-logging
    396       1.1   yamt 	 *     out rules.
    397       1.1   yamt 	 */
    398       1.1   yamt 
    399       1.1   yamt 	/* shortcut.  there will be alot of 1-rule superblocks */
    400       1.1   yamt 	if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry))
    401       1.1   yamt 		return (0);
    402       1.1   yamt 
    403       1.1   yamt #ifdef OPT_DEBUG
    404       1.1   yamt 	printf("--- Superblock ---\n");
    405       1.1   yamt 	TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
    406       1.1   yamt 		printf("  ");
    407  1.5.20.1   yamt 		print_rule(&por->por_rule, por->por_rule.anchor ?
    408  1.5.20.1   yamt 		    por->por_rule.anchor->name : "", 1);
    409       1.1   yamt 	}
    410       1.1   yamt #endif /* OPT_DEBUG */
    411       1.1   yamt 
    412       1.1   yamt 
    413       1.1   yamt 	if (remove_identical_rules(pf, block))
    414       1.1   yamt 		return (1);
    415       1.1   yamt 	if (combine_rules(pf, block))
    416       1.1   yamt 		return (1);
    417  1.5.20.1   yamt 	if ((pf->optimize & PF_OPTIMIZE_PROFILE) &&
    418       1.1   yamt 	    TAILQ_FIRST(&block->sb_rules)->por_rule.quick &&
    419       1.1   yamt 	    block->sb_profiled_block) {
    420       1.1   yamt 		if (block_feedback(pf, block))
    421       1.1   yamt 			return (1);
    422       1.1   yamt 	} else if (reorder_rules(pf, block, 0)) {
    423       1.1   yamt 		return (1);
    424       1.1   yamt 	}
    425       1.1   yamt 
    426       1.1   yamt 	/*
    427       1.1   yamt 	 * Don't add any optimization passes below reorder_rules().  It will
    428       1.1   yamt 	 * have divided superblocks into smaller blocks for further refinement
    429       1.1   yamt 	 * and doesn't put them back together again.  What once was a true
    430       1.1   yamt 	 * superblock might have been split into multiple superblocks.
    431       1.1   yamt 	 */
    432       1.1   yamt 
    433       1.1   yamt #ifdef OPT_DEBUG
    434       1.1   yamt 	printf("--- END Superblock ---\n");
    435       1.1   yamt #endif /* OPT_DEBUG */
    436       1.1   yamt 	return (0);
    437       1.1   yamt }
    438       1.1   yamt 
    439       1.1   yamt 
    440       1.1   yamt /*
    441       1.1   yamt  * Optimization pass #1: remove identical rules
    442       1.1   yamt  */
    443       1.1   yamt int
    444       1.1   yamt remove_identical_rules(struct pfctl *pf, struct superblock *block)
    445       1.1   yamt {
    446       1.1   yamt 	struct pf_opt_rule *por1, *por2, *por_next, *por2_next;
    447       1.1   yamt 	struct pf_rule a, a2, b, b2;
    448       1.1   yamt 
    449       1.1   yamt 	for (por1 = TAILQ_FIRST(&block->sb_rules); por1; por1 = por_next) {
    450       1.1   yamt 		por_next = TAILQ_NEXT(por1, por_entry);
    451       1.1   yamt 		for (por2 = por_next; por2; por2 = por2_next) {
    452       1.1   yamt 			por2_next = TAILQ_NEXT(por2, por_entry);
    453       1.1   yamt 			comparable_rule(&a, &por1->por_rule, DC);
    454       1.1   yamt 			comparable_rule(&b, &por2->por_rule, DC);
    455       1.1   yamt 			memcpy(&a2, &a, sizeof(a2));
    456       1.1   yamt 			memcpy(&b2, &b, sizeof(b2));
    457       1.1   yamt 
    458       1.1   yamt 			exclude_supersets(&a, &b);
    459       1.1   yamt 			exclude_supersets(&b2, &a2);
    460       1.1   yamt 			if (memcmp(&a, &b, sizeof(a)) == 0) {
    461       1.1   yamt 				DEBUG("removing identical rule  nr%d = *nr%d*",
    462       1.1   yamt 				    por1->por_rule.nr, por2->por_rule.nr);
    463       1.1   yamt 				TAILQ_REMOVE(&block->sb_rules, por2, por_entry);
    464       1.1   yamt 				if (por_next == por2)
    465       1.1   yamt 					por_next = TAILQ_NEXT(por1, por_entry);
    466       1.1   yamt 				free(por2);
    467       1.1   yamt 			} else if (memcmp(&a2, &b2, sizeof(a2)) == 0) {
    468       1.1   yamt 				DEBUG("removing identical rule  *nr%d* = nr%d",
    469       1.1   yamt 				    por1->por_rule.nr, por2->por_rule.nr);
    470       1.1   yamt 				TAILQ_REMOVE(&block->sb_rules, por1, por_entry);
    471       1.1   yamt 				free(por1);
    472       1.1   yamt 				break;
    473       1.1   yamt 			}
    474       1.1   yamt 		}
    475       1.1   yamt 	}
    476       1.1   yamt 
    477       1.1   yamt 	return (0);
    478       1.1   yamt }
    479       1.1   yamt 
    480       1.1   yamt 
    481       1.1   yamt /*
    482       1.1   yamt  * Optimization pass #2: combine similar rules with different addresses
    483       1.1   yamt  * into a single rule and a table
    484       1.1   yamt  */
    485       1.1   yamt int
    486       1.1   yamt combine_rules(struct pfctl *pf, struct superblock *block)
    487       1.1   yamt {
    488       1.1   yamt 	struct pf_opt_rule *p1, *p2, *por_next;
    489       1.1   yamt 	int src_eq, dst_eq;
    490       1.1   yamt 
    491       1.1   yamt 	if ((pf->loadopt & PFCTL_FLAG_TABLE) == 0) {
    492       1.1   yamt 		warnx("Must enable table loading for optimizations");
    493       1.1   yamt 		return (1);
    494       1.1   yamt 	}
    495       1.1   yamt 
    496       1.1   yamt 	/* First we make a pass to combine the rules.  O(n log n) */
    497       1.1   yamt 	TAILQ_FOREACH(p1, &block->sb_rules, por_entry) {
    498       1.1   yamt 		for (p2 = TAILQ_NEXT(p1, por_entry); p2; p2 = por_next) {
    499       1.1   yamt 			por_next = TAILQ_NEXT(p2, por_entry);
    500       1.1   yamt 
    501       1.1   yamt 			src_eq = addrs_equal(&p1->por_rule.src,
    502       1.1   yamt 			    &p2->por_rule.src);
    503       1.1   yamt 			dst_eq = addrs_equal(&p1->por_rule.dst,
    504       1.1   yamt 			    &p2->por_rule.dst);
    505       1.1   yamt 
    506       1.1   yamt 			if (src_eq && !dst_eq && p1->por_src_tbl == NULL &&
    507       1.1   yamt 			    p2->por_dst_tbl == NULL &&
    508       1.5  peter 			    p2->por_src_tbl == NULL &&
    509       1.1   yamt 			    rules_combineable(&p1->por_rule, &p2->por_rule) &&
    510       1.1   yamt 			    addrs_combineable(&p1->por_rule.dst,
    511       1.1   yamt 			    &p2->por_rule.dst)) {
    512       1.1   yamt 				DEBUG("can combine rules  nr%d = nr%d",
    513       1.1   yamt 				    p1->por_rule.nr, p2->por_rule.nr);
    514       1.1   yamt 				if (p1->por_dst_tbl == NULL &&
    515       1.1   yamt 				    add_opt_table(pf, &p1->por_dst_tbl,
    516       1.1   yamt 				    p1->por_rule.af, &p1->por_rule.dst))
    517       1.1   yamt 					return (1);
    518       1.1   yamt 				if (add_opt_table(pf, &p1->por_dst_tbl,
    519       1.1   yamt 				    p1->por_rule.af, &p2->por_rule.dst))
    520       1.1   yamt 					return (1);
    521       1.1   yamt 				p2->por_dst_tbl = p1->por_dst_tbl;
    522       1.1   yamt 				if (p1->por_dst_tbl->pt_rulecount >=
    523       1.1   yamt 				    TABLE_THRESHOLD) {
    524       1.1   yamt 					TAILQ_REMOVE(&block->sb_rules, p2,
    525       1.1   yamt 					    por_entry);
    526       1.1   yamt 					free(p2);
    527       1.1   yamt 				}
    528       1.1   yamt 			} else if (!src_eq && dst_eq && p1->por_dst_tbl == NULL
    529       1.1   yamt 			    && p2->por_src_tbl == NULL &&
    530       1.5  peter 			    p2->por_dst_tbl == NULL &&
    531       1.1   yamt 			    rules_combineable(&p1->por_rule, &p2->por_rule) &&
    532       1.1   yamt 			    addrs_combineable(&p1->por_rule.src,
    533       1.1   yamt 			    &p2->por_rule.src)) {
    534       1.1   yamt 				DEBUG("can combine rules  nr%d = nr%d",
    535       1.1   yamt 				    p1->por_rule.nr, p2->por_rule.nr);
    536       1.1   yamt 				if (p1->por_src_tbl == NULL &&
    537       1.1   yamt 				    add_opt_table(pf, &p1->por_src_tbl,
    538       1.1   yamt 				    p1->por_rule.af, &p1->por_rule.src))
    539       1.1   yamt 					return (1);
    540       1.1   yamt 				if (add_opt_table(pf, &p1->por_src_tbl,
    541       1.1   yamt 				    p1->por_rule.af, &p2->por_rule.src))
    542       1.1   yamt 					return (1);
    543       1.1   yamt 				p2->por_src_tbl = p1->por_src_tbl;
    544       1.1   yamt 				if (p1->por_src_tbl->pt_rulecount >=
    545       1.1   yamt 				    TABLE_THRESHOLD) {
    546       1.1   yamt 					TAILQ_REMOVE(&block->sb_rules, p2,
    547       1.1   yamt 					    por_entry);
    548       1.1   yamt 					free(p2);
    549       1.1   yamt 				}
    550       1.1   yamt 			}
    551       1.1   yamt 		}
    552       1.1   yamt 	}
    553       1.1   yamt 
    554       1.1   yamt 
    555       1.1   yamt 	/*
    556       1.1   yamt 	 * Then we make a final pass to create a valid table name and
    557       1.1   yamt 	 * insert the name into the rules.
    558       1.1   yamt 	 */
    559       1.1   yamt 	for (p1 = TAILQ_FIRST(&block->sb_rules); p1; p1 = por_next) {
    560       1.1   yamt 		por_next = TAILQ_NEXT(p1, por_entry);
    561       1.1   yamt 		assert(p1->por_src_tbl == NULL || p1->por_dst_tbl == NULL);
    562       1.1   yamt 
    563       1.1   yamt 		if (p1->por_src_tbl && p1->por_src_tbl->pt_rulecount >=
    564       1.1   yamt 		    TABLE_THRESHOLD) {
    565       1.1   yamt 			if (p1->por_src_tbl->pt_generated) {
    566       1.1   yamt 				/* This rule is included in a table */
    567       1.1   yamt 				TAILQ_REMOVE(&block->sb_rules, p1, por_entry);
    568       1.1   yamt 				free(p1);
    569       1.1   yamt 				continue;
    570       1.1   yamt 			}
    571       1.1   yamt 			p1->por_src_tbl->pt_generated = 1;
    572       1.1   yamt 
    573       1.1   yamt 			if ((pf->opts & PF_OPT_NOACTION) == 0 &&
    574       1.1   yamt 			    pf_opt_create_table(pf, p1->por_src_tbl))
    575       1.1   yamt 				return (1);
    576       1.1   yamt 
    577       1.1   yamt 			pf->tdirty = 1;
    578       1.1   yamt 
    579       1.1   yamt 			if (pf->opts & PF_OPT_VERBOSE)
    580       1.1   yamt 				print_tabledef(p1->por_src_tbl->pt_name,
    581       1.1   yamt 				    PFR_TFLAG_CONST, 1,
    582       1.1   yamt 				    &p1->por_src_tbl->pt_nodes);
    583       1.1   yamt 
    584       1.1   yamt 			memset(&p1->por_rule.src.addr, 0,
    585       1.1   yamt 			    sizeof(p1->por_rule.src.addr));
    586       1.1   yamt 			p1->por_rule.src.addr.type = PF_ADDR_TABLE;
    587       1.1   yamt 			strlcpy(p1->por_rule.src.addr.v.tblname,
    588       1.1   yamt 			    p1->por_src_tbl->pt_name,
    589       1.1   yamt 			    sizeof(p1->por_rule.src.addr.v.tblname));
    590       1.1   yamt 
    591       1.1   yamt 			pfr_buf_clear(p1->por_src_tbl->pt_buf);
    592       1.1   yamt 			free(p1->por_src_tbl->pt_buf);
    593       1.1   yamt 			p1->por_src_tbl->pt_buf = NULL;
    594       1.1   yamt 		}
    595       1.1   yamt 		if (p1->por_dst_tbl && p1->por_dst_tbl->pt_rulecount >=
    596       1.1   yamt 		    TABLE_THRESHOLD) {
    597       1.1   yamt 			if (p1->por_dst_tbl->pt_generated) {
    598       1.1   yamt 				/* This rule is included in a table */
    599       1.1   yamt 				TAILQ_REMOVE(&block->sb_rules, p1, por_entry);
    600       1.1   yamt 				free(p1);
    601       1.1   yamt 				continue;
    602       1.1   yamt 			}
    603       1.1   yamt 			p1->por_dst_tbl->pt_generated = 1;
    604       1.1   yamt 
    605       1.1   yamt 			if ((pf->opts & PF_OPT_NOACTION) == 0 &&
    606       1.1   yamt 			    pf_opt_create_table(pf, p1->por_dst_tbl))
    607       1.1   yamt 				return (1);
    608       1.1   yamt 			pf->tdirty = 1;
    609       1.1   yamt 
    610       1.1   yamt 			if (pf->opts & PF_OPT_VERBOSE)
    611       1.1   yamt 				print_tabledef(p1->por_dst_tbl->pt_name,
    612       1.1   yamt 				    PFR_TFLAG_CONST, 1,
    613       1.1   yamt 				    &p1->por_dst_tbl->pt_nodes);
    614       1.1   yamt 
    615       1.1   yamt 			memset(&p1->por_rule.dst.addr, 0,
    616       1.1   yamt 			    sizeof(p1->por_rule.dst.addr));
    617       1.1   yamt 			p1->por_rule.dst.addr.type = PF_ADDR_TABLE;
    618       1.1   yamt 			strlcpy(p1->por_rule.dst.addr.v.tblname,
    619       1.1   yamt 			    p1->por_dst_tbl->pt_name,
    620       1.1   yamt 			    sizeof(p1->por_rule.dst.addr.v.tblname));
    621       1.1   yamt 
    622       1.1   yamt 			pfr_buf_clear(p1->por_dst_tbl->pt_buf);
    623       1.1   yamt 			free(p1->por_dst_tbl->pt_buf);
    624       1.1   yamt 			p1->por_dst_tbl->pt_buf = NULL;
    625       1.1   yamt 		}
    626       1.1   yamt 	}
    627       1.1   yamt 
    628       1.1   yamt 	return (0);
    629       1.1   yamt }
    630       1.1   yamt 
    631       1.1   yamt 
    632       1.1   yamt /*
    633       1.1   yamt  * Optimization pass #3: re-order rules to improve skip steps
    634       1.1   yamt  */
    635       1.1   yamt int
    636       1.1   yamt reorder_rules(struct pfctl *pf, struct superblock *block, int depth)
    637       1.1   yamt {
    638       1.1   yamt 	struct superblock *newblock;
    639       1.1   yamt 	struct pf_skip_step *skiplist;
    640       1.1   yamt 	struct pf_opt_rule *por;
    641       1.4  lukem 	int i, largest, largest_list = -1, rule_count = 0;
    642       1.1   yamt 	TAILQ_HEAD( , pf_opt_rule) head;
    643       1.1   yamt 
    644       1.1   yamt 	/*
    645       1.1   yamt 	 * Calculate the best-case skip steps.  We put each rule in a list
    646       1.1   yamt 	 * of other rules with common fields
    647       1.1   yamt 	 */
    648       1.1   yamt 	for (i = 0; i < PF_SKIP_COUNT; i++) {
    649       1.1   yamt 		TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
    650       1.1   yamt 			TAILQ_FOREACH(skiplist, &block->sb_skipsteps[i],
    651       1.1   yamt 			    ps_entry) {
    652       1.1   yamt 				if (skip_compare(i, skiplist, por) == 0)
    653       1.1   yamt 					break;
    654       1.1   yamt 			}
    655       1.1   yamt 			if (skiplist == NULL) {
    656       1.1   yamt 				if ((skiplist = calloc(1, sizeof(*skiplist))) ==
    657       1.1   yamt 				    NULL)
    658       1.1   yamt 					err(1, "calloc");
    659       1.1   yamt 				TAILQ_INIT(&skiplist->ps_rules);
    660       1.1   yamt 				TAILQ_INSERT_TAIL(&block->sb_skipsteps[i],
    661       1.1   yamt 				    skiplist, ps_entry);
    662       1.1   yamt 			}
    663       1.1   yamt 			skip_append(block, i, skiplist, por);
    664       1.1   yamt 		}
    665       1.1   yamt 	}
    666       1.1   yamt 
    667       1.1   yamt 	TAILQ_FOREACH(por, &block->sb_rules, por_entry)
    668       1.1   yamt 		rule_count++;
    669       1.1   yamt 
    670       1.1   yamt 	/*
    671       1.1   yamt 	 * Now we're going to ignore any fields that are identical between
    672       1.1   yamt 	 * all of the rules in the superblock and those fields which differ
    673       1.1   yamt 	 * between every rule in the superblock.
    674       1.1   yamt 	 */
    675       1.1   yamt 	largest = 0;
    676       1.1   yamt 	for (i = 0; i < PF_SKIP_COUNT; i++) {
    677       1.1   yamt 		skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]);
    678       1.1   yamt 		if (skiplist->ps_count == rule_count) {
    679       1.1   yamt 			DEBUG("(%d) original skipstep '%s' is all rules",
    680       1.1   yamt 			    depth, skip_comparitors_names[i]);
    681       1.1   yamt 			skiplist->ps_count = 0;
    682       1.1   yamt 		} else if (skiplist->ps_count == 1) {
    683       1.1   yamt 			skiplist->ps_count = 0;
    684       1.1   yamt 		} else {
    685       1.1   yamt 			DEBUG("(%d) original skipstep '%s' largest jump is %d",
    686       1.1   yamt 			    depth, skip_comparitors_names[i],
    687       1.1   yamt 			    skiplist->ps_count);
    688       1.1   yamt 			if (skiplist->ps_count > largest)
    689       1.1   yamt 				largest = skiplist->ps_count;
    690       1.1   yamt 		}
    691       1.1   yamt 	}
    692       1.1   yamt 	if (largest == 0) {
    693       1.1   yamt 		/* Ugh.  There is NO commonality in the superblock on which
    694       1.1   yamt 		 * optimize the skipsteps optimization.
    695       1.1   yamt 		 */
    696       1.1   yamt 		goto done;
    697       1.1   yamt 	}
    698       1.1   yamt 
    699       1.1   yamt 	/*
    700       1.1   yamt 	 * Now we're going to empty the superblock rule list and re-create
    701       1.1   yamt 	 * it based on a more optimal skipstep order.
    702       1.1   yamt 	 */
    703       1.1   yamt 	TAILQ_INIT(&head);
    704       1.1   yamt 	while ((por = TAILQ_FIRST(&block->sb_rules))) {
    705       1.1   yamt 		TAILQ_REMOVE(&block->sb_rules, por, por_entry);
    706       1.1   yamt 		TAILQ_INSERT_TAIL(&head, por, por_entry);
    707       1.1   yamt 	}
    708       1.1   yamt 
    709       1.1   yamt 
    710       1.1   yamt 	while (!TAILQ_EMPTY(&head)) {
    711       1.1   yamt 		largest = 1;
    712       1.1   yamt 
    713       1.1   yamt 		/*
    714       1.1   yamt 		 * Find the most useful skip steps remaining
    715       1.1   yamt 		 */
    716       1.1   yamt 		for (i = 0; i < PF_SKIP_COUNT; i++) {
    717       1.1   yamt 			skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]);
    718       1.1   yamt 			if (skiplist->ps_count > largest) {
    719       1.1   yamt 				largest = skiplist->ps_count;
    720       1.1   yamt 				largest_list = i;
    721       1.1   yamt 			}
    722       1.1   yamt 		}
    723       1.1   yamt 
    724       1.1   yamt 		if (largest <= 1) {
    725       1.1   yamt 			/*
    726       1.1   yamt 			 * Nothing useful left.  Leave remaining rules in order.
    727       1.1   yamt 			 */
    728       1.1   yamt 			DEBUG("(%d) no more commonality for skip steps", depth);
    729       1.1   yamt 			while ((por = TAILQ_FIRST(&head))) {
    730       1.1   yamt 				TAILQ_REMOVE(&head, por, por_entry);
    731       1.1   yamt 				TAILQ_INSERT_TAIL(&block->sb_rules, por,
    732       1.1   yamt 				    por_entry);
    733       1.1   yamt 			}
    734       1.1   yamt 		} else {
    735       1.1   yamt 			/*
    736       1.1   yamt 			 * There is commonality.  Extract those common rules
    737       1.1   yamt 			 * and place them in the ruleset adjacent to each
    738       1.1   yamt 			 * other.
    739       1.1   yamt 			 */
    740       1.1   yamt 			skiplist = TAILQ_FIRST(&block->sb_skipsteps[
    741       1.1   yamt 			    largest_list]);
    742       1.1   yamt 			DEBUG("(%d) skipstep '%s' largest jump is %d @ #%d",
    743       1.1   yamt 			    depth, skip_comparitors_names[largest_list],
    744       1.1   yamt 			    largest, TAILQ_FIRST(&TAILQ_FIRST(&block->
    745       1.1   yamt 			    sb_skipsteps [largest_list])->ps_rules)->
    746       1.1   yamt 			    por_rule.nr);
    747       1.1   yamt 			TAILQ_REMOVE(&block->sb_skipsteps[largest_list],
    748       1.1   yamt 			    skiplist, ps_entry);
    749       1.1   yamt 
    750       1.1   yamt 
    751       1.1   yamt 			/*
    752       1.1   yamt 			 * There may be further commonality inside these
    753       1.1   yamt 			 * rules.  So we'll split them off into they're own
    754       1.1   yamt 			 * superblock and pass it back into the optimizer.
    755       1.1   yamt 			 */
    756       1.1   yamt 			if (skiplist->ps_count > 2) {
    757       1.1   yamt 				if ((newblock = calloc(1, sizeof(*newblock)))
    758       1.1   yamt 				    == NULL) {
    759       1.1   yamt 					warn("calloc");
    760       1.1   yamt 					return (1);
    761       1.1   yamt 				}
    762       1.1   yamt 				TAILQ_INIT(&newblock->sb_rules);
    763       1.1   yamt 				for (i = 0; i < PF_SKIP_COUNT; i++)
    764       1.1   yamt 					TAILQ_INIT(&newblock->sb_skipsteps[i]);
    765       1.1   yamt 				TAILQ_INSERT_BEFORE(block, newblock, sb_entry);
    766       1.1   yamt 				DEBUG("(%d) splitting off %d rules from superblock @ #%d",
    767       1.1   yamt 				    depth, skiplist->ps_count,
    768       1.1   yamt 				    TAILQ_FIRST(&skiplist->ps_rules)->
    769       1.1   yamt 				    por_rule.nr);
    770       1.1   yamt 			} else {
    771       1.1   yamt 				newblock = block;
    772       1.1   yamt 			}
    773       1.1   yamt 
    774       1.1   yamt 			while ((por = TAILQ_FIRST(&skiplist->ps_rules))) {
    775       1.1   yamt 				TAILQ_REMOVE(&head, por, por_entry);
    776       1.1   yamt 				TAILQ_REMOVE(&skiplist->ps_rules, por,
    777       1.1   yamt 				    por_skip_entry[largest_list]);
    778       1.1   yamt 				TAILQ_INSERT_TAIL(&newblock->sb_rules, por,
    779       1.1   yamt 				    por_entry);
    780       1.1   yamt 
    781       1.1   yamt 				/* Remove this rule from all other skiplists */
    782       1.1   yamt 				remove_from_skipsteps(&block->sb_skipsteps[
    783       1.1   yamt 				    largest_list], block, por, skiplist);
    784       1.1   yamt 			}
    785       1.1   yamt 			free(skiplist);
    786       1.1   yamt 			if (newblock != block)
    787       1.1   yamt 				if (reorder_rules(pf, newblock, depth + 1))
    788       1.1   yamt 					return (1);
    789       1.1   yamt 		}
    790       1.1   yamt 	}
    791       1.1   yamt 
    792       1.1   yamt done:
    793       1.1   yamt 	for (i = 0; i < PF_SKIP_COUNT; i++) {
    794       1.1   yamt 		while ((skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]))) {
    795       1.1   yamt 			TAILQ_REMOVE(&block->sb_skipsteps[i], skiplist,
    796       1.1   yamt 			    ps_entry);
    797       1.1   yamt 			free(skiplist);
    798       1.1   yamt 		}
    799       1.1   yamt 	}
    800       1.1   yamt 
    801       1.1   yamt 	return (0);
    802       1.1   yamt }
    803       1.1   yamt 
    804       1.1   yamt 
    805       1.1   yamt /*
    806       1.1   yamt  * Optimization pass #4: re-order 'quick' rules based on feedback from the
    807       1.1   yamt  * currently running ruleset
    808       1.1   yamt  */
    809       1.1   yamt int
    810       1.1   yamt block_feedback(struct pfctl *pf, struct superblock *block)
    811       1.1   yamt {
    812       1.1   yamt 	TAILQ_HEAD( , pf_opt_rule) queue;
    813       1.1   yamt 	struct pf_opt_rule *por1, *por2;
    814       1.1   yamt 	u_int64_t total_count = 0;
    815       1.1   yamt 	struct pf_rule a, b;
    816       1.1   yamt 
    817       1.1   yamt 
    818       1.1   yamt 	/*
    819       1.1   yamt 	 * Walk through all of the profiled superblock's rules and copy
    820       1.1   yamt 	 * the counters onto our rules.
    821       1.1   yamt 	 */
    822       1.1   yamt 	TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) {
    823       1.1   yamt 		comparable_rule(&a, &por1->por_rule, DC);
    824  1.5.20.1   yamt 		total_count += por1->por_rule.packets[0] +
    825  1.5.20.1   yamt 		    por1->por_rule.packets[1];
    826       1.1   yamt 		TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
    827       1.1   yamt 			if (por2->por_profile_count)
    828       1.1   yamt 				continue;
    829       1.1   yamt 			comparable_rule(&b, &por2->por_rule, DC);
    830       1.1   yamt 			if (memcmp(&a, &b, sizeof(a)) == 0) {
    831       1.1   yamt 				por2->por_profile_count =
    832  1.5.20.1   yamt 				    por1->por_rule.packets[0] +
    833  1.5.20.1   yamt 				    por1->por_rule.packets[1];
    834       1.1   yamt 				break;
    835       1.1   yamt 			}
    836       1.1   yamt 		}
    837       1.1   yamt 	}
    838       1.1   yamt 	superblock_free(pf, block->sb_profiled_block);
    839       1.1   yamt 	block->sb_profiled_block = NULL;
    840       1.1   yamt 
    841       1.1   yamt 	/*
    842       1.1   yamt 	 * Now we pull all of the rules off the superblock and re-insert them
    843       1.1   yamt 	 * in sorted order.
    844       1.1   yamt 	 */
    845       1.1   yamt 
    846       1.1   yamt 	TAILQ_INIT(&queue);
    847       1.1   yamt 	while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) {
    848       1.1   yamt 		TAILQ_REMOVE(&block->sb_rules, por1, por_entry);
    849       1.1   yamt 		TAILQ_INSERT_TAIL(&queue, por1, por_entry);
    850       1.1   yamt 	}
    851       1.1   yamt 
    852       1.1   yamt 	while ((por1 = TAILQ_FIRST(&queue)) != NULL) {
    853       1.1   yamt 		TAILQ_REMOVE(&queue, por1, por_entry);
    854       1.1   yamt /* XXX I should sort all of the unused rules based on skip steps */
    855       1.1   yamt 		TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
    856       1.1   yamt 			if (por1->por_profile_count > por2->por_profile_count) {
    857       1.1   yamt 				TAILQ_INSERT_BEFORE(por2, por1, por_entry);
    858       1.1   yamt 				break;
    859       1.1   yamt 			}
    860       1.1   yamt 		}
    861       1.1   yamt 		if (por2 == TAILQ_END(&block->sb_rules))
    862       1.1   yamt 			TAILQ_INSERT_TAIL(&block->sb_rules, por1, por_entry);
    863       1.1   yamt 	}
    864       1.1   yamt 
    865       1.1   yamt 	return (0);
    866       1.1   yamt }
    867       1.1   yamt 
    868       1.1   yamt 
    869       1.1   yamt /*
    870       1.1   yamt  * Load the current ruleset from the kernel and try to associate them with
    871       1.1   yamt  * the ruleset we're optimizing.
    872       1.1   yamt  */
    873       1.1   yamt int
    874       1.1   yamt load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
    875       1.1   yamt {
    876       1.1   yamt 	struct superblock *block, *blockcur;
    877       1.1   yamt 	struct superblocks prof_superblocks;
    878       1.1   yamt 	struct pf_opt_rule *por;
    879       1.1   yamt 	struct pf_opt_queue queue;
    880       1.1   yamt 	struct pfioc_rule pr;
    881       1.1   yamt 	struct pf_rule a, b;
    882       1.1   yamt 	int nr, mnr;
    883       1.1   yamt 
    884       1.1   yamt 	TAILQ_INIT(&queue);
    885       1.1   yamt 	TAILQ_INIT(&prof_superblocks);
    886       1.1   yamt 
    887       1.1   yamt 	memset(&pr, 0, sizeof(pr));
    888       1.1   yamt 	pr.rule.action = PF_PASS;
    889       1.1   yamt 	if (ioctl(pf->dev, DIOCGETRULES, &pr)) {
    890       1.1   yamt 		warn("DIOCGETRULES");
    891       1.1   yamt 		return (1);
    892       1.1   yamt 	}
    893       1.1   yamt 	mnr = pr.nr;
    894       1.1   yamt 
    895       1.1   yamt 	DEBUG("Loading %d active rules for a feedback profile", mnr);
    896       1.1   yamt 	for (nr = 0; nr < mnr; ++nr) {
    897  1.5.20.1   yamt 		struct pf_ruleset *rs;
    898       1.1   yamt 		if ((por = calloc(1, sizeof(*por))) == NULL) {
    899       1.1   yamt 			warn("calloc");
    900       1.1   yamt 			return (1);
    901       1.1   yamt 		}
    902       1.1   yamt 		pr.nr = nr;
    903       1.1   yamt 		if (ioctl(pf->dev, DIOCGETRULE, &pr)) {
    904       1.1   yamt 			warn("DIOCGETRULES");
    905       1.1   yamt 			return (1);
    906       1.1   yamt 		}
    907       1.1   yamt 		memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule));
    908  1.5.20.1   yamt 		rs = pf_find_or_create_ruleset(pr.anchor_call);
    909  1.5.20.1   yamt 		por->por_rule.anchor = rs->anchor;
    910       1.1   yamt 		if (TAILQ_EMPTY(&por->por_rule.rpool.list))
    911       1.1   yamt 			memset(&por->por_rule.rpool, 0,
    912       1.1   yamt 			    sizeof(por->por_rule.rpool));
    913       1.1   yamt 		TAILQ_INSERT_TAIL(&queue, por, por_entry);
    914       1.1   yamt 
    915       1.1   yamt 		/* XXX pfctl_get_pool(pf->dev, &pr.rule.rpool, nr, pr.ticket,
    916       1.1   yamt 		 *         PF_PASS, pf->anchor) ???
    917       1.1   yamt 		 * ... pfctl_clear_pool(&pr.rule.rpool)
    918       1.1   yamt 		 */
    919       1.1   yamt 	}
    920       1.1   yamt 
    921       1.1   yamt 	if (construct_superblocks(pf, &queue, &prof_superblocks))
    922       1.1   yamt 		return (1);
    923       1.1   yamt 
    924       1.1   yamt 
    925       1.1   yamt 	/*
    926       1.1   yamt 	 * Now we try to associate the active ruleset's superblocks with
    927       1.1   yamt 	 * the superblocks we're compiling.
    928       1.1   yamt 	 */
    929       1.1   yamt 	block = TAILQ_FIRST(superblocks);
    930       1.1   yamt 	blockcur = TAILQ_FIRST(&prof_superblocks);
    931       1.1   yamt 	while (block && blockcur) {
    932       1.1   yamt 		comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule,
    933       1.1   yamt 		    BREAK);
    934       1.1   yamt 		comparable_rule(&b, &TAILQ_FIRST(&blockcur->sb_rules)->por_rule,
    935       1.1   yamt 		    BREAK);
    936       1.1   yamt 		if (memcmp(&a, &b, sizeof(a)) == 0) {
    937       1.1   yamt 			/* The two superblocks lined up */
    938       1.1   yamt 			block->sb_profiled_block = blockcur;
    939       1.1   yamt 		} else {
    940       1.1   yamt 			DEBUG("superblocks don't line up between #%d and #%d",
    941       1.1   yamt 			    TAILQ_FIRST(&block->sb_rules)->por_rule.nr,
    942       1.1   yamt 			    TAILQ_FIRST(&blockcur->sb_rules)->por_rule.nr);
    943       1.1   yamt 			break;
    944       1.1   yamt 		}
    945       1.1   yamt 		block = TAILQ_NEXT(block, sb_entry);
    946       1.1   yamt 		blockcur = TAILQ_NEXT(blockcur, sb_entry);
    947       1.1   yamt 	}
    948       1.1   yamt 
    949       1.1   yamt 
    950       1.1   yamt 
    951       1.1   yamt 	/* Free any superblocks we couldn't link */
    952       1.1   yamt 	while (blockcur) {
    953       1.1   yamt 		block = TAILQ_NEXT(blockcur, sb_entry);
    954       1.1   yamt 		superblock_free(pf, blockcur);
    955       1.1   yamt 		blockcur = block;
    956       1.1   yamt 	}
    957       1.1   yamt 	return (0);
    958       1.1   yamt }
    959       1.1   yamt 
    960       1.1   yamt 
    961       1.1   yamt /*
    962       1.1   yamt  * Compare a rule to a skiplist to see if the rule is a member
    963       1.1   yamt  */
    964       1.1   yamt int
    965       1.1   yamt skip_compare(int skipnum, struct pf_skip_step *skiplist,
    966       1.1   yamt     struct pf_opt_rule *por)
    967       1.1   yamt {
    968       1.1   yamt 	struct pf_rule *a, *b;
    969       1.1   yamt 	if (skipnum >= PF_SKIP_COUNT || skipnum < 0)
    970       1.1   yamt 		errx(1, "skip_compare() out of bounds");
    971       1.1   yamt 	a = &por->por_rule;
    972       1.1   yamt 	b = &TAILQ_FIRST(&skiplist->ps_rules)->por_rule;
    973       1.1   yamt 
    974       1.1   yamt 	return ((skip_comparitors[skipnum])(a, b));
    975       1.1   yamt }
    976       1.1   yamt 
    977       1.1   yamt 
    978       1.1   yamt /*
    979       1.1   yamt  * Add a rule to a skiplist
    980       1.1   yamt  */
    981       1.1   yamt void
    982       1.1   yamt skip_append(struct superblock *superblock, int skipnum,
    983       1.1   yamt     struct pf_skip_step *skiplist, struct pf_opt_rule *por)
    984       1.1   yamt {
    985       1.1   yamt 	struct pf_skip_step *prev;
    986       1.1   yamt 
    987       1.1   yamt 	skiplist->ps_count++;
    988       1.1   yamt 	TAILQ_INSERT_TAIL(&skiplist->ps_rules, por, por_skip_entry[skipnum]);
    989       1.1   yamt 
    990       1.1   yamt 	/* Keep the list of skiplists sorted by whichever is larger */
    991       1.1   yamt 	while ((prev = TAILQ_PREV(skiplist, skiplist, ps_entry)) &&
    992       1.1   yamt 	    prev->ps_count < skiplist->ps_count) {
    993       1.1   yamt 		TAILQ_REMOVE(&superblock->sb_skipsteps[skipnum],
    994       1.1   yamt 		    skiplist, ps_entry);
    995       1.1   yamt 		TAILQ_INSERT_BEFORE(prev, skiplist, ps_entry);
    996       1.1   yamt 	}
    997       1.1   yamt }
    998       1.1   yamt 
    999       1.1   yamt 
   1000       1.1   yamt /*
   1001       1.1   yamt  * Remove a rule from the other skiplist calculations.
   1002       1.1   yamt  */
   1003       1.1   yamt void
   1004       1.1   yamt remove_from_skipsteps(struct skiplist *head, struct superblock *block,
   1005       1.1   yamt     struct pf_opt_rule *por, struct pf_skip_step *active_list)
   1006       1.1   yamt {
   1007       1.1   yamt 	struct pf_skip_step *sk, *next;
   1008       1.1   yamt 	struct pf_opt_rule *p2;
   1009       1.1   yamt 	int i, found;
   1010       1.1   yamt 
   1011       1.1   yamt 	for (i = 0; i < PF_SKIP_COUNT; i++) {
   1012       1.1   yamt 		sk = TAILQ_FIRST(&block->sb_skipsteps[i]);
   1013       1.1   yamt 		if (sk == NULL || sk == active_list || sk->ps_count <= 1)
   1014       1.1   yamt 			continue;
   1015       1.1   yamt 		found = 0;
   1016       1.1   yamt 		do {
   1017       1.1   yamt 			TAILQ_FOREACH(p2, &sk->ps_rules, por_skip_entry[i])
   1018       1.1   yamt 				if (p2 == por) {
   1019       1.1   yamt 					TAILQ_REMOVE(&sk->ps_rules, p2,
   1020       1.1   yamt 					    por_skip_entry[i]);
   1021       1.1   yamt 					found = 1;
   1022       1.1   yamt 					sk->ps_count--;
   1023       1.1   yamt 					break;
   1024       1.1   yamt 				}
   1025       1.1   yamt 		} while (!found && (sk = TAILQ_NEXT(sk, ps_entry)));
   1026       1.1   yamt 		if (found && sk) {
   1027       1.1   yamt 			/* Does this change the sorting order? */
   1028       1.1   yamt 			while ((next = TAILQ_NEXT(sk, ps_entry)) &&
   1029       1.1   yamt 			    next->ps_count > sk->ps_count) {
   1030       1.1   yamt 				TAILQ_REMOVE(head, sk, ps_entry);
   1031       1.1   yamt 				TAILQ_INSERT_AFTER(head, next, sk, ps_entry);
   1032       1.1   yamt 			}
   1033       1.1   yamt #ifdef OPT_DEBUG
   1034       1.1   yamt 			next = TAILQ_NEXT(sk, ps_entry);
   1035       1.1   yamt 			assert(next == NULL || next->ps_count <= sk->ps_count);
   1036       1.1   yamt #endif /* OPT_DEBUG */
   1037       1.1   yamt 		}
   1038       1.1   yamt 	}
   1039       1.1   yamt }
   1040       1.1   yamt 
   1041       1.1   yamt 
   1042       1.1   yamt /* Compare two rules AF field for skiplist construction */
   1043       1.1   yamt int
   1044       1.1   yamt skip_cmp_af(struct pf_rule *a, struct pf_rule *b)
   1045       1.1   yamt {
   1046       1.1   yamt 	if (a->af != b->af || a->af == 0)
   1047       1.1   yamt 		return (1);
   1048       1.1   yamt 	return (0);
   1049       1.1   yamt }
   1050       1.1   yamt 
   1051       1.1   yamt /* Compare two rules DIRECTION field for skiplist construction */
   1052       1.1   yamt int
   1053       1.1   yamt skip_cmp_dir(struct pf_rule *a, struct pf_rule *b)
   1054       1.1   yamt {
   1055       1.1   yamt 	if (a->direction == 0 || a->direction != b->direction)
   1056       1.1   yamt 		return (1);
   1057       1.1   yamt 	return (0);
   1058       1.1   yamt }
   1059       1.1   yamt 
   1060       1.1   yamt /* Compare two rules DST Address field for skiplist construction */
   1061       1.1   yamt int
   1062       1.1   yamt skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b)
   1063       1.1   yamt {
   1064       1.1   yamt 	if (a->dst.neg != b->dst.neg ||
   1065       1.1   yamt 	    a->dst.addr.type != b->dst.addr.type)
   1066       1.1   yamt 		return (1);
   1067       1.1   yamt 	/* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
   1068       1.1   yamt 	 *    && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
   1069       1.1   yamt 	 *    a->proto == IPPROTO_ICMP
   1070       1.1   yamt 	 *	return (1);
   1071       1.1   yamt 	 */
   1072       1.1   yamt 	switch (a->dst.addr.type) {
   1073       1.1   yamt 	case PF_ADDR_ADDRMASK:
   1074       1.1   yamt 		if (memcmp(&a->dst.addr.v.a.addr, &b->dst.addr.v.a.addr,
   1075       1.1   yamt 		    sizeof(a->dst.addr.v.a.addr)) ||
   1076       1.1   yamt 		    memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask,
   1077       1.1   yamt 		    sizeof(a->dst.addr.v.a.mask)) ||
   1078       1.1   yamt 		    (a->dst.addr.v.a.addr.addr32[0] == 0 &&
   1079       1.1   yamt 		    a->dst.addr.v.a.addr.addr32[1] == 0 &&
   1080       1.1   yamt 		    a->dst.addr.v.a.addr.addr32[2] == 0 &&
   1081       1.1   yamt 		    a->dst.addr.v.a.addr.addr32[3] == 0))
   1082       1.1   yamt 			return (1);
   1083       1.1   yamt 		return (0);
   1084       1.1   yamt 	case PF_ADDR_DYNIFTL:
   1085       1.1   yamt 		if (strcmp(a->dst.addr.v.ifname, b->dst.addr.v.ifname) != 0 ||
   1086       1.1   yamt 		    a->dst.addr.iflags != a->dst.addr.iflags ||
   1087       1.1   yamt 		    memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask,
   1088       1.1   yamt 		    sizeof(a->dst.addr.v.a.mask)))
   1089       1.1   yamt 			return (1);
   1090       1.1   yamt 		return (0);
   1091       1.1   yamt 	case PF_ADDR_NOROUTE:
   1092  1.5.20.1   yamt 	case PF_ADDR_URPFFAILED:
   1093       1.1   yamt 		return (0);
   1094       1.1   yamt 	case PF_ADDR_TABLE:
   1095       1.1   yamt 		return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname));
   1096       1.1   yamt 	}
   1097       1.1   yamt 	return (1);
   1098       1.1   yamt }
   1099       1.1   yamt 
   1100       1.1   yamt /* Compare two rules DST port field for skiplist construction */
   1101       1.1   yamt int
   1102       1.1   yamt skip_cmp_dst_port(struct pf_rule *a, struct pf_rule *b)
   1103       1.1   yamt {
   1104       1.1   yamt 	/* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
   1105       1.1   yamt 	 *    && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
   1106       1.1   yamt 	 *    a->proto == IPPROTO_ICMP
   1107       1.1   yamt 	 *	return (1);
   1108       1.1   yamt 	 */
   1109       1.1   yamt 	if (a->dst.port_op == PF_OP_NONE || a->dst.port_op != b->dst.port_op ||
   1110       1.1   yamt 	    a->dst.port[0] != b->dst.port[0] ||
   1111       1.1   yamt 	    a->dst.port[1] != b->dst.port[1])
   1112       1.1   yamt 		return (1);
   1113       1.1   yamt 	return (0);
   1114       1.1   yamt }
   1115       1.1   yamt 
   1116       1.1   yamt /* Compare two rules IFP field for skiplist construction */
   1117       1.1   yamt int
   1118       1.1   yamt skip_cmp_ifp(struct pf_rule *a, struct pf_rule *b)
   1119       1.1   yamt {
   1120       1.1   yamt 	if (strcmp(a->ifname, b->ifname) || a->ifname[0] == '\0')
   1121       1.1   yamt 		return (1);
   1122       1.1   yamt 	return (a->ifnot != b->ifnot);
   1123       1.1   yamt }
   1124       1.1   yamt 
   1125       1.1   yamt /* Compare two rules PROTO field for skiplist construction */
   1126       1.1   yamt int
   1127       1.1   yamt skip_cmp_proto(struct pf_rule *a, struct pf_rule *b)
   1128       1.1   yamt {
   1129       1.1   yamt 	return (a->proto != b->proto || a->proto == 0);
   1130       1.1   yamt }
   1131       1.1   yamt 
   1132       1.1   yamt /* Compare two rules SRC addr field for skiplist construction */
   1133       1.1   yamt int
   1134       1.1   yamt skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b)
   1135       1.1   yamt {
   1136       1.1   yamt 	if (a->src.neg != b->src.neg ||
   1137       1.1   yamt 	    a->src.addr.type != b->src.addr.type)
   1138       1.1   yamt 		return (1);
   1139       1.1   yamt 	/* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
   1140       1.1   yamt 	 *    && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
   1141       1.1   yamt 	 *    a->proto == IPPROTO_ICMP
   1142       1.1   yamt 	 *	return (1);
   1143       1.1   yamt 	 */
   1144       1.1   yamt 	switch (a->src.addr.type) {
   1145       1.1   yamt 	case PF_ADDR_ADDRMASK:
   1146       1.1   yamt 		if (memcmp(&a->src.addr.v.a.addr, &b->src.addr.v.a.addr,
   1147       1.1   yamt 		    sizeof(a->src.addr.v.a.addr)) ||
   1148       1.1   yamt 		    memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask,
   1149       1.1   yamt 		    sizeof(a->src.addr.v.a.mask)) ||
   1150       1.1   yamt 		    (a->src.addr.v.a.addr.addr32[0] == 0 &&
   1151       1.1   yamt 		    a->src.addr.v.a.addr.addr32[1] == 0 &&
   1152       1.1   yamt 		    a->src.addr.v.a.addr.addr32[2] == 0 &&
   1153       1.1   yamt 		    a->src.addr.v.a.addr.addr32[3] == 0))
   1154       1.1   yamt 			return (1);
   1155       1.1   yamt 		return (0);
   1156       1.1   yamt 	case PF_ADDR_DYNIFTL:
   1157       1.1   yamt 		if (strcmp(a->src.addr.v.ifname, b->src.addr.v.ifname) != 0 ||
   1158       1.1   yamt 		    a->src.addr.iflags != a->src.addr.iflags ||
   1159       1.1   yamt 		    memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask,
   1160       1.1   yamt 		    sizeof(a->src.addr.v.a.mask)))
   1161       1.1   yamt 			return (1);
   1162       1.1   yamt 		return (0);
   1163       1.1   yamt 	case PF_ADDR_NOROUTE:
   1164  1.5.20.1   yamt 	case PF_ADDR_URPFFAILED:
   1165       1.1   yamt 		return (0);
   1166       1.1   yamt 	case PF_ADDR_TABLE:
   1167       1.1   yamt 		return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname));
   1168       1.1   yamt 	}
   1169       1.1   yamt 	return (1);
   1170       1.1   yamt }
   1171       1.1   yamt 
   1172       1.1   yamt /* Compare two rules SRC port field for skiplist construction */
   1173       1.1   yamt int
   1174       1.1   yamt skip_cmp_src_port(struct pf_rule *a, struct pf_rule *b)
   1175       1.1   yamt {
   1176       1.1   yamt 	if (a->src.port_op == PF_OP_NONE || a->src.port_op != b->src.port_op ||
   1177       1.1   yamt 	    a->src.port[0] != b->src.port[0] ||
   1178       1.1   yamt 	    a->src.port[1] != b->src.port[1])
   1179       1.1   yamt 		return (1);
   1180       1.1   yamt 	/* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
   1181       1.1   yamt 	 *    && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
   1182       1.1   yamt 	 *    a->proto == IPPROTO_ICMP
   1183       1.1   yamt 	 *	return (1);
   1184       1.1   yamt 	 */
   1185       1.1   yamt 	return (0);
   1186       1.1   yamt }
   1187       1.1   yamt 
   1188       1.1   yamt 
   1189       1.1   yamt void
   1190       1.1   yamt skip_init(void)
   1191       1.1   yamt {
   1192       1.1   yamt 	struct {
   1193       1.1   yamt 		char *name;
   1194       1.1   yamt 		int skipnum;
   1195       1.1   yamt 		int (*func)(struct pf_rule *, struct pf_rule *);
   1196       1.1   yamt 	} comps[] = PF_SKIP_COMPARITORS;
   1197       1.1   yamt 	int skipnum, i;
   1198       1.1   yamt 
   1199       1.1   yamt 	for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) {
   1200       1.1   yamt 		for (i = 0; i < sizeof(comps)/sizeof(*comps); i++)
   1201       1.1   yamt 			if (comps[i].skipnum == skipnum) {
   1202       1.1   yamt 				skip_comparitors[skipnum] = comps[i].func;
   1203       1.1   yamt 				skip_comparitors_names[skipnum] = comps[i].name;
   1204       1.1   yamt 			}
   1205       1.1   yamt 	}
   1206       1.1   yamt 	for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++)
   1207       1.1   yamt 		if (skip_comparitors[skipnum] == NULL)
   1208       1.1   yamt 			errx(1, "Need to add skip step comparitor to pfctl?!");
   1209       1.1   yamt }
   1210       1.1   yamt 
   1211       1.1   yamt /*
   1212       1.1   yamt  * Add a host/netmask to a table
   1213       1.1   yamt  */
   1214       1.1   yamt int
   1215       1.1   yamt add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af,
   1216       1.1   yamt     struct pf_rule_addr *addr)
   1217       1.1   yamt {
   1218       1.1   yamt #ifdef OPT_DEBUG
   1219       1.1   yamt 	char buf[128];
   1220       1.1   yamt #endif /* OPT_DEBUG */
   1221       1.1   yamt 	static int tablenum = 0;
   1222       1.1   yamt 	struct node_host node_host;
   1223       1.1   yamt 
   1224       1.1   yamt 	if (*tbl == NULL) {
   1225       1.1   yamt 		if ((*tbl = calloc(1, sizeof(**tbl))) == NULL ||
   1226       1.1   yamt 		    ((*tbl)->pt_buf = calloc(1, sizeof(*(*tbl)->pt_buf))) ==
   1227       1.1   yamt 		    NULL)
   1228       1.1   yamt 			err(1, "calloc");
   1229       1.1   yamt 		(*tbl)->pt_buf->pfrb_type = PFRB_ADDRS;
   1230       1.1   yamt 		SIMPLEQ_INIT(&(*tbl)->pt_nodes);
   1231       1.1   yamt 
   1232       1.1   yamt 		/* This is just a temporary table name */
   1233       1.1   yamt 		snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d",
   1234       1.1   yamt 		    PF_OPT_TABLE_PREFIX, tablenum++);
   1235       1.1   yamt 		DEBUG("creating table <%s>", (*tbl)->pt_name);
   1236       1.1   yamt 	}
   1237       1.1   yamt 
   1238       1.1   yamt 	memset(&node_host, 0, sizeof(node_host));
   1239       1.1   yamt 	node_host.af = af;
   1240       1.1   yamt 	node_host.addr = addr->addr;
   1241       1.1   yamt 
   1242       1.1   yamt #ifdef OPT_DEBUG
   1243       1.1   yamt 	DEBUG("<%s> adding %s/%d", (*tbl)->pt_name, inet_ntop(af,
   1244       1.1   yamt 	    &node_host.addr.v.a.addr, buf, sizeof(buf)),
   1245       1.1   yamt 	    unmask(&node_host.addr.v.a.mask, af));
   1246       1.1   yamt #endif /* OPT_DEBUG */
   1247       1.1   yamt 
   1248       1.5  peter 	if (append_addr_host((*tbl)->pt_buf, &node_host, 0, 0)) {
   1249       1.5  peter 		warn("failed to add host");
   1250       1.1   yamt 		return (1);
   1251       1.5  peter 	}
   1252       1.1   yamt 	if (pf->opts & PF_OPT_VERBOSE) {
   1253       1.1   yamt 		struct node_tinit *ti;
   1254       1.1   yamt 
   1255       1.1   yamt 		if ((ti = calloc(1, sizeof(*ti))) == NULL)
   1256       1.1   yamt 			err(1, "malloc");
   1257       1.1   yamt 		if ((ti->host = malloc(sizeof(*ti->host))) == NULL)
   1258       1.1   yamt 			err(1, "malloc");
   1259       1.1   yamt 		memcpy(ti->host, &node_host, sizeof(*ti->host));
   1260       1.1   yamt 		SIMPLEQ_INSERT_TAIL(&(*tbl)->pt_nodes, ti, entries);
   1261       1.1   yamt 	}
   1262       1.1   yamt 
   1263       1.1   yamt 	(*tbl)->pt_rulecount++;
   1264       1.1   yamt 	if ((*tbl)->pt_rulecount == TABLE_THRESHOLD)
   1265       1.1   yamt 		DEBUG("table <%s> now faster than skip steps", (*tbl)->pt_name);
   1266       1.1   yamt 
   1267       1.1   yamt 	return (0);
   1268       1.1   yamt }
   1269       1.1   yamt 
   1270       1.1   yamt 
   1271       1.1   yamt /*
   1272       1.1   yamt  * Do the dirty work of choosing an unused table name and creating it.
   1273       1.1   yamt  * (be careful with the table name, it might already be used in another anchor)
   1274       1.1   yamt  */
   1275       1.1   yamt int
   1276       1.1   yamt pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl)
   1277       1.1   yamt {
   1278       1.1   yamt 	static int tablenum;
   1279       1.1   yamt 	struct pfr_table *t;
   1280       1.1   yamt 
   1281       1.1   yamt 	if (table_buffer.pfrb_type == 0) {
   1282       1.1   yamt 		/* Initialize the list of tables */
   1283       1.1   yamt 		table_buffer.pfrb_type = PFRB_TABLES;
   1284       1.1   yamt 		for (;;) {
   1285       1.1   yamt 			pfr_buf_grow(&table_buffer, table_buffer.pfrb_size);
   1286       1.1   yamt 			table_buffer.pfrb_size = table_buffer.pfrb_msize;
   1287       1.1   yamt 			if (pfr_get_tables(NULL, table_buffer.pfrb_caddr,
   1288       1.1   yamt 			    &table_buffer.pfrb_size, PFR_FLAG_ALLRSETS))
   1289       1.1   yamt 				err(1, "pfr_get_tables");
   1290       1.1   yamt 			if (table_buffer.pfrb_size <= table_buffer.pfrb_msize)
   1291       1.1   yamt 				break;
   1292       1.1   yamt 		}
   1293       1.1   yamt 		table_identifier = arc4random();
   1294       1.1   yamt 	}
   1295       1.1   yamt 
   1296       1.1   yamt 	/* XXX would be *really* nice to avoid duplicating identical tables */
   1297       1.1   yamt 
   1298       1.1   yamt 	/* Now we have to pick a table name that isn't used */
   1299       1.1   yamt again:
   1300       1.1   yamt 	DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name,
   1301       1.1   yamt 	    PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
   1302       1.1   yamt 	snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d",
   1303       1.1   yamt 	    PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
   1304       1.1   yamt 	PFRB_FOREACH(t, &table_buffer) {
   1305       1.1   yamt 		if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) {
   1306       1.1   yamt 			/* Collision.  Try again */
   1307       1.1   yamt 			DEBUG("wow, table <%s> in use.  trying again",
   1308       1.1   yamt 			    tbl->pt_name);
   1309       1.1   yamt 			table_identifier = arc4random();
   1310       1.1   yamt 			goto again;
   1311       1.1   yamt 		}
   1312       1.1   yamt 	}
   1313       1.1   yamt 	tablenum++;
   1314       1.1   yamt 
   1315       1.1   yamt 
   1316  1.5.20.1   yamt 	if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1,
   1317  1.5.20.1   yamt 	    pf->anchor->name, tbl->pt_buf, pf->anchor->ruleset.tticket)) {
   1318       1.5  peter 		warn("failed to create table %s", tbl->pt_name);
   1319       1.1   yamt 		return (1);
   1320       1.5  peter 	}
   1321       1.1   yamt 	return (0);
   1322       1.1   yamt }
   1323       1.1   yamt 
   1324       1.1   yamt /*
   1325       1.1   yamt  * Partition the flat ruleset into a list of distinct superblocks
   1326       1.1   yamt  */
   1327       1.1   yamt int
   1328       1.1   yamt construct_superblocks(struct pfctl *pf, struct pf_opt_queue *opt_queue,
   1329       1.1   yamt     struct superblocks *superblocks)
   1330       1.1   yamt {
   1331       1.1   yamt 	struct superblock *block = NULL;
   1332       1.1   yamt 	struct pf_opt_rule *por;
   1333       1.1   yamt 	int i;
   1334       1.1   yamt 
   1335       1.1   yamt 	while (!TAILQ_EMPTY(opt_queue)) {
   1336       1.1   yamt 		por = TAILQ_FIRST(opt_queue);
   1337       1.1   yamt 		TAILQ_REMOVE(opt_queue, por, por_entry);
   1338       1.1   yamt 		if (block == NULL || !superblock_inclusive(block, por)) {
   1339       1.1   yamt 			if ((block = calloc(1, sizeof(*block))) == NULL) {
   1340       1.1   yamt 				warn("calloc");
   1341       1.1   yamt 				return (1);
   1342       1.1   yamt 			}
   1343       1.1   yamt 			TAILQ_INIT(&block->sb_rules);
   1344       1.1   yamt 			for (i = 0; i < PF_SKIP_COUNT; i++)
   1345       1.1   yamt 				TAILQ_INIT(&block->sb_skipsteps[i]);
   1346       1.1   yamt 			TAILQ_INSERT_TAIL(superblocks, block, sb_entry);
   1347       1.1   yamt 		}
   1348       1.1   yamt 		TAILQ_INSERT_TAIL(&block->sb_rules, por, por_entry);
   1349       1.1   yamt 	}
   1350       1.1   yamt 
   1351       1.1   yamt 	return (0);
   1352       1.1   yamt }
   1353       1.1   yamt 
   1354       1.1   yamt 
   1355       1.1   yamt /*
   1356       1.1   yamt  * Compare two rule addresses
   1357       1.1   yamt  */
   1358       1.1   yamt int
   1359       1.1   yamt addrs_equal(struct pf_rule_addr *a, struct pf_rule_addr *b)
   1360       1.1   yamt {
   1361       1.1   yamt 	if (a->neg != b->neg)
   1362       1.1   yamt 		return (0);
   1363       1.1   yamt 	return (memcmp(&a->addr, &b->addr, sizeof(a->addr)) == 0);
   1364       1.1   yamt }
   1365       1.1   yamt 
   1366       1.1   yamt 
   1367       1.1   yamt /*
   1368       1.1   yamt  * The addresses are not equal, but can we combine them into one table?
   1369       1.1   yamt  */
   1370       1.1   yamt int
   1371       1.1   yamt addrs_combineable(struct pf_rule_addr *a, struct pf_rule_addr *b)
   1372       1.1   yamt {
   1373       1.3   yamt 	if (a->addr.type != PF_ADDR_ADDRMASK ||
   1374       1.1   yamt 	    b->addr.type != PF_ADDR_ADDRMASK)
   1375       1.1   yamt 		return (0);
   1376       1.1   yamt 	if (a->neg != b->neg || a->port_op != b->port_op ||
   1377       1.1   yamt 	    a->port[0] != b->port[0] || a->port[1] != b->port[1])
   1378       1.1   yamt 		return (0);
   1379       1.1   yamt 	return (1);
   1380       1.1   yamt }
   1381       1.1   yamt 
   1382       1.1   yamt 
   1383       1.1   yamt /*
   1384       1.1   yamt  * Are we allowed to combine these two rules
   1385       1.1   yamt  */
   1386       1.1   yamt int
   1387       1.1   yamt rules_combineable(struct pf_rule *p1, struct pf_rule *p2)
   1388       1.1   yamt {
   1389       1.1   yamt 	struct pf_rule a, b;
   1390       1.1   yamt 
   1391       1.1   yamt 	comparable_rule(&a, p1, COMBINED);
   1392       1.1   yamt 	comparable_rule(&b, p2, COMBINED);
   1393       1.1   yamt 	return (memcmp(&a, &b, sizeof(a)) == 0);
   1394       1.1   yamt }
   1395       1.1   yamt 
   1396       1.1   yamt 
   1397       1.1   yamt /*
   1398       1.1   yamt  * Can a rule be included inside a superblock
   1399       1.1   yamt  */
   1400       1.1   yamt int
   1401       1.1   yamt superblock_inclusive(struct superblock *block, struct pf_opt_rule *por)
   1402       1.1   yamt {
   1403       1.1   yamt 	struct pf_rule a, b;
   1404       1.1   yamt 	int i, j;
   1405       1.1   yamt 
   1406       1.1   yamt 	/* First check for hard breaks */
   1407       1.1   yamt 	for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) {
   1408       1.1   yamt 		if (pf_rule_desc[i].prf_type == BARRIER) {
   1409       1.1   yamt 			for (j = 0; j < pf_rule_desc[i].prf_size; j++)
   1410       1.1   yamt 				if (((char *)&por->por_rule)[j +
   1411       1.1   yamt 				    pf_rule_desc[i].prf_offset] != 0)
   1412       1.1   yamt 					return (0);
   1413       1.1   yamt 		}
   1414       1.1   yamt 	}
   1415       1.1   yamt 
   1416  1.5.20.1   yamt 	/* per-rule src-track is also a hard break */
   1417  1.5.20.1   yamt 	if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK)
   1418       1.1   yamt 		return (0);
   1419       1.1   yamt 
   1420  1.5.20.1   yamt 	/*
   1421  1.5.20.1   yamt 	 * Have to handle interface groups seperately.  Consider the following
   1422  1.5.20.1   yamt 	 * rules:
   1423  1.5.20.1   yamt 	 *	block on EXTIFS to any port 22
   1424  1.5.20.1   yamt 	 *	pass  on em0 to any port 22
   1425  1.5.20.1   yamt 	 * (where EXTIFS is an arbitrary interface group)
   1426  1.5.20.1   yamt 	 * The optimizer may decide to re-order the pass rule in front of the
   1427  1.5.20.1   yamt 	 * block rule.  But what if EXTIFS includes em0???  Such a reordering
   1428  1.5.20.1   yamt 	 * would change the meaning of the ruleset.
   1429  1.5.20.1   yamt 	 * We can't just lookup the EXTIFS group and check if em0 is a member
   1430  1.5.20.1   yamt 	 * because the user is allowed to add interfaces to a group during
   1431  1.5.20.1   yamt 	 * runtime.
   1432  1.5.20.1   yamt 	 * Ergo interface groups become a defacto superblock break :-(
   1433  1.5.20.1   yamt 	 */
   1434  1.5.20.1   yamt 	if (interface_group(por->por_rule.ifname) ||
   1435  1.5.20.1   yamt 	    interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) {
   1436  1.5.20.1   yamt 		if (strcasecmp(por->por_rule.ifname,
   1437  1.5.20.1   yamt 		    TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0)
   1438  1.5.20.1   yamt 			return (0);
   1439  1.5.20.1   yamt 	}
   1440  1.5.20.1   yamt 
   1441       1.1   yamt 	comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE);
   1442       1.1   yamt 	comparable_rule(&b, &por->por_rule, NOMERGE);
   1443  1.5.20.1   yamt 	if (memcmp(&a, &b, sizeof(a)) == 0)
   1444       1.1   yamt 		return (1);
   1445       1.1   yamt 
   1446       1.1   yamt #ifdef OPT_DEBUG
   1447       1.1   yamt 	for (i = 0; i < sizeof(por->por_rule); i++) {
   1448       1.1   yamt 		int closest = -1;
   1449       1.1   yamt 		if (((u_int8_t *)&a)[i] != ((u_int8_t *)&b)[i]) {
   1450       1.1   yamt 			for (j = 0; j < sizeof(pf_rule_desc) /
   1451       1.1   yamt 			    sizeof(*pf_rule_desc); j++) {
   1452       1.1   yamt 				if (i >= pf_rule_desc[j].prf_offset &&
   1453       1.1   yamt 				    i < pf_rule_desc[j].prf_offset +
   1454       1.1   yamt 				    pf_rule_desc[j].prf_size) {
   1455       1.1   yamt 					DEBUG("superblock break @ %d due to %s",
   1456       1.1   yamt 					    por->por_rule.nr,
   1457       1.1   yamt 					    pf_rule_desc[j].prf_name);
   1458       1.1   yamt 					return (0);
   1459       1.1   yamt 				}
   1460       1.1   yamt 				if (i > pf_rule_desc[j].prf_offset) {
   1461       1.1   yamt 					if (closest == -1 ||
   1462       1.1   yamt 					    i-pf_rule_desc[j].prf_offset <
   1463       1.1   yamt 					    i-pf_rule_desc[closest].prf_offset)
   1464       1.1   yamt 						closest = j;
   1465       1.1   yamt 				}
   1466       1.1   yamt 			}
   1467       1.1   yamt 
   1468       1.1   yamt 			if (closest >= 0)
   1469       1.1   yamt 				DEBUG("superblock break @ %d on %s+%xh",
   1470       1.1   yamt 				    por->por_rule.nr,
   1471       1.1   yamt 				    pf_rule_desc[closest].prf_name,
   1472       1.1   yamt 				    i - pf_rule_desc[closest].prf_offset -
   1473       1.1   yamt 				    pf_rule_desc[closest].prf_size);
   1474       1.1   yamt 			else
   1475       1.1   yamt 				DEBUG("superblock break @ %d on field @ %d",
   1476       1.1   yamt 				    por->por_rule.nr, i);
   1477       1.1   yamt 			return (0);
   1478       1.1   yamt 		}
   1479       1.1   yamt 	}
   1480       1.1   yamt #endif /* OPT_DEBUG */
   1481       1.1   yamt 
   1482       1.1   yamt 	return (0);
   1483       1.1   yamt }
   1484       1.1   yamt 
   1485       1.1   yamt 
   1486       1.1   yamt /*
   1487  1.5.20.1   yamt  * Figure out if an interface name is an actual interface or actually a
   1488  1.5.20.1   yamt  * group of interfaces.
   1489  1.5.20.1   yamt  */
   1490  1.5.20.1   yamt int
   1491  1.5.20.1   yamt interface_group(const char *ifname)
   1492  1.5.20.1   yamt {
   1493  1.5.20.1   yamt 	if (ifname == NULL || !ifname[0])
   1494  1.5.20.1   yamt 		return (0);
   1495  1.5.20.1   yamt 
   1496  1.5.20.1   yamt 	/* Real interfaces must end in a number, interface groups do not */
   1497  1.5.20.1   yamt 	if (isdigit((unsigned char)ifname[strlen(ifname) - 1]))
   1498  1.5.20.1   yamt 		return (0);
   1499  1.5.20.1   yamt 	else
   1500  1.5.20.1   yamt 		return (1);
   1501  1.5.20.1   yamt }
   1502  1.5.20.1   yamt 
   1503  1.5.20.1   yamt 
   1504  1.5.20.1   yamt /*
   1505       1.1   yamt  * Make a rule that can directly compared by memcmp()
   1506       1.1   yamt  */
   1507       1.1   yamt void
   1508       1.1   yamt comparable_rule(struct pf_rule *dst, const struct pf_rule *src, int type)
   1509       1.1   yamt {
   1510       1.1   yamt 	int i;
   1511       1.1   yamt 	/*
   1512       1.1   yamt 	 * To simplify the comparison, we just zero out the fields that are
   1513       1.1   yamt 	 * allowed to be different and then do a simple memcmp()
   1514       1.1   yamt 	 */
   1515       1.1   yamt 	memcpy(dst, src, sizeof(*dst));
   1516       1.1   yamt 	for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++)
   1517       1.1   yamt 		if (pf_rule_desc[i].prf_type >= type) {
   1518       1.1   yamt #ifdef OPT_DEBUG
   1519       1.1   yamt 			assert(pf_rule_desc[i].prf_type != NEVER ||
   1520       1.1   yamt 			    *(((char *)dst) + pf_rule_desc[i].prf_offset) == 0);
   1521       1.1   yamt #endif /* OPT_DEBUG */
   1522       1.1   yamt 			memset(((char *)dst) + pf_rule_desc[i].prf_offset, 0,
   1523       1.1   yamt 			    pf_rule_desc[i].prf_size);
   1524       1.1   yamt 		}
   1525       1.1   yamt }
   1526       1.1   yamt 
   1527       1.1   yamt 
   1528       1.1   yamt /*
   1529       1.1   yamt  * Remove superset information from two rules so we can directly compare them
   1530       1.1   yamt  * with memcmp()
   1531       1.1   yamt  */
   1532       1.1   yamt void
   1533       1.1   yamt exclude_supersets(struct pf_rule *super, struct pf_rule *sub)
   1534       1.1   yamt {
   1535       1.1   yamt 	if (super->ifname[0] == '\0')
   1536       1.1   yamt 		memset(sub->ifname, 0, sizeof(sub->ifname));
   1537       1.1   yamt 	if (super->direction == PF_INOUT)
   1538       1.1   yamt 		sub->direction = PF_INOUT;
   1539       1.1   yamt 	if ((super->proto == 0 || super->proto == sub->proto) &&
   1540       1.1   yamt 	    super->flags == 0 && super->flagset == 0 && (sub->flags ||
   1541       1.1   yamt 	    sub->flagset)) {
   1542       1.1   yamt 		sub->flags = super->flags;
   1543       1.1   yamt 		sub->flagset = super->flagset;
   1544       1.1   yamt 	}
   1545       1.1   yamt 	if (super->proto == 0)
   1546       1.1   yamt 		sub->proto = 0;
   1547       1.1   yamt 
   1548       1.1   yamt 	if (super->src.port_op == 0) {
   1549       1.1   yamt 		sub->src.port_op = 0;
   1550       1.1   yamt 		sub->src.port[0] = 0;
   1551       1.1   yamt 		sub->src.port[1] = 0;
   1552       1.1   yamt 	}
   1553       1.1   yamt 	if (super->dst.port_op == 0) {
   1554       1.1   yamt 		sub->dst.port_op = 0;
   1555       1.1   yamt 		sub->dst.port[0] = 0;
   1556       1.1   yamt 		sub->dst.port[1] = 0;
   1557       1.1   yamt 	}
   1558       1.1   yamt 
   1559       1.1   yamt 	if (super->src.addr.type == PF_ADDR_ADDRMASK && !super->src.neg &&
   1560       1.1   yamt 	    !sub->src.neg && super->src.addr.v.a.mask.addr32[0] == 0 &&
   1561       1.1   yamt 	    super->src.addr.v.a.mask.addr32[1] == 0 &&
   1562       1.1   yamt 	    super->src.addr.v.a.mask.addr32[2] == 0 &&
   1563       1.1   yamt 	    super->src.addr.v.a.mask.addr32[3] == 0)
   1564       1.1   yamt 		memset(&sub->src.addr, 0, sizeof(sub->src.addr));
   1565       1.1   yamt 	else if (super->src.addr.type == PF_ADDR_ADDRMASK &&
   1566       1.1   yamt 	    sub->src.addr.type == PF_ADDR_ADDRMASK &&
   1567       1.1   yamt 	    super->src.neg == sub->src.neg &&
   1568       1.1   yamt 	    super->af == sub->af &&
   1569       1.1   yamt 	    unmask(&super->src.addr.v.a.mask, super->af) <
   1570       1.1   yamt 	    unmask(&sub->src.addr.v.a.mask, sub->af) &&
   1571       1.1   yamt 	    super->src.addr.v.a.addr.addr32[0] ==
   1572       1.1   yamt 	    (sub->src.addr.v.a.addr.addr32[0] &
   1573       1.1   yamt 	    super->src.addr.v.a.mask.addr32[0]) &&
   1574       1.1   yamt 	    super->src.addr.v.a.addr.addr32[1] ==
   1575       1.1   yamt 	    (sub->src.addr.v.a.addr.addr32[1] &
   1576       1.1   yamt 	    super->src.addr.v.a.mask.addr32[1]) &&
   1577       1.1   yamt 	    super->src.addr.v.a.addr.addr32[2] ==
   1578       1.1   yamt 	    (sub->src.addr.v.a.addr.addr32[2] &
   1579       1.1   yamt 	    super->src.addr.v.a.mask.addr32[2]) &&
   1580       1.1   yamt 	    super->src.addr.v.a.addr.addr32[3] ==
   1581       1.1   yamt 	    (sub->src.addr.v.a.addr.addr32[3] &
   1582       1.1   yamt 	    super->src.addr.v.a.mask.addr32[3])) {
   1583       1.1   yamt 		/* sub->src.addr is a subset of super->src.addr/mask */
   1584       1.1   yamt 		memcpy(&sub->src.addr, &super->src.addr, sizeof(sub->src.addr));
   1585       1.1   yamt 	}
   1586       1.1   yamt 
   1587       1.1   yamt 	if (super->dst.addr.type == PF_ADDR_ADDRMASK && !super->dst.neg &&
   1588       1.1   yamt 	    !sub->dst.neg && super->dst.addr.v.a.mask.addr32[0] == 0 &&
   1589       1.1   yamt 	    super->dst.addr.v.a.mask.addr32[1] == 0 &&
   1590       1.1   yamt 	    super->dst.addr.v.a.mask.addr32[2] == 0 &&
   1591       1.1   yamt 	    super->dst.addr.v.a.mask.addr32[3] == 0)
   1592       1.1   yamt 		memset(&sub->dst.addr, 0, sizeof(sub->dst.addr));
   1593       1.1   yamt 	else if (super->dst.addr.type == PF_ADDR_ADDRMASK &&
   1594       1.1   yamt 	    sub->dst.addr.type == PF_ADDR_ADDRMASK &&
   1595       1.1   yamt 	    super->dst.neg == sub->dst.neg &&
   1596       1.1   yamt 	    super->af == sub->af &&
   1597       1.1   yamt 	    unmask(&super->dst.addr.v.a.mask, super->af) <
   1598       1.1   yamt 	    unmask(&sub->dst.addr.v.a.mask, sub->af) &&
   1599       1.1   yamt 	    super->dst.addr.v.a.addr.addr32[0] ==
   1600       1.1   yamt 	    (sub->dst.addr.v.a.addr.addr32[0] &
   1601       1.1   yamt 	    super->dst.addr.v.a.mask.addr32[0]) &&
   1602       1.1   yamt 	    super->dst.addr.v.a.addr.addr32[1] ==
   1603       1.1   yamt 	    (sub->dst.addr.v.a.addr.addr32[1] &
   1604       1.1   yamt 	    super->dst.addr.v.a.mask.addr32[1]) &&
   1605       1.1   yamt 	    super->dst.addr.v.a.addr.addr32[2] ==
   1606       1.1   yamt 	    (sub->dst.addr.v.a.addr.addr32[2] &
   1607       1.1   yamt 	    super->dst.addr.v.a.mask.addr32[2]) &&
   1608       1.1   yamt 	    super->dst.addr.v.a.addr.addr32[3] ==
   1609       1.1   yamt 	    (sub->dst.addr.v.a.addr.addr32[3] &
   1610       1.1   yamt 	    super->dst.addr.v.a.mask.addr32[3])) {
   1611       1.1   yamt 		/* sub->dst.addr is a subset of super->dst.addr/mask */
   1612       1.1   yamt 		memcpy(&sub->dst.addr, &super->dst.addr, sizeof(sub->dst.addr));
   1613       1.1   yamt 	}
   1614       1.1   yamt 
   1615       1.1   yamt 	if (super->af == 0)
   1616       1.1   yamt 		sub->af = 0;
   1617       1.1   yamt }
   1618       1.1   yamt 
   1619       1.1   yamt 
   1620       1.1   yamt void
   1621       1.1   yamt superblock_free(struct pfctl *pf, struct superblock *block)
   1622       1.1   yamt {
   1623       1.1   yamt 	struct pf_opt_rule *por;
   1624       1.1   yamt 	while ((por = TAILQ_FIRST(&block->sb_rules))) {
   1625       1.1   yamt 		TAILQ_REMOVE(&block->sb_rules, por, por_entry);
   1626       1.1   yamt 		if (por->por_src_tbl) {
   1627       1.1   yamt 			if (por->por_src_tbl->pt_buf) {
   1628       1.1   yamt 				pfr_buf_clear(por->por_src_tbl->pt_buf);
   1629       1.1   yamt 				free(por->por_src_tbl->pt_buf);
   1630       1.1   yamt 			}
   1631       1.1   yamt 			free(por->por_src_tbl);
   1632       1.1   yamt 		}
   1633       1.1   yamt 		if (por->por_dst_tbl) {
   1634       1.1   yamt 			if (por->por_dst_tbl->pt_buf) {
   1635       1.1   yamt 				pfr_buf_clear(por->por_dst_tbl->pt_buf);
   1636       1.1   yamt 				free(por->por_dst_tbl->pt_buf);
   1637       1.1   yamt 			}
   1638       1.1   yamt 			free(por->por_dst_tbl);
   1639       1.1   yamt 		}
   1640       1.1   yamt 		free(por);
   1641       1.1   yamt 	}
   1642       1.1   yamt 	if (block->sb_profiled_block)
   1643       1.1   yamt 		superblock_free(pf, block->sb_profiled_block);
   1644       1.1   yamt 	free(block);
   1645       1.1   yamt }
   1646       1.1   yamt 
   1647