Deleted Added
full compact
pfctl_optimize.c (145840) pfctl_optimize.c (171172)
1/* $OpenBSD: pfctl_optimize.c,v 1.5 2005/01/03 15:18:10 frantzen Exp $ */
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>
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: head/contrib/pf/pfctl/pfctl_optimize.c 145840 2005-05-03 16:55:20Z mlaier $");
20__FBSDID("$FreeBSD: head/contrib/pf/pfctl/pfctl_optimize.c 171172 2007-07-03 12:30:03Z mlaier $");
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

--- 78 unchanged lines hidden (view full) ---

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),
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

--- 78 unchanged lines hidden (view full) ---

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 */
115
116 /*
117 * These fields must be the same between all rules in the same superblock.
118 * These rules are allowed to be re-ordered but only among like rules.
119 * For instance we can re-order all 'tag "foo"' rules because they have the
120 * same tag. But we can not re-order between a 'tag "foo"' and a
121 * 'tag "bar"' since that would change the meaning of the ruleset.
122 */
123 PF_RULE_FIELD(tagname, BREAK),
124 PF_RULE_FIELD(keep_state, BREAK),
125 PF_RULE_FIELD(qname, BREAK),
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),
126 PF_RULE_FIELD(rt, BREAK),
127 PF_RULE_FIELD(allow_opts, BREAK),
128 PF_RULE_FIELD(rule_flag, BREAK),
129 PF_RULE_FIELD(action, 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),
130
131 /*
132 * Any fields not listed in this structure act as BREAK fields
133 */
134
135
136 /*
137 * These fields must not differ when we merge two rules together but
138 * their difference isn't enough to put the rules in different superblocks.
139 * There are no problems re-ordering any rules with these fields.
140 */
141 PF_RULE_FIELD(af, NOMERGE),
142 PF_RULE_FIELD(ifnot, NOMERGE),
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),
143 PF_RULE_FIELD(ifname, NOMERGE),
155 PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */
144 PF_RULE_FIELD(match_tag_not, NOMERGE),
145 PF_RULE_FIELD(match_tagname, NOMERGE),
146 PF_RULE_FIELD(os_fingerprint, NOMERGE),
147 PF_RULE_FIELD(timeout, NOMERGE),
148 PF_RULE_FIELD(return_icmp, NOMERGE),
149 PF_RULE_FIELD(return_icmp6, NOMERGE),
150 PF_RULE_FIELD(uid, NOMERGE),
151 PF_RULE_FIELD(gid, NOMERGE),

--- 16 unchanged lines hidden (view full) ---

168 PF_RULE_FIELD(dst.addr, COMBINED),
169
170 /* We just don't care about these fields. They're set by the kernel */
171 PF_RULE_FIELD(skip, DC),
172 PF_RULE_FIELD(evaluations, DC),
173 PF_RULE_FIELD(packets, DC),
174 PF_RULE_FIELD(bytes, DC),
175 PF_RULE_FIELD(kif, DC),
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),

--- 16 unchanged lines hidden (view full) ---

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),
176 PF_RULE_FIELD(anchor, DC),
177 PF_RULE_FIELD(states, DC),
178 PF_RULE_FIELD(src_nodes, DC),
179 PF_RULE_FIELD(nr, DC),
180 PF_RULE_FIELD(entries, DC),
181 PF_RULE_FIELD(qid, DC),
182 PF_RULE_FIELD(pqid, DC),
183 PF_RULE_FIELD(anchor_relative, DC),
184 PF_RULE_FIELD(anchor_wildcard, 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),
185
186 /* These fields should never be set in a PASS/BLOCK rule */
187 PF_RULE_FIELD(natpass, NEVER),
188 PF_RULE_FIELD(max_mss, NEVER),
189 PF_RULE_FIELD(min_ttl, NEVER),
190};
191
192
193
194int add_opt_table(struct pfctl *, struct pf_opt_tbl **, sa_family_t,
195 struct pf_rule_addr *);
196int addrs_combineable(struct pf_rule_addr *, struct pf_rule_addr *);
197int addrs_equal(struct pf_rule_addr *, struct pf_rule_addr *);
198int block_feedback(struct pfctl *, struct superblock *);
199int combine_rules(struct pfctl *, struct superblock *);
200void comparable_rule(struct pf_rule *, const struct pf_rule *, int);
201int construct_superblocks(struct pfctl *, struct pf_opt_queue *,
202 struct superblocks *);
203void exclude_supersets(struct pf_rule *, struct pf_rule *);
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
208int add_opt_table(struct pfctl *, struct pf_opt_tbl **, sa_family_t,
209 struct pf_rule_addr *);
210int addrs_combineable(struct pf_rule_addr *, struct pf_rule_addr *);
211int addrs_equal(struct pf_rule_addr *, struct pf_rule_addr *);
212int block_feedback(struct pfctl *, struct superblock *);
213int combine_rules(struct pfctl *, struct superblock *);
214void comparable_rule(struct pf_rule *, const struct pf_rule *, int);
215int construct_superblocks(struct pfctl *, struct pf_opt_queue *,
216 struct superblocks *);
217void exclude_supersets(struct pf_rule *, struct pf_rule *);
218int interface_group(const char *);
204int load_feedback_profile(struct pfctl *, struct superblocks *);
205int optimize_superblock(struct pfctl *, struct superblock *);
206int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *);
207void remove_from_skipsteps(struct skiplist *, struct superblock *,
208 struct pf_opt_rule *, struct pf_skip_step *);
209int remove_identical_rules(struct pfctl *, struct superblock *);
210int reorder_rules(struct pfctl *, struct superblock *, int);
211int rules_combineable(struct pf_rule *, struct pf_rule *);

