From 0f20090d78c318ca997af0e706729353ed611d74 Mon Sep 17 00:00:00 2001 From: soypat Date: Sat, 16 Aug 2025 18:26:50 -0300 Subject: [PATCH] bugfix: use ISS on active TCP connection --- examples/xnet/main.go | 3 ++- tcp/conn.go | 4 ++++ tcp/handler.go | 5 +++-- tcp/txqueue.go | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/xnet/main.go b/examples/xnet/main.go index 66d8da9..f813765 100644 --- a/examples/xnet/main.go +++ b/examples/xnet/main.go @@ -203,8 +203,9 @@ func run() (err error) { if err != nil { return err } + const tcpDebugTimeout = 60 * time.Minute target := netip.AddrPortFrom(addrs[0], 80) - conn, err := rstack.DoDialTCP(uint16(softRand&0xefff)+1024, target, internetTimeout, internetRetries) + conn, err := rstack.DoDialTCP(uint16(softRand&0xefff)+1024, target, tcpDebugTimeout, internetRetries) if err != nil { return fmt.Errorf("TCP failed: %w", err) } diff --git a/tcp/conn.go b/tcp/conn.go index 662cdff..539867b 100644 --- a/tcp/conn.go +++ b/tcp/conn.go @@ -17,6 +17,7 @@ import ( var ( errDeadlineExceeded = os.ErrDeadlineExceeded errNoRemoteAddr = errors.New("tcp: no remote address established") + errInvalidIP = errors.New("tcp: invalid IP") errMismatchedIPVersion = errors.New("mismatched IP version") ) @@ -70,6 +71,9 @@ func (conn *Conn) BufferedInput() int { return conn.h.BufferedInput() } // OpenActive opens a connection to a remote peer with a known IP address and port combination. // iss is the initial send sequence number which is ideally a random number which is far away from the last sequence number used on a connection to the same host. func (conn *Conn) OpenActive(localPort uint16, remote netip.AddrPort, iss Value) error { + if !remote.IsValid() { + return errInvalidIP + } err := conn.h.OpenActive(localPort, remote.Port(), iss) if err != nil { return err diff --git a/tcp/handler.go b/tcp/handler.go index bcd339b..936e465 100644 --- a/tcp/handler.go +++ b/tcp/handler.go @@ -92,6 +92,7 @@ func (h *Handler) OpenActive(localPort, remotePort uint16, iss Value) error { return errors.New("zero port on open call") } h.reset(localPort, remotePort, iss) + h.scb.SetRecvWindow(Size(h.bufRx.Size())) return nil } @@ -234,7 +235,7 @@ func (h *Handler) Send(b []byte) (int, error) { var segment Segment if h.AwaitingSynSend() { // Handling init syn segment. - segment = ClientSynSegment(h.scb.ISS(), h.scb.RecvWindow()) + segment = ClientSynSegment(h.bufTx.iss, Size(h.bufRx.Size())) h.optcodec.PutOption16(b[sizeHeaderTCP:], OptMaxSegmentSize, uint16(len(b))) offset++ } else { @@ -266,7 +267,7 @@ func (h *Handler) Send(b []byte) (int, error) { } tfrm.SetSourcePort(h.localPort) tfrm.SetDestinationPort(h.remotePort) - tfrm.SetSegment(segment, offset) // No TCP options. + tfrm.SetSegment(segment, offset) tfrm.SetUrgentPtr(0) return int(offset)*4 + int(segment.DATALEN), nil } diff --git a/tcp/txqueue.go b/tcp/txqueue.go index 9463773..479e579 100644 --- a/tcp/txqueue.go +++ b/tcp/txqueue.go @@ -32,6 +32,7 @@ type ringTx struct { // seq Value // always empty ring. emptyRing ringidx + iss Value } // ringidx represents packet data inside RingTx @@ -49,7 +50,7 @@ type ringidx struct { // Reset resets the RingTx's internal state to use buf as the main ring buffer and creates or reuses // the packet ring buffer. -func (rtx *ringTx) Reset(buf []byte, maxqueuedPackets int, seq Value) error { +func (rtx *ringTx) Reset(buf []byte, maxqueuedPackets int, iss Value) error { buf = buf[:len(buf):len(buf)] // safely omit capacity section. if maxqueuedPackets <= 0 { return errors.New("queued packets <=0") @@ -66,6 +67,7 @@ func (rtx *ringTx) Reset(buf []byte, maxqueuedPackets int, seq Value) error { for i := range rtx.packets { rtx.packets[i].markRcvd() } + rtx.iss = iss return nil }