huge improvements to stack example

This commit is contained in:
soypat
2025-01-24 17:30:23 -03:00
parent f2ce6312d3
commit b40927ebcd
3 changed files with 37 additions and 22 deletions
+16 -6
View File
@@ -17,7 +17,6 @@ func main() {
rng := rand.New(rand.NewSource(1)) rng := rand.New(rand.NewSource(1))
var gen ltesto.PacketGen var gen ltesto.PacketGen
gen.RandomizeAddrs(rng) gen.RandomizeAddrs(rng)
slogger := logger{slog.Default()} slogger := logger{slog.Default()}
lStack := LinkStack{ lStack := LinkStack{
logger: slogger, logger: slogger,
@@ -49,18 +48,29 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
iss := tcp.Value(100)
err = pStack.tcb.Open(tcp.Value(rng.Int()), 256, tcp.StateListen) err = pStack.tcb.Open(iss, 256, tcp.StateListen)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
seg := tcp.Segment{
SEQ: 300,
ACK: iss,
DATALEN: 0,
WND: 256,
Flags: tcp.FlagSYN,
}
buf := make([]byte, lStack.mtu) buf := make([]byte, lStack.mtu)
packet := gen.AppendRandomIPv4TCPPacket(buf[:0], rng) packet := gen.AppendRandomIPv4TCPPacket(buf[:0], rng, seg)
err = lStack.RecvEth(packet) err = lStack.RecvEth(packet)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
n, err := lStack.HandleEth(buf)
if err != nil {
log.Fatal(n, err)
}
log.Println("success receiving packet")
} }
type Handler interface { type Handler interface {
@@ -334,7 +344,7 @@ func (ts *TCPStack) Handle(ipFrame []byte, tcpOff int) (n int, err error) {
return 0, err return 0, err
} }
// TCP packet written. // TCP packet written.
tfrm, _ := lneto.NewTCPFrame(ipFrame[tcpOff:]) tfrm, _ := lneto.NewTCPFrame(ipFrame[tcpOff : tcpOff+n])
ts.validator.ResetErr() ts.validator.ResetErr()
tfrm.ValidateSize(&ts.validator) // Perform basic validation. tfrm.ValidateSize(&ts.validator) // Perform basic validation.
if err = ts.validator.Err(); err != nil { if err = ts.validator.Err(); err != nil {
+2 -2
View File
@@ -610,7 +610,7 @@ func (tfrm TCPFrame) CalculateIPv4CRC(ifrm IPv4Frame) uint16 {
ifrm.crcWriteTCPPseudo(&crc) ifrm.crcWriteTCPPseudo(&crc)
expectLen := int(ifrm.TotalLength()) - ifrm.HeaderLength() expectLen := int(ifrm.TotalLength()) - ifrm.HeaderLength()
if expectLen != len(tfrm.buf) { if expectLen != len(tfrm.buf) {
println("unexpected TCP buffer length mismatches IPv4 header total length", expectLen, len(tfrm.buf)) println("unexpected TCP buffer length mismatches IPv4 header total length", len(tfrm.buf), expectLen)
} }
tfrm.crcWrite(&crc) tfrm.crcWrite(&crc)
return crc.Sum16() return crc.Sum16()
@@ -622,7 +622,7 @@ func (tfrm TCPFrame) CalculateIPv6CRC(ifrm IPv6Frame) uint16 {
ifrm.crcWritePseudo(&crc) ifrm.crcWritePseudo(&crc)
expectLen := int(ifrm.PayloadLength()) expectLen := int(ifrm.PayloadLength())
if expectLen != len(tfrm.buf) { if expectLen != len(tfrm.buf) {
println("unexpected TCP buffer length mismatches IPv4 header total length", expectLen, len(tfrm.buf)) println("unexpected TCP buffer length mismatches IPv4 header total length", len(tfrm.buf), expectLen)
} }
tfrm.crcWrite(&crc) tfrm.crcWrite(&crc)
return crc.Sum16() return crc.Sum16()
+19 -14
View File
@@ -2,6 +2,7 @@ package ltesto
import ( import (
"bytes" "bytes"
"math"
"math/rand" "math/rand"
"github.com/soypat/lneto" "github.com/soypat/lneto"
@@ -34,13 +35,17 @@ func (gen *PacketGen) RandomizeAddrs(rng *rand.Rand) {
gen.DstTCP = uint16(ports >> 16) gen.DstTCP = uint16(ports >> 16)
} }
func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand) []byte { func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg tcp.Segment) []byte {
if seg.WND > math.MaxUint16 {
panic("TCP segment window overflow")
} else if seg.DATALEN > 2048 {
panic("too long datalen")
}
ri := rng.Int() ri := rng.Int()
var ( var (
isVLAN = ri&(1<<0) != 0 isVLAN = ri&(1<<0) != 0
hasIPOpt = ri&(1<<1) != 0 hasIPOpt = ri&(1<<1) != 0
hasTCPOpt = ri&(1<<2) != 0 hasTCPOpt = ri&(1<<2) != 0
hasPayload = ri&(1<<3) != 0
) )
var etherType lneto.EtherType = lneto.EtherTypeIPv4 var etherType lneto.EtherType = lneto.EtherTypeIPv4
var ipOpts []byte var ipOpts []byte
@@ -56,14 +61,11 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand) []by
if hasTCPOpt { if hasTCPOpt {
tcpOpts = []byte{byte(tcp.OptSACKPermitted), 0, 1, 0} tcpOpts = []byte{byte(tcp.OptSACKPermitted), 0, 1, 0}
} }
var payloadLen int
if hasPayload {
payloadLen = (ri >> 16) % 1024
}
ipOptWLen := sizeWord(len(ipOpts)) ipOptWLen := sizeWord(len(ipOpts))
tcpOptWlen := sizeWord(len(tcpOpts)) tcpOptWlen := sizeWord(len(tcpOpts))
off := len(dst) off := len(dst)
dst = append(dst, make([]byte, ethsize+sizeHeaderIPv4+4*int(ipOptWLen)+sizeHeaderTCP+4*int(tcpOptWlen)+payloadLen)...) dst = append(dst, make([]byte, ethsize+sizeHeaderIPv4+4*int(ipOptWLen)+sizeHeaderTCP+4*int(tcpOptWlen)+int(seg.DATALEN))...)
efrm, err := lneto.NewEthFrame(dst[off:]) efrm, err := lneto.NewEthFrame(dst[off:])
if err != nil { if err != nil {
panic(err) panic(err)
@@ -99,11 +101,11 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand) []by
} }
tfrm.SetSourcePort(gen.SrcTCP) tfrm.SetSourcePort(gen.SrcTCP)
tfrm.SetDestinationPort(gen.DstTCP) tfrm.SetDestinationPort(gen.DstTCP)
tfrm.SetSeq(tcp.Value(rng.Uint32())) tfrm.SetSeq(seg.SEQ)
tfrm.SetAck(tcp.Value(rng.Uint32())) tfrm.SetAck(seg.ACK)
wlen := sizeWord(sizeHeaderTCP + len(tcpOpts)) wlen := sizeWord(sizeHeaderTCP + len(tcpOpts))
tfrm.SetOffsetAndFlags(wlen, tcp.Flags(rng.Uint32())) tfrm.SetOffsetAndFlags(wlen, seg.Flags)
tfrm.SetWindowSize(uint16(rng.Uint32())) tfrm.SetWindowSize(uint16(seg.WND))
urgPtr := uint16(rng.Uint32()) urgPtr := uint16(rng.Uint32())
tfrm.SetUrgentPtr(urgPtr) tfrm.SetUrgentPtr(urgPtr)
tcpPayload := tfrm.Payload() tcpPayload := tfrm.Payload()
@@ -111,6 +113,9 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand) []by
if len(tcpPayload) > 0 { if len(tcpPayload) > 0 {
rng.Read(tcpPayload) rng.Read(tcpPayload)
firstPayloadByte = tcpPayload[0] firstPayloadByte = tcpPayload[0]
if len(tcpPayload) != int(seg.DATALEN) {
panic("incorrect payload length calculation")
}
} }
// Set Variable section of data. // Set Variable section of data.
copy(ifrm.Options(), ipOpts) copy(ifrm.Options(), ipOpts)