rdr pass for proto tcp sometimes creates states with expire time zero and so breaking connections
Kristof Provost
kristof at sigsegv.be
Sat Oct 27 17:44:40 UTC 2018
On 27 Oct 2018, at 5:22, Andreas Longwitz wrote:
> Thanks very much for answer especially for the hint to openbsd.
>
>> I wonder if there’s an integer overflow in the of_state_expires()
>> calculation.
>> The OpenBSD people have a cast to u_int64_t in their version:
>>
>> |timeout = (u_int64_t)timeout * (end - states) / (end - start);
>> |
>>
>> Perhaps this would fix your problem? (Untested, not even compiled)
>>
>> | if (end && states > start && start < end) {
>> if (states < end) {
>> timeout = (uint64_t)timeout * (end - states) /
>> (end - start);
>> return (state->expire + timeout;
>> }
>> else
>> return (time_uptime);
>> }
>> return (state->expire + timeout);
>
> I can confirm the patch of the openbsd people adding the uint64_t cast
> makes sense. If
> timeout * (end - states)
> becomes bigger than UINT32_MAX (I am on i386) the cast prevents the
> overflow of this product and the result of the adaptive calculation
> will
> always be correct.
>
> Example: start=6000, end=12000, timeout=86400 * 5 (5 days), states=100
> result 140972, result with cast patch 856800.
>
> In the problem I have reported for states of "rdr pass" rules I see
> start=6000, end=12000, timeout=86400 and (obviously erroneous,
> probably
> negative) states=0xffffffd0.
>
I have no idea how that can happen. Just to make sure I understand: you
know that states is negative here because of a printf() or SDT addition
in pf_expire_states(), right?
> Further the counter variable for states_cur of pf_default_rule is
> used für all "rdr/nat/binat pass" rules together. This was a little
> bit
> suprising for me, but I think this is intended behaviour. Correct ?
>
Yes.
> Are there any hints why the counter pf_default_rule->states_cur
> could get a negative value ?
>
I’m afraid I have no idea right now.
Best regards,
Kristof
More information about the freebsd-pf
mailing list