chore: listeners support shadowsocks/vmess

This commit is contained in:
wwqgtxx 2022-12-05 10:12:53 +08:00
parent 2e22c712af
commit b7d976796a
24 changed files with 453 additions and 125 deletions

View file

@ -4,12 +4,20 @@ import (
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
) )
type Addition struct { type Addition func(metadata *C.Metadata)
InName string
SpecialRules string
}
func (a Addition) Apply(metadata *C.Metadata) { func (a Addition) Apply(metadata *C.Metadata) {
metadata.InName = a.InName a(metadata)
metadata.SpecialRules = a.SpecialRules }
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
}
} }

View file

@ -8,11 +8,10 @@ type Listener interface {
Close() error Close() error
} }
type AdvanceListener interface { type MultiAddrListener interface {
Close() error Close() error
Config() string Config() string
AddrList() (addrList []net.Addr) AddrList() (addrList []net.Addr)
HandleConn(conn net.Conn, in chan<- ConnContext)
} }
type InboundListener interface { type InboundListener interface {

View file

@ -121,7 +121,7 @@ tunnels:
- tcp/udp,127.0.0.1:6553,114.114.114.114:53,proxy - tcp/udp,127.0.0.1:6553,114.114.114.114:53,proxy
- tcp,127.0.0.1:6666,rds.mysql.com:3306,vpn - tcp,127.0.0.1:6666,rds.mysql.com:3306,vpn
# full yaml config # full yaml config
- network: [tcp, udp] - network: [ tcp, udp ]
address: 127.0.0.1:7777 address: 127.0.0.1:7777
target: target.com target: target.com
proxy: proxy proxy: proxy
@ -693,13 +693,32 @@ listeners:
type: tproxy type: tproxy
port: 10812 port: 10812
listen: 0.0.0.0 listen: 0.0.0.0
# udp: false # 默认 true
# rule: sub-rule # 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 - name: tuic-in-1
type: tuic type: tuic
port: 10813 port: 10815
listen: 0.0.0.0 listen: 0.0.0.0
# rule: sub-rule
# token: # token:
# - TOKEN # - TOKEN
# certificate: ./server.crt # certificate: ./server.crt

View file

@ -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) { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-REDIR", inbound.WithInName("DEFAULT-REDIR"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
l, err := net.Listen("tcp", addr) l, err := net.Listen("tcp", addr)
if err != nil { if err != nil {

View file

@ -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)
}

22
listener/config/vmess.go Normal file
View file

@ -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)
}

View file

@ -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) { func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool, additions ...inbound.Addition) (*Listener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-HTTP", inbound.WithInName("DEFAULT-HTTP"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
l, err := inbound.Listen("tcp", addr) l, err := inbound.Listen("tcp", addr)

View file

@ -87,10 +87,10 @@ func (o BaseOption) Equal(config C.InboundConfig) bool {
} }
func (o BaseOption) Additions() []inbound.Addition { func (o BaseOption) Additions() []inbound.Addition {
return []inbound.Addition{{ return []inbound.Addition{
InName: o.NameStr, inbound.WithInName(o.NameStr),
SpecialRules: o.SpecialRules, inbound.WithSpecialRules(o.SpecialRules),
}} }
} }
var _ C.InboundConfig = (*BaseOption)(nil) var _ C.InboundConfig = (*BaseOption)(nil)

View file

@ -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)

91
listener/inbound/vmess.go Normal file
View file

@ -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)

View file

