socks5

package module
v0.0.18 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2025 License: MIT Imports: 10 Imported by: 1

README

build coverage goreport Docs

socks5

SOCKS5 client and server. Full test coverage provided by https://github.com/linkdata/socks5test.

  • Support for the CONNECT command
  • Support for the BIND command
  • Support for the ASSOCIATE command
  • Uses ContextDialer's for easy interoperation with other packages
  • Only depends on the standard library

Client

The client support for net.Listener includes reporting the bound address and port before calling Accept() and supports multiple concurrent Accept() calls, allowing you to reverse-proxy a server using this package.

Server

The server can listen on multiple listeners concurrently.

The server provides two abstractions to customize it's behavior.

The Authenticator interface allows custom authentication methods, and comes with implementations for anonymous usage (NoAuthAuthenticator) or username/password authentication (UserPassAuthenticator).

The DialerSelector interface allows selecting the ContextDialer to use for each outgoing connection based on authentication method, username, network and address. The default uses socks5.DefaultDialer.

Example

package main

import (
	"context"
	"errors"
	"log/slog"
	"net"
	"time"

	"github.com/linkdata/socks5/client"
	"github.com/linkdata/socks5/server"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second/10)
	defer cancel()

	listener, err := net.Listen("tcp", ":0")
	if err == nil {
		defer listener.Close()
		srv := server.Server{
			Logger: slog.Default(),
			Authenticators: []server.Authenticator{
				server.NoAuthAuthenticator{},
				server.UserPassAuthenticator{
					Credentials: server.StaticCredentials{
						"joe": "123456",
					},
				},
			},
		}
		go srv.Serve(ctx, listener)
		var cli *client.Client
		if cli, err = client.New("socks5h://joe:123456@" + listener.Addr().String()); err == nil {
			var l net.Listener
			if l, err = cli.ListenContext(ctx, "tcp", ":0"); err == nil {
				defer l.Close()
				slog.Info("client BIND", "address", l.Addr().String())
			}
		}
	}
	if err != nil && !errors.Is(err, context.DeadlineExceeded) {
		slog.Error("failed", "error", err)
	}
}

Documentation

Overview

Example
package main

import (
	"context"
	"errors"
	"fmt"
	"log/slog"
	"net"
	"time"

	"github.com/linkdata/socks5/client"
	"github.com/linkdata/socks5/server"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second/10)
	defer cancel()

	listener, err := net.Listen("tcp", ":0")
	if err == nil {
		defer listener.Close()
		srv := server.Server{
			Logger: slog.Default(),
			Authenticators: []server.Authenticator{
				server.NoAuthAuthenticator{},
				server.UserPassAuthenticator{
					Credentials: server.StaticCredentials{
						"joe": "123456",
					},
				},
			},
		}
		go srv.Serve(ctx, listener)
		var cli *client.Client
		if cli, err = client.New("socks5h://joe:123456@" + listener.Addr().String()); err == nil {
			var l net.Listener
			if l, err = cli.ListenContext(ctx, "tcp", ":0"); err == nil {
				defer l.Close()
				slog.Info("client BIND", "address", l.Addr().String())
				fmt.Println("client BIND success")
			}
		}
	}
	if err != nil && !errors.Is(err, context.DeadlineExceeded) {
		fmt.Printf("failed: %v\n", err)
	}
}
Output:

client BIND success

Index

Examples

Constants

View Source
const (
	AuthMethodNone      AuthMethod = 0   // no authentication required (RFC 1928, section 3)
	AuthUserPass        AuthMethod = 2   // user/password authentication (RFC 1928, section 3)
	AuthNoAcceptable    AuthMethod = 255 // no acceptable authentication methods (RFC 1928, section 3)
	AuthSuccess                    = 0   // client auth accepted
	AuthFailure                    = 1   // client auth denied
	AuthUserPassVersion            = 1   // auth version byte (RFC 1929).
)
View Source
const Socks5Version = 5

Variables

View Source
var (
	ErrInvalidIPv4Address     = errors.New("invalid IPv4 address for binding")
	ErrInvalidIPv6Address     = errors.New("invalid IPv6 address for binding")
	ErrUnsupportedAddressType = errors.New("unsupported address type")
	ErrInvalidDomainName      = errors.New("invalid domain name for binding")
)
View Source
var (
	ErrUnsupportedNetwork      = errors.New("unsupported network")
	ErrAuthMethodNotSupported  = errors.New("auth method not supported")
	ErrIllegalUsername         = errors.New("illegal username")
	ErrIllegalPassword         = errors.New("illegal password")
	ErrVersion                 = errors.New("invalid SOCKS version")
	ErrInvalidPortNumber       = errors.New("invalid port number")
	ErrBadSOCKSAuthVersion     = errors.New("bad SOCKS auth version")
	ErrAuthFailed              = errors.New("authentication failed")
	ErrInvalidUDPPacket        = errors.New("invalid udp packet")
	ErrFragmentedUDPPacket     = errors.New("fragmented udp packet")
	ErrNoAcceptableAuthMethods = errors.New("no acceptable auth methods")
	ErrUnsupportedScheme       = errors.New("unsupported scheme")
)
View Source
var (
	ErrReply                     = ReplyError{ReplyGeneralFailure} // for testing against with errors.Is()
	ErrReplySuccess              = ReplyError{ReplySuccess}
	ErrReplyGeneralFailure       = ReplyError{ReplyGeneralFailure}
	ErrReplyConnectionNotAllowed = ReplyError{ReplyConnectionNotAllowed}
	ErrReplyNetworkUnreachable   = ReplyError{ReplyNetworkUnreachable}
	ErrReplyHostUnreachable      = ReplyError{ReplyHostUnreachable}
	ErrReplyConnectionRefused    = ReplyError{ReplyConnectionRefused}
	ErrReplyTTLExpired           = ReplyError{ReplyTTLExpired}
	ErrReplyCommandNotSupported  = ReplyError{ReplyCommandNotSupported}
	ErrReplyAddrTypeNotSupported = ReplyError{ReplyAddrTypeNotSupported}
)
View Source
var ZeroAddr = Addr{Type: Ipv4, Addr: "0.0.0.0", Port: 0}

