mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Skip incremental checksum update for unmodified fields
This is important for correctness, because the current incremental checksum
update routine does not work correctly when the field is set to the same value.
See this equation from RFC 1071:
C - one's complement sum of old header
C' - one's complement sum of new header
m - old value of a 16-bit field
m' - new value of a 16-bit field
C' = C + (-m) + m' = C + (m' - m)
Assuming m is a 16-bit field, when m == m', then (m' - m) == (m + ~m) will
always equal -0, or 0xFFFF in one's complement arithmetic, rather than 0x0000.
The additive identity is typically 0, but since -0 has a different
representation, it is *not* an identity and therefore the equation produces a
different value.
PiperOrigin-RevId: 610963455
This commit is contained in:
committed by
gVisor bot
parent
8841a6e25c
commit
ccc3c2cbd2
@@ -57,6 +57,9 @@ func checksumUpdate2ByteAlignedUint16(xsum, old, new uint16) uint16 {
|
||||
// checksum C, the new checksum C' is:
|
||||
//
|
||||
// C' = C + (-m) + m' = C + (m' - m)
|
||||
if old == new {
|
||||
return xsum
|
||||
}
|
||||
return checksum.Combine(xsum, checksum.Combine(new, ^old))
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package header_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
@@ -89,6 +90,24 @@ func TestICMPv4Checksum(t *testing.T) {
|
||||
}, want, fmt.Sprintf("header: {% x} data {% x}", h, b.Flatten()))
|
||||
}
|
||||
|
||||
func TestICMPv4ChecksumUpdate(t *testing.T) {
|
||||
const icmpIdent = 0
|
||||
|
||||
data := make([]byte, header.ICMPv4MinimumSize)
|
||||
h := header.ICMPv4(data)
|
||||
h.SetType(header.ICMPv4EchoReply)
|
||||
h.SetCode(header.ICMPv4UnusedCode)
|
||||
h.SetIdent(icmpIdent)
|
||||
h.SetChecksum(^checksum.Checksum(data, 0))
|
||||
|
||||
updated := header.ICMPv4(bytes.Clone(data))
|
||||
// Perform an incremental checksum update where we aren't actually changing the ID.
|
||||
updated.SetIdentWithChecksumUpdate(icmpIdent)
|
||||
if updated.Checksum() != h.Checksum() {
|
||||
t.Errorf("got updated.Checksum() = %x, want = %x", updated.Checksum(), h.Checksum())
|
||||
}
|
||||
}
|
||||
|
||||
func TestICMPv6Checksum(t *testing.T) {
|
||||
rnd := rand.New(rand.NewSource(42))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user