Jason
5 years ago
6 changed files with 376 additions and 288 deletions
@ -1,164 +0,0 @@ |
|||
// Code in this file are grabbed from https://github.com/nadoo/glider, which
|
|||
// is also referencing another repo: https://github.com/shadowsocks/go-shadowsocks2
|
|||
|
|||
package proxy |
|||
|
|||
import ( |
|||
"errors" |
|||
"io" |
|||
"net" |
|||
"strconv" |
|||
) |
|||
|
|||
const socks5Version = 5 |
|||
|
|||
// SOCKS request commands as defined in RFC 1928 section 4.
|
|||
const ( |
|||
// socks5Connect = 1
|
|||
// socks5Bind = 2
|
|||
socks5UDPAssociate = 3 |
|||
) |
|||
|
|||
// SOCKS address types as defined in RFC 1928 section 5.
|
|||
const ( |
|||
socks5IP4 = 1 |
|||
socks5Domain = 3 |
|||
socks5IP6 = 4 |
|||
) |
|||
|
|||
var socks5Errors = []error{ |
|||
errors.New(""), |
|||
errors.New("general failure"), |
|||
errors.New("connection forbidden"), |
|||
errors.New("network unreachable"), |
|||
errors.New("host unreachable"), |
|||
errors.New("connection refused"), |
|||
errors.New("TTL expired"), |
|||
errors.New("command not supported"), |
|||
errors.New("address type not supported"), |
|||
errors.New("socks5UDPAssociate"), |
|||
} |
|||
|
|||
// MaxAddrLen is the maximum size of SOCKS address in bytes.
|
|||
const MaxAddrLen = 1 + 1 + 255 + 2 |
|||
|
|||
// ATYP return the address type
|
|||
func ATYP(b byte) int { |
|||
return int(b &^ 0x8) |
|||
} |
|||
|
|||
// Addr represents a SOCKS address as defined in RFC 1928 section 5.
|
|||
type Addr []byte |
|||
|
|||
// String serializes SOCKS address a to string form.
|
|||
func (a Addr) String() string { |
|||
var host, port string |
|||
|
|||
switch ATYP(a[0]) { // address type
|
|||
case socks5Domain: |
|||
host = string(a[2 : 2+int(a[1])]) |
|||
port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1])) |
|||
case socks5IP4: |
|||
host = net.IP(a[1 : 1+net.IPv4len]).String() |
|||
port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1])) |
|||
case socks5IP6: |
|||
host = net.IP(a[1 : 1+net.IPv6len]).String() |
|||
port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1])) |
|||
} |
|||
|
|||
return net.JoinHostPort(host, port) |
|||
} |
|||
|
|||
// ParseAddr parses the address in string s. Returns nil if failed.
|
|||
func ParseAddr(s string) Addr { |
|||
var addr Addr |
|||
host, port, err := net.SplitHostPort(s) |
|||
if err != nil { |
|||
return nil |
|||
} |
|||
if ip := net.ParseIP(host); ip != nil { |
|||
if ip4 := ip.To4(); ip4 != nil { |
|||
addr = make([]byte, 1+net.IPv4len+2) |
|||
addr[0] = socks5IP4 |
|||
copy(addr[1:], ip4) |
|||
} else { |
|||
addr = make([]byte, 1+net.IPv6len+2) |
|||
addr[0] = socks5IP6 |
|||
copy(addr[1:], ip) |
|||
} |
|||
} else { |
|||
if len(host) > 255 { |
|||
return nil |
|||
} |
|||
addr = make([]byte, 1+1+len(host)+2) |
|||
addr[0] = socks5Domain |
|||
addr[1] = byte(len(host)) |
|||
copy(addr[2:], host) |
|||
} |
|||
|
|||
portUint, err := strconv.ParseUint(port, 10, 16) |
|||
if err != nil { |
|||
return nil |
|||
} |
|||
|
|||
addr[len(addr)-2], addr[len(addr)-1] = byte(portUint>>8), byte(portUint) |
|||
|
|||
return addr |
|||
} |
|||
|
|||
func readAddr(r io.Reader, b []byte) (Addr, error) { |
|||
if len(b) < MaxAddrLen { |
|||
return nil, io.ErrShortBuffer |
|||
} |
|||
_, err := io.ReadFull(r, b[:1]) // read 1st byte for address type
|
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
switch ATYP(b[0]) { |
|||
case socks5Domain: |
|||
_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
|
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
_, err = io.ReadFull(r, b[2:2+int(b[1])+2]) |
|||
return b[:1+1+int(b[1])+2], err |
|||
case socks5IP4: |
|||
_, err = io.ReadFull(r, b[1:1+net.IPv4len+2]) |
|||
return b[:1+net.IPv4len+2], err |
|||
case socks5IP6: |
|||
_, err = io.ReadFull(r, b[1:1+net.IPv6len+2]) |
|||
return b[:1+net.IPv6len+2], err |
|||
} |
|||
|
|||
return nil, socks5Errors[8] |
|||
} |
|||
|
|||
// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed.
|
|||
func SplitAddr(b []byte) Addr { |
|||
addrLen := 1 |
|||
if len(b) < addrLen { |
|||
return nil |
|||
} |
|||
|
|||
switch ATYP(b[0]) { |
|||
case socks5Domain: |
|||
if len(b) < 2 { |
|||
return nil |
|||
} |
|||
addrLen = 1 + 1 + int(b[1]) + 2 |
|||
case socks5IP4: |
|||
addrLen = 1 + net.IPv4len + 2 |
|||
case socks5IP6: |
|||
addrLen = 1 + net.IPv6len + 2 |
|||
default: |
|||
return nil |
|||
|
|||
} |
|||
|
|||
if len(b) < addrLen { |
|||
return nil |
|||
} |
|||
|
|||
return b[:addrLen] |
|||
} |
@ -0,0 +1,101 @@ |
|||
package socks |
|||
|
|||
import ( |
|||
"fmt" |
|||
"io" |
|||
"io/ioutil" |
|||
"net" |
|||
"time" |
|||
) |
|||
|
|||
var tcpTimeout = 30 * time.Second |
|||
|
|||
func Dial(proxy, target string) (net.Conn, error) { |
|||
c, err := net.DialTimeout("tcp", proxy, tcpTimeout) |
|||
if err != nil { |
|||
return nil, fmt.Errorf("%s connect error", proxy) |
|||
} |
|||
|
|||
if _, err := ClientHandshake(c, ParseAddr(target), CmdConnect); err != nil { |
|||
return nil, err |
|||
} |
|||
return c, nil |
|||
} |
|||
|
|||
func DialUDP(proxy, target string) (_ net.PacketConn, _ net.Addr, err error) { |
|||
c, err := net.DialTimeout("tcp", proxy, tcpTimeout) |
|||
if err != nil { |
|||
err = fmt.Errorf("%s connect error", proxy) |
|||
return |
|||
} |
|||
|
|||
// tcp set keepalive
|
|||
c.(*net.TCPConn).SetKeepAlive(true) |
|||
c.(*net.TCPConn).SetKeepAlivePeriod(tcpTimeout) |
|||
|
|||
defer func() { |
|||
if err != nil { |
|||
c.Close() |
|||
} |
|||
}() |
|||
|
|||
bindAddr, err := ClientHandshake(c, ParseAddr(target), CmdUDPAssociate) |
|||
if err != nil { |
|||
err = fmt.Errorf("%v client hanshake error", err) |
|||
return |
|||
} |
|||
|
|||
addr, err := net.ResolveUDPAddr("udp", bindAddr.String()) |
|||
if err != nil { |
|||
return |
|||
} |
|||
|
|||
targetAddr, err := net.ResolveUDPAddr("udp", target) |
|||
if err != nil { |
|||
return |
|||
} |
|||
|
|||
pc, err := net.ListenPacket("udp", "") |
|||
if err != nil { |
|||
return |
|||
} |
|||
|
|||
go func() { |
|||
io.Copy(ioutil.Discard, c) |
|||
c.Close() |
|||
// A UDP association terminates when the TCP connection that the UDP
|
|||
// ASSOCIATE request arrived on terminates. RFC1928
|
|||
pc.Close() |
|||
}() |
|||
|
|||
return &socksUDPConn{PacketConn: pc, tcpConn: c, targetAddr: targetAddr}, addr, nil |
|||
} |
|||
|
|||
type socksUDPConn struct { |
|||
net.PacketConn |
|||
tcpConn net.Conn |
|||
targetAddr net.Addr |
|||
} |
|||
|
|||
func (c *socksUDPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { |
|||
packet, err := EncodeUDPPacket(c.targetAddr.String(), b) |
|||
if err != nil { |
|||
return |
|||
} |
|||
return c.PacketConn.WriteTo(packet, addr) |
|||
} |
|||
|
|||
func (c *socksUDPConn) ReadFrom(b []byte) (int, net.Addr, error) { |
|||
n, a, e := c.PacketConn.ReadFrom(b) |
|||
addr, payload, err := DecodeUDPPacket(b) |
|||
if err != nil { |
|||
return 0, nil, err |
|||
} |
|||
copy(b, payload) |
|||
return n - len(addr) - 3, a, e |
|||
} |
|||
|
|||
func (c *socksUDPConn) Close() error { |
|||
c.tcpConn.Close() |
|||
return c.PacketConn.Close() |
|||
} |
@ -0,0 +1,246 @@ |
|||
package socks |
|||
|
|||
import ( |
|||
"bytes" |
|||
"errors" |
|||
"io" |
|||
"net" |
|||
"strconv" |
|||
) |
|||
|
|||
const Version = 5 |
|||
|
|||
// Error represents a SOCKS error
|
|||
type Error byte |
|||
|
|||
func (err Error) Error() string { |
|||
return "SOCKS5 error: " + strconv.Itoa(int(err)) |
|||
} |
|||
|
|||
// Command is request commands as defined in RFC 1928 section 4.
|
|||
type Command = uint8 |
|||
|
|||
// SOCKS request commands as defined in RFC 1928 section 4.
|
|||
const ( |
|||
CmdConnect Command = 1 |
|||
CmdBind Command = 2 |
|||
CmdUDPAssociate Command = 3 |
|||
) |
|||
|
|||
// SOCKS address types as defined in RFC 1928 section 5.
|
|||
const ( |
|||
AtypIPv4 = 1 |
|||
AtypDomainName = 3 |
|||
AtypIPv6 = 4 |
|||
) |
|||
|
|||
// MaxAddrLen is the maximum size of SOCKS address in bytes.
|
|||
const MaxAddrLen = 1 + 1 + 255 + 2 |
|||
|
|||
// MaxAuthLen is the maximum size of user/password field in SOCKS5 Auth
|
|||
const MaxAuthLen = 255 |
|||
|
|||
// Addr represents a SOCKS address as defined in RFC 1928 section 5.
|
|||
type Addr []byte |
|||
|
|||
func (a Addr) String() string { |
|||
var host, port string |
|||
|
|||
switch a[0] { |
|||
case AtypDomainName: |
|||
host = string(a[2 : 2+int(a[1])]) |
|||
port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1])) |
|||
case AtypIPv4: |
|||
host = net.IP(a[1 : 1+net.IPv4len]).String() |
|||
port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1])) |
|||
case AtypIPv6: |
|||
host = net.IP(a[1 : 1+net.IPv6len]).String() |
|||
port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1])) |
|||
} |
|||
|
|||
return net.JoinHostPort(host, port) |
|||
} |
|||
|
|||
// SOCKS errors as defined in RFC 1928 section 6.
|
|||
const ( |
|||
ErrGeneralFailure = Error(1) |
|||
ErrConnectionNotAllowed = Error(2) |
|||
ErrNetworkUnreachable = Error(3) |
|||
ErrHostUnreachable = Error(4) |
|||
ErrConnectionRefused = Error(5) |
|||
ErrTTLExpired = Error(6) |
|||
ErrCommandNotSupported = Error(7) |
|||
ErrAddressNotSupported = Error(8) |
|||
) |
|||
|
|||
// Auth errors used to return a specific "Auth failed" error
|
|||
var ErrAuth = errors.New("auth failed") |
|||
|
|||
// ClientHandshake fast-tracks SOCKS initialization to get target address to connect on client side.
|
|||
func ClientHandshake(rw io.ReadWriter, addr Addr, command Command) (Addr, error) { |
|||
buf := make([]byte, MaxAddrLen) |
|||
var err error |
|||
|
|||
// VER, NMETHODS, METHODS
|
|||
_, err = rw.Write([]byte{Version, 1, 0}) |
|||
|
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// VER, METHOD
|
|||
if _, err := io.ReadFull(rw, buf[:2]); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if buf[0] != 5 { |
|||
return nil, errors.New("SOCKS version error") |
|||
} |
|||
|
|||
if buf[1] != 0 { |
|||
return nil, errors.New("SOCKS need auth") |
|||
} |
|||
|
|||
// VER, CMD, RSV, ADDR
|
|||
if _, err := rw.Write(bytes.Join([][]byte{{5, command, 0}, addr}, []byte{})); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// VER, REP, RSV
|
|||
if _, err := io.ReadFull(rw, buf[:3]); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return readAddr(rw, buf) |
|||
} |
|||
|
|||
func readAddr(r io.Reader, b []byte) (Addr, error) { |
|||
if len(b) < MaxAddrLen { |
|||
return nil, io.ErrShortBuffer |
|||
} |
|||
_, err := io.ReadFull(r, b[:1]) // read 1st byte for address type
|
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
switch b[0] { |
|||
case AtypDomainName: |
|||
_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
|
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
domainLength := uint16(b[1]) |
|||
_, err = io.ReadFull(r, b[2:2+domainLength+2]) |
|||
return b[:1+1+domainLength+2], err |
|||
case AtypIPv4: |
|||
_, err = io.ReadFull(r, b[1:1+net.IPv4len+2]) |
|||
return b[:1+net.IPv4len+2], err |
|||
case AtypIPv6: |
|||
_, err = io.ReadFull(r, b[1:1+net.IPv6len+2]) |
|||
return b[:1+net.IPv6len+2], err |
|||
} |
|||
|
|||
return nil, ErrAddressNotSupported |
|||
} |
|||
|
|||
// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed.
|
|||
func SplitAddr(b []byte) Addr { |
|||
addrLen := 1 |
|||
if len(b) < addrLen { |
|||
return nil |
|||
} |
|||
|
|||
switch b[0] { |
|||
case AtypDomainName: |
|||
if len(b) < 2 { |
|||
return nil |
|||
} |
|||
addrLen = 1 + 1 + int(b[1]) + 2 |
|||
case AtypIPv4: |
|||
addrLen = 1 + net.IPv4len + 2 |
|||
case AtypIPv6: |
|||
addrLen = 1 + net.IPv6len + 2 |
|||
default: |
|||
return nil |
|||
|
|||
} |
|||
|
|||
if len(b) < addrLen { |
|||
return nil |
|||
} |
|||
|
|||
return b[:addrLen] |
|||
} |
|||
|
|||
// ParseAddr parses the address in string s. Returns nil if failed.
|
|||
func ParseAddr(s string) Addr { |
|||
var addr Addr |
|||
host, port, err := net.SplitHostPort(s) |
|||
if err != nil { |
|||
return nil |
|||
} |
|||
if ip := net.ParseIP(host); ip != nil { |
|||
if ip4 := ip.To4(); ip4 != nil { |
|||
addr = make([]byte, 1+net.IPv4len+2) |
|||
addr[0] = AtypIPv4 |
|||
copy(addr[1:], ip4) |
|||
} else { |
|||
addr = make([]byte, 1+net.IPv6len+2) |
|||
addr[0] = AtypIPv6 |
|||
copy(addr[1:], ip) |
|||
} |
|||
} else { |
|||
if len(host) > 255 { |
|||
return nil |
|||
} |
|||
addr = make([]byte, 1+1+len(host)+2) |
|||
addr[0] = AtypDomainName |
|||
addr[1] = byte(len(host)) |
|||
copy(addr[2:], host) |
|||
} |
|||
|
|||
portUint, err := strconv.ParseUint(port, 10, 16) |
|||
if err != nil { |
|||
return nil |
|||
} |
|||
|
|||
addr[len(addr)-2], addr[len(addr)-1] = byte(portUint>>8), byte(portUint) |
|||
|
|||
return addr |
|||
} |
|||
|
|||
func DecodeUDPPacket(packet []byte) (addr Addr, payload []byte, err error) { |
|||
if len(packet) < 5 { |
|||
err = errors.New("insufficient length of packet") |
|||
return |
|||
} |
|||
|
|||
// packet[0] and packet[1] are reserved
|
|||
if !bytes.Equal(packet[:2], []byte{0, 0}) { |
|||
err = errors.New("reserved fields should be zero") |
|||
return |
|||
} |
|||
|
|||
if packet[2] != 0 /* fragments */ { |
|||
err = errors.New("discarding fragmented payload") |
|||
return |
|||
} |
|||
|
|||
addr = SplitAddr(packet[3:]) |
|||
if addr == nil { |
|||
err = errors.New("failed to read UDP header") |
|||
} |
|||
|
|||
payload = bytes.Join([][]byte{packet[3+len(addr):]}, []byte{}) |
|||
return |
|||
} |
|||
|
|||
func EncodeUDPPacket(addr string, payload []byte) (packet []byte, err error) { |
|||
rAddr := ParseAddr(addr) |
|||
if rAddr == nil { |
|||
err = errors.New("cannot parse addr") |
|||
return |
|||
} |
|||
packet = bytes.Join([][]byte{{0, 0, 0}, rAddr, payload}, []byte{}) |
|||
return |
|||
} |
Loading…
Reference in new issue