diff --git a/examples/stack/main.go b/examples/stack/main.go index fcf4d5e..63b2a49 100644 --- a/examples/stack/main.go +++ b/examples/stack/main.go @@ -17,7 +17,6 @@ func main() { rng := rand.New(rand.NewSource(1)) var gen ltesto.PacketGen gen.RandomizeAddrs(rng) - slogger := logger{slog.Default()} lStack := LinkStack{ logger: slogger, @@ -49,18 +48,29 @@ func main() { if err != nil { log.Fatal(err) } - - err = pStack.tcb.Open(tcp.Value(rng.Int()), 256, tcp.StateListen) + iss := tcp.Value(100) + err = pStack.tcb.Open(iss, 256, tcp.StateListen) if err != nil { log.Fatal(err) } - + seg := tcp.Segment{ + SEQ: 300, + ACK: iss, + DATALEN: 0, + WND: 256, + Flags: tcp.FlagSYN, + } buf := make([]byte, lStack.mtu) - packet := gen.AppendRandomIPv4TCPPacket(buf[:0], rng) + packet := gen.AppendRandomIPv4TCPPacket(buf[:0], rng, seg) err = lStack.RecvEth(packet) if err != nil { log.Fatal(err) } + n, err := lStack.HandleEth(buf) + if err != nil { + log.Fatal(n, err) + } + log.Println("success receiving packet") } type Handler interface { @@ -334,7 +344,7 @@ func (ts *TCPStack) Handle(ipFrame []byte, tcpOff int) (n int, err error) { return 0, err } // TCP packet written. - tfrm, _ := lneto.NewTCPFrame(ipFrame[tcpOff:]) + tfrm, _ := lneto.NewTCPFrame(ipFrame[tcpOff : tcpOff+n]) ts.validator.ResetErr() tfrm.ValidateSize(&ts.validator) // Perform basic validation. if err = ts.validator.Err(); err != nil { diff --git a/frames.go b/frames.go index 95c13e8..c32c02f 100644 --- a/frames.go +++ b/frames.go @@ -610,7 +610,7 @@ func (tfrm TCPFrame) CalculateIPv4CRC(ifrm IPv4Frame) uint16 { ifrm.crcWriteTCPPseudo(&crc) expectLen := int(ifrm.TotalLength()) - ifrm.HeaderLength() 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) return crc.Sum16() @@ -622,7 +622,7 @@ func (tfrm TCPFrame) CalculateIPv6CRC(ifrm IPv6Frame) uint16 { ifrm.crcWritePseudo(&crc) expectLen := int(ifrm.PayloadLength()) 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) return crc.Sum16() diff --git a/internal/ltesto/ltesto.go b/internal/ltesto/ltesto.go index 947e68b..a21e9a1 100644 --- a/internal/ltesto/ltesto.go +++ b/internal/ltesto/ltesto.go @@ -2,6 +2,7 @@ package ltesto import ( "bytes" + "math" "math/rand" "github.com/soypat/lneto" @@ -34,13 +35,17 @@ func (gen *PacketGen) RandomizeAddrs(rng *rand.Rand) { 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() var ( - isVLAN = ri&(1<<0) != 0 - hasIPOpt = ri&(1<<1) != 0 - hasTCPOpt = ri&(1<<2) != 0 - hasPayload = ri&(1<<3) != 0 + isVLAN = ri&(1<<0) != 0 + hasIPOpt = ri&(1<<1) != 0 + hasTCPOpt = ri&(1<<2) != 0 ) var etherType lneto.EtherType = lneto.EtherTypeIPv4 var ipOpts []byte @@ -56,14 +61,11 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand) []by if hasTCPOpt { tcpOpts = []byte{byte(tcp.OptSACKPermitted), 0, 1, 0} } - var payloadLen int - if hasPayload { - payloadLen = (ri >> 16) % 1024 - } + ipOptWLen := sizeWord(len(ipOpts)) tcpOptWlen := sizeWord(len(tcpOpts)) 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:]) if err != nil { panic(err) @@ -99,11 +101,11 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand) []by } tfrm.SetSourcePort(gen.SrcTCP) tfrm.SetDestinationPort(gen.DstTCP) - tfrm.SetSeq(tcp.Value(rng.Uint32())) - tfrm.SetAck(tcp.Value(rng.Uint32())) + tfrm.SetSeq(seg.SEQ) + tfrm.SetAck(seg.ACK) wlen := sizeWord(sizeHeaderTCP + len(tcpOpts)) - tfrm.SetOffsetAndFlags(wlen, tcp.Flags(rng.Uint32())) - tfrm.SetWindowSize(uint16(rng.Uint32())) + tfrm.SetOffsetAndFlags(wlen, seg.Flags) + tfrm.SetWindowSize(uint16(seg.WND)) urgPtr := uint16(rng.Uint32()) tfrm.SetUrgentPtr(urgPtr) tcpPayload := tfrm.Payload() @@ -111,6 +113,9 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand) []by if len(tcpPayload) > 0 { rng.Read(tcpPayload) firstPayloadByte = tcpPayload[0] + if len(tcpPayload) != int(seg.DATALEN) { + panic("incorrect payload length calculation") + } } // Set Variable section of data. copy(ifrm.Options(), ipOpts)