mirror of
https://github.com/soypat/lneto.git
synced 2026-07-26 10:38:47 +00:00
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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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])
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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] {
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user