socks6

package module
v0.0.0-...-48a15a0 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2022 License: 0BSD Imports: 27 Imported by: 0

README

SOCKS 6 Golang implementation

Maybe production ready, if someone have a production, please let me know.

currently based on draft 12

Usage

Use socks6.Server to create a SOCKS 6 over TCP/IP server.

If you need process SOCKS 6 connection in other protocol, named pipe, etc., use socks6.ServerWorker to process connection.

You can modify socks6.ServerWorker 's fields to customize it's behavior.

Use socks6.Client to create a SOCKS 6 over TCP/IP client.

Change socks6.Client.DialFunc to dial over other protocol.

SOCKS 6 wireformat parser and serializer is located in message package.

Reference


Experimental/customized features

This implementation contains some experimental and customized features.

Experimental features are intended to integrate to RFC. If they are not integrated eventually, it will either removed or become optional customized feature.

Customized features are designed to improve user experience, especially under eletronic warfare scenario, which radar cross section (RCS) are important. All of these features are optional.

(Radar: a device which determine some object's position and type, by sending some carefully constructed data then read and analysis possible reflection data.)

Consistent address format

See https://github.com/45G/socks6-draft/issues/5

Use same address format in TCP and UDP message, to simplify address parsing. Not integrate to RFC yet, can't be disabled.

Ignore fragmented request message

Optional. Used to mitigate large packet DDoS [1] attack and to help reduce server's RCS[2].

Implemented by only reading from buffer when parsing request message, which is implemented by setting read timeout to 1us after accept connection and hope it works as intended/imagine. It cause reflection only occured when incoming pulse is long enough and using special modulation, effectively make reflection harder to occur, which in turn reduced RCS.

Address dependent filtering NAT (Restricted cone)

Optional. In some sceneario, UDP Endpoint independent filtering (Full cone) NAT can reflect radar pulse, cause much higher RCS. Switch to address dependent filtering can absorb incoming radar pulse, reduce RCS significantly without losing critical end-to-end property too much.

About UDP NAT behavior see RFC4787

QUIC transport

Optional. Should belongs to another Internet Draft or a new Workgroup,

RFC9221 mentioned

Unreliable QUIC datagrams can also be used to implement an IP packet tunnel over QUIC, such as for a Virtual Private Network (VPN).

And here comes a Virtual Private Network (VPN).

Technically SOCKS works on Session Layer (L5), most VPN works on Network Layer (L3), but thanks for our great vendors and service providers, modern Internet even only need two transport layer protocols (By the way, that's why I choose shiny new QUIC transport instead of old school SCTP transport,), unbreakable obstacle between the layers has been broken, we are going toward a layerless Internet which all nodes are equal,

Not tested yet. Since there are no such Internet Draft not to mention Workgroup yet. Here's my simple draft.

Draft

BCP14 boilerplate, you know what it is, omitted.

  • All QUIC stream use same protocol with TCP, no "control stream"
  • Client SHOULD try to authenticate over every stream until one stream finished authentication (either success or fail).
  • Server SHOULD only authenticate first incoming stream, when fail, close entire conn.
  • All stream in a connection are belongs to same session.

(stack option may wont works as expected?)

Per command requirement:

  • CONNECT
    • (nothing)
  • BIND
    • When backlog option enabled, server open a new stream to client, send remote's address via a operation reply (without client send anything). Only a backlog enabled stream per connection.
    • client can use streamid option to open multiple backlog bind
    c               s               r
    ---------------------------------
    ---#1 bind sa1-->
                    listen sa1
    <--#1 oprep sa1--
                    <---- sa1<ra1 ---

without streamid
    <--#2 oprep ra1--
    <--#2 relay -------------- ra1-->

with streamid
    <-#2 oprep ra1(#1)
    <--#2 relay -------------- ra1-->
  • UDP
    • use assoc id to distinguish between streams
    • Client SHOULD send QUIC datagram
    • Client and server MAY use UDP over TCP on QUIC stream (to support QUIC impl without RFC9221 and muxconn with no dgram capability, i.e. SCTP)
    • Both side MUST NOT skip association check

New option: StreamID, contains a uint32, unique for each conn. Used by client to enable mux bind.

  • non-mux conn MUST ignore it.
  • In same conn, client MUST either always send it or not send it.
  • When not send by client, client MUST NOT open more than 1 backlog bind per conn.
  • Server MUST reply same stream id when ack mux bind

IANA consideration:

  • socks6 over quic port
  • streamid option

Normative ref:

  • RFC9000 (quic)
  • RFC9221 (quic dgram)
  • BCP14 (keyword)
  • I-D.socks6

Informative ref:

  • RFC9260 (sctp)
  • RFC6951 (sctp over udp)

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrTTLExpired          = errors.New("ttl expired")
	ErrServerFailure       = errors.New("socks 6 server failure")
	ErrUnexpectedMessage   = errors.New("unexpected protocol message")
	ErrAssociationMismatch = errors.New("association mismatch")
)

Functions

func ReplyVersionSpecificError

func ReplyVersionSpecificError(ctx context.Context, ver message.VersionMismatchError, conn net.Conn)

ReplyVersionSpecificError guess which protocol client is using, reply corresponding "version error", then close conn.

Types

type Client

type Client struct {
	// server address
	Server string
	// use TLS and DTLS when connect to server
	Encrypted bool
	// use QUIC
	QUIC bool
	// send datagram over TCP, when use QUIC, send datagram over QUIC stream instead of QUIC datagram
	UDPOverTCP bool
	// function to create underlying connection, net.Dial will used when it is nil
	DialFunc func(ctx context.Context, network string, addr string) (net.Conn, error)
	// authentication method to be used, can be nil
	AuthenticationMethod auth.ClientAuthenticationMethod

	// should client request session
	UseSession bool
	// how much token will requested
	UseToken uint32
	// suggested bind backlog
	Backlog int

	EnableICMP bool
	// contains filtered or unexported fields
}

Client is a SOCKS 6 client, implements net.Dialer, net.Listener.

func (*Client) BindRequest

func (c *Client) BindRequest(ctx context.Context, addr net.Addr, option *message.OptionSet) (*ProxyTCPListener, error)

func (*Client) ConnectRequest

func (c *Client) ConnectRequest(ctx context.Context, addr net.Addr, initData []byte, option *message.OptionSet) (net.Conn, error)

func (*Client) Dial

func (c *Client) Dial(network string, addr string) (net.Conn, error)

func (*Client) DialContext

func (c *Client) DialContext(ctx context.Context, network string, addr string) (net.Conn, error)

func (*Client) Listen

func (c *Client) Listen(network string, addr string) (net.Listener, error)

func (*Client) ListenContext

func (c *Client) ListenContext(ctx context.Context, network string, addr string) (net.Listener, error)

func (*Client) ListenPacket

func (c *Client) ListenPacket(network string, addr string) (net.PacketConn, error)

func (*Client) ListenPacketContext

func (c *Client) ListenPacketContext(ctx context.Context, network string, addr string) (net.PacketConn, error)

func (*Client) NoopRequest

func (c *Client) NoopRequest(ctx context.Context) error

NoopRequest send a NOOP request.

func (*Client) UDPAssociateRequest

func (c *Client) UDPAssociateRequest(ctx context.Context, addr net.Addr, option *message.OptionSet) (*ProxyUDPConn, error)

type CommandHandler

type CommandHandler func(
	ctx context.Context,
	cc SocksConn,
)

type MessageReplyCodeError

type MessageReplyCodeError message.ReplyCode

func (MessageReplyCodeError) Error

func (m MessageReplyCodeError) Error() string

type ProxyTCPConn

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

ProxyTCPConn represents a proxied TCP connection, implements net.Conn.

func (*ProxyTCPConn) ProxyLocalAddr

func (t *ProxyTCPConn) ProxyLocalAddr() net.Addr

func (*ProxyTCPConn) ProxyRemoteAddr

func (t *ProxyTCPConn) ProxyRemoteAddr() net.Addr

func (*ProxyTCPConn) RemoteAddr

func (t *ProxyTCPConn) RemoteAddr() net.Addr

type ProxyTCPListener

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

func (*ProxyTCPListener) Accept

func (t *ProxyTCPListener) Accept() (net.Conn, error)

func (*ProxyTCPListener) AcceptContext

func (t *ProxyTCPListener) AcceptContext(ctx context.Context) (net.Conn, error)

func (*ProxyTCPListener) Addr

func (t *ProxyTCPListener) Addr() net.Addr

func (*ProxyTCPListener) Close

func (t *ProxyTCPListener) Close() error

func (*ProxyTCPListener) LocalAddr

func (t *ProxyTCPListener) LocalAddr() net.Addr

func (*ProxyTCPListener) ProxyRemoteAddr

func (t *ProxyTCPListener) ProxyRemoteAddr() net.Addr

type ProxyUDPConn

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

ProxyUDPConn represents a SOCKS 6 UDP client "connection", implements net.PacketConn, net.Conn.

func (*ProxyUDPConn) Close

func (u *ProxyUDPConn) Close() error

func (*ProxyUDPConn) LocalAddr

func (u *ProxyUDPConn) LocalAddr() net.Addr

LocalAddr return client-proxy connection's client side address.

func (*ProxyUDPConn) ProxyBindAddr

func (u *ProxyUDPConn) ProxyBindAddr() net.Addr

ProxyBindAddr return proxy's outbound address.

func (*ProxyUDPConn) ProxyRemoteAddr

func (u *ProxyUDPConn) ProxyRemoteAddr() net.Addr

ProxyRemoteAddr return client-proxy connection's proxy side address.

func (*ProxyUDPConn) Read

func (u *ProxyUDPConn) Read(p []byte) (int, error)

Read implements net.Conn.

func (*ProxyUDPConn) ReadFrom

func (u *ProxyUDPConn) ReadFrom(p []byte) (int, net.Addr, error)

ReadFrom implements net.PacketConn.

func (*ProxyUDPConn) RemoteAddr

func (u *ProxyUDPConn) RemoteAddr() net.Addr

func (*ProxyUDPConn) SetDeadline

func (u *ProxyUDPConn) SetDeadline(t time.Time) error

func (*ProxyUDPConn) SetReadDeadline

func (u *ProxyUDPConn) SetReadDeadline(t time.Time) error

func (*ProxyUDPConn) SetWriteDeadline

func (u *ProxyUDPConn) SetWriteDeadline(t time.Time) error

func (*ProxyUDPConn) Write

func (u *ProxyUDPConn) Write(p []byte) (int, error)

Write implements net.Conn.

func (*ProxyUDPConn) WriteTo

func (u *ProxyUDPConn) WriteTo(p []byte, addr net.Addr) (int, error)

WriteTo implements net.PacketConn.

type Server

type Server struct {
	Address       string
	CleartextPort uint16
	EncryptedPort uint16
	QuicPort      uint16

	TLSConfig *tls.Config
	Worker    *ServerWorker
	// contains filtered or unexported fields
}

Server is a SOCKS 6 over TCP/TLS/UDP/DTLS server zero value is a cleartext only server with default server worker.

func (*Server) Start

func (s *Server) Start(ctx context.Context)

type ServerWorker

type ServerWorker struct {
	Authenticator auth.ServerAuthenticator
	Rule          func(cc SocksConn) bool

	CommandHandlers map[message.CommandCode]CommandHandler
	// VersionErrorHandler will handle non-SOCKS6 protocol request.
	// VersionErrorHandler should close connection by itself
	VersionErrorHandler func(ctx context.Context, ver message.VersionMismatchError, conn net.Conn)

	DatagramVersionErrorHandler func(ctx context.Context, ver message.VersionMismatchError, dgram nt.Datagram)

	Outbound nt.Outbound

	// control UDP NAT filtering behavior,
	// mapping behavior is always Endpoint Independent.
	//
	// when false, use Endpoint Independent filtering (Full Cone)
	//
	// when true, use Address Dependent filtering (Restricted Cone)
	AddressDependentFiltering bool

	// require request message fully received in first packet
	//
	// Yes, TCP has no "packet" -- but that's only makes sense for people
	// who never need to touch the dark side of Internet.
	// Packet are everywhere in a packet switched network,
	// you can create a stream on it and hide it behind API,
	// but it's still a packet sequence on wire.
	IgnoreFragmentedRequest bool
	EnableICMP              bool

	HandshakeTimeout time.Duration
	StreamTimeout    time.Duration
	DatagramTimeout  time.Duration
	// contains filtered or unexported fields
}

ServerWorker is a customizeable SOCKS 6 server.

func NewServerWorker

func NewServerWorker() *ServerWorker

NewServerWorker create a standard SOCKS 6 server.

func (*ServerWorker) BindHandler

func (s *ServerWorker) BindHandler(
	ctx context.Context,
	cc SocksConn,
)

func (*ServerWorker) ClearUnusedResource

func (s *ServerWorker) ClearUnusedResource(ctx context.Context)

ClearUnusedResource clear no longer used resources (UDP associations, etc.) only need to call it once for each ServerWorker.

func (*ServerWorker) ConnectHandler

func (s *ServerWorker) ConnectHandler(
	ctx context.Context,
	cc SocksConn,
)

func (*ServerWorker) ForwardICMP

func (s *ServerWorker) ForwardICMP(ctx context.Context, msg *icmp.Message, ip *net.IPAddr, ver int)

func (*ServerWorker) NoopHandler

func (s *ServerWorker) NoopHandler(
	ctx context.Context,
	cc SocksConn,
)

func (*ServerWorker) ServeDatagram

func (s *ServerWorker) ServeDatagram(
	ctx context.Context,
	dgram nt.Datagram,
)

func (*ServerWorker) ServeMuxConn

func (s *ServerWorker) ServeMuxConn(
	ctx context.Context,
	mux nt.MultiplexedConn,
)

func (*ServerWorker) ServeSeqPacket

func (s *ServerWorker) ServeSeqPacket(
	ctx context.Context,
	dgramSrc nt.SeqPacket,
)

func (*ServerWorker) ServeStream

func (s *ServerWorker) ServeStream(
	ctx context.Context,
	conn net.Conn,
)

ServeStream process incoming TCP and TLS connection return when connection process complete, e.g. remote closed connection.

func (*ServerWorker) UDPAssociateHandler

func (s *ServerWorker) UDPAssociateHandler(
	ctx context.Context,
	cc SocksConn,
)

type SocksConn

type SocksConn struct {
	Conn    net.Conn
	MuxConn nt.MultiplexedConn
	Request *message.Request // request sent by client

	ClientID    string // client identifier provided by authenticator
	Session     []byte // the session this connection belongs to
	StreamID    uint32 // stream id provided by client
	InitialData []byte // client's initial data
}

SocksConn represents a SOCKS 6 connection received by server.

func (SocksConn) ConnID

func (c SocksConn) ConnID() string

ConnID return connection's client endpoint string for logging purpose.

func (SocksConn) Destination

func (c SocksConn) Destination() message.SocksAddr

Destination is endpoint included in client's request.

func (SocksConn) WriteReply

func (c SocksConn) WriteReply(code message.ReplyCode, ep net.Addr, opt *message.OptionSet) error

WriteReply write operation reply with given parameter to client.

func (SocksConn) WriteReplyAddr

func (c SocksConn) WriteReplyAddr(code message.ReplyCode, ep net.Addr) error

WriteReplyAddr see WriteReply.

func (SocksConn) WriteReplyCode

func (c SocksConn) WriteReplyCode(code message.ReplyCode) error

WriteReplyCode see WriteReply.

Directories

Path Synopsis
cmd
lg
lg is a wrapper of builtin log package
lg is a wrapper of builtin log package
nt
rnd
e2e
message contains SOCKS 6 wireformat parser and serializer
message contains SOCKS 6 wireformat parser and serializer

Jump to

Keyboard shortcuts

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