On Tue, Jul 22, 2014 at 19:03 +0200, Mike Belopuhov wrote:
> Hi,
> 
> Before I send a diff for pfctl to disable "once" on "match" rules,
> I've decided to try and see how much work is it to make it actually
> work.  Turns out that I need to extend pf_rule_item by 3 pointers
> to track the match rule ruleset, anchor rule and the ruleset it
> belongs to.
> 
> Here's what this means in practice.  Consider a ruleset:
> 
>  block drop all
>  match out log proto tcp to port 22 once
>  anchor "foo" all {
>    match out log proto tcp to port 22 once
>    anchor "bar" all {
>      match out log proto tcp to port 22 once
>      pass out quick proto tcp to port 22 once
>    }
>  }
> 
> Once we send a packet to port 22 the ruleset collapses to just:
> 
>  block drop all
> 
> Thoughts?

Henning thinks it's a bit of an overkill.  Any other opinions?

> 
> diff --git sys/net/pf.c sys/net/pf.c
> index 9f0e2d6..5679a40 100644
> --- sys/net/pf.c
> +++ sys/net/pf.c
> @@ -3279,15 +3279,16 @@ pf_test_rule(struct pf_pdesc *pd, struct pf_rule 
> **rm, struct pf_state **sm,
>                                   PR_NOWAIT)) == NULL) {
>                                       REASON_SET(&reason, PFRES_MEMORY);
>                                       goto cleanup;
>                               }
>                               ri->r = r;
> +                             ri->ar = a;
> +                             ri->rs = ruleset;
> +                             ri->ars = aruleset;
>                               /* order is irrelevant */
>                               SLIST_INSERT_HEAD(&rules, ri, entry);
>                               pf_rule_to_actions(r, &act);
> -                             if (r->rule_flag & PFRULE_AFTO)
> -                                     pd->naf = r->naf;
>                               if (pf_get_transaddr(r, pd, sns, &nr) == -1) {
>                                       REASON_SET(&reason, PFRES_TRANSLATE);
>                                       goto cleanup;
>                               }
>                               if (r->log || act.log & PF_LOG_MATCHES) {
> @@ -3428,10 +3429,12 @@ pf_test_rule(struct pf_pdesc *pd, struct pf_rule 
> **rm, struct pf_state **sm,
>                           virtual_type, icmp_dir);
>               }
>       } else {
>               while ((ri = SLIST_FIRST(&rules))) {
>                       SLIST_REMOVE_HEAD(&rules, entry);
> +                     if (ri->r->rule_flag & PFRULE_ONCE)
> +                             pf_purge_rule(ri->rs, ri->r, ri->ars, ri->ar);
>                       pool_put(&pf_rule_item_pl, ri);
>               }
>       }
>  
>       /* copy back packet headers if needed */
> @@ -3454,10 +3457,23 @@ pf_test_rule(struct pf_pdesc *pd, struct pf_rule 
> **rm, struct pf_state **sm,
>       }
>  #endif
>  
>       if (r->rule_flag & PFRULE_ONCE)
>               pf_purge_rule(ruleset, r, aruleset, a);
> +     if (*sm) {
> +             SLIST_FOREACH(ri, &(*sm)->match_rules, entry) {
> +                     if (ri->r->rule_flag & PFRULE_ONCE)
> +                             /*
> +                              * We can be sure that pf_purge_rule won't
> +                              * pool_put the rule because when *sm != NULL
> +                              * STATE_INC_COUNTERS has increased states_cur.
> +                              * pf_rule_item's and rules will be g/c'ed by
> +                              * pf_free_state.
> +                              */
> +                             pf_purge_rule(ri->rs, ri->r, ri->ars, ri->ar);
> +             }
> +     }
>  
>  #if INET && INET6
>       if (rewrite && skw->af != sks->af)
>               return (PF_AFRT);
>  #endif /* INET && INET6 */
> diff --git sys/net/pfvar.h sys/net/pfvar.h
> index a0d94f7..49af7b4 100644
> --- sys/net/pfvar.h
> +++ sys/net/pfvar.h
> @@ -691,10 +691,13 @@ struct pf_threshold {
>  };
>  
>  struct pf_rule_item {
>       SLIST_ENTRY(pf_rule_item)        entry;
>       struct pf_rule                  *r;
> +     struct pf_rule                  *ar;
> +     struct pf_ruleset               *rs;
> +     struct pf_ruleset               *ars;
>  };
>  
>  SLIST_HEAD(pf_rule_slist, pf_rule_item);
>  
>  enum pf_sn_types { PF_SN_NONE, PF_SN_NAT, PF_SN_RDR, PF_SN_ROUTE, PF_SN_MAX 
> };

Reply via email to