Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions pkg/tcpip/header/udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,15 @@ func (b UDP) SetSourcePortWithChecksumUpdate(new uint16) {
}
old := b.SourcePort()
b.SetSourcePort(new)
b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
xsum := ^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new)
// RFC 768:
// If the computed checksum is zero, it is transmitted as all ones.
// An all zero transmitted checksum value means that
// the transmitter generated no checksum.
if xsum == 0 {
xsum = 0xFFFF
}
b.SetChecksum(xsum)
}

// SetDestinationPortWithChecksumUpdate implements ChecksummableTransport.
Expand All @@ -151,12 +159,16 @@ func (b UDP) SetDestinationPortWithChecksumUpdate(new uint16) {
}
old := b.DestinationPort()
b.SetDestinationPort(new)
b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
xsum := ^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new)
if xsum == 0 {
xsum = 0xFFFF
}
b.SetChecksum(xsum)
}

// UpdateChecksumPseudoHeaderAddress implements ChecksummableTransport.
func (b UDP) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address, fullChecksum bool) {
if b.Checksum() == 0 {
if fullChecksum && b.Checksum() == 0 {
return
}
xsum := b.Checksum()
Expand All @@ -167,6 +179,13 @@ func (b UDP) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address, fullCheck
xsum = checksumUpdate2ByteAlignedAddress(xsum, old, new)
if fullChecksum {
xsum = ^xsum
// RFC 768:
// If the computed checksum is zero, it is transmitted as all ones.
// An all zero transmitted checksum value means that
// the transmitter generated no checksum.
if xsum == 0 {
xsum = 0xFFFF
}
}

b.SetChecksum(xsum)
Expand Down
7 changes: 6 additions & 1 deletion pkg/tcpip/network/ipv4/ipv4.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,12 @@ func recalculateChecksum(pkt *stack.PacketBuffer, r *stack.Route) tcpip.Error {
xsum := r.PseudoHeaderChecksum(header.UDPProtocolNumber, netHdr.PayloadLength())
xsum = checksum.Combine(xsum, pkt.Data().Checksum())
udp.SetChecksum(0)
udp.SetChecksum(^udp.CalculateChecksum(xsum))
csum := ^udp.CalculateChecksum(xsum)
// RFC 768: If the computed checksum is zero, it is transmitted as all ones.
if csum == 0 {
csum = 0xFFFF
}
udp.SetChecksum(csum)
}
return nil
}
Expand Down
24 changes: 22 additions & 2 deletions pkg/tcpip/nftables/nft_payload_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,23 @@ func (op payloadSet) evaluate(regs *registerSet, evalCtx opEvalCtx) {
// Reads the old checksum from the packet payload.
oldTotalCsum := binary.BigEndian.Uint16(payload[op.csumOffset:])

updateUDPCsum := op.base == linux.NFT_PAYLOAD_TRANSPORT_HEADER && pkt.TransportProtocolNumber == header.UDPProtocolNumber

// If the UDP checksum is 0, it means the checksum is not set.
if updateUDPCsum && oldTotalCsum == 0 {
return
}

// New Total = Old Total - Old Data + New Data
// Logic is very similar to checksum.checksumUpdate2ByteAlignedUint16
// in gvisor/pkg/tcpip/header/checksum.go
newTotalCsum := checksum.Combine(^oldTotalCsum, checksum.Combine(newDataCsum, ^oldDataCsum))
checksum.Put(payload[op.csumOffset:], ^newTotalCsum)
csum := ^newTotalCsum
// If the UDP checksum is 0, set it to all ones.
if updateUDPCsum && csum == 0 {
csum = 0xFFFF
}
checksum.Put(payload[op.csumOffset:], csum)
}

// Separately updates the L4 checksum if the pseudo-header flag is set.
Expand All @@ -189,8 +201,16 @@ func (op payloadSet) evaluate(regs *registerSet, evalCtx opEvalCtx) {
transport = header.IGMP(tBytes)
}
if transport != nil { // only updates if the transport header is present.
isUDP := pkt.TransportProtocolNumber == header.UDPProtocolNumber
if isUDP && transport.Checksum() == 0 {
return
}
// New Total = Old Total - Old Data + New Data (same as above)
transport.SetChecksum(^checksum.Combine(^transport.Checksum(), checksum.Combine(newDataCsum, ^oldDataCsum)))
csum := ^checksum.Combine(^transport.Checksum(), checksum.Combine(newDataCsum, ^oldDataCsum))
if isUDP && csum == 0 {
csum = 0xFFFF
}
transport.SetChecksum(csum)
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/tcpip/stack/packet_buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,11 @@ func (pk *PacketBuffer) CalculateTransportChecksum() {
xsum = header.PseudoHeaderChecksum(proto, src, dst, totalLen)
xsum = checksum.Combine(xsum, pk.Data().Checksum())
t.SetChecksum(0)
t.SetChecksum(^t.CalculateChecksum(xsum))
csum := ^t.CalculateChecksum(xsum)
// udp csum RFC 768.
if csum == 0 {
csum = 0xFFFF
}
t.SetChecksum(csum)
}
}
Loading