Feature: socks5 udp associate
This commit is contained in:
@ -10,26 +10,16 @@ import (
|
||||
|
||||
// HTTPAdapter is a adapter for HTTP connection
|
||||
type HTTPAdapter struct {
|
||||
net.Conn
|
||||
metadata *C.Metadata
|
||||
conn net.Conn
|
||||
R *http.Request
|
||||
}
|
||||
|
||||
// Close HTTP connection
|
||||
func (h *HTTPAdapter) Close() {
|
||||
h.conn.Close()
|
||||
}
|
||||
|
||||
// Metadata return destination metadata
|
||||
func (h *HTTPAdapter) Metadata() *C.Metadata {
|
||||
return h.metadata
|
||||
}
|
||||
|
||||
// Conn return raw net.Conn of HTTP
|
||||
func (h *HTTPAdapter) Conn() net.Conn {
|
||||
return h.conn
|
||||
}
|
||||
|
||||
// NewHTTP is HTTPAdapter generator
|
||||
func NewHTTP(request *http.Request, conn net.Conn) *HTTPAdapter {
|
||||
metadata := parseHTTPAddr(request)
|
||||
@ -37,7 +27,7 @@ func NewHTTP(request *http.Request, conn net.Conn) *HTTPAdapter {
|
||||
return &HTTPAdapter{
|
||||
metadata: metadata,
|
||||
R: request,
|
||||
conn: conn,
|
||||
Conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,6 @@ func NewHTTPS(request *http.Request, conn net.Conn) *SocketAdapter {
|
||||
metadata.SourceIP = parseSourceIP(conn)
|
||||
return &SocketAdapter{
|
||||
metadata: metadata,
|
||||
conn: conn,
|
||||
Conn: conn,
|
||||
}
|
||||
}
|
||||
|
@ -9,33 +9,24 @@ import (
|
||||
|
||||
// SocketAdapter is a adapter for socks and redir connection
|
||||
type SocketAdapter struct {
|
||||
conn net.Conn
|
||||
net.Conn
|
||||
metadata *C.Metadata
|
||||
}
|
||||
|
||||
// Close socks and redir connection
|
||||
func (s *SocketAdapter) Close() {
|
||||
s.conn.Close()
|
||||
}
|
||||
|
||||
// Metadata return destination metadata
|
||||
func (s *SocketAdapter) Metadata() *C.Metadata {
|
||||
return s.metadata
|
||||
}
|
||||
|
||||
// Conn return raw net.Conn
|
||||
func (s *SocketAdapter) Conn() net.Conn {
|
||||
return s.conn
|
||||
}
|
||||
|
||||
// NewSocket is SocketAdapter generator
|
||||
func NewSocket(target socks.Addr, conn net.Conn, source C.SourceType) *SocketAdapter {
|
||||
func NewSocket(target socks.Addr, conn net.Conn, source C.SourceType, netType C.NetWork) *SocketAdapter {
|
||||
metadata := parseSocksAddr(target)
|
||||
metadata.NetWork = netType
|
||||
metadata.Source = source
|
||||
metadata.SourceIP = parseSourceIP(conn)
|
||||
|
||||
return &SocketAdapter{
|
||||
conn: conn,
|
||||
Conn: conn,
|
||||
metadata: metadata,
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
|
||||
func parseSocksAddr(target socks.Addr) *C.Metadata {
|
||||
metadata := &C.Metadata{
|
||||
NetWork: C.TCP,
|
||||
AddrType: int(target[0]),
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package adapters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
@ -13,6 +14,7 @@ import (
|
||||
type Base struct {
|
||||
name string
|
||||
tp C.AdapterType
|
||||
udp bool
|
||||
}
|
||||
|
||||
func (b *Base) Name() string {
|
||||
@ -23,6 +25,14 @@ func (b *Base) Type() C.AdapterType {
|
||||
return b.tp
|
||||
}
|
||||
|
||||
func (b *Base) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
|
||||
return nil, nil, errors.New("no support")
|
||||
}
|
||||
|
||||
func (b *Base) SupportUDP() bool {
|
||||
return b.udp
|
||||
}
|
||||
|
||||
func (b *Base) Destroy() {}
|
||||
|
||||
func (b *Base) MarshalJSON() ([]byte, error) {
|
||||
|
@ -24,11 +24,22 @@ func (d *Direct) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (d *Direct) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
|
||||
pc, err := net.ListenPacket("udp", "")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
addr, _ := net.ResolveUDPAddr("udp", net.JoinHostPort(metadata.String(), metadata.Port))
|
||||
return pc, addr, nil
|
||||
}
|
||||
|
||||
func NewDirect() *Direct {
|
||||
return &Direct{
|
||||
Base: &Base{
|
||||
name: "DIRECT",
|
||||
tp: C.Direct,
|
||||
udp: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,16 @@ func (f *Fallback) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
return proxy.Dial(metadata)
|
||||
}
|
||||
|
||||
func (f *Fallback) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
|
||||
proxy := f.findAliveProxy()
|
||||
return proxy.DialUDP(metadata)
|
||||
}
|
||||
|
||||
func (f *Fallback) SupportUDP() bool {
|
||||
proxy := f.findAliveProxy()
|
||||
return proxy.SupportUDP()
|
||||
}
|
||||
|
||||
func (f *Fallback) MarshalJSON() ([]byte, error) {
|
||||
var all []string
|
||||
for _, proxy := range f.proxies {
|
||||
|
@ -67,6 +67,24 @@ func (lb *LoadBalance) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
return lb.proxies[0].Dial(metadata)
|
||||
}
|
||||
|
||||
func (lb *LoadBalance) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
|
||||
key := uint64(murmur3.Sum32([]byte(getKey(metadata))))
|
||||
buckets := int32(len(lb.proxies))
|
||||
for i := 0; i < lb.maxRetry; i, key = i+1, key+1 {
|
||||
idx := jumpHash(key, buckets)
|
||||
proxy := lb.proxies[idx]
|
||||
if proxy.Alive() {
|
||||
return proxy.DialUDP(metadata)
|
||||
}
|
||||
}
|
||||
|
||||
return lb.proxies[0].DialUDP(metadata)
|
||||
}
|
||||
|
||||
func (lb *LoadBalance) SupportUDP() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (lb *LoadBalance) Destroy() {
|
||||
lb.done <- struct{}{}
|
||||
}
|
||||
|
@ -24,6 +24,14 @@ func (s *Selector) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
return s.selected.Dial(metadata)
|
||||
}
|
||||
|
||||
func (s *Selector) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
|
||||
return s.selected.DialUDP(metadata)
|
||||
}
|
||||
|
||||
func (s *Selector) SupportUDP() bool {
|
||||
return s.selected.SupportUDP()
|
||||
}
|
||||
|
||||
func (s *Selector) MarshalJSON() ([]byte, error) {
|
||||
var all []string
|
||||
for k := range s.proxies {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
"github.com/Dreamacro/clash/common/structure"
|
||||
obfs "github.com/Dreamacro/clash/component/simple-obfs"
|
||||
v2rayObfs "github.com/Dreamacro/clash/component/v2ray-plugin"
|
||||
@ -34,6 +35,7 @@ type ShadowSocksOption struct {
|
||||
Port int `proxy:"port"`
|
||||
Password string `proxy:"password"`
|
||||
Cipher string `proxy:"cipher"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
Plugin string `proxy:"plugin,omitempty"`
|
||||
PluginOpts map[string]interface{} `proxy:"plugin-opts,omitempty"`
|
||||
|
||||
@ -80,6 +82,19 @@ func (ss *ShadowSocks) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
|
||||
pc, err := net.ListenPacket("udp", "")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
addr, _ := net.ResolveUDPAddr("udp", ss.server)
|
||||
remoteAddr, _ := net.ResolveUDPAddr("udp", net.JoinHostPort(metadata.String(), metadata.Port))
|
||||
|
||||
pc = ss.cipher.PacketConn(pc)
|
||||
return &ssUDPConn{PacketConn: pc, rAddr: remoteAddr}, addr, nil
|
||||
}
|
||||
|
||||
func (ss *ShadowSocks) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]string{
|
||||
"type": ss.Type().String(),
|
||||
@ -144,6 +159,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
Base: &Base{
|
||||
name: option.Name,
|
||||
tp: C.Shadowsocks,
|
||||
udp: option.UDP,
|
||||
},
|
||||
server: server,
|
||||
cipher: ciph,
|
||||
@ -173,3 +189,24 @@ func serializesSocksAddr(metadata *C.Metadata) []byte {
|
||||
}
|
||||
return bytes.Join(buf, nil)
|
||||
}
|
||||
|
||||
type ssUDPConn struct {
|
||||
net.PacketConn
|
||||
rAddr net.Addr
|
||||
}
|
||||
|
||||
func (uc *ssUDPConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
buf := pool.BufPool.Get().([]byte)
|
||||
defer pool.BufPool.Put(buf[:cap(buf)])
|
||||
rAddr := socks.ParseAddr(uc.rAddr.String())
|
||||
copy(buf[len(rAddr):], b)
|
||||
copy(buf, rAddr)
|
||||
return uc.PacketConn.WriteTo(buf[:len(rAddr)+len(b)], addr)
|
||||
}
|
||||
|
||||
func (uc *ssUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
n, a, e := uc.PacketConn.ReadFrom(b)
|
||||
addr := socks.SplitAddr(b[:n])
|
||||
copy(b, b[len(addr):])
|
||||
return n - len(addr), a, e
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ type Socks5Option struct {
|
||||
UserName string `proxy:"username,omitempty"`
|
||||
Password string `proxy:"password,omitempty"`
|
||||
TLS bool `proxy:"tls,omitempty"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
}
|
||||
|
||||
@ -126,6 +127,7 @@ func NewSocks5(option Socks5Option) *Socks5 {
|
||||
Base: &Base{
|
||||
name: option.Name,
|
||||
tp: C.Socks5,
|
||||
udp: option.UDP,
|
||||
},
|
||||
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
||||
user: option.UserName,
|
||||
|
@ -43,6 +43,14 @@ func (u *URLTest) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
return a, err
|
||||
}
|
||||
|
||||
func (u *URLTest) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
|
||||
return u.fast.DialUDP(metadata)
|
||||
}
|
||||
|
||||
func (u *URLTest) SupportUDP() bool {
|
||||
return u.fast.SupportUDP()
|
||||
}
|
||||
|
||||
func (u *URLTest) MarshalJSON() ([]byte, error) {
|
||||
var all []string
|
||||
for _, proxy := range u.proxies {
|
||||
|
Reference in New Issue
Block a user