mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
Add Socks5 support
This commit is contained in:
+29
-32
@@ -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")
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user