feat: Add v2ray httpupgrade fast open support
This commit is contained in:
parent
84a334dd3a
commit
5f7053c519
8 changed files with 160 additions and 77 deletions
|
@ -67,6 +67,7 @@ type v2rayObfsOption struct {
|
|||
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
|
||||
Mux bool `obfs:"mux,omitempty"`
|
||||
V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"`
|
||||
V2rayHttpUpgradeFastOpen bool `obfs:"v2ray-http-upgrade-fast-open,omitempty"`
|
||||
}
|
||||
|
||||
type shadowTLSOption struct {
|
||||
|
@ -265,6 +266,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||
Headers: opts.Headers,
|
||||
Mux: opts.Mux,
|
||||
V2rayHttpUpgrade: opts.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: opts.V2rayHttpUpgradeFastOpen,
|
||||
}
|
||||
|
||||
if opts.TLS {
|
||||
|
|
|
@ -57,6 +57,7 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error)
|
|||
Port: port,
|
||||
Path: t.option.WSOpts.Path,
|
||||
V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: t.option.WSOpts.V2rayHttpUpgradeFastOpen,
|
||||
Headers: http.Header{},
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
|
|||
MaxEarlyData: v.option.WSOpts.MaxEarlyData,
|
||||
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
|
||||
V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: v.option.WSOpts.V2rayHttpUpgradeFastOpen,
|
||||
ClientFingerprint: v.option.ClientFingerprint,
|
||||
Headers: http.Header{},
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ type WSOptions struct {
|
|||
MaxEarlyData int `proxy:"max-early-data,omitempty"`
|
||||
EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"`
|
||||
V2rayHttpUpgrade bool `proxy:"v2ray-http-upgrade,omitempty"`
|
||||
V2rayHttpUpgradeFastOpen bool `proxy:"v2ray-http-upgrade-fast-open,omitempty"`
|
||||
}
|
||||
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
|
@ -112,6 +113,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
|
|||
MaxEarlyData: v.option.WSOpts.MaxEarlyData,
|
||||
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
|
||||
V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: v.option.WSOpts.V2rayHttpUpgradeFastOpen,
|
||||
ClientFingerprint: v.option.ClientFingerprint,
|
||||
Headers: http.Header{},
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ type WebsocketOption struct {
|
|||
Path string
|
||||
Headers http.Header
|
||||
V2rayHttpUpgrade bool
|
||||
V2rayHttpUpgradeFastOpen bool
|
||||
}
|
||||
|
||||
type Trojan struct {
|
||||
|
@ -134,6 +135,7 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio
|
|||
Path: wsOptions.Path,
|
||||
Headers: wsOptions.Headers,
|
||||
V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: wsOptions.V2rayHttpUpgradeFastOpen,
|
||||
TLS: true,
|
||||
TLSConfig: tlsConfig,
|
||||
ClientFingerprint: t.option.ClientFingerprint,
|
||||
|
|
|
@ -21,6 +21,7 @@ type Option struct {
|
|||
Fingerprint string
|
||||
Mux bool
|
||||
V2rayHttpUpgrade bool
|
||||
V2rayHttpUpgradeFastOpen bool
|
||||
}
|
||||
|
||||
// NewV2rayObfs return a HTTPObfs
|
||||
|
@ -35,6 +36,7 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn,
|
|||
Port: option.Port,
|
||||
Path: option.Path,
|
||||
V2rayHttpUpgrade: option.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: option.V2rayHttpUpgradeFastOpen,
|
||||
Headers: header,
|
||||
}
|
||||
|
||||
|
|
65
transport/vmess/httpupgrade.go
Normal file
65
transport/vmess/httpupgrade.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
package vmess
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/metacubex/mihomo/common/buf"
|
||||
"github.com/metacubex/mihomo/common/net"
|
||||
)
|
||||
|
||||
type httpUpgradeEarlyConn struct {
|
||||
*net.BufferedConn
|
||||
create sync.Once
|
||||
done bool
|
||||
err error
|
||||
}
|
||||
|
||||
func (c *httpUpgradeEarlyConn) readResponse() {
|
||||
var request http.Request
|
||||
response, err := http.ReadResponse(c.Reader(), &request)
|
||||
c.done = true
|
||||
if err != nil {
|
||||
c.err = err
|
||||
return
|
||||
}
|
||||
if response.StatusCode != http.StatusSwitchingProtocols ||
|
||||
!strings.EqualFold(response.Header.Get("Connection"), "upgrade") ||
|
||||
!strings.EqualFold(response.Header.Get("Upgrade"), "websocket") {
|
||||
c.err = fmt.Errorf("unexpected status: %s", response.Status)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *httpUpgradeEarlyConn) Read(p []byte) (int, error) {
|
||||
c.create.Do(c.readResponse)
|
||||
if c.err != nil {
|
||||
return 0, c.err
|
||||
}
|
||||
return c.BufferedConn.Read(p)
|
||||
}
|
||||
|
||||
func (c *httpUpgradeEarlyConn) ReadBuffer(buffer *buf.Buffer) error {
|
||||
c.create.Do(c.readResponse)
|
||||
if c.err != nil {
|
||||
return c.err
|
||||
}
|
||||
return c.BufferedConn.ReadBuffer(buffer)
|
||||
}
|
||||
|
||||
func (c *httpUpgradeEarlyConn) ReaderReplaceable() bool {
|
||||
return c.done
|
||||
}
|
||||
|
||||
func (c *httpUpgradeEarlyConn) ReaderPossiblyReplaceable() bool {
|
||||
return !c.done
|
||||
}
|
||||
|
||||
func (c *httpUpgradeEarlyConn) ReadCached() *buf.Buffer {
|
||||
if c.done {
|
||||
return c.BufferedConn.ReadCached()
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -59,6 +59,7 @@ type WebsocketConfig struct {
|
|||
EarlyDataHeaderName string
|
||||
ClientFingerprint string
|
||||
V2rayHttpUpgrade bool
|
||||
V2rayHttpUpgradeFastOpen bool
|
||||
}
|
||||
|
||||
// Read implements net.Conn.Read()
|
||||
|
@ -415,6 +416,13 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
|
|||
return nil, err
|
||||
}
|
||||
bufferedConn := N.NewBufferedConn(conn)
|
||||
|
||||
if c.V2rayHttpUpgrade && c.V2rayHttpUpgradeFastOpen {
|
||||
return &httpUpgradeEarlyConn{
|
||||
BufferedConn: bufferedConn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
response, err := http.ReadResponse(bufferedConn.Reader(), request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
Loading…
Reference in a new issue