mirror of
https://github.com/fatedier/frp.git
synced 2026-07-17 01:39:18 +08:00
The ws/wss transport carries a raw byte stream (yamux), but the golang.org/x/net/websocket Conn defaults to text frames (PayloadType TextFrame). Per RFC 6455 §5.6 a text frame must contain valid UTF-8, so RFC-compliant intermediaries (API gateways / reverse proxies) validate the payload and close the connection when the binary tunnel data is not valid UTF-8. This goes unnoticed peer-to-peer because x/net/websocket does not validate UTF-8 on read, but it breaks the connection through a compliant validating proxy. Set PayloadType to BinaryFrame on both the server listener and the client dialer so the tunnel is framed as binary.
56 lines
1.4 KiB
Go
56 lines
1.4 KiB
Go
package net
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/url"
|
|
|
|
libnet "github.com/fatedier/golib/net"
|
|
"golang.org/x/net/websocket"
|
|
)
|
|
|
|
func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) libnet.AfterHookFunc {
|
|
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
|
if enableTLS && !disableCustomTLSHeadByte {
|
|
_, err := c.Write([]byte{byte(FRPTLSHeadByte)})
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
return ctx, c, nil
|
|
}
|
|
}
|
|
|
|
func DialHookWebsocket(protocol string, host string) libnet.AfterHookFunc {
|
|
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
|
if protocol != "wss" {
|
|
protocol = "ws"
|
|
}
|
|
if host == "" {
|
|
host = addr
|
|
}
|
|
addr = protocol + "://" + host + FrpWebsocketPath
|
|
uri, err := url.Parse(addr)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
origin := "http://" + uri.Host
|
|
cfg, err := websocket.NewConfig(addr, origin)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
conn, err := websocket.NewClient(cfg, c)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
// The tunnel payload is a raw byte stream (yamux), not UTF-8 text.
|
|
// Send it as binary frames; otherwise RFC 6455-compliant intermediaries
|
|
// (e.g. API gateways/reverse proxies) UTF-8-validate the default text
|
|
// frames and close the connection on invalid bytes.
|
|
conn.PayloadType = websocket.BinaryFrame
|
|
return ctx, conn, nil
|
|
}
|
|
}
|