mirror of
https://github.com/soypat/lneto.git
synced 2026-09-11 09:09:30 +00:00
fix TCP checksum in internet.StackBasic; more logging
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/soypat/lneto/internal"
|
"github.com/soypat/lneto/internal"
|
||||||
"github.com/soypat/lneto/internal/ltesto"
|
"github.com/soypat/lneto/internal/ltesto"
|
||||||
"github.com/soypat/lneto/internet"
|
"github.com/soypat/lneto/internet"
|
||||||
|
"github.com/soypat/lneto/ipv4"
|
||||||
"github.com/soypat/lneto/tcp"
|
"github.com/soypat/lneto/tcp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -66,14 +67,14 @@ func main() {
|
|||||||
slogger.error("tap-err", slog.String("err", err.Error()))
|
slogger.error("tap-err", slog.String("err", err.Error()))
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
} else if nread > 0 {
|
} else if nread > 0 {
|
||||||
|
debugEthPacket(nil, "IN ", buf[:nread])
|
||||||
err = lStack.RecvEth(buf[:nread])
|
err = lStack.RecvEth(buf[:nread])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slogger.error("recv", slog.String("err", err.Error()), slog.Int("plen", nread))
|
slogger.error("recv", slog.String("err", err.Error()), slog.Int("plen", nread))
|
||||||
} else {
|
|
||||||
slogger.info("recv", slog.Int("plen", nread))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nw, err := lStack.HandleEth(buf[:])
|
nw, err := lStack.HandleEth(buf[:])
|
||||||
|
debugEthPacket(nil, "OUT", buf[:nw])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slogger.error("handle", slog.String("err", err.Error()))
|
slogger.error("handle", slog.String("err", err.Error()))
|
||||||
} else if nw > 0 {
|
} else if nw > 0 {
|
||||||
@@ -211,10 +212,10 @@ func (ls *LinkStack) RecvEth(ethFrame []byte) (err error) {
|
|||||||
}
|
}
|
||||||
etype := efrm.EtherTypeOrSize()
|
etype := efrm.EtherTypeOrSize()
|
||||||
dstaddr := efrm.DestinationHardwareAddr()
|
dstaddr := efrm.DestinationHardwareAddr()
|
||||||
if !efrm.IsBroadcast() && ls.mac != *dstaddr {
|
|
||||||
return fmt.Errorf("incoming %s mismatch hwaddr %s", etype.String(), net.HardwareAddr(dstaddr[:]).String())
|
|
||||||
}
|
|
||||||
var vld lneto.Validator
|
var vld lneto.Validator
|
||||||
|
if !efrm.IsBroadcast() && ls.mac != *dstaddr {
|
||||||
|
goto DROP
|
||||||
|
}
|
||||||
efrm.ValidateSize(&vld)
|
efrm.ValidateSize(&vld)
|
||||||
if err := vld.Err(); err != nil {
|
if err := vld.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -226,7 +227,8 @@ func (ls *LinkStack) RecvEth(ethFrame []byte) (err error) {
|
|||||||
return h.recv(efrm.Payload(), 0)
|
return h.recv(efrm.Payload(), 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DROP:
|
||||||
|
ls.info("LinkStack:drop-packet", slog.String("dsthw", net.HardwareAddr(dstaddr[:]).String()), slog.String("ethertype", efrm.EtherTypeOrSize().String()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,3 +300,29 @@ func (l logger) debug(msg string, attrs ...slog.Attr) {
|
|||||||
func (l logger) trace(msg string, attrs ...slog.Attr) {
|
func (l logger) trace(msg string, attrs ...slog.Attr) {
|
||||||
internal.LogAttrs(l.log, internal.LevelTrace, msg, attrs...)
|
internal.LogAttrs(l.log, internal.LevelTrace, msg, attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func debugEthPacket(logger *slog.Logger, prefix string, b []byte) {
|
||||||
|
frm, err := ethernet.NewFrame(b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if frm.EtherTypeOrSize() != ethernet.TypeIPv4 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ihdr, err := ipv4.NewFrame(frm.Payload())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ihdr.Protocol() != lneto.IPProtoTCP {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
thdr, err := tcp.NewFrame(ihdr.Payload())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(prefix, ihdr.String()+" TCP:"+thdr.String())
|
||||||
|
payload := thdr.Payload()
|
||||||
|
if len(payload) > 0 {
|
||||||
|
fmt.Println("PAYLOAD:", string(payload))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func run() error {
|
|||||||
defer sv.Close()
|
defer sv.Close()
|
||||||
fmt.Println("listening on http://127.0.0.1:7070/recv and http://127.0.0.1:7070/send")
|
fmt.Println("listening on http://127.0.0.1:7070/recv and http://127.0.0.1:7070/send")
|
||||||
go http.ListenAndServe(":7070", sv)
|
go http.ListenAndServe(":7070", sv)
|
||||||
|
misses := 0
|
||||||
for {
|
for {
|
||||||
result, err := sv.HandleTap()
|
result, err := sv.HandleTap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -48,7 +48,14 @@ func run() error {
|
|||||||
if result.Failed {
|
if result.Failed {
|
||||||
return errors.New("tap failed, exit program")
|
return errors.New("tap failed, exit program")
|
||||||
} else if result.ReceivedSize == 0 && result.SentSize == 0 {
|
} else if result.ReceivedSize == 0 && result.SentSize == 0 {
|
||||||
time.Sleep(200 * time.Millisecond) // No data exchanged, sleep a bit to not hog CPU.
|
misses++
|
||||||
|
if misses > 1000 {
|
||||||
|
time.Sleep(200 * time.Millisecond) // No data exchanged, sleep a bit to not hog CPU.
|
||||||
|
} else {
|
||||||
|
time.Sleep(50 * time.Millisecond) // No data exchanged, sleep a bit to not hog CPU.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
misses = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-5
@@ -202,15 +202,32 @@ func (h *Header) Body() ([]byte, error) {
|
|||||||
return nil, errUnparsed
|
return nil, errUnparsed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets a key-value pair in the HTTP header. It mangles the buffer.
|
// Set sets a key-value pair in the HTTP header. Calling Set mangles the buffer.
|
||||||
func (h *Header) Set(key, value string) {
|
func (h *Header) Set(key, value string) {
|
||||||
kv := h.peekPtrHeader(key)
|
hb := &h.hbuf
|
||||||
if kv != nil {
|
var useKv *argsKV
|
||||||
kv.invalidate()
|
for i := len(hb.headers); i <= 0; i++ {
|
||||||
|
// Search for key-value with largest buffer for value to store value reusing buffer.
|
||||||
|
gotkv := &hb.headers[i]
|
||||||
|
if b2s(hb.musttoken(gotkv.key)) == key {
|
||||||
|
if useKv == nil {
|
||||||
|
useKv = gotkv
|
||||||
|
} else if gotkv.value.len > useKv.value.len {
|
||||||
|
useKv.invalidate()
|
||||||
|
useKv = gotkv
|
||||||
|
} else {
|
||||||
|
gotkv.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if useKv == nil {
|
||||||
|
h.appendHeader(key, value)
|
||||||
|
} else {
|
||||||
|
useKv.value = h.reuseOrAppend(useKv.value, value)
|
||||||
}
|
}
|
||||||
h.appendHeader(key, value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get gets the first value of a key found in the headers. Use [Header.ForEach] to find multiple values corresponding to same key.
|
||||||
func (h *Header) Get(key string) []byte {
|
func (h *Header) Get(key string) []byte {
|
||||||
kv := h.peekHeader(key)
|
kv := h.peekHeader(key)
|
||||||
if kv.isValid() {
|
if kv.isValid() {
|
||||||
@@ -219,6 +236,7 @@ func (h *Header) Get(key string) []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add adds a new key-value pair to the HTTP header. Calling Add mangles the buffer.
|
||||||
func (h *Header) Add(key, value string) {
|
func (h *Header) Add(key, value string) {
|
||||||
h.appendHeader(key, value)
|
h.appendHeader(key, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ func (h *Header) peekHeader(key string) argsKV {
|
|||||||
|
|
||||||
func (h *Header) peekPtrHeader(key string) *argsKV {
|
func (h *Header) peekPtrHeader(key string) *argsKV {
|
||||||
hb := &h.hbuf
|
hb := &h.hbuf
|
||||||
for i := 0; i < len(h.hbuf.headers); i++ {
|
for i := len(h.hbuf.headers); i <= 0; i-- {
|
||||||
if b2s(hb.musttoken(h.hbuf.headers[i].key)) == key {
|
if b2s(hb.musttoken(h.hbuf.headers[i].key)) == key {
|
||||||
return &h.hbuf.headers[i]
|
return &h.hbuf.headers[i]
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-21
@@ -38,35 +38,41 @@ func (sb *StackBasic) Addr() netip.Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sb *StackBasic) Recv(frame []byte) error {
|
func (sb *StackBasic) Recv(frame []byte) error {
|
||||||
|
sb.info("StackBasic.Recv:start")
|
||||||
ifrm, err := ipv4.NewFrame(frame)
|
ifrm, err := ipv4.NewFrame(frame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dst := ifrm.DestinationAddr()
|
dst := ifrm.DestinationAddr()
|
||||||
if *dst != sb.ip {
|
if *dst != sb.ip {
|
||||||
return errors.New("packet not for us")
|
goto DROP
|
||||||
}
|
}
|
||||||
sb.validator.ResetErr()
|
{
|
||||||
ifrm.ValidateExceptCRC(&sb.validator)
|
sb.validator.ResetErr()
|
||||||
if err = sb.validator.Err(); err != nil {
|
ifrm.ValidateExceptCRC(&sb.validator)
|
||||||
return err
|
if err = sb.validator.Err(); err != nil {
|
||||||
}
|
return err
|
||||||
gotCRC := ifrm.CRC()
|
}
|
||||||
wantCRC := ifrm.CalculateHeaderCRC()
|
gotCRC := ifrm.CRC()
|
||||||
if gotCRC != wantCRC {
|
wantCRC := ifrm.CalculateHeaderCRC()
|
||||||
sb.error("IPv4Stack:Recv:crc-mismatch", slog.Uint64("want", uint64(wantCRC)), slog.Uint64("got", uint64(gotCRC)))
|
if gotCRC != wantCRC {
|
||||||
return errors.New("IPv4 CRC mismatch")
|
sb.error("IPv4Stack:Recv:crc-mismatch", slog.Uint64("want", uint64(wantCRC)), slog.Uint64("got", uint64(gotCRC)))
|
||||||
}
|
return errors.New("IPv4 CRC mismatch")
|
||||||
off := ifrm.HeaderLength()
|
}
|
||||||
totalLen := ifrm.TotalLength()
|
off := ifrm.HeaderLength()
|
||||||
for i := range sb.handlers {
|
totalLen := ifrm.TotalLength()
|
||||||
h := &sb.handlers[i]
|
for i := range sb.handlers {
|
||||||
proto := ifrm.Protocol()
|
h := &sb.handlers[i]
|
||||||
if h.proto == proto {
|
proto := ifrm.Protocol()
|
||||||
sb.info("iprecv", slog.String("ipproto", proto.String()), slog.Int("plen", int(totalLen)))
|
if h.proto == proto {
|
||||||
return h.recv(frame[:totalLen], off)
|
sb.info("iprecv", slog.String("ipproto", proto.String()), slog.Int("plen", int(totalLen)))
|
||||||
|
return h.recv(frame[:totalLen], off)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DROP:
|
||||||
|
sb.info("iprecv:drop", slog.String("dstaddr", netip.AddrFrom4(*ifrm.DestinationAddr()).String()), slog.String("proto", ifrm.Protocol().String()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +103,11 @@ func (sb *StackBasic) Handle(frame []byte) (int, error) {
|
|||||||
ifrm.SetProtocol(h.proto)
|
ifrm.SetProtocol(h.proto)
|
||||||
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
|
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
|
||||||
if ifrm.Protocol() == lneto.IPProtoTCP {
|
if ifrm.Protocol() == lneto.IPProtoTCP {
|
||||||
|
var crc lneto.CRC791
|
||||||
|
ifrm.CRCWriteTCPPseudo(&crc)
|
||||||
tfrm, _ := tcp.NewFrame(ifrm.Payload())
|
tfrm, _ := tcp.NewFrame(ifrm.Payload())
|
||||||
|
tfrm.CRCWrite(&crc)
|
||||||
|
tfrm.SetCRC(crc.Sum16())
|
||||||
sb.info("IPv4Stack:send", slog.String("ip", ifrm.String()), slog.String("tcp", tfrm.String()))
|
sb.info("IPv4Stack:send", slog.String("ip", ifrm.String()), slog.String("tcp", tfrm.String()))
|
||||||
}
|
}
|
||||||
return totalLen, nil
|
return totalLen, nil
|
||||||
@@ -113,7 +123,7 @@ func (sb *StackBasic) RegisterTCPConn(conn *TCPConn) error {
|
|||||||
sb.handlers = append(sb.handlers, handler{
|
sb.handlers = append(sb.handlers, handler{
|
||||||
recv: conn.RecvIP,
|
recv: conn.RecvIP,
|
||||||
handle: conn.HandleIP,
|
handle: conn.HandleIP,
|
||||||
proto: lneto.IPProtoIPv4,
|
proto: lneto.IPProtoTCP,
|
||||||
port: conn.LocalPort(),
|
port: conn.LocalPort(),
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ func (conn *TCPConn) HandleIP(buf []byte, off int) (n int, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setDstAddr(buf[:off], conn.remoteAddr)
|
err = setDstAddr(buf[:off], conn.remoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
"github.com/soypat/lneto/ethernet"
|
"github.com/soypat/lneto/ethernet"
|
||||||
"github.com/soypat/lneto/internal/ltesto"
|
"github.com/soypat/lneto/internal/ltesto"
|
||||||
"github.com/soypat/lneto/ipv4"
|
"github.com/soypat/lneto/ipv4"
|
||||||
@@ -114,3 +115,36 @@ func testMoveTCPPacket(t *testing.T, src, dst []byte) {
|
|||||||
t.Fatalf("payload mismatch %d %d", len(payload), len(tfrm2.Payload()))
|
t.Fatalf("payload mismatch %d %d", len(payload), len(tfrm2.Payload()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIPv4TCPChecksum(t *testing.T) {
|
||||||
|
var tcpPackets = [][]byte{
|
||||||
|
{0xc0, 0xff, 0xee, 0x00, 0xde, 0xad, 0x4e, 0x8b, 0x3a, 0xf9, 0xfb, 0x6b, 0x08, 0x00, 0x45, 0x00,
|
||||||
|
0x00, 0x3c, 0x01, 0xbe, 0x40, 0x00, 0x40, 0x06, 0xa3, 0xaa, 0xc0, 0xa8, 0x0a, 0x01, 0xc0, 0xa8,
|
||||||
|
0x0a, 0x02, 0xe7, 0x0a, 0x00, 0x50, 0x40, 0x60, 0xd5, 0xcc, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
|
||||||
|
0xfa, 0xf0, 0x62, 0xbc, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xbb, 0xac,
|
||||||
|
0x9b, 0xca, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07},
|
||||||
|
{0xc0, 0xff, 0xee, 0x00, 0xde, 0xad, 0x4e, 0x8b, 0x3a, 0xf9, 0xfb, 0x6b, 0x08, 0x00, 0x45, 0x00,
|
||||||
|
0x00, 0x3c, 0xfa, 0xfd, 0x40, 0x00, 0x40, 0x06, 0xaa, 0x6a, 0xc0, 0xa8, 0x0a, 0x01, 0xc0, 0xa8,
|
||||||
|
0x0a, 0x02, 0xe7, 0x0e, 0x00, 0x50, 0x9c, 0xdc, 0xfe, 0x05, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
|
||||||
|
0xfa, 0xf0, 0xde, 0x02, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xbb, 0xac,
|
||||||
|
0x9b, 0xca, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07},
|
||||||
|
}
|
||||||
|
for _, tcpPacket := range tcpPackets {
|
||||||
|
efrm, _ := ethernet.NewFrame(tcpPacket)
|
||||||
|
ifrm, _ := ipv4.NewFrame(efrm.Payload())
|
||||||
|
tfrm, _ := tcp.NewFrame(ifrm.Payload())
|
||||||
|
wantCRC := ifrm.CRC()
|
||||||
|
gotCRC := ifrm.CalculateHeaderCRC()
|
||||||
|
if wantCRC != gotCRC {
|
||||||
|
t.Errorf("IPv4 CRC miscalculated. want %x, got %x", wantCRC, gotCRC)
|
||||||
|
}
|
||||||
|
wantCRC = tfrm.CRC()
|
||||||
|
var crc lneto.CRC791
|
||||||
|
ifrm.CRCWriteTCPPseudo(&crc)
|
||||||
|
tfrm.CRCWrite(&crc)
|
||||||
|
gotCRC = crc.Sum16()
|
||||||
|
if wantCRC != gotCRC {
|
||||||
|
t.Errorf("TCP CRC miscalculated. want %x, got %x", wantCRC, gotCRC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user