--- 26 unchanged lines hidden (view full) ---

238 { "dport", PF_SKIP_DST_PORT, skip_cmp_dst_port } \
239}
240
241struct pfr_buffer table_buffer;
242int table_identifier;
243
244
245int
219int load_feedback_profile(struct pfctl *, struct superblocks *);
220int optimize_superblock(struct pfctl *, struct superblock *);
221int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *);
222void remove_from_skipsteps(struct skiplist *, struct superblock *,
223 struct pf_opt_rule *, struct pf_skip_step *);
224int remove_identical_rules(struct pfctl *, struct superblock *);
225int reorder_rules(struct pfctl *, struct superblock *, int);
226int rules_combineable(struct pf_rule *, struct pf_rule *);

--- 26 unchanged lines hidden (view full) ---

253 { "dport", PF_SKIP_DST_PORT, skip_cmp_dst_port } \
254}
255
256struct pfr_buffer table_buffer;
257int table_identifier;
258
259
260int
246pfctl_optimize_rules(struct pfctl *pf)
261pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs)
247{
248 struct superblocks superblocks;
262{
263 struct superblocks superblocks;
264 struct pf_opt_queue opt_queue;
249 struct superblock *block;
250 struct pf_opt_rule *por;
265 struct superblock *block;
266 struct pf_opt_rule *por;
251 int nr;
267 struct pf_rule *r;
268 struct pf_rulequeue *old_rules;
252
253 DEBUG("optimizing ruleset");
254 memset(&table_buffer, 0, sizeof(table_buffer));
255 skip_init();
269
270 DEBUG("optimizing ruleset");
271 memset(&table_buffer, 0, sizeof(table_buffer));
272 skip_init();
273 TAILQ_INIT(&opt_queue);
256
274
257 if (TAILQ_FIRST(&pf->opt_queue))
258 nr = TAILQ_FIRST(&pf->opt_queue)->por_rule.nr;
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;
259
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
260 TAILQ_INIT(&superblocks);
302 TAILQ_INIT(&superblocks);
261 if (construct_superblocks(pf, &pf->opt_queue, &superblocks))
303 if (construct_superblocks(pf, &opt_queue, &superblocks))
262 goto error;
263
304 goto error;
305
264 if (pf->opts & PF_OPT_OPTIMIZE_PROFILE) {
306 if (pf->optimize & PF_OPTIMIZE_PROFILE) {
265 if (load_feedback_profile(pf, &superblocks))
266 goto error;
267 }
268
269 TAILQ_FOREACH(block, &superblocks, sb_entry) {
270 if (optimize_superblock(pf, block))
271 goto error;
272 }
273
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
274
275 /*
276 * Optimizations are done so we turn off the optimization flag and
277 * put the rules right back into the regular codepath.
278 */
279 pf->opts &= ~PF_OPT_OPTIMIZE;
280
316 rs->anchor->refcnt = 0;
281 while ((block = TAILQ_FIRST(&superblocks))) {
282 TAILQ_REMOVE(&superblocks, block, sb_entry);
283
284 while ((por = TAILQ_FIRST(&block->sb_rules))) {
285 TAILQ_REMOVE(&block->sb_rules, por, por_entry);
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);
286 por->por_rule.nr = nr++;
287 if (pfctl_add_rule(pf, &por->por_rule,
288 por->por_anchor)) {
289 free(por);
290 goto error;
291 }
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);
292 free(por);
293 }
294 free(block);
295 }
296
297 return (0);
298
299error:
331 free(por);
332 }
333 free(block);
334 }
335
336 return (0);
337
338error:
300 while ((por = TAILQ_FIRST(&pf->opt_queue))) {
301 TAILQ_REMOVE(&pf->opt_queue, por, por_entry);
339 while ((por = TAILQ_FIRST(&opt_queue))) {
340 TAILQ_REMOVE(&opt_queue, por, por_entry);
302 if (por->por_src_tbl) {
303 pfr_buf_clear(por->por_src_tbl->pt_buf);
304 free(por->por_src_tbl->pt_buf);
305 free(por->por_src_tbl);
306 }
307 if (por->por_dst_tbl) {
308 pfr_buf_clear(por->por_dst_tbl->pt_buf);
309 free(por->por_dst_tbl->pt_buf);

--- 52 unchanged lines hidden (view full) ---

362 /* shortcut. there will be alot of 1-rule superblocks */
363 if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry))
364 return (0);
365
366#ifdef OPT_DEBUG
367 printf("--- Superblock ---\n");
368 TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
369 printf(" ");
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);

--- 52 unchanged lines hidden (view full) ---

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(" ");
370 print_rule(&por->por_rule, por->por_anchor, 1);
409 print_rule(&por->por_rule, por->por_rule.anchor ?
410 por->por_rule.anchor->name : "", 1);
371 }
372#endif /* OPT_DEBUG */
373
374
375 if (remove_identical_rules(pf, block))
376 return (1);
377 if (combine_rules(pf, block))
378 return (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);
379 if ((pf->opts & PF_OPT_OPTIMIZE_PROFILE) &&
419 if ((pf->optimize & PF_OPTIMIZE_PROFILE) &&
380 TAILQ_FIRST(&block->sb_rules)->por_rule.quick &&
381 block->sb_profiled_block) {
382 if (block_feedback(pf, block))
383 return (1);
384 } else if (reorder_rules(pf, block, 0)) {
385 return (1);
386 }
387

--- 390 unchanged lines hidden (view full) ---

778
779
780 /*
781 * Walk through all of the profiled superblock's rules and copy
782 * the counters onto our rules.
783 */
784 TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) {
785 comparable_rule(&a, &por1->por_rule, DC);
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

--- 390 unchanged lines hidden (view full) ---

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);
786 total_count += por1->por_rule.packets;
826 total_count += por1->por_rule.packets[0] +
827 por1->por_rule.packets[1];
787 TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
788 if (por2->por_profile_count)
789 continue;
790 comparable_rule(&b, &por2->por_rule, DC);
791 if (memcmp(&a, &b, sizeof(a)) == 0) {
792 por2->por_profile_count =
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 =
793 por1->por_rule.packets;
834 por1->por_rule.packets[0] +
835 por1->por_rule.packets[1];
794 break;
795 }
796 }
797 }
798 superblock_free(pf, block->sb_profiled_block);
799 block->sb_profiled_block = NULL;
800
801 /*

--- 51 unchanged lines hidden (view full) ---

853 if (ioctl(pf->dev, DIOCGETRULES, &pr)) {
854 warn("DIOCGETRULES");
855 return (1);
856 }
857 mnr = pr.nr;
858
859 DEBUG("Loading %d active rules for a feedback profile", mnr);
860 for (nr = 0; nr < mnr; ++nr) {
836 break;
837 }
838 }
839 }
840 superblock_free(pf, block->sb_profiled_block);
841 block->sb_profiled_block = NULL;
842
843 /*

--- 51 unchanged lines hidden (view full) ---

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;
861 if ((por = calloc(1, sizeof(*por))) == NULL) {
862 warn("calloc");
863 return (1);
864 }
865 pr.nr = nr;
866 if (ioctl(pf->dev, DIOCGETRULE, &pr)) {
867 warn("DIOCGETRULES");
868 return (1);
869 }
870 memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule));
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));
871 strlcpy(por->por_anchor, pr.anchor_call,
872 sizeof(por->por_anchor));
914 rs = pf_find_or_create_ruleset(pr.anchor_call);
915 por->por_rule.anchor = rs->anchor;
873 if (TAILQ_EMPTY(&por->por_rule.rpool.list))
874 memset(&por->por_rule.rpool, 0,
875 sizeof(por->por_rule.rpool));
876 TAILQ_INSERT_TAIL(&queue, por, por_entry);
877
878 /* XXX pfctl_get_pool(pf->dev, &pr.rule.rpool, nr, pr.ticket,
879 * PF_PASS, pf->anchor) ???
880 * ... pfctl_clear_pool(&pr.rule.rpool)

--- 166 unchanged lines hidden (view full) ---

1047 case PF_ADDR_DYNIFTL:
1048 if (strcmp(a->dst.addr.v.ifname, b->dst.addr.v.ifname) != 0 ||
1049 a->dst.addr.iflags != a->dst.addr.iflags ||
1050 memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask,
1051 sizeof(a->dst.addr.v.a.mask)))
1052 return (1);
1053 return (0);
1054 case PF_ADDR_NOROUTE:
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)

--- 166 unchanged lines hidden (view full) ---

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:
1055 return (0);
1056 case PF_ADDR_TABLE:
1057 return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname));
1058 }
1059 return (1);
1060}
1061
1062/* Compare two rules DST port field for skiplist construction */

