github.com/kelleygo/clashcore@v1.0.2/component/proxydialer/proxydialer.go (about) 1 package proxydialer 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "net/netip" 9 "strings" 10 11 N "github.com/kelleygo/clashcore/common/net" 12 "github.com/kelleygo/clashcore/component/dialer" 13 "github.com/kelleygo/clashcore/component/resolver" 14 C "github.com/kelleygo/clashcore/constant" 15 "github.com/kelleygo/clashcore/tunnel" 16 "github.com/kelleygo/clashcore/tunnel/statistic" 17 ) 18 19 type proxyDialer struct { 20 proxy C.ProxyAdapter 21 dialer C.Dialer 22 statistic bool 23 } 24 25 func New(proxy C.ProxyAdapter, dialer C.Dialer, statistic bool) C.Dialer { 26 return proxyDialer{proxy: proxy, dialer: dialer, statistic: statistic} 27 } 28 29 func NewByName(proxyName string, dialer C.Dialer) (C.Dialer, error) { 30 proxies := tunnel.Proxies() 31 if proxy, ok := proxies[proxyName]; ok { 32 return New(proxy, dialer, true), nil 33 } 34 return nil, fmt.Errorf("proxyName[%s] not found", proxyName) 35 } 36 37 func (p proxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { 38 currentMeta := &C.Metadata{Type: C.INNER} 39 if err := currentMeta.SetRemoteAddress(address); err != nil { 40 return nil, err 41 } 42 if strings.Contains(network, "udp") { // using in wireguard outbound 43 if !currentMeta.Resolved() { 44 ip, err := resolver.ResolveIP(ctx, currentMeta.Host) 45 if err != nil { 46 return nil, errors.New("can't resolve ip") 47 } 48 currentMeta.DstIP = ip 49 } 50 pc, err := p.listenPacket(ctx, currentMeta) 51 if err != nil { 52 return nil, err 53 } 54 return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil 55 } 56 var conn C.Conn 57 var err error 58 if d, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work 59 conn, err = p.proxy.DialContext(ctx, currentMeta, dialer.WithOption(d.Opt)) 60 } else { 61 conn, err = p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) 62 } 63 if err != nil { 64 return nil, err 65 } 66 if p.statistic { 67 conn = statistic.NewTCPTracker(conn, statistic.DefaultManager, currentMeta, nil, 0, 0, false) 68 } 69 return conn, err 70 } 71 72 func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { 73 currentMeta := &C.Metadata{Type: C.INNER, DstIP: rAddrPort.Addr(), DstPort: rAddrPort.Port()} 74 return p.listenPacket(ctx, currentMeta) 75 } 76 77 func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) (C.PacketConn, error) { 78 var pc C.PacketConn 79 var err error 80 currentMeta.NetWork = C.UDP 81 if d, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work 82 pc, err = p.proxy.ListenPacketContext(ctx, currentMeta, dialer.WithOption(d.Opt)) 83 } else { 84 pc, err = p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) 85 } 86 if err != nil { 87 return nil, err 88 } 89 if p.statistic { 90 pc = statistic.NewUDPTracker(pc, statistic.DefaultManager, currentMeta, nil, 0, 0, false) 91 } 92 return pc, nil 93 }