New: custom socks5 proxy support
This commit is contained in:
parent
9a1de2a815
commit
2aa9bcaf9c
6 changed files with 105 additions and 8 deletions
|
@ -78,6 +78,9 @@ external-controller = 127.0.0.1:8080
|
||||||
ss1 = ss, server1, port, AEAD_CHACHA20_POLY1305, password
|
ss1 = ss, server1, port, AEAD_CHACHA20_POLY1305, password
|
||||||
ss2 = ss, server2, port, AEAD_CHACHA20_POLY1305, password
|
ss2 = ss, server2, port, AEAD_CHACHA20_POLY1305, password
|
||||||
|
|
||||||
|
# name = socks5, server, port
|
||||||
|
socks = socks5, server1, port
|
||||||
|
|
||||||
[Proxy Group]
|
[Proxy Group]
|
||||||
# url-test select which proxy will be used by benchmarking speed to a URL.
|
# url-test select which proxy will be used by benchmarking speed to a URL.
|
||||||
# name = url-test, [proxies], url, interval(second)
|
# name = url-test, [proxies], url, interval(second)
|
||||||
|
|
91
adapters/remote/socks5.go
Normal file
91
adapters/remote/socks5.go
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
|
@ -228,6 +228,14 @@ func (c *Config) parseProxies(cfg *ini.File) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
proxies[key.Name()] = ss
|
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)
|
log.Errorf("Listening HTTP proxy at %s error", c.general.Port)
|
||||||
c.general.Port = 0
|
c.general.Port = 0
|
||||||
}
|
}
|
||||||
break
|
|
||||||
case "socks-addr":
|
case "socks-addr":
|
||||||
if event.Payload.(bool) == false {
|
if event.Payload.(bool) == false {
|
||||||
log.Errorf("Listening SOCKS proxy at %s error", c.general.SocksPort)
|
log.Errorf("Listening SOCKS proxy at %s error", c.general.SocksPort)
|
||||||
c.general.SocksPort = 0
|
c.general.SocksPort = 0
|
||||||
}
|
}
|
||||||
break
|
|
||||||
case "redir-addr":
|
case "redir-addr":
|
||||||
if event.Payload.(bool) == false {
|
if event.Payload.(bool) == false {
|
||||||
log.Errorf("Listening Redir proxy at %s error", c.general.RedirPort)
|
log.Errorf("Listening Redir proxy at %s error", c.general.RedirPort)
|
||||||
c.general.RedirPort = 0
|
c.general.RedirPort = 0
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ const (
|
||||||
Reject
|
Reject
|
||||||
Selector
|
Selector
|
||||||
Shadowsocks
|
Shadowsocks
|
||||||
|
Socks5
|
||||||
URLTest
|
URLTest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@ func (at AdapterType) String() string {
|
||||||
return "Selector"
|
return "Selector"
|
||||||
case Shadowsocks:
|
case Shadowsocks:
|
||||||
return "Shadowsocks"
|
return "Shadowsocks"
|
||||||
|
case Socks5:
|
||||||
|
return "Socks5"
|
||||||
case URLTest:
|
case URLTest:
|
||||||
return "URLTest"
|
return "URLTest"
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -84,17 +84,14 @@ func (l *Listener) process(signal chan<- struct{}) {
|
||||||
addr := event.Payload.(string)
|
addr := event.Payload.(string)
|
||||||
err := l.updateHTTP(addr)
|
err := l.updateHTTP(addr)
|
||||||
reportCH <- &config.Event{Type: "http-addr", Payload: err == nil}
|
reportCH <- &config.Event{Type: "http-addr", Payload: err == nil}
|
||||||
break
|
|
||||||
case "socks-addr":
|
case "socks-addr":
|
||||||
addr := event.Payload.(string)
|
addr := event.Payload.(string)
|
||||||
err := l.updateSocks(addr)
|
err := l.updateSocks(addr)
|
||||||
reportCH <- &config.Event{Type: "socks-addr", Payload: err == nil}
|
reportCH <- &config.Event{Type: "socks-addr", Payload: err == nil}
|
||||||
break
|
|
||||||
case "redir-addr":
|
case "redir-addr":
|
||||||
addr := event.Payload.(string)
|
addr := event.Payload.(string)
|
||||||
err := l.updateRedir(addr)
|
err := l.updateRedir(addr)
|
||||||
reportCH <- &config.Event{Type: "redir-addr", Payload: err == nil}
|
reportCH <- &config.Event{Type: "redir-addr", Payload: err == nil}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,10 +106,8 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) {
|
||||||
switch adapter := localConn.(type) {
|
switch adapter := localConn.(type) {
|
||||||
case *LocalAdapter.HttpAdapter:
|
case *LocalAdapter.HttpAdapter:
|
||||||
t.handleHTTP(adapter, remoConn)
|
t.handleHTTP(adapter, remoConn)
|
||||||
break
|
|
||||||
case *LocalAdapter.SocksAdapter:
|
case *LocalAdapter.SocksAdapter:
|
||||||
t.handleSOCKS(adapter, remoConn)
|
t.handleSOCKS(adapter, remoConn)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue