[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: about the ULID in the TCP checksum



On 28-dec-2006, at 18:57, marcelo bagnulo braun wrote:

The problem here is that some intermediate system, such as a firewall or a smart NIC, may take it upon itself to check the TCP or UDP checksum and discard the packet if the checksum fails.

how common is this practice? is this widely used?

Certainly not with IPv6. But checksumming NICs are very common for IPv4 so I'm sure we'll have those for IPv6 too in the future. And at one point, PIX firewalls would truncate DNS packets that were longer than 512 bytes, creating much mayham with EDNS0. So I have a healthy suspicion of firewall builders.

For firewalls and the like, the best thing is probably either to fully monitor the shim state so they can do this properly, or forego such checking if a shim header is present.

yes, this is probably useful in terms of security also, just like in the case to TCP connections, where the firewall can decide to accept segments of connections for which the firewall have previosuly seen SYN exchange

do you think we should add text about this? (if you do, please send text)

"Firewalls and other middleboxes SHALL NOT drop TCP, UDP and ICMP packets with apparently incorrect checksums based on that fact alone unless they implement (monitoring of) the full shim6 protocol and are able to determine the checksum that must be present in a packet with addresses rewritten by shim6."

For NICs a better solution would be to do an incremental checksum verification and only over the ULP segment, so that the host stack must complete the calculation by applying the increment from the pseudo header, which can largely be cached, so the performance advantages are almost completely preserved

i don't understand what do you mean by incremental checksum verification... could you expand on this?

The checksum is defined as the one's complement of the one's complement additions of the 16-bit words making up the pseudo-header and the TCP/UDP/ICMP segment. So you could calculate it this way:

//  0  start
chksm = 0;

//  1  pseudoheader
for (i = 0; i < pseudo.length; i++)
  chcksm = 1cmpadd(chcksm, pseudo.hdr[i]);

//  2  TCP
for (i = 0; i < tcp.length; i++)
  chcksm = 1cmpadd(chcksm, tcp.data[i]);

//  3  check
if (1cmp(chcksm) == tcp.checksum)
  return happy;
else
  return sad;

As far as I can tell, NICs can do parts 0 - 2 and leave 3 up to the IP stack. This method isn't compatible with shim6 because then the NIC would have to be aware of the address rewriting. However, it wouldn't be hard to do 0 and 1 in the IP stack, 2 in the NIC and 3 in the IP stack again. Since the pseudoheader is always the same for a session, this part can be pre-computed, so the only part that actually requires real work is checking the TCP/UDP/ICMP segment, which is exactly the part that still happens in the NIC, so performance can be the same but now everything is shim-compatible.