rdr pass for proto tcp sometimes creates states with expire time zero and so breaking connections
Kristof Provost
kristof at sigsegv.be
Thu Oct 18 18:11:57 UTC 2018
On 15 Oct 2018, at 15:26, Andreas Longwitz wrote:
> On two of my FreeBSD 10 (r338093) firewall servers some incoming ssh
> connections stopped to work because pf started to create states with
> expire time zero (instead of 86400 sec) for translation statements
> like
>
> rdr pass on em0 proto tcp from any to myip port 8022 --> 10.0.0.254
>
> Therefore a command given on a remote server like
>
> ssh -p 8022 myip sleep 15
>
> did not return, because the created state for the connection was
> purged
> by pf (interval 10 sec) before 15 seconds. If I replace the rdr pass
> rule with a rdr rule and a separate filter pass rule then the created
> state always has expire time 24h and everything is ok.
>
> I have tried to analyze the bug in the rdr pass rule. Immediately
> after
> starting the above ssh command on the remote sever I see with pfctl
> -vss
> the sreated state on my firewall machine:
>
> all tcp 10.0.0.254:8022 (myip:8022) <- remoteip:59233
> ESTABLISHED:ESTABLISHED
> [1443872812 + 66608] wscale 6 [1365307391 + 66560] wscale 3
> age 00:00:00, expires in 00:00:00, 13:12 pkts, 2955:3306 bytes
>
> and a DTrace script running at the same time gives
>
> 3 19323 pfsync_state_export:entry
> creation=4491391. expire=4491391, state_timeout=2
> 3 16459 pf_state_expires:entry
> state_timeout=86400,
> start_timeout=6000, end_timeout=12000 states=882
> 3 17624 counter_u64_fetch:entry
> 3 17625 counter_u64_fetch:return
> returncode (states_cur)=4294967248 = 0xffffffd0
> 3 16460 pf_state_expires:return
> returncode=4491391
> 3 19324 pfsync_state_export:return
> creation=0. expire=0, syncstate_timeout=2
> 0 12730 pfioctl:return
> returncode=0, time_uptime=4491391
>
> So pf_state_expires() returns the value time_update and therefore
> pfsync_state_export() gives expire zero. Reason for this is the very
> big
> (means negative) value returned by the function counter_u64_fetch()
> for
> states_cur. This variable is of type uint64_t and only incremented and
> decremented by the macros STATE_INC_COUNTERS and STATE_DEC_COUNTERS.
>
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);
}
Best regards,
Kristof
More information about the freebsd-pf
mailing list