vmess.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. package outbound
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "net/http"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. N "github.com/metacubex/mihomo/common/net"
  13. "github.com/metacubex/mihomo/common/utils"
  14. "github.com/metacubex/mihomo/component/ca"
  15. "github.com/metacubex/mihomo/component/dialer"
  16. "github.com/metacubex/mihomo/component/proxydialer"
  17. "github.com/metacubex/mihomo/component/resolver"
  18. tlsC "github.com/metacubex/mihomo/component/tls"
  19. C "github.com/metacubex/mihomo/constant"
  20. "github.com/metacubex/mihomo/ntp"
  21. "github.com/metacubex/mihomo/transport/gun"
  22. mihomoVMess "github.com/metacubex/mihomo/transport/vmess"
  23. vmess "github.com/metacubex/sing-vmess"
  24. "github.com/metacubex/sing-vmess/packetaddr"
  25. M "github.com/sagernet/sing/common/metadata"
  26. )
  27. var ErrUDPRemoteAddrMismatch = errors.New("udp packet dropped due to mismatched remote address")
  28. type Vmess struct {
  29. *Base
  30. client *vmess.Client
  31. option *VmessOption
  32. // for gun mux
  33. gunTLSConfig *tls.Config
  34. gunConfig *gun.Config
  35. transport *gun.TransportWrap
  36. realityConfig *tlsC.RealityConfig
  37. }
  38. type VmessOption struct {
  39. BasicOption
  40. Name string `proxy:"name"`
  41. Server string `proxy:"server"`
  42. Port int `proxy:"port"`
  43. UUID string `proxy:"uuid"`
  44. AlterID int `proxy:"alterId"`
  45. Cipher string `proxy:"cipher"`
  46. UDP bool `proxy:"udp,omitempty"`
  47. Network string `proxy:"network,omitempty"`
  48. TLS bool `proxy:"tls,omitempty"`
  49. ALPN []string `proxy:"alpn,omitempty"`
  50. SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
  51. Fingerprint string `proxy:"fingerprint,omitempty"`
  52. ServerName string `proxy:"servername,omitempty"`
  53. RealityOpts RealityOptions `proxy:"reality-opts,omitempty"`
  54. HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
  55. HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
  56. GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
  57. WSOpts WSOptions `proxy:"ws-opts,omitempty"`
  58. PacketAddr bool `proxy:"packet-addr,omitempty"`
  59. XUDP bool `proxy:"xudp,omitempty"`
  60. PacketEncoding string `proxy:"packet-encoding,omitempty"`
  61. GlobalPadding bool `proxy:"global-padding,omitempty"`
  62. AuthenticatedLength bool `proxy:"authenticated-length,omitempty"`
  63. ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
  64. }
  65. type HTTPOptions struct {
  66. Method string `proxy:"method,omitempty"`
  67. Path []string `proxy:"path,omitempty"`
  68. Headers map[string][]string `proxy:"headers,omitempty"`
  69. }
  70. type HTTP2Options struct {
  71. Host []string `proxy:"host,omitempty"`
  72. Path string `proxy:"path,omitempty"`
  73. }
  74. type GrpcOptions struct {
  75. GrpcServiceName string `proxy:"grpc-service-name,omitempty"`
  76. }
  77. type WSOptions struct {
  78. Path string `proxy:"path,omitempty"`
  79. Headers map[string]string `proxy:"headers,omitempty"`
  80. MaxEarlyData int `proxy:"max-early-data,omitempty"`
  81. EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"`
  82. V2rayHttpUpgrade bool `proxy:"v2ray-http-upgrade,omitempty"`
  83. V2rayHttpUpgradeFastOpen bool `proxy:"v2ray-http-upgrade-fast-open,omitempty"`
  84. }
  85. // StreamConnContext implements C.ProxyAdapter
  86. func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
  87. var err error
  88. if tlsC.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) {
  89. v.option.ClientFingerprint = tlsC.GetGlobalFingerprint()
  90. }
  91. switch v.option.Network {
  92. case "ws":
  93. host, port, _ := net.SplitHostPort(v.addr)
  94. wsOpts := &mihomoVMess.WebsocketConfig{
  95. Host: host,
  96. Port: port,
  97. Path: v.option.WSOpts.Path,
  98. MaxEarlyData: v.option.WSOpts.MaxEarlyData,
  99. EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
  100. V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade,
  101. V2rayHttpUpgradeFastOpen: v.option.WSOpts.V2rayHttpUpgradeFastOpen,
  102. ClientFingerprint: v.option.ClientFingerprint,
  103. Headers: http.Header{},
  104. }
  105. if len(v.option.WSOpts.Headers) != 0 {
  106. for key, value := range v.option.WSOpts.Headers {
  107. wsOpts.Headers.Add(key, value)
  108. }
  109. }
  110. if v.option.TLS {
  111. wsOpts.TLS = true
  112. tlsConfig := &tls.Config{
  113. ServerName: host,
  114. InsecureSkipVerify: v.option.SkipCertVerify,
  115. NextProtos: []string{"http/1.1"},
  116. }
  117. wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint)
  118. if err != nil {
  119. return nil, err
  120. }
  121. if v.option.ServerName != "" {
  122. wsOpts.TLSConfig.ServerName = v.option.ServerName
  123. } else if host := wsOpts.Headers.Get("Host"); host != "" {
  124. wsOpts.TLSConfig.ServerName = host
  125. }
  126. }
  127. c, err = mihomoVMess.StreamWebsocketConn(ctx, c, wsOpts)
  128. case "http":
  129. // readability first, so just copy default TLS logic
  130. if v.option.TLS {
  131. host, _, _ := net.SplitHostPort(v.addr)
  132. tlsOpts := &mihomoVMess.TLSConfig{
  133. Host: host,
  134. SkipCertVerify: v.option.SkipCertVerify,
  135. ClientFingerprint: v.option.ClientFingerprint,
  136. Reality: v.realityConfig,
  137. NextProtos: v.option.ALPN,
  138. }
  139. if v.option.ServerName != "" {
  140. tlsOpts.Host = v.option.ServerName
  141. }
  142. c, err = mihomoVMess.StreamTLSConn(ctx, c, tlsOpts)
  143. if err != nil {
  144. return nil, err
  145. }
  146. }
  147. host, _, _ := net.SplitHostPort(v.addr)
  148. httpOpts := &mihomoVMess.HTTPConfig{
  149. Host: host,
  150. Method: v.option.HTTPOpts.Method,
  151. Path: v.option.HTTPOpts.Path,
  152. Headers: v.option.HTTPOpts.Headers,
  153. }
  154. c = mihomoVMess.StreamHTTPConn(c, httpOpts)
  155. case "h2":
  156. host, _, _ := net.SplitHostPort(v.addr)
  157. tlsOpts := mihomoVMess.TLSConfig{
  158. Host: host,
  159. SkipCertVerify: v.option.SkipCertVerify,
  160. FingerPrint: v.option.Fingerprint,
  161. NextProtos: []string{"h2"},
  162. ClientFingerprint: v.option.ClientFingerprint,
  163. Reality: v.realityConfig,
  164. }
  165. if v.option.ServerName != "" {
  166. tlsOpts.Host = v.option.ServerName
  167. }
  168. c, err = mihomoVMess.StreamTLSConn(ctx, c, &tlsOpts)
  169. if err != nil {
  170. return nil, err
  171. }
  172. h2Opts := &mihomoVMess.H2Config{
  173. Hosts: v.option.HTTP2Opts.Host,
  174. Path: v.option.HTTP2Opts.Path,
  175. }
  176. c, err = mihomoVMess.StreamH2Conn(c, h2Opts)
  177. case "grpc":
  178. c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig)
  179. default:
  180. // handle TLS
  181. if v.option.TLS {
  182. host, _, _ := net.SplitHostPort(v.addr)
  183. tlsOpts := &mihomoVMess.TLSConfig{
  184. Host: host,
  185. SkipCertVerify: v.option.SkipCertVerify,
  186. FingerPrint: v.option.Fingerprint,
  187. ClientFingerprint: v.option.ClientFingerprint,
  188. Reality: v.realityConfig,
  189. NextProtos: v.option.ALPN,
  190. }
  191. if v.option.ServerName != "" {
  192. tlsOpts.Host = v.option.ServerName
  193. }
  194. c, err = mihomoVMess.StreamTLSConn(ctx, c, tlsOpts)
  195. }
  196. }
  197. if err != nil {
  198. return nil, err
  199. }
  200. return v.streamConn(c, metadata)
  201. }
  202. func (v *Vmess) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) {
  203. if metadata.NetWork == C.UDP {
  204. if v.option.XUDP {
  205. var globalID [8]byte
  206. if metadata.SourceValid() {
  207. globalID = utils.GlobalID(metadata.SourceAddress())
  208. }
  209. if N.NeedHandshake(c) {
  210. conn = v.client.DialEarlyXUDPPacketConn(c,
  211. globalID,
  212. M.SocksaddrFromNet(metadata.UDPAddr()))
  213. } else {
  214. conn, err = v.client.DialXUDPPacketConn(c,
  215. globalID,
  216. M.SocksaddrFromNet(metadata.UDPAddr()))
  217. }
  218. } else if v.option.PacketAddr {
  219. if N.NeedHandshake(c) {
  220. conn = v.client.DialEarlyPacketConn(c,
  221. M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443))
  222. } else {
  223. conn, err = v.client.DialPacketConn(c,
  224. M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443))
  225. }
  226. conn = packetaddr.NewBindConn(conn)
  227. } else {
  228. if N.NeedHandshake(c) {
  229. conn = v.client.DialEarlyPacketConn(c,
  230. M.SocksaddrFromNet(metadata.UDPAddr()))
  231. } else {
  232. conn, err = v.client.DialPacketConn(c,
  233. M.SocksaddrFromNet(metadata.UDPAddr()))
  234. }
  235. }
  236. } else {
  237. if N.NeedHandshake(c) {
  238. conn = v.client.DialEarlyConn(c,
  239. M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort))
  240. } else {
  241. conn, err = v.client.DialConn(c,
  242. M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort))
  243. }
  244. }
  245. if err != nil {
  246. conn = nil
  247. }
  248. return
  249. }
  250. // DialContext implements C.ProxyAdapter
  251. func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
  252. // gun transport
  253. if v.transport != nil && len(opts) == 0 {
  254. c, err := gun.StreamGunWithTransport(v.transport, v.gunConfig)
  255. if err != nil {
  256. return nil, err
  257. }
  258. defer func(c net.Conn) {
  259. safeConnClose(c, err)
  260. }(c)
  261. c, err = v.client.DialConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort))
  262. if err != nil {
  263. return nil, err
  264. }
  265. return NewConn(c, v), nil
  266. }
  267. return v.DialContextWithDialer(ctx, dialer.NewDialer(v.Base.DialOptions(opts...)...), metadata)
  268. }
  269. // DialContextWithDialer implements C.ProxyAdapter
  270. func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
  271. if len(v.option.DialerProxy) > 0 {
  272. dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer)
  273. if err != nil {
  274. return nil, err
  275. }
  276. }
  277. c, err := dialer.DialContext(ctx, "tcp", v.addr)
  278. if err != nil {
  279. return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
  280. }
  281. N.TCPKeepAlive(c)
  282. defer func(c net.Conn) {
  283. safeConnClose(c, err)
  284. }(c)
  285. c, err = v.StreamConnContext(ctx, c, metadata)
  286. return NewConn(c, v), err
  287. }
  288. // ListenPacketContext implements C.ProxyAdapter
  289. func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) {
  290. // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr
  291. if !metadata.Resolved() {
  292. ip, err := resolver.ResolveIP(ctx, metadata.Host)
  293. if err != nil {
  294. return nil, errors.New("can't resolve ip")
  295. }
  296. metadata.DstIP = ip
  297. }
  298. var c net.Conn
  299. // gun transport
  300. if v.transport != nil && len(opts) == 0 {
  301. c, err = gun.StreamGunWithTransport(v.transport, v.gunConfig)
  302. if err != nil {
  303. return nil, err
  304. }
  305. defer func(c net.Conn) {
  306. safeConnClose(c, err)
  307. }(c)
  308. c, err = v.streamConn(c, metadata)
  309. if err != nil {
  310. return nil, fmt.Errorf("new vmess client error: %v", err)
  311. }
  312. return v.ListenPacketOnStreamConn(ctx, c, metadata)
  313. }
  314. return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.Base.DialOptions(opts...)...), metadata)
  315. }
  316. // ListenPacketWithDialer implements C.ProxyAdapter
  317. func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
  318. if len(v.option.DialerProxy) > 0 {
  319. dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer)
  320. if err != nil {
  321. return nil, err
  322. }
  323. }
  324. // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr
  325. if !metadata.Resolved() {
  326. ip, err := resolver.ResolveIP(ctx, metadata.Host)
  327. if err != nil {
  328. return nil, errors.New("can't resolve ip")
  329. }
  330. metadata.DstIP = ip
  331. }
  332. c, err := dialer.DialContext(ctx, "tcp", v.addr)
  333. if err != nil {
  334. return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
  335. }
  336. N.TCPKeepAlive(c)
  337. defer func(c net.Conn) {
  338. safeConnClose(c, err)
  339. }(c)
  340. c, err = v.StreamConnContext(ctx, c, metadata)
  341. if err != nil {
  342. return nil, fmt.Errorf("new vmess client error: %v", err)
  343. }
  344. return v.ListenPacketOnStreamConn(ctx, c, metadata)
  345. }
  346. // SupportWithDialer implements C.ProxyAdapter
  347. func (v *Vmess) SupportWithDialer() C.NetWork {
  348. return C.ALLNet
  349. }
  350. // ListenPacketOnStreamConn implements C.ProxyAdapter
  351. func (v *Vmess) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
  352. // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr
  353. if !metadata.Resolved() {
  354. ip, err := resolver.ResolveIP(ctx, metadata.Host)
  355. if err != nil {
  356. return nil, errors.New("can't resolve ip")
  357. }
  358. metadata.DstIP = ip
  359. }
  360. if pc, ok := c.(net.PacketConn); ok {
  361. return newPacketConn(N.NewThreadSafePacketConn(pc), v), nil
  362. }
  363. return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil
  364. }
  365. // SupportUOT implements C.ProxyAdapter
  366. func (v *Vmess) SupportUOT() bool {
  367. return true
  368. }
  369. func NewVmess(option VmessOption) (*Vmess, error) {
  370. security := strings.ToLower(option.Cipher)
  371. var options []vmess.ClientOption
  372. if option.GlobalPadding {
  373. options = append(options, vmess.ClientWithGlobalPadding())
  374. }
  375. if option.AuthenticatedLength {
  376. options = append(options, vmess.ClientWithAuthenticatedLength())
  377. }
  378. options = append(options, vmess.ClientWithTimeFunc(ntp.Now))
  379. client, err := vmess.NewClient(option.UUID, security, option.AlterID, options...)
  380. if err != nil {
  381. return nil, err
  382. }
  383. switch option.PacketEncoding {
  384. case "packetaddr", "packet":
  385. option.PacketAddr = true
  386. case "xudp":
  387. option.XUDP = true
  388. }
  389. if option.XUDP {
  390. option.PacketAddr = false
  391. }
  392. v := &Vmess{
  393. Base: &Base{
  394. name: option.Name,
  395. addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
  396. tp: C.Vmess,
  397. udp: option.UDP,
  398. xudp: option.XUDP,
  399. tfo: option.TFO,
  400. mpTcp: option.MPTCP,
  401. iface: option.Interface,
  402. rmark: option.RoutingMark,
  403. prefer: C.NewDNSPrefer(option.IPVersion),
  404. },
  405. client: client,
  406. option: &option,
  407. }
  408. switch option.Network {
  409. case "h2":
  410. if len(option.HTTP2Opts.Host) == 0 {
  411. option.HTTP2Opts.Host = append(option.HTTP2Opts.Host, "www.example.com")
  412. }
  413. case "grpc":
  414. dialFn := func(network, addr string) (net.Conn, error) {
  415. var err error
  416. var cDialer C.Dialer = dialer.NewDialer(v.Base.DialOptions()...)
  417. if len(v.option.DialerProxy) > 0 {
  418. cDialer, err = proxydialer.NewByName(v.option.DialerProxy, cDialer)
  419. if err != nil {
  420. return nil, err
  421. }
  422. }
  423. c, err := cDialer.DialContext(context.Background(), "tcp", v.addr)
  424. if err != nil {
  425. return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
  426. }
  427. N.TCPKeepAlive(c)
  428. return c, nil
  429. }
  430. gunConfig := &gun.Config{
  431. ServiceName: v.option.GrpcOpts.GrpcServiceName,
  432. Host: v.option.ServerName,
  433. ClientFingerprint: v.option.ClientFingerprint,
  434. }
  435. if option.ServerName == "" {
  436. gunConfig.Host = v.addr
  437. }
  438. var tlsConfig *tls.Config
  439. if option.TLS {
  440. tlsConfig = ca.GetGlobalTLSConfig(&tls.Config{
  441. InsecureSkipVerify: v.option.SkipCertVerify,
  442. ServerName: v.option.ServerName,
  443. })
  444. if option.ServerName == "" {
  445. host, _, _ := net.SplitHostPort(v.addr)
  446. tlsConfig.ServerName = host
  447. }
  448. }
  449. v.gunTLSConfig = tlsConfig
  450. v.gunConfig = gunConfig
  451. v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint, v.realityConfig)
  452. }
  453. v.realityConfig, err = v.option.RealityOpts.Parse()
  454. if err != nil {
  455. return nil, err
  456. }
  457. return v, nil
  458. }
  459. type vmessPacketConn struct {
  460. net.Conn
  461. rAddr net.Addr
  462. access sync.Mutex
  463. }
  464. // WriteTo implments C.PacketConn.WriteTo
  465. // Since VMess doesn't support full cone NAT by design, we verify if addr matches uc.rAddr, and drop the packet if not.
  466. func (uc *vmessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
  467. allowedAddr := uc.rAddr
  468. destAddr := addr
  469. if allowedAddr.String() != destAddr.String() {
  470. return 0, ErrUDPRemoteAddrMismatch
  471. }
  472. uc.access.Lock()
  473. defer uc.access.Unlock()
  474. return uc.Conn.Write(b)
  475. }
  476. func (uc *vmessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
  477. n, err := uc.Conn.Read(b)
  478. return n, uc.rAddr, err
  479. }