Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 05 Nov 2014 15:28:07 +0100
From:      Ilya Bakulin <ilya@bakulin.de>
To:        freebsd-pf@freebsd.org, freebsd-hackers@freebsd.org, freebsd-net@freebsd.org
Subject:   Checksumming outgoing packets in PF vs in =?UTF-8?Q?ip=5B=36=5D?= =?UTF-8?Q?=5Foutput?=
Message-ID:  <d2f0c43909d9c9bada9a5bda7719cfca@mail.bakulin.de>

next in thread | raw e-mail | index | archive | help
Hi all,

I have been hit by this 2-year-old bug with PF and 'scrub reassemble 
tcp' on IPv6 connections:
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=172648

I have been able to trace it down to the modifications of timestamp 
values by timestamp modulation code [1].
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[6]_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[6]_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 
won't bailout
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 [2] solves the problem described in [2] 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.

[1] 
https://github.com/freebsd/freebsd/blob/49c137f7be5791eee8102395257cdf48b40c81f7/sys/netpfil/pf/pf_norm.c#L1569
[2] http://dl.bakulin.de/freebsd/pf_fix_reass_tcp_ipv6.diff



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?d2f0c43909d9c9bada9a5bda7719cfca>