feat: add v2ray-http-upgrade support

This commit is contained in:
wwqgtxx 2023-11-02 11:11:19 +08:00
parent b0638cfc49
commit ceac5bfaa4
8 changed files with 97 additions and 49 deletions

View file

@ -66,6 +66,7 @@ type v2rayObfsOption struct {
Headers map[string]string `obfs:"headers,omitempty"` Headers map[string]string `obfs:"headers,omitempty"`
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
Mux bool `obfs:"mux,omitempty"` Mux bool `obfs:"mux,omitempty"`
V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"`
} }
type shadowTLSOption struct { type shadowTLSOption struct {
@ -263,6 +264,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
Path: opts.Path, Path: opts.Path,
Headers: opts.Headers, Headers: opts.Headers,
Mux: opts.Mux, Mux: opts.Mux,
V2rayHttpUpgrade: opts.V2rayHttpUpgrade,
} }
if opts.TLS { if opts.TLS {

View file

@ -56,6 +56,7 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error)
Host: host, Host: host,
Port: port, Port: port,
Path: t.option.WSOpts.Path, Path: t.option.WSOpts.Path,
V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade,
} }
if t.option.SNI != "" { if t.option.SNI != "" {

View file

@ -93,6 +93,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
Path: v.option.WSOpts.Path, Path: v.option.WSOpts.Path,
MaxEarlyData: v.option.WSOpts.MaxEarlyData, MaxEarlyData: v.option.WSOpts.MaxEarlyData,
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade,
ClientFingerprint: v.option.ClientFingerprint, ClientFingerprint: v.option.ClientFingerprint,
Headers: http.Header{}, Headers: http.Header{},
} }

View file

@ -91,6 +91,7 @@ type WSOptions struct {
Headers map[string]string `proxy:"headers,omitempty"` Headers map[string]string `proxy:"headers,omitempty"`
MaxEarlyData int `proxy:"max-early-data,omitempty"` MaxEarlyData int `proxy:"max-early-data,omitempty"`
EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"`
V2rayHttpUpgrade bool `proxy:"v2ray-http-upgrade,omitempty"`
} }
// StreamConnContext implements C.ProxyAdapter // StreamConnContext implements C.ProxyAdapter
@ -110,6 +111,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
Path: v.option.WSOpts.Path, Path: v.option.WSOpts.Path,
MaxEarlyData: v.option.WSOpts.MaxEarlyData, MaxEarlyData: v.option.WSOpts.MaxEarlyData,
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade,
ClientFingerprint: v.option.ClientFingerprint, ClientFingerprint: v.option.ClientFingerprint,
Headers: http.Header{}, Headers: http.Header{},
} }

View file

@ -362,6 +362,7 @@ proxies: # socks5
# mux: true # mux: true
# headers: # headers:
# custom: value # custom: value
# v2ray-http-upgrade: false
- name: "ss4-shadow-tls" - name: "ss4-shadow-tls"
type: ss type: ss
@ -439,6 +440,7 @@ proxies: # socks5
# Host: v2ray.com # Host: v2ray.com
# max-early-data: 2048 # max-early-data: 2048
# early-data-header-name: Sec-WebSocket-Protocol # early-data-header-name: Sec-WebSocket-Protocol
# v2ray-http-upgrade: false
- name: "vmess-h2" - name: "vmess-h2"
type: vmess type: vmess
@ -566,6 +568,7 @@ proxies: # socks5
path: "/" path: "/"
headers: headers:
Host: example.com Host: example.com
# v2ray-http-upgrade: false
# Trojan # Trojan
- name: "trojan" - name: "trojan"
@ -609,6 +612,7 @@ proxies: # socks5
# path: /path # path: /path
# headers: # headers:
# Host: example.com # Host: example.com
# v2ray-http-upgrade: false
- name: "trojan-xtls" - name: "trojan-xtls"
type: trojan type: trojan

View file

@ -59,6 +59,7 @@ type WebsocketOption struct {
Port string Port string
Path string Path string
Headers http.Header Headers http.Header
V2rayHttpUpgrade bool
} }
type Trojan struct { type Trojan struct {
@ -132,6 +133,7 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio
Port: wsOptions.Port, Port: wsOptions.Port,
Path: wsOptions.Path, Path: wsOptions.Path,
Headers: wsOptions.Headers, Headers: wsOptions.Headers,
V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade,
TLS: true, TLS: true,
TLSConfig: tlsConfig, TLSConfig: tlsConfig,
ClientFingerprint: t.option.ClientFingerprint, ClientFingerprint: t.option.ClientFingerprint,

View file

@ -20,6 +20,7 @@ type Option struct {
SkipCertVerify bool SkipCertVerify bool
Fingerprint string Fingerprint string
Mux bool Mux bool
V2rayHttpUpgrade bool
} }
// NewV2rayObfs return a HTTPObfs // NewV2rayObfs return a HTTPObfs
@ -33,6 +34,7 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn,
Host: option.Host, Host: option.Host,
Port: option.Port, Port: option.Port,
Path: option.Path, Path: option.Path,
V2rayHttpUpgrade: option.V2rayHttpUpgrade,
Headers: header, Headers: header,
} }

View file

@ -55,6 +55,7 @@ type WebsocketConfig struct {
MaxEarlyData int MaxEarlyData int
EarlyDataHeaderName string EarlyDataHeaderName string
ClientFingerprint string ClientFingerprint string
V2rayHttpUpgrade bool
} }
// Read implements net.Conn.Read() // Read implements net.Conn.Read()
@ -352,6 +353,39 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
RawQuery: u.RawQuery, RawQuery: u.RawQuery,
} }
if c.V2rayHttpUpgrade {
if c.TLS {
if dialer.TLSClient != nil {
conn = dialer.TLSClient(conn, uri.Host)
} else {
conn = tls.Client(conn, dialer.TLSConfig)
}
}
request := &http.Request{
Method: http.MethodGet,
URL: &uri,
Header: c.Headers.Clone(),
Host: c.Host,
}
request.Header.Set("Connection", "Upgrade")
request.Header.Set("Upgrade", "websocket")
err = request.Write(conn)
if err != nil {
return nil, err
}
bufferedConn := N.NewBufferedConn(conn)
response, err := http.ReadResponse(bufferedConn.Reader(), request)
if err != nil {
return nil, err
}
if response.StatusCode != 101 ||
!strings.EqualFold(response.Header.Get("Connection"), "upgrade") ||
!strings.EqualFold(response.Header.Get("Upgrade"), "websocket") {
return nil, fmt.Errorf("unexpected status: %s", response.Status)
}
return bufferedConn, nil
}
headers := http.Header{} headers := http.Header{}
headers.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http headers.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http
if c.Headers != nil { if c.Headers != nil {