@ -16,6 +16,7 @@ import (
"github.com/Dreamacro/clash/listener/http" "github.com/Dreamacro/clash/listener/http"
"github.com/Dreamacro/clash/listener/mixed" "github.com/Dreamacro/clash/listener/mixed"
"github.com/Dreamacro/clash/listener/redir" "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_shadowsocks"
"github.com/Dreamacro/clash/listener/sing_tun" "github.com/Dreamacro/clash/listener/sing_tun"
"github.com/Dreamacro/clash/listener/sing_vmess" "github.com/Dreamacro/clash/listener/sing_vmess"
@ -45,7 +46,7 @@ var (
tunnelUDPListeners = map[string]*tunnel.PacketConn{} tunnelUDPListeners = map[string]*tunnel.PacketConn{}
inboundListeners = map[string]C.InboundListener{} inboundListeners = map[string]C.InboundListener{}
tunLister *sing_tun.Listener tunLister *sing_tun.Listener
shadowSocksListener C.AdvanceListener shadowSocksListener C.MultiAddrListener
vmessListener *sing_vmess.Listener vmessListener *sing_vmess.Listener
tuicListener *tuic.Listener tuicListener *tuic.Listener
autoRedirListener *autoredir.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 shouldIgnore := false
if shadowSocksListener != nil { if shadowSocksListener != nil {
if shadowSocksListener.Config() != shadowSocksConfig { if shadowSocksListener.Config() != ssConfig.String() {
shadowSocksListener.Close() shadowSocksListener.Close()
shadowSocksListener = nil shadowSocksListener = nil
} else { } else {
@ -278,17 +289,20 @@ func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, u
return return
} }
if len(shadowSocksConfig) == 0 { if !ssConfig.Enable {
return return
} }
listener, err := sing_shadowsocks.New(shadowSocksConfig, tcpIn, udpIn) listener, err := sing_shadowsocks.New(ssConfig, tcpIn, udpIn)
if err != nil { if err != nil {
return return
} }
shadowSocksListener = listener shadowSocksListener = listener
for _, addr := range shadowSocksListener.AddrList() {
log.Infoln("ShadowSocks proxy listening at: %s", addr.String())
}
return 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 shouldIgnore := false
if vmessListener != nil { if vmessListener != nil {
if vmessListener.Config() != vmessConfig { if vmessListener.Config() != vsConfig.String() {
vmessListener.Close() vmessListener.Close()
vmessListener = nil vmessListener = nil
} else { } else {
@ -318,17 +341,20 @@ func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<-
return return
} }
if len(vmessConfig) == 0 { if !vsConfig.Enable {
return return
} }
listener, err := sing_vmess.New(vmessConfig, tcpIn, udpIn) listener, err := sing_vmess.New(vsConfig, tcpIn, udpIn)
if err != nil { if err != nil {
return return
} }
vmessListener = listener vmessListener = listener
for _, addr := range vmessListener.AddrList() {
log.Infoln("Vmess proxy listening at: %s", addr.String())
}
return return
} }

View file

@ -38,10 +38,10 @@ func (l *Listener) Close() error {
func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-MIXED", inbound.WithInName("DEFAULT-MIXED"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
l, err := inbound.Listen("tcp", addr) l, err := inbound.Listen("tcp", addr)
if err != nil { if err != nil {

View file

@ -55,6 +55,20 @@ func ParseListener(mapping map[string]any) (C.InboundListener, error) {
return nil, err return nil, err
} }
listener, err = IN.NewMixed(mixedOption) 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": case "tuic":
tuicOption := &IN.TuicOption{ tuicOption := &IN.TuicOption{
MaxIdleTime: 15000, MaxIdleTime: 15000,

View file

@ -31,10 +31,10 @@ func (l *Listener) Close() error {
func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-REDIR", inbound.WithInName("DEFAULT-REDIR"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
l, err := net.Listen("tcp", addr) l, err := net.Listen("tcp", addr)
if err != nil { if err != nil {

View file

@ -6,14 +6,14 @@ import (
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant" 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/shadowsocks/core"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
) )
type Listener struct { type Listener struct {
closed bool closed bool
config string config LC.ShadowsocksServer
listeners []net.Listener listeners []net.Listener
udpListeners []*UDPListener udpListeners []*UDPListener
pickCipher core.Cipher pickCipher core.Cipher
@ -21,13 +21,8 @@ type Listener struct {
var _listener *Listener var _listener *Listener
func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (*Listener, error) { func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (*Listener, error) {
addr, cipher, password, err := ParseSSURL(config) pickCipher, err := core.PickCipher(config.Cipher, nil, config.Password)
if err != nil {
return nil, err
}
pickCipher, err := core.PickCipher(cipher, nil, password)
if err != nil { if err != nil {
return nil, err 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} sl := &Listener{false, config, nil, nil, pickCipher}
_listener = sl _listener = sl
for _, addr := range strings.Split(addr, ",") { for _, addr := range strings.Split(config.Listen, ",") {
addr := addr addr := addr
//UDP //UDP
@ -53,7 +48,6 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter
sl.listeners = append(sl.listeners, l) sl.listeners = append(sl.listeners, l)
go func() { go func() {
log.Infoln("ShadowSocks proxy listening at: %s", l.Addr().String())
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
@ -89,7 +83,7 @@ func (l *Listener) Close() error {
} }
func (l *Listener) Config() string { func (l *Listener) Config() string {
return l.config return l.config.String()
} }
func (l *Listener) AddrList() (addrList []net.Addr) { func (l *Listener) AddrList() (addrList []net.Addr) {
@ -102,7 +96,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) {
return 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) conn = l.pickCipher.StreamConn(conn)
target, err := socks5.ReadAddr(conn, make([]byte, socks5.MaxAddrLen)) 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() _ = conn.Close()
return 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 { if _listener != nil && _listener.pickCipher != nil {
go _listener.HandleConn(conn, in) go _listener.HandleConn(conn, in, additions...)
return true return true
} }
return false return false

24
listener/sing/context.go Normal file
View file

@ -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
}

View file

@ -3,6 +3,7 @@ package sing
import ( import (
"context" "context"
"errors" "errors"
"golang.org/x/exp/slices"
"net" "net"
"sync" "sync"
"time" "time"
@ -23,9 +24,10 @@ import (
const UDPTimeout = 5 * time.Minute const UDPTimeout = 5 * time.Minute
type ListenerHandler struct { type ListenerHandler struct {
TcpIn chan<- C.ConnContext TcpIn chan<- C.ConnContext
UdpIn chan<- C.PacketAdapter UdpIn chan<- C.PacketAdapter
Type C.Type Type C.Type
Additions []inbound.Addition
} }
type waitCloseConn struct { 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 { 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 { switch metadata.Destination.Fqdn {
case vmess.MuxDestination.Fqdn: case vmess.MuxDestination.Fqdn:
return vmess.HandleMuxConnection(ctx, conn, h) return vmess.HandleMuxConnection(ctx, conn, h)
@ -58,11 +65,17 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
defer wg.Wait() // this goroutine must exit after conn.Close() defer wg.Wait() // this goroutine must exit after conn.Close()
wg.Add(1) 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 return nil
} }
func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { 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() }() defer func() { _ = conn.Close() }()
mutex := sync.Mutex{} mutex := sync.Mutex{}
conn2 := conn // a new interface to set nil in defer 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, buff: buff,
} }
select { select {
case h.UdpIn <- inbound.NewPacket(target, packet, h.Type): case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...):
default: default:
} }
} }

View file

@ -9,6 +9,7 @@ import (
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/sockopt" "github.com/Dreamacro/clash/common/sockopt"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
LC "github.com/Dreamacro/clash/listener/config"
embedSS "github.com/Dreamacro/clash/listener/shadowsocks" embedSS "github.com/Dreamacro/clash/listener/shadowsocks"
"github.com/Dreamacro/clash/listener/sing" "github.com/Dreamacro/clash/listener/sing"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
@ -24,7 +25,7 @@ import (
type Listener struct { type Listener struct {
closed bool closed bool
config string config LC.ShadowsocksServer
listeners []net.Listener listeners []net.Listener
udpListeners []net.PacketConn udpListeners []net.PacketConn
service shadowsocks.Service service shadowsocks.Service
@ -32,39 +33,46 @@ type Listener struct {
var _listener *Listener var _listener *Listener
func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (C.AdvanceListener, error) { func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (C.MultiAddrListener, error) {
addr, cipher, password, err := embedSS.ParseSSURL(config) var sl *Listener
if err != nil { var err error
return nil, err if len(additions) == 0 {
additions = []inbound.Addition{
inbound.WithInName("DEFAULT-SHADOWSOCKS"),
inbound.WithSpecialRules(""),
}
defer func() {
_listener = sl
}()
} }
udpTimeout := int64(sing.UDPTimeout.Seconds()) udpTimeout := int64(sing.UDPTimeout.Seconds())
h := &sing.ListenerHandler{ h := &sing.ListenerHandler{
TcpIn: tcpIn, TcpIn: tcpIn,
UdpIn: udpIn, UdpIn: udpIn,
Type: C.SHADOWSOCKS, Type: C.SHADOWSOCKS,
Additions: additions,
} }
sl := &Listener{false, config, nil, nil, nil} sl = &Listener{false, config, nil, nil, nil}
switch { switch {
case cipher == shadowsocks.MethodNone: case config.Cipher == shadowsocks.MethodNone:
sl.service = shadowsocks.NewNoneService(udpTimeout, h) sl.service = shadowsocks.NewNoneService(udpTimeout, h)
case common.Contains(shadowaead.List, cipher): case common.Contains(shadowaead.List, config.Cipher):
sl.service, err = shadowaead.NewService(cipher, nil, password, udpTimeout, h) sl.service, err = shadowaead.NewService(config.Cipher, nil, config.Password, udpTimeout, h)
case common.Contains(shadowaead_2022.List, cipher): case common.Contains(shadowaead_2022.List, config.Cipher):
sl.service, err = shadowaead_2022.NewServiceWithPassword(cipher, password, udpTimeout, h) sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h)
default: default:
err = fmt.Errorf("shadowsocks: unsupported method: %s", cipher) err = fmt.Errorf("shadowsocks: unsupported method: %s", config.Cipher)
return embedSS.New(config, tcpIn, udpIn) return embedSS.New(config, tcpIn, udpIn)
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
_listener = sl for _, addr := range strings.Split(config.Listen, ",") {
for _, addr := range strings.Split(addr, ",") {
addr := addr addr := addr
//UDP //UDP
@ -107,7 +115,6 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter
sl.listeners = append(sl.listeners, l) sl.listeners = append(sl.listeners, l)
go func() { go func() {
log.Infoln("ShadowSocks proxy listening at: %s", l.Addr().String())
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
@ -145,7 +152,7 @@ func (l *Listener) Close() error {
} }
func (l *Listener) Config() string { func (l *Listener) Config() string {
return l.config return l.config.String()
} }
func (l *Listener) AddrList() (addrList []net.Addr) { func (l *Listener) AddrList() (addrList []net.Addr) {
@ -158,8 +165,9 @@ func (l *Listener) AddrList() (addrList []net.Addr) {
return 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) {
err := l.service.NewConnection(context.TODO(), conn, metadata.Metadata{ ctx := sing.WithAdditions(context.TODO(), additions...)
err := l.service.NewConnection(ctx, conn, metadata.Metadata{
Protocol: "shadowsocks", Protocol: "shadowsocks",
Source: metadata.ParseSocksaddr(conn.RemoteAddr().String()), 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 { if _listener != nil && _listener.service != nil {
go _listener.HandleConn(conn, in) go _listener.HandleConn(conn, in, additions...)
return true return true
} }
return embedSS.HandleShadowSocks(conn, in) return embedSS.HandleShadowSocks(conn, in, additions...)
} }

View file

@ -8,36 +8,51 @@ import (
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
LC "github.com/Dreamacro/clash/listener/config"
"github.com/Dreamacro/clash/listener/sing" "github.com/Dreamacro/clash/listener/sing"
"github.com/Dreamacro/clash/log"
vmess "github.com/sagernet/sing-vmess" vmess "github.com/sagernet/sing-vmess"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/metadata"
) )
type Listener struct { type Listener struct {
closed bool closed bool
config string config LC.VmessServer
listeners []net.Listener listeners []net.Listener
service *vmess.Service[string] service *vmess.Service[string]
} }
var _listener *Listener var _listener *Listener
func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (*Listener, error) { func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (sl *Listener, err error) {
addr, username, password, err := parseVmessURL(config) if len(additions) == 0 {
if err != nil { additions = []inbound.Addition{
return nil, err inbound.WithInName("DEFAULT-VMESS"),
inbound.WithSpecialRules(""),
}
defer func() {
_listener = sl
}()
} }
h := &sing.ListenerHandler{ h := &sing.ListenerHandler{
TcpIn: tcpIn, TcpIn: tcpIn,
UdpIn: udpIn, UdpIn: udpIn,
Type: C.VMESS, Type: C.VMESS,
Additions: additions,
} }
service := vmess.NewService[string](h) 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 { if err != nil {
return nil, err return nil, err
} }
@ -47,10 +62,9 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter
return nil, err return nil, err
} }
sl := &Listener{false, config, nil, service} sl = &Listener{false, config, nil, service}
_listener = sl
for _, addr := range strings.Split(addr, ",") { for _, addr := range strings.Split(config.Listen, ",") {
addr := addr addr := addr
//TCP //TCP
@ -61,7 +75,6 @@ func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter
sl.listeners = append(sl.listeners, l) sl.listeners = append(sl.listeners, l)
go func() { go func() {
log.Infoln("Vmess proxy listening at: %s", l.Addr().String())
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
@ -97,7 +110,7 @@ func (l *Listener) Close() error {
} }
func (l *Listener) Config() string { func (l *Listener) Config() string {
return l.config return l.config.String()
} }
func (l *Listener) AddrList() (addrList []net.Addr) { func (l *Listener) AddrList() (addrList []net.Addr) {
@ -107,8 +120,9 @@ func (l *Listener) AddrList() (addrList []net.Addr) {
return 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) {
err := l.service.NewConnection(context.TODO(), conn, metadata.Metadata{ ctx := sing.WithAdditions(context.TODO(), additions...)
err := l.service.NewConnection(ctx, conn, metadata.Metadata{
Protocol: "vmess", Protocol: "vmess",
Source: metadata.ParseSocksaddr(conn.RemoteAddr().String()), 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 { if _listener != nil && _listener.service != nil {
go _listener.HandleConn(conn, in) go _listener.HandleConn(conn, in, additions...)
return true return true
} }
return false 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) u, err := url.Parse(s)
if err != nil { if err != nil {
return return

View file

@ -36,10 +36,10 @@ func (l *Listener) Close() error {
func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-SOCKS", inbound.WithInName("DEFAULT-SOCKS"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
l, err := inbound.Listen("tcp", addr) l, err := inbound.Listen("tcp", addr)
if err != nil { if err != nil {

View file

@ -35,10 +35,10 @@ func (l *UDPListener) Close() error {
func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) { func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-SOCKS", inbound.WithInName("DEFAULT-SOCKS"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
l, err := net.ListenPacket("udp", addr) l, err := net.ListenPacket("udp", addr)
if err != nil { if err != nil {

View file

@ -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) { func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-TPROXY", inbound.WithInName("DEFAULT-TPROXY"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
l, err := net.Listen("tcp", addr) l, err := net.Listen("tcp", addr)
if err != nil { if err != nil {

View file

@ -34,10 +34,10 @@ func (l *UDPListener) Close() error {
func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) { func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-TPROXY", inbound.WithInName("DEFAULT-TPROXY"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
l, err := net.ListenPacket("udp", addr) l, err := net.ListenPacket("udp", addr)
if err != nil { if err != nil {

View file

@ -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) { func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) {
if len(additions) == 0 { if len(additions) == 0 {
additions = []inbound.Addition{{ additions = []inbound.Addition{
InName: "DEFAULT-TUIC", inbound.WithInName("DEFAULT-TUIC"),
SpecialRules: "", inbound.WithSpecialRules(""),
}} }
} }
cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) cert, err := CN.ParseCert(config.Certificate, config.PrivateKey)
if err != nil { if err != nil {