relay.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package outboundgroup
  2. import (
  3. "context"
  4. "encoding/json"
  5. "github.com/metacubex/mihomo/adapter/outbound"
  6. "github.com/metacubex/mihomo/component/dialer"
  7. "github.com/metacubex/mihomo/component/proxydialer"
  8. C "github.com/metacubex/mihomo/constant"
  9. "github.com/metacubex/mihomo/constant/provider"
  10. "github.com/metacubex/mihomo/log"
  11. )
  12. type Relay struct {
  13. *GroupBase
  14. Hidden bool
  15. Icon string
  16. }
  17. // DialContext implements C.ProxyAdapter
  18. func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
  19. proxies, chainProxies := r.proxies(metadata, true)
  20. switch len(proxies) {
  21. case 0:
  22. return outbound.NewDirect().DialContext(ctx, metadata, r.Base.DialOptions(opts...)...)
  23. case 1:
  24. return proxies[0].DialContext(ctx, metadata, r.Base.DialOptions(opts...)...)
  25. }
  26. var d C.Dialer
  27. d = dialer.NewDialer(r.Base.DialOptions(opts...)...)
  28. for _, proxy := range proxies[:len(proxies)-1] {
  29. d = proxydialer.New(proxy, d, false)
  30. }
  31. last := proxies[len(proxies)-1]
  32. conn, err := last.DialContextWithDialer(ctx, d, metadata)
  33. if err != nil {
  34. return nil, err
  35. }
  36. for i := len(chainProxies) - 2; i >= 0; i-- {
  37. conn.AppendToChains(chainProxies[i])
  38. }
  39. conn.AppendToChains(r)
  40. return conn, nil
  41. }
  42. // ListenPacketContext implements C.ProxyAdapter
  43. func (r *Relay) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) {
  44. proxies, chainProxies := r.proxies(metadata, true)
  45. switch len(proxies) {
  46. case 0:
  47. return outbound.NewDirect().ListenPacketContext(ctx, metadata, r.Base.DialOptions(opts...)...)
  48. case 1:
  49. return proxies[0].ListenPacketContext(ctx, metadata, r.Base.DialOptions(opts...)...)
  50. }
  51. var d C.Dialer
  52. d = dialer.NewDialer(r.Base.DialOptions(opts...)...)
  53. for _, proxy := range proxies[:len(proxies)-1] {
  54. d = proxydialer.New(proxy, d, false)
  55. }
  56. last := proxies[len(proxies)-1]
  57. pc, err := last.ListenPacketWithDialer(ctx, d, metadata)
  58. if err != nil {
  59. return nil, err
  60. }
  61. for i := len(chainProxies) - 2; i >= 0; i-- {
  62. pc.AppendToChains(chainProxies[i])
  63. }
  64. pc.AppendToChains(r)
  65. return pc, nil
  66. }
  67. // SupportUDP implements C.ProxyAdapter
  68. func (r *Relay) SupportUDP() bool {
  69. proxies, _ := r.proxies(nil, false)
  70. if len(proxies) == 0 { // C.Direct
  71. return true
  72. }
  73. for i := len(proxies) - 1; i >= 0; i-- {
  74. proxy := proxies[i]
  75. if !proxy.SupportUDP() {
  76. return false
  77. }
  78. if proxy.SupportUOT() {
  79. return true
  80. }
  81. switch proxy.SupportWithDialer() {
  82. case C.ALLNet:
  83. case C.UDP:
  84. default: // C.TCP and C.InvalidNet
  85. return false
  86. }
  87. }
  88. return true
  89. }
  90. // MarshalJSON implements C.ProxyAdapter
  91. func (r *Relay) MarshalJSON() ([]byte, error) {
  92. all := []string{}
  93. for _, proxy := range r.GetProxies(false) {
  94. all = append(all, proxy.Name())
  95. }
  96. return json.Marshal(map[string]any{
  97. "type": r.Type().String(),
  98. "all": all,
  99. "hidden": r.Hidden,
  100. "icon": r.Icon,
  101. })
  102. }
  103. func (r *Relay) proxies(metadata *C.Metadata, touch bool) ([]C.Proxy, []C.Proxy) {
  104. rawProxies := r.GetProxies(touch)
  105. var proxies []C.Proxy
  106. var chainProxies []C.Proxy
  107. var targetProxies []C.Proxy
  108. for n, proxy := range rawProxies {
  109. proxies = append(proxies, proxy)
  110. chainProxies = append(chainProxies, proxy)
  111. subproxy := proxy.Unwrap(metadata, touch)
  112. for subproxy != nil {
  113. chainProxies = append(chainProxies, subproxy)
  114. proxies[n] = subproxy
  115. subproxy = subproxy.Unwrap(metadata, touch)
  116. }
  117. }
  118. for _, proxy := range proxies {
  119. if proxy.Type() != C.Direct && proxy.Type() != C.Compatible {
  120. targetProxies = append(targetProxies, proxy)
  121. }
  122. }
  123. return targetProxies, chainProxies
  124. }
  125. func (r *Relay) Addr() string {
  126. proxies, _ := r.proxies(nil, false)
  127. return proxies[len(proxies)-1].Addr()
  128. }
  129. func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
  130. log.Warnln("The group [%s] with relay type is deprecated, please using dialer-proxy instead", option.Name)
  131. return &Relay{
  132. GroupBase: NewGroupBase(GroupBaseOption{
  133. outbound.BaseOption{
  134. Name: option.Name,
  135. Type: C.Relay,
  136. Interface: option.Interface,
  137. RoutingMark: option.RoutingMark,
  138. },
  139. "",
  140. "",
  141. "",
  142. 5000,
  143. 5,
  144. providers,
  145. }),
  146. Hidden: option.Hidden,
  147. Icon: option.Icon,
  148. }
  149. }