Add Socks5 support

This commit is contained in:
wweir
2020-02-17 06:19:36 +08:00
parent 4681dd9845
commit 7d77f4a85e
14 changed files with 187 additions and 139 deletions
+29 -32
View File
@@ -72,16 +72,10 @@ func (c *conn) Write(b []byte) (n int, err error) {
}
// ParseAddr parse target addr from net.Conn
func ParseAddr(conn net.Conn, password []byte) (c net.Conn, domain string, port uint16, err error) {
func ParseAddr(conn net.Conn, password []byte) (_ net.Conn, domain string, port uint16, err error) {
teeConn := &util.TeeConn{Conn: conn}
teeConn.StartOrReset()
defer func() {
if err != nil {
teeConn.Close()
} else {
teeConn.Stop()
}
}()
defer teeConn.Stop()
head := new(header)
if err = binary.Read(conn, binary.BigEndian, head); err != nil {
@@ -102,37 +96,40 @@ func ParseAddr(conn net.Conn, password []byte) (c net.Conn, domain string, port
case TGT_HTTP:
teeConn.DropAndRestart()
var resp *http.Request
resp, err = http.ReadRequest(bufio.NewReader(teeConn))
if err != nil {
return nil, "", 0, err
}
idx := strings.LastIndex(resp.Host, ":")
if idx == -1 {
return teeConn, resp.Host, 80, nil
}
var port uint64
if port, err = strconv.ParseUint(resp.Host[idx+1:], 10, 16); err != nil {
return nil, "", 0, err
}
return teeConn, resp.Host[:idx], uint16(port), nil
return ParseHTTP(teeConn)
case TGT_HTTPS:
teeConn.DropAndRestart()
domain, _, err := extractSNI(teeConn)
if err != nil {
return nil, "", 0, err
}
return teeConn, domain, head.Port, nil
conn, domain, err = ParseHTTPS(teeConn)
return conn, domain, head.Port, err
default:
return nil, "", 0, errors.New("invalid request")
return teeConn, "", 0, errors.New("invalid request")
}
}
func ParseHTTP(teeConn net.Conn) (_ net.Conn, domain string, port uint16, err error) {
resp, err := http.ReadRequest(bufio.NewReader(teeConn))
if err != nil {
return teeConn, "", 0, err
}
idx := strings.LastIndex(resp.Host, ":")
if idx == -1 {
return teeConn, resp.Host, 80, nil
}
p, err := strconv.ParseUint(resp.Host[idx+1:], 10, 16)
if err != nil {
return teeConn, "", 0, err
}
return teeConn, resp.Host[:idx], uint16(p), nil
}
func ParseHTTPS(teeConn net.Conn) (_ net.Conn, domain string, err error) {
if domain, _, err = extractSNI(teeConn); err != nil {
return nil, "", err
}
return teeConn, domain, nil
}
var errChecksum = errors.New("invalid checksum")
+44
View File
@@ -0,0 +1,44 @@
package socks5
// https://tools.ietf.org/html/rfc1928
type authReq struct {
VER byte
NMETHODS byte
METHODS [1]byte // 1 to 255, fix to no authentication
}
type authResp struct {
VER byte
METHOD byte
}
type request struct {
req
DST_ADDR []byte // first byte is length
DST_PORT []byte // two bytes
}
type req struct {
VER byte
CMD byte
RSV byte
ATYP byte
}
func (r *request) Bytes() []byte {
out := []byte{r.VER, r.CMD, r.RSV, r.ATYP}
out = append(out, r.DST_ADDR...)
return append(out, r.DST_PORT...)
}
type response struct {
resp
DST_ADDR []byte // first byte is length
DST_PORT []byte // two bytes
}
type resp struct {
VER byte
REP byte
RSV byte
ATYP byte
}
+20 -46
View File
@@ -5,13 +5,28 @@ import (
"fmt"
"io"
"net"
"strconv"
"strings"
)
func ToSocks5(c net.Conn, domain, port string) net.Conn {
num, _ := strconv.Atoi(port)
bytes := []byte{byte(num >> 8), byte(num)}
return &conn{init: make(chan struct{}), Conn: c, domain: domain, port: bytes}
func IsSocks5Schema(addr string) (string, bool) {
if strings.HasPrefix(addr, "socks5://") {
return strings.TrimPrefix(addr, "socks5://"), true
}
if strings.HasPrefix(addr, "socks5h://") {
return strings.TrimPrefix(addr, "socks5h://"), true
}
return addr, false
}
func ToSocks5(c net.Conn, domain string, port uint16) net.Conn {
return &conn{
init: make(chan struct{}),
Conn: c,
domain: domain,
port: []byte{byte(port >> 8), byte(port)},
}
}
type conn struct {
@@ -106,44 +121,3 @@ func (c *conn) Write(b []byte) (n int, err error) {
close(c.init)
return c.Conn.Write(b)
}
type authReq struct {
VER byte
NMETHODS byte
METHODS [1]byte // 1 to 255, fix to no authentication
}
type authResp struct {
VER byte
METHOD byte
}
type request struct {
req
DST_ADDR []byte // first byte is length
DST_PORT []byte // two bytes
}
type req struct {
VER byte
CMD byte
RSV byte
ATYP byte
}
func (r *request) Bytes() []byte {
out := []byte{r.VER, r.CMD, r.RSV, r.ATYP}
out = append(out, r.DST_ADDR...)
return append(out, r.DST_PORT...)
}
type response struct {
resp
DST_ADDR []byte // first byte is length
DST_PORT []byte // two bytes
}
type resp struct {
VER byte
REP byte
RSV byte
ATYP byte
}