From 6885d8593cd2df60bb322976a30de79a538fd4ed Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Mon, 5 Dec 2022 10:12:53 +0800 Subject: [PATCH] chore: listeners support shadowsocks/vmess --- adapter/inbound/addition.go | 20 +++++-- constant/listener.go | 3 +- docs/config.yaml | 25 +++++++- listener/autoredir/tcp.go | 8 +-- listener/config/shadowsocks.go | 17 ++++++ listener/config/vmess.go | 22 +++++++ listener/http/server.go | 8 +-- listener/inbound/base.go | 8 +-- listener/inbound/shadowsocks.go | 79 +++++++++++++++++++++++++ listener/inbound/vmess.go | 91 +++++++++++++++++++++++++++++ listener/listener.go | 40 ++++++++++--- listener/mixed/mixed.go | 8 +-- listener/parse.go | 14 +++++ listener/redir/tcp.go | 8 +-- listener/shadowsocks/tcp.go | 26 ++++----- listener/sing/context.go | 24 ++++++++ listener/sing/sing.go | 23 ++++++-- listener/sing_shadowsocks/server.go | 58 ++++++++++-------- listener/sing_vmess/server.go | 56 +++++++++++------- listener/socks/tcp.go | 8 +-- listener/socks/udp.go | 8 +-- listener/tproxy/tproxy.go | 8 +-- listener/tproxy/udp.go | 8 +-- listener/tuic/server.go | 8 +-- 24 files changed, 453 insertions(+), 125 deletions(-) create mode 100644 listener/config/shadowsocks.go create mode 100644 listener/config/vmess.go create mode 100644 listener/inbound/shadowsocks.go create mode 100644 listener/inbound/vmess.go create mode 100644 listener/sing/context.go diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 4d57fcee..8bf1e786 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -4,12 +4,20 @@ import ( C "github.com/Dreamacro/clash/constant" ) -type Addition struct { - InName string - SpecialRules string -} +type Addition func(metadata *C.Metadata) func (a Addition) Apply(metadata *C.Metadata) { - metadata.InName = a.InName - metadata.SpecialRules = a.SpecialRules + a(metadata) +} + +func WithInName(name string) Addition { + return func(metadata *C.Metadata) { + metadata.InName = name + } +} + +func WithSpecialRules(specialRules string) Addition { + return func(metadata *C.Metadata) { + metadata.SpecialRules = specialRules + } } diff --git a/constant/listener.go b/constant/listener.go index cb7ab456..a52c1946 100644 --- a/constant/listener.go +++ b/constant/listener.go @@ -8,11 +8,10 @@ type Listener interface { Close() error } -type AdvanceListener interface { +type MultiAddrListener interface { Close() error Config() string AddrList() (addrList []net.Addr) - HandleConn(conn net.Conn, in chan<- ConnContext) } type InboundListener interface { diff --git a/docs/config.yaml b/docs/config.yaml index e58746e0..c20228db 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -121,7 +121,7 @@ tunnels: - tcp/udp,127.0.0.1:6553,114.114.114.114:53,proxy - tcp,127.0.0.1:6666,rds.mysql.com:3306,vpn # full yaml config - - network: [tcp, udp] + - network: [ tcp, udp ] address: 127.0.0.1:7777 target: target.com proxy: proxy @@ -693,13 +693,32 @@ listeners: type: tproxy port: 10812 listen: 0.0.0.0 - # udp: false # 默认 true # rule: sub-rule + # udp: false # 默认 true + + - name: shadowsocks-in-1 + type: shadowsocks + port: 10813 + listen: 0.0.0.0 + # rule: sub-rule + password: vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg= + cipher: 2022-blake3-aes-256-gcm + + - name: vmess-in-1 + type: vmess + port: 10814 + listen: 0.0.0.0 + # rule: sub-rule + users: + - username: 1 + uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 + alterId: 1 - name: tuic-in-1 type: tuic - port: 10813 + port: 10815 listen: 0.0.0.0 + # rule: sub-rule # token: # - TOKEN # certificate: ./server.crt diff --git a/listener/autoredir/tcp.go b/listener/autoredir/tcp.go index 67b57022..854d31d6 100644 --- a/listener/autoredir/tcp.go +++ b/listener/autoredir/tcp.go @@ -62,10 +62,10 @@ func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-REDIR", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-REDIR"), + inbound.WithSpecialRules(""), + } } l, err := net.Listen("tcp", addr) if err != nil { diff --git a/listener/config/shadowsocks.go b/listener/config/shadowsocks.go new file mode 100644 index 00000000..cfe31f62 --- /dev/null +++ b/listener/config/shadowsocks.go @@ -0,0 +1,17 @@ +package config + +import ( + "encoding/json" +) + +type ShadowsocksServer struct { + Enable bool + Listen string + Password string + Cipher string +} + +func (t ShadowsocksServer) String() string { + b, _ := json.Marshal(t) + return string(b) +} diff --git a/listener/config/vmess.go b/listener/config/vmess.go new file mode 100644 index 00000000..cc49433e --- /dev/null +++ b/listener/config/vmess.go @@ -0,0 +1,22 @@ +package config + +import ( + "encoding/json" +) + +type VmessUser struct { + Username string + UUID string + AlterID int +} + +type VmessServer struct { + Enable bool + Listen string + Users []VmessUser +} + +func (t VmessServer) String() string { + b, _ := json.Marshal(t) + return string(b) +} diff --git a/listener/http/server.go b/listener/http/server.go index c8379955..8819af11 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -36,10 +36,10 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-HTTP", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-HTTP"), + inbound.WithSpecialRules(""), + } } l, err := inbound.Listen("tcp", addr) diff --git a/listener/inbound/base.go b/listener/inbound/base.go index df61b0ea..46cd190d 100644 --- a/listener/inbound/base.go +++ b/listener/inbound/base.go @@ -87,10 +87,10 @@ func (o BaseOption) Equal(config C.InboundConfig) bool { } func (o BaseOption) Additions() []inbound.Addition { - return []inbound.Addition{{ - InName: o.NameStr, - SpecialRules: o.SpecialRules, - }} + return []inbound.Addition{ + inbound.WithInName(o.NameStr), + inbound.WithSpecialRules(o.SpecialRules), + } } var _ C.InboundConfig = (*BaseOption)(nil) diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go new file mode 100644 index 00000000..c21f2f39 --- /dev/null +++ b/listener/inbound/shadowsocks.go @@ -0,0 +1,79 @@ +package inbound + +import ( + C "github.com/Dreamacro/clash/constant" + LC "github.com/Dreamacro/clash/listener/config" + "github.com/Dreamacro/clash/listener/sing_shadowsocks" + "github.com/Dreamacro/clash/log" +) + +type ShadowSocksOption struct { + BaseOption + Password string `inbound:"password"` + Cipher string `inbound:"cipher"` +} + +func (o ShadowSocksOption) Equal(config C.InboundConfig) bool { + return optionToString(o) == optionToString(config) +} + +type ShadowSocks struct { + *Base + config *ShadowSocksOption + l C.MultiAddrListener +} + +func NewShadowSocks(options *ShadowSocksOption) (*ShadowSocks, error) { + base, err := NewBase(&options.BaseOption) + if err != nil { + return nil, err + } + return &ShadowSocks{ + Base: base, + config: options, + }, nil + +} + +// Config implements constant.InboundListener +func (s *ShadowSocks) Config() C.InboundConfig { + return s.config +} + +// Address implements constant.InboundListener +func (s *ShadowSocks) Address() string { + if s.l != nil { + for _, addr := range s.l.AddrList() { + return addr.String() + } + } + return "" +} + +// Listen implements constant.InboundListener +func (s *ShadowSocks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { + var err error + s.l, err = sing_shadowsocks.New( + LC.ShadowsocksServer{ + Enable: true, + Listen: s.RawAddress(), + Password: s.config.Password, + Cipher: s.config.Cipher, + }, + tcpIn, + udpIn, + s.Additions()..., + ) + if err != nil { + return err + } + log.Infoln("ShadowSocks[%s] proxy listening at: %s", s.Name(), s.Address()) + return nil +} + +// Close implements constant.InboundListener +func (s *ShadowSocks) Close() error { + return s.l.Close() +} + +var _ C.InboundListener = (*ShadowSocks)(nil) diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go new file mode 100644 index 00000000..745da45e --- /dev/null +++ b/listener/inbound/vmess.go @@ -0,0 +1,91 @@ +package inbound + +import ( + C "github.com/Dreamacro/clash/constant" + LC "github.com/Dreamacro/clash/listener/config" + "github.com/Dreamacro/clash/listener/sing_vmess" + "github.com/Dreamacro/clash/log" +) + +type VmessOption struct { + BaseOption + Users []VmessUser `inbound:"users"` +} + +type VmessUser struct { + Username string `inbound:"username,omitempty"` + UUID string `inbound:"uuid"` + AlterID int `inbound:"alterId"` +} + +func (o VmessOption) Equal(config C.InboundConfig) bool { + return optionToString(o) == optionToString(config) +} + +type Vmess struct { + *Base + config *VmessOption + l C.MultiAddrListener +} + +func NewVmess(options *VmessOption) (*Vmess, error) { + base, err := NewBase(&options.BaseOption) + if err != nil { + return nil, err + } + return &Vmess{ + Base: base, + config: options, + }, nil + +} + +// Config implements constant.InboundListener +func (v *Vmess) Config() C.InboundConfig { + return v.config +} + +// Address implements constant.InboundListener +func (v *Vmess) Address() string { + if v.l != nil { + for _, addr := range v.l.AddrList() { + return addr.String() + } + } + return "" +} + +// Listen implements constant.InboundListener +func (v *Vmess) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { + var err error + users := make([]LC.VmessUser, len(v.config.Users)) + for i, v := range v.config.Users { + users[i] = LC.VmessUser{ + Username: v.Username, + UUID: v.UUID, + AlterID: v.AlterID, + } + } + v.l, err = sing_vmess.New( + LC.VmessServer{ + Enable: true, + Listen: v.RawAddress(), + Users: users, + }, + tcpIn, + udpIn, + v.Additions()..., + ) + if err != nil { + return err + } + log.Infoln("Vmess[%s] proxy listening at: %s", v.Name(), v.Address()) + return nil +} + +// Close implements constant.InboundListener +func (v *Vmess) Close() error { + return v.l.Close() +} + +var _ C.InboundListener = (*Vmess)(nil) diff --git a/listener/listener.go b/listener/listener.go index 18b13b7f..99e16aea 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -16,6 +16,7 @@ import ( "github.com/Dreamacro/clash/listener/http" "github.com/Dreamacro/clash/listener/mixed" "github.com/Dreamacro/clash/listener/redir" + embedSS "github.com/Dreamacro/clash/listener/shadowsocks" "github.com/Dreamacro/clash/listener/sing_shadowsocks" "github.com/Dreamacro/clash/listener/sing_tun" "github.com/Dreamacro/clash/listener/sing_vmess" @@ -45,7 +46,7 @@ var ( tunnelUDPListeners = map[string]*tunnel.PacketConn{} inboundListeners = map[string]C.InboundListener{} tunLister *sing_tun.Listener - shadowSocksListener C.AdvanceListener + shadowSocksListener C.MultiAddrListener vmessListener *sing_vmess.Listener tuicListener *tuic.Listener autoRedirListener *autoredir.Listener @@ -263,10 +264,20 @@ func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, u } }() + var ssConfig LC.ShadowsocksServer + if addr, cipher, password, err := embedSS.ParseSSURL(shadowSocksConfig); err == nil { + ssConfig = LC.ShadowsocksServer{ + Enable: true, + Listen: addr, + Password: password, + Cipher: cipher, + } + } + shouldIgnore := false if shadowSocksListener != nil { - if shadowSocksListener.Config() != shadowSocksConfig { + if shadowSocksListener.Config() != ssConfig.String() { shadowSocksListener.Close() shadowSocksListener = nil } else { @@ -278,17 +289,20 @@ func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, u return } - if len(shadowSocksConfig) == 0 { + if !ssConfig.Enable { return } - listener, err := sing_shadowsocks.New(shadowSocksConfig, tcpIn, udpIn) + listener, err := sing_shadowsocks.New(ssConfig, tcpIn, udpIn) if err != nil { return } shadowSocksListener = listener + for _, addr := range shadowSocksListener.AddrList() { + log.Infoln("ShadowSocks proxy listening at: %s", addr.String()) + } return } @@ -303,10 +317,19 @@ func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- } }() + var vsConfig LC.VmessServer + if addr, username, password, err := sing_vmess.ParseVmessURL(vmessConfig); err == nil { + vsConfig = LC.VmessServer{ + Enable: true, + Listen: addr, + Users: []LC.VmessUser{{Username: username, UUID: password, AlterID: 1}}, + } + } + shouldIgnore := false if vmessListener != nil { - if vmessListener.Config() != vmessConfig { + if vmessListener.Config() != vsConfig.String() { vmessListener.Close() vmessListener = nil } else { @@ -318,17 +341,20 @@ func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- return } - if len(vmessConfig) == 0 { + if !vsConfig.Enable { return } - listener, err := sing_vmess.New(vmessConfig, tcpIn, udpIn) + listener, err := sing_vmess.New(vsConfig, tcpIn, udpIn) if err != nil { return } vmessListener = listener + for _, addr := range vmessListener.AddrList() { + log.Infoln("Vmess proxy listening at: %s", addr.String()) + } return } diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index 47beaf65..e8385873 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -38,10 +38,10 @@ func (l *Listener) Close() error { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-MIXED", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-MIXED"), + inbound.WithSpecialRules(""), + } } l, err := inbound.Listen("tcp", addr) if err != nil { diff --git a/listener/parse.go b/listener/parse.go index 6270daf1..eef1df16 100644 --- a/listener/parse.go +++ b/listener/parse.go @@ -55,6 +55,20 @@ func ParseListener(mapping map[string]any) (C.InboundListener, error) { return nil, err } listener, err = IN.NewMixed(mixedOption) + case "shadowsocks": + shadowsocksOption := &IN.ShadowSocksOption{} + err = decoder.Decode(mapping, shadowsocksOption) + if err != nil { + return nil, err + } + listener, err = IN.NewShadowSocks(shadowsocksOption) + case "vmess": + vmessOption := &IN.VmessOption{} + err = decoder.Decode(mapping, vmessOption) + if err != nil { + return nil, err + } + listener, err = IN.NewVmess(vmessOption) case "tuic": tuicOption := &IN.TuicOption{ MaxIdleTime: 15000, diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go index 6849605a..ad4a91bc 100644 --- a/listener/redir/tcp.go +++ b/listener/redir/tcp.go @@ -31,10 +31,10 @@ func (l *Listener) Close() error { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-REDIR", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-REDIR"), + inbound.WithSpecialRules(""), + } } l, err := net.Listen("tcp", addr) if err != nil { diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 9d4b13b3..21db5b63 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -6,14 +6,14 @@ import ( "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + LC "github.com/Dreamacro/clash/listener/config" "github.com/Dreamacro/clash/transport/shadowsocks/core" "github.com/Dreamacro/clash/transport/socks5" ) type Listener struct { closed bool - config string + config LC.ShadowsocksServer listeners []net.Listener udpListeners []*UDPListener pickCipher core.Cipher @@ -21,13 +21,8 @@ type Listener struct { var _listener *Listener -func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (*Listener, error) { - addr, cipher, password, err := ParseSSURL(config) - if err != nil { - return nil, err - } - - pickCipher, err := core.PickCipher(cipher, nil, password) +func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (*Listener, error) { + pickCipher, err := core.PickCipher(config.Cipher, nil, config.Password) if err != nil { return nil, err } @@ -35,7 +30,7 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter sl := &Listener{false, config, nil, nil, pickCipher} _listener = sl - for _, addr := range strings.Split(addr, ",") { + for _, addr := range strings.Split(config.Listen, ",") { addr := addr //UDP @@ -53,7 +48,6 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter sl.listeners = append(sl.listeners, l) go func() { - log.Infoln("ShadowSocks proxy listening at: %s", l.Addr().String()) for { c, err := l.Accept() if err != nil { @@ -89,7 +83,7 @@ func (l *Listener) Close() error { } func (l *Listener) Config() string { - return l.config + return l.config.String() } func (l *Listener) AddrList() (addrList []net.Addr) { @@ -102,7 +96,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext) { +func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { conn = l.pickCipher.StreamConn(conn) target, err := socks5.ReadAddr(conn, make([]byte, socks5.MaxAddrLen)) @@ -110,12 +104,12 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext) { _ = conn.Close() return } - in <- inbound.NewSocket(target, conn, C.SHADOWSOCKS) + in <- inbound.NewSocket(target, conn, C.SHADOWSOCKS, additions...) } -func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext) bool { +func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { if _listener != nil && _listener.pickCipher != nil { - go _listener.HandleConn(conn, in) + go _listener.HandleConn(conn, in, additions...) return true } return false diff --git a/listener/sing/context.go b/listener/sing/context.go new file mode 100644 index 00000000..f7aed851 --- /dev/null +++ b/listener/sing/context.go @@ -0,0 +1,24 @@ +package sing + +import ( + "context" + + "github.com/Dreamacro/clash/adapter/inbound" +) + +type contextKey string + +var ctxKeyAdditions = contextKey("Additions") + +func WithAdditions(ctx context.Context, additions ...inbound.Addition) context.Context { + return context.WithValue(ctx, ctxKeyAdditions, additions) +} + +func getAdditions(ctx context.Context) []inbound.Addition { + if v := ctx.Value(ctxKeyAdditions); v != nil { + if a, ok := v.([]inbound.Addition); ok { + return a + } + } + return nil +} diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 5b605373..e8aafa39 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -3,6 +3,7 @@ package sing import ( "context" "errors" + "golang.org/x/exp/slices" "net" "sync" "time" @@ -23,9 +24,10 @@ import ( const UDPTimeout = 5 * time.Minute type ListenerHandler struct { - TcpIn chan<- C.ConnContext - UdpIn chan<- C.PacketAdapter - Type C.Type + TcpIn chan<- C.ConnContext + UdpIn chan<- C.PacketAdapter + Type C.Type + Additions []inbound.Addition } type waitCloseConn struct { @@ -47,6 +49,11 @@ func (c *waitCloseConn) RemoteAddr() net.Addr { } func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + additions := h.Additions + if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { + additions = slices.Clone(additions) + additions = append(additions, ctxAdditions...) + } switch metadata.Destination.Fqdn { case vmess.MuxDestination.Fqdn: return vmess.HandleMuxConnection(ctx, conn, h) @@ -58,11 +65,17 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta wg := &sync.WaitGroup{} defer wg.Wait() // this goroutine must exit after conn.Close() wg.Add(1) - h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{Conn: conn, wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type) + + h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{Conn: conn, wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, additions...) return nil } func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { + additions := h.Additions + if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { + additions = slices.Clone(additions) + additions = append(additions, ctxAdditions...) + } defer func() { _ = conn.Close() }() mutex := sync.Mutex{} conn2 := conn // a new interface to set nil in defer @@ -90,7 +103,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. buff: buff, } select { - case h.UdpIn <- inbound.NewPacket(target, packet, h.Type): + case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...): default: } } diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index c0f62f78..d89085cd 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -9,6 +9,7 @@ import ( "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/common/sockopt" C "github.com/Dreamacro/clash/constant" + LC "github.com/Dreamacro/clash/listener/config" embedSS "github.com/Dreamacro/clash/listener/shadowsocks" "github.com/Dreamacro/clash/listener/sing" "github.com/Dreamacro/clash/log" @@ -24,7 +25,7 @@ import ( type Listener struct { closed bool - config string + config LC.ShadowsocksServer listeners []net.Listener udpListeners []net.PacketConn service shadowsocks.Service @@ -32,39 +33,46 @@ type Listener struct { var _listener *Listener -func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (C.AdvanceListener, error) { - addr, cipher, password, err := embedSS.ParseSSURL(config) - if err != nil { - return nil, err +func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (C.MultiAddrListener, error) { + var sl *Listener + var err error + if len(additions) == 0 { + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-SHADOWSOCKS"), + inbound.WithSpecialRules(""), + } + defer func() { + _listener = sl + }() } + udpTimeout := int64(sing.UDPTimeout.Seconds()) h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, - Type: C.SHADOWSOCKS, + TcpIn: tcpIn, + UdpIn: udpIn, + Type: C.SHADOWSOCKS, + Additions: additions, } - sl := &Listener{false, config, nil, nil, nil} + sl = &Listener{false, config, nil, nil, nil} switch { - case cipher == shadowsocks.MethodNone: + case config.Cipher == shadowsocks.MethodNone: sl.service = shadowsocks.NewNoneService(udpTimeout, h) - case common.Contains(shadowaead.List, cipher): - sl.service, err = shadowaead.NewService(cipher, nil, password, udpTimeout, h) - case common.Contains(shadowaead_2022.List, cipher): - sl.service, err = shadowaead_2022.NewServiceWithPassword(cipher, password, udpTimeout, h) + case common.Contains(shadowaead.List, config.Cipher): + sl.service, err = shadowaead.NewService(config.Cipher, nil, config.Password, udpTimeout, h) + case common.Contains(shadowaead_2022.List, config.Cipher): + sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h) default: - err = fmt.Errorf("shadowsocks: unsupported method: %s", cipher) + err = fmt.Errorf("shadowsocks: unsupported method: %s", config.Cipher) return embedSS.New(config, tcpIn, udpIn) } if err != nil { return nil, err } - _listener = sl - - for _, addr := range strings.Split(addr, ",") { + for _, addr := range strings.Split(config.Listen, ",") { addr := addr //UDP @@ -107,7 +115,6 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter sl.listeners = append(sl.listeners, l) go func() { - log.Infoln("ShadowSocks proxy listening at: %s", l.Addr().String()) for { c, err := l.Accept() if err != nil { @@ -145,7 +152,7 @@ func (l *Listener) Close() error { } func (l *Listener) Config() string { - return l.config + return l.config.String() } func (l *Listener) AddrList() (addrList []net.Addr) { @@ -158,8 +165,9 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext) { - err := l.service.NewConnection(context.TODO(), conn, metadata.Metadata{ +func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { + ctx := sing.WithAdditions(context.TODO(), additions...) + err := l.service.NewConnection(ctx, conn, metadata.Metadata{ Protocol: "shadowsocks", Source: metadata.ParseSocksaddr(conn.RemoteAddr().String()), }) @@ -169,10 +177,10 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext) { } } -func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext) bool { +func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { if _listener != nil && _listener.service != nil { - go _listener.HandleConn(conn, in) + go _listener.HandleConn(conn, in, additions...) return true } - return embedSS.HandleShadowSocks(conn, in) + return embedSS.HandleShadowSocks(conn, in, additions...) } diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index ca1ecdbd..859317f0 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -8,36 +8,51 @@ import ( "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" + LC "github.com/Dreamacro/clash/listener/config" "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" vmess "github.com/sagernet/sing-vmess" + "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/metadata" ) type Listener struct { closed bool - config string + config LC.VmessServer listeners []net.Listener service *vmess.Service[string] } var _listener *Listener -func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (*Listener, error) { - addr, username, password, err := parseVmessURL(config) - if err != nil { - return nil, err +func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (sl *Listener, err error) { + if len(additions) == 0 { + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-VMESS"), + inbound.WithSpecialRules(""), + } + defer func() { + _listener = sl + }() } - h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, - Type: C.VMESS, + TcpIn: tcpIn, + UdpIn: udpIn, + Type: C.VMESS, + Additions: additions, } service := vmess.NewService[string](h) - err = service.UpdateUsers([]string{username}, []string{password}, []int{1}) + err = service.UpdateUsers( + common.Map(config.Users, func(it LC.VmessUser) string { + return it.Username + }), + common.Map(config.Users, func(it LC.VmessUser) string { + return it.UUID + }), + common.Map(config.Users, func(it LC.VmessUser) int { + return it.AlterID + })) if err != nil { return nil, err } @@ -47,10 +62,9 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter return nil, err } - sl := &Listener{false, config, nil, service} - _listener = sl + sl = &Listener{false, config, nil, service} - for _, addr := range strings.Split(addr, ",") { + for _, addr := range strings.Split(config.Listen, ",") { addr := addr //TCP @@ -61,7 +75,6 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter sl.listeners = append(sl.listeners, l) go func() { - log.Infoln("Vmess proxy listening at: %s", l.Addr().String()) for { c, err := l.Accept() if err != nil { @@ -97,7 +110,7 @@ func (l *Listener) Close() error { } func (l *Listener) Config() string { - return l.config + return l.config.String() } func (l *Listener) AddrList() (addrList []net.Addr) { @@ -107,8 +120,9 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext) { - err := l.service.NewConnection(context.TODO(), conn, metadata.Metadata{ +func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { + ctx := sing.WithAdditions(context.TODO(), additions...) + err := l.service.NewConnection(ctx, conn, metadata.Metadata{ Protocol: "vmess", Source: metadata.ParseSocksaddr(conn.RemoteAddr().String()), }) @@ -118,15 +132,15 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext) { } } -func HandleVmess(conn net.Conn, in chan<- C.ConnContext) bool { +func HandleVmess(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { if _listener != nil && _listener.service != nil { - go _listener.HandleConn(conn, in) + go _listener.HandleConn(conn, in, additions...) return true } return false } -func parseVmessURL(s string) (addr, username, password string, err error) { +func ParseVmessURL(s string) (addr, username, password string, err error) { u, err := url.Parse(s) if err != nil { return diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index e2cb9d9a..cbaac987 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -36,10 +36,10 @@ func (l *Listener) Close() error { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-SOCKS", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-SOCKS"), + inbound.WithSpecialRules(""), + } } l, err := inbound.Listen("tcp", addr) if err != nil { diff --git a/listener/socks/udp.go b/listener/socks/udp.go index a718e21b..f375dade 100644 --- a/listener/socks/udp.go +++ b/listener/socks/udp.go @@ -35,10 +35,10 @@ func (l *UDPListener) Close() error { func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-SOCKS", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-SOCKS"), + inbound.WithSpecialRules(""), + } } l, err := net.ListenPacket("udp", addr) if err != nil { diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go index 59b8f090..198481f7 100644 --- a/listener/tproxy/tproxy.go +++ b/listener/tproxy/tproxy.go @@ -38,10 +38,10 @@ func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext, addition func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-TPROXY", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-TPROXY"), + inbound.WithSpecialRules(""), + } } l, err := net.Listen("tcp", addr) if err != nil { diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go index 9488a668..f85c9ea9 100644 --- a/listener/tproxy/udp.go +++ b/listener/tproxy/udp.go @@ -34,10 +34,10 @@ func (l *UDPListener) Close() error { func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-TPROXY", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-TPROXY"), + inbound.WithSpecialRules(""), + } } l, err := net.ListenPacket("udp", addr) if err != nil { diff --git a/listener/tuic/server.go b/listener/tuic/server.go index a5ed7151..8b928637 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -27,10 +27,10 @@ type Listener struct { func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { - additions = []inbound.Addition{{ - InName: "DEFAULT-TUIC", - SpecialRules: "", - }} + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-TUIC"), + inbound.WithSpecialRules(""), + } } cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) if err != nil {