diff --git a/constant/listener.go b/constant/listener.go index c5e327ec..a6696af4 100644 --- a/constant/listener.go +++ b/constant/listener.go @@ -20,4 +20,5 @@ type NewListener interface { Close() error Address() string RawAddress() string + Config() string } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 9a1003ef..94db8c0f 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -138,13 +138,25 @@ func GetGeneral() *config.General { func updateListeners(listeners map[string]C.NewListener) { tcpIn := tunnel.TCPIn() udpIn := tunnel.UDPIn() - for _, listener := range tunnel.Listeners() { - _ = listener.Close() + + skipNames := map[string]struct{}{} + 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 _, listener := range listeners { - if err := listener.Listen(tcpIn, udpIn); err != nil { - log.Errorln("Listener %s listen err: %s", listener.Name(), err.Error()) + 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) diff --git a/listener/inbound/base.go b/listener/inbound/base.go index 10008843..ebe65309 100644 --- a/listener/inbound/base.go +++ b/listener/inbound/base.go @@ -1,6 +1,7 @@ package inbound import ( + "encoding/json" "net" "net/netip" "strconv" @@ -9,6 +10,7 @@ import ( ) type Base struct { + config *BaseOption name string preferRulesName string listenAddr netip.Addr @@ -28,9 +30,15 @@ func NewBase(options *BaseOption) (*Base, error) { listenAddr: addr, preferRulesName: options.PreferRulesName, port: options.Port, + config: options, }, nil } +// Config implements constant.NewListener +func (b *Base) Config() string { + return optionToString(b.config) +} + // Address implements constant.NewListener func (b *Base) Address() string { return b.RawAddress() @@ -51,7 +59,7 @@ func (b *Base) RawAddress() string { return net.JoinHostPort(b.listenAddr.String(), strconv.Itoa(int(b.port))) } -// ReCreate implements constant.NewListener +// Listen implements constant.NewListener func (*Base) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { return nil } @@ -64,3 +72,8 @@ type BaseOption struct { } var _ C.NewListener = (*Base)(nil) + +func optionToString(option any) string { + str, _ := json.Marshal(option) + return string(str) +} diff --git a/listener/inbound/http.go b/listener/inbound/http.go index 1092d2f9..6f04b4b6 100644 --- a/listener/inbound/http.go +++ b/listener/inbound/http.go @@ -11,7 +11,8 @@ type HTTPOption struct { } type HTTP struct { *Base - l *http.Listener + config *HTTPOption + l *http.Listener } func NewHTTP(options *HTTPOption) (*HTTP, error) { @@ -20,16 +21,22 @@ func NewHTTP(options *HTTPOption) (*HTTP, error) { return nil, err } return &HTTP{ - Base: base, + Base: base, + config: options, }, nil } +// Config implements constant.NewListener +func (h *HTTP) Config() string { + return optionToString(h.config) +} + // Address implements constant.NewListener func (h *HTTP) Address() string { return h.l.Address() } -// ReCreate implements constant.NewListener +// Listen implements constant.NewListener func (h *HTTP) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { var err error h.l, err = http.NewWithInfos(h.RawAddress(), h.name, h.preferRulesName, tcpIn) diff --git a/listener/inbound/mixed.go b/listener/inbound/mixed.go index 949064fe..01120dd7 100644 --- a/listener/inbound/mixed.go +++ b/listener/inbound/mixed.go @@ -17,9 +17,10 @@ type MixedOption struct { type Mixed struct { *Base - l *mixed.Listener - lUDP *socks.UDPListener - udp bool + config *MixedOption + l *mixed.Listener + lUDP *socks.UDPListener + udp bool } func NewMixed(options *MixedOption) (*Mixed, error) { @@ -28,17 +29,23 @@ func NewMixed(options *MixedOption) (*Mixed, error) { return nil, err } return &Mixed{ - Base: base, - udp: options.UDP == nil || *options.UDP, + Base: base, + config: options, + udp: options.UDP == nil || *options.UDP, }, nil } +// Config implements constant.NewListener +func (m *Mixed) Config() string { + return optionToString(m.config) +} + // Address implements constant.NewListener func (m *Mixed) Address() string { return m.l.Address() } -// ReCreate implements constant.NewListener +// Listen implements constant.NewListener func (m *Mixed) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { var err error m.l, err = mixed.NewWithInfos(m.RawAddress(), m.name, m.preferRulesName, tcpIn) diff --git a/listener/inbound/redir.go b/listener/inbound/redir.go index 029e103a..6d6ca4f0 100644 --- a/listener/inbound/redir.go +++ b/listener/inbound/redir.go @@ -12,7 +12,8 @@ type RedirOption struct { type Redir struct { *Base - l *redir.Listener + config *RedirOption + l *redir.Listener } func NewRedir(options *RedirOption) (*Redir, error) { @@ -21,16 +22,22 @@ func NewRedir(options *RedirOption) (*Redir, error) { return nil, err } return &Redir{ - Base: base, + Base: base, + config: options, }, nil } +// Config implements constant.NewListener +func (r *Redir) Config() string { + return optionToString(r.config) +} + // Address implements constant.NewListener func (r *Redir) Address() string { return r.l.Address() } -// ReCreate implements constant.NewListener +// Listen implements constant.NewListener func (r *Redir) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { var err error r.l, err = redir.NewWithInfos(r.Address(), r.name, r.preferRulesName, tcpIn) diff --git a/listener/inbound/socks.go b/listener/inbound/socks.go index 1aa3c23f..9e826bc3 100644 --- a/listener/inbound/socks.go +++ b/listener/inbound/socks.go @@ -14,9 +14,10 @@ type SocksOption struct { type Socks struct { *Base - udp bool - stl *socks.Listener - sul *socks.UDPListener + config *SocksOption + udp bool + stl *socks.Listener + sul *socks.UDPListener } func NewSocks(options *SocksOption) (*Socks, error) { @@ -25,11 +26,17 @@ func NewSocks(options *SocksOption) (*Socks, error) { return nil, err } return &Socks{ - Base: base, - udp: options.UDP == nil || *options.UDP, + Base: base, + config: options, + udp: options.UDP == nil || *options.UDP, }, nil } +// Config implements constant.NewListener +func (s *Socks) Config() string { + return optionToString(s.config) +} + // Close implements constant.NewListener func (s *Socks) Close() error { var err error @@ -56,7 +63,7 @@ func (s *Socks) Address() string { return s.stl.Address() } -// ReCreate implements constant.NewListener +// Listen implements constant.NewListener func (s *Socks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { var err error if s.stl, err = socks.NewWithInfos(s.RawAddress(), s.name, s.preferRulesName, tcpIn); err != nil { diff --git a/listener/inbound/tproxy.go b/listener/inbound/tproxy.go index 00d9c555..3a86919c 100644 --- a/listener/inbound/tproxy.go +++ b/listener/inbound/tproxy.go @@ -15,9 +15,10 @@ type TProxyOption struct { type TProxy struct { *Base - lUDP *tproxy.UDPListener - lTCP *tproxy.Listener - udp bool + config *TProxyOption + lUDP *tproxy.UDPListener + lTCP *tproxy.Listener + udp bool } func NewTProxy(options *TProxyOption) (*TProxy, error) { @@ -26,18 +27,24 @@ func NewTProxy(options *TProxyOption) (*TProxy, error) { return nil, err } return &TProxy{ - Base: base, - udp: options.UDP == nil || *options.UDP, + Base: base, + config: options, + udp: options.UDP == nil || *options.UDP, }, nil } +// Config implements constant.NewListener +func (t *TProxy) Config() string { + return optionToString(t.config) +} + // Address implements constant.NewListener func (t *TProxy) Address() string { return t.lTCP.Address() } -// ReCreate implements constant.NewListener +// Listen implements constant.NewListener func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { var err error t.lTCP, err = tproxy.NewWithInfos(t.RawAddress(), t.name, t.preferRulesName, tcpIn) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 2c8d37e0..3be2f4aa 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -87,9 +87,10 @@ func Rules() []C.Rule { return rules } -func Listeners()map[string]C.NewListener{ +func Listeners() map[string]C.NewListener { return listeners } + // UpdateRules handle update rules func UpdateRules(newRules []C.Rule, newSubRule map[string][]C.Rule, rp map[string]provider.RuleProvider) { configMux.Lock() @@ -125,7 +126,7 @@ func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]provid func UpdateListeners(newListeners map[string]C.NewListener) { configMux.Lock() defer configMux.Unlock() - listeners=newListeners + listeners = newListeners } func UpdateSniffer(dispatcher *sniffer.SnifferDispatcher) {