Skip to content

Commit

Permalink
feat: add v2ray-http-upgrade support
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Nov 2, 2023
1 parent b0638cf commit ceac5bf
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 49 deletions.
26 changes: 14 additions & 12 deletions adapter/outbound/shadowsocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,15 @@ type simpleObfsOption struct {
}

type v2rayObfsOption struct {
Mode string `obfs:"mode"`
Host string `obfs:"host,omitempty"`
Path string `obfs:"path,omitempty"`
TLS bool `obfs:"tls,omitempty"`
Fingerprint string `obfs:"fingerprint,omitempty"`
Headers map[string]string `obfs:"headers,omitempty"`
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
Mux bool `obfs:"mux,omitempty"`
Mode string `obfs:"mode"`
Host string `obfs:"host,omitempty"`
Path string `obfs:"path,omitempty"`
TLS bool `obfs:"tls,omitempty"`
Fingerprint string `obfs:"fingerprint,omitempty"`
Headers map[string]string `obfs:"headers,omitempty"`
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
Mux bool `obfs:"mux,omitempty"`
V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"`
}

type shadowTLSOption struct {
Expand Down Expand Up @@ -259,10 +260,11 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
}
obfsMode = opts.Mode
v2rayOption = &v2rayObfs.Option{
Host: opts.Host,
Path: opts.Path,
Headers: opts.Headers,
Mux: opts.Mux,
Host: opts.Host,
Path: opts.Path,
Headers: opts.Headers,
Mux: opts.Mux,
V2rayHttpUpgrade: opts.V2rayHttpUpgrade,
}

if opts.TLS {
Expand Down
7 changes: 4 additions & 3 deletions adapter/outbound/trojan.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error)
if t.option.Network == "ws" {
host, port, _ := net.SplitHostPort(t.addr)
wsOpts := &trojan.WebsocketOption{
Host: host,
Port: port,
Path: t.option.WSOpts.Path,
Host: host,
Port: port,
Path: t.option.WSOpts.Path,
V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade,
}

if t.option.SNI != "" {
Expand Down
1 change: 1 addition & 0 deletions adapter/outbound/vless.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
Path: v.option.WSOpts.Path,
MaxEarlyData: v.option.WSOpts.MaxEarlyData,
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade,
ClientFingerprint: v.option.ClientFingerprint,
Headers: http.Header{},
}
Expand Down
2 changes: 2 additions & 0 deletions adapter/outbound/vmess.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type WSOptions struct {
Headers map[string]string `proxy:"headers,omitempty"`
MaxEarlyData int `proxy:"max-early-data,omitempty"`
EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"`
V2rayHttpUpgrade bool `proxy:"v2ray-http-upgrade,omitempty"`
}

// StreamConnContext implements C.ProxyAdapter
Expand All @@ -110,6 +111,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
Path: v.option.WSOpts.Path,
MaxEarlyData: v.option.WSOpts.MaxEarlyData,
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade,
ClientFingerprint: v.option.ClientFingerprint,
Headers: http.Header{},
}
Expand Down
40 changes: 22 additions & 18 deletions docs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -352,16 +352,17 @@ proxies: # socks5
plugin: v2ray-plugin
plugin-opts:
mode: websocket # no QUIC now
# tls: true # wss
# 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
# 配置指纹将实现 SSL Pining 效果
# fingerprint: xxxx
# skip-cert-verify: true
# host: bing.com
# path: "/"
# mux: true
# headers:
# custom: value
# tls: true # wss
# 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
# 配置指纹将实现 SSL Pining 效果
# fingerprint: xxxx
# skip-cert-verify: true
# host: bing.com
# path: "/"
# mux: true
# headers:
# custom: value
# v2ray-http-upgrade: false

- name: "ss4-shadow-tls"
type: ss
Expand Down Expand Up @@ -434,11 +435,12 @@ proxies: # socks5
# servername: example.com # priority over wss host
# network: ws
# ws-opts:
# path: /path
# headers:
# Host: v2ray.com
# max-early-data: 2048
# early-data-header-name: Sec-WebSocket-Protocol
# path: /path
# headers:
# Host: v2ray.com
# max-early-data: 2048
# early-data-header-name: Sec-WebSocket-Protocol
# v2ray-http-upgrade: false

- name: "vmess-h2"
type: vmess
Expand Down Expand Up @@ -566,6 +568,7 @@ proxies: # socks5
path: "/"
headers:
Host: example.com
# v2ray-http-upgrade: false

# Trojan
- name: "trojan"
Expand Down Expand Up @@ -606,9 +609,10 @@ proxies: # socks5
# fingerprint: xxxx
udp: true
# ws-opts:
# path: /path
# headers:
# Host: example.com
# path: /path
# headers:
# Host: example.com
# v2ray-http-upgrade: false

- name: "trojan-xtls"
type: trojan
Expand Down
10 changes: 6 additions & 4 deletions transport/trojan/trojan.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ type Option struct {
}

type WebsocketOption struct {
Host string
Port string
Path string
Headers http.Header
Host string
Port string
Path string
Headers http.Header
V2rayHttpUpgrade bool
}

type Trojan struct {
Expand Down Expand Up @@ -132,6 +133,7 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio
Port: wsOptions.Port,
Path: wsOptions.Path,
Headers: wsOptions.Headers,
V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade,
TLS: true,
TLSConfig: tlsConfig,
ClientFingerprint: t.option.ClientFingerprint,
Expand Down
26 changes: 14 additions & 12 deletions transport/v2ray-plugin/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import (

// Option is options of websocket obfs
type Option struct {
Host string
Port string
Path string
Headers map[string]string
TLS bool
SkipCertVerify bool
Fingerprint string
Mux bool
Host string
Port string
Path string
Headers map[string]string
TLS bool
SkipCertVerify bool
Fingerprint string
Mux bool
V2rayHttpUpgrade bool
}

// NewV2rayObfs return a HTTPObfs
Expand All @@ -30,10 +31,11 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn,
}

config := &vmess.WebsocketConfig{
Host: option.Host,
Port: option.Port,
Path: option.Path,
Headers: header,
Host: option.Host,
Port: option.Port,
Path: option.Path,
V2rayHttpUpgrade: option.V2rayHttpUpgrade,
Headers: header,
}

if option.TLS {
Expand Down
34 changes: 34 additions & 0 deletions transport/vmess/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type WebsocketConfig struct {
MaxEarlyData int
EarlyDataHeaderName string
ClientFingerprint string
V2rayHttpUpgrade bool
}

// Read implements net.Conn.Read()
Expand Down Expand Up @@ -352,6 +353,39 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
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.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http
if c.Headers != nil {
Expand Down

0 comments on commit ceac5bf

Please sign in to comment.