nio

package
v0.0.0-...-2867ec3 Latest Latest
Warning

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

Go to latest
Published: Feb 29, 2024 License: Apache-2.0 Imports: 22 Imported by: 11

Documentation

Index

Constants

View Source
const (
	ConnectCommand   = uint8(1)
	BindCommand      = uint8(2)
	AssociateCommand = uint8(3)
)
View Source
const (
	NoAuth = uint8(0)

	UserPassAuth = uint8(2)
)
View Source
const (
	SO_ORIGINAL_DST      = 80
	IP6T_SO_ORIGINAL_DST = 80
)
View Source
const ConnectOverrideHeader = "x-host"
View Source
const ContextKey = "ugate.stream"
View Source
const DebugClose = true

If true, will debug or close operations. Close is one of the hardest problems, due to FIN/RST multiple interfaces.

Variables

View Source
var (
	CountGetBuffer atomic.Int32
	CountPutBuffer atomic.Int32
)

Buffer chunks are allocated from a pool to reduce pressure on GC. The maximum wasted space per dataBuffer is 2x the largest size class, which happens when the dataBuffer has multiple chunks and there is one unread byte in both the first and last chunks. We use a few size classes to minimize overheads for servers that typically receive very small request bodies.

View Source
var (
	VarzSErrRead  = expvar.NewInt("ugate_srv_err_read_total")
	VarzSErrWrite = expvar.NewInt("ugate_srv_err_write_total")
	VarzCErrRead  = expvar.NewInt("ugate_client_err_read_total")
	VarzCErrWrite = expvar.NewInt("ugate_client_err_write_total")

	VarzMaxRead = expvar.NewInt("ugate_max_read_bytes")

	// Managed by 'NewTCPProxy' - before dial.
	TcpConTotal = expvar.NewInt("gate_tcp_total")

	// Managed by updateStatsOnClose - including error cases.
	TcpConActive = expvar.NewInt("gate_tcp_active")
)
View Source
var Debug = false

TODO: benchmark different sizes.

View Source
var DebugRW = false
View Source
var ErrDeadlineExceeded error = &DeadlineExceededError{}

ErrDeadlineExceeded is returned for an expired deadline. This is exported by the os package as os.ErrDeadlineExceeded.

View Source
var ProxyCnt atomic.Int32
View Source
var StreamId uint32
View Source
var (
	// Number of copy operations using slice.
	VarzReadFromC = expvar.NewInt("io_copy_slice_total")
)

Varz interface. Varz is a wrapper for atomic operation, with a json http interface. Prometheus, OTel etc can directly use them.

Functions

func AcceptTProxy

func AcceptTProxy(l *net.TCPListener) (*net.TCPConn, error)

AcceptTProxy will accept a TCP connection and wrap it to a TProxy connection to provide TProxy functionality

func CanSplice

func CanSplice(in io.Reader, out io.Writer) bool

Verify if in and out can be spliced. Used by proxy code to determine best method to copy.

Tcp connections implement ReadFrom, not WriteTo ReadFrom is only spliced in few cases

func CopyRequestHeaders

func CopyRequestHeaders(dst, src http.Header)

used in createUpstreamRequetst to copy the headers to the new req.

func CopyResponseHeaders

func CopyResponseHeaders(dst, src http.Header)

Also used in httpproxy_capture, for forward http proxy

func CreateUpstreamRequest

func CreateUpstreamRequest(rw http.ResponseWriter, r *http.Request) *http.Request

CreateUpstremRequest shallow-copies r into a new request that can be sent upstream.

Derived from reverseproxy.go in the standard Go httputil package.

Use with a roundtripper - HTTP1.1 or H2C or HTTPS, followed by SendBackResponse

func DialOriginalDestination

func DialOriginalDestination(remote, local *net.TCPAddr) (*net.TCPConn, error)

DialOriginalDestination will open a TCP connection to the original destination that the client was trying to connect to before being intercepted.

When local is nil, the connection will originate from local, which can be the IP address and port that the client used when making the connection with TProxy. Otherwise, when true, the connection will originate from an IP address and port assigned by the Linux kernel that is owned by the operating system

remoteSocketAddress in TProxy case is the localAddr of the tproxy - original destination. localSocketAddress in TProxy is the local IP - to preserve port

func GetDataBufferChunk

func GetDataBufferChunk(size int64) []byte

Get a raw buffer with approximate size. Used by framer.

func GetREDIRECTOriginalDst

func GetREDIRECTOriginalDst(clientConn *net.TCPConn) (rawaddr *net.TCPAddr, err error)

Should be used only for REDIRECT capture.

func HandleSocks

func HandleSocks(br *BufferReader, s *Socks, w io.WriteCloser) (err error)

func IptablesCapture

