shadowsocks.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. package outbound
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "strconv"
  8. N "github.com/metacubex/mihomo/common/net"
  9. "github.com/metacubex/mihomo/common/structure"
  10. "github.com/metacubex/mihomo/component/dialer"
  11. "github.com/metacubex/mihomo/component/proxydialer"
  12. "github.com/metacubex/mihomo/component/resolver"
  13. C "github.com/metacubex/mihomo/constant"
  14. "github.com/metacubex/mihomo/transport/restls"
  15. obfs "github.com/metacubex/mihomo/transport/simple-obfs"
  16. shadowtls "github.com/metacubex/mihomo/transport/sing-shadowtls"
  17. v2rayObfs "github.com/metacubex/mihomo/transport/v2ray-plugin"
  18. restlsC "github.com/3andne/restls-client-go"
  19. shadowsocks "github.com/metacubex/sing-shadowsocks2"
  20. "github.com/sagernet/sing/common/bufio"
  21. M "github.com/sagernet/sing/common/metadata"
  22. "github.com/sagernet/sing/common/uot"
  23. )
  24. type ShadowSocks struct {
  25. *Base
  26. method shadowsocks.Method
  27. option *ShadowSocksOption
  28. // obfs
  29. obfsMode string
  30. obfsOption *simpleObfsOption
  31. v2rayOption *v2rayObfs.Option
  32. shadowTLSOption *shadowtls.ShadowTLSOption
  33. restlsConfig *restlsC.Config
  34. }
  35. type ShadowSocksOption struct {
  36. BasicOption
  37. Name string `proxy:"name"`
  38. Server string `proxy:"server"`
  39. Port int `proxy:"port"`
  40. Password string `proxy:"password"`
  41. Cipher string `proxy:"cipher"`
  42. UDP bool `proxy:"udp,omitempty"`
  43. Plugin string `proxy:"plugin,omitempty"`
  44. PluginOpts map[string]any `proxy:"plugin-opts,omitempty"`
  45. UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"`
  46. UDPOverTCPVersion int `proxy:"udp-over-tcp-version,omitempty"`
  47. ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
  48. }
  49. type simpleObfsOption struct {
  50. Mode string `obfs:"mode,omitempty"`
  51. Host string `obfs:"host,omitempty"`
  52. }
  53. type v2rayObfsOption struct {
  54. Mode string `obfs:"mode"`
  55. Host string `obfs:"host,omitempty"`
  56. Path string `obfs:"path,omitempty"`
  57. TLS bool `obfs:"tls,omitempty"`
  58. Fingerprint string `obfs:"fingerprint,omitempty"`
  59. Headers map[string]string `obfs:"headers,omitempty"`
  60. SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
  61. Mux bool `obfs:"mux,omitempty"`
  62. V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"`
  63. V2rayHttpUpgradeFastOpen bool `obfs:"v2ray-http-upgrade-fast-open,omitempty"`
  64. }
  65. type shadowTLSOption struct {
  66. Password string `obfs:"password"`
  67. Host string `obfs:"host"`
  68. Fingerprint string `obfs:"fingerprint,omitempty"`
  69. SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
  70. Version int `obfs:"version,omitempty"`
  71. }
  72. type restlsOption struct {
  73. Password string `obfs:"password"`
  74. Host string `obfs:"host"`
  75. VersionHint string `obfs:"version-hint"`
  76. RestlsScript string `obfs:"restls-script,omitempty"`
  77. }
  78. // StreamConnContext implements C.ProxyAdapter
  79. func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
  80. useEarly := false
  81. switch ss.obfsMode {
  82. case "tls":
  83. c = obfs.NewTLSObfs(c, ss.obfsOption.Host)
  84. case "http":
  85. _, port, _ := net.SplitHostPort(ss.addr)
  86. c = obfs.NewHTTPObfs(c, ss.obfsOption.Host, port)
  87. case "websocket":
  88. var err error
  89. c, err = v2rayObfs.NewV2rayObfs(ctx, c, ss.v2rayOption)
  90. if err != nil {
  91. return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
  92. }
  93. case shadowtls.Mode:
  94. var err error
  95. c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption)
  96. if err != nil {
  97. return nil, err
  98. }
  99. useEarly = true
  100. case restls.Mode:
  101. var err error
  102. c, err = restls.NewRestls(ctx, c, ss.restlsConfig)
  103. if err != nil {
  104. return nil, fmt.Errorf("%s (restls) connect error: %w", ss.addr, err)
  105. }
  106. useEarly = true
  107. }
  108. useEarly = useEarly || N.NeedHandshake(c)
  109. if metadata.NetWork == C.UDP && ss.option.UDPOverTCP {
  110. uotDestination := uot.RequestDestination(uint8(ss.option.UDPOverTCPVersion))
  111. if useEarly {
  112. return ss.method.DialEarlyConn(c, uotDestination), nil
  113. } else {
  114. return ss.method.DialConn(c, uotDestination)
  115. }
  116. }
  117. if useEarly {
  118. return ss.method.DialEarlyConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)), nil
  119. } else {
  120. return ss.method.DialConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort))
  121. }
  122. }
  123. // DialContext implements C.ProxyAdapter
  124. func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
  125. return ss.DialContextWithDialer(ctx, dialer.NewDialer(ss.Base.DialOptions(opts...)...), metadata)
  126. }
  127. // DialContextWithDialer implements C.ProxyAdapter
  128. func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
  129. if len(ss.option.DialerProxy) > 0 {
  130. dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer)
  131. if err != nil {
  132. return nil, err
  133. }
  134. }
  135. c, err := dialer.DialContext(ctx, "tcp", ss.addr)
  136. if err != nil {
  137. return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
  138. }
  139. N.TCPKeepAlive(c)
  140. defer func(c net.Conn) {
  141. safeConnClose(c, err)
  142. }(c)
  143. c, err = ss.StreamConnContext(ctx, c, metadata)
  144. return NewConn(c, ss), err
  145. }
  146. // ListenPacketContext implements C.ProxyAdapter
  147. func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
  148. return ss.ListenPacketWithDialer(ctx, dialer.NewDialer(ss.Base.DialOptions(opts...)...), metadata)
  149. }
  150. // ListenPacketWithDialer implements C.ProxyAdapter
  151. func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
  152. if ss.option.UDPOverTCP {
  153. tcpConn, err := ss.DialContextWithDialer(ctx, dialer, metadata)
  154. if err != nil {
  155. return nil, err
  156. }
  157. return ss.ListenPacketOnStreamConn(ctx, tcpConn, metadata)
  158. }
  159. if len(ss.option.DialerProxy) > 0 {
  160. dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer)
  161. if err != nil {
  162. return nil, err
  163. }
  164. }
  165. addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer)
  166. if err != nil {
  167. return nil, err
  168. }
  169. pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort())
  170. if err != nil {
  171. return nil, err
  172. }
  173. pc = ss.method.DialPacketConn(bufio.NewBindPacketConn(pc, addr))
  174. return newPacketConn(pc, ss), nil
  175. }
  176. // SupportWithDialer implements C.ProxyAdapter
  177. func (ss *ShadowSocks) SupportWithDialer() C.NetWork {
  178. return C.ALLNet
  179. }
  180. // ListenPacketOnStreamConn implements C.ProxyAdapter
  181. func (ss *ShadowSocks) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
  182. if ss.option.UDPOverTCP {
  183. // ss uot use stream-oriented udp with a special address, so we need a net.UDPAddr
  184. if !metadata.Resolved() {
  185. ip, err := resolver.ResolveIP(ctx, metadata.Host)
  186. if err != nil {
  187. return nil, errors.New("can't resolve ip")
  188. }
  189. metadata.DstIP = ip
  190. }
  191. destination := M.SocksaddrFromNet(metadata.UDPAddr())
  192. if ss.option.UDPOverTCPVersion == uot.LegacyVersion {
  193. return newPacketConn(N.NewThreadSafePacketConn(uot.NewConn(c, uot.Request{Destination: destination})), ss), nil
  194. } else {
  195. return newPacketConn(N.NewThreadSafePacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination})), ss), nil
  196. }
  197. }
  198. return nil, C.ErrNotSupport
  199. }
  200. // SupportUOT implements C.ProxyAdapter
  201. func (ss *ShadowSocks) SupportUOT() bool {
  202. return ss.option.UDPOverTCP
  203. }
  204. func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
  205. addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
  206. method, err := shadowsocks.CreateMethod(context.Background(), option.Cipher, shadowsocks.MethodOptions{
  207. Password: option.Password,
  208. })
  209. if err != nil {
  210. return nil, fmt.Errorf("ss %s initialize error: %w", addr, err)
  211. }
  212. var v2rayOption *v2rayObfs.Option
  213. var obfsOption *simpleObfsOption
  214. var shadowTLSOpt *shadowtls.ShadowTLSOption
  215. var restlsConfig *restlsC.Config
  216. obfsMode := ""
  217. decoder := structure.NewDecoder(structure.Option{TagName: "obfs", WeaklyTypedInput: true})
  218. if option.Plugin == "obfs" {
  219. opts := simpleObfsOption{Host: "bing.com"}
  220. if err := decoder.Decode(option.PluginOpts, &opts); err != nil {
  221. return nil, fmt.Errorf("ss %s initialize obfs error: %w", addr, err)
  222. }
  223. if opts.Mode != "tls" && opts.Mode != "http" {
  224. return nil, fmt.Errorf("ss %s obfs mode error: %s", addr, opts.Mode)
  225. }
  226. obfsMode = opts.Mode
  227. obfsOption = &opts
  228. } else if option.Plugin == "v2ray-plugin" {
  229. opts := v2rayObfsOption{Host: "bing.com", Mux: true}
  230. if err := decoder.Decode(option.PluginOpts, &opts); err != nil {
  231. return nil, fmt.Errorf("ss %s initialize v2ray-plugin error: %w", addr, err)
  232. }
  233. if opts.Mode != "websocket" {
  234. return nil, fmt.Errorf("ss %s obfs mode error: %s", addr, opts.Mode)
  235. }
  236. obfsMode = opts.Mode
  237. v2rayOption = &v2rayObfs.Option{
  238. Host: opts.Host,
  239. Path: opts.Path,
  240. Headers: opts.Headers,
  241. Mux: opts.Mux,
  242. V2rayHttpUpgrade: opts.V2rayHttpUpgrade,
  243. V2rayHttpUpgradeFastOpen: opts.V2rayHttpUpgradeFastOpen,
  244. }
  245. if opts.TLS {
  246. v2rayOption.TLS = true
  247. v2rayOption.SkipCertVerify = opts.SkipCertVerify
  248. v2rayOption.Fingerprint = opts.Fingerprint
  249. }
  250. } else if option.Plugin == shadowtls.Mode {
  251. obfsMode = shadowtls.Mode
  252. opt := &shadowTLSOption{
  253. Version: 2,
  254. }
  255. if err := decoder.Decode(option.PluginOpts, opt); err != nil {
  256. return nil, fmt.Errorf("ss %s initialize shadow-tls-plugin error: %w", addr, err)
  257. }
  258. shadowTLSOpt = &shadowtls.ShadowTLSOption{
  259. Password: opt.Password,
  260. Host: opt.Host,
  261. Fingerprint: opt.Fingerprint,
  262. ClientFingerprint: option.ClientFingerprint,
  263. SkipCertVerify: opt.SkipCertVerify,
  264. Version: opt.Version,
  265. }
  266. } else if option.Plugin == restls.Mode {
  267. obfsMode = restls.Mode
  268. restlsOpt := &restlsOption{}
  269. if err := decoder.Decode(option.PluginOpts, restlsOpt); err != nil {
  270. return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err)
  271. }
  272. restlsConfig, err = restlsC.NewRestlsConfig(restlsOpt.Host, restlsOpt.Password, restlsOpt.VersionHint, restlsOpt.RestlsScript, option.ClientFingerprint)
  273. if err != nil {
  274. return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err)
  275. }
  276. }
  277. switch option.UDPOverTCPVersion {
  278. case uot.Version, uot.LegacyVersion:
  279. case 0:
  280. option.UDPOverTCPVersion = uot.LegacyVersion
  281. default:
  282. return nil, fmt.Errorf("ss %s unknown udp over tcp protocol version: %d", addr, option.UDPOverTCPVersion)
  283. }
  284. return &ShadowSocks{
  285. Base: &Base{
  286. name: option.Name,
  287. addr: addr,
  288. tp: C.Shadowsocks,
  289. udp: option.UDP,
  290. tfo: option.TFO,
  291. mpTcp: option.MPTCP,
  292. iface: option.Interface,
  293. rmark: option.RoutingMark,
  294. prefer: C.NewDNSPrefer(option.IPVersion),
  295. },
  296. method: method,
  297. option: &option,
  298. obfsMode: obfsMode,
  299. v2rayOption: v2rayOption,
  300. obfsOption: obfsOption,
  301. shadowTLSOption: shadowTLSOpt,
  302. restlsConfig: restlsConfig,
  303. }, nil
  304. }