rdr pass for proto tcp sometimes creates states with expire time zero and so breaking connections

Andreas Longwitz longwitz at incore.de
Tue Feb 19 21:53:17 UTC 2019


Kristof Provost wrote:
> 
>     Because fetching a counter is a rather expansive function we should use
>     counter_u64_fetch() in pf_state_expires() only when necessary. A "rdr
>     pass" rule should not cause more effort than separate "rdr" and "pass"
>     rules. For rules with adaptive timeout values the call of
>     counter_u64_fetch() should be accepted, but otherwise not.
> 
>     For a small gain in performance especially for "rdr pass" rules I
>     suggest something like
> 
>     --- pf.c.orig 2019-02-18 17:49:22.944751000 +0100
>     +++ pf.c 2019-02-18 17:55:07.396163000 +0100
>     @@ -1558,7 +1558,7 @@
>     if (!timeout)
>        timeout = V_pf_default_rule.timeout[state->timeout];
>     start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
>   - if (start) {
>   + if (start && state->rule.ptr != &V_pf_default_rule) {
>        end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
>        states = counter_u64_fetch(state->rule.ptr->states_cur);
>     } else {
> 
> I think that looks correct. Do you have any performance measurements on
> this?

No

> Although presumably it only really matters in cases where there’s no
> explicit catch-all rule, so I do wonder if it’s worth it.

Sorry, but I do not understand this argument.

>From manpage:
   The adaptive timeout values can be defined both globally and for
   each rule.  When used on a per-rule basis, the values relate to the
   number of states created by the rule, otherwise to the total number
   of states.

This handling of adaptive timeouts is done in pf_state_expires():

     start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
     if (start) {
             end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
             states = counter_u64_fetch(state->rule.ptr->states_cur);
     } else {
             start = V_pf_default_rule.timeout[PFTM_ADAPTIVE_START];
             end = V_pf_default_rule.timeout[PFTM_ADAPTIVE_END];
             states = V_pf_status.states;
     }

The following calculation needs three values: start, end and states.

1. Normal rules "pass .." without adaptive setting meaning "start = 0"
   runs in the else-section of the code snippet and therefore takes
   "start" and "end" from the global default settings and sets "states"
   to pf_status.states (= total number of states).

2. Special rules like
       "pass .. keep state (adaptive.start 500 adaptive.end 1000)"
   have start != 0, run in the if-section of the code snippet and take
   "start" and "end" from the rule and set "states" to the number of
   states created by their rule using counter_u64_fetch().

Thats all ok, but there is a third case without special handling in the
above code snippet:

3. All "rdr/nat pass .." statements use together the pf_default_rule.
   Therefore we have "start != 0" in this case and we run the
   if-section of the code snippet but we better should run the
   else-section in this case and do not fetch the counter of the
   pf_default_rule but take the total number of states.

Thats what the patch does.


Regards
Andreas


More information about the freebsd-pf mailing list