vtcp

package
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package vtcp implements a full, RFC-compliant TCP protocol engine operating on raw TCP segments. It is IP-agnostic and Ethernet-agnostic — callers provide a SegmentWriter callback for sending and feed incoming segments via HandleSegment.

Supported RFCs:

  • RFC 793: TCP state machine
  • RFC 6298: RTO calculation (SRTT, RTTVAR, Karn's algorithm)
  • RFC 5681: Congestion control (slow start, congestion avoidance, fast retransmit/recovery)
  • RFC 7323: Window scaling, timestamps (RTTM, PAWS)
  • RFC 2018: Selective acknowledgment (SACK)
  • RFC 1122: Keepalive

Index

Constants

View Source
const (
	FlagFIN = 0x01
	FlagSYN = 0x02
	FlagRST = 0x04
	FlagPSH = 0x08
	FlagACK = 0x10
	FlagURG = 0x20
)

TCP header flag bits.

View Source
const (
	DefaultMSS        = 1460
	DefaultWindowSize = 65535
	DefaultSendBuf    = 1 << 20 // 1 MB
	DefaultRecvBuf    = 1 << 20 // 1 MB

	DefaultRTO = time.Second
	MinRTO     = 200 * time.Millisecond
	MaxRTO     = 60 * time.Second
	MaxRetries = 8

	TimeWaitDuration = 2 * time.Second // shortened for virtual environments

	DefaultKeepaliveIdle     = 300 * time.Second
	DefaultKeepaliveInterval = 15 * time.Second
	DefaultKeepaliveCount    = 3
)

Default values.

View Source
const (
	OptEnd       byte = 0
	OptNOP       byte = 1
	OptMSS       byte = 2
	OptWScale    byte = 3
	OptSACKPerm  byte = 4
	OptSACK      byte = 5
	OptTimestamp byte = 8
)

TCP option kinds.

Variables

This section is empty.

Functions

func BuildOptions

func BuildOptions(opts []Option) []byte

BuildOptions serializes options into wire format, NOP-padded to 4-byte boundary.

func GetMSS

func GetMSS(opts []Option) uint16

GetMSS extracts the MSS value from options, returning 0 if not present.

func GetTimestamp

func GetTimestamp(opts []Option) (tsVal, tsEcr uint32, ok bool)

GetTimestamp extracts TSval and TSecr from options. Returns ok=false if not present.

func GetWScale

func GetWScale(opts []Option) int

GetWScale extracts the window scale shift from options, returning -1 if not present.

func HasSACKPerm

func HasSACKPerm(opts []Option) bool

HasSACKPerm checks if SACK-Permitted is in the options.

func RandUint32Exported

func RandUint32Exported() uint32

RandUint32Exported returns a cryptographically random uint32.

func SeqAfter

func SeqAfter(a, b uint32) bool

SeqAfter reports whether sequence number a is after b.

func SeqAfterEq

func SeqAfterEq(a, b uint32) bool

SeqAfterEq reports whether a is after or equal to b.

func SeqBefore

func SeqBefore(a, b uint32) bool

SeqBefore reports whether sequence number a is before b.

func SeqBeforeEq

func SeqBeforeEq(a, b uint32) bool

SeqBeforeEq reports whether a is before or equal to b.

func SeqInRange

func SeqInRange(seq, lo, hi uint32) bool

SeqInRange reports whether seq is in [lo, hi) in sequence space.

func SeqInRangeInclusive

func SeqInRangeInclusive(seq, lo, hi uint32) bool

SeqInRangeInclusive reports whether seq is in [lo, hi] in sequence space.

Types

type CongestionController

type CongestionController interface {
	// OnACK is called when new bytes are acknowledged.
	OnACK(bytesAcked uint32)
	// OnDupACK is called on each duplicate ACK.
	// Returns true if fast retransmit should be triggered (3rd dup ACK).
	OnDupACK() bool
	// OnTimeout is called on RTO timeout (loss detected via timeout).
	OnTimeout()
	// OnFastRetransmit is called when entering fast retransmit/recovery.
	// sndNxt is the current SND.NXT, used as the recovery point.
	OnFastRetransmit(flightSize uint32, sndNxt uint32)
	// ExitRecovery is called when recovery is complete (all data acked past recovery point).
	ExitRecovery()
	// SendWindow returns the current congestion window in bytes.
	SendWindow() uint32
	// InRecovery reports whether the sender is in fast recovery.
	InRecovery() bool
	// RecoverySeq returns the sequence number that must be fully acknowledged
	// to exit fast recovery (SND.NXT at the time recovery was entered).
	RecoverySeq() uint32
}

CongestionController defines the interface for TCP congestion control algorithms.

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn is a single TCP connection implementing net.Conn. It runs the full TCP state machine (RFC 793) with congestion control (RFC 5681), retransmission (RFC 6298), and optional modern extensions.

Callers interact with Conn from two sides:

  • Network side: HandleSegment (inbound), returned packets (outbound)
  • Application side: Read, Write, Close (net.Conn interface)

All outgoing packets are returned from methods (never sent while holding the internal mutex), making Conn safe for synchronous delivery patterns.

func NewConn

func NewConn(cfg ConnConfig) *Conn

NewConn creates a new TCP connection in the CLOSED state.

func (*Conn) Abort

func (c *Conn) Abort() [][]byte

Abort immediately tears down the connection.

func (*Conn) AcceptCookie

func (c *Conn) AcceptCookie(remoteSeq, ourISS uint32, mss uint16, initialData []byte) [][]byte

AcceptCookie initializes a Conn directly into StateEstablished from a validated SYN cookie handshake. Unlike AcceptSYN, this skips the SYN-RECEIVED state since the three-way handshake already completed (the SYN-ACK was sent statelessly via the cookie engine).

Parameters:

  • remoteSeq: the remote's current sequence number (their ISN + 1)
  • ourISS: our initial sequence number (the cookie value)
  • mss: the negotiated MSS from the cookie
  • initialData: any data carried in the completing ACK (may be nil)

func (*Conn) AcceptSYN

func (c *Conn) AcceptSYN(syn Segment) [][]byte

AcceptSYN processes an incoming SYN for passive open. Sets up connection state, queues a SYN-ACK, and returns packets to send.

func (*Conn) Close

func (c *Conn) Close() error

func (*Conn) Connect

func (c *Conn) Connect(ctx context.Context) error

Connect initiates a TCP handshake (active open). Sends SYN and blocks until the handshake completes or ctx is cancelled.

func (*Conn) Established

func (c *Conn) Established() <-chan struct{}

Established returns a channel that is closed when the connection reaches the ESTABLISHED state (three-way handshake complete).

func (*Conn) Flush

func (c *Conn) Flush(pkts [][]byte)

Flush sends outgoing packets via the Writer, with a trampoline to prevent stack overflow from synchronous mutual recursion (e.g. two vclients on the same L2Hub). Callers should use this instead of iterating Writer() directly.

func (*Conn) HandleSegment

func (c *Conn) HandleSegment(seg Segment) [][]byte

HandleSegment processes an incoming TCP segment following RFC 9293 §3.10.7.4. Returns packets to send in response. The caller MUST send these.

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() net.Addr

func (*Conn) Read

func (c *Conn) Read(b []byte) (int, error)

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) error

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

func (*Conn) SetWriteDeadline

func (c *Conn) SetWriteDeadline(t time.Time) error

func (*Conn) SetupForHandshake

func (c *Conn) SetupForHandshake(iss uint32)

SetupForHandshake puts the connection into SYN-SENT state with the given ISN, allowing HandleSegment to process a SYN-ACK. This is used for manual handshake in tests where Connect() can't be used (synchronous delivery).

func (*Conn) State

func (c *Conn) State() State

State returns the current TCP state.

func (*Conn) Write

func (c *Conn) Write(b []byte) (int, error)

func (*Conn) Writer

func (c *Conn) Writer() SegmentWriter

type ConnConfig

type ConnConfig struct {
	LocalAddr  net.Addr
	RemoteAddr net.Addr
	LocalPort  uint16
	RemotePort uint16
	Writer     SegmentWriter
	MSS        int

	// RFC 7323
	NoWindowScaling  bool // set true to disable window scaling (enabled by default)
	EnableTimestamps bool

	// RFC 2018
	EnableSACK bool

	// Congestion control: "newreno" or "highspeed" (default: "highspeed")
	CongestionControl string

	// RFC 1122 keepalive
	Keepalive         bool
	KeepaliveIdle     time.Duration
	KeepaliveInterval time.Duration
	KeepaliveCount    int

	SendBufSize int
	RecvBufSize int
}

ConnConfig holds configuration for a new Conn.

type HighSpeed

type HighSpeed struct {
	// contains filtered or unexported fields
}

HighSpeed implements RFC 3649 HighSpeed TCP for large congestion windows. When cwnd <= Low_Window (38 segments), it behaves identically to NewReno. Above that threshold, it uses more aggressive increase/decrease functions that scale better on high-BDP networks.

func NewHighSpeed

func NewHighSpeed(mss uint32) *HighSpeed

NewHighSpeed creates a HighSpeed TCP congestion controller (RFC 3649).

func (*HighSpeed) ExitRecovery

func (hs *HighSpeed) ExitRecovery()

func (*HighSpeed) InRecovery

func (hs *HighSpeed) InRecovery() bool

func (*HighSpeed) OnACK

func (hs *HighSpeed) OnACK(bytesAcked uint32)

func (*HighSpeed) OnDupACK

func (hs *HighSpeed) OnDupACK() bool

func (*HighSpeed) OnFastRetransmit

func (hs *HighSpeed) OnFastRetransmit(flightSize uint32, sndNxt uint32)

func (*HighSpeed) OnTimeout

func (hs *HighSpeed) OnTimeout()

func (*HighSpeed) RecoverySeq

func (hs *HighSpeed) RecoverySeq() uint32

func (*HighSpeed) SSThresh

func (hs *HighSpeed) SSThresh() uint32

func (*HighSpeed) SendWindow

func (hs *HighSpeed) SendWindow() uint32

type NewReno

type NewReno struct {
	// contains filtered or unexported fields
}

NewReno implements RFC 5681 TCP congestion control: slow start, congestion avoidance, fast retransmit, fast recovery.

func NewNewReno

func NewNewReno(mss uint32) *NewReno

NewNewReno creates a NewReno congestion controller. Initial cwnd is set to min(10*MSS, max(2*MSS, 14600)) per RFC 6928.

func (*NewReno) ExitRecovery

func (nr *NewReno) ExitRecovery()

ExitRecovery leaves fast recovery, deflating cwnd. RFC 5681 Section 3.2.

func (*NewReno) InRecovery

func (nr *NewReno) InRecovery() bool

InRecovery reports whether we are in fast recovery.

func (*NewReno) OnACK

func (nr *NewReno) OnACK(bytesAcked uint32)

OnACK processes a new ACK. RFC 5681 Section 3.1.

func (*NewReno) OnDupACK

func (nr *NewReno) OnDupACK() bool

OnDupACK processes a duplicate ACK. Returns true if this is the 3rd dup ACK (triggering fast retransmit). RFC 5681 Section 3.2.

func (*NewReno) OnFastRetransmit

func (nr *NewReno) OnFastRetransmit(flightSize uint32, sndNxt uint32)

OnFastRetransmit enters fast recovery. RFC 5681 Section 3.2.

func (*NewReno) OnTimeout

func (nr *NewReno) OnTimeout()

OnTimeout handles RTO timeout. RFC 5681 Section 3.1.

func (*NewReno) RecoverySeq

func (nr *NewReno) RecoverySeq() uint32

RecoverySeq returns the recovery point (SND.NXT at time of entering recovery).

func (*NewReno) SSThresh

func (nr *NewReno) SSThresh() uint32

SSThresh returns the current slow start threshold.

func (*NewReno) SendWindow

func (nr *NewReno) SendWindow() uint32

SendWindow returns the current congestion window.

type Option

type Option struct {
	Kind byte
	Data []byte // raw data (excluding kind and length bytes)
}

Option represents a parsed TCP option.

func MSSOption

func MSSOption(mss uint16) Option

MSSOption creates an MSS option.

func ParseOptions

func ParseOptions(raw []byte) []Option

ParseOptions parses the options portion of a TCP header.

func SACKOption

func SACKOption(blocks []SACKBlock) Option

SACKOption creates a SACK option with the given blocks.

func SACKPermOption

func SACKPermOption() Option

SACKPermOption creates a SACK-Permitted option.

func TimestampOption

func TimestampOption(tsVal, tsEcr uint32) Option

TimestampOption creates a timestamps option.

func WScaleOption

func WScaleOption(shift uint8) Option

WScaleOption creates a window scale option.

type RTOCalculator

type RTOCalculator struct {
	// contains filtered or unexported fields
}

RTOCalculator implements RFC 6298 RTO computation.

func NewRTOCalculator

func NewRTOCalculator() *RTOCalculator

NewRTOCalculator creates an RTO calculator with the default initial RTO.

func (*RTOCalculator) AckReceived

func (r *RTOCalculator) AckReceived(ack uint32) bool

AckReceived checks if the ACK covers the timed segment. If so, records the sample and stops timing. Returns true if a sample was taken.

func (*RTOCalculator) Backoff

func (r *RTOCalculator) Backoff()

Backoff doubles the current RTO (exponential backoff on timeout).

