base.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. package outbound
  2. import (
  3. "context"
  4. "encoding/json"
  5. "net"
  6. "strings"
  7. "syscall"
  8. N "github.com/metacubex/mihomo/common/net"
  9. "github.com/metacubex/mihomo/common/utils"
  10. "github.com/metacubex/mihomo/component/dialer"
  11. C "github.com/metacubex/mihomo/constant"
  12. )
  13. type Base struct {
  14. name string
  15. addr string
  16. iface string
  17. tp C.AdapterType
  18. udp bool
  19. xudp bool
  20. tfo bool
  21. mpTcp bool
  22. rmark int
  23. id string
  24. prefer C.DNSPrefer
  25. }
  26. // Name implements C.ProxyAdapter
  27. func (b *Base) Name() string {
  28. return b.name
  29. }
  30. // Id implements C.ProxyAdapter
  31. func (b *Base) Id() string {
  32. if b.id == "" {
  33. b.id = utils.NewUUIDV6().String()
  34. }
  35. return b.id
  36. }
  37. // Type implements C.ProxyAdapter
  38. func (b *Base) Type() C.AdapterType {
  39. return b.tp
  40. }
  41. // StreamConnContext implements C.ProxyAdapter
  42. func (b *Base) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
  43. return c, C.ErrNotSupport
  44. }
  45. func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
  46. return nil, C.ErrNotSupport
  47. }
  48. // DialContextWithDialer implements C.ProxyAdapter
  49. func (b *Base) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
  50. return nil, C.ErrNotSupport
  51. }
  52. // ListenPacketContext implements C.ProxyAdapter
  53. func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
  54. return nil, C.ErrNotSupport
  55. }
  56. // ListenPacketWithDialer implements C.ProxyAdapter
  57. func (b *Base) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
  58. return nil, C.ErrNotSupport
  59. }
  60. // SupportWithDialer implements C.ProxyAdapter
  61. func (b *Base) SupportWithDialer() C.NetWork {
  62. return C.InvalidNet
  63. }
  64. // SupportUOT implements C.ProxyAdapter
  65. func (b *Base) SupportUOT() bool {
  66. return false
  67. }
  68. // SupportUDP implements C.ProxyAdapter
  69. func (b *Base) SupportUDP() bool {
  70. return b.udp
  71. }
  72. // SupportXUDP implements C.ProxyAdapter
  73. func (b *Base) SupportXUDP() bool {
  74. return b.xudp
  75. }
  76. // SupportTFO implements C.ProxyAdapter
  77. func (b *Base) SupportTFO() bool {
  78. return b.tfo
  79. }
  80. // IsL3Protocol implements C.ProxyAdapter
  81. func (b *Base) IsL3Protocol(metadata *C.Metadata) bool {
  82. return false
  83. }
  84. // MarshalJSON implements C.ProxyAdapter
  85. func (b *Base) MarshalJSON() ([]byte, error) {
  86. return json.Marshal(map[string]string{
  87. "type": b.Type().String(),
  88. "id": b.Id(),
  89. })
  90. }
  91. // Addr implements C.ProxyAdapter
  92. func (b *Base) Addr() string {
  93. return b.addr
  94. }
  95. // Unwrap implements C.ProxyAdapter
  96. func (b *Base) Unwrap(metadata *C.Metadata, touch bool) C.Proxy {
  97. return nil
  98. }
  99. // DialOptions return []dialer.Option from struct
  100. func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option {
  101. if b.iface != "" {
  102. opts = append(opts, dialer.WithInterface(b.iface))
  103. }
  104. if b.rmark != 0 {
  105. opts = append(opts, dialer.WithRoutingMark(b.rmark))
  106. }
  107. switch b.prefer {
  108. case C.IPv4Only:
  109. opts = append(opts, dialer.WithOnlySingleStack(true))
  110. case C.IPv6Only:
  111. opts = append(opts, dialer.WithOnlySingleStack(false))
  112. case C.IPv4Prefer:
  113. opts = append(opts, dialer.WithPreferIPv4())
  114. case C.IPv6Prefer:
  115. opts = append(opts, dialer.WithPreferIPv6())
  116. default:
  117. }
  118. if b.tfo {
  119. opts = append(opts, dialer.WithTFO(true))
  120. }
  121. if b.mpTcp {
  122. opts = append(opts, dialer.WithMPTCP(true))
  123. }
  124. return opts
  125. }
  126. type BasicOption struct {
  127. TFO bool `proxy:"tfo,omitempty" group:"tfo,omitempty"`
  128. MPTCP bool `proxy:"mptcp,omitempty" group:"mptcp,omitempty"`
  129. Interface string `proxy:"interface-name,omitempty" group:"interface-name,omitempty"`
  130. RoutingMark int `proxy:"routing-mark,omitempty" group:"routing-mark,omitempty"`
  131. IPVersion string `proxy:"ip-version,omitempty" group:"ip-version,omitempty"`
  132. DialerProxy string `proxy:"dialer-proxy,omitempty"` // don't apply this option into groups, but can set a group name in a proxy
  133. }
  134. type BaseOption struct {
  135. Name string
  136. Addr string
  137. Type C.AdapterType
  138. UDP bool
  139. XUDP bool
  140. TFO bool
  141. MPTCP bool
  142. Interface string
  143. RoutingMark int
  144. Prefer C.DNSPrefer
  145. }
  146. func NewBase(opt BaseOption) *Base {
  147. return &Base{
  148. name: opt.Name,
  149. addr: opt.Addr,
  150. tp: opt.Type,
  151. udp: opt.UDP,
  152. xudp: opt.XUDP,
  153. tfo: opt.TFO,
  154. mpTcp: opt.MPTCP,
  155. iface: opt.Interface,
  156. rmark: opt.RoutingMark,
  157. prefer: opt.Prefer,
  158. }
  159. }
  160. type conn struct {
  161. N.ExtendedConn
  162. chain C.Chain
  163. actualRemoteDestination string
  164. }
  165. func (c *conn) RemoteDestination() string {
  166. return c.actualRemoteDestination
  167. }
  168. // Chains implements C.Connection
  169. func (c *conn) Chains() C.Chain {
  170. return c.chain
  171. }
  172. // AppendToChains implements C.Connection
  173. func (c *conn) AppendToChains(a C.ProxyAdapter) {
  174. c.chain = append(c.chain, a.Name())
  175. }
  176. func (c *conn) Upstream() any {
  177. return c.ExtendedConn
  178. }
  179. func (c *conn) WriterReplaceable() bool {
  180. return true
  181. }
  182. func (c *conn) ReaderReplaceable() bool {
  183. return true
  184. }
  185. func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
  186. if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn
  187. c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly
  188. }
  189. return &conn{N.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())}
  190. }
  191. type packetConn struct {
  192. N.EnhancePacketConn
  193. chain C.Chain
  194. adapterName string
  195. connID string
  196. actualRemoteDestination string
  197. }
  198. func (c *packetConn) RemoteDestination() string {
  199. return c.actualRemoteDestination
  200. }
  201. // Chains implements C.Connection
  202. func (c *packetConn) Chains() C.Chain {
  203. return c.chain
  204. }
  205. // AppendToChains implements C.Connection
  206. func (c *packetConn) AppendToChains(a C.ProxyAdapter) {
  207. c.chain = append(c.chain, a.Name())
  208. }
  209. func (c *packetConn) LocalAddr() net.Addr {
  210. lAddr := c.EnhancePacketConn.LocalAddr()
  211. return N.NewCustomAddr(c.adapterName, c.connID, lAddr) // make quic-go's connMultiplexer happy
  212. }
  213. func (c *packetConn) Upstream() any {
  214. return c.EnhancePacketConn
  215. }
  216. func (c *packetConn) WriterReplaceable() bool {
  217. return true
  218. }
  219. func (c *packetConn) ReaderReplaceable() bool {
  220. return true
  221. }
  222. func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
  223. epc := N.NewEnhancePacketConn(pc)
  224. if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
  225. epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
  226. }
  227. return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())}
  228. }
  229. func parseRemoteDestination(addr string) string {
  230. if dst, _, err := net.SplitHostPort(addr); err == nil {
  231. return dst
  232. } else {
  233. if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
  234. return dst
  235. } else {
  236. return ""
  237. }
  238. }
  239. }