Functions

func AppendString

func AppendString(inbuf []byte, s string, lengtherror error) (outbuf []byte, err error)

func JoinErrs added in v0.0.4

func JoinErrs(errs ...error) (err error)

func MustEqual

func MustEqual[T comparable](a, b T, err error) error

MustEqual returns nil if a == b, otherwise it returns err.

func Note

func Note(err error, txt string) error

Note returns nil if err is nil, otherwise returns err prefixed with txt, a colon and a space.

func SplitHostPort

func SplitHostPort(hostport string) (host string, port uint16, err error)

Types

type Addr

type Addr struct {
	Addr string
	Port uint16
	Type AddrType
}

func AddrFromHostPort

func AddrFromHostPort(host string, port uint16) (addr Addr)

func AddrFromString

func AddrFromString(s string) (addr Addr, err error)

func ReadAddr

func ReadAddr(r io.Reader) (addr Addr, err error)

func (Addr) AppendBinary

func (s Addr) AppendBinary(inbuf []byte) (outbuf []byte, err error)

func (*Addr) IsAny

func (s *Addr) IsAny() bool

func (Addr) MarshalBinary

func (s Addr) MarshalBinary() ([]byte, error)

func (Addr) Network

func (s Addr) Network() string

func (*Addr) ReplaceAny

func (s *Addr) ReplaceAny(hostport string)

func (Addr) String

func (s Addr) String() string

type AddrType

type AddrType byte

AddrType are the bytes sent in SOCKS5 packets that represent particular address types.

const (
	Ipv4       AddrType = 1
	DomainName AddrType = 3
	Ipv6       AddrType = 4
)

The set of valid SOCKS5 address types as defined in RFC 1928.

type AuthMethod

type AuthMethod byte

type CommandType

type CommandType byte
const (
	CommandConnect   CommandType = 1
	CommandBind      CommandType = 2
	CommandAssociate CommandType = 3
)

type ContextDialer

type ContextDialer interface {
	DialContext(ctx context.Context, network, addr string) (net.Conn, error)
}
var (
	DefaultDialer ContextDialer = &net.Dialer{}
	LogPrefix                   = "socks5: "
)

type Dialer added in v0.0.14

type Dialer interface {
	Dial(network, addr string) (conn net.Conn, err error)
}

type HostLookuper

type HostLookuper interface {
	LookupHost(ctx context.Context, host string) (addrs []string, err error)
}

HostLookuper is the signature of net.DefaultResolver.LookupHost

type Logger

type Logger interface {
	Info(msg string, keyvaluepairs ...any)
	Error(msg string, keyvaluepairs ...any)
}

Logger is an abstraction of log/slog.

type ReplyCode

type ReplyCode byte

ReplyCode is the reply code in SOCKS5 packets sent from the server to a client.

const (
	ReplySuccess              ReplyCode = 0
	ReplyGeneralFailure       ReplyCode = 1
	ReplyConnectionNotAllowed ReplyCode = 2
	ReplyNetworkUnreachable   ReplyCode = 3
	ReplyHostUnreachable      ReplyCode = 4
	ReplyConnectionRefused    ReplyCode = 5
	ReplyTTLExpired           ReplyCode = 6
	ReplyCommandNotSupported  ReplyCode = 7
	ReplyAddrTypeNotSupported ReplyCode = 8
)

func (ReplyCode) ToError

func (code ReplyCode) ToError() error

type ReplyError added in v0.0.15

type ReplyError struct {
	ReplyCode
}

func (ReplyError) Error added in v0.0.15

func (re ReplyError) Error() string

func (ReplyError) Is added in v0.0.15

func (re ReplyError) Is(target error) (yes bool)

type UDPPacket

type UDPPacket struct {
	Addr Addr
	Body []byte
}

func ParseUDPPacket

func ParseUDPPacket(data []byte) (pkt *UDPPacket, err error)

func (*UDPPacket) AppendBinary

func (u *UDPPacket) AppendBinary(inbuf []byte) (outbuf []byte, err error)

func (*UDPPacket) MarshalBinary

func (u *UDPPacket) MarshalBinary() (pkt []byte, err error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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