func (*RTOCalculator) InvalidateTiming

func (r *RTOCalculator) InvalidateTiming()

InvalidateTiming implements Karn's algorithm: discard the current timing on retransmission (don't sample retransmitted segments).

func (*RTOCalculator) RTO

func (r *RTOCalculator) RTO() time.Duration

RTO returns the current retransmission timeout.

func (*RTOCalculator) SRTT

func (r *RTOCalculator) SRTT() time.Duration

SRTT returns the smoothed RTT. Returns 0 if no measurement yet.

func (*RTOCalculator) Sample

func (r *RTOCalculator) Sample(rtt time.Duration)

Sample records an RTT measurement and recalculates RTO per RFC 6298.

func (*RTOCalculator) StartTiming

func (r *RTOCalculator) StartTiming(seq uint32)

StartTiming begins timing a segment for RTT measurement.

type RecvBuf

type RecvBuf struct {
	// contains filtered or unexported fields
}

RecvBuf reassembles an incoming TCP byte stream, handling both in-order and out-of-order segments. It maintains a SACK scoreboard for reporting non-contiguous received blocks.

func NewRecvBuf

func NewRecvBuf(initialNxt uint32, windowSize int) *RecvBuf

NewRecvBuf creates a receive buffer with the given initial sequence number and maximum window size. Data beyond nxt+windowSize is rejected.

func (*RecvBuf) HasOOO

func (r *RecvBuf) HasOOO() bool

HasOOO reports whether there are out-of-order segments buffered.

func (*RecvBuf) Insert

func (r *RecvBuf) Insert(seq uint32, data []byte) int

Insert adds a segment's payload at the given sequence number. Returns the number of new contiguous bytes added (available for Read). Out-of-order segments are buffered for later reassembly. Data beyond the receive window (nxt + windowSize) is trimmed.

func (*RecvBuf) Nxt

func (r *RecvBuf) Nxt() uint32

Nxt returns RCV.NXT (next expected sequence number).

func (*RecvBuf) Read

func (r *RecvBuf) Read(p []byte) int

Read copies contiguous data into p and removes it from the buffer.

func (*RecvBuf) Readable

func (r *RecvBuf) Readable() int

Readable returns the number of contiguous bytes available for Read.

func (*RecvBuf) SACKBlocks

func (r *RecvBuf) SACKBlocks() []SACKBlock

SACKBlocks returns up to 3 SACK blocks describing out-of-order data held.

func (*RecvBuf) Window

func (r *RecvBuf) Window() uint32

Window returns the current receive window (available space).

type SACKBlock

type SACKBlock struct {
	Left  uint32
	Right uint32
}

SACKBlock represents a SACK block (left edge inclusive, right edge exclusive).

func GetSACKBlocks

func GetSACKBlocks(opts []Option) []SACKBlock

GetSACKBlocks extracts SACK blocks from options.

type SYNCookies

type SYNCookies struct {
	// contains filtered or unexported fields
}

SYNCookies generates and validates SYN cookies for TCP SYN flood protection. When a listener's accept queue is full, SYN cookies allow handshakes to complete without allocating any per-connection state until the final ACK.

