zerocopy

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2022 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package zerocopy defines interfaces and helper functions for zero-copy read/write operations.

Index

Constants

View Source
const (
	IPv4HeaderLength = 20
	IPv6HeaderLength = 40
	UDPHeaderLength  = 8
)

Used in packet size calculations.

Variables

View Source
var (
	ErrPacketTooSmall = errors.New("packet too small to unpack")
	ErrPayloadTooBig  = errors.New("payload too big to pack")
)
View Source
var ErrAcceptDoneNoRelay = errors.New("the accepted connection has been handled without relaying")

Functions

func CloseWriteDrain

func CloseWriteDrain(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

CloseWriteDrain closes the write end of the TCP connection, then drain the read end.

func CopyWriteOnce

func CopyWriteOnce(rw ReadWriter, b []byte) (n int, err error)

func ForceReset

func ForceReset(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

ForceReset forces a reset of the TCP connection, regardless of whether there's unread data or not.

func MaxPacketSizeForAddr

func MaxPacketSizeForAddr(mtu int, addr netip.Addr) int

MaxPacketSizeForAddr calculates the maximum packet size for the given address based on the MTU and the address family.

func PackerUnpackerTestFunc

func PackerUnpackerTestFunc(t *testing.T, packer Packer, unpacker Unpacker)

PackerUnpackerTestFunc tests the packer and the unpacker by using the packer to pack a random payload and using the unpacker to unpack the packed packet.

func ReadWriterTestFunc

func ReadWriterTestFunc(t *testing.T, l, r ReadWriter)

ReadWriterTestFunc tests the left and right ReadWriters by performing 2 writes on each ReadWriter and validating the read results.

The left and right ReadWriters must be connected with a duplex pipe.

func Relay

func Relay(w Writer, r Reader) (n int64, err error)

Relay reads from r and writes to w using zero-copy methods. It returns the number of bytes transferred, and any error occurred during transfer.

func TwoWayRelay

func TwoWayRelay(left, right ReadWriter) (nl2r, nr2l int64, err error)

TwoWayRelay relays data between left and right using zero-copy methods. It returns the number of bytes sent from left to right, from right to left, and any error occurred during transfer.

Types

type CloseRead

type CloseRead interface {
	// CloseRead indicates to the underlying reader that no further reads will happen.
	CloseRead() error
}

CloseRead provides the CloseRead method.

type CloseWrite

type CloseWrite interface {
	// CloseWrite indicates to the underlying writer that no further writes will happen.
	CloseWrite() error
}

CloseWrite provides the CloseWrite method.

type CopyReadWriter

type CopyReadWriter struct {
	ReadWriter
	// contains filtered or unexported fields
}

CopyReadWriter wraps a ReadWriter and provides the io.ReadWriter Read and Write methods by copying from and to internal buffers and using the zerocopy methods on them.

func NewCopyReadWriter

func NewCopyReadWriter(rw ReadWriter) *CopyReadWriter

func (*CopyReadWriter) Read

func (rw *CopyReadWriter) Read(b []byte) (n int, err error)

Read implements the io.Reader Read method.

func (*CopyReadWriter) Write

func (rw *CopyReadWriter) Write(b []byte) (n int, err error)

Write implements the io.Writer Write method.

type DirectReadCloser

type DirectReadCloser interface {
	// DirectReadCloser returns the underlying reader for direct reads.
	DirectReadCloser() io.ReadCloser
}

DirectReadCloser provides access to the underlying io.ReadCloser.

type DirectReadWriteCloser

type DirectReadWriteCloser interface {
	io.ReadWriteCloser
	CloseRead
	CloseWrite
}

DirectReadWriteCloser extends io.ReadWriteCloser with CloseRead and CloseWrite.

type DirectWriteCloser

type DirectWriteCloser interface {
	// DirectWriteCloser returns the underlying writer for direct writes.
	DirectWriteCloser() io.WriteCloser
}

DirectWriteCloser provides access to the underlying io.WriteCloser.

type Headroom

type Headroom interface {
	// FrontHeadroom returns the minimum space required at the beginning of the buffer before payload.
	FrontHeadroom() int

	// RearHeadroom returns the minimum space required at the end of the buffer after payload.
	RearHeadroom() int
}

Headroom is implemented by readers and writers that require extra buffer space as headroom in read/write calls.

type InitialPayloader

type InitialPayloader interface {
	// NativeInitialPayload reports whether the protocol natively supports
	// sending the initial payload within or along with the request header.
	//
	// No matter true or false, the Dial method must process the initial payload.
	//
	// When false, the Accept method will not return non-empty initial payload.
	NativeInitialPayload() bool
}

InitialPayloader is implemented by a protocol's TCP client or server when the protocol's initial handshake message can carry payload.

type PackUnpacker

type PackUnpacker interface {
	Packer
	Unpacker
}

PackUnpacker implements both Packer and Unpacker interfaces.

type Packer

type Packer interface {
	Headroom

	// PackInPlace packs the payload in-place into a packet and returns packet start offset, packet length,
	// or an error if packing fails.
	PackInPlace(b []byte, targetAddr socks5.Addr, payloadStart, payloadLen, maxPacketLen int) (packetStart, packetLen int, err error)
}

Packer processes raw payload into packets.

type ReadWriter

type ReadWriter interface {
	Reader
	Writer
	CloseRead
	CloseWrite
}

ReadWriter provides a stream interface for reading and writing.

type Reader

type Reader interface {
	Headroom

	// MinPayloadBufferSizePerRead returns the minimum size of payload buffer
	// the ReadZeroCopy method requires for an unbuffered read.
	//
	// This is usually required by chunk-based protocols to be able to read
	// whole chunks without needing internal caching.
	MinPayloadBufferSizePerRead() int

	// ReadZeroCopy uses b as buffer space to initiate a read operation.
	//
	// b must have at least FrontOverhead() bytes before payloadBufStart
	// and RearOverhead() bytes after payloadBufStart + payloadBufLen.
	//
	// payloadBufLen must be at least MinPayloadBufferSizePerRead().
	//
	// The read operation may use the whole space of b.
	// The actual payload will be confined in [payloadBufStart, payloadBufLen).
	//
	// If no error occurs, the returned payload is b[payloadBufStart : payloadBufStart+payloadLen].
	ReadZeroCopy(b []byte, payloadBufStart, payloadBufLen int) (payloadLen int, err error)

	io.Closer
}

Reader provides a stream interface for reading.

type SimpleUDPClient

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

SimpleUDPClient wraps a PackUnpacker and uses it for all sessions.

SimpleUDPClient implements the UDPClient interface.

func NewSimpleUDPClient

func NewSimpleUDPClient(p PackUnpacker, addrPort netip.AddrPort, hasAddrPort bool, mtu, fwmark, frontHeadroom, rearHeadroom int) *SimpleUDPClient

NewSimpleUDPClient wraps a PackUnpacker into a UDPClient and uses it for all sessions.

func (*SimpleUDPClient) AddrPort

func (c *SimpleUDPClient) AddrPort() (netip.AddrPort, int, int, bool)

AddrPort implements the UDPClient AddrPort method.

func (*SimpleUDPClient) FrontHeadroom

func (c *SimpleUDPClient) FrontHeadroom() int

FrontHeadroom implements the UDPClient FrontHeadroom method.

func (*SimpleUDPClient) NewSession

func (c *SimpleUDPClient) NewSession() (Packer, Unpacker, error)

NewSession implements the UDPClient NewSession method.

func (*SimpleUDPClient) RearHeadroom

func (c *SimpleUDPClient) RearHeadroom() int

RearHeadroom implements the UDPClient RearHeadroom method.

type TCPClient

type TCPClient interface {
	InitialPayloader

	// Dial creates a connection to the target address under the protocol's
	// encapsulation and returns the established connection and a ReadWriter for read-write access.
	Dial(targetAddr socks5.Addr, payload []byte) (tfoConn tfo.Conn, rw ReadWriter, err error)
}

TCPClient is a protocol's TCP client.

type TCPConnCloser

type TCPConnCloser func(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

TCPConnCloser handles a potentially malicious TCP connection. Upon returning, the TCP connection is safe to close.

func ParseRejectPolicy

func ParseRejectPolicy(rejectPolicy string, server TCPServer) (TCPConnCloser, error)

ParseRejectPolicy parses a string representation of a reject policy.

func (TCPConnCloser) Do

func (c TCPConnCloser) Do(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

Do invokes the TCPConnCloser if it's not nil.

type TCPServer

type TCPServer interface {
	InitialPayloader

	// Accept takes a newly-accepted TCP connection and wraps it into a
	// protocol stream server.
	//
	// If the returned error is ErrAcceptDoneNoRelay, the connection has been handled by this method.
	// Two-way relay is not needed.
	Accept(conn tfo.Conn) (rw ReadWriter, targetAddr socks5.Addr, payload []byte, err error)

	// DefaultTCPConnCloser returns the default function to handle the closing
	// of a potentially malicious TCP connection.
	//
	// If no special handling is required, return nil.
	DefaultTCPConnCloser() TCPConnCloser
}

TCPServer provides a protocol's TCP service.

type UDPClient

type UDPClient interface {
	// Headroom reports client packer headroom requirements.
	Headroom

	// NewSession creates a new session and returns the packet packer
	// and unpacker for the session, or an error.
	NewSession() (Packer, Unpacker, error)

	// AddrPort returns the fixed target address and port of packed outgoing packets,
	// or false if individual packet's target address should be used.
	AddrPort() (addrPort netip.AddrPort, mtu, fwmark int, ok bool)
}

UDPClient stores the necessary information for creating new sessions.

type UDPServer

type UDPServer interface {
	// Headroom reports server unpacker headroom requirements.
	Headroom

	// SessionInfo extracts session ID from a received packet b.
	//
	// The returned session ID is then used by the caller to look up the session table.
	// If no matching entries were found, NewUnpacker should be called to create a new
	// packet unpacker for the packet.
	SessionInfo(b []byte) (csid uint64, err error)

	// NewUnpacker creates a new packet unpacker for the specified client session.
	//
	// The returned unpacker is then used by the caller to unpack the incoming packet.
	// Upon successful unpacking, NewPacker should be called to create a corresponding
	// server session.
	NewUnpacker(b []byte, csid uint64) (Unpacker, error)

	// NewPacker creates a new server session for the specified client session
	// and returns the server session's packer, or an error.
	NewPacker(csid uint64) (Packer, error)
}

UDPServer deals with incoming sessions.

type Unpacker

type Unpacker interface {
	Headroom

	// UnpackInPlace unpacks the packet in-place and returns target address, payload start offset, payload length,
	// or an error if unpacking fails.
	//
	// If the packed packet does not contain information about the target address, hasTargetAddr should be false,
	// and the packet's source address should be used instead.
	UnpackInPlace(b []byte, packetStart, packetLen int) (targetAddr socks5.Addr, hasTargetAddr bool, payloadStart, payloadLen int, err error)
}

Unpacker processes packets into raw payload.

type Writer

type Writer interface {
	Headroom

	// MaxPayloadSizePerWrite returns the maximum size of payload
	// the WriteZeroCopy method can write at a time.
	//
	// This is usually required by chunk-based protocols to be able to write
	// one chunk at a time without needing to break up the payload.
	//
	// If there isn't a maximum limit, return 0.
	MaxPayloadSizePerWrite() int

	// WriteZeroCopy uses b as buffer space to initiate a write operation.
	//
	// b must have at least FrontOverhead() bytes before payloadBufStart
	// and RearOverhead() bytes after payloadBufStart + payloadBufLen.
	//
	// payloadLen must not be greater than MaxPayloadSizePerWrite().
	//
	// The write operation may use the whole space of b.
	WriteZeroCopy(b []byte, payloadStart, payloadLen int) (payloadWritten int, err error)

	io.Closer
}

Writer provides a stream interface for writing.

type ZeroHeadroom

type ZeroHeadroom struct{}

ZeroHeadroom can be embedded by types that have zero headroom.

func (ZeroHeadroom) FrontHeadroom

func (z ZeroHeadroom) FrontHeadroom() int

FrontHeadroom implements the Headroom FrontHeadroom method.

func (ZeroHeadroom) RearHeadroom

func (z ZeroHeadroom) RearHeadroom() int

RearHeadroom implements the Headroom RearHeadroom method.

Jump to

Keyboard shortcuts

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