proxydialer.go 2.7 KB

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