func IptablesCapture(addr string, ug func(nc net.Conn, dest, la *net.TCPAddr)) (*net.TCPListener, error)

func Listen

func Listen(addr string) (net.Listener, error)

func ListenAndServe

func ListenAndServe(addr string, f func(conn net.Conn)) (net.Listener, error)

func ListenTProxy

func ListenTProxy(network string, laddr *net.TCPAddr) (*net.TCPListener, error)

ListenTProxy will construct a new TCP listener socket with the Linux IP_TRANSPARENT option set on the underlying socket

func NoEOF

func NoEOF(err error) error

func Proxy

func Proxy(nc net.Conn, in io.Reader, w io.Writer, dest string) error

Proxy forwards from nc to in/w. nc is typically the result of DialContext

func PutDataBufferChunk

func PutDataBufferChunk(p []byte)

Return a chunk to the pool. Called after write is completed or the buffer is no longer needed.

func SendBackResponse

func SendBackResponse(w http.ResponseWriter, r *http.Request,
	res *http.Response, err error)

Used by both ForwardHTTP and ForwardMesh, after RoundTrip is done. Will copy response headers and body

func ServeListener

func ServeListener(l net.Listener, f func(conn net.Conn)) error

func Sock5Capture

func Sock5Capture(addr string, cb func(s *Socks, c net.Conn)) (net.Listener, error)

Types

type Buffer

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

Buffer is a buffer associated with a stream that can be used to sniff data and to reuse the read buffers and frames.

The Fill method will populate the buffer by doing one or more Read() operations, up to buffer size. Read will first return data from the buffer, and if buffer is empty will read directly from the source reader. The buffer can be used for parsing.

func GetBuffer

func GetBuffer(prefix, size int) *Buffer

func (*Buffer) Buffer

func (b *Buffer) Buffer() []byte

func (*Buffer) Bytes

func (b *Buffer) Bytes() []byte

Return the unread portion of the buffer

func (*Buffer) BytesAppend

func (b *Buffer) BytesAppend() []byte

func (*Buffer) Clear

func (b *Buffer) Clear()

func (*Buffer) Compact

func (b *Buffer) Compact()

func (*Buffer) Discard

func (b *Buffer) Discard(n int)

func (*Buffer) End

func (b *Buffer) End() int

func (*Buffer) Fill

func (s *Buffer) Fill(r io.Reader, i int) ([]byte, error)

func (*Buffer) Frame

func (b *Buffer) Frame(start, end int) *Buffer

Return a subset (view) of a real read buffer

func (*Buffer) Grow

func (b *Buffer) Grow(n int)

Grow enough for n additional bytes

func (*Buffer) IsEmpty

func (b *Buffer) IsEmpty() bool

func (*Buffer) Len

func (b *Buffer) Len() int

func (*Buffer) Out

func (b *Buffer) Out() []byte

func (*Buffer) ReadBlocking

func (s *Buffer) ReadBlocking(r io.Reader, d []byte) (int, error)

func (*Buffer) ReadByte

func (s *Buffer) ReadByte(ior io.Reader) (byte, error)

func (*Buffer) ReadData

func (s *Buffer) ReadData(d []byte) (int, error)

func (*Buffer) Recycle

func (b *Buffer) Recycle()

func (*Buffer) SetByte

func (b *Buffer) SetByte(pos int, i byte)

func (*Buffer) SetUnint32

func (b *Buffer) SetUnint32(pos int, i uint32)

func (*Buffer) SetUnint32BE

func (b *Buffer) SetUnint32BE(pos int, i uint32)

func (*Buffer) Size

func (b *Buffer) Size() int

Size return the number of unread bytes in the buffer.

func (*Buffer) Skip

func (b *Buffer) Skip(count int) int

func (*Buffer) Start

func (b *Buffer) Start() int

func (*Buffer) UpdateAppend

func (b *Buffer) UpdateAppend(bout []byte)

UpdateAppend should be called if any append operation may resize and replace the buffer - for example protobuf case.

func (*Buffer) Write

func (b *Buffer) Write(p []byte) (n int, err error)

func (*Buffer) WriteByte

func (b *Buffer) WriteByte(d byte)

func (*Buffer) WriteUnint32

func (b *Buffer) WriteUnint32(i uint32)

WriteUint32 adds a little endian uint32 to the buffer.

func (*Buffer) WriteVarint

func (b *Buffer) WriteVarint(i int64)

type BufferPool

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

func (*BufferPool) GetBuffer

func (bp *BufferPool) GetBuffer() *Buffer

type BufferReader

type BufferReader struct {
	Reader io.Reader
	Buffer *Buffer
}

A Reader with an associated read buffer for sniffing or copy.

func NewBufferReader

func NewBufferReader(in io.Reader) *BufferReader

