160 lines
3.8 KiB
Go
160 lines
3.8 KiB
Go
package socks5
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
Method_NO_AUTH = uint8(0x00)
|
|
Method_GSSAPI = uint8(0x01)
|
|
Method_USER_PASS = uint8(0x02)
|
|
Method_IANA = uint8(0x7F)
|
|
Method_RESVERVE = uint8(0x80)
|
|
Method_NONE_ACCEPTABLE = uint8(0xFF)
|
|
VERSION_V5 = uint8(0x05)
|
|
CMD_CONNECT = uint8(0x01)
|
|
CMD_BIND = uint8(0x02)
|
|
CMD_ASSOCIATE = uint8(0x03)
|
|
ATYP_IPV4 = uint8(0x01)
|
|
ATYP_DOMAIN = uint8(0x03)
|
|
ATYP_IPV6 = uint8(0x04)
|
|
REP_SUCCESS = uint8(0x00)
|
|
REP_REQ_FAIL = uint8(0x01)
|
|
REP_RULE_FORBIDDEN = uint8(0x02)
|
|
REP_NETWOR_UNREACHABLE = uint8(0x03)
|
|
REP_HOST_UNREACHABLE = uint8(0x04)
|
|
REP_CONNECTION_REFUSED = uint8(0x05)
|
|
REP_TTL_TIMEOUT = uint8(0x06)
|
|
REP_CMD_UNSUPPORTED = uint8(0x07)
|
|
REP_ATYP_UNSUPPORTED = uint8(0x08)
|
|
REP_UNKNOWN = uint8(0x09)
|
|
RSV = uint8(0x00)
|
|
)
|
|
|
|
var (
|
|
ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
|
|
ZERO_PORT = []byte{0x00, 0x00}
|
|
)
|
|
var Socks5Errors = []string{
|
|
"",
|
|
"general failure",
|
|
"connection forbidden",
|
|
"network unreachable",
|
|
"host unreachable",
|
|
"connection refused",
|
|
"TTL expired",
|
|
"command not supported",
|
|
"address type not supported",
|
|
}
|
|
|
|
// Auth contains authentication parameters that specific Dialers may require.
|
|
type UsernamePassword struct {
|
|
Username, Password string
|
|
}
|
|
|
|
type PacketUDP struct {
|
|
rsv uint16
|
|
frag uint8
|
|
atype uint8
|
|
dstHost string
|
|
dstPort string
|
|
data []byte
|
|
}
|
|
|
|
func NewPacketUDP() (p PacketUDP) {
|
|
return PacketUDP{}
|
|
}
|
|
func (p *PacketUDP) Build(destAddr string, data []byte) (err error) {
|
|
host, port, err := net.SplitHostPort(destAddr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
p.rsv = 0
|
|
p.frag = 0
|
|
p.dstHost = host
|
|
p.dstPort = port
|
|
p.atype = ATYP_IPV4
|
|
if ip := net.ParseIP(host); ip != nil {
|
|
if ip4 := ip.To4(); ip4 != nil {
|
|
p.atype = ATYP_IPV4
|
|
ip = ip4
|
|
} else {
|
|
p.atype = ATYP_IPV6
|
|
}
|
|
} else {
|
|
if len(host) > 255 {
|
|
err = errors.New("proxy: destination host name too long: " + host)
|
|
return
|
|
}
|
|
p.atype = ATYP_DOMAIN
|
|
}
|
|
p.data = data
|
|
|
|
return
|
|
}
|
|
func (p *PacketUDP) Parse(b []byte) (err error) {
|
|
p.frag = uint8(b[2])
|
|
if p.frag != 0 {
|
|
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
|
|
return
|
|
}
|
|
portIndex := 0
|
|
p.atype = b[3]
|
|
switch p.atype {
|
|
case ATYP_IPV4: //IP V4
|
|
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
|
|
portIndex = 8
|
|
case ATYP_DOMAIN: //域名
|
|
domainLen := uint8(b[4])
|
|
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
|
|
portIndex = int(5 + domainLen)
|
|
case ATYP_IPV6: //IP V6
|
|
p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
|
|
portIndex = 20
|
|
}
|
|
p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
|
|
p.data = b[portIndex+2:]
|
|
return
|
|
}
|
|
func (p *PacketUDP) Header() []byte {
|
|
header := new(bytes.Buffer)
|
|
header.Write([]byte{0x00, 0x00, p.frag, p.atype})
|
|
if p.atype == ATYP_IPV4 {
|
|
ip := net.ParseIP(p.dstHost)
|
|
header.Write(ip.To4())
|
|
} else if p.atype == ATYP_IPV6 {
|
|
ip := net.ParseIP(p.dstHost)
|
|
header.Write(ip.To16())
|
|
} else if p.atype == ATYP_DOMAIN {
|
|
hBytes := []byte(p.dstHost)
|
|
header.WriteByte(byte(len(hBytes)))
|
|
header.Write(hBytes)
|
|
}
|
|
port, _ := strconv.ParseUint(p.dstPort, 10, 64)
|
|
portBytes := new(bytes.Buffer)
|
|
binary.Write(portBytes, binary.BigEndian, port)
|
|
header.Write(portBytes.Bytes()[portBytes.Len()-2:])
|
|
return header.Bytes()
|
|
}
|
|
func (p *PacketUDP) Bytes() []byte {
|
|
packBytes := new(bytes.Buffer)
|
|
packBytes.Write(p.Header())
|
|
packBytes.Write(p.data)
|
|
return packBytes.Bytes()
|
|
}
|
|
func (p *PacketUDP) Host() string {
|
|
return p.dstHost
|
|
}
|
|
|
|
func (p *PacketUDP) Port() string {
|
|
return p.dstPort
|
|
}
|
|
func (p *PacketUDP) Data() []byte {
|
|
return p.data
|
|
}
|