Checksumming outgoing packets in PF vs in ip_output
ilya at bakulin.de
Wed Nov 5 14:28:10 UTC 2014
I have been hit by this 2-year-old bug with PF and 'scrub reassemble
tcp' on IPv6 connections:
I have been able to trace it down to the modifications of timestamp
values by timestamp modulation code .
If I remove those two pf_change_a() calls in the output path (pd->dir ==
PF_OUT) then everything works as it should, except that the timestamps
are not modulated which is kinda sucks.
Of course it was interesting what does the upstream PF do (@ OpenBSD).
Seems they have made the decision to
leave the task of recalculating the checksums for outgoing packets to
ip_output, because currently
the code there overwrites the checksum anyway.
This seems a correct way to me. pf should not longer do any checksum
updates in inbound and outbound path.
For inbound path, it should however check the checksum correctness and
set a flag in mbuf csum flags so
the tcp_input doesn't try to verify it. In this case even if we
modify something while applying TS modulation
or sequence number modulation or something else in PF the upper-layer
because it will see that the checksum was already verified and won't try
to verify it once again.
OpenBSD does it this way and they seem to be happy.
For now, I decided to leave the inbound path as-is and instead wanted to
fix the outbound path.
The patch  solves the problem described in  in the following way:
1) Hijack the last argument of pf_change_a() so that it doesn't update
the checksum of the packet;
2) When updating the timestamps in pf_normalize_tcp_stateful() call
pf_change_a() in "no-update-checksum" mode;
3) In pf_check_out() remove the checks for CSUM_DELAY_DATA -- don't
calculate the checksum in any case.
Such fix should be done in pf_check6_out() as well, but in my test setup
I haven't seen that flag anyway.
In future we probably should implement pf_change_a changes the same or
similar way OpenBSD does it.
More information about the freebsd-net