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
+34 -67
View File
@@ -11,35 +11,25 @@ import (
// //
// The zero value of CRC791 is ready to use. // The zero value of CRC791 is ready to use.
type CRC791 struct { type CRC791 struct {
sum uint32 sum uint32
excedent uint8
needPad bool
} }
// Write adds the bytes in p to the running checksum. func sum16(sum uint32) uint16 {
func (c *CRC791) Write(buff []byte) (n int, err error) { sum = (sum & 0xffff) + sum>>16
if len(buff) == 0 { // the max value of sum at this point is 0x1fffe, so an additional round is enough
return 0, nil return ^uint16(sum + sum>>16)
}
func sumWriteEven(sum uint32, buff []byte) uint32 {
for i := 0; i < len(buff); i += 2 {
sum += uint32(binary.BigEndian.Uint16(buff[i:]))
} }
if c.needPad { return sum
c.sum += uint32(c.excedent)<<8 + uint32(buff[0]) }
buff = buff[1:]
c.excedent = 0 // Write adds the bytes in p to the running checksum. The buffer size must be even or the function will panic.
c.needPad = false func (c *CRC791) WriteEven(buff []byte) {
if len(buff) == 0 { c.sum = sumWriteEven(c.sum, buff)
return 1, nil
}
}
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
} }
// AddUint32 adds a 32 bit value to the running checksum interpreted as BigEndian (network order). // 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). // Add16 adds a 16 bit value to the running checksum interpreted as BigEndian (network order).
func (c *CRC791) AddUint16(value uint16) { func (c *CRC791) AddUint16(value uint16) {
if c.needPad { c.sum += uint32(value)
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. // Sum16 calculates the checksum with the data written to c thus far.
func (c *CRC791) Sum16() uint16 { func (c *CRC791) Sum16() uint16 {
sum16 := c.sum16() return sum16(c.sum)
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
} }
// VerifySum16 verifies that the given checksum matches the data written to c thus far. // PayloadSum16 returns the checksum resulting by adding the bytes in p to the running checksum.
func (c *CRC791) VerifySum16(expectedSum16 uint16) bool { func (c *CRC791) PayloadSum16(buff []byte) uint16 {
// as recommended by RFC 1624, this implementation supports both 0x0000 and 0xFFFF as zero value for the checksum odd := len(buff) & 1
cc := *c sum := sumWriteEven(c.sum, buff[:len(buff)-odd])
if cc.needPad { if odd > 0 {
cc.AddUint8(0) sum += uint32(buff[len(buff)-1]) << 8
} }
cc.AddUint16(expectedSum16) return sum16(sum)
return cc.sum16() == 0
} }
// Reset zeros out the CRC791, resetting it to the initial state. // Reset zeros out the CRC791, resetting it to the initial state.
func (c *CRC791) Reset() { *c = CRC791{} } 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.SetProtocol(lneto.IPProtoTCP)
*ifrm.SourceAddr() = gen.SrcIPv4 *ifrm.SourceAddr() = gen.SrcIPv4
*ifrm.DestinationAddr() = gen.DstIPv4 *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() ipPayload := ifrm.Payload()
tfrm, err := tcp.NewFrame(ipPayload) tfrm, err := tcp.NewFrame(ipPayload)
@@ -124,9 +127,10 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
copy(tfrm.Options(), tcpOpts) copy(tfrm.Options(), tcpOpts)
var crc lneto.CRC791 var crc lneto.CRC791
ifrm.CRCWriteTCPPseudo(&crc) ifrm.CRCWriteTCPPseudo(&crc)
tfrm.CRCWrite(&crc) // Zero the CRC field so its value does not add to the final result.
tfrm.SetCRC(0)
tfrm.SetCRC(crc.Sum16()) crcValue = crc.PayloadSum16(tfrm.RawData())
tfrm.SetCRC(crcValue)
switch { switch {
case gen.SrcTCP != tfrm.SourcePort(): case gen.SrcTCP != tfrm.SourcePort():
panic("IP options overwrite TCP header") panic("IP options overwrite TCP header")
+33 -53
View File
@@ -161,27 +161,26 @@ func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) (
end := bitOffset + 40*octet end := bitOffset + 40*octet
var protoErrs []error var protoErrs []error
var crc lneto.CRC791 var crc lneto.CRC791
if proto == lneto.IPProtoTCP { ifrm6.CRCWritePseudo(&crc)
ifrm6.CRCWritePseudo(&crc) switch proto {
tfrm, err := tcp.NewFrame(ifrm6.Payload()) case lneto.IPProtoTCP:
if err == nil { if crc.PayloadSum16(ifrm6.Payload()) != 0 {
tfrm.CRCWrite(&crc) protoErrs = append(protoErrs, lneto.ErrBadCRC)
wantSum := crc.Sum16()
gotSum := tfrm.CRC()
if wantSum != gotSum {
protoErrs = append(protoErrs, &crcError16{protocol: "ipv6+tcp", want: wantSum, got: gotSum})
}
} }
} else if proto == lneto.IPProtoUDP || proto == lneto.IPProtoUDPLite { case lneto.IPProtoUDP, lneto.IPProtoUDPLite:
ifrm6.CRCWritePseudo(&crc)
ufrm, err := udp.NewFrame(ifrm6.Payload()) ufrm, err := udp.NewFrame(ifrm6.Payload())
if err == nil { if err != nil {
ufrm.CRCWriteIPv6(&crc) protoErrs = append(protoErrs, err)
wantSum := crc.Sum16() break
gotSum := ufrm.CRC() }
if wantSum != gotSum { ufrm.ValidateSize(pc.validator())
protoErrs = append(protoErrs, &crcError16{protocol: "ipv6+udp", want: wantSum, got: gotSum}) 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...) 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), BitLength: octet * len(options),
}) })
} }
gotSum := ifrm4.CRC() if ifrm4.CalculateHeaderCRC() != 0 {
wantSum := ifrm4.CalculateHeaderCRC() finfo.Errors = append(finfo.Errors, lneto.ErrBadCRC)
if gotSum != wantSum {
finfo.Errors = append(finfo.Errors, &crcError16{protocol: "ipv4", want: wantSum, got: gotSum})
} }
dst = append(dst, finfo) dst = append(dst, finfo)
proto := ifrm4.Protocol() proto := ifrm4.Protocol()
end := bitOffset + octet*ifrm4.HeaderLength() end := bitOffset + octet*ifrm4.HeaderLength()
var protoErrs []error var protoErrs []error
var crc lneto.CRC791 var crc lneto.CRC791
payload := ifrm4.Payload()
switch proto { switch proto {
case lneto.IPProtoTCP: case lneto.IPProtoTCP:
ifrm4.CRCWriteTCPPseudo(&crc) tfrm, err := tcp.NewFrame(payload)
tfrm, err := tcp.NewFrame(ifrm4.Payload())
if err == nil { if err == nil {
tfrm.ValidateSize(pc.validator()) tfrm.ValidateSize(pc.validator())
if pc.vld.HasError() { if pc.vld.HasError() {
println("BAD TCP") println("BAD TCP")
return dst, pc.vld.ErrPop() return dst, pc.vld.ErrPop()
} }
tfrm.CRCWrite(&crc) ifrm4.CRCWriteTCPPseudo(&crc)
wantSum := crc.Sum16() if crc.PayloadSum16(payload) != 0 {
gotSum := tfrm.CRC() protoErrs = append(protoErrs, lneto.ErrBadCRC)
if wantSum != gotSum {
protoErrs = append(protoErrs, &crcError16{protocol: "ipv4+tcp", want: wantSum, got: gotSum})
} }
} }
case lneto.IPProtoUDP: case lneto.IPProtoUDP:
ifrm4.CRCWriteUDPPseudo(&crc) ufrm, err := udp.NewFrame(payload)
ufrm, err := udp.NewFrame(ifrm4.Payload())
if err == nil { if err == nil {
ufrm.ValidateSize(pc.validator()) ufrm.ValidateSize(pc.validator())
if pc.vld.HasError() { if pc.vld.HasError() {
println("BAD UDP") println("BAD UDP")
return dst, pc.vld.ErrPop() return dst, pc.vld.ErrPop()
} }
ufrm.CRCWriteIPv4(&crc) frameLen := ufrm.Length()
wantSum := crc.Sum16() ifrm4.CRCWriteUDPPseudo(&crc, frameLen)
gotSum := ufrm.CRC() if crc.PayloadSum16(ufrm.RawData()[:frameLen]) != 0 {
if wantSum != gotSum { protoErrs = append(protoErrs, lneto.ErrBadCRC)
protoErrs = append(protoErrs, &crcError16{protocol: "ipv4+udp", want: wantSum, got: gotSum})
} }
} }
case lneto.IPProtoICMP: case lneto.IPProtoICMP:
ifrm, err := icmpv4.NewFrame(ifrm4.Payload()) _, err := icmpv4.NewFrame(payload)
if err == nil { if err == nil {
ifrm.CRCWrite(&crc) if crc.PayloadSum16(payload) != 0 {
wantSum := crc.Sum16() protoErrs = append(protoErrs, lneto.ErrBadCRC)
gotSum := ifrm.CRC()
if wantSum != gotSum {
protoErrs = append(protoErrs, &crcError16{protocol: "icmpv4", want: wantSum, got: gotSum})
} }
} }
} }
@@ -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 totalLen := ipv4Size + udpSize + dhcpLen
ifrm.SetTotalLength(uint16(totalLen)) ifrm.SetTotalLength(uint16(totalLen))
ufrm.SetLength(uint16(udpSize + dhcpLen)) ufrm.SetLength(uint16(udpSize + dhcpLen))
// The CRC field is already zero here.
ifrm.SetCRC(ifrm.CalculateHeaderCRC()) ifrm.SetCRC(ifrm.CalculateHeaderCRC())
pkt = pkt[:ethSize+totalLen] pkt = pkt[:ethSize+totalLen]
+30 -34
View File
@@ -10,7 +10,6 @@ import (
"github.com/soypat/lneto/ethernet" "github.com/soypat/lneto/ethernet"
"github.com/soypat/lneto/internal" "github.com/soypat/lneto/internal"
"github.com/soypat/lneto/ipv4" "github.com/soypat/lneto/ipv4"
"github.com/soypat/lneto/ipv4/icmpv4"
"github.com/soypat/lneto/tcp" "github.com/soypat/lneto/tcp"
"github.com/soypat/lneto/udp" "github.com/soypat/lneto/udp"
) )
@@ -91,11 +90,9 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error {
return err return err
} }
// Incoming CRC Validation of common IP Protocols. if ifrm.CalculateHeaderCRC() != 0 {
var crc lneto.CRC791
ifrm.CRCWriteHeader(&crc)
if !crc.VerifySum16(ifrm.CRC()) {
sb.handlers.error("ip:demux.crc") sb.handlers.error("ip:demux.crc")
return lneto.ErrBadCRC
} }
off := ifrm.HeaderLength() off := ifrm.HeaderLength()
totalLen := ifrm.TotalLength() totalLen := ifrm.TotalLength()
@@ -111,28 +108,27 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error {
return lneto.ErrPacketDrop return lneto.ErrPacketDrop
} }
// Incoming CRC Validation of common IP Protocols. // Incoming CRC Validation of common IP Protocols.
crc.Reset() var crc lneto.CRC791
switch proto { switch proto {
case lneto.IPProtoTCP: case lneto.IPProtoTCP:
ifrm.CRCWriteTCPPseudo(&crc) ifrm.CRCWriteTCPPseudo(&crc)
tfrm, err := tcp.NewFrame(ifrm.Payload()) if crc.PayloadSum16(ifrm.Payload()) != 0 {
if err != nil {
return err
}
tfrm.CRCWrite(&crc)
if !crc.VerifySum16(tfrm.CRC()) {
sb.handlers.error("ip:demux.tcpcrc") sb.handlers.error("ip:demux.tcpcrc")
return lneto.ErrBadCRC return lneto.ErrBadCRC
} }
case lneto.IPProtoUDP: case lneto.IPProtoUDP:
ifrm.CRCWriteUDPPseudo(&crc)
ufrm, err := udp.NewFrame(ifrm.Payload()) ufrm, err := udp.NewFrame(ifrm.Payload())
if err != nil { if err != nil {
return err return err
} }
ufrm.CRCWriteIPv4(&crc) ufrm.ValidateSize(&sb.validator)
// checksums are optional in UDP: the field is set to zero in this case if err = sb.validator.ErrPop(); err != nil {
if gotCrc := ufrm.CRC(); gotCrc != 0 && !crc.VerifySum16(gotCrc) { 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") sb.handlers.error("ip:demux.udpcrc")
return lneto.ErrBadCRC return lneto.ErrBadCRC
} }
@@ -174,25 +170,29 @@ func (sb *StackIP) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int
totalLen := n + headerlen totalLen := n + headerlen
ifrm.SetTotalLength(uint16(totalLen)) ifrm.SetTotalLength(uint16(totalLen))
ifrm.SetProtocol(proto) 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. // Calculate CRC for our newly generated packet.
var crc lneto.CRC791 var crc lneto.CRC791
payload := ifrm.Payload()
switch proto { switch proto {
case lneto.IPProtoTCP: case lneto.IPProtoTCP:
ifrm.CRCWriteTCPPseudo(&crc) ifrm.CRCWriteTCPPseudo(&crc)
tfrm, _ := tcp.NewFrame(ifrm.Payload()) tfrm, _ := tcp.NewFrame(payload)
tfrm.CRCWrite(&crc) // Zero the CRC field so its value does not add to the final result.
tfrm.SetCRC(crc.Sum16()) tfrm.SetCRC(0)
crcValue = crc.PayloadSum16(payload)
tfrm.SetCRC(crcValue)
case lneto.IPProtoUDP: case lneto.IPProtoUDP:
ifrm.CRCWriteUDPPseudo(&crc) ufrm, _ := udp.NewFrame(payload)
ufrm, _ := udp.NewFrame(ifrm.Payload()) ifrm.CRCWriteUDPPseudo(&crc, uint16(n))
ufrm.SetLength(uint16(n)) ufrm.SetLength(uint16(n))
ufrm.CRCWriteIPv4(&crc) // Zero the CRC field so its value does not add to the final result.
ufrm.SetCRC(crc.Sum16()) ufrm.SetCRC(0)
if n != int(ufrm.Length()) { crcValue = lneto.NeverZeroSum(crc.PayloadSum16(payload))
sb.handlers.error("StackIP:encaps", slog.Int("n", n), slog.Int("un", int(ufrm.Length()))) ufrm.SetCRC(crcValue)
return 0, errors.New("invalid UDP length")
}
} }
return totalLen, err return totalLen, err
} }
@@ -206,13 +206,9 @@ func (sb *StackIP) Register(h StackNode) error {
} }
func (sb *StackIP) recvicmp(carrierData []byte, offset int) error { func (sb *StackIP) recvicmp(carrierData []byte, offset int) error {
frameData := carrierData[offset:]
var crc lneto.CRC791 var crc lneto.CRC791
cfrm, err := icmpv4.NewFrame(carrierData[offset:]) if crc.PayloadSum16(frameData) != 0 {
if err != nil {
return err
}
cfrm.CRCWrite(&crc)
if !crc.VerifySum16(cfrm.CRC()) {
return errors.New("ICMP CRC mismatch") return errors.New("ICMP CRC mismatch")
} }
return nil return nil
+10 -8
View File
@@ -136,23 +136,25 @@ func (ifrm Frame) CalculateHeaderCRC() uint16 {
} }
func (ifrm Frame) CRCWriteHeader(crc *lneto.CRC791) { func (ifrm Frame) CRCWriteHeader(crc *lneto.CRC791) {
crc.Write(ifrm.buf[0:10]) crc.WriteEven(ifrm.buf[:20])
crc.Write(ifrm.buf[12:20])
} }
func (ifrm Frame) CRCWriteTCPPseudo(crc *lneto.CRC791) { func (ifrm Frame) CRCWriteTCPPseudo(crc *lneto.CRC791) {
crc.Write(ifrm.SourceAddr()[:]) crc.WriteEven(ifrm.sourceAndDestinationAddr())
crc.Write(ifrm.DestinationAddr()[:]) crc.AddUint16(ifrm.TotalLength() - uint16(ifrm.HeaderLength()))
crc.AddUint16(ifrm.TotalLength() - 4*uint16(ifrm.ihl()))
crc.AddUint16(uint16(ifrm.Protocol())) crc.AddUint16(uint16(ifrm.Protocol()))
} }
func (ifrm Frame) CRCWriteUDPPseudo(crc *lneto.CRC791) { func (ifrm Frame) CRCWriteUDPPseudo(crc *lneto.CRC791, udpLength uint16) {
crc.Write(ifrm.SourceAddr()[:]) crc.WriteEven(ifrm.sourceAndDestinationAddr())
crc.Write(ifrm.DestinationAddr()[:]) crc.AddUint16(udpLength)
crc.AddUint16(uint16(ifrm.Protocol())) 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. // SourceAddr returns pointer to the source IPv4 address in the IP header.
func (ifrm Frame) SourceAddr() *[4]byte { func (ifrm Frame) SourceAddr() *[4]byte {
return (*[4]byte)(ifrm.buf[12:16]) return (*[4]byte)(ifrm.buf[12:16])
-8
View File
@@ -3,8 +3,6 @@ package icmpv4
import ( import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"github.com/soypat/lneto"
) )
type Type uint8 type Type uint8
@@ -87,12 +85,6 @@ func (frm Frame) SetCRC(crc uint16) {
binary.BigEndian.PutUint16(frm.buf[2:4], crc) 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 { func (frm Frame) payload() []byte {
return frm.buf[4:] return frm.buf[4:]
} }
+5 -2
View File
@@ -88,6 +88,10 @@ func (i6frm Frame) SetHopLimit(hop uint8) {
i6frm.buf[7] = hop 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. // SourceAddr returns pointer to the sending node unicast IPv6 address in the IP header.
func (i6frm Frame) SourceAddr() *[16]byte { func (i6frm Frame) SourceAddr() *[16]byte {
return (*[16]byte)(i6frm.buf[8:24]) return (*[16]byte)(i6frm.buf[8:24])
@@ -99,8 +103,7 @@ func (i6frm Frame) DestinationAddr() *[16]byte {
} }
func (i6frm Frame) CRCWritePseudo(crc *lneto.CRC791) { func (i6frm Frame) CRCWritePseudo(crc *lneto.CRC791) {
crc.Write(i6frm.SourceAddr()[:]) crc.WriteEven(i6frm.sourceAndDestinationAddr())
crc.Write(i6frm.DestinationAddr()[:])
crc.AddUint32(uint32(i6frm.PayloadLength())) crc.AddUint32(uint32(i6frm.PayloadLength()))
crc.AddUint32(uint32(i6frm.NextHeader())) crc.AddUint32(uint32(i6frm.NextHeader()))
} }
+5 -2
View File
@@ -141,6 +141,8 @@ func TestIPv4TCPChecksum(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
wantCRC := ifrm.CRC() wantCRC := ifrm.CRC()
// Zero the CRC field so its value does not add to the final result.
ifrm.SetCRC(0)
gotCRC := ifrm.CalculateHeaderCRC() gotCRC := ifrm.CalculateHeaderCRC()
if wantCRC != gotCRC { if wantCRC != gotCRC {
t.Errorf("IPv4 CRC miscalculated. want %x, got %x", 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() wantCRC = tfrm.CRC()
var crc lneto.CRC791 var crc lneto.CRC791
ifrm.CRCWriteTCPPseudo(&crc) ifrm.CRCWriteTCPPseudo(&crc)
tfrm.CRCWrite(&crc) // Zero the CRC field so its value does not add to the final result.
gotCRC = crc.Sum16() tfrm.SetCRC(0)
gotCRC = crc.PayloadSum16(tfrm.RawData())
if wantCRC != gotCRC { if wantCRC != gotCRC {
t.Errorf("TCP CRC miscalculated. want %x, got %x", 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]. // 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. // Offset, like in [Frame.SetOffset], is expressed in words with minimum being 5.
func (tfrm Frame) SetSegment(seg Segment, offset uint8) { func (tfrm Frame) SetSegment(seg Segment, offset uint8) {
+1 -37
View File
@@ -7,7 +7,7 @@ import (
"github.com/soypat/lneto" "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. // An error is returned if the buffer size is smaller than 8.
// Users should still call [Frame.ValidateSize] before working // Users should still call [Frame.ValidateSize] before working
// with payload/options of frames to avoid panics. // with payload/options of frames to avoid panics.
@@ -79,42 +79,6 @@ func (ufrm Frame) Payload() []byte {
return ufrm.buf[sizeHeader:l] 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. // ClearHeader zeros out the header contents.
func (frm Frame) ClearHeader() { func (frm Frame) ClearHeader() {
for i := range frm.buf[:sizeHeader] { 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 { func hash(b []byte) uint16 {
var csum lneto.CRC791 var csum lneto.CRC791
csum.Write(b) return csum.PayloadSum16(b)
return csum.Sum16()
} }
+11 -5
View File
@@ -205,7 +205,10 @@ func buildDNSResponsePacket(t *testing.T, txid uint16, dstPort uint16, hostname
ifrm.SetProtocol(lneto.IPProtoUDP) ifrm.SetProtocol(lneto.IPProtoUDP)
*ifrm.SourceAddr() = srcIP.As4() *ifrm.SourceAddr() = srcIP.As4()
*ifrm.DestinationAddr() = dstIP.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. // UDP header.
udpStart := ipStart + ipHdrLen udpStart := ipStart + ipHdrLen
@@ -215,7 +218,8 @@ func buildDNSResponsePacket(t *testing.T, txid uint16, dstPort uint16, hostname
} }
udpFrame.SetSourcePort(dns.ServerPort) udpFrame.SetSourcePort(dns.ServerPort)
udpFrame.SetDestinationPort(dstPort) udpFrame.SetDestinationPort(dstPort)
udpFrame.SetLength(uint16(udpHdrLen + len(dnsPayload))) udpLen := udpHdrLen + len(dnsPayload)
udpFrame.SetLength(uint16(udpLen))
// Copy DNS payload before calculating checksum. // Copy DNS payload before calculating checksum.
dnsStart := udpStart + udpHdrLen dnsStart := udpStart + udpHdrLen
@@ -223,9 +227,11 @@ func buildDNSResponsePacket(t *testing.T, txid uint16, dstPort uint16, hostname
// Calculate UDP checksum using pseudo header. // Calculate UDP checksum using pseudo header.
var crc lneto.CRC791 var crc lneto.CRC791
ifrm.CRCWriteUDPPseudo(&crc) ifrm.CRCWriteUDPPseudo(&crc, uint16(udpLen))
udpFrame.CRCWriteIPv4(&crc) // Zero the CRC field so its value does not add to the final result.
udpFrame.SetCRC(crc.Sum16()) udpFrame.SetCRC(0)
crcValue = crc.PayloadSum16(udpFrame.RawData())
udpFrame.SetCRC(crcValue)
return pkt, nil return pkt, nil
} }