From 07ce5e64224fac62d5430ea9dbb6c474ab4ecf15 Mon Sep 17 00:00:00 2001 From: xjasonlyu Date: Thu, 9 Sep 2021 12:50:23 +0800 Subject: [PATCH] Feature: socks5 over unix domain socket(UDS) support this feature is compatible with tor proxy. --- engine/parse.go | 23 +++++++++++++++++------ proxy/socks5.go | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/engine/parse.go b/engine/parse.go index ff64bfd..24e60e1 100644 --- a/engine/parse.go +++ b/engine/parse.go @@ -51,11 +51,11 @@ func parseProxy(s string) (proxy.Proxy, error) { case proto.Reject.String(): return proxy.NewReject(), nil case proto.HTTP.String(): - return proxy.NewHTTP(parseAddrUserPass(u)) + return proxy.NewHTTP(parseHTTP(u)) case proto.Socks4.String(): - return proxy.NewSocks4(parseAddrUser(u)) + return proxy.NewSocks4(parseSocks4(u)) case proto.Socks5.String(): - return proxy.NewSocks5(parseAddrUserPass(u)) + return proxy.NewSocks5(parseSocks5(u)) case proto.Shadowsocks.String(): return proxy.NewShadowsocks(parseShadowsocks(u)) default: @@ -63,14 +63,25 @@ func parseProxy(s string) (proxy.Proxy, error) { } } -func parseAddrUser(u *url.URL) (address, username string) { +func parseHTTP(u *url.URL) (address, username, password string) { + address, username = u.Host, u.User.Username() + password, _ = u.User.Password() + return +} + +func parseSocks4(u *url.URL) (address, username string) { address, username = u.Host, u.User.Username() return } -func parseAddrUserPass(u *url.URL) (address, username, password string) { - address, username = parseAddrUser(u) +func parseSocks5(u *url.URL) (address, username, password string) { + address, username = u.Host, u.User.Username() password, _ = u.User.Password() + + // Socks5 over UDS + if address == "" { + address = u.Path + } return } diff --git a/proxy/socks5.go b/proxy/socks5.go index b77a666..86e3dcd 100755 --- a/proxy/socks5.go +++ b/proxy/socks5.go @@ -2,6 +2,7 @@ package proxy import ( "context" + "errors" "fmt" "io" "net" @@ -19,6 +20,9 @@ type Socks5 struct { user string pass string + + // unix indicates if socks5 over UDS is enabled. + unix bool } func NewSocks5(addr, user, pass string) (*Socks5, error) { @@ -29,11 +33,17 @@ func NewSocks5(addr, user, pass string) (*Socks5, error) { }, user: user, pass: pass, + unix: len(addr) > 0 && addr[0] == '/', }, nil } func (ss *Socks5) DialContext(ctx context.Context, metadata *M.Metadata) (c net.Conn, err error) { - c, err = dialer.DialContext(ctx, "tcp", ss.Addr()) + var network = "tcp" + if ss.unix { + network = "unix" + } + + c, err = dialer.DialContext(ctx, network, ss.Addr()) if err != nil { return nil, fmt.Errorf("connect to %s: %w", ss.Addr(), err) } @@ -54,6 +64,10 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *M.Metadata) (c net. } func (ss *Socks5) DialUDP(*M.Metadata) (_ net.PacketConn, err error) { + if ss.unix { + return nil, errors.New("not supported when unix domain socket is enabled") + } + ctx, cancel := context.WithTimeout(context.Background(), tcpConnectTimeout) defer cancel()