socks5

package module
Version: v0.0.0-...-fa1f52a Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2021 License: MIT Imports: 14 Imported by: 52

README

socks5

中文

Go Report Card GoDoc Donate Slack

SOCKS Protocol Version 5 Library.

Full TCP/UDP and IPv4/IPv6 support. Goals: KISS, less is more, small API, code is like the original protocol.

❤️ A project by txthinking.com

Install

$ go get github.com/txthinking/socks5

Struct is like concept in protocol

  • Negotiation:
    • type NegotiationRequest struct
      • func NewNegotiationRequest(methods []byte), in client
      • func (r *NegotiationRequest) WriteTo(w io.Writer), client writes to server
      • func NewNegotiationRequestFrom(r io.Reader), server reads from client
    • type NegotiationReply struct
      • func NewNegotiationReply(method byte), in server
      • func (r *NegotiationReply) WriteTo(w io.Writer), server writes to client
      • func NewNegotiationReplyFrom(r io.Reader), client reads from server
  • User and password negotiation:
    • type UserPassNegotiationRequest struct
      • func NewUserPassNegotiationRequest(username []byte, password []byte), in client
      • func (r *UserPassNegotiationRequest) WriteTo(w io.Writer), client writes to server
      • func NewUserPassNegotiationRequestFrom(r io.Reader), server reads from client
    • type UserPassNegotiationReply struct
      • func NewUserPassNegotiationReply(status byte), in server
      • func (r *UserPassNegotiationReply) WriteTo(w io.Writer), server writes to client
      • func NewUserPassNegotiationReplyFrom(r io.Reader), client reads from server
  • Request:
    • type Request struct
      • func NewRequest(cmd byte, atyp byte, dstaddr []byte, dstport []byte), in client
      • func (r *Request) WriteTo(w io.Writer), client writes to server
      • func NewRequestFrom(r io.Reader), server reads from client
      • After server gets the client's *Request, processes...
  • Reply:
    • type Reply struct
      • func NewReply(rep byte, atyp byte, bndaddr []byte, bndport []byte), in server
      • func (r *Reply) WriteTo(w io.Writer), server writes to client
      • func NewReplyFrom(r io.Reader), client reads from server
  • Datagram:
    • type Datagram struct
      • func NewDatagram(atyp byte, dstaddr []byte, dstport []byte, data []byte)
      • func NewDatagramFromBytes(bb []byte)
      • func (d *Datagram) Bytes()

Advanced API

Server. You can process client's request by yourself after reading Request from client. Also, here is a advanced interfaces.

  • type Server struct
  • type Handler interface
    • TCPHandle(*Server, *net.TCPConn, *Request) error
    • UDPHandle(*Server, *net.UDPAddr, *Datagram) error

Example:

s, _ := NewClassicServer(addr, ip, username, password, tcpTimeout, udpTimeout)
s.ListenAndServe(Handler)
  • If you want a standard socks5 server, pass in nil
  • If you want to handle data by yourself, pass in a custom Handler

Client. Here is a client support both TCP and UDP and return net.Conn.

  • type Client struct

Example:

c, _ := socks5.NewClient(server, username, password, tcpTimeout, udpTimeout)
conn, _ := c.Dial(network, addr)

Users:

License

Licensed under The MIT License

Documentation

Index

Examples

Constants

View Source
const (
	// Ver is socks protocol version
	Ver byte = 0x05

	// MethodNone is none method
	MethodNone byte = 0x00
	// MethodGSSAPI is gssapi method
	MethodGSSAPI byte = 0x01 // MUST support // todo
	// MethodUsernamePassword is username/assword auth method
	MethodUsernamePassword byte = 0x02 // SHOULD support
	// MethodUnsupportAll means unsupport all given methods
	MethodUnsupportAll byte = 0xFF

	// UserPassVer is username/password auth protocol version
	UserPassVer byte = 0x01
	// UserPassStatusSuccess is success status of username/password auth
	UserPassStatusSuccess byte = 0x00
	// UserPassStatusFailure is failure status of username/password auth
	UserPassStatusFailure byte = 0x01 // just other than 0x00

	// CmdConnect is connect command
	CmdConnect byte = 0x01
	// CmdBind is bind command
	CmdBind byte = 0x02
	// CmdUDP is UDP command
	CmdUDP byte = 0x03

	// ATYPIPv4 is ipv4 address type
	ATYPIPv4 byte = 0x01 // 4 octets
	// ATYPDomain is domain address type
	ATYPDomain byte = 0x03 // The first octet of the address field contains the number of octets of name that follow, there is no terminating NUL octet.
	// ATYPIPv6 is ipv6 address type
	ATYPIPv6 byte = 0x04 // 16 octets

	// RepSuccess means that success for repling
	RepSuccess byte = 0x00
	// RepServerFailure means the server failure
	RepServerFailure byte = 0x01
	// RepNotAllowed means the request not allowed
	RepNotAllowed byte = 0x02
	// RepNetworkUnreachable means the network unreachable
	RepNetworkUnreachable byte = 0x03
	// RepHostUnreachable means the host unreachable
	RepHostUnreachable byte = 0x04
	// RepConnectionRefused means the connection refused
	RepConnectionRefused byte = 0x05
	// RepTTLExpired means the TTL expired
	RepTTLExpired byte = 0x06
	// RepCommandNotSupported means the request command not supported
	RepCommandNotSupported byte = 0x07
	// RepAddressNotSupported means the request address not supported
	RepAddressNotSupported byte = 0x08
)

Variables

View Source
var (
	// ErrUnsupportCmd is the error when got unsupport command
	ErrUnsupportCmd = errors.New("Unsupport Command")
	// ErrUserPassAuth is the error when got invalid username or password
	ErrUserPassAuth = errors.New("Invalid Username or Password for Auth")
)
View Source
var (
	// ErrVersion is version error
	ErrVersion = errors.New("Invalid Version")
	// ErrUserPassVersion is username/password auth version error
	ErrUserPassVersion = errors.New("Invalid Version of Username Password Auth")
	// ErrBadRequest is bad request error
	ErrBadRequest = errors.New("Bad Request")
)
View Source
var Debug bool

Debug enable debug log

View Source
var (
	// ErrBadReply is the error when read reply
	ErrBadReply = errors.New("Bad Reply")
)

Functions

func ParseAddress

func ParseAddress(address string) (a byte, addr []byte, port []byte, err error)

ParseAddress format address x.x.x.x:xx to raw address. addr contains domain length

func ParseBytesAddress

func ParseBytesAddress(b []byte) (a byte, addr []byte, port []byte, err error)

bytes to address addr contains domain length

func ToAddress

func ToAddress(a byte, addr []byte, port []byte) string

ToAddress format raw address to x.x.x.x:xx addr contains domain length

Types

type Client

type Client struct {
	Server   string
	UserName string
	Password string
	// On cmd UDP, let server control the tcp and udp connection relationship
	TCPConn       *net.TCPConn
	UDPConn       *net.UDPConn
	RemoteAddress net.Addr
	TCPTimeout    int
	UDPTimeout    int
	// HijackServerUDPAddr can let client control which server UDP address to connect to after sending request,
	// In most cases, you should ignore this, according to the standard server will return the address in reply,
	// More: https://github.com/txthinking/socks5/pull/8.
	HijackServerUDPAddr func(*Reply) (*net.UDPAddr, error)
}

Client is socks5 client wrapper

Example (Tcp)
package main

import (
	"io/ioutil"
	"log"
	"net"
	"net/http"

	"github.com/txthinking/socks5"
)

func main() {
	c, err := socks5.NewClient("127.0.0.1:1080", "", "", 0, 60)
	if err != nil {
		panic(err)
	}
	client := &http.Client{
		Transport: &http.Transport{
			Dial: func(network, addr string) (net.Conn, error) {
				return c.Dial(network, addr)
			},
		},
	}
	res, err := client.Get("https://ifconfig.co")
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	log.Println(string(b))
}
Output:

Example (Udp)
package main

import (
	"encoding/hex"
	"log"
	"net"

	"github.com/txthinking/socks5"
)

func main() {
	c, err := socks5.NewClient("127.0.0.1:1080", "", "", 0, 60)
	if err != nil {
		panic(err)
	}
	conn, err := c.Dial("udp", "8.8.8.8:53")
	if err != nil {
		panic(err)
	}
	b, err := hex.DecodeString("0001010000010000000000000a74787468696e6b696e6703636f6d0000010001")
	if err != nil {
		panic(err)
	}
	if _, err := conn.Write(b); err != nil {
		panic(err)
	}
	b = make([]byte, 2048)
	n, err := conn.Read(b)
	if err != nil {
		panic(err)
	}
	b = b[:n]
	b = b[len(b)-4:]
	log.Println(net.IPv4(b[0], b[1], b[2], b[3]))
}
Output:

func NewClient

func NewClient(addr, username, password string, tcpTimeout, udpTimeout int) (*Client, error)

This is just create a client, you need to use Dial to create conn

func (*Client) Close

func (c *Client) Close() error

func (*Client) Dial

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

func (*Client) DialWithLocalAddr

func (c *Client) DialWithLocalAddr(network, src, dst string, remoteAddr net.Addr) (net.Conn, error)

func (*Client) LocalAddr

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

func (*Client) Negotiate

func (c *Client) Negotiate(laddr *net.TCPAddr) error

func (*Client) Read

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

func (*Client) RemoteAddr

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

func (*Client) Request

func (c *Client) Request(r *Request) (*Reply, error)

func (*Client) SetDeadline

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

func (*Client) SetReadDeadline

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

func (*Client) SetWriteDeadline

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

func (*Client) Write

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

type Datagram

type Datagram struct {
	Rsv     []byte // 0x00 0x00
	Frag    byte
	Atyp    byte
	DstAddr []byte
	DstPort []byte // 2 bytes
	Data    []byte
}

Datagram is the UDP packet

func NewDatagram

func NewDatagram(atyp byte, dstaddr []byte, dstport []byte, data []byte) *Datagram

NewDatagram return datagram packet can be writed into client, dstaddr should not have domain length

func NewDatagramFromBytes

func NewDatagramFromBytes(bb []byte) (*Datagram, error)

func (*Datagram) Address

func (d *Datagram) Address() string

Address return datagram address like ip:xx

func (*Datagram) Bytes

func (d *Datagram) Bytes() []byte

Bytes return []byte

type DefaultHandle

type DefaultHandle struct {
}

DefaultHandle implements Handler interface

func (*DefaultHandle) TCPHandle

func (h *DefaultHandle) TCPHandle(s *Server, c *net.TCPConn, r *Request) error

TCPHandle auto handle request. You may prefer to do yourself.

func (*DefaultHandle) UDPHandle

func (h *DefaultHandle) UDPHandle(s *Server, addr *net.UDPAddr, d *Datagram) error

UDPHandle auto handle packet. You may prefer to do yourself.

type Handler

type Handler interface {
	// Request has not been replied yet
	TCPHandle(*Server, *net.TCPConn, *Request) error
	UDPHandle(*Server, *net.UDPAddr, *Datagram) error
}

Handler handle tcp, udp request

type NegotiationReply

type NegotiationReply struct {
	Ver    byte
	Method byte
}

NegotiationReply is the negotiation reply packet

func NewNegotiationReply

func NewNegotiationReply(method byte) *NegotiationReply

NewNegotiationReply return negotiation reply packet can be writed into client

func NewNegotiationReplyFrom

func NewNegotiationReplyFrom(r io.Reader) (*NegotiationReply, error)

NewNegotiationReplyFrom read negotiation reply packet from server

func (*NegotiationReply) WriteTo

func (r *NegotiationReply) WriteTo(w io.Writer) (int64, error)

WriteTo write negotiation reply packet into client

type NegotiationRequest

type NegotiationRequest struct {
	Ver      byte
	NMethods byte
	Methods  []byte // 1-255 bytes
}

NegotiationRequest is the negotiation reqeust packet

func NewNegotiationRequest

func NewNegotiationRequest(methods []byte) *NegotiationRequest

NewNegotiationRequest return negotiation request packet can be writed into server

func NewNegotiationRequestFrom

func NewNegotiationRequestFrom(r io.Reader) (*NegotiationRequest, error)

NewNegotiationRequestFrom read negotiation requst packet from client

func (*NegotiationRequest) WriteTo

func (r *NegotiationRequest) WriteTo(w io.Writer) (int64, error)

WriteTo write negotiation request packet into server

type Reply

type Reply struct {
	Ver  byte
	Rep  byte
	Rsv  byte // 0x00
	Atyp byte
	// CONNECT socks server's address which used to connect to dst addr
	// BIND ...
	// UDP socks server's address which used to connect to dst addr
	BndAddr []byte
	// CONNECT socks server's port which used to connect to dst addr
	// BIND ...
	// UDP socks server's port which used to connect to dst addr
	BndPort []byte // 2 bytes
}

Reply is the reply packet

func NewReply

func NewReply(rep byte, atyp byte, bndaddr []byte, bndport []byte) *Reply

NewReply return reply packet can be writed into client, bndaddr should not have domain length

func NewReplyFrom

func NewReplyFrom(r io.Reader) (*Reply, error)

NewReplyFrom read reply packet from server

func (*Reply) Address

func (r *Reply) Address() string

Address return request address like ip:xx

func (*Reply) WriteTo

func (r *Reply) WriteTo(w io.Writer) (int64, error)

WriteTo write reply packet into client

type Request

type Request struct {
	Ver     byte
	Cmd     byte
	Rsv     byte // 0x00
	Atyp    byte
	DstAddr []byte
	DstPort []byte // 2 bytes
}

Request is the request packet

func NewRequest

func NewRequest(cmd byte, atyp byte, dstaddr []byte, dstport []byte) *Request

NewRequest return request packet can be writed into server, dstaddr should not have domain length

func NewRequestFrom

func NewRequestFrom(r io.Reader) (*Request, error)

NewRequestFrom read requst packet from client

func (*Request) Address

func (r *Request) Address() string

Address return request address like ip:xx

func (*Request) Connect

func (r *Request) Connect(w io.Writer) (*net.TCPConn, error)

Connect remote conn which u want to connect with your dialer Error or OK both replied.

func (*Request) UDP

func (r *Request) UDP(c *net.TCPConn, serverAddr *net.UDPAddr) (*net.UDPAddr, error)

UDP remote conn which u want to connect with your dialer. Error or OK both replied. Addr can be used to associate TCP connection with the coming UDP connection.

func (*Request) WriteTo

func (r *Request) WriteTo(w io.Writer) (int64, error)

WriteTo write request packet into server

type Server

type Server struct {
	UserName          string
	Password          string
	Method            byte
	SupportedCommands []byte
	TCPAddr           *net.TCPAddr
	UDPAddr           *net.UDPAddr
	ServerAddr        *net.UDPAddr
	TCPListen         *net.TCPListener
	UDPConn           *net.UDPConn
	UDPExchanges      *cache.Cache
	TCPTimeout        int
	UDPTimeout        int
	Handle            Handler
	AssociatedUDP     *cache.Cache
	UDPSrc            *cache.Cache
	RunnerGroup       *runnergroup.RunnerGroup
	// RFC: [UDP ASSOCIATE] The server MAY use this information to limit access to the association. Default false, no limit.
	LimitUDP bool
}

Server is socks5 server wrapper

Example
package main

import (
	"github.com/txthinking/socks5"
)

func main() {
	s, err := socks5.NewClassicServer("127.0.0.1:1080", "127.0.0.1", "", "", 0, 60)
	if err != nil {
		panic(err)
	}
	// You can pass in custom Handler
	s.ListenAndServe(nil)
	// #Output:
}
Output:

func NewClassicServer

func NewClassicServer(addr, ip, username, password string, tcpTimeout, udpTimeout int) (*Server, error)

NewClassicServer return a server which allow none method

func (*Server) GetRequest

func (s *Server) GetRequest(rw io.ReadWriter) (*Request, error)

GetRequest get request packet from client, and check command according to SupportedCommands Error replied.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(h Handler) error

Run server

func (*Server) Negotiate

func (s *Server) Negotiate(rw io.ReadWriter) error

Negotiate handle negotiate packet. This method do not handle gssapi(0x01) method now. Error or OK both replied.

func (*Server) RunTCPServer

func (s *Server) RunTCPServer() error

RunTCPServer starts tcp server

func (*Server) RunUDPServer

func (s *Server) RunUDPServer() error

RunUDPServer starts udp server

func (*Server) Shutdown

func (s *Server) Shutdown() error

Stop server

type UDPExchange

type UDPExchange struct {
	ClientAddr *net.UDPAddr
	RemoteConn *net.UDPConn
}

UDPExchange used to store client address and remote connection

type UserPassNegotiationReply

type UserPassNegotiationReply struct {
	Ver    byte
	Status byte
}

UserPassNegotiationReply is the negotiation username/password reply packet

func NewUserPassNegotiationReply

func NewUserPassNegotiationReply(status byte) *UserPassNegotiationReply

NewUserPassNegotiationReply return negotiation username password reply packet can be writed into client

func NewUserPassNegotiationReplyFrom

func NewUserPassNegotiationReplyFrom(r io.Reader) (*UserPassNegotiationReply, error)

NewUserPassNegotiationReplyFrom read user password negotiation reply packet from server

func (*UserPassNegotiationReply) WriteTo

func (r *UserPassNegotiationReply) WriteTo(w io.Writer) (int64, error)

WriteTo write negotiation username password reply packet into client

type UserPassNegotiationRequest

type UserPassNegotiationRequest struct {
	Ver    byte
	Ulen   byte
	Uname  []byte // 1-255 bytes
	Plen   byte
	Passwd []byte // 1-255 bytes
}

UserPassNegotiationRequest is the negotiation username/password reqeust packet

func NewUserPassNegotiationRequest

func NewUserPassNegotiationRequest(username []byte, password []byte) *UserPassNegotiationRequest

NewUserPassNegotiationRequest return user password negotiation request packet can be writed into server

func NewUserPassNegotiationRequestFrom

func NewUserPassNegotiationRequestFrom(r io.Reader) (*UserPassNegotiationRequest, error)

NewUserPassNegotiationRequestFrom read user password negotiation request packet from client

func (*UserPassNegotiationRequest) WriteTo

func (r *UserPassNegotiationRequest) WriteTo(w io.Writer) (int64, error)

WriteTo write user password negotiation request packet into server

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL