New: custom socks5 proxy support

This commit is contained in:
Dreamacro 2018-08-12 13:50:54 +08:00
parent 35e572406b
commit 2b87b907ae
6 changed files with 105 additions and 8 deletions

View file

@ -78,6 +78,9 @@ external-controller = 127.0.0.1:8080
ss1 = ss, server1, port, AEAD_CHACHA20_POLY1305, password
ss2 = ss, server2, port, AEAD_CHACHA20_POLY1305, password
# name = socks5, server, port
socks = socks5, server1, port
[Proxy Group]
# url-test select which proxy will be used by benchmarking speed to a URL.
# name = url-test, [proxies], url, interval(second)

91
adapters/remote/socks5.go Normal file
View file

@ -0,0 +1,91 @@
package adapters
import (
"bytes"
"errors"
"fmt"
"io"
"net"
C "github.com/Dreamacro/clash/constant"
"github.com/riobard/go-shadowsocks2/socks"
)
// Socks5Adapter is a shadowsocks adapter
type Socks5Adapter struct {
conn net.Conn
}
// Close is used to close connection
func (ss *Socks5Adapter) Close() {
ss.conn.Close()
}
func (ss *Socks5Adapter) Conn() net.Conn {
return ss.conn
}
type Socks5 struct {
addr string
name string
}
func (ss *Socks5) Name() string {
return ss.name
}
func (ss *Socks5) Type() C.AdapterType {
return C.Socks5
}
func (ss *Socks5) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
c, err := net.Dial("tcp", ss.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error", ss.addr)
}
c.(*net.TCPConn).SetKeepAlive(true)
if err := ss.sharkHand(addr, c); err != nil {
return nil, err
}
return &Socks5Adapter{conn: c}, nil
}
func (ss *Socks5) sharkHand(addr *C.Addr, rw io.ReadWriter) error {
buf := make([]byte, socks.MaxAddrLen)
// VER, CMD, RSV
_, err := rw.Write([]byte{5, 1, 0})
if err != nil {
return err
}
if _, err := io.ReadFull(rw, buf[:2]); err != nil {
return err
}
if buf[0] != 5 {
return errors.New("SOCKS version error")
} else if buf[1] != 0 {
return errors.New("SOCKS need auth")
}
// VER, CMD, RSV, ADDR
if _, err := rw.Write(bytes.Join([][]byte{[]byte{5, 1, 0}, serializesSocksAddr(addr)}, []byte(""))); err != nil {
return err
}
if _, err := io.ReadFull(rw, buf[:10]); err != nil {
return err
}
return nil
}
func NewSocks5(name, addr string) *Socks5 {
return &Socks5{
addr: addr,
name: name,
}
}

View file

@ -228,6 +228,14 @@ func (c *Config) parseProxies(cfg *ini.File) error {
return err
}
proxies[key.Name()] = ss
// socks5, server, port
case "socks5":
if len(proxy) < 3 {
continue
}
addr := fmt.Sprintf("%s:%s", proxy[1], proxy[2])
socks5 := adapters.NewSocks5(key.Name(), addr)
proxies[key.Name()] = socks5
}
}
@ -325,19 +333,16 @@ func (c *Config) handleResponseMessage() {
log.Errorf("Listening HTTP proxy at %s error", c.general.Port)
c.general.Port = 0
}
break
case "socks-addr":
if event.Payload.(bool) == false {
log.Errorf("Listening SOCKS proxy at %s error", c.general.SocksPort)
c.general.SocksPort = 0
}
break
case "redir-addr":
if event.Payload.(bool) == false {
log.Errorf("Listening Redir proxy at %s error", c.general.RedirPort)
c.general.RedirPort = 0
}
break
}
}
}

View file

@ -10,6 +10,7 @@ const (
Reject
Selector
Shadowsocks
Socks5
URLTest
)
@ -42,6 +43,8 @@ func (at AdapterType) String() string {
return "Selector"
case Shadowsocks:
return "Shadowsocks"
case Socks5:
return "Socks5"
case URLTest:
return "URLTest"
default:

View file

@ -84,17 +84,14 @@ func (l *Listener) process(signal chan<- struct{}) {
addr := event.Payload.(string)
err := l.updateHTTP(addr)
reportCH <- &config.Event{Type: "http-addr", Payload: err == nil}
break
case "socks-addr":
addr := event.Payload.(string)
err := l.updateSocks(addr)
reportCH <- &config.Event{Type: "socks-addr", Payload: err == nil}
break
case "redir-addr":
addr := event.Payload.(string)
err := l.updateRedir(addr)
reportCH <- &config.Event{Type: "redir-addr", Payload: err == nil}
break
}
}
}

View file

@ -106,10 +106,8 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) {
switch adapter := localConn.(type) {
case *LocalAdapter.HttpAdapter:
t.handleHTTP(adapter, remoConn)
break
case *LocalAdapter.SocksAdapter:
t.handleSOCKS(adapter, remoConn)
break
}
}