Hello,

there was still one more glitch catched by mikeb:

    I have to sanitize pointer when copying rule to userland.

The other thing pointed out by mike is the Expired time should
be printed for expired rules only in debug mode output (pfctl -sr -g)

Incremental patch is as follows:
--------8<---------------8<---------------8<------------------8<--------
diff -r 7a93d568ede3 -r b366ba821dfb src/sbin/pfctl/pfctl.c
--- a/src/sbin/pfctl/pfctl.c    Sat Sep 03 15:06:16 2016 +0200
+++ b/src/sbin/pfctl/pfctl.c    Sat Sep 03 16:20:24 2016 +0200
@@ -702,14 +702,9 @@ pfctl_print_rule_counters(struct pf_rule
                printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
                    rule->qname, rule->qid, rule->pqname, rule->pqid);
 
-               if (rule->rule_flag & PFRULE_ONCE)
-                       if (rule->rule_flag & PFRULE_EXPIRED)
-                               printf("  [ Expired: %lld secs ago ]\n",
-                                   (long long)(time(NULL) - rule->exptime));
-                       else
-                               printf("  [ Expired: not yet ]\n");
-               else
-                       printf("  [ Expired: never ]\n");
+               if (rule->rule_flag & PFRULE_EXPIRED)
+                       printf("  [ Expired: %lld secs ago ]\n",
+                           (long long)(time(NULL) - rule->exptime));
        }
        if (opts & PF_OPT_VERBOSE) {
                printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
diff -r 7a93d568ede3 -r b366ba821dfb src/sys/net/pf_ioctl.c
--- a/src/sys/net/pf_ioctl.c    Sat Sep 03 15:06:16 2016 +0200
+++ b/src/sys/net/pf_ioctl.c    Sat Sep 03 16:20:24 2016 +0200
@@ -1268,6 +1268,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
                pr->rule.rcv_kif = NULL;
                pr->rule.anchor = NULL;
                pr->rule.overload_tbl = NULL;
+               bzero(&pr->rule.gcle, sizeof(pr->rule.gcle));
+               pr->rule.ruleset = NULL;
                if (pf_anchor_copyout(ruleset, rule, pr)) {
                        error = EBUSY;
                        break;
--------8<---------------8<---------------8<------------------8<--------

complete patch I'd like to commit is further below.

regards
sasha

--------8<---------------8<---------------8<------------------8<--------
diff -r 8006a1eca673 src/sbin/pfctl/pfctl.c
--- a/src/sbin/pfctl/pfctl.c    Sat Sep 03 14:19:17 2016 +0200
+++ b/src/sbin/pfctl/pfctl.c    Sat Sep 03 16:26:08 2016 +0200
@@ -701,6 +701,10 @@ pfctl_print_rule_counters(struct pf_rule
 
                printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
                    rule->qname, rule->qid, rule->pqname, rule->pqid);
+
+               if (rule->rule_flag & PFRULE_EXPIRED)
+                       printf("  [ Expired: %lld secs ago ]\n",
+                           (long long)(time(NULL) - rule->exptime));
        }
        if (opts & PF_OPT_VERBOSE) {
                printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
@@ -848,7 +852,13 @@ pfctl_show_rules(int dev, char *path, in
                                INDENT(depth, !(opts & PF_OPT_VERBOSE));
                                printf("}\n");
                        } else {
-                               printf("\n");
+                               /*
+                                * Do not print newline, when we have not
+                                * printed expired rule.
+                                */
+                               if (!(pr.rule.rule_flag & PFRULE_EXPIRED) ||
+                                   (opts & (PF_OPT_VERBOSE2|PF_OPT_DEBUG)))
+                                       printf("\n");
                                pfctl_print_rule_counters(&pr.rule, opts);
                        }
                        break;
diff -r 8006a1eca673 src/sbin/pfctl/pfctl_parser.c
--- a/src/sbin/pfctl/pfctl_parser.c     Sat Sep 03 14:19:17 2016 +0200
+++ b/src/sbin/pfctl/pfctl_parser.c     Sat Sep 03 16:26:08 2016 +0200
@@ -701,8 +701,12 @@ print_rule(struct pf_rule *r, const char
        int     verbose = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
        char    *p;
 
+       if ((r->rule_flag & PFRULE_EXPIRED) && (!verbose))
+               return;
+
        if (verbose)
                printf("@%d ", r->nr);
+
        if (r->action > PF_MATCH)
                printf("action(%d)", r->action);
        else if (anchor_call[0]) {
diff -r 8006a1eca673 src/sys/net/pf.c
--- a/src/sys/net/pf.c  Sat Sep 03 14:19:17 2016 +0200
+++ b/src/sys/net/pf.c  Sat Sep 03 16:26:08 2016 +0200
@@ -311,6 +311,9 @@ 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)
 {
@@ -1174,6 +1177,29 @@ pf_state_export(struct pfsync_state *sp,
 /* END state table stuff */
 
 void
+pf_purge_expired_rules(int locked)
+{
+       struct pf_rule  *r;
+
+       if (SLIST_EMPTY(&pf_rule_gcl))
+               return;
+
+       if (!locked)
+               rw_enter_write(&pf_consistency_lock);
+       else
+               rw_assert_wrlock(&pf_consistency_lock);
+
+       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);
+       }
+
+       if (!locked)
+               rw_exit_write(&pf_consistency_lock);
+}
+
+void
 pf_purge_thread(void *v)
 {
        int nloops = 0, s;
@@ -1191,6 +1217,7 @@ pf_purge_thread(void *v)
                if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
                        pf_purge_expired_fragments();
                        pf_purge_expired_src_nodes(0);
+                       pf_purge_expired_rules(0);
                        nloops = 0;
                }
 
@@ -3491,6 +3518,10 @@ pf_test_rule(struct pf_pdesc *pd, struct
        ruleset = &pf_main_ruleset;
        r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr);
        while (r != NULL) {
+               if (r->rule_flag & PFRULE_EXPIRED) {
+                       r = TAILQ_NEXT(r, entries);
+                       goto nextrule;
+               }
                r->evaluations++;
                PF_TEST_ATTRIB((pfi_kif_match(r->kif, pd->kif) == r->ifnot),
                        r->skip[PF_SKIP_IFP].ptr);
@@ -3796,8 +3827,17 @@ pf_test_rule(struct pf_pdesc *pd, struct
        }
 #endif /* NPFSYNC > 0 */
 
-       if (r->rule_flag & PFRULE_ONCE)
-               pf_purge_rule(ruleset, r, aruleset, a);
+       if (r->rule_flag & PFRULE_ONCE) {
+               if ((a != NULL) && TAILQ_EMPTY(a->ruleset->rules.active.ptr)) {
+                       a->rule_flag |= PFRULE_EXPIRED;
+                       a->exptime = time_second;
+                       SLIST_INSERT_HEAD(&pf_rule_gcl, a, gcle);
+               }
+
+               r->rule_flag |= PFRULE_EXPIRED;
+               r->exptime = time_second;
+               SLIST_INSERT_HEAD(&pf_rule_gcl, r, gcle);
+       }
 
        return (action);
 
diff -r 8006a1eca673 src/sys/net/pf_ioctl.c
--- a/src/sys/net/pf_ioctl.c    Sat Sep 03 14:19:17 2016 +0200
+++ b/src/sys/net/pf_ioctl.c    Sat Sep 03 16:26:08 2016 +0200
@@ -309,12 +309,13 @@ pf_rm_rule(struct pf_rulequeue *rulequeu
 }
 
 void
-pf_purge_rule(struct pf_ruleset *ruleset, struct pf_rule *rule,
-    struct pf_ruleset *aruleset, struct pf_rule *arule)
+pf_purge_rule(struct pf_rule *rule)
 {
        u_int32_t                nr = 0;
+       struct pf_ruleset       *ruleset;
 
-       KASSERT(ruleset != NULL && rule != NULL);
+       KASSERT((rule != NULL) && (rule->ruleset != NULL));
+       ruleset = rule->ruleset;
 
        pf_rm_rule(ruleset->rules.active.ptr, rule);
        ruleset->rules.active.rcount--;
@@ -322,16 +323,6 @@ pf_purge_rule(struct pf_ruleset *ruleset
                rule->nr = nr++;
        ruleset->rules.active.ticket++;
        pf_calc_skip_steps(ruleset->rules.active.ptr);
-
-       /* remove the parent anchor rule */
-       if (nr == 0 && arule && aruleset) {
-               pf_rm_rule(aruleset->rules.active.ptr, arule);
-               aruleset->rules.active.rcount--;
-               TAILQ_FOREACH(rule, aruleset->rules.active.ptr, entries)
-                       rule->nr = nr++;
-               aruleset->rules.active.ticket++;
-               pf_calc_skip_steps(aruleset->rules.active.ptr);
-       }
 }
 
 u_int16_t
@@ -783,6 +774,9 @@ pf_commit_rules(u_int32_t ticket, char *
        int                      s, error;
        u_int32_t                old_rcount;
 
+       /* Make sure any expired rules get removed from active rules first. */
+       pf_purge_expired_rules(1);
+
        rs = pf_find_ruleset(anchor);
        if (rs == NULL || !rs->rules.inactive.open ||
            ticket != rs->rules.inactive.ticket)
@@ -1217,6 +1211,7 @@ 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++;
                break;
        }
@@ -1273,6 +1268,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
                pr->rule.rcv_kif = NULL;
                pr->rule.anchor = NULL;
                pr->rule.overload_tbl = NULL;
+               bzero(&pr->rule.gcle, sizeof(pr->rule.gcle));
+               pr->rule.ruleset = NULL;
                if (pf_anchor_copyout(ruleset, rule, pr)) {
                        error = EBUSY;
                        break;
diff -r 8006a1eca673 src/sys/net/pfvar.h
--- a/src/sys/net/pfvar.h       Sat Sep 03 14:19:17 2016 +0200
+++ b/src/sys/net/pfvar.h       Sat Sep 03 16:26:08 2016 +0200
@@ -571,6 +571,10 @@ struct pf_rule {
                struct pf_addr          addr;
                u_int16_t               port;
        }                       divert, divert_packet;
+
+       SLIST_ENTRY(pf_rule)     gcle;
+       struct pf_ruleset       *ruleset;
+       time_t                   exptime;
 };
 
 /* rule flags */
@@ -589,6 +593,7 @@ struct pf_rule {
 #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 */
 
 #define PFSTATE_HIWAT          10000   /* default state table size */
 #define PFSTATE_ADAPT_START    6000    /* default adaptive timeout start */
@@ -1666,6 +1671,7 @@ extern void                        
pf_calc_skip_steps(struct
 extern void                     pf_purge_thread(void *);
 extern void                     pf_purge_expired_src_nodes(int);
 extern void                     pf_purge_expired_states(u_int32_t);
+extern void                     pf_purge_expired_rules(int);
 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 *);
@@ -1695,9 +1701,7 @@ 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_ruleset *,
-                                   struct pf_rule *, struct pf_ruleset *,
-                                   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 *, void *,
                                    sa_family_t, int, struct pfi_kif *,

Reply via email to