fatedier / frp

A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.
Apache License 2.0
85.46k stars 13.25k forks source link

Cannot handle Websocket traffic #4501

Open JobberRT opened 8 hours ago

JobberRT commented 8 hours ago

Bug Description

frpc cannot handle websocket traffic in both transport.protocol=tcp and transport.protocol=websocket. Websocket server indicates that Websocket Handshake Not Finished.

frpc Version

0.60.0

frps Version

0.60.0

System Architecture

linux/amd64

Configurations

frpc.ini

# A literal address or host name for IPv6 must be enclosed
# in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80"
# For single serverAddr field, no need square brackets, like serverAddr = "::".
serverAddr = "{{ .Envs.SERVER_ADDR }}"
serverPort = {{ .Envs.SERVER_PORT }}

# Decide if exit program when first login failed, otherwise continuous relogin to frps
# default is true
loginFailExit = true

# console or real logFile path like ./frpc.log
log.to = "console"
# trace, debug, info, warn, error
log.level = "trace"
log.maxDays = 3
# disable log colors when log.to is console, default is false
log.disablePrintColor = false

auth.method = "token"
# auth.additionalScopes specifies additional scopes to include authentication information.
# Optional values are HeartBeats, NewWorkConns.
# auth.additionalScopes = ["HeartBeats", "NewWorkConns"]

# auth token
auth.token = "{{ .Envs.TOKEN }}"

# Enable golang pprof handlers in admin listener.
webServer.pprofEnable = false

# The maximum amount of time a dial to server will wait for a connect to complete. Default value is 10 seconds.
transport.dialServerTimeout = 15

# dialServerKeepalive specifies the interval between keep-alive probes for an active network connection between frpc and frps.
# If negative, keep-alive probes are disabled.
transport.dialServerKeepalive = 7200

# connections will be established in advance, default value is zero
transport.poolCount = 5

# If tcp stream multiplexing is used, default is true, it must be same with frps
transport.tcpMux = true

# Specify keep alive interval for tcp mux.
# only valid if tcpMux is enabled.
transport.tcpMuxKeepaliveInterval = 30

# Communication protocol used to connect to server
# supports tcp, kcp, quic, websocket and wss now, default is tcp
transport.protocol = "{{ .Envs.PROTOCOL }}"

# set client binding ip when connect server, default is empty.
# only when protocol = tcp or websocket, the value will be used.
transport.connectServerLocalIP = "0.0.0.0"

# If tls.enable is true, frpc will connect frps by tls.
# Since v0.50.0, the default value has been changed to true, and tls is enabled by default.
transport.tls.enable = true
# transport.tls.certFile = "{{ .Envs.TLS_CERT_PATH }}"
# transport.tls.keyFile = "{{ .Envs.TLS_KEY_PATH }}"
# transport.tls.trustedCaFile = "{{ .Envs.TLS_CA_PATH }}"
# transport.tls.serverName = "{{ .Envs.TLS_SERVER_NAME }}"

# Heartbeat configure, it's not recommended to modify the default value.
# The default value of heartbeatInterval is 10 and heartbeatTimeout is 90. Set negative value
# to disable it.
transport.heartbeatInterval = 15
transport.heartbeatTimeout = 30

# Specify udp packet size, unit is byte. If not set, the default value is 1500.
# This parameter should be same between client and server.
# It affects the udp and sudp proxy.
udpPacketSize = 1500

# Additional metadatas for client.
# metadatas.var1 = "abc"
# metadatas.var2 = "123"

# Include other config files for proxies.
includes = ["./config/*.toml"]

A frpc proxy config example(using rustdesk as example)

[[proxies]]
name = "Rustdesk-hbbr@21117"
type = "tcp"
localIP = "rustdesk-hbbr"
localPort = 21117
remotePort = 21117

transport.bandwidthLimit = "256KB"
transport.bandwidthLimitMode = "client"
transport.useEncryption = true
transport.useCompression = true

healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 15
healthCheck.maxFailed = 5
healthCheck.intervalSeconds = 15

[[proxies]]
name = "Rustdesk-hbbr@21119"
type = "tcp"
localIP = "rustdesk-hbbr"
localPort = 21119
remotePort = 21119

transport.bandwidthLimit = "256KB"
transport.bandwidthLimitMode = "client"
transport.useEncryption = true
transport.useCompression = true

healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 15
healthCheck.maxFailed = 5
healthCheck.intervalSeconds = 15

[[proxies]]
name = "Rustdesk-hbbs@21114"
type = "tcp"
localIP = "rustdesk-hbbs"
localPort = 21114
remotePort = 21114

transport.bandwidthLimit = "256KB"
transport.bandwidthLimitMode = "client"
transport.useEncryption = true
transport.useCompression = true

healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 15
healthCheck.maxFailed = 5
healthCheck.intervalSeconds = 15

[[proxies]]
name = "Rustdesk-hbbs@21115"
type = "tcp"
localIP = "rustdesk-hbbs"
localPort = 21115
remotePort = 21115

transport.bandwidthLimit = "256KB"
transport.bandwidthLimitMode = "client"
transport.useEncryption = true
transport.useCompression = true

healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 15
healthCheck.maxFailed = 5
healthCheck.intervalSeconds = 15

[[proxies]]
name = "Rustdesk-hbbs@21116T"
type = "tcp"
localIP = "rustdesk-hbbs"
localPort = 21116
remotePort = 21116

transport.bandwidthLimit = "256KB"
transport.bandwidthLimitMode = "client"
transport.useEncryption = true
transport.useCompression = true

healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 15
healthCheck.maxFailed = 5
healthCheck.intervalSeconds = 15

[[proxies]]
name = "Rustdesk-hbbs@21116U"
type = "udp"
localIP = "rustdesk-hbbs"
localPort = 21116
remotePort = 21116

transport.bandwidthLimit = "256KB"
transport.bandwidthLimitMode = "client"
transport.useEncryption = true
transport.useCompression = true

[[proxies]]
name = "Rustdesk-hbbs@21118"
type = "tcp"
localIP = "rustdesk-hbbs"
localPort = 21118
remotePort = 21118

transport.bandwidthLimit = "256KB"
transport.bandwidthLimitMode = "client"
transport.useEncryption = true
transport.useCompression = true

healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 15
healthCheck.maxFailed = 5
healthCheck.intervalSeconds = 15

Logs

frpc log

2024-10-18 12:49:37.295 [T] [proxy/proxy.go:224] [661d6f2026d94f8f] [Rustdesk-hbbr@21117] join connections errors: [writeto tcp 172.18.0.2:35598->172.18.0.8:21117: read tcp 172.18.0.2:35598->172.18.0.8:21117: use of closed network connection]

rustdesk log

Caused by:

    Handshake not finished, hbbs::rendezvous_server:src/rendezvous_server.rs:1101:13

[2024-10-18 12:50:13.552107 +00:00] DEBUG [src/rendezvous_server.rs:1097] Tcp connection from [::ffff:172.18.0.2]:39068, ws: true

[2024-10-18 12:50:13.552138 +00:00] DEBUG [src/rendezvous_server.rs:1097] Tcp connection from [::ffff:172.18.0.2]:53500, ws: false

[2024-10-18 12:50:13.552340 +00:00] DEBUG [src/rendezvous_server.rs:1101] WebSocket protocol error: Handshake not finished

Steps to reproduce

No response

Affected area

JobberRT commented 8 hours ago

The same problem can also be found when using portainer's web terminal