Update On Tue Dec 2 19:43:48 CET 2025

This commit is contained in:
github-action[bot]
2025-12-02 19:43:49 +01:00
parent 65e86886d3
commit e535633874
268 changed files with 2470 additions and 2814 deletions

View File

@@ -7,7 +7,6 @@ import (
"time"
CN "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/anytls"
@@ -20,7 +19,6 @@ import (
type AnyTLS struct {
*Base
client *anytls.Client
dialer proxydialer.SingDialer
option *AnyTLSOption
}
@@ -101,9 +99,8 @@ func NewAnyTLS(option AnyTLSOption) (*AnyTLS, error) {
},
option: &option,
}
singDialer := proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer(outbound.DialOptions()...))
outbound.dialer = singDialer
outbound.dialer = option.NewDialer(outbound.DialOptions())
singDialer := proxydialer.NewSingDialer(outbound.dialer)
tOption := anytls.ClientConfig{
Password: option.Password,

View File

@@ -12,6 +12,7 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
"github.com/metacubex/mihomo/component/resolver"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log"
@@ -35,6 +36,7 @@ type Base struct {
rmark int
id string
prefer C.DNSPrefer
dialer C.Dialer
}
// Name implements C.ProxyAdapter
@@ -56,35 +58,15 @@ func (b *Base) Type() C.AdapterType {
return b.tp
}
// StreamConnContext implements C.ProxyAdapter
func (b *Base) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
return c, C.ErrNotSupport
}
func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
return nil, C.ErrNotSupport
}
// DialContextWithDialer implements C.ProxyAdapter
func (b *Base) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
return nil, C.ErrNotSupport
}
// ListenPacketContext implements C.ProxyAdapter
func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
return nil, C.ErrNotSupport
}
// ListenPacketWithDialer implements C.ProxyAdapter
func (b *Base) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
return nil, C.ErrNotSupport
}
// SupportWithDialer implements C.ProxyAdapter
func (b *Base) SupportWithDialer() C.NetWork {
return C.InvalidNet
}
// SupportUOT implements C.ProxyAdapter
func (b *Base) SupportUOT() bool {
return false
@@ -184,6 +166,20 @@ type BasicOption struct {
RoutingMark int `proxy:"routing-mark,omitempty"`
IPVersion string `proxy:"ip-version,omitempty"`
DialerProxy string `proxy:"dialer-proxy,omitempty"` // don't apply this option into groups, but can set a group name in a proxy
DialerForAPI C.Dialer `proxy:"-"` // the dialer used for API usage has higher priority than all the above configurations.
}
func (b *BasicOption) NewDialer(opts []dialer.Option) C.Dialer {
cDialer := b.DialerForAPI
if cDialer == nil {
if b.DialerProxy != "" {
cDialer = proxydialer.NewByName(b.DialerProxy)
} else {
cDialer = dialer.NewDialer(opts...)
}
}
return cDialer
}
type BaseOption struct {
@@ -348,17 +344,6 @@ func (p *autoCloseProxyAdapter) DialContext(ctx context.Context, metadata *C.Met
return c, nil
}
func (p *autoCloseProxyAdapter) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
c, err := p.ProxyAdapter.DialContextWithDialer(ctx, dialer, metadata)
if err != nil {
return nil, err
}
if c, ok := c.(AddRef); ok {
c.AddRef(p)
}
return c, nil
}
func (p *autoCloseProxyAdapter) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
pc, err := p.ProxyAdapter.ListenPacketContext(ctx, metadata)
if err != nil {
@@ -370,17 +355,6 @@ func (p *autoCloseProxyAdapter) ListenPacketContext(ctx context.Context, metadat
return pc, nil
}
func (p *autoCloseProxyAdapter) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
pc, err := p.ProxyAdapter.ListenPacketWithDialer(ctx, dialer, metadata)
if err != nil {
return nil, err
}
if pc, ok := pc.(AddRef); ok {
pc.AddRef(p)
}
return pc, nil
}
func (p *autoCloseProxyAdapter) Close() error {
p.closeOnce.Do(func() {
log.Debugln("Closing outdated proxy [%s]", p.Name())

View File

@@ -13,8 +13,6 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
)
@@ -61,18 +59,7 @@ func (h *Http) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Me
// DialContext implements C.ProxyAdapter
func (h *Http) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
return h.DialContextWithDialer(ctx, dialer.NewDialer(h.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(h.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(h.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
c, err := dialer.DialContext(ctx, "tcp", h.addr)
c, err := h.dialer.DialContext(ctx, "tcp", h.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", h.addr, err)
}
@@ -89,11 +76,6 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad
return NewConn(c, h), nil
}
// SupportWithDialer implements C.ProxyAdapter
func (h *Http) SupportWithDialer() C.NetWork {
return C.TCP
}
// ProxyInfo implements C.ProxyAdapter
func (h *Http) ProxyInfo() C.ProxyInfo {
info := h.Base.ProxyInfo()
@@ -183,7 +165,7 @@ func NewHttp(option HttpOption) (*Http, error) {
}
}
return &Http{
outbound := &Http{
Base: &Base{
name: option.Name,
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
@@ -198,5 +180,7 @@ func NewHttp(option HttpOption) (*Http, error) {
pass: option.Password,
tlsConfig: tlsConfig,
option: &option,
}, nil
}
outbound.dialer = option.NewDialer(outbound.DialOptions())
return outbound, nil
}

View File

@@ -13,7 +13,6 @@ import (
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/ech"
"github.com/metacubex/mihomo/component/proxydialer"
tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log"
@@ -74,16 +73,8 @@ func (h *Hysteria) genHdc(ctx context.Context) utils.PacketDialer {
return &hyDialerWithContext{
ctx: context.Background(),
hyDialer: func(network string, rAddr net.Addr) (net.PacketConn, error) {
var err error
var cDialer C.Dialer = dialer.NewDialer(h.DialOptions()...)
if len(h.option.DialerProxy) > 0 {
cDialer, err = proxydialer.NewByName(h.option.DialerProxy, cDialer)
if err != nil {
return nil, err
}
}
rAddrPort, _ := netip.ParseAddrPort(rAddr.String())
return cDialer.ListenPacket(ctx, network, "", rAddrPort)
return h.dialer.ListenPacket(ctx, network, "", rAddrPort)
},
remoteAddr: func(addr string) (net.Addr, error) {
udpAddr, err := resolveUDPAddr(ctx, "udp", addr, h.prefer)
@@ -263,6 +254,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
tlsConfig: tlsClientConfig,
echConfig: echConfig,
}
outbound.dialer = option.NewDialer(outbound.DialOptions())
return outbound, nil
}

View File

@@ -12,7 +12,6 @@ import (
CN "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant"
@@ -36,7 +35,6 @@ type Hysteria2 struct {
option *Hysteria2Option
client *hysteria2.Client
dialer proxydialer.SingDialer
}
type Hysteria2Option struct {
@@ -119,9 +117,8 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) {
},
option: &option,
}
singDialer := proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer(outbound.DialOptions()...))
outbound.dialer = singDialer
outbound.dialer = option.NewDialer(outbound.DialOptions())
singDialer := proxydialer.NewSingDialer(outbound.dialer)
var salamanderPassword string
if len(option.Obfs) > 0 {

View File

@@ -9,8 +9,6 @@ import (
"sync"
CN "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
"github.com/metacubex/mihomo/component/resolver"
C "github.com/metacubex/mihomo/constant"
@@ -130,20 +128,12 @@ func (m *Mieru) ensureClientIsRunning() error {
}
// Create a dialer and add it to the client config, before starting the client.
var dialer C.Dialer = dialer.NewDialer(m.DialOptions()...)
var err error
if len(m.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(m.option.DialerProxy, dialer)
if err != nil {
return err
}
}
config, err := m.client.Load()
if err != nil {
return err
}
config.Dialer = dialer
config.PacketDialer = mieruPacketDialer{Dialer: dialer}
config.Dialer = m.dialer
config.PacketDialer = mieruPacketDialer{Dialer: m.dialer}
config.Resolver = mieruDNSResolver{prefer: m.prefer}
if err := m.client.Store(config); err != nil {
return err
@@ -187,6 +177,7 @@ func NewMieru(option MieruOption) (*Mieru, error) {
option: &option,
client: c,
}
outbound.dialer = option.NewDialer(outbound.DialOptions())
return outbound, nil
}

View File

@@ -17,6 +17,7 @@ type Reject struct {
}
type RejectOption struct {
BasicOption
Name string `proxy:"name"`
}

View File

@@ -8,8 +8,6 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/structure"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/ntp"
gost "github.com/metacubex/mihomo/transport/gost-plugin"
@@ -191,17 +189,6 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada
// DialContext implements C.ProxyAdapter
func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
return ss.DialContextWithDialer(ctx, dialer.NewDialer(ss.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(ss.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
var c net.Conn
if ss.kcptunClient != nil {
c, err = ss.kcptunClient.OpenStream(ctx, func(ctx context.Context) (net.PacketConn, net.Addr, error) {
@@ -213,7 +200,7 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale
return nil, nil, err
}
pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort())
pc, err := ss.dialer.ListenPacket(ctx, "udp", "", addr.AddrPort())
if err != nil {
return nil, nil, err
}
@@ -221,7 +208,7 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale
return pc, addr, nil
})
} else {
c, err = dialer.DialContext(ctx, "tcp", ss.addr)
c, err = ss.dialer.DialContext(ctx, "tcp", ss.addr)
}
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
@@ -237,25 +224,14 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale
// ListenPacketContext implements C.ProxyAdapter
func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
return ss.ListenPacketWithDialer(ctx, dialer.NewDialer(ss.DialOptions()...), metadata)
}
// ListenPacketWithDialer implements C.ProxyAdapter
func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
if ss.option.UDPOverTCP {
tcpConn, err := ss.DialContextWithDialer(ctx, dialer, metadata)
tcpConn, err := ss.DialContext(ctx, metadata)
if err != nil {
return nil, err
}
return ss.ListenPacketOnStreamConn(ctx, tcpConn, metadata)
}
if len(ss.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
if err = ss.ResolveUDP(ctx, metadata); err != nil {
if err := ss.ResolveUDP(ctx, metadata); err != nil {
return nil, err
}
addr, err := resolveUDPAddr(ctx, "udp", ss.addr, ss.prefer)
@@ -263,7 +239,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial
return nil, err
}
pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort())
pc, err := ss.dialer.ListenPacket(ctx, "udp", "", addr.AddrPort())
if err != nil {
return nil, err
}
@@ -271,11 +247,6 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial
return newPacketConn(pc, ss), nil
}
// SupportWithDialer implements C.ProxyAdapter
func (ss *ShadowSocks) SupportWithDialer() C.NetWork {
return C.ALLNet
}
// ProxyInfo implements C.ProxyAdapter
func (ss *ShadowSocks) ProxyInfo() C.ProxyInfo {
info := ss.Base.ProxyInfo()
@@ -482,7 +453,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
return nil, fmt.Errorf("ss %s unknown udp over tcp protocol version: %d", addr, option.UDPOverTCPVersion)
}
return &ShadowSocks{
outbound := &ShadowSocks{
Base: &Base{
name: option.Name,
addr: addr,
@@ -504,5 +475,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
shadowTLSOption: shadowTLSOpt,
restlsConfig: restlsConfig,
kcptunClient: kcptunClient,
}, nil
}
outbound.dialer = option.NewDialer(outbound.DialOptions())
return outbound, nil
}

View File

@@ -8,8 +8,6 @@ import (
"strconv"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/shadowsocks/core"
"github.com/metacubex/mihomo/transport/shadowsocks/shadowaead"
@@ -68,18 +66,7 @@ func (ssr *ShadowSocksR) StreamConnContext(ctx context.Context, c net.Conn, meta
// DialContext implements C.ProxyAdapter
func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
return ssr.DialContextWithDialer(ctx, dialer.NewDialer(ssr.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(ssr.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(ssr.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
c, err := dialer.DialContext(ctx, "tcp", ssr.addr)
c, err := ssr.dialer.DialContext(ctx, "tcp", ssr.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err)
}
@@ -94,18 +81,7 @@ func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dia
// ListenPacketContext implements C.ProxyAdapter
func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
return ssr.ListenPacketWithDialer(ctx, dialer.NewDialer(ssr.DialOptions()...), metadata)
}
// ListenPacketWithDialer implements C.ProxyAdapter
func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
if len(ssr.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(ssr.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
if err = ssr.ResolveUDP(ctx, metadata); err != nil {
if err := ssr.ResolveUDP(ctx, metadata); err != nil {
return nil, err
}
addr, err := resolveUDPAddr(ctx, "udp", ssr.addr, ssr.prefer)
@@ -113,7 +89,7 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di
return nil, err
}
pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort())
pc, err := ssr.dialer.ListenPacket(ctx, "udp", "", addr.AddrPort())
if err != nil {
return nil, err
}
@@ -123,11 +99,6 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di
return newPacketConn(&ssrPacketConn{EnhancePacketConn: epc, rAddr: addr}, ssr), nil
}
// SupportWithDialer implements C.ProxyAdapter
func (ssr *ShadowSocksR) SupportWithDialer() C.NetWork {
return C.ALLNet
}
// ProxyInfo implements C.ProxyAdapter
func (ssr *ShadowSocksR) ProxyInfo() C.ProxyInfo {
info := ssr.Base.ProxyInfo()
@@ -186,7 +157,7 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
return nil, fmt.Errorf("ssr %s initialize protocol error: %w", addr, err)
}
return &ShadowSocksR{
outbound := &ShadowSocksR{
Base: &Base{
name: option.Name,
addr: addr,
@@ -202,7 +173,9 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
cipher: coreCiph,
obfs: obfs,
protocol: protocol,
}, nil
}
outbound.dialer = option.NewDialer(outbound.DialOptions())
return outbound, nil
}
type ssrPacketConn struct {

View File

@@ -4,7 +4,6 @@ import (
"context"
CN "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log"
@@ -17,7 +16,6 @@ import (
type SingMux struct {
ProxyAdapter
client *mux.Client
dialer proxydialer.SingDialer
onlyTcp bool
}
@@ -96,7 +94,7 @@ func NewSingMux(option SingMuxOption, proxy ProxyAdapter) (ProxyAdapter, error)
// TODO
// "TCP Brutal is only supported on Linux-based systems"
singDialer := proxydialer.NewSingDialer(proxy, dialer.NewDialer(proxy.DialOptions()...), option.Statistic)
singDialer := proxydialer.NewSingDialer(proxydialer.New(proxy, option.Statistic))
client, err := mux.NewClient(mux.Options{
Dialer: singDialer,
Logger: log.SingLogger,
@@ -117,7 +115,6 @@ func NewSingMux(option SingMuxOption, proxy ProxyAdapter) (ProxyAdapter, error)
outbound := &SingMux{
ProxyAdapter: proxy,
client: client,
dialer: singDialer,
onlyTcp: option.OnlyTcp,
}
return outbound, nil

View File

@@ -8,8 +8,6 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/structure"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
obfs "github.com/metacubex/mihomo/transport/simple-obfs"
"github.com/metacubex/mihomo/transport/snell"
@@ -89,18 +87,7 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn
return NewConn(c, s), err
}
return s.DialContextWithDialer(ctx, dialer.NewDialer(s.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(s.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(s.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
c, err := dialer.DialContext(ctx, "tcp", s.addr)
c, err := s.dialer.DialContext(ctx, "tcp", s.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", s.addr, err)
}
@@ -115,22 +102,11 @@ func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
// ListenPacketContext implements C.ProxyAdapter
func (s *Snell) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
return s.ListenPacketWithDialer(ctx, dialer.NewDialer(s.DialOptions()...), metadata)
}
// ListenPacketWithDialer implements C.ProxyAdapter
func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (C.PacketConn, error) {
var err error
if len(s.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(s.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
if err = s.ResolveUDP(ctx, metadata); err != nil {
return nil, err
}
c, err := dialer.DialContext(ctx, "tcp", s.addr)
c, err := s.dialer.DialContext(ctx, "tcp", s.addr)
if err != nil {
return nil, err
}
@@ -141,11 +117,6 @@ func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
return newPacketConn(pc, s), nil
}
// SupportWithDialer implements C.ProxyAdapter
func (s *Snell) SupportWithDialer() C.NetWork {
return C.ALLNet
}
// SupportUOT implements C.ProxyAdapter
func (s *Snell) SupportUOT() bool {
return true
@@ -206,18 +177,11 @@ func NewSnell(option SnellOption) (*Snell, error) {
obfsOption: obfsOption,
version: option.Version,
}
s.dialer = option.NewDialer(s.DialOptions())
if option.Version == snell.Version2 {
s.pool = snell.NewPool(func(ctx context.Context) (*snell.Snell, error) {
var err error
var cDialer C.Dialer = dialer.NewDialer(s.DialOptions()...)
if len(s.option.DialerProxy) > 0 {
cDialer, err = proxydialer.NewByName(s.option.DialerProxy, cDialer)
if err != nil {
return nil, err
}
}
c, err := cDialer.DialContext(ctx, "tcp", addr)
c, err := s.dialer.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, err
}

View File

@@ -12,8 +12,6 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/socks5"
)
@@ -69,18 +67,7 @@ func (ss *Socks5) StreamConnContext(ctx context.Context, c net.Conn, metadata *C
// DialContext implements C.ProxyAdapter
func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
return ss.DialContextWithDialer(ctx, dialer.NewDialer(ss.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(ss.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
c, err := dialer.DialContext(ctx, "tcp", ss.addr)
c, err := ss.dialer.DialContext(ctx, "tcp", ss.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
}
@@ -97,24 +84,12 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me
return NewConn(c, ss), nil
}
// SupportWithDialer implements C.ProxyAdapter
func (ss *Socks5) SupportWithDialer() C.NetWork {
return C.TCP
}
// ListenPacketContext implements C.ProxyAdapter
func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
var cDialer C.Dialer = dialer.NewDialer(ss.DialOptions()...)
if len(ss.option.DialerProxy) > 0 {
cDialer, err = proxydialer.NewByName(ss.option.DialerProxy, cDialer)
if err != nil {
return nil, err
}
}
if err = ss.ResolveUDP(ctx, metadata); err != nil {
return nil, err
}
c, err := cDialer.DialContext(ctx, "tcp", ss.addr)
c, err := ss.dialer.DialContext(ctx, "tcp", ss.addr)
if err != nil {
err = fmt.Errorf("%s connect error: %w", ss.addr, err)
return
@@ -161,7 +136,7 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
bindUDPAddr.IP = serverAddr.IP
}
pc, err := cDialer.ListenPacket(ctx, "udp", "", bindUDPAddr.AddrPort())
pc, err := ss.dialer.ListenPacket(ctx, "udp", "", bindUDPAddr.AddrPort())
if err != nil {
return
}
@@ -210,7 +185,7 @@ func NewSocks5(option Socks5Option) (*Socks5, error) {
}
}
return &Socks5{
outbound := &Socks5{
Base: &Base{
name: option.Name,
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
@@ -228,7 +203,9 @@ func NewSocks5(option Socks5Option) (*Socks5, error) {
tls: option.TLS,
skipCertVerify: option.SkipCertVerify,
tlsConfig: tlsConfig,
}, nil
}
outbound.dialer = option.NewDialer(outbound.DialOptions())
return outbound, nil
}
type socksPacketConn struct {

View File

@@ -12,8 +12,6 @@ import (
"sync"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/randv2"
@@ -44,14 +42,7 @@ type SshOption struct {
}
func (s *Ssh) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
var cDialer C.Dialer = dialer.NewDialer(s.DialOptions()...)
if len(s.option.DialerProxy) > 0 {
cDialer, err = proxydialer.NewByName(s.option.DialerProxy, cDialer)
if err != nil {
return nil, err
}
}
client, err := s.connect(ctx, cDialer, s.addr)
client, err := s.connect(ctx, s.addr)
if err != nil {
return nil, err
}
@@ -63,13 +54,13 @@ func (s *Ssh) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn,
return NewConn(c, s), nil
}
func (s *Ssh) connect(ctx context.Context, cDialer C.Dialer, addr string) (client *ssh.Client, err error) {
func (s *Ssh) connect(ctx context.Context, addr string) (client *ssh.Client, err error) {
s.cMutex.Lock()
defer s.cMutex.Unlock()
if s.client != nil {
return s.client, nil
}
c, err := cDialer.DialContext(ctx, "tcp", addr)
c, err := s.dialer.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, err
}
@@ -203,6 +194,6 @@ func NewSsh(option SshOption) (*Ssh, error) {
option: &option,
config: &config,
}
outbound.dialer = option.NewDialer(outbound.DialOptions())
return outbound, nil
}

View File

@@ -11,17 +11,14 @@ import (
"strings"
"time"
"github.com/metacubex/mihomo/log"
"github.com/saba-futai/sudoku/apis"
"github.com/saba-futai/sudoku/pkg/crypto"
"github.com/saba-futai/sudoku/pkg/obfs/httpmask"
"github.com/saba-futai/sudoku/pkg/obfs/sudoku"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log"
)
type Sudoku struct {
@@ -45,25 +42,13 @@ type SudokuOption struct {
}
// DialContext implements C.ProxyAdapter
func (s *Sudoku) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
return s.DialContextWithDialer(ctx, dialer.NewDialer(s.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (s *Sudoku) DialContextWithDialer(ctx context.Context, d C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(s.option.DialerProxy) > 0 {
d, err = proxydialer.NewByName(s.option.DialerProxy, d)
if err != nil {
return nil, err
}
}
func (s *Sudoku) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) {
cfg, err := s.buildConfig(metadata)
if err != nil {
return nil, err
}
c, err := d.DialContext(ctx, "tcp", s.addr)
c, err := s.dialer.DialContext(ctx, "tcp", s.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", s.addr, err)
}
@@ -95,11 +80,6 @@ func (s *Sudoku) SupportUOT() bool {
return false // Sudoku protocol only supports TCP
}
// SupportWithDialer implements C.ProxyAdapter
func (s *Sudoku) SupportWithDialer() C.NetWork {
return C.TCP
}
// ProxyInfo implements C.ProxyAdapter
func (s *Sudoku) ProxyInfo() C.ProxyInfo {
info := s.Base.ProxyInfo()
@@ -206,7 +186,7 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) {
baseConf.AEADMethod = option.AEADMethod
}
return &Sudoku{
outbound := &Sudoku{
Base: &Base{
name: option.Name,
addr: baseConf.ServerAddress,
@@ -221,7 +201,9 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) {
option: &option,
table: table,
baseConf: baseConf,
}, nil
}
outbound.dialer = option.NewDialer(outbound.DialOptions())
return outbound, nil
}
func buildSudokuHandshakePayload(key string) [16]byte {

View File

@@ -11,9 +11,7 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/ech"
"github.com/metacubex/mihomo/component/proxydialer"
tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/gun"
@@ -196,18 +194,7 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con
return NewConn(c, t), nil
}
return t.DialContextWithDialer(ctx, dialer.NewDialer(t.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(t.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
c, err := dialer.DialContext(ctx, "tcp", t.addr)
c, err = t.dialer.DialContext(ctx, "tcp", t.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
@@ -250,21 +237,10 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
pc := trojan.NewPacketConn(c)
return newPacketConn(pc, t), err
}
return t.ListenPacketWithDialer(ctx, dialer.NewDialer(t.DialOptions()...), metadata)
}
// ListenPacketWithDialer implements C.ProxyAdapter
func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
if len(t.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
if err = t.ResolveUDP(ctx, metadata); err != nil {
return nil, err
}
c, err := dialer.DialContext(ctx, "tcp", t.addr)
c, err = t.dialer.DialContext(ctx, "tcp", t.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
@@ -280,11 +256,6 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me
return newPacketConn(pc, t), err
}
// SupportWithDialer implements C.ProxyAdapter
func (t *Trojan) SupportWithDialer() C.NetWork {
return C.ALLNet
}
// SupportUOT implements C.ProxyAdapter
func (t *Trojan) SupportUOT() bool {
return true
@@ -327,6 +298,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
option: &option,
hexPassword: trojan.Key(option.Password),
}
t.dialer = option.NewDialer(t.DialOptions())
var err error
t.realityConfig, err = option.RealityOpts.Parse()
@@ -355,15 +327,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
if option.Network == "grpc" {
dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
var err error
var cDialer C.Dialer = dialer.NewDialer(t.DialOptions()...)
if len(t.option.DialerProxy) > 0 {
cDialer, err = proxydialer.NewByName(t.option.DialerProxy, cDialer)
if err != nil {
return nil, err
}
}
c, err := cDialer.DialContext(ctx, "tcp", t.addr)
c, err := t.dialer.DialContext(ctx, "tcp", t.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", t.addr, err.Error())
}

View File

@@ -10,9 +10,7 @@ import (
"time"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/ech"
"github.com/metacubex/mihomo/component/proxydialer"
tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/tuic"
@@ -70,12 +68,7 @@ type TuicOption struct {
// DialContext implements C.ProxyAdapter
func (t *Tuic) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
return t.DialContextWithDialer(ctx, dialer.NewDialer(t.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (t *Tuic) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (C.Conn, error) {
conn, err := t.client.DialContextWithDialer(ctx, metadata, dialer, t.dialWithDialer)
conn, err := t.client.DialContext(ctx, metadata)
if err != nil {
return nil, err
}
@@ -84,11 +77,6 @@ func (t *Tuic) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad
// ListenPacketContext implements C.ProxyAdapter
func (t *Tuic) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
return t.ListenPacketWithDialer(ctx, dialer.NewDialer(t.DialOptions()...), metadata)
}
// ListenPacketWithDialer implements C.ProxyAdapter
func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
if err = t.ResolveUDP(ctx, metadata); err != nil {
return nil, err
}
@@ -98,7 +86,7 @@ func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, meta
uotMetadata := *metadata
uotMetadata.Host = uotDestination.Fqdn
uotMetadata.DstPort = uotDestination.Port
c, err := t.DialContextWithDialer(ctx, dialer, &uotMetadata)
c, err := t.DialContext(ctx, &uotMetadata)
if err != nil {
return nil, err
}
@@ -112,25 +100,14 @@ func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, meta
return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), t), nil
}
}
pc, err := t.client.ListenPacketWithDialer(ctx, metadata, dialer, t.dialWithDialer)
pc, err := t.client.ListenPacket(ctx, metadata)
if err != nil {
return nil, err
}
return newPacketConn(pc, t), nil
}
// SupportWithDialer implements C.ProxyAdapter
func (t *Tuic) SupportWithDialer() C.NetWork {
return C.ALLNet
}
func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) {
if len(t.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer)
if err != nil {
return nil, nil, err
}
}
func (t *Tuic) dial(ctx context.Context) (transport *quic.Transport, addr net.Addr, err error) {
udpAddr, err := resolveUDPAddr(ctx, "udp", t.addr, t.prefer)
if err != nil {
return nil, nil, err
@@ -141,7 +118,7 @@ func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (transport *
}
addr = udpAddr
var pc net.PacketConn
pc, err = dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort())
pc, err = t.dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort())
if err != nil {
return nil, nil, err
}
@@ -285,6 +262,7 @@ func NewTuic(option TuicOption) (*Tuic, error) {
tlsConfig: tlsClientConfig,
echConfig: echConfig,
}
t.dialer = option.NewDialer(t.DialOptions())
clientMaxOpenStreams := int64(option.MaxOpenStreams)
@@ -313,7 +291,7 @@ func NewTuic(option TuicOption) (*Tuic, error) {
CWND: option.CWND,
}
t.client = tuic.NewPoolClientV4(clientOption)
t.client = tuic.NewPoolClientV4(clientOption, t.dial)
} else {
maxUdpRelayPacketSize := option.MaxUdpRelayPacketSize
if maxUdpRelayPacketSize > tuic.MaxFragSizeV5 {
@@ -332,7 +310,7 @@ func NewTuic(option TuicOption) (*Tuic, error) {
CWND: option.CWND,
}
t.client = tuic.NewPoolClientV5(clientOption)
t.client = tuic.NewPoolClientV5(clientOption, t.dial)
}
return t, nil

View File

@@ -12,9 +12,7 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/ech"
"github.com/metacubex/mihomo/component/proxydialer"
tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/gun"
@@ -252,18 +250,7 @@ func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn
return NewConn(c, v), nil
}
return v.DialContextWithDialer(ctx, dialer.NewDialer(v.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(v.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
c, err := dialer.DialContext(ctx, "tcp", v.addr)
c, err = v.dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
@@ -301,23 +288,12 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (
return v.ListenPacketOnStreamConn(ctx, c, metadata)
}
return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.DialOptions()...), metadata)
}
// ListenPacketWithDialer implements C.ProxyAdapter
func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
if len(v.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
if err = v.ResolveUDP(ctx, metadata); err != nil {
return nil, err
}
c, err := dialer.DialContext(ctx, "tcp", v.addr)
c, err = v.dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
@@ -333,11 +309,6 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
return v.ListenPacketOnStreamConn(ctx, c, metadata)
}
// SupportWithDialer implements C.ProxyAdapter
func (v *Vless) SupportWithDialer() C.NetWork {
return C.ALLNet
}
// ListenPacketOnStreamConn implements C.ProxyAdapter
func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
if err = v.ResolveUDP(ctx, metadata); err != nil {
@@ -457,6 +428,7 @@ func NewVless(option VlessOption) (*Vless, error) {
client: client,
option: &option,
}
v.dialer = option.NewDialer(v.DialOptions())
v.encryption, err = encryption.NewClient(option.Encryption)
if err != nil {
@@ -480,15 +452,7 @@ func NewVless(option VlessOption) (*Vless, error) {
}
case "grpc":
dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
var err error
var cDialer C.Dialer = dialer.NewDialer(v.DialOptions()...)
if len(v.option.DialerProxy) > 0 {
cDialer, err = proxydialer.NewByName(v.option.DialerProxy, cDialer)
if err != nil {
return nil, err
}
}
c, err := cDialer.DialContext(ctx, "tcp", v.addr)
c, err := v.dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}

View File

@@ -14,9 +14,7 @@ import (
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/ech"
"github.com/metacubex/mihomo/component/proxydialer"
tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/ntp"
@@ -313,18 +311,7 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn
return NewConn(c, v), nil
}
return v.DialContextWithDialer(ctx, dialer.NewDialer(v.DialOptions()...), metadata)
}
// DialContextWithDialer implements C.ProxyAdapter
func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
if len(v.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
c, err := dialer.DialContext(ctx, "tcp", v.addr)
c, err = v.dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
@@ -358,23 +345,12 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (
}
return v.ListenPacketOnStreamConn(ctx, c, metadata)
}
return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.DialOptions()...), metadata)
}
// ListenPacketWithDialer implements C.ProxyAdapter
func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
if len(v.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer)
if err != nil {
return nil, err
}
}
if err = v.ResolveUDP(ctx, metadata); err != nil {
return nil, err
}
c, err := dialer.DialContext(ctx, "tcp", v.addr)
c, err = v.dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
@@ -389,11 +365,6 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
return v.ListenPacketOnStreamConn(ctx, c, metadata)
}
// SupportWithDialer implements C.ProxyAdapter
func (v *Vmess) SupportWithDialer() C.NetWork {
return C.ALLNet
}
// ProxyInfo implements C.ProxyAdapter
func (v *Vmess) ProxyInfo() C.ProxyInfo {
info := v.Base.ProxyInfo()
@@ -467,6 +438,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
client: client,
option: &option,
}
v.dialer = option.NewDialer(v.DialOptions())
v.realityConfig, err = v.option.RealityOpts.Parse()
if err != nil {
@@ -485,15 +457,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
}
case "grpc":
dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
var err error
var cDialer C.Dialer = dialer.NewDialer(v.DialOptions()...)
if len(v.option.DialerProxy) > 0 {
cDialer, err = proxydialer.NewByName(v.option.DialerProxy, cDialer)
if err != nil {
return nil, err
}
}
c, err := cDialer.DialContext(ctx, "tcp", v.addr)
c, err := v.dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}

View File

@@ -40,7 +40,6 @@ type WireGuard struct {
bind *wireguard.ClientBind
device wireguardGoDevice
tunDevice wireguard.Device
dialer proxydialer.SingDialer
resolver resolver.Resolver
initOk atomic.Bool
@@ -177,8 +176,8 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) {
prefer: C.NewDNSPrefer(option.IPVersion),
},
}
singDialer := proxydialer.NewSlowDownSingDialer(proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer(outbound.DialOptions()...)), slowdown.New())
outbound.dialer = singDialer
outbound.dialer = option.NewDialer(outbound.DialOptions())
singDialer := proxydialer.NewSlowDownSingDialer(proxydialer.NewSingDialer(outbound.dialer), slowdown.New())
var reserved [3]uint8
if len(option.Reserved) > 0 {
@@ -196,7 +195,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) {
outbound.connectAddr = option.Addr()
}
}
outbound.bind = wireguard.NewClientBind(context.Background(), wgSingErrorHandler{outbound.Name()}, outbound.dialer, isConnect, outbound.connectAddr.AddrPort(), reserved)
outbound.bind = wireguard.NewClientBind(context.Background(), wgSingErrorHandler{outbound.Name()}, singDialer, isConnect, outbound.connectAddr.AddrPort(), reserved)
var err error
outbound.localPrefixes, err = option.Prefixes()

View File

@@ -35,18 +35,6 @@ func (lb *LoadBalance) Now() string {
return ""
}
func (r *Relay) Providers() []P.ProxyProvider {
return r.providers
}
func (r *Relay) Proxies() []C.Proxy {
return r.GetProxies(false)
}
func (r *Relay) Now() string {
return ""
}
func (s *Selector) Providers() []P.ProxyProvider {
return s.providers
}

View File

@@ -1,163 +0,0 @@
package outboundgroup
import (
"context"
"encoding/json"
"github.com/metacubex/mihomo/adapter/outbound"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
)
type Relay struct {
*GroupBase
Hidden bool
Icon string
}
// DialContext implements C.ProxyAdapter
func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
proxies, chainProxies := r.proxies(metadata, true)
switch len(proxies) {
case 0:
return outbound.NewDirect().DialContext(ctx, metadata)
case 1:
return proxies[0].DialContext(ctx, metadata)
}
var d C.Dialer
d = dialer.NewDialer()
for _, proxy := range proxies[:len(proxies)-1] {
d = proxydialer.New(proxy, d, false)
}
last := proxies[len(proxies)-1]
conn, err := last.DialContextWithDialer(ctx, d, metadata)
if err != nil {
return nil, err
}
for i := len(chainProxies) - 2; i >= 0; i-- {
conn.AppendToChains(chainProxies[i])
}
conn.AppendToChains(r)
return conn, nil
}
// ListenPacketContext implements C.ProxyAdapter
func (r *Relay) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
proxies, chainProxies := r.proxies(metadata, true)
switch len(proxies) {
case 0:
return outbound.NewDirect().ListenPacketContext(ctx, metadata)
case 1:
return proxies[0].ListenPacketContext(ctx, metadata)
}
var d C.Dialer
d = dialer.NewDialer()
for _, proxy := range proxies[:len(proxies)-1] {
d = proxydialer.New(proxy, d, false)
}
last := proxies[len(proxies)-1]
pc, err := last.ListenPacketWithDialer(ctx, d, metadata)
if err != nil {
return nil, err
}
for i := len(chainProxies) - 2; i >= 0; i-- {
pc.AppendToChains(chainProxies[i])
}
pc.AppendToChains(r)
return pc, nil
}
// SupportUDP implements C.ProxyAdapter
func (r *Relay) SupportUDP() bool {
proxies, _ := r.proxies(nil, false)
if len(proxies) == 0 { // C.Direct
return true
}
for i := len(proxies) - 1; i >= 0; i-- {
proxy := proxies[i]
if !proxy.SupportUDP() {
return false
}
if proxy.SupportUOT() {
return true
}
switch proxy.SupportWithDialer() {
case C.ALLNet:
case C.UDP:
default: // C.TCP and C.InvalidNet
return false
}
}
return true
}
// MarshalJSON implements C.ProxyAdapter
func (r *Relay) MarshalJSON() ([]byte, error) {
all := []string{}
for _, proxy := range r.GetProxies(false) {
all = append(all, proxy.Name())
}
return json.Marshal(map[string]any{
"type": r.Type().String(),
"all": all,
"hidden": r.Hidden,
"icon": r.Icon,
})
}
func (r *Relay) proxies(metadata *C.Metadata, touch bool) ([]C.Proxy, []C.Proxy) {
rawProxies := r.GetProxies(touch)
var proxies []C.Proxy
var chainProxies []C.Proxy
var targetProxies []C.Proxy
for n, proxy := range rawProxies {
proxies = append(proxies, proxy)
chainProxies = append(chainProxies, proxy)
subproxy := proxy.Unwrap(metadata, touch)
for subproxy != nil {
chainProxies = append(chainProxies, subproxy)
proxies[n] = subproxy
subproxy = subproxy.Unwrap(metadata, touch)
}
}
for _, proxy := range proxies {
if proxy.Type() != C.Direct && proxy.Type() != C.Compatible {
targetProxies = append(targetProxies, proxy)
}
}
return targetProxies, chainProxies
}
func (r *Relay) Addr() string {
proxies, _ := r.proxies(nil, false)
return proxies[len(proxies)-1].Addr()
}
func NewRelay(option *GroupCommonOption, providers []P.ProxyProvider) *Relay {
log.Warnln("The group [%s] with relay type is deprecated, please using dialer-proxy instead", option.Name)
return &Relay{
GroupBase: NewGroupBase(GroupBaseOption{
Name: option.Name,
Type: C.Relay,
Providers: providers,
}),
Hidden: option.Hidden,
Icon: option.Icon,
}
}

View File

@@ -8,146 +8,151 @@ import (
C "github.com/metacubex/mihomo/constant"
)
func ParseProxy(mapping map[string]any) (C.Proxy, error) {
func ParseProxy(mapping map[string]any, options ...ProxyOption) (C.Proxy, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true, KeyReplacer: structure.DefaultKeyReplacer})
proxyType, existType := mapping["type"].(string)
if !existType {
return nil, fmt.Errorf("missing type")
}
opt := applyProxyOptions(options...)
basicOption := outbound.BasicOption{
DialerForAPI: opt.DialerForAPI,
}
var (
proxy outbound.ProxyAdapter
err error
)
switch proxyType {
case "ss":
ssOption := &outbound.ShadowSocksOption{}
ssOption := &outbound.ShadowSocksOption{BasicOption: basicOption}
err = decoder.Decode(mapping, ssOption)
if err != nil {
break
}
proxy, err = outbound.NewShadowSocks(*ssOption)
case "ssr":
ssrOption := &outbound.ShadowSocksROption{}
ssrOption := &outbound.ShadowSocksROption{BasicOption: basicOption}
err = decoder.Decode(mapping, ssrOption)
if err != nil {
break
}
proxy, err = outbound.NewShadowSocksR(*ssrOption)
case "socks5":
socksOption := &outbound.Socks5Option{}
socksOption := &outbound.Socks5Option{BasicOption: basicOption}
err = decoder.Decode(mapping, socksOption)
if err != nil {
break
}
proxy, err = outbound.NewSocks5(*socksOption)
case "http":
httpOption := &outbound.HttpOption{}
httpOption := &outbound.HttpOption{BasicOption: basicOption}
err = decoder.Decode(mapping, httpOption)
if err != nil {
break
}
proxy, err = outbound.NewHttp(*httpOption)
case "vmess":
vmessOption := &outbound.VmessOption{}
vmessOption := &outbound.VmessOption{BasicOption: basicOption}
err = decoder.Decode(mapping, vmessOption)
if err != nil {
break
}
proxy, err = outbound.NewVmess(*vmessOption)
case "vless":
vlessOption := &outbound.VlessOption{}
vlessOption := &outbound.VlessOption{BasicOption: basicOption}
err = decoder.Decode(mapping, vlessOption)
if err != nil {
break
}
proxy, err = outbound.NewVless(*vlessOption)
case "snell":
snellOption := &outbound.SnellOption{}
snellOption := &outbound.SnellOption{BasicOption: basicOption}
err = decoder.Decode(mapping, snellOption)
if err != nil {
break
}
proxy, err = outbound.NewSnell(*snellOption)
case "trojan":
trojanOption := &outbound.TrojanOption{}
trojanOption := &outbound.TrojanOption{BasicOption: basicOption}
err = decoder.Decode(mapping, trojanOption)
if err != nil {
break
}
proxy, err = outbound.NewTrojan(*trojanOption)
case "hysteria":
hyOption := &outbound.HysteriaOption{}
hyOption := &outbound.HysteriaOption{BasicOption: basicOption}
err = decoder.Decode(mapping, hyOption)
if err != nil {
break
}
proxy, err = outbound.NewHysteria(*hyOption)
case "hysteria2":
hyOption := &outbound.Hysteria2Option{}
hyOption := &outbound.Hysteria2Option{BasicOption: basicOption}
err = decoder.Decode(mapping, hyOption)
if err != nil {
break
}
proxy, err = outbound.NewHysteria2(*hyOption)
case "wireguard":
wgOption := &outbound.WireGuardOption{}
wgOption := &outbound.WireGuardOption{BasicOption: basicOption}
err = decoder.Decode(mapping, wgOption)
if err != nil {
break
}
proxy, err = outbound.NewWireGuard(*wgOption)
case "tuic":
tuicOption := &outbound.TuicOption{}
tuicOption := &outbound.TuicOption{BasicOption: basicOption}
err = decoder.Decode(mapping, tuicOption)
if err != nil {
break
}
proxy, err = outbound.NewTuic(*tuicOption)
case "direct":
directOption := &outbound.DirectOption{}
directOption := &outbound.DirectOption{BasicOption: basicOption}
err = decoder.Decode(mapping, directOption)
if err != nil {
break
}
proxy = outbound.NewDirectWithOption(*directOption)
case "dns":
dnsOptions := &outbound.DnsOption{}
dnsOptions := &outbound.DnsOption{BasicOption: basicOption}
err = decoder.Decode(mapping, dnsOptions)
if err != nil {
break
}
proxy = outbound.NewDnsWithOption(*dnsOptions)
case "reject":
rejectOption := &outbound.RejectOption{}
rejectOption := &outbound.RejectOption{BasicOption: basicOption}
err = decoder.Decode(mapping, rejectOption)
if err != nil {
break
}
proxy = outbound.NewRejectWithOption(*rejectOption)
case "ssh":
sshOption := &outbound.SshOption{}
sshOption := &outbound.SshOption{BasicOption: basicOption}
err = decoder.Decode(mapping, sshOption)
if err != nil {
break
}
proxy, err = outbound.NewSsh(*sshOption)
case "mieru":
mieruOption := &outbound.MieruOption{}
mieruOption := &outbound.MieruOption{BasicOption: basicOption}
err = decoder.Decode(mapping, mieruOption)
if err != nil {
break
}
proxy, err = outbound.NewMieru(*mieruOption)
case "anytls":
anytlsOption := &outbound.AnyTLSOption{}
anytlsOption := &outbound.AnyTLSOption{BasicOption: basicOption}
err = decoder.Decode(mapping, anytlsOption)
if err != nil {
break
}
proxy, err = outbound.NewAnyTLS(*anytlsOption)
case "sudoku":
sudokuOption := &outbound.SudokuOption{}
sudokuOption := &outbound.SudokuOption{BasicOption: basicOption}
err = decoder.Decode(mapping, sudokuOption)
if err != nil {
break
@@ -178,3 +183,23 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
proxy = outbound.NewAutoCloseProxyAdapter(proxy)
return NewProxy(proxy), nil
}
type proxyOption struct {
DialerForAPI C.Dialer
}
func applyProxyOptions(options ...ProxyOption) proxyOption {
opt := proxyOption{}
for _, o := range options {
o(&opt)
}
return opt
}
type ProxyOption func(opt *proxyOption)
func WithDialerForAPI(dialer C.Dialer) ProxyOption {
return func(opt *proxyOption) {
opt.DialerForAPI = dialer
}
}

View File

@@ -0,0 +1,37 @@
package proxydialer
import (
"context"
"fmt"
"net"
"net/netip"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/tunnel"
)
type byNameProxyDialer struct {
proxyName string
}
func (d byNameProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
proxies := tunnel.Proxies()
proxy, ok := proxies[d.proxyName]
if !ok {
return nil, fmt.Errorf("proxyName[%s] not found", d.proxyName)
}
return New(proxy, true).DialContext(ctx, network, address)
}
func (d byNameProxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) {
proxies := tunnel.Proxies()
proxy, ok := proxies[d.proxyName]
if !ok {
return nil, fmt.Errorf("proxyName[%s] not found", d.proxyName)
}
return New(proxy, true).ListenPacket(ctx, network, address, rAddrPort)
}
func NewByName(proxyName string) C.Dialer {
return byNameProxyDialer{proxyName: proxyName}
}

View File

@@ -2,34 +2,22 @@ package proxydialer
import (
"context"
"fmt"
"net"
"net/netip"
"strings"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/dialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/tunnel"
"github.com/metacubex/mihomo/tunnel/statistic"
)
type proxyDialer struct {
proxy C.ProxyAdapter
dialer C.Dialer
statistic bool
}
func New(proxy C.ProxyAdapter, dialer C.Dialer, statistic bool) C.Dialer {
return proxyDialer{proxy: proxy, dialer: dialer, statistic: statistic}
}
func NewByName(proxyName string, dialer C.Dialer) (C.Dialer, error) {
proxies := tunnel.Proxies()
if proxy, ok := proxies[proxyName]; ok {
return New(proxy, dialer, true), nil
}
return nil, fmt.Errorf("proxyName[%s] not found", proxyName)
func New(proxy C.ProxyAdapter, statistic bool) C.Dialer {
return proxyDialer{proxy: proxy, statistic: statistic}
}
func (p proxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
@@ -50,13 +38,7 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) (
}
return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil
}
var conn C.Conn
var err error
if _, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work
conn, err = p.proxy.DialContext(ctx, currentMeta)
} else {
conn, err = p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta)
}
conn, err := p.proxy.DialContext(ctx, currentMeta)
if err != nil {
return nil, err
}
@@ -72,14 +54,8 @@ func (p proxyDialer) ListenPacket(ctx context.Context, network, address string,
}
func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) (C.PacketConn, error) {
var pc C.PacketConn
var err error
currentMeta.NetWork = C.UDP
if _, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work
pc, err = p.proxy.ListenPacketContext(ctx, currentMeta)
} else {
pc, err = p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta)
}
pc, err := p.proxy.ListenPacketContext(ctx, currentMeta)
if err != nil {
return nil, err
}

View File

@@ -12,71 +12,22 @@ import (
type SingDialer interface {
N.Dialer
SetDialer(dialer C.Dialer)
}
type singDialer proxyDialer
type singDialer struct {
cDialer C.Dialer
}
var _ N.Dialer = (*singDialer)(nil)
func (d *singDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
return (*proxyDialer)(d).DialContext(ctx, network, destination.String())
func (d singDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
return d.cDialer.DialContext(ctx, network, destination.String())
}
func (d *singDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return (*proxyDialer)(d).ListenPacket(ctx, "udp", "", destination.AddrPort())
func (d singDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return d.cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort())
}
func (d *singDialer) SetDialer(dialer C.Dialer) {
(*proxyDialer)(d).dialer = dialer
}
func NewSingDialer(proxy C.ProxyAdapter, dialer C.Dialer, statistic bool) SingDialer {
return (*singDialer)(&proxyDialer{
proxy: proxy,
dialer: dialer,
statistic: statistic,
})
}
type byNameSingDialer struct {
dialer C.Dialer
proxyName string
}
var _ N.Dialer = (*byNameSingDialer)(nil)
func (d *byNameSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
var cDialer C.Dialer = d.dialer
if len(d.proxyName) > 0 {
pd, err := NewByName(d.proxyName, d.dialer)
if err != nil {
return nil, err
}
cDialer = pd
}
return cDialer.DialContext(ctx, network, destination.String())
}
func (d *byNameSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
var cDialer C.Dialer = d.dialer
if len(d.proxyName) > 0 {
pd, err := NewByName(d.proxyName, d.dialer)
if err != nil {
return nil, err
}
cDialer = pd
}
return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort())
}
func (d *byNameSingDialer) SetDialer(dialer C.Dialer) {
d.dialer = dialer
}
func NewByNameSingDialer(proxyName string, dialer C.Dialer) SingDialer {
return &byNameSingDialer{
dialer: dialer,
proxyName: proxyName,
}
func NewSingDialer(cDialer C.Dialer) SingDialer {
return singDialer{cDialer: cDialer}
}

View File

@@ -121,17 +121,6 @@ type ProxyAdapter interface {
ProxyInfo() ProxyInfo
MarshalJSON() ([]byte, error)
// Deprecated: use DialContextWithDialer and ListenPacketWithDialer instead.
// StreamConn wraps a protocol around net.Conn with Metadata.
//
// Examples:
// conn, _ := net.DialContext(context.Background(), "tcp", "host:port")
// conn, _ = adapter.StreamConnContext(context.Background(), conn, metadata)
//
// It returns a C.Conn with protocol which start with
// a new session (if any)
StreamConnContext(ctx context.Context, c net.Conn, metadata *Metadata) (net.Conn, error)
// DialContext return a C.Conn with protocol which
// contains multiplexing-related reuse logic (if any)
DialContext(ctx context.Context, metadata *Metadata) (Conn, error)
@@ -140,13 +129,6 @@ type ProxyAdapter interface {
// SupportUOT return UDP over TCP support
SupportUOT() bool
// SupportWithDialer only for deprecated relay group, the new protocol does not need to be implemented.
SupportWithDialer() NetWork
// DialContextWithDialer only for deprecated relay group, the new protocol does not need to be implemented.
DialContextWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (Conn, error)
// ListenPacketWithDialer only for deprecated relay group, the new protocol does not need to be implemented.
ListenPacketWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (PacketConn, error)
// IsL3Protocol return ProxyAdapter working in L3 (tell dns module not pass the domain to avoid loopback)
IsL3Protocol(metadata *Metadata) bool

View File

@@ -7,6 +7,7 @@ import (
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log"
mihomoNtp "github.com/metacubex/mihomo/ntp"
@@ -36,9 +37,13 @@ func ReCreateNTPService(server string, interval time.Duration, dialerProxy strin
return
}
ctx, cancel := context.WithCancel(context.Background())
var cDialer C.Dialer = dialer.NewDialer()
if dialerProxy != "" {
cDialer = proxydialer.NewByName(dialerProxy)
}
globalSrv = &Service{
server: M.ParseSocksaddr(server),
dialer: proxydialer.NewByNameSingDialer(dialerProxy, dialer.NewDialer()),
dialer: proxydialer.NewSingDialer(cDialer),
ticker: time.NewTicker(interval * time.Minute),
ctx: ctx,
cancel: cancel,

View File

@@ -18,13 +18,12 @@ var (
TooManyOpenStreams = errors.New("tuic: too many open streams")
)
type DialFunc func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error)
type DialFunc func(ctx context.Context) (transport *quic.Transport, addr net.Addr, err error)
type Client interface {
DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error)
ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error)
DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error)
ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error)
OpenStreams() int64
DialerRef() C.Dialer
LastVisited() time.Time
SetLastVisited(last time.Time)
Close()

View File

@@ -6,6 +6,7 @@ import (
"net"
"runtime"
"sync"
"sync/atomic"
"time"
N "github.com/metacubex/mihomo/common/net"
@@ -17,30 +18,21 @@ import (
list "github.com/bahlo/generic-list-go"
)
type dialResult struct {
transport *quic.Transport
addr net.Addr
err error
}
type PoolClient struct {
newClientOptionV4 *ClientOptionV4
newClientOptionV5 *ClientOptionV5
dialResultMap map[C.Dialer]dialResult
dialResultMutex *sync.Mutex
tcpClients *list.List[Client]
tcpClientsMutex *sync.Mutex
udpClients *list.List[Client]
udpClientsMutex *sync.Mutex
dialHelper *poolDialHelper
tcpClients list.List[Client]
tcpClientsMutex sync.Mutex
udpClients list.List[Client]
udpClientsMutex sync.Mutex
}
func (t *PoolClient) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error) {
newDialFn := func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) {
return t.dial(ctx, dialer, dialFn)
}
conn, err := t.getClient(false, dialer).DialContextWithDialer(ctx, metadata, dialer, newDialFn)
func (t *PoolClient) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) {
conn, err := t.getClient(false).DialContext(ctx, metadata)
if errors.Is(err, TooManyOpenStreams) {
conn, err = t.newClient(false, dialer).DialContextWithDialer(ctx, metadata, dialer, newDialFn)
conn, err = t.newClient(false).DialContext(ctx, metadata)
}
if err != nil {
return nil, err
@@ -48,13 +40,10 @@ func (t *PoolClient) DialContextWithDialer(ctx context.Context, metadata *C.Meta
return N.NewRefConn(conn, t), err
}
func (t *PoolClient) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) {
newDialFn := func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) {
return t.dial(ctx, dialer, dialFn)
}
pc, err := t.getClient(true, dialer).ListenPacketWithDialer(ctx, metadata, dialer, newDialFn)
func (t *PoolClient) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) {
pc, err := t.getClient(true).ListenPacket(ctx, metadata)
if errors.Is(err, TooManyOpenStreams) {
pc, err = t.newClient(true, dialer).ListenPacketWithDialer(ctx, metadata, dialer, newDialFn)
pc, err = t.newClient(true).ListenPacket(ctx, metadata)
}
if err != nil {
return nil, err
@@ -62,58 +51,63 @@ func (t *PoolClient) ListenPacketWithDialer(ctx context.Context, metadata *C.Met
return N.NewRefPacketConn(pc, t), nil
}
func (t *PoolClient) dial(ctx context.Context, dialer C.Dialer, dialFn DialFunc) (transport *quic.Transport, addr net.Addr, err error) {
t.dialResultMutex.Lock()
dr, ok := t.dialResultMap[dialer]
t.dialResultMutex.Unlock()
if ok {
return dr.transport, dr.addr, dr.err
// poolDialHelper is a helper for dialFn
// using a standalone struct to let finalizer working
type poolDialHelper struct {
dialFn DialFunc
dialResult atomic.Pointer[dialResult]
}
type dialResult struct {
transport *quic.Transport
addr net.Addr
}
func (t *poolDialHelper) dial(ctx context.Context) (transport *quic.Transport, addr net.Addr, err error) {
if dr := t.dialResult.Load(); dr != nil {
return dr.transport, dr.addr, nil
}
transport, addr, err = dialFn(ctx, dialer)
transport, addr, err = t.dialFn(ctx)
if err != nil {
return nil, nil, err
}
if _, ok := transport.Conn.(*net.UDPConn); ok { // only cache the system's UDPConn
transport.SetSingleUse(false) // don't close transport in each dial
dr.transport, dr.addr, dr.err = transport, addr, err
t.dialResultMutex.Lock()
t.dialResultMap[dialer] = dr
t.dialResultMutex.Unlock()
dr := &dialResult{transport: transport, addr: addr}
t.dialResult.Store(dr)
}
return transport, addr, err
}
func (t *PoolClient) forceClose() {
t.dialResultMutex.Lock()
defer t.dialResultMutex.Unlock()
for key := range t.dialResultMap {
transport := t.dialResultMap[key].transport
func (t *poolDialHelper) forceClose() {
if dr := t.dialResult.Swap(nil); dr != nil {
transport := dr.transport
if transport != nil {
_ = transport.Close()
}
delete(t.dialResultMap, key)
}
}
func (t *PoolClient) newClient(udp bool, dialer C.Dialer) (client Client) {
clients := t.tcpClients
clientsMutex := t.tcpClientsMutex
func (t *PoolClient) newClient(udp bool) (client Client) {
clients := &t.tcpClients
clientsMutex := &t.tcpClientsMutex
if udp {
clients = t.udpClients
clientsMutex = t.udpClientsMutex
clients = &t.udpClients
clientsMutex = &t.udpClientsMutex
}
clientsMutex.Lock()
defer clientsMutex.Unlock()
dialHelper := t.dialHelper
if t.newClientOptionV4 != nil {
client = NewClientV4(t.newClientOptionV4, udp, dialer)
client = NewClientV4(t.newClientOptionV4, udp, dialHelper.dial)
} else {
client = NewClientV5(t.newClientOptionV5, udp, dialer)
client = NewClientV5(t.newClientOptionV5, udp, dialHelper.dial)
}
client.SetLastVisited(time.Now())
@@ -122,12 +116,12 @@ func (t *PoolClient) newClient(udp bool, dialer C.Dialer) (client Client) {
return client
}
func (t *PoolClient) getClient(udp bool, dialer C.Dialer) Client {
clients := t.tcpClients
clientsMutex := t.tcpClientsMutex
func (t *PoolClient) getClient(udp bool) Client {
clients := &t.tcpClients
clientsMutex := &t.tcpClientsMutex
if udp {
clients = t.udpClients
clientsMutex = t.udpClientsMutex
clients = &t.udpClients
clientsMutex = &t.udpClientsMutex
}
var bestClient Client
@@ -142,46 +136,39 @@ func (t *PoolClient) getClient(udp bool, dialer C.Dialer) Client {
it = next
continue
}
if client.DialerRef() == dialer {
if bestClient == nil {
if bestClient == nil {
bestClient = client
} else {
if client.OpenStreams() < bestClient.OpenStreams() {
bestClient = client
} else {
if client.OpenStreams() < bestClient.OpenStreams() {
bestClient = client
}
}
}
it = it.Next()
}
}()
for it := clients.Front(); it != nil; {
client := it.Value
if client != bestClient && client.OpenStreams() == 0 && time.Now().Sub(client.LastVisited()) > 30*time.Minute {
client.Close()
next := it.Next()
clients.Remove(it)
it = next
continue
for it := clients.Front(); it != nil; {
client := it.Value
if client != bestClient && client.OpenStreams() == 0 && time.Now().Sub(client.LastVisited()) > 30*time.Minute {
client.Close()
next := it.Next()
clients.Remove(it)
it = next
continue
}
it = it.Next()
}
it = it.Next()
}
}()
if bestClient == nil {
return t.newClient(udp, dialer)
return t.newClient(udp)
} else {
bestClient.SetLastVisited(time.Now())
return bestClient
}
}
func NewPoolClientV4(clientOption *ClientOptionV4) *PoolClient {
func NewPoolClientV4(clientOption *ClientOptionV4, dialFn DialFunc) *PoolClient {
p := &PoolClient{
dialResultMap: make(map[C.Dialer]dialResult),
dialResultMutex: &sync.Mutex{},
tcpClients: list.New[Client](),
tcpClientsMutex: &sync.Mutex{},
udpClients: list.New[Client](),
udpClientsMutex: &sync.Mutex{},
dialHelper: &poolDialHelper{dialFn: dialFn},
}
newClientOption := *clientOption
p.newClientOptionV4 = &newClientOption
@@ -190,14 +177,9 @@ func NewPoolClientV4(clientOption *ClientOptionV4) *PoolClient {
return p
}
func NewPoolClientV5(clientOption *ClientOptionV5) *PoolClient {
func NewPoolClientV5(clientOption *ClientOptionV5, dialFn DialFunc) *PoolClient {
p := &PoolClient{
dialResultMap: make(map[C.Dialer]dialResult),
dialResultMutex: &sync.Mutex{},
tcpClients: list.New[Client](),
tcpClientsMutex: &sync.Mutex{},
udpClients: list.New[Client](),
udpClientsMutex: &sync.Mutex{},
dialHelper: &poolDialHelper{dialFn: dialFn},
}
newClientOption := *clientOption
p.newClientOptionV5 = &newClientOption
@@ -208,5 +190,5 @@ func NewPoolClientV5(clientOption *ClientOptionV5) *PoolClient {
func closeClientPool(client *PoolClient) {
log.Debugln("Close Tuic PoolClient at %p", client)
client.forceClose()
client.dialHelper.forceClose()
}

View File

@@ -1,7 +1,6 @@
package tuic
import (
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/tuic/common"
v4 "github.com/metacubex/mihomo/transport/tuic/v4"
v5 "github.com/metacubex/mihomo/transport/tuic/v5"
@@ -12,12 +11,12 @@ type ClientOptionV5 = v5.ClientOption
type Client = common.Client
func NewClientV4(clientOption *ClientOptionV4, udp bool, dialerRef C.Dialer) Client {
return v4.NewClient(clientOption, udp, dialerRef)
func NewClientV4(clientOption *ClientOptionV4, udp bool, dialFn DialFunc) Client {
return v4.NewClient(clientOption, udp, dialFn)
}
func NewClientV5(clientOption *ClientOptionV5, udp bool, dialerRef C.Dialer) Client {
return v5.NewClient(clientOption, udp, dialerRef)
func NewClientV5(clientOption *ClientOptionV5, udp bool, dialFn DialFunc) Client {
return v5.NewClient(clientOption, udp, dialFn)
}
type DialFunc = common.DialFunc

View File

@@ -40,7 +40,8 @@ type ClientOption struct {
type clientImpl struct {
*ClientOption
udp bool
dialFn common.DialFunc
udp bool
quicConn *quic.Conn
connMutex sync.Mutex
@@ -51,7 +52,6 @@ type clientImpl struct {
udpInputMap xsync.Map[uint32, net.Conn]
// only ready for PoolClient
dialerRef C.Dialer
lastVisited atomic2.TypedValue[time.Time]
}
@@ -59,10 +59,6 @@ func (t *clientImpl) OpenStreams() int64 {
return t.openStreams.Load()
}
func (t *clientImpl) DialerRef() C.Dialer {
return t.dialerRef
}
func (t *clientImpl) LastVisited() time.Time {
return t.lastVisited.Load()
}
@@ -71,13 +67,13 @@ func (t *clientImpl) SetLastVisited(last time.Time) {
t.lastVisited.Store(last)
}
func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn common.DialFunc) (*quic.Conn, error) {
func (t *clientImpl) getQuicConn(ctx context.Context) (*quic.Conn, error) {
t.connMutex.Lock()
defer t.connMutex.Unlock()
if t.quicConn != nil {
return t.quicConn, nil
}
transport, addr, err := dialFn(ctx, dialer)
transport, addr, err := t.dialFn(ctx)
if err != nil {
return nil, err
}
@@ -262,7 +258,7 @@ func (t *clientImpl) forceClose(quicConn *quic.Conn, err error) {
if quicConn != nil {
_ = quicConn.CloseWithError(ProtocolError, errStr)
}
udpInputMap := t.udpInputMap
udpInputMap := &t.udpInputMap
udpInputMap.Range(func(key uint32, value net.Conn) bool {
conn := value
_ = conn.Close()
@@ -278,8 +274,8 @@ func (t *clientImpl) Close() {
}
}
func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) {
quicConn, err := t.getQuicConn(ctx, dialer, dialFn)
func (t *clientImpl) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) {
quicConn, err := t.getQuicConn(ctx)
if err != nil {
return nil, err
}
@@ -353,8 +349,8 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta
return bufConn, nil
}
func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) {
quicConn, err := t.getQuicConn(ctx, dialer, dialFn)
func (t *clientImpl) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) {
quicConn, err := t.getQuicConn(ctx)
if err != nil {
return nil, err
}
@@ -397,16 +393,16 @@ type Client struct {
*clientImpl // use an independent pointer to let Finalizer can work no matter somewhere handle an influence in clientImpl inner
}
func (t *Client) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) {
conn, err := t.clientImpl.DialContextWithDialer(ctx, metadata, dialer, dialFn)
func (t *Client) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) {
conn, err := t.clientImpl.DialContext(ctx, metadata)
if err != nil {
return nil, err
}
return N.NewRefConn(conn, t), err
}
func (t *Client) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) {
pc, err := t.clientImpl.ListenPacketWithDialer(ctx, metadata, dialer, dialFn)
func (t *Client) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) {
pc, err := t.clientImpl.ListenPacket(ctx, metadata)
if err != nil {
return nil, err
}
@@ -417,11 +413,11 @@ func (t *Client) forceClose() {
t.clientImpl.forceClose(nil, common.ClientClosed)
}
func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client {
func NewClient(clientOption *ClientOption, udp bool, dialFn common.DialFunc) *Client {
ci := &clientImpl{
ClientOption: clientOption,
dialFn: dialFn,
udp: udp,
dialerRef: dialerRef,
}
c := &Client{ci}
runtime.SetFinalizer(c, closeClient)

View File

@@ -39,7 +39,8 @@ type ClientOption struct {
type clientImpl struct {
*ClientOption
udp bool
dialFn common.DialFunc
udp bool
quicConn *quic.Conn
connMutex sync.Mutex
@@ -50,7 +51,6 @@ type clientImpl struct {
udpInputMap xsync.Map[uint16, net.Conn]
// only ready for PoolClient
dialerRef C.Dialer
lastVisited atomic2.TypedValue[time.Time]
}
@@ -58,10 +58,6 @@ func (t *clientImpl) OpenStreams() int64 {
return t.openStreams.Load()
}
func (t *clientImpl) DialerRef() C.Dialer {
return t.dialerRef
}
func (t *clientImpl) LastVisited() time.Time {
return t.lastVisited.Load()
}
@@ -70,13 +66,13 @@ func (t *clientImpl) SetLastVisited(last time.Time) {
t.lastVisited.Store(last)
}
func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn common.DialFunc) (*quic.Conn, error) {
func (t *clientImpl) getQuicConn(ctx context.Context) (*quic.Conn, error) {
t.connMutex.Lock()
defer t.connMutex.Unlock()
if t.quicConn != nil {
return t.quicConn, nil
}
transport, addr, err := dialFn(ctx, dialer)
transport, addr, err := t.dialFn(ctx)
if err != nil {
return nil, err
}
@@ -270,7 +266,7 @@ func (t *clientImpl) forceClose(quicConn *quic.Conn, err error) {
if quicConn != nil {
_ = quicConn.CloseWithError(ProtocolError, errStr)
}
udpInputMap := t.udpInputMap
udpInputMap := &t.udpInputMap
udpInputMap.Range(func(key uint16, value net.Conn) bool {
conn := value
_ = conn.Close()
@@ -286,8 +282,8 @@ func (t *clientImpl) Close() {
}
}
func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) {
quicConn, err := t.getQuicConn(ctx, dialer, dialFn)
func (t *clientImpl) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) {
quicConn, err := t.getQuicConn(ctx)
if err != nil {
return nil, err
}
@@ -337,8 +333,8 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta
return stream, nil
}
func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) {
quicConn, err := t.getQuicConn(ctx, dialer, dialFn)
func (t *clientImpl) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) {
quicConn, err := t.getQuicConn(ctx)
if err != nil {
return nil, err
}
@@ -381,16 +377,16 @@ type Client struct {
*clientImpl // use an independent pointer to let Finalizer can work no matter somewhere handle an influence in clientImpl inner
}
func (t *Client) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) {
conn, err := t.clientImpl.DialContextWithDialer(ctx, metadata, dialer, dialFn)
func (t *Client) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) {
conn, err := t.clientImpl.DialContext(ctx, metadata)
if err != nil {
return nil, err
}
return N.NewRefConn(conn, t), err
}
func (t *Client) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) {
pc, err := t.clientImpl.ListenPacketWithDialer(ctx, metadata, dialer, dialFn)
func (t *Client) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) {
pc, err := t.clientImpl.ListenPacket(ctx, metadata)
if err != nil {
return nil, err
}
@@ -401,11 +397,11 @@ func (t *Client) forceClose() {
t.clientImpl.forceClose(nil, common.ClientClosed)
}
func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client {
func NewClient(clientOption *ClientOption, udp bool, dialFn common.DialFunc) *Client {
ci := &clientImpl{
ClientOption: clientOption,
dialFn: dialFn,
udp: udp,
dialerRef: dialerRef,
}
c := &Client{ci}
runtime.SetFinalizer(c, closeClient)