--- 55 unchanged lines hidden (view full) ---

1118 case PF_ADDR_DYNIFTL:
1119 if (strcmp(a->src.addr.v.ifname, b->src.addr.v.ifname) != 0 ||
1120 a->src.addr.iflags != a->src.addr.iflags ||
1121 memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask,
1122 sizeof(a->src.addr.v.a.mask)))
1123 return (1);
1124 return (0);
1125 case PF_ADDR_NOROUTE:
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 */

--- 55 unchanged lines hidden (view full) ---

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:
1126 return (0);
1127 case PF_ADDR_TABLE:
1128 return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname));
1129 }
1130 return (1);
1131}
1132
1133/* Compare two rules SRC port field for skiplist construction */

--- 135 unchanged lines hidden (view full) ---

1269 tbl->pt_name);
1270 table_identifier = arc4random();
1271 goto again;
1272 }
1273 }
1274 tablenum++;
1275
1276
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 */

--- 135 unchanged lines hidden (view full) ---

1314 tbl->pt_name);
1315 table_identifier = arc4random();
1316 goto again;
1317 }
1318 }
1319 tablenum++;
1320
1321
1277 if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, pf->anchor,
1278 tbl->pt_buf, pf->tticket)) {
1322 if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1,
1323 pf->anchor->name, tbl->pt_buf, pf->anchor->ruleset.tticket)) {
1279 warn("failed to create table %s", tbl->pt_name);
1280 return (1);
1281 }
1282 return (0);
1283}
1284
1285/*
1286 * Partition the flat ruleset into a list of distinct superblocks

--- 82 unchanged lines hidden (view full) ---

1369 if (pf_rule_desc[i].prf_type == BARRIER) {
1370 for (j = 0; j < pf_rule_desc[i].prf_size; j++)
1371 if (((char *)&por->por_rule)[j +
1372 pf_rule_desc[i].prf_offset] != 0)
1373 return (0);
1374 }
1375 }
1376
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

--- 82 unchanged lines hidden (view full) ---

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
1377 /* 'anchor' heads and per-rule src-track are also hard breaks */
1378 if (por->por_anchor[0] != '\0' ||
1379 (por->por_rule.rule_flag & PFRULE_RULESRCTRACK))
1422 /* per-rule src-track is also a hard break */
1423 if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK)
1380 return (0);
1381
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
1382 comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE);
1383 comparable_rule(&b, &por->por_rule, NOMERGE);
1447 comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE);
1448 comparable_rule(&b, &por->por_rule, NOMERGE);
1384 if (strcmp(TAILQ_FIRST(&block->sb_rules)->por_anchor,
1385 por->por_anchor) == 0 && memcmp(&a, &b, sizeof(a)) == 0)
1449 if (memcmp(&a, &b, sizeof(a)) == 0)
1386 return (1);
1387
1388#ifdef OPT_DEBUG
1389 for (i = 0; i < sizeof(por->por_rule); i++) {
1390 int closest = -1;
1391 if (((u_int8_t *)&a)[i] != ((u_int8_t *)&b)[i]) {
1392 for (j = 0; j < sizeof(pf_rule_desc) /
1393 sizeof(*pf_rule_desc); j++) {

--- 27 unchanged lines hidden (view full) ---

1421 }
1422#endif /* OPT_DEBUG */
1423
1424 return (0);
1425}
1426
1427
1428/*
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++) {

--- 27 unchanged lines hidden (view full) ---

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 */
1496int
1497interface_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/*
1429 * Make a rule that can directly compared by memcmp()
1430 */
1431void
1432comparable_rule(struct pf_rule *dst, const struct pf_rule *src, int type)
1433{
1434 int i;
1435 /*
1436 * To simplify the comparison, we just zero out the fields that are

--- 134 unchanged lines hidden ---
1511 * Make a rule that can directly compared by memcmp()
1512 */
1513void
1514comparable_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

--- 134 unchanged lines hidden ---