NewBufferReader adds a buffer associated with a reader. Read will first consume the buffer. The BufferReader can peek and parse the input. Once the bufer is read, Read() will directly use the stream unless Peek methods are used.

func (*BufferReader) Close

func (s *BufferReader) Close() error

func (*BufferReader) Discard

func (br *BufferReader) Discard(n int)

Discard will move the start with n bytes. TODO: if n > buffer, blocking read. Currently not used in the code. Same interface as bufio.Reader

func (*BufferReader) Peek

func (s *BufferReader) Peek(i int) ([]byte, error)

Peek returns the next n bytes without advancing the reader. The bytes stop being valid at the next read call. If Peek returns fewer than n bytes, it also returns an error explaining why the read is short.

Same interface as bufio.Reader Unlike bufio.Reader, if n is larger than buffer size the buffer is resized.

Peek ensures at least i bytes are read. Blocking.

Returns the buffer with all readable data, may be more than i If i==0, does one Read.

func (*BufferReader) Read

func (s *BufferReader) Read(d []byte) (int, error)

type ChannelListener

type ChannelListener struct {
	Address net.Addr
	// contains filtered or unexported fields
}

ChannelListener implements Listener interface over a chan It allows apps expecting a net.Listener to accept virtual streams tunneled and multiplexed.

func NewChannelListener

func NewChannelListener() *ChannelListener

func (*ChannelListener) Accept

func (l *ChannelListener) Accept() (net.Conn, error)

func (*ChannelListener) Addr

func (l *ChannelListener) Addr() net.Addr

func (*ChannelListener) Close

func (l *ChannelListener) Close() error

func (*ChannelListener) OnConnection

func (l *ChannelListener) OnConnection(c net.Conn) error

type ClientHelloMsg

type ClientHelloMsg struct {
	Raw []byte

	//random              []byte
	SessionID    []byte
	CipherSuites []uint16
	//compressionMethods  []uint8
	ServerName string
	// contains filtered or unexported fields
}

ClientHelloMsg is a subset of the TLS ClientHello

func SniffClientHello

func SniffClientHello(acc *BufferReader) (*ClientHelloMsg, string, error)

SniffClientHello will peek into acc and read enough for parsing a TLS ClientHello. All read data will be left in the stream, including bytes after ClientHello.

If ClientHello is not detected or is invalid - nil will be returned.

TODO: if a session WorkloadID is provided, use it as a cookie and attempt to find the corresponding host. On server side generate session IDs !

TODO: in mesh, use one cypher suite (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) maybe 2 ( since keys are ECDSA )

type CloseWriter

type CloseWriter interface {
	CloseWrite() error
}

CloseWriter is one of possible interfaces implemented by RequestInPipe to send a FIN, without closing the input. Some writers only do this when Close is called.

type ContextGetter

type ContextGetter interface {
	Context() context.Context
}

ContextGetter allows getting a Context associated with a stream or request or other high-level object. Based on http.Request

type DeadlineExceededError

type DeadlineExceededError struct{}

DeadlineExceededError is returned for an expired deadline.

func (*DeadlineExceededError) Error

func (e *DeadlineExceededError) Error() string

Implement the net.Error interface. The string is "i/o timeout" because that is what was returned by earlier Go versions. Changing it may break programs that match on error strings.

func (*DeadlineExceededError) Temporary

func (e *DeadlineExceededError) Temporary() bool

func (*DeadlineExceededError) Timeout

func (e *DeadlineExceededError) Timeout() bool

type H2Dialer

type H2Dialer struct {
	MDS        TokenSource
	H2TunURL   string
	HttpClient *http.Client
}

func NewH2Dialer

func NewH2Dialer(tunURL string) *H2Dialer

func (*H2Dialer) DialContext

func (h2d *H2Dialer) DialContext(ctx context.Context, net, addr string) (net.Conn, error)

type InOutStream

type InOutStream struct {
	StreamState

	// In - data from remote.
	//
	// - TCP or TLS net.Conn,
	// - a http request Body (stream mapped to a http accepted connection in a Handler)
	// - http response Body (stream mapped to a client http connection)
	// - a QUIC stream - accepted or dialed
	// - some other ReadCloser.
	//
	// Closing In without fully reading all data may result in RST.
	//
	// Normal process for close is to call CloseWrite (sending a FIN), read In fully
	// ( i.e. until remote FIN is received ) and call In.Close.
	// If In.Close is called before FIN was received the TCP stack may send a RST if more
	// data is received from the other end.
	In io.ReadCloser `json:"-"`

	// Out - send to remote.
	//
	// - an instance of net.Conn or tls.Conn - both implementing CloseWrite for FIN
	// - http.ResponseWriter - for accepted HTTP connections, implements CloseWrite
	// - a Pipe - for dialed HTTP connections, emulating DialContext behavior ( no body sent before connection is
	//   completed)
	// - nil, if the remote side is read only ( GET ) or if the creation of the
	//   stream passed a Reader object which is automatically piped to the RequestInPipe, for example
	//   when a HTTP request body is used.
	//
	Out io.Writer `json:"-"`

	// Request associated with the stream. Will be set if the stream is
	// received over HTTP (real or over another virtual connection),
	// or if the stream is originated locally and sent to a HTTP dest.
	//
	// For streams associated with HTTP server handlers, Out is the ResponseWriter.
	//
	Request *http.Request `json:"-"`
	// ---------------------------------------------------
	// Used for gRPC and other similar framing protocols
	// Response holds the response, for client mode
	Response *http.Response

	// Metadata to send. InOutStream implements http.ResponseWriter.
	// For streams without metadata - will be ignored.
	// Incoming metadata is set in Request.
	// TODO: without a request, use a buffer, append headers in serialized format directly, flush on first Write
	// @Deprecated - use a buf.
	OutHeader http.Header `json:"-"`

	// Header received from the remote.
	// For egress it is the response headers.
	// For ingress it is the request headers.
	// TODO: map[int][]byte, use read buffer to parse to avoid alloc.
	// Use equivalent of QPACK with uncompressed headers, custom dict.
	// @Deprecated - use a buf, packed format, id-based headers.
	InHeader http.Header `json:"-"`

	// Set if the connection finished a TLS handshake.
	// A 'dummy' value may be set if a sidecar terminated the connection.
	TLS *tls.ConnectionState `json:"-"`

	// Remote mesh ID, if authenticated. Base32(SHA256(PUB)) or Base32(PUB) (for ED)
	// This can be used in DNS names, URLs, etc.
	RemoteID string

	// Remote mesh ID, in byte form.
	Remote [32]byte

	// VIP is the internal ID used in dmesh, based on the SHA of address or public key.
	RemoteVIP uint64

	// Original dest - hostname or IP, including port. Parameter of the original RoundTripStart from the captured egress stream.
	// May be a mesh IP6, host, etc. If original address was captured by IP, destIP will also be set.
	// Host is extracted from metadata (SOCKS, iptables, etc)
	// Typically a DNS or IP address
	// For example in CONNECT it will be hostname:port or IP:port
	// For HTTP PROXY the path is a full URL.
	Dest string

	LocalA net.Addr

	// Resolved destination IP. May be nil if SOCKS or forwarding is done. Final Gateway will have it set.
	// If capture is based on IP, it'll be set in all hops.
	// If set, this is the authoritiative destination.
	DestAddr *net.TCPAddr

	//  Real remote address form the socket. May be different from DestAddr (DestAddr can be VIP)
	RemoteA net.Addr

	// Client type - original capture and all transport hops.
	// SOCKS, CONNECT, PROXY, SOCKSIP, PROXYIP,
	// EPROXY = TCP-over-HTTP in, direct host out
	// MUX- - for streams associated with a mux.
	// TODO: use int
	Type string

	// Methods to call when the stream is closed on the read side, i.e. received a FIN or RST or
	// the context was canceled.
	ReadCloser func() `json:"-"`

	// Set if CloseWrite() was called, which should result in a FIN sent.
	// This should happen if a EOF was received when proxying.
	ServerClose bool `json:"-"`

	// Set if the client has sent the FIN, and gateway sent the FIN to server
	ClientClose bool `json:"-"`

	// Set if Close() was called.
	Closed bool `json:"-"`

	// Only for 'accepted' streams (server side), in proxy mode: keep track
	// of the client side. The server is driving the proxying.
	ProxyReadErr  error `json:"-"`
	ProxyWriteErr error `json:"-"`

	// Optional function to call after dial (proxied streams) or after a stream handling has started for local handlers.
	// Used to send back metadata or finish the handshake.
	//
	// For example in SOCKS it sends back the IP/port of the remote.
	// net.Conn may be a InOutStream or a regular TCP/TLS connection.
	PostDialHandler func(net.Conn, error) `json:"-"`

	//
	//
	//
	Direction StreamType

	Listener net.Listener

	// Will receive a 'nil' or error on connect.
	// Will receive a nil or error on receive error (clean close or RST)
	ErrChan chan error
	// contains filtered or unexported fields
}

InOutStream implements net.Conn using a tunneled, multi-layer protocol with metadata.

The 'raw' connection is typically: - an accepted connection - In/RequestInPipe are the raw net.Conn - with sniffing and processing of SNI/TLS-SNI, SOCKS - a TLSConn, wrapping the accepted connection - HTTP2 RequestBody+ResponseWriter

Metadata is extracted from the headers, SNI, SOCKS, Iptables. Example: - raw TCP connection - SOCKS - extracted dest host:port or IP:port - IPTables - extracted original DST IP:port - SNI - extracted 'Server Name' - port based on the listener port - TLS - peer certificates, SNI, ALPN

Metrics and security info are also maintained.

Implements net.Conn - but does not implement ConnectionState(), so the stream can be used with H2 library to create multiplexed H2 connections over the stream.

func GetStream

func GetStream(out io.Writer, in io.ReadCloser) *InOutStream

GetStream should be used to get a (recycled) stream. Streams will be tracked, and must be closed and recycled.

func NewStream

func NewStream() *InOutStream

NewStream create a new stream. This stream is not tracked.

func (*InOutStream) Close

func (s *InOutStream) Close() error

Must be called at the end. It is expected CloseWrite has been called, for graceful FIN.

func (*InOutStream) CloseWrite

func (s *InOutStream) CloseWrite() error

func (*InOutStream) Context

func (s *InOutStream) Context() context.Context

Context of the stream. It has a value 'ugate.stream' that points back to the stream, so it can be passed in various methods that only take context.

This is NOT associated with the context of the original H2 request, there is a lot of complexity and strange behaviors in the stack.

func (*InOutStream) CopyBuffered

func (s *InOutStream) CopyBuffered(dst io.Writer, src io.Reader, srcIsRemote bool) (written int64, err error)

Copy src to dst, using a pooled intermediary buffer.

Will update stats about activity and data. Does not close dst when src is closed

Blocking, returns when src returned an error or EOF/graceful close. May also return with error if src or dst return errors.

srcIsRemote indicates that the connection is from the server to client. (remote to local) If false, the connection is from client to server ( local to remote )

func (*InOutStream) Fill

func (s *InOutStream) Fill(nb int) ([]byte, error)

Fill the buffer by doing one Read() from the underlying reader.

Future calls to Read() will use the remaining data in the buffer. @Deprecated - use BufferReader.Peek()

func (*InOutStream) Flush

func (s *InOutStream) Flush()

func (*InOutStream) GetWriteFrame

func (hc *InOutStream) GetWriteFrame(sz int) *Buffer

Return a buffer with reserved front space to be used for appending. If using functions like proto.Marshal, b.UpdateForAppend should be called with the new []byte. App should not touch the prefix.

func (*InOutStream) Header

func (s *InOutStream) Header() http.Header

func (*InOutStream) LocalAddr

func (s *InOutStream) LocalAddr() net.Addr

func (*InOutStream) PostDial

func (b *InOutStream) PostDial(nc net.Conn, err error)

func (*InOutStream) ProxyTo

func (s *InOutStream) ProxyTo(nc net.Conn) error

Proxy the accepted connection to a dialed connection. Blocking, will wait for both sides to FIN or RST.

func (*InOutStream) RBuffer

func (s *InOutStream) RBuffer() *Buffer

RBuffer method will return or create a buffer. It can be used for parsing headers or sniffing. The 'Read' and 'WriteTo' methods are aware of the buffer, and will use the first consume buffered data, but if the buffer is IsEmpty will use directly In.

func (*InOutStream) Read

func (s *InOutStream) Read(out []byte) (int, error)

func (*InOutStream) ReadByte

func (s *InOutStream) ReadByte() (byte, error)

func (*InOutStream) ReadFrom

func (s *InOutStream) ReadFrom(cin io.Reader) (n int64, err error)

Reads data from cin (the client/dialed con) until EOF or error TCP Connections typically implement this, using io.Copy().

func (*InOutStream) ReadHeader

func (s *InOutStream) ReadHeader(in io.Reader) error

func (*InOutStream) Recv

func (hc *InOutStream) Recv(last bool) (*Buffer, error)

func (*InOutStream) RemoteAddr

func (s *InOutStream) RemoteAddr() net.Addr

RemoteAddr is the client (for accepted) or server (for originated). It should be the real IP, extracted from connection or metadata. RemoteID returns the authenticated ID.

func (*InOutStream) RequestHeader

func (s *InOutStream) RequestHeader() http.Header

func (*InOutStream) Send

func (hc *InOutStream) Send(b *Buffer) error

Framed sending/receiving.

func (*InOutStream) SendHeader

func (s *InOutStream) SendHeader(w io.WriteCloser, h http.Header) error

Send will marshall the metadata (headers) and start sending the body to w.

func (*InOutStream) SetDeadline

func (s *InOutStream) SetDeadline(t time.Time) error

func (*InOutStream) SetReadDeadline

func (s *InOutStream) SetReadDeadline(t time.Time) error

func (*InOutStream) SetWriteDeadline

func (s *InOutStream) SetWriteDeadline(t time.Time) error

func (*InOutStream) Skip

func (s *InOutStream) Skip(n int)

Skip only implemented for buffer Deprecated: use BufferReader.Discard()

func (*InOutStream) State

func (s *InOutStream) State() *StreamState

func (*InOutStream) TLSConnectionState

func (s *InOutStream) TLSConnectionState() *tls.ConnectionState

func (*InOutStream) TransportConn

func (s *InOutStream) TransportConn() net.Conn

func (*InOutStream) WBuffer

func (s *InOutStream) WBuffer() *Buffer

WBuffer returns the write buffer associated with the stream. Used to encode headers or for buffering - to avoid the pattern of allocating small non-pooled buffers. TODO: also to use for bucket passing instead of copy.

func (*InOutStream) Write

func (s *InOutStream) Write(b []byte) (n int, err error)

Write implements the io.Writer. The Write() is flushed if possible.

TODO: incorporate the wbuffer, optimize based on size.

func (*InOutStream) WriteHeader

func (s *InOutStream) WriteHeader(statusCode int)

func (*InOutStream) WriteTo

func (s *InOutStream) WriteTo(w io.Writer) (n int64, err error)

WriteTo implements the interface, using the read buffer.

type ReaderCopier

type ReaderCopier struct {
	// Number of bytes copied.
	Written int64
	MaxRead int
	ReadCnt int

	// First error - may be on reading from In (InError=true) or writing to Out.
	Err error

	InError bool

	In io.Reader

	// For tunneled connections, this can be a tls.Writer. Close will write an TOS close.
	Out io.Writer

	// An ID of the copier, for debug purpose.
	ID string

	// Set if out doesn't implement Flusher and a separate function is needed.
	// Example: tunneled mTLS over http, Out is a tls.Conn which writes to a http Body.
	Flusher http.Flusher
}

ReaderCopier copies from In to Out, keeping track of copied bytes and errors.

func (*ReaderCopier) Close

func (rc *ReaderCopier) Close()

func (*ReaderCopier) Copy

func (s *ReaderCopier) Copy(ch chan int, close bool)

Copy will copy src to dst, using a pooled intermediary buffer.

Blocking, returns when src returned an error or EOF/graceful close.

May also return with error if src or dst return errors.

Copy may be called in a go routine, for one of the streams in the connection - the stats and error are returned on a channel.

type RecvBufferReader

type RecvBufferReader struct {

	// Err is set when a buffer with that error is Put. backlog may have additional data,
	// but no new data will be received.
	// May be io.EOF
	Err error

	ReadDeadline time.Time
	// contains filtered or unexported fields
}

RecvBufferReader implements io.Reader interface to readBlocking the frame data. Frames are added to the backlog or sent (non-blocking) to the channel from the reader thread.

The blocking readBlocking is pretty complicated, attempts to consume all availalbe data first and returns it - before doing a blocking receive on the channel.

TODO: WIP to pass data frames and avoid one copy.

Orig RecvBuffer is an unbounded channel of RecvMsg structs. It can grow up to window size - flow control protects it.

Note: RecvBuffer differs from buffer.Unbounded only in the fact that it holds a channel of RecvMsg structs instead of objects implementing "item" interface. RecvBuffer is written to much more often and using strict RecvMsg structs helps avoid allocation in "RecvBuffer.Put"

func NewRecvBuffer

func NewRecvBuffer(ctxDone <-chan struct{},
	recycleBuffer func(*bytes.Buffer), closeStream func(err error)) *RecvBufferReader

NewRecvBuffer creates a receive buffer.

Will hold frames, represented as bytes.Buffer, added with Put

The Read() method will first return existing data, then block.

recycleBuffer, if set, will be called after the buffer has been copied and can be reused. closeStream is called if there is any error except io.EOF or deadline exceeded.

func (*RecvBufferReader) Put

func (b *RecvBufferReader) Put(r RecvMsg)

Put adds the buffer to either the chan or backlog. Reads on chan most be followed by reloadChannel.

func (*RecvBufferReader) Read

func (r *RecvBufferReader) Read(p []byte) (n int, err error)

Read reads the next len(p) bytes from last. If last is drained, it tries to readBlocking additional data from recv. It blocks if there no additional data available in recv. If Read returns any non-nil error, it will continue to return that error.

func (*RecvBufferReader) Recv

func (r *RecvBufferReader) Recv() (bb *bytes.Buffer, err error)

Recv returns next data frame buffer, or block until a new buffer is available.

func (*RecvBufferReader) RecvNB

func (r *RecvBufferReader) RecvNB() (bb *bytes.Buffer, err error)

RecvNonBlocking is like Recv, but won't block

type RecvMsg

type RecvMsg struct {
	Buffer *bytes.Buffer
	// nil: received some data
	// io.EOF: stream is completed. data is nil.
	// other non-nil error: transport failure. data is nil.
	Err error
}

RecvMsg represents the received msg from the transport. All transport protocol specific info has been removed.

type Socks

type Socks struct {
	Dest     string
	DestAddr *net.TCPAddr
	Writer   io.WriteCloser
}

func (*Socks) PostDialHandler

func (s *Socks) PostDialHandler(localAddr net.Addr, err error)

Must be called before sending any data, to send the local addr used when dialing. This is rarely used - tproxy doesn't send anything back either.

type Stats

type Stats struct {
	Open time.Time

	// last receive from local (and send to remote)
	LastWrite time.Time

	// last receive from remote (and send to local)
	LastRead time.Time

	// Sent from client to server ( client is initiator of the proxy )
	SentBytes   int
	SentPackets int

	// Received from server to client
	RcvdBytes   int
	RcvdPackets int
}

Stats holds telemetry for a stream or peer.

type Stream

type Stream interface {
	net.Conn
	//context.Context
	StreamMeta
	ContextGetter
}

Stream interface extends net.Conn with a context and metadata.

func NewStreamRequest

func NewStreamRequest(r *http.Request, out io.WriteCloser, w *http.Response) Stream

NewStreamRequest creates a Stream based on the result of a RoundTrip. out is typically the pipe used by request to send bytes. TODO: abstract the pipe and the roundtrip call.

type StreamConn

type StreamConn struct {
	StreamState

	Conn net.Conn // may be a *tls.Conn

	// TLS info - if the connection is direct TLS.
	TLS *tls.ConnectionState

	// May be populated from Istio metadata or PROXY protocol, etc.
	ResponseHeader http.Header
	RequestHeaders http.Header
	// contains filtered or unexported fields
}

StreamConn wraps a net.Conn or a tls connection

func NewStreamConn

func NewStreamConn(r net.Conn) *StreamConn

func (*StreamConn) Close

func (s *StreamConn) Close() error

func (*StreamConn) Context

func (s *StreamConn) Context() context.Context

func (*StreamConn) Header

func (s *StreamConn) Header() http.Header

func (*StreamConn) LocalAddr

func (s *StreamConn) LocalAddr() net.Addr

func (*StreamConn) Read

func (s *StreamConn) Read(b []byte) (n int, err error)

func (*StreamConn) RemoteAddr

func (s *StreamConn) RemoteAddr() net.Addr

func (*StreamConn) RequestHeader

func (s *StreamConn) RequestHeader() http.Header

func (*StreamConn) SetDeadline

func (s *StreamConn) SetDeadline(t time.Time) error

func (*StreamConn) SetReadDeadline

func (s *StreamConn) SetReadDeadline(t time.Time) error

func (*StreamConn) SetWriteDeadline

func (s *StreamConn) SetWriteDeadline(t time.Time) error

func (*StreamConn) State

func (s *StreamConn) State() *StreamState

func (*StreamConn) TLSConnectionState

func (s *StreamConn) TLSConnectionState() *tls.ConnectionState

func (*StreamConn) Write

func (s *StreamConn) Write(b []byte) (n int, err error)

type StreamHttpClient

type StreamHttpClient struct {
	StreamState

	Request    *http.Request
	Response   *http.Response
	ReadCloser func()

	// Writer side of the request pipe
	TLS           *tls.ConnectionState
	RequestInPipe io.WriteCloser
}

func NewStreamH2

func NewStreamH2(ctx context.Context, hc *http.Client, addr string, tcpaddr string, mds TokenSource) (*StreamHttpClient, error)

NewStreamH2 creates a H2 stream using POST.

Will use the token provider if not nil.

func (*StreamHttpClient) Close

func (s *StreamHttpClient) Close() error

func (*StreamHttpClient) CloseWrite

func (s *StreamHttpClient) CloseWrite() error

func (*StreamHttpClient) Context

func (s *StreamHttpClient) Context() context.Context

func (*StreamHttpClient) Header

func (s *StreamHttpClient) Header() http.Header

func (*StreamHttpClient) LocalAddr

func (s *StreamHttpClient) LocalAddr() net.Addr

func (*StreamHttpClient) Read

func (s *StreamHttpClient) Read(b []byte) (n int, err error)

func (*StreamHttpClient) RemoteAddr

func (s *StreamHttpClient) RemoteAddr() net.Addr

func (*StreamHttpClient) RequestHeader

func (s *StreamHttpClient) RequestHeader() http.Header

func (*StreamHttpClient) SetDeadline

func (s *StreamHttpClient) SetDeadline(t time.Time) error

func (*StreamHttpClient) SetReadDeadline

func (s *StreamHttpClient) SetReadDeadline(t time.Time) error

func (*StreamHttpClient) SetWriteDeadline

func (s *StreamHttpClient) SetWriteDeadline(t time.Time) error

func (*StreamHttpClient) State

func (s *StreamHttpClient) State() *StreamState

func (*StreamHttpClient) TLSConnectionState

func (s *StreamHttpClient) TLSConnectionState() *tls.ConnectionState

func (*StreamHttpClient) Write

func (s *StreamHttpClient) Write(b []byte) (n int, err error)

type StreamHttpServer

type StreamHttpServer struct {
	StreamState

	Request        *http.Request
	TLS            *tls.ConnectionState
	ResponseWriter http.ResponseWriter

	// If set, the function will be called when Close() is called.
	ReadCloser func()
}

func NewStreamServerRequest

func NewStreamServerRequest(r *http.Request, w http.ResponseWriter) *StreamHttpServer

Create a new stream from a HTTP request/response.

For accepted requests, http2/server.go newWriterAndRequests populates the request based on the headers. Server validates method, path and scheme=http|https. Req.Body is a pipe - similar with what we use for egress. Request context is based on stream context, which is a 'with cancel' based on the serverConn baseCtx.

func (*StreamHttpServer) Close

func (s *StreamHttpServer) Close() error

func (*StreamHttpServer) CloseWrite

func (s *StreamHttpServer) CloseWrite() error

func (*StreamHttpServer) Context

func (s *StreamHttpServer) Context() context.Context

func (*StreamHttpServer) Header

func (s *StreamHttpServer) Header() http.Header

func (*StreamHttpServer) LocalAddr

func (s *StreamHttpServer) LocalAddr() net.Addr

func (*StreamHttpServer) Read

func (s *StreamHttpServer) Read(b []byte) (n int, err error)

func (*StreamHttpServer) RemoteAddr

func (s *StreamHttpServer) RemoteAddr() net.Addr

func (*StreamHttpServer) RequestHeader

func (s *StreamHttpServer) RequestHeader() http.Header

func (*StreamHttpServer) SetDeadline

func (s *StreamHttpServer) SetDeadline(t time.Time) error

func (*StreamHttpServer) SetReadDeadline

func (s *StreamHttpServer) SetReadDeadline(t time.Time) error

func (*StreamHttpServer) SetWriteDeadline

func (s *StreamHttpServer) SetWriteDeadline(t time.Time) error

func (*StreamHttpServer) State

func (s *StreamHttpServer) State() *StreamState

func (*StreamHttpServer) TLSConnectionState

func (s *StreamHttpServer) TLSConnectionState() *tls.ConnectionState

func (*StreamHttpServer) Write

func (s *StreamHttpServer) Write(b []byte) (n int, err error)

type StreamMeta

type StreamMeta interface {
	State() *StreamState

	// Also part of ResponseWriter - it is the response header.
	Header() http.Header

	RequestHeader() http.Header

	TLSConnectionState() *tls.ConnectionState
}

type StreamState

type StreamState struct {

	// It is the key in the Active table.
	// Streams may also have local ids associated with the transport.
	StreamId string

	// WritErr indicates that Write failed - timeout or a RST closing the stream.
	WriteErr error `json:"-"`
	// ReadErr, if not nil, indicates that Read() failed - connection was closed with RST
	// or timedout instead of FIN
	ReadErr error `json:"-"`

	Stats

	// Original or infered destination.
	Dest string
}

StreamState provides metadata about a stream.

It includes errors, stats, other metadata. The Stream interface wraps a net.Conn with context and state.

type StreamType

type StreamType int
const (
	StreamTypeUnknown StreamType = iota

	// Ingress - received on the HBONE mux for the local process, on
	//  a 'sidecar'.
	StreamTypeIn

	// Egress - indicates if is originated from local machine, i.e.
	// SOCKS/iptables/TUN capture or dialed from local process
	StreamTypeOut

	// Forward - received on HBONE mux to forward to a workload
	StreamTypeForward
)

type TokenSource

type TokenSource interface {
	// GetToken for a given audience.
	GetToken(context.Context, string) (string, error)
}

TokenSource is a common interface for anything returning Bearer or other kind of tokens.

Directories

Path Synopsis
Package bufferv2 provides the implementation of a non-contiguous buffer that is reference counted, pooled, and copy-on-write.
Package bufferv2 provides the implementation of a non-contiguous buffer that is reference counted, pooled, and copy-on-write.
bits
Package bits includes all bit related types and operations.
Package bits includes all bit related types and operations.
Package syscall provides functionalities that grpc uses to get low-level operating system stats/info.
Package syscall provides functionalities that grpc uses to get low-level operating system stats/info.

Jump to

Keyboard shortcuts

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