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