The tradeoff is that SYN-cookie-established connections do not negotiate window scaling, SACK, or timestamps (there aren't enough bits in the 32-bit ISS to encode these options). This matches Linux's behavior.

func NewSYNCookies

func NewSYNCookies() *SYNCookies

NewSYNCookies creates a new SYN cookie engine with a random secret.

func (*SYNCookies) GenerateSYNACK

func (sc *SYNCookies) GenerateSYNACK(syn Segment, localPort, mss uint16) Segment

GenerateSYNACK builds a SYN-ACK segment using a SYN cookie as the ISS. No connection state is allocated. The caller is responsible for wrapping the returned segment in an IP packet and sending it.

func (*SYNCookies) ValidateACK

func (sc *SYNCookies) ValidateACK(seg Segment, localPort uint16) (mss uint16, remoteISN uint32, ok bool)

ValidateACK checks whether an incoming ACK segment completes a SYN-cookie handshake. If valid, returns the negotiated MSS and the remote's initial sequence number (seg.Seq - 1). The caller should then create a Conn via AcceptCookie.

type Segment

type Segment struct {
	SrcPort  uint16
	DstPort  uint16
	Seq      uint32
	Ack      uint32
	Flags    uint8
	Window   uint16
	Checksum uint16
	Urgent   uint16
	Options  []Option
	Payload  []byte
}

Segment represents a parsed TCP segment (header + payload).

func ParseSegment

func ParseSegment(raw []byte) (Segment, error)

ParseSegment parses a raw TCP segment (no IP header).

func (*Segment) DataLen

func (s *Segment) DataLen() uint32

DataLen returns the payload length of the segment.

func (*Segment) HasFlag

func (s *Segment) HasFlag(flag uint8) bool

HasFlag reports whether the segment has the given flag set.

func (*Segment) Marshal

func (s *Segment) Marshal() []byte

Marshal serializes a Segment to wire format. The checksum field is set to zero — the caller must compute and fill it using IP pseudo-header information.

func (*Segment) SegLen

func (s *Segment) SegLen() uint32

SegLen returns the "segment length" consumed in sequence space: payload length + 1 for SYN + 1 for FIN.

type SegmentWriter

type SegmentWriter func(seg []byte) error

SegmentWriter is the callback for sending outgoing TCP segments. The data is a raw TCP segment (header + payload, no IP header). The caller is responsible for wrapping it in an IP packet and Ethernet frame and computing the TCP checksum (which requires the IP pseudo-header). The checksum field in the segment is left at zero.

type SendBuf

type SendBuf struct {
	// contains filtered or unexported fields
}

SendBuf tracks application data through the TCP send pipeline:

[acknowledged] [sent but unacked] [unsent / queued] [free space]
               ^                  ^                 ^
               una                nxt               tail

The buffer is a simple slice-based implementation. Data is appended at the tail and removed from the front as it is acknowledged.

func NewSendBuf

func NewSendBuf(capacity int, initialSeq uint32) *SendBuf

NewSendBuf creates a send buffer with the given capacity and initial sequence number.

func (*SendBuf) Acknowledge

func (s *SendBuf) Acknowledge(ack uint32) uint32

Acknowledge advances una to ack, freeing buffer space. Returns the number of bytes newly acknowledged.

func (*SendBuf) AdvanceSent

func (s *SendBuf) AdvanceSent(n int)

AdvanceSent marks n bytes as sent (moves nxt forward).

func (*SendBuf) Available

func (s *SendBuf) Available() int

Available returns the number of bytes of free space in the buffer.

func (*SendBuf) IsEmpty

func (s *SendBuf) IsEmpty() bool

IsEmpty reports whether all data is acknowledged and nothing is queued.

func (*SendBuf) IsSACKed

func (s *SendBuf) IsSACKed(seq uint32) bool

IsSACKed reports whether the given sequence number has been selectively acknowledged by the receiver.

func (*SendBuf) MarkSACKed

func (s *SendBuf) MarkSACKed(blocks []SACKBlock)

MarkSACKed records SACK blocks from the receiver. These indicate out-of-order data the receiver holds. Used to avoid retransmitting already-received segments.

func (*SendBuf) NXT

func (s *SendBuf) NXT() uint32

NXT returns SND.NXT.

func (*SendBuf) PeekUnsent

func (s *SendBuf) PeekUnsent(n int) []byte

PeekUnsent returns up to n bytes of unsent data without consuming them.

func (*SendBuf) Pending

func (s *SendBuf) Pending() int

Pending returns the number of bytes queued but not yet sent.

func (*SendBuf) RetransmitData

func (s *SendBuf) RetransmitData(n int) []byte

RetransmitData returns the first n bytes of unacknowledged data (from una), skipping any SACK'd ranges to avoid redundant retransmissions.

func (*SendBuf) UNA

func (s *SendBuf) UNA() uint32

UNA returns SND.UNA.

func (*SendBuf) Unacked

func (s *SendBuf) Unacked() int

Unacked returns the number of sent-but-unacknowledged bytes.

func (*SendBuf) Write

func (s *SendBuf) Write(p []byte) int

Write appends application data. Returns the number of bytes accepted. May return less than len(p) if the buffer is full.

type State

type State uint8

State represents a TCP connection state per RFC 793.

const (
	StateClosed      State = iota
	StateListen            // passive open, waiting for SYN
	StateSynSent           // active open, SYN sent
	StateSynReceived       // SYN received, SYN-ACK sent
	StateEstablished       // data transfer
	StateFinWait1          // FIN sent, waiting for ACK or FIN
	StateFinWait2          // our FIN ACKed, waiting for remote FIN
	StateCloseWait         // remote FIN received, app hasn't closed yet
	StateClosing           // simultaneous close (both FINs sent, waiting for ACK)
	StateLastAck           // close from CloseWait, FIN sent, waiting for ACK
	StateTimeWait          // both FINs ACKed, waiting before final close
)

func (State) String

func (s State) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL