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:
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -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)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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])
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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] {
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user