chore: rebuild InboundListener

This commit is contained in:
wwqgtxx 2022-12-04 21:53:13 +08:00
parent 8144373725
commit 62226e8b3d
14 changed files with 138 additions and 96 deletions

View file

@ -2,17 +2,13 @@ package adapter
import ( import (
"fmt" "fmt"
"strings"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/common/structure"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
) )
var keyReplacer = strings.NewReplacer("_", "-")
func ParseProxy(mapping map[string]any) (C.Proxy, error) { func ParseProxy(mapping map[string]any) (C.Proxy, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true, KeyReplacer: keyReplacer}) decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true, KeyReplacer: structure.DefaultKeyReplacer})
proxyType, existType := mapping["type"].(string) proxyType, existType := mapping["type"].(string)
if !existType { if !existType {
return nil, fmt.Errorf("missing type") return nil, fmt.Errorf("missing type")

View file

@ -16,6 +16,8 @@ type Option struct {
KeyReplacer *strings.Replacer KeyReplacer *strings.Replacer
} }
var DefaultKeyReplacer = strings.NewReplacer("_", "-")
// Decoder is the core of structure // Decoder is the core of structure
type Decoder struct { type Decoder struct {
option *Option option *Option

View file

@ -200,7 +200,7 @@ type Config struct {
SubRules map[string][]C.Rule SubRules map[string][]C.Rule
Users []auth.AuthUser Users []auth.AuthUser
Proxies map[string]C.Proxy Proxies map[string]C.Proxy
Listeners map[string]C.NewListener Listeners map[string]C.InboundListener
Providers map[string]providerTypes.ProxyProvider Providers map[string]providerTypes.ProxyProvider
RuleProviders map[string]providerTypes.RuleProvider RuleProviders map[string]providerTypes.RuleProvider
Tunnels []tunnel.Tunnel Tunnels []tunnel.Tunnel
@ -694,8 +694,8 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
return proxies, providersMap, nil return proxies, providersMap, nil
} }
func parseListeners(cfg *RawConfig) (listeners map[string]C.NewListener, err error) { func parseListeners(cfg *RawConfig) (listeners map[string]C.InboundListener, err error) {
listeners = make(map[string]C.NewListener) listeners = make(map[string]C.InboundListener)
for index, mapping := range cfg.Listeners { for index, mapping := range cfg.Listeners {
listener, err := L.ParseListener(mapping) listener, err := L.ParseListener(mapping)
if err != nil { if err != nil {

View file

@ -14,11 +14,16 @@ type AdvanceListener interface {
HandleConn(conn net.Conn, in chan<- ConnContext) HandleConn(conn net.Conn, in chan<- ConnContext)
} }
type NewListener interface { type InboundListener interface {
Name() string Name() string
Listen(tcpIn chan<- ConnContext, udpIn chan<- PacketAdapter) error Listen(tcpIn chan<- ConnContext, udpIn chan<- PacketAdapter) error
Close() error Close() error
Address() string Address() string
RawAddress() string RawAddress() string
Config() string Config() InboundConfig
}
type InboundConfig interface {
Name() string
Equal(config InboundConfig) bool
} }

View file

@ -135,31 +135,11 @@ func GetGeneral() *config.General {
return general return general
} }
func updateListeners(listeners map[string]C.NewListener) { func updateListeners(listeners map[string]C.InboundListener) {
tcpIn := tunnel.TCPIn() tcpIn := tunnel.TCPIn()
udpIn := tunnel.UDPIn() udpIn := tunnel.UDPIn()
skipNames := map[string]struct{}{} listener.PatchInboundListeners(listeners, tcpIn, udpIn, true)
for name, oldListener := range tunnel.Listeners() {
if newListener, ok := listeners[name]; ok {
if newListener.Config() == oldListener.Config() {
listeners[name] = oldListener
skipNames[name] = struct{}{}
continue
}
}
_ = oldListener.Close()
}
for name, newListener := range listeners {
if _, ok := skipNames[name]; ok {
continue
}
if err := newListener.Listen(tcpIn, udpIn); err != nil {
log.Errorln("Listener %s listen err: %s", newListener.Name(), err.Error())
}
}
tunnel.UpdateListeners(listeners)
} }
func updateExperimental(c *config.Config) { func updateExperimental(c *config.Config) {

View file

@ -26,7 +26,7 @@ func NewBase(options *BaseOption) (*Base, error) {
return nil, err return nil, err
} }
return &Base{ return &Base{
name: options.Name, name: options.Name(),
listenAddr: addr, listenAddr: addr,
preferRulesName: options.PreferRulesName, preferRulesName: options.PreferRulesName,
port: options.Port, port: options.Port,
@ -34,44 +34,54 @@ func NewBase(options *BaseOption) (*Base, error) {
}, nil }, nil
} }
// Config implements constant.NewListener // Config implements constant.InboundListener
func (b *Base) Config() string { func (b *Base) Config() C.InboundConfig {
return optionToString(b.config) return b.config
} }
// Address implements constant.NewListener // Address implements constant.InboundListener
func (b *Base) Address() string { func (b *Base) Address() string {
return b.RawAddress() return b.RawAddress()
} }
// Close implements constant.NewListener // Close implements constant.InboundListener
func (*Base) Close() error { func (*Base) Close() error {
return nil return nil
} }
// Name implements constant.NewListener // Name implements constant.InboundListener
func (b *Base) Name() string { func (b *Base) Name() string {
return b.name return b.name
} }
// RawAddress implements constant.NewListener // RawAddress implements constant.InboundListener
func (b *Base) RawAddress() string { func (b *Base) RawAddress() string {
return net.JoinHostPort(b.listenAddr.String(), strconv.Itoa(int(b.port))) return net.JoinHostPort(b.listenAddr.String(), strconv.Itoa(int(b.port)))
} }
// Listen implements constant.NewListener // Listen implements constant.InboundListener
func (*Base) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { func (*Base) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
return nil return nil
} }
var _ C.InboundListener = (*Base)(nil)
type BaseOption struct { type BaseOption struct {
Name string `inbound:"name"` NameStr string `inbound:"name"`
Listen string `inbound:"listen,omitempty"` Listen string `inbound:"listen,omitempty"`
Port int `inbound:"port"` Port int `inbound:"port"`
PreferRulesName string `inbound:"rule,omitempty"` PreferRulesName string `inbound:"rule,omitempty"`
} }
var _ C.NewListener = (*Base)(nil) func (o BaseOption) Name() string {
return o.NameStr
}
func (o BaseOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
}
var _ C.InboundConfig = (*BaseOption)(nil)
func optionToString(option any) string { func optionToString(option any) string {
str, _ := json.Marshal(option) str, _ := json.Marshal(option)

View file

@ -9,6 +9,11 @@ import (
type HTTPOption struct { type HTTPOption struct {
BaseOption BaseOption
} }
func (o HTTPOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
}
type HTTP struct { type HTTP struct {
*Base *Base
config *HTTPOption config *HTTPOption
@ -26,17 +31,17 @@ func NewHTTP(options *HTTPOption) (*HTTP, error) {
}, nil }, nil
} }
// Config implements constant.NewListener // Config implements constant.InboundListener
func (h *HTTP) Config() string { func (h *HTTP) Config() C.InboundConfig {
return optionToString(h.config) return h.config
} }
// Address implements constant.NewListener // Address implements constant.InboundListener
func (h *HTTP) Address() string { func (h *HTTP) Address() string {
return h.l.Address() return h.l.Address()
} }
// Listen implements constant.NewListener // Listen implements constant.InboundListener
func (h *HTTP) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { func (h *HTTP) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error var err error
h.l, err = http.NewWithInfos(h.RawAddress(), h.name, h.preferRulesName, tcpIn) h.l, err = http.NewWithInfos(h.RawAddress(), h.name, h.preferRulesName, tcpIn)
@ -47,7 +52,7 @@ func (h *HTTP) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter)
return nil return nil
} }
// Close implements constant.NewListener // Close implements constant.InboundListener
func (h *HTTP) Close() error { func (h *HTTP) Close() error {
if h.l != nil { if h.l != nil {
return h.l.Close() return h.l.Close()
@ -55,4 +60,4 @@ func (h *HTTP) Close() error {
return nil return nil
} }
var _ C.NewListener = (*HTTP)(nil) var _ C.InboundListener = (*HTTP)(nil)

View file

@ -12,7 +12,11 @@ import (
type MixedOption struct { type MixedOption struct {
BaseOption BaseOption
UDP *bool `inbound:"udp,omitempty"` UDP bool `inbound:"udp,omitempty"`
}
func (o MixedOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
} }
type Mixed struct { type Mixed struct {
@ -31,21 +35,21 @@ func NewMixed(options *MixedOption) (*Mixed, error) {
return &Mixed{ return &Mixed{
Base: base, Base: base,
config: options, config: options,
udp: options.UDP == nil || *options.UDP, udp: options.UDP,
}, nil }, nil
} }
// Config implements constant.NewListener // Config implements constant.InboundListener
func (m *Mixed) Config() string { func (m *Mixed) Config() C.InboundConfig {
return optionToString(m.config) return m.config
} }
// Address implements constant.NewListener // Address implements constant.InboundListener
func (m *Mixed) Address() string { func (m *Mixed) Address() string {
return m.l.Address() return m.l.Address()
} }
// Listen implements constant.NewListener // Listen implements constant.InboundListener
func (m *Mixed) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { func (m *Mixed) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error var err error
m.l, err = mixed.NewWithInfos(m.RawAddress(), m.name, m.preferRulesName, tcpIn) m.l, err = mixed.NewWithInfos(m.RawAddress(), m.name, m.preferRulesName, tcpIn)
@ -62,7 +66,7 @@ func (m *Mixed) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter)
return nil return nil
} }
// Close implements constant.NewListener // Close implements constant.InboundListener
func (m *Mixed) Close() error { func (m *Mixed) Close() error {
var err error var err error
if m.l != nil { if m.l != nil {
@ -82,4 +86,4 @@ func (m *Mixed) Close() error {
return err return err
} }
var _ C.NewListener = (*Mixed)(nil) var _ C.InboundListener = (*Mixed)(nil)

View file

@ -10,6 +10,10 @@ type RedirOption struct {
BaseOption BaseOption
} }
func (o RedirOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
}
type Redir struct { type Redir struct {
*Base *Base
config *RedirOption config *RedirOption
@ -27,17 +31,17 @@ func NewRedir(options *RedirOption) (*Redir, error) {
}, nil }, nil
} }
// Config implements constant.NewListener // Config implements constant.InboundListener
func (r *Redir) Config() string { func (r *Redir) Config() C.InboundConfig {
return optionToString(r.config) return r.config
} }
// Address implements constant.NewListener // Address implements constant.InboundListener
func (r *Redir) Address() string { func (r *Redir) Address() string {
return r.l.Address() return r.l.Address()
} }
// Listen implements constant.NewListener // Listen implements constant.InboundListener
func (r *Redir) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { func (r *Redir) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error var err error
r.l, err = redir.NewWithInfos(r.Address(), r.name, r.preferRulesName, tcpIn) r.l, err = redir.NewWithInfos(r.Address(), r.name, r.preferRulesName, tcpIn)
@ -48,7 +52,7 @@ func (r *Redir) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter)
return nil return nil
} }
// Close implements constant.NewListener // Close implements constant.InboundListener
func (r *Redir) Close() error { func (r *Redir) Close() error {
if r.l != nil { if r.l != nil {
r.l.Close() r.l.Close()
@ -56,4 +60,4 @@ func (r *Redir) Close() error {
return nil return nil
} }
var _ C.NewListener = (*Redir)(nil) var _ C.InboundListener = (*Redir)(nil)

View file

@ -9,7 +9,11 @@ import (
type SocksOption struct { type SocksOption struct {
BaseOption BaseOption
UDP *bool `inbound:"udp,omitempty"` UDP bool `inbound:"udp,omitempty"`
}
func (o SocksOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
} }
type Socks struct { type Socks struct {
@ -28,16 +32,16 @@ func NewSocks(options *SocksOption) (*Socks, error) {
return &Socks{ return &Socks{
Base: base, Base: base,
config: options, config: options,
udp: options.UDP == nil || *options.UDP, udp: options.UDP,
}, nil }, nil
} }
// Config implements constant.NewListener // Config implements constant.InboundListener
func (s *Socks) Config() string { func (s *Socks) Config() C.InboundConfig {
return optionToString(s.config) return s.config
} }
// Close implements constant.NewListener // Close implements constant.InboundListener
func (s *Socks) Close() error { func (s *Socks) Close() error {
var err error var err error
if s.stl != nil { if s.stl != nil {
@ -58,12 +62,12 @@ func (s *Socks) Close() error {
return err return err
} }
// Address implements constant.NewListener // Address implements constant.InboundListener
func (s *Socks) Address() string { func (s *Socks) Address() string {
return s.stl.Address() return s.stl.Address()
} }
// Listen implements constant.NewListener // Listen implements constant.InboundListener
func (s *Socks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { func (s *Socks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error var err error
if s.stl, err = socks.NewWithInfos(s.RawAddress(), s.name, s.preferRulesName, tcpIn); err != nil { if s.stl, err = socks.NewWithInfos(s.RawAddress(), s.name, s.preferRulesName, tcpIn); err != nil {
@ -79,4 +83,4 @@ func (s *Socks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter)
return nil return nil
} }
var _ C.NewListener = (*Socks)(nil) var _ C.InboundListener = (*Socks)(nil)

View file

@ -10,7 +10,11 @@ import (
type TProxyOption struct { type TProxyOption struct {
BaseOption BaseOption
UDP *bool `inbound:"udp,omitempty"` UDP bool `inbound:"udp,omitempty"`
}
func (o TProxyOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
} }
type TProxy struct { type TProxy struct {
@ -29,22 +33,22 @@ func NewTProxy(options *TProxyOption) (*TProxy, error) {
return &TProxy{ return &TProxy{
Base: base, Base: base,
config: options, config: options,
udp: options.UDP == nil || *options.UDP, udp: options.UDP,
}, nil }, nil
} }
// Config implements constant.NewListener // Config implements constant.InboundListener
func (t *TProxy) Config() string { func (t *TProxy) Config() C.InboundConfig {
return optionToString(t.config) return t.config
} }
// Address implements constant.NewListener // Address implements constant.InboundListener
func (t *TProxy) Address() string { func (t *TProxy) Address() string {
return t.lTCP.Address() return t.lTCP.Address()
} }
// Listen implements constant.NewListener // Listen implements constant.InboundListener
func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error var err error
t.lTCP, err = tproxy.NewWithInfos(t.RawAddress(), t.name, t.preferRulesName, tcpIn) t.lTCP, err = tproxy.NewWithInfos(t.RawAddress(), t.name, t.preferRulesName, tcpIn)
@ -64,7 +68,7 @@ func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter
return nil return nil
} }
// Close implements constant.NewListener // Close implements constant.InboundListener
func (t *TProxy) Close() error { func (t *TProxy) Close() error {
var tcpErr error var tcpErr error
var udpErr error var udpErr error
@ -87,4 +91,4 @@ func (t *TProxy) Close() error {
return nil return nil
} }
var _ C.NewListener = (*TProxy)(nil) var _ C.InboundListener = (*TProxy)(nil)

View file

@ -43,6 +43,7 @@ var (
mixedUDPLister *socks.UDPListener mixedUDPLister *socks.UDPListener
tunnelTCPListeners = map[string]*tunnel.Listener{} tunnelTCPListeners = map[string]*tunnel.Listener{}
tunnelUDPListeners = map[string]*tunnel.PacketConn{} tunnelUDPListeners = map[string]*tunnel.PacketConn{}
inboundListeners = map[string]C.InboundListener{}
tunLister *sing_tun.Listener tunLister *sing_tun.Listener
shadowSocksListener C.AdvanceListener shadowSocksListener C.AdvanceListener
vmessListener *sing_vmess.Listener vmessListener *sing_vmess.Listener
@ -58,6 +59,7 @@ var (
tproxyMux sync.Mutex tproxyMux sync.Mutex
mixedMux sync.Mutex mixedMux sync.Mutex
tunnelMux sync.Mutex tunnelMux sync.Mutex
inboundMux sync.Mutex
tunMux sync.Mutex tunMux sync.Mutex
ssMux sync.Mutex ssMux sync.Mutex
vmessMux sync.Mutex vmessMux sync.Mutex
@ -682,6 +684,35 @@ func PatchTunnel(tunnels []tunnel.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan
} }
} }
func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, dropOld bool) {
inboundMux.Lock()
defer inboundMux.Unlock()
for name, newListener := range newListenerMap {
if oldListener, ok := inboundListeners[name]; ok {
if !oldListener.Config().Equal(newListener.Config()) {
_ = oldListener.Close()
} else {
continue
}
}
if err := newListener.Listen(tcpIn, udpIn); err != nil {
log.Errorln("Listener %s listen err: %s", name, err.Error())
continue
}
inboundListeners[name] = newListener
}
if dropOld {
for name, oldListener := range inboundListeners {
if _, ok := newListenerMap[name]; !ok {
_ = oldListener.Close()
delete(inboundListeners, name)
}
}
}
}
// GetPorts return the ports of proxy servers // GetPorts return the ports of proxy servers
func GetPorts() *Ports { func GetPorts() *Ports {
ports := &Ports{} ports := &Ports{}

View file

@ -2,29 +2,26 @@ package listener
import ( import (
"fmt" "fmt"
"strings"
"github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/common/structure"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
IN "github.com/Dreamacro/clash/listener/inbound" IN "github.com/Dreamacro/clash/listener/inbound"
) )
var keyReplacer = strings.NewReplacer("_", "-") func ParseListener(mapping map[string]any) (C.InboundListener, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "inbound", WeaklyTypedInput: true, KeyReplacer: structure.DefaultKeyReplacer})
func ParseListener(mapping map[string]any) (C.NewListener, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "inbound", WeaklyTypedInput: true, KeyReplacer: keyReplacer})
proxyType, existType := mapping["type"].(string) proxyType, existType := mapping["type"].(string)
if !existType { if !existType {
return nil, fmt.Errorf("missing type") return nil, fmt.Errorf("missing type")
} }
var ( var (
listener C.NewListener listener C.InboundListener
err error err error
) )
switch proxyType { switch proxyType {
case "socks": case "socks":
socksOption := &IN.SocksOption{} socksOption := &IN.SocksOption{UDP: true}
err = decoder.Decode(mapping, socksOption) err = decoder.Decode(mapping, socksOption)
if err != nil { if err != nil {
return nil, err return nil, err
@ -38,7 +35,7 @@ func ParseListener(mapping map[string]any) (C.NewListener, error) {
} }
listener, err = IN.NewHTTP(httpOption) listener, err = IN.NewHTTP(httpOption)
case "tproxy": case "tproxy":
tproxyOption := &IN.TProxyOption{} tproxyOption := &IN.TProxyOption{UDP: true}
err = decoder.Decode(mapping, tproxyOption) err = decoder.Decode(mapping, tproxyOption)
if err != nil { if err != nil {
return nil, err return nil, err
@ -52,7 +49,7 @@ func ParseListener(mapping map[string]any) (C.NewListener, error) {
} }
listener, err = IN.NewRedir(redirOption) listener, err = IN.NewRedir(redirOption)
case "mixed": case "mixed":
mixedOption := &IN.MixedOption{} mixedOption := &IN.MixedOption{UDP: true}
err = decoder.Decode(mapping, mixedOption) err = decoder.Decode(mapping, mixedOption)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -29,7 +29,7 @@ var (
udpQueue = make(chan C.PacketAdapter, 200) udpQueue = make(chan C.PacketAdapter, 200)
natTable = nat.New() natTable = nat.New()
rules []C.Rule rules []C.Rule
listeners = make(map[string]C.NewListener) listeners = make(map[string]C.InboundListener)
subRules map[string][]C.Rule subRules map[string][]C.Rule
proxies = make(map[string]C.Proxy) proxies = make(map[string]C.Proxy)
providers map[string]provider.ProxyProvider providers map[string]provider.ProxyProvider
@ -87,7 +87,7 @@ func Rules() []C.Rule {
return rules return rules
} }
func Listeners() map[string]C.NewListener { func Listeners() map[string]C.InboundListener {
return listeners return listeners
} }
@ -123,7 +123,7 @@ func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]provid
configMux.Unlock() configMux.Unlock()
} }
func UpdateListeners(newListeners map[string]C.NewListener) { func UpdateListeners(newListeners map[string]C.InboundListener) {
configMux.Lock() configMux.Lock()
defer configMux.Unlock() defer configMux.Unlock()
listeners = newListeners listeners = newListeners