Checksum simplification proposal (#29)

* Simplified checksum calculation and verification

* Fixed tests

* UDP: using NewBoundedFrame to create a Frame instance limited to the actual frame size.

* Minor: renamed some functions

* Commented and made more readable consecutive SetCRC calls.

* Fixed icmp checksum calculation after rebase

* Replaced NewBoundedFrame with explicit validation
This commit is contained in:
ddirect
2026-02-05 22:35:42 +02:00
committed by GitHub
parent cd51bd6c3f
commit fba97c990a
13 changed files with 139 additions and 228 deletions
+30 -63
View File
@@ -12,34 +12,24 @@ import (
// The zero value of CRC791 is ready to use.
type CRC791 struct {
sum uint32
excedent uint8
needPad bool
}
// Write adds the bytes in p to the running checksum.
func (c *CRC791) Write(buff []byte) (n int, err error) {
if len(buff) == 0 {
return 0, nil
func sum16(sum uint32) uint16 {
sum = (sum & 0xffff) + sum>>16
// the max value of sum at this point is 0x1fffe, so an additional round is enough
return ^uint16(sum + sum>>16)
}
if c.needPad {
c.sum += uint32(c.excedent)<<8 + uint32(buff[0])
buff = buff[1:]
c.excedent = 0
c.needPad = false
if len(buff) == 0 {
return 1, nil
func sumWriteEven(sum uint32, buff []byte) uint32 {
for i := 0; i < len(buff); i += 2 {
sum += uint32(binary.BigEndian.Uint16(buff[i:]))
}
return sum
}
count := len(buff)
for count > 1 {
c.sum += uint32(binary.BigEndian.Uint16(buff[len(buff)-count:]))
count -= 2
}
if count != 0 {
c.excedent = buff[len(buff)-1]
c.needPad = true
}
return len(buff), nil
// Write adds the bytes in p to the running checksum. The buffer size must be even or the function will panic.
func (c *CRC791) WriteEven(buff []byte) {
c.sum = sumWriteEven(c.sum, buff)
}
// AddUint32 adds a 32 bit value to the running checksum interpreted as BigEndian (network order).
@@ -50,55 +40,32 @@ func (c *CRC791) AddUint32(value uint32) {
// Add16 adds a 16 bit value to the running checksum interpreted as BigEndian (network order).
func (c *CRC791) AddUint16(value uint16) {
if c.needPad {
c.sum += uint32(c.excedent)<<8 | uint32(value>>8)
c.excedent = byte(value)
} else {
c.sum += uint32(value)
}
}
// Add16 adds value to the running checksum interpreted as BigEndian (network order).
func (c *CRC791) AddUint8(value uint8) {
if c.needPad {
c.sum += uint32(c.excedent)<<8 | uint32(value)
} else {
c.excedent = value
}
c.needPad = !c.needPad
}
func (c *CRC791) sum16() uint16 {
sum := c.sum
if c.needPad {
sum += uint32(c.excedent) << 8
}
for sum>>16 != 0 {
sum = (sum & 0xffff) + (sum >> 16)
}
return uint16(^sum)
}
// Sum16 calculates the checksum with the data written to c thus far.
func (c *CRC791) Sum16() uint16 {
sum16 := c.sum16()
if sum16 == 0 {
// The zero value is always transmitted as 0xFFFF, as required by UDP (RFC 768), and still valid for TCP and IP.
sum16 = 0xffff
}
return sum16
return sum16(c.sum)
}
// VerifySum16 verifies that the given checksum matches the data written to c thus far.
func (c *CRC791) VerifySum16(expectedSum16 uint16) bool {
// as recommended by RFC 1624, this implementation supports both 0x0000 and 0xFFFF as zero value for the checksum
cc := *c
if cc.needPad {
cc.AddUint8(0)
// PayloadSum16 returns the checksum resulting by adding the bytes in p to the running checksum.
func (c *CRC791) PayloadSum16(buff []byte) uint16 {
odd := len(buff) & 1
sum := sumWriteEven(c.sum, buff[:len(buff)-odd])
if odd > 0 {
sum += uint32(buff[len(buff)-1]) << 8
}
cc.AddUint16(expectedSum16)
return cc.sum16() == 0
return sum16(sum)
}
// Reset zeros out the CRC791, resetting it to the initial state.
func (c *CRC791) Reset() { *c = CRC791{} }
// NonZeroChecksum ensures that the given checksum is not zero, by returning 0xffff instead.
func NeverZeroSum(sum16 uint16) uint16 {
// 0x0000 and 0xffff are the same number in ones' complement math
if sum16 == 0 {
return 0xffff
}
return sum16
}
+8 -4
View File
@@ -94,7 +94,10 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
ifrm.SetProtocol(lneto.IPProtoTCP)
*ifrm.SourceAddr() = gen.SrcIPv4
*ifrm.DestinationAddr() = gen.DstIPv4
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
// Zero the CRC field so its value does not add to the final result.
ifrm.SetCRC(0)
crcValue := ifrm.CalculateHeaderCRC()
ifrm.SetCRC(crcValue)
ipPayload := ifrm.Payload()
tfrm, err := tcp.NewFrame(ipPayload)
@@ -124,9 +127,10 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
copy(tfrm.Options(), tcpOpts)
var crc lneto.CRC791
ifrm.CRCWriteTCPPseudo(&crc)
tfrm.CRCWrite(&crc)
tfrm.SetCRC(crc.Sum16())
// Zero the CRC field so its value does not add to the final result.
tfrm.SetCRC(0)
crcValue = crc.PayloadSum16(tfrm.RawData())
tfrm.SetCRC(crcValue)
switch {
case gen.SrcTCP != tfrm.SourcePort():
panic("IP options overwrite TCP header")
+31 -51
View File
@@ -161,27 +161,26 @@ func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) (
end := bitOffset + 40*octet
var protoErrs []error
var crc lneto.CRC791
if proto == lneto.IPProtoTCP {
ifrm6.CRCWritePseudo(&crc)
tfrm, err := tcp.NewFrame(ifrm6.Payload())
if err == nil {
tfrm.CRCWrite(&crc)
wantSum := crc.Sum16()
gotSum := tfrm.CRC()
if wantSum != gotSum {
protoErrs = append(protoErrs, &crcError16{protocol: "ipv6+tcp", want: wantSum, got: gotSum})
switch proto {
case lneto.IPProtoTCP:
if crc.PayloadSum16(ifrm6.Payload()) != 0 {
protoErrs = append(protoErrs, lneto.ErrBadCRC)
}
}
} else if proto == lneto.IPProtoUDP || proto == lneto.IPProtoUDPLite {
ifrm6.CRCWritePseudo(&crc)
case lneto.IPProtoUDP, lneto.IPProtoUDPLite:
ufrm, err := udp.NewFrame(ifrm6.Payload())
if err == nil {
ufrm.CRCWriteIPv6(&crc)
wantSum := crc.Sum16()
gotSum := ufrm.CRC()
if wantSum != gotSum {
protoErrs = append(protoErrs, &crcError16{protocol: "ipv6+udp", want: wantSum, got: gotSum})
if err != nil {
protoErrs = append(protoErrs, err)
break
}
ufrm.ValidateSize(pc.validator())
if err = pc.validator().ErrPop(); err != nil {
protoErrs = append(protoErrs, err)
break
}
frameLen := ufrm.Length()
if crc.PayloadSum16(ufrm.RawData()[:frameLen]) != 0 {
protoErrs = append(protoErrs, lneto.ErrBadCRC)
}
}
return pc.captureIPProto(proto, dst, pkt, end, protoErrs...)
@@ -214,57 +213,48 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
BitLength: octet * len(options),
})
}
gotSum := ifrm4.CRC()
wantSum := ifrm4.CalculateHeaderCRC()
if gotSum != wantSum {
finfo.Errors = append(finfo.Errors, &crcError16{protocol: "ipv4", want: wantSum, got: gotSum})
if ifrm4.CalculateHeaderCRC() != 0 {
finfo.Errors = append(finfo.Errors, lneto.ErrBadCRC)
}
dst = append(dst, finfo)
proto := ifrm4.Protocol()
end := bitOffset + octet*ifrm4.HeaderLength()
var protoErrs []error
var crc lneto.CRC791
payload := ifrm4.Payload()
switch proto {
case lneto.IPProtoTCP:
ifrm4.CRCWriteTCPPseudo(&crc)
tfrm, err := tcp.NewFrame(ifrm4.Payload())
tfrm, err := tcp.NewFrame(payload)
if err == nil {
tfrm.ValidateSize(pc.validator())
if pc.vld.HasError() {
println("BAD TCP")
return dst, pc.vld.ErrPop()
}
tfrm.CRCWrite(&crc)
wantSum := crc.Sum16()
gotSum := tfrm.CRC()
if wantSum != gotSum {
protoErrs = append(protoErrs, &crcError16{protocol: "ipv4+tcp", want: wantSum, got: gotSum})
ifrm4.CRCWriteTCPPseudo(&crc)
if crc.PayloadSum16(payload) != 0 {
protoErrs = append(protoErrs, lneto.ErrBadCRC)
}
}
case lneto.IPProtoUDP:
ifrm4.CRCWriteUDPPseudo(&crc)
ufrm, err := udp.NewFrame(ifrm4.Payload())
ufrm, err := udp.NewFrame(payload)
if err == nil {
ufrm.ValidateSize(pc.validator())
if pc.vld.HasError() {
println("BAD UDP")
return dst, pc.vld.ErrPop()
}
ufrm.CRCWriteIPv4(&crc)
wantSum := crc.Sum16()
gotSum := ufrm.CRC()
if wantSum != gotSum {
protoErrs = append(protoErrs, &crcError16{protocol: "ipv4+udp", want: wantSum, got: gotSum})
frameLen := ufrm.Length()
ifrm4.CRCWriteUDPPseudo(&crc, frameLen)
if crc.PayloadSum16(ufrm.RawData()[:frameLen]) != 0 {
protoErrs = append(protoErrs, lneto.ErrBadCRC)
}
}
case lneto.IPProtoICMP:
ifrm, err := icmpv4.NewFrame(ifrm4.Payload())
_, err := icmpv4.NewFrame(payload)
if err == nil {
ifrm.CRCWrite(&crc)
wantSum := crc.Sum16()
gotSum := ifrm.CRC()
if wantSum != gotSum {
protoErrs = append(protoErrs, &crcError16{protocol: "icmpv4", want: wantSum, got: gotSum})
if crc.PayloadSum16(payload) != 0 {
protoErrs = append(protoErrs, lneto.ErrBadCRC)
}
}
}
@@ -1309,13 +1299,3 @@ func remainingFrameInfo(proto any, class FieldClass, pktBitOffset, pktBitLen int
}},
}
}
type crcError16 struct {
protocol string
want uint16
got uint16
}
func (cerr *crcError16) Error() string {
return fmt.Sprintf("%s:incorrect checksum. want 0x%x, got 0x%x", cerr.protocol, cerr.want, cerr.got)
}
+1
View File
@@ -447,6 +447,7 @@ func ExampleFormatter_dhcp() {
totalLen := ipv4Size + udpSize + dhcpLen
ifrm.SetTotalLength(uint16(totalLen))
ufrm.SetLength(uint16(udpSize + dhcpLen))
// The CRC field is already zero here.
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
pkt = pkt[:ethSize+totalLen]
+30 -34
View File
@@ -10,7 +10,6 @@ import (
"github.com/soypat/lneto/ethernet"
"github.com/soypat/lneto/internal"
"github.com/soypat/lneto/ipv4"
"github.com/soypat/lneto/ipv4/icmpv4"
"github.com/soypat/lneto/tcp"
"github.com/soypat/lneto/udp"
)
@@ -91,11 +90,9 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error {
return err
}
// Incoming CRC Validation of common IP Protocols.
var crc lneto.CRC791
ifrm.CRCWriteHeader(&crc)
if !crc.VerifySum16(ifrm.CRC()) {
if ifrm.CalculateHeaderCRC() != 0 {
sb.handlers.error("ip:demux.crc")
return lneto.ErrBadCRC
}
off := ifrm.HeaderLength()
totalLen := ifrm.TotalLength()
@@ -111,28 +108,27 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error {
return lneto.ErrPacketDrop
}
// Incoming CRC Validation of common IP Protocols.
crc.Reset()
var crc lneto.CRC791
switch proto {
case lneto.IPProtoTCP:
ifrm.CRCWriteTCPPseudo(&crc)
tfrm, err := tcp.NewFrame(ifrm.Payload())
if err != nil {
return err
}
tfrm.CRCWrite(&crc)
if !crc.VerifySum16(tfrm.CRC()) {
if crc.PayloadSum16(ifrm.Payload()) != 0 {
sb.handlers.error("ip:demux.tcpcrc")
return lneto.ErrBadCRC
}
case lneto.IPProtoUDP:
ifrm.CRCWriteUDPPseudo(&crc)
ufrm, err := udp.NewFrame(ifrm.Payload())
if err != nil {
return err
}
ufrm.CRCWriteIPv4(&crc)
// checksums are optional in UDP: the field is set to zero in this case
if gotCrc := ufrm.CRC(); gotCrc != 0 && !crc.VerifySum16(gotCrc) {
ufrm.ValidateSize(&sb.validator)
if err = sb.validator.ErrPop(); err != nil {
sb.handlers.error("ip:demux.udpvalidatesize")
return err
}
frameLen := ufrm.Length()
ifrm.CRCWriteUDPPseudo(&crc, frameLen)
if crc.PayloadSum16(ufrm.RawData()[:frameLen]) != 0 {
sb.handlers.error("ip:demux.udpcrc")
return lneto.ErrBadCRC
}
@@ -174,25 +170,29 @@ func (sb *StackIP) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int
totalLen := n + headerlen
ifrm.SetTotalLength(uint16(totalLen))
ifrm.SetProtocol(proto)
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
// Zero the CRC field so its value does not add to the final result.
ifrm.SetCRC(0)
crcValue := ifrm.CalculateHeaderCRC()
ifrm.SetCRC(crcValue)
// Calculate CRC for our newly generated packet.
var crc lneto.CRC791
payload := ifrm.Payload()
switch proto {
case lneto.IPProtoTCP:
ifrm.CRCWriteTCPPseudo(&crc)
tfrm, _ := tcp.NewFrame(ifrm.Payload())
tfrm.CRCWrite(&crc)
tfrm.SetCRC(crc.Sum16())
tfrm, _ := tcp.NewFrame(payload)
// Zero the CRC field so its value does not add to the final result.
tfrm.SetCRC(0)
crcValue = crc.PayloadSum16(payload)
tfrm.SetCRC(crcValue)
case lneto.IPProtoUDP:
ifrm.CRCWriteUDPPseudo(&crc)
ufrm, _ := udp.NewFrame(ifrm.Payload())
ufrm, _ := udp.NewFrame(payload)
ifrm.CRCWriteUDPPseudo(&crc, uint16(n))
ufrm.SetLength(uint16(n))
ufrm.CRCWriteIPv4(&crc)
ufrm.SetCRC(crc.Sum16())
if n != int(ufrm.Length()) {
sb.handlers.error("StackIP:encaps", slog.Int("n", n), slog.Int("un", int(ufrm.Length())))
return 0, errors.New("invalid UDP length")
}
// Zero the CRC field so its value does not add to the final result.
ufrm.SetCRC(0)
crcValue = lneto.NeverZeroSum(crc.PayloadSum16(payload))
ufrm.SetCRC(crcValue)
}
return totalLen, err
}
@@ -206,13 +206,9 @@ func (sb *StackIP) Register(h StackNode) error {
}
func (sb *StackIP) recvicmp(carrierData []byte, offset int) error {
frameData := carrierData[offset:]
var crc lneto.CRC791
cfrm, err := icmpv4.NewFrame(carrierData[offset:])
if err != nil {
return err
}
cfrm.CRCWrite(&crc)
if !crc.VerifySum16(cfrm.CRC()) {
if crc.PayloadSum16(frameData) != 0 {
return errors.New("ICMP CRC mismatch")
}
return nil
+10 -8
View File
@@ -136,23 +136,25 @@ func (ifrm Frame) CalculateHeaderCRC() uint16 {
}
func (ifrm Frame) CRCWriteHeader(crc *lneto.CRC791) {
crc.Write(ifrm.buf[0:10])
crc.Write(ifrm.buf[12:20])
crc.WriteEven(ifrm.buf[:20])
}
func (ifrm Frame) CRCWriteTCPPseudo(crc *lneto.CRC791) {
crc.Write(ifrm.SourceAddr()[:])
crc.Write(ifrm.DestinationAddr()[:])
crc.AddUint16(ifrm.TotalLength() - 4*uint16(ifrm.ihl()))
crc.WriteEven(ifrm.sourceAndDestinationAddr())
crc.AddUint16(ifrm.TotalLength() - uint16(ifrm.HeaderLength()))
crc.AddUint16(uint16(ifrm.Protocol()))
}
func (ifrm Frame) CRCWriteUDPPseudo(crc *lneto.CRC791) {
crc.Write(ifrm.SourceAddr()[:])
crc.Write(ifrm.DestinationAddr()[:])
func (ifrm Frame) CRCWriteUDPPseudo(crc *lneto.CRC791, udpLength uint16) {
crc.WriteEven(ifrm.sourceAndDestinationAddr())
crc.AddUint16(udpLength)
crc.AddUint16(uint16(ifrm.Protocol()))
}
func (ifrm Frame) sourceAndDestinationAddr() []byte {
return ifrm.buf[12:20]
}
// SourceAddr returns pointer to the source IPv4 address in the IP header.
func (ifrm Frame) SourceAddr() *[4]byte {
return (*[4]byte)(ifrm.buf[12:16])
-8
View File
@@ -3,8 +3,6 @@ package icmpv4
import (
"encoding/binary"
"errors"
"github.com/soypat/lneto"
)
type Type uint8
@@ -87,12 +85,6 @@ func (frm Frame) SetCRC(crc uint16) {
binary.BigEndian.PutUint16(frm.buf[2:4], crc)
}
// CRCWrite calculates the checksum of the ICMP packet. Treats the checksum field as zero as per RFC 792.
func (frm Frame) CRCWrite(crc *lneto.CRC791) {
crc.AddUint16(binary.BigEndian.Uint16(frm.buf[0:2]))
crc.Write(frm.buf[4:])
}
func (frm Frame) payload() []byte {
return frm.buf[4:]
}
+5 -2
View File
@@ -88,6 +88,10 @@ func (i6frm Frame) SetHopLimit(hop uint8) {
i6frm.buf[7] = hop
}
func (i6frm Frame) sourceAndDestinationAddr() []byte {
return i6frm.buf[8:40]
}
// SourceAddr returns pointer to the sending node unicast IPv6 address in the IP header.
func (i6frm Frame) SourceAddr() *[16]byte {
return (*[16]byte)(i6frm.buf[8:24])
@@ -99,8 +103,7 @@ func (i6frm Frame) DestinationAddr() *[16]byte {
}
func (i6frm Frame) CRCWritePseudo(crc *lneto.CRC791) {
crc.Write(i6frm.SourceAddr()[:])
crc.Write(i6frm.DestinationAddr()[:])
crc.WriteEven(i6frm.sourceAndDestinationAddr())
crc.AddUint32(uint32(i6frm.PayloadLength()))
crc.AddUint32(uint32(i6frm.NextHeader()))
}
+5 -2
View File
@@ -141,6 +141,8 @@ func TestIPv4TCPChecksum(t *testing.T) {
t.Fatal(err)
}
wantCRC := ifrm.CRC()
// Zero the CRC field so its value does not add to the final result.
ifrm.SetCRC(0)
gotCRC := ifrm.CalculateHeaderCRC()
if wantCRC != gotCRC {
t.Errorf("IPv4 CRC miscalculated. want %x, got %x", wantCRC, gotCRC)
@@ -148,8 +150,9 @@ func TestIPv4TCPChecksum(t *testing.T) {
wantCRC = tfrm.CRC()
var crc lneto.CRC791
ifrm.CRCWriteTCPPseudo(&crc)
tfrm.CRCWrite(&crc)
gotCRC = crc.Sum16()
// Zero the CRC field so its value does not add to the final result.
tfrm.SetCRC(0)
gotCRC = crc.PayloadSum16(tfrm.RawData())
if wantCRC != gotCRC {
t.Errorf("TCP CRC miscalculated. want %x, got %x", wantCRC, gotCRC)
}
-6
View File
@@ -140,12 +140,6 @@ func (tfrm Frame) Segment(payloadSize int) Segment {
}
}
func (tfrm Frame) CRCWrite(crc *lneto.CRC791) {
// Write excluding CRC
crc.Write(tfrm.buf[:16])
crc.Write(tfrm.buf[18:])
}
// SetSegment sets the sequence, acknowledgment, offset, window and flag fields of the TCP header from the the [Segment].
// Offset, like in [Frame.SetOffset], is expressed in words with minimum being 5.
func (tfrm Frame) SetSegment(seg Segment, offset uint8) {
+1 -37
View File
@@ -7,7 +7,7 @@ import (
"github.com/soypat/lneto"
)
// NewUDPFrame returns a new UDPFrame with data set to buf.
// NewFrame returns a new udp.Frame with data set to buf.
// An error is returned if the buffer size is smaller than 8.
// Users should still call [Frame.ValidateSize] before working
// with payload/options of frames to avoid panics.
@@ -79,42 +79,6 @@ func (ufrm Frame) Payload() []byte {
return ufrm.buf[sizeHeader:l]
}
func (ufrm Frame) CRCWriteIPv4(crc *lneto.CRC791) {
crc.AddUint16(ufrm.Length())
crc.AddUint16(ufrm.SourcePort())
crc.AddUint16(ufrm.DestinationPort())
crc.AddUint16(ufrm.Length()) // Length double tap for IPv4.
crc.Write(ufrm.Payload())
}
func (ufrm Frame) CRCWriteIPv6(crc *lneto.CRC791) {
crc.AddUint16(ufrm.SourcePort())
crc.AddUint16(ufrm.DestinationPort())
crc.AddUint16(ufrm.Length())
crc.Write(ufrm.Payload())
}
// func (ufrm Frame) CalculateIPv4Checksum(ifrm IPv4Frame) uint16 {
// var crc lneto.CRC791
// ifrm.crcWriteUDPPseudo(&crc)
// crc.AddUint16(ufrm.Length())
// crc.AddUint16(ufrm.SourcePort())
// crc.AddUint16(ufrm.DestinationPort())
// crc.AddUint16(ufrm.Length()) // Length double tap.
// crc.Write(ufrm.Payload())
// return crc.Sum16()
// }
// func (ufrm Frame) CalculateIPv6Checksum(ifrm IPv6Frame) uint16 {
// var crc lneto.CRC791
// ifrm.crcWritePseudo(&crc)
// crc.AddUint16(ufrm.SourcePort())
// crc.AddUint16(ufrm.DestinationPort())
// crc.AddUint16(ufrm.Length()) // Length double tap.
// crc.Write(ufrm.Payload())
// return crc.Sum16()
// }
// ClearHeader zeros out the header contents.
func (frm Frame) ClearHeader() {
for i := range frm.buf[:sizeHeader] {
+1 -2
View File
@@ -567,6 +567,5 @@ func addr4(addr [4]byte, ok bool) netip.Addr {
func hash(b []byte) uint16 {
var csum lneto.CRC791
csum.Write(b)
return csum.Sum16()
return csum.PayloadSum16(b)
}
+11 -5
View File
@@ -205,7 +205,10 @@ func buildDNSResponsePacket(t *testing.T, txid uint16, dstPort uint16, hostname
ifrm.SetProtocol(lneto.IPProtoUDP)
*ifrm.SourceAddr() = srcIP.As4()
*ifrm.DestinationAddr() = dstIP.As4()
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
// Zero the CRC field so its value does not add to the final result.
ifrm.SetCRC(0)
crcValue := ifrm.CalculateHeaderCRC()
ifrm.SetCRC(crcValue)
// UDP header.
udpStart := ipStart + ipHdrLen
@@ -215,7 +218,8 @@ func buildDNSResponsePacket(t *testing.T, txid uint16, dstPort uint16, hostname
}
udpFrame.SetSourcePort(dns.ServerPort)
udpFrame.SetDestinationPort(dstPort)
udpFrame.SetLength(uint16(udpHdrLen + len(dnsPayload)))
udpLen := udpHdrLen + len(dnsPayload)
udpFrame.SetLength(uint16(udpLen))
// Copy DNS payload before calculating checksum.
dnsStart := udpStart + udpHdrLen
@@ -223,9 +227,11 @@ func buildDNSResponsePacket(t *testing.T, txid uint16, dstPort uint16, hostname
// Calculate UDP checksum using pseudo header.
var crc lneto.CRC791
ifrm.CRCWriteUDPPseudo(&crc)
udpFrame.CRCWriteIPv4(&crc)
udpFrame.SetCRC(crc.Sum16())
ifrm.CRCWriteUDPPseudo(&crc, uint16(udpLen))
// Zero the CRC field so its value does not add to the final result.
udpFrame.SetCRC(0)
crcValue = crc.PayloadSum16(udpFrame.RawData())
udpFrame.SetCRC(crcValue)
return pkt, nil
}