Hi,

PF supports 'one shot rules'. Quoting pf.conf(5) "once - Creates a one 
shot rule that will remove itself from an active ruleset after the first 
match."

I'd like to simplify pf by removing them, unless there's a compelling 
reason not to.

Particularly as there is no 'first match' under concurrent ruleset 
evaluation (which we aim at). That obliges the code for one-shot rules to 
either serialise evaluation to some degree (hurting performance) or fail 
to do what it says on the tin in all cases (hurting correctness). Either 
way the code creates surprises and has to do a lot of hoop-jumping.

Thoughts?

cheers,
Richard. 


Index: sbin/pfctl/parse.y
===================================================================
RCS file: /cvs/src/sbin/pfctl/parse.y,v
retrieving revision 1.700
diff -u -p -u -p -r1.700 parse.y
--- sbin/pfctl/parse.y  15 Jan 2020 22:38:30 -0000      1.700
+++ sbin/pfctl/parse.y  24 Jan 2020 06:12:06 -0000
@@ -242,7 +242,6 @@ struct filter_opts {
 #define FOM_SETTOS     0x0100
 #define FOM_SCRUB_TCP  0x0200
 #define FOM_SETPRIO    0x0400
-#define FOM_ONCE       0x1000
 #define FOM_PRIO       0x2000
 #define FOM_SETDELAY   0x4000
        struct node_uid         *uid;
@@ -487,7 +486,7 @@ int parseport(char *, struct range *r, i
 %token BITMASK RANDOM SOURCEHASH ROUNDROBIN LEASTSTATES STATICPORT PROBABILITY
 %token WEIGHT BANDWIDTH FLOWS QUANTUM
 %token QUEUE PRIORITY QLIMIT RTABLE RDOMAIN MINIMUM BURST PARENT
-%token LOAD RULESET_OPTIMIZATION RTABLE RDOMAIN PRIO ONCE DEFAULT DELAY
+%token LOAD RULESET_OPTIMIZATION RTABLE RDOMAIN PRIO DEFAULT DELAY
 %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
 %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW MAXPKTRATE
 %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE
@@ -2163,9 +2162,6 @@ filter_opt        : USER uids {
                        filter_opts.rcv = $3;
                        filter_opts.rcv->not = $1;
                }
-               | ONCE {
-                       filter_opts.marker |= FOM_ONCE;
-               }
                | MAXPKTRATE NUMBER '/' NUMBER {
                        if ($2 < 0 || $2 > UINT_MAX ||
                            $4 < 0 || $4 > UINT_MAX) {
@@ -5086,7 +5082,6 @@ lookup(char *s)
                { "no-route",           NOROUTE},
                { "no-sync",            NOSYNC},
                { "on",                 ON},
-               { "once",               ONCE},
                { "optimization",       OPTIMIZATION},
                { "os",                 OS},
                { "out",                OUT},
@@ -5909,14 +5904,6 @@ rdomain_exists(u_int rdomain)
 int
 filteropts_to_rule(struct pf_rule *r, struct filter_opts *opts)
 {
-       if (opts->marker & FOM_ONCE) {
-               if ((r->action != PF_PASS && r->action != PF_DROP) || 
r->anchor) {
-                       yyerror("'once' only applies to pass/block rules");
-                       return (1);
-               }
-               r->rule_flag |= PFRULE_ONCE;
-       }
-
        r->keep_state = opts->keep.action;
        r->pktrate.limit = opts->pktrate.limit;
        r->pktrate.seconds = opts->pktrate.seconds;
Index: sbin/pfctl/pfctl_parser.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl_parser.c,v
retrieving revision 1.342
diff -u -p -u -p -r1.342 pfctl_parser.c
--- sbin/pfctl/pfctl_parser.c   17 Oct 2019 21:54:28 -0000      1.342
+++ sbin/pfctl/pfctl_parser.c   24 Jan 2020 06:12:06 -0000
@@ -1085,8 +1085,6 @@ print_rule(struct pf_rule *r, const char
                printf(" allow-opts");
        if (r->label[0])
                printf(" label \"%s\"", r->label);
-       if (r->rule_flag & PFRULE_ONCE)
-               printf(" once");
        if (r->tagname[0])
                printf(" tag %s", r->tagname);
        if (r->match_tagname[0]) {
Index: share/man/man5/pf.conf.5
===================================================================
RCS file: /cvs/src/share/man/man5/pf.conf.5,v
retrieving revision 1.583
diff -u -p -u -p -r1.583 pf.conf.5
--- share/man/man5/pf.conf.5    17 Jan 2020 09:07:35 -0000      1.583
+++ share/man/man5/pf.conf.5    24 Jan 2020 06:12:08 -0000
@@ -639,12 +639,6 @@ pass in proto icmp max-pkt-rate 100/10
 When the rate is exceeded, all ICMP is blocked until the rate falls below
 100 per 10 seconds again.
 .Pp
-.It Cm once
-Creates a one shot rule that will remove itself from an active ruleset after
-the first match.
-In case this is the only rule in the anchor, the anchor will be destroyed
-automatically after the rule is matched.
-.Pp
 .It Cm probability Ar number Ns %
 A probability attribute can be attached to a rule,
 with a value set between 0 and 100%,
Index: sys/net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.1091
diff -u -p -u -p -r1.1091 pf.c
--- sys/net/pf.c        17 Nov 2019 08:25:05 -0000      1.1091
+++ sys/net/pf.c        24 Jan 2020 06:12:13 -0000
@@ -315,9 +315,6 @@ RB_GENERATE(pf_state_tree, pf_state_key,
 RB_GENERATE(pf_state_tree_id, pf_state,
     entry_id, pf_state_compare_id);
 
-SLIST_HEAD(pf_rule_gcl, pf_rule)       pf_rule_gcl =
-       SLIST_HEAD_INITIALIZER(pf_rule_gcl);
-
 __inline int
 pf_addr_compare(struct pf_addr *a, struct pf_addr *b, sa_family_t af)
 {
@@ -1233,23 +1230,6 @@ pf_state_export(struct pfsync_state *sp,
 /* END state table stuff */
 
 void
-pf_purge_expired_rules(void)
-{
-       struct pf_rule  *r;
-
-       PF_ASSERT_LOCKED();
-
-       if (SLIST_EMPTY(&pf_rule_gcl))
-               return;
-
-       while ((r = SLIST_FIRST(&pf_rule_gcl)) != NULL) {
-               SLIST_REMOVE(&pf_rule_gcl, r, pf_rule, gcle);
-               KASSERT(r->rule_flag & PFRULE_EXPIRED);
-               pf_purge_rule(r);
-       }
-}
-
-void
 pf_purge_timeout(void *unused)
 {
        task_add(net_tq(0), &pf_purge_task);
@@ -1277,7 +1257,6 @@ pf_purge(void *xnloops)
        /* purge other expired types every PFTM_INTERVAL seconds */
        if (++(*nloops) >= pf_default_rule.timeout[PFTM_INTERVAL]) {
                pf_purge_expired_src_nodes();
-               pf_purge_expired_rules();
        }
        PF_UNLOCK();
 
@@ -3964,22 +3943,6 @@ pf_test_rule(struct pf_pdesc *pd, struct
                        return (PF_DEFER);
        }
 #endif /* NPFSYNC > 0 */
-
-       if (r->rule_flag & PFRULE_ONCE) {
-               u_int32_t       rule_flag;
-
-               /*
-                * Use atomic_cas() to determine a clear winner, which will
-                * insert an expired rule to gcl.
-                */
-               rule_flag = r->rule_flag;
-               if (((rule_flag & PFRULE_EXPIRED) == 0) &&
-                   atomic_cas_uint(&r->rule_flag, rule_flag,
-                       rule_flag | PFRULE_EXPIRED) == rule_flag) {
-                       r->exptime = time_second;
-                       SLIST_INSERT_HEAD(&pf_rule_gcl, r, gcle);
-               }
-       }
 
        return (action);
 
Index: sys/net/pf_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net/pf_ioctl.c,v
retrieving revision 1.348
diff -u -p -u -p -r1.348 pf_ioctl.c
--- sys/net/pf_ioctl.c  8 Jan 2020 21:48:59 -0000       1.348
+++ sys/net/pf_ioctl.c  24 Jan 2020 06:12:17 -0000
@@ -321,24 +321,6 @@ pf_rm_rule(struct pf_rulequeue *rulequeu
        pool_put(&pf_rule_pl, rule);
 }
 
-void
-pf_purge_rule(struct pf_rule *rule)
-{
-       u_int32_t                nr = 0;
-       struct pf_ruleset       *ruleset;
-
-       KASSERT((rule != NULL) && (rule->ruleset != NULL));
-       ruleset = rule->ruleset;
-
-       pf_rm_rule(ruleset->rules.active.ptr, rule);
-       ruleset->rules.active.rcount--;
-       TAILQ_FOREACH(rule, ruleset->rules.active.ptr, entries)
-               rule->nr = nr++;
-       ruleset->rules.active.ticket++;
-       pf_calc_skip_steps(ruleset->rules.active.ptr);
-       pf_remove_if_empty_ruleset(ruleset);
-}
-
 u_int16_t
 tagname2tag(struct pf_tags *head, char *tagname, int create)
 {
@@ -808,9 +790,6 @@ pf_commit_rules(u_int32_t ticket, char *
        int                      error;
        u_int32_t                old_rcount;
 
-       /* Make sure any expired rules get removed from active rules first. */
-       pf_purge_expired_rules();
-
        rs = pf_find_ruleset(anchor);
        if (rs == NULL || !rs->rules.inactive.open ||
            ticket != rs->rules.inactive.ticket)
@@ -1280,7 +1259,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
                }
                TAILQ_INSERT_TAIL(ruleset->rules.inactive.ptr,
                    rule, entries);
-               rule->ruleset = ruleset;
                ruleset->rules.inactive.rcount++;
                PF_UNLOCK();
                break;
@@ -1346,8 +1324,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
                pr->rule.anchor = NULL;
                pr->rule.overload_tbl = NULL;
                pr->rule.pktrate.limit /= PF_THRESHOLD_MULT;
-               memset(&pr->rule.gcle, 0, sizeof(pr->rule.gcle));
-               pr->rule.ruleset = NULL;
                if (pf_anchor_copyout(ruleset, rule, pr)) {
                        error = EBUSY;
                        PF_UNLOCK();
Index: sys/net/pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.493
diff -u -p -u -p -r1.493 pfvar.h
--- sys/net/pfvar.h     17 Nov 2019 08:25:05 -0000      1.493
+++ sys/net/pfvar.h     24 Jan 2020 06:12:19 -0000
@@ -596,10 +596,6 @@ struct pf_rule {
                u_int16_t               port;
                u_int8_t                type;
        }                       divert;
-
-       SLIST_ENTRY(pf_rule)     gcle;
-       struct pf_ruleset       *ruleset;
-       time_t                   exptime;
 };
 
 /* rule flags */
@@ -617,7 +613,6 @@ struct pf_rule {
 #define PFRULE_IFBOUND         0x00010000      /* if-bound */
 #define PFRULE_STATESLOPPY     0x00020000      /* sloppy state tracking */
 #define PFRULE_PFLOW           0x00040000
-#define PFRULE_ONCE            0x00100000      /* one shot rule */
 #define PFRULE_AFTO            0x00200000      /* af-to rule */
 #define        PFRULE_EXPIRED          0x00400000      /* one shot rule hit by 
pkt */
 
@@ -1704,7 +1699,6 @@ extern void                        
pf_tbladdr_copyout(struct
 extern void                     pf_calc_skip_steps(struct pf_rulequeue *);
 extern void                     pf_purge_expired_src_nodes(void);
 extern void                     pf_purge_expired_states(u_int32_t);
-extern void                     pf_purge_expired_rules(void);
 extern void                     pf_remove_state(struct pf_state *);
 extern void                     pf_remove_divert_state(struct pf_state_key *);
 extern void                     pf_free_state(struct pf_state *);
@@ -1734,7 +1728,6 @@ extern void                        pf_addrcpy(struct 
pf_addr
                                    sa_family_t);
 void                            pf_rm_rule(struct pf_rulequeue *,
                                    struct pf_rule *);
-void                            pf_purge_rule(struct pf_rule *);
 struct pf_divert               *pf_find_divert(struct mbuf *);
 int                             pf_setup_pdesc(struct pf_pdesc *, sa_family_t,
                                    int, struct pfi_kif *, struct mbuf *,
Index: usr.sbin/tftp-proxy/filter.c
===================================================================
RCS file: /cvs/src/usr.sbin/tftp-proxy/filter.c,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 filter.c
--- usr.sbin/tftp-proxy/filter.c        21 Jan 2015 21:50:33 -0000      1.2
+++ usr.sbin/tftp-proxy/filter.c        24 Jan 2020 06:12:34 -0000
@@ -208,9 +208,6 @@ prepare_rule(u_int32_t id, struct sockad
        }
        pfr.rule.dst.port_op = PF_OP_EQ;
        pfr.rule.dst.port[0] = htons(d_port);
-#ifdef notyet
-       pfr.rule.rule_flag = PFRULE_ONCE;
-#endif
        pfr.rule.action = PF_PASS;
        pfr.rule.quick = 1;
        pfr.rule.log = rule_log;



Reply via email to