diff --git a/docs/config.yaml b/docs/config.yaml index 52ccecf4..9641fafa 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -1096,7 +1096,7 @@ sub-rules: listeners: - name: socks5-in-1 type: socks - port: 10808 + port: 10808 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 #listen: 0.0.0.0 # 默认监听 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 @@ -1107,7 +1107,7 @@ listeners: - name: http-in-1 type: http - port: 10809 + port: 10809 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1117,7 +1117,7 @@ listeners: - name: mixed-in-1 type: mixed # HTTP(S) 和 SOCKS 代理混合 - port: 10810 + port: 10810 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1128,14 +1128,14 @@ listeners: - name: reidr-in-1 type: redir - port: 10811 + port: 10811 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) - name: tproxy-in-1 type: tproxy - port: 10812 + port: 10812 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1143,7 +1143,7 @@ listeners: - name: shadowsocks-in-1 type: shadowsocks - port: 10813 + port: 10813 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1152,7 +1152,7 @@ listeners: - name: vmess-in-1 type: vmess - port: 10814 + port: 10814 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1176,7 +1176,7 @@ listeners: - name: tuic-in-1 type: tuic - port: 10815 + port: 10815 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1196,7 +1196,7 @@ listeners: - name: tunnel-in-1 type: tunnel - port: 10816 + port: 10816 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1205,7 +1205,7 @@ listeners: - name: vless-in-1 type: vless - port: 10817 + port: 10817 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1230,7 +1230,7 @@ listeners: - name: anytls-in-1 type: anytls - port: 10818 + port: 10818 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 users: username1: password1 @@ -1242,7 +1242,7 @@ listeners: - name: trojan-in-1 type: trojan - port: 10819 + port: 10819 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) diff --git a/listener/inbound/anytls.go b/listener/inbound/anytls.go index a995bf4f..6f1e6350 100644 --- a/listener/inbound/anytls.go +++ b/listener/inbound/anytls.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/anytls" LC "github.com/metacubex/mihomo/listener/config" @@ -52,12 +54,13 @@ func (v *AnyTLS) Config() C.InboundConfig { // Address implements constant.InboundListener func (v *AnyTLS) Address() string { + var addrList []string if v.l != nil { for _, addr := range v.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/listener/inbound/base.go b/listener/inbound/base.go index e8f860a0..d4377986 100644 --- a/listener/inbound/base.go +++ b/listener/inbound/base.go @@ -5,8 +5,10 @@ import ( "net" "net/netip" "strconv" + "strings" "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/utils" C "github.com/metacubex/mihomo/constant" ) @@ -15,7 +17,7 @@ type Base struct { name string specialRules string listenAddr netip.Addr - port int + ports utils.IntRanges[uint16] } func NewBase(options *BaseOption) (*Base, error) { @@ -26,11 +28,15 @@ func NewBase(options *BaseOption) (*Base, error) { if err != nil { return nil, err } + ports, err := utils.NewUnsignedRanges[uint16](options.Port) + if err != nil { + return nil, err + } return &Base{ name: options.Name(), listenAddr: addr, specialRules: options.SpecialRules, - port: options.Port, + ports: ports, config: options, }, nil } @@ -57,7 +63,15 @@ func (b *Base) Name() string { // RawAddress implements constant.InboundListener func (b *Base) RawAddress() string { - return net.JoinHostPort(b.listenAddr.String(), strconv.Itoa(int(b.port))) + if len(b.ports) == 0 { + return net.JoinHostPort(b.listenAddr.String(), "0") + } + address := make([]string, 0, len(b.ports)) + b.ports.Range(func(port uint16) bool { + address = append(address, net.JoinHostPort(b.listenAddr.String(), strconv.Itoa(int(port)))) + return true + }) + return strings.Join(address, ",") } // Listen implements constant.InboundListener @@ -74,7 +88,7 @@ var _ C.InboundListener = (*Base)(nil) type BaseOption struct { NameStr string `inbound:"name"` Listen string `inbound:"listen,omitempty"` - Port int `inbound:"port,omitempty"` + Port string `inbound:"port,omitempty"` SpecialRules string `inbound:"rule,omitempty"` SpecialProxy string `inbound:"proxy,omitempty"` } diff --git a/listener/inbound/http.go b/listener/inbound/http.go index e20a9a23..018c8a7e 100644 --- a/listener/inbound/http.go +++ b/listener/inbound/http.go @@ -1,6 +1,10 @@ package inbound import ( + "errors" + "fmt" + "strings" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/http" "github.com/metacubex/mihomo/log" @@ -18,7 +22,7 @@ func (o HTTPOption) Equal(config C.InboundConfig) bool { type HTTP struct { *Base config *HTTPOption - l *http.Listener + l []*http.Listener } func NewHTTP(options *HTTPOption) (*HTTP, error) { @@ -39,15 +43,21 @@ func (h *HTTP) Config() C.InboundConfig { // Address implements constant.InboundListener func (h *HTTP) Address() string { - return h.l.Address() + var addrList []string + for _, l := range h.l { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (h *HTTP) Listen(tunnel C.Tunnel) error { - var err error - h.l, err = http.NewWithAuthenticator(h.RawAddress(), tunnel, h.config.Users.GetAuthStore(), h.Additions()...) - if err != nil { - return err + for _, addr := range strings.Split(h.RawAddress(), ",") { + l, err := http.NewWithAuthenticator(addr, tunnel, h.config.Users.GetAuthStore(), h.Additions()...) + if err != nil { + return err + } + h.l = append(h.l, l) } log.Infoln("HTTP[%s] proxy listening at: %s", h.Name(), h.Address()) return nil @@ -55,8 +65,15 @@ func (h *HTTP) Listen(tunnel C.Tunnel) error { // Close implements constant.InboundListener func (h *HTTP) Close() error { - if h.l != nil { - return h.l.Close() + var errs []error + for _, l := range h.l { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) + } + } + if len(errs) > 0 { + return errors.Join(errs...) } return nil } diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index 23b2ada3..62d19c82 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing_hysteria2" @@ -83,12 +85,13 @@ func (t *Hysteria2) Config() C.InboundConfig { // Address implements constant.InboundListener func (t *Hysteria2) Address() string { + var addrList []string if t.l != nil { for _, addr := range t.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/listener/inbound/mixed.go b/listener/inbound/mixed.go index 1d79929a..0d285ce7 100644 --- a/listener/inbound/mixed.go +++ b/listener/inbound/mixed.go @@ -1,7 +1,9 @@ package inbound import ( + "errors" "fmt" + "strings" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" @@ -23,8 +25,8 @@ func (o MixedOption) Equal(config C.InboundConfig) bool { type Mixed struct { *Base config *MixedOption - l *mixed.Listener - lUDP *socks.UDPListener + l []*mixed.Listener + lUDP []*socks.UDPListener udp bool } @@ -47,21 +49,28 @@ func (m *Mixed) Config() C.InboundConfig { // Address implements constant.InboundListener func (m *Mixed) Address() string { - return m.l.Address() + var addrList []string + for _, l := range m.l { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (m *Mixed) Listen(tunnel C.Tunnel) error { - var err error - m.l, err = mixed.NewWithAuthenticator(m.RawAddress(), tunnel, m.config.Users.GetAuthStore(), m.Additions()...) - if err != nil { - return err - } - if m.udp { - m.lUDP, err = socks.NewUDP(m.RawAddress(), tunnel, m.Additions()...) + for _, addr := range strings.Split(m.RawAddress(), ",") { + l, err := mixed.NewWithAuthenticator(addr, tunnel, m.config.Users.GetAuthStore(), m.Additions()...) if err != nil { return err } + m.l = append(m.l, l) + if m.udp { + lUDP, err := socks.NewUDP(addr, tunnel, m.Additions()...) + if err != nil { + return err + } + m.lUDP = append(m.lUDP, lUDP) + } } log.Infoln("Mixed(http+socks)[%s] proxy listening at: %s", m.Name(), m.Address()) return nil @@ -69,22 +78,23 @@ func (m *Mixed) Listen(tunnel C.Tunnel) error { // Close implements constant.InboundListener func (m *Mixed) Close() error { - var err error - if m.l != nil { - if tcpErr := m.l.Close(); tcpErr != nil { - err = tcpErr + var errs []error + for _, l := range m.l { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) } } - if m.udp && m.lUDP != nil { - if udpErr := m.lUDP.Close(); udpErr != nil { - if err == nil { - err = udpErr - } else { - return fmt.Errorf("close tcp err: %s, close udp err: %s", err.Error(), udpErr.Error()) - } + for _, l := range m.lUDP { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close udp listener %s err: %w", l.Address(), err)) } } - return err + if len(errs) > 0 { + return errors.Join(errs...) + } + return nil } var _ C.InboundListener = (*Mixed)(nil) diff --git a/listener/inbound/redir.go b/listener/inbound/redir.go index ee090ade..2981ddfc 100644 --- a/listener/inbound/redir.go +++ b/listener/inbound/redir.go @@ -1,6 +1,10 @@ package inbound import ( + "errors" + "fmt" + "strings" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/redir" "github.com/metacubex/mihomo/log" @@ -17,7 +21,7 @@ func (o RedirOption) Equal(config C.InboundConfig) bool { type Redir struct { *Base config *RedirOption - l *redir.Listener + l []*redir.Listener } func NewRedir(options *RedirOption) (*Redir, error) { @@ -38,15 +42,21 @@ func (r *Redir) Config() C.InboundConfig { // Address implements constant.InboundListener func (r *Redir) Address() string { - return r.l.Address() + var addrList []string + for _, l := range r.l { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (r *Redir) Listen(tunnel C.Tunnel) error { - var err error - r.l, err = redir.New(r.RawAddress(), tunnel, r.Additions()...) - if err != nil { - return err + for _, addr := range strings.Split(r.RawAddress(), ",") { + l, err := redir.New(addr, tunnel, r.Additions()...) + if err != nil { + return err + } + r.l = append(r.l, l) } log.Infoln("Redir[%s] proxy listening at: %s", r.Name(), r.Address()) return nil @@ -54,8 +64,15 @@ func (r *Redir) Listen(tunnel C.Tunnel) error { // Close implements constant.InboundListener func (r *Redir) Close() error { - if r.l != nil { - r.l.Close() + var errs []error + for _, l := range r.l { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close redir listener %s err: %w", l.Address(), err)) + } + } + if len(errs) > 0 { + return errors.Join(errs...) } return nil } diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index 240e6419..51592ab3 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing_shadowsocks" @@ -52,12 +54,13 @@ func (s *ShadowSocks) Config() C.InboundConfig { // Address implements constant.InboundListener func (s *ShadowSocks) Address() string { + var addrList []string if s.l != nil { for _, addr := range s.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/listener/inbound/socks.go b/listener/inbound/socks.go index 119eec82..fc7735f2 100644 --- a/listener/inbound/socks.go +++ b/listener/inbound/socks.go @@ -1,7 +1,10 @@ package inbound import ( + "errors" "fmt" + "strings" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/socks" "github.com/metacubex/mihomo/log" @@ -21,8 +24,8 @@ type Socks struct { *Base config *SocksOption udp bool - stl *socks.Listener - sul *socks.UDPListener + stl []*socks.Listener + sul []*socks.UDPListener } func NewSocks(options *SocksOption) (*Socks, error) { @@ -44,40 +47,49 @@ func (s *Socks) Config() C.InboundConfig { // Close implements constant.InboundListener func (s *Socks) Close() error { - var err error - if s.stl != nil { - if tcpErr := s.stl.Close(); tcpErr != nil { - err = tcpErr + var errs []error + for _, l := range s.stl { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) } } - if s.udp && s.sul != nil { - if udpErr := s.sul.Close(); udpErr != nil { - if err == nil { - err = udpErr - } else { - return fmt.Errorf("close tcp err: %s, close udp err: %s", err.Error(), udpErr.Error()) - } + for _, l := range s.sul { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close udp listener %s err: %w", l.Address(), err)) } } - - return err + if len(errs) > 0 { + return errors.Join(errs...) + } + return nil } // Address implements constant.InboundListener func (s *Socks) Address() string { - return s.stl.Address() + var addrList []string + for _, l := range s.stl { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (s *Socks) Listen(tunnel C.Tunnel) error { - var err error - if s.stl, err = socks.NewWithAuthenticator(s.RawAddress(), tunnel, s.config.Users.GetAuthStore(), s.Additions()...); err != nil { - return err - } - if s.udp { - if s.sul, err = socks.NewUDP(s.RawAddress(), tunnel, s.Additions()...); err != nil { + for _, addr := range strings.Split(s.RawAddress(), ",") { + stl, err := socks.NewWithAuthenticator(addr, tunnel, s.config.Users.GetAuthStore(), s.Additions()...) + if err != nil { return err } + s.stl = append(s.stl, stl) + if s.udp { + sul, err := socks.NewUDP(addr, tunnel, s.Additions()...) + if err != nil { + return err + } + s.sul = append(s.sul, sul) + } } log.Infoln("SOCKS[%s] proxy listening at: %s", s.Name(), s.Address()) diff --git a/listener/inbound/tproxy.go b/listener/inbound/tproxy.go index acc8cb5e..66a50f75 100644 --- a/listener/inbound/tproxy.go +++ b/listener/inbound/tproxy.go @@ -1,7 +1,9 @@ package inbound import ( + "errors" "fmt" + "strings" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/tproxy" @@ -20,8 +22,8 @@ func (o TProxyOption) Equal(config C.InboundConfig) bool { type TProxy struct { *Base config *TProxyOption - lUDP *tproxy.UDPListener - lTCP *tproxy.Listener + lUDP []*tproxy.UDPListener + lTCP []*tproxy.Listener udp bool } @@ -45,21 +47,28 @@ func (t *TProxy) Config() C.InboundConfig { // Address implements constant.InboundListener func (t *TProxy) Address() string { - return t.lTCP.Address() + var addrList []string + for _, l := range t.lTCP { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (t *TProxy) Listen(tunnel C.Tunnel) error { - var err error - t.lTCP, err = tproxy.New(t.RawAddress(), tunnel, t.Additions()...) - if err != nil { - return err - } - if t.udp { - t.lUDP, err = tproxy.NewUDP(t.RawAddress(), tunnel, t.Additions()...) + for _, addr := range strings.Split(t.RawAddress(), ",") { + lTCP, err := tproxy.New(addr, tunnel, t.Additions()...) if err != nil { return err } + t.lTCP = append(t.lTCP, lTCP) + if t.udp { + lUDP, err := tproxy.NewUDP(addr, tunnel, t.Additions()...) + if err != nil { + return err + } + t.lUDP = append(t.lUDP, lUDP) + } } log.Infoln("TProxy[%s] proxy listening at: %s", t.Name(), t.Address()) return nil @@ -67,23 +76,21 @@ func (t *TProxy) Listen(tunnel C.Tunnel) error { // Close implements constant.InboundListener func (t *TProxy) Close() error { - var tcpErr error - var udpErr error - if t.lTCP != nil { - tcpErr = t.lTCP.Close() + var errs []error + for _, l := range t.lTCP { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) + } } - if t.lUDP != nil { - udpErr = t.lUDP.Close() + for _, l := range t.lUDP { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close udp listener %s err: %w", l.Address(), err)) + } } - - if tcpErr != nil && udpErr != nil { - return fmt.Errorf("tcp close err: %s and udp close err: %s", tcpErr, udpErr) - } - if tcpErr != nil { - return tcpErr - } - if udpErr != nil { - return udpErr + if len(errs) > 0 { + return errors.Join(errs...) } return nil } diff --git a/listener/inbound/trojan.go b/listener/inbound/trojan.go index 0cf5ef41..44c56b0b 100644 --- a/listener/inbound/trojan.go +++ b/listener/inbound/trojan.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/trojan" @@ -83,12 +85,13 @@ func (v *Trojan) Config() C.InboundConfig { // Address implements constant.InboundListener func (v *Trojan) Address() string { + var addrList []string if v.l != nil { for _, addr := range v.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index 562228ee..e9c2f21b 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/tuic" @@ -66,12 +68,13 @@ func (t *Tuic) Config() C.InboundConfig { // Address implements constant.InboundListener func (t *Tuic) Address() string { + var addrList []string if t.l != nil { for _, addr := range t.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/listener/inbound/tunnel.go b/listener/inbound/tunnel.go index 2dfaac74..0b3d5b23 100644 --- a/listener/inbound/tunnel.go +++ b/listener/inbound/tunnel.go @@ -1,7 +1,9 @@ package inbound import ( + "errors" "fmt" + "strings" C "github.com/metacubex/mihomo/constant" LT "github.com/metacubex/mihomo/listener/tunnel" @@ -21,8 +23,8 @@ func (o TunnelOption) Equal(config C.InboundConfig) bool { type Tunnel struct { *Base config *TunnelOption - ttl *LT.Listener - tul *LT.PacketConn + ttl []*LT.Listener + tul []*LT.PacketConn } func NewTunnel(options *TunnelOption) (*Tunnel, error) { @@ -43,56 +45,62 @@ func (t *Tunnel) Config() C.InboundConfig { // Close implements constant.InboundListener func (t *Tunnel) Close() error { - var err error - if t.ttl != nil { - if tcpErr := t.ttl.Close(); tcpErr != nil { - err = tcpErr + var errs []error + for _, l := range t.ttl { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) } } - if t.tul != nil { - if udpErr := t.tul.Close(); udpErr != nil { - if err == nil { - err = udpErr - } else { - return fmt.Errorf("close tcp err: %s, close udp err: %s", err.Error(), udpErr.Error()) - } + for _, l := range t.tul { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close udp listener %s err: %w", l.Address(), err)) } } - - return err -} - -// Address implements constant.InboundListener -func (t *Tunnel) Address() string { - if t.ttl != nil { - return t.ttl.Address() - } - if t.tul != nil { - return t.tul.Address() - } - return "" -} - -// Listen implements constant.InboundListener -func (t *Tunnel) Listen(tunnel C.Tunnel) error { - var err error - for _, network := range t.config.Network { - switch network { - case "tcp": - if t.ttl, err = LT.New(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...); err != nil { - return err - } - case "udp": - if t.tul, err = LT.NewUDP(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...); err != nil { - return err - } - default: - log.Warnln("unknown network type: %s, passed", network) - continue - } - log.Infoln("Tunnel[%s](%s/%s)proxy listening at: %s", t.Name(), network, t.config.Target, t.Address()) + if len(errs) > 0 { + return errors.Join(errs...) } return nil } +// Address implements constant.InboundListener +func (t *Tunnel) Address() string { + var addrList []string + for _, l := range t.ttl { + addrList = append(addrList, "tcp://"+l.Address()) + } + for _, l := range t.tul { + addrList = append(addrList, "udp://"+l.Address()) + } + return strings.Join(addrList, ",") +} + +// Listen implements constant.InboundListener +func (t *Tunnel) Listen(tunnel C.Tunnel) error { + for _, addr := range strings.Split(t.RawAddress(), ",") { + for _, network := range t.config.Network { + switch network { + case "tcp": + ttl, err := LT.New(addr, t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...) + if err != nil { + return err + } + t.ttl = append(t.ttl, ttl) + case "udp": + tul, err := LT.NewUDP(addr, t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...) + if err != nil { + return err + } + t.tul = append(t.tul, tul) + default: + log.Warnln("unknown network type: %s, passed", network) + continue + } + } + } + log.Infoln("Tunnel[%s](%s)proxy listening at: %s", t.Name(), t.config.Target, t.Address()) + return nil +} + var _ C.InboundListener = (*Tunnel)(nil) diff --git a/listener/inbound/vless.go b/listener/inbound/vless.go index 3e892cce..0cbf214f 100644 --- a/listener/inbound/vless.go +++ b/listener/inbound/vless.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing_vless" @@ -72,12 +74,13 @@ func (v *Vless) Config() C.InboundConfig { // Address implements constant.InboundListener func (v *Vless) Address() string { + var addrList []string if v.l != nil { for _, addr := range v.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 471d26f9..2212a75d 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing_vmess" @@ -72,12 +74,13 @@ func (v *Vmess) Config() C.InboundConfig { // Address implements constant.InboundListener func (v *Vmess) Address() string { + var addrList []string if v.l != nil { for _, addr := range v.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener