diff --git a/client/control.go b/client/control.go index 81aaf7be..a799b14a 100644 --- a/client/control.go +++ b/client/control.go @@ -244,7 +244,9 @@ func (ctl *Control) connectServer() (conn net.Conn, err error) { protocol := ctl.clientCfg.Protocol if protocol == "websocket" { protocol = "tcp" - dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: frpNet.DialHookWebsocket()})) + dialOptions = append(dialOptions, + libdial.WithAfterHook(libdial.AfterHook{Hook: frpNet.DialHookWebsocket(ctl.clientCfg.WebsocketPath)}), + ) } if ctl.clientCfg.ConnectServerLocalIP != "" { dialOptions = append(dialOptions, libdial.WithLocalAddr(ctl.clientCfg.ConnectServerLocalIP)) diff --git a/client/service.go b/client/service.go index 96ddadfd..73518b77 100644 --- a/client/service.go +++ b/client/service.go @@ -235,7 +235,9 @@ func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) { protocol := svr.cfg.Protocol if protocol == "websocket" { protocol = "tcp" - dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: frpNet.DialHookWebsocket()})) + dialOptions = append(dialOptions, + libdial.WithAfterHook(libdial.AfterHook{Hook: frpNet.DialHookWebsocket(svr.cfg.WebsocketPath)}), + ) } if svr.cfg.ConnectServerLocalIP != "" { dialOptions = append(dialOptions, libdial.WithLocalAddr(svr.cfg.ConnectServerLocalIP)) diff --git a/conf/frpc_full.ini b/conf/frpc_full.ini index 58aefde8..b6356271 100644 --- a/conf/frpc_full.ini +++ b/conf/frpc_full.ini @@ -85,6 +85,10 @@ login_fail_exit = true # now it supports tcp, kcp and websocket, default is tcp protocol = tcp +# the websocket PATH when working in WS mode. +# require start with '/', no space. By default, this value is "/~!frp". +websocket_path = /~!frp + # set client binding ip when connect server, default is empty. # only when protocol = tcp or websocket, the value will be used. connect_server_local_ip = 0.0.0.0 diff --git a/conf/frps_full.ini b/conf/frps_full.ini index 4aef9774..aa6ee6c7 100644 --- a/conf/frps_full.ini +++ b/conf/frps_full.ini @@ -13,6 +13,10 @@ bind_udp_port = 7001 # if not set, kcp is disabled in frps kcp_bind_port = 7000 +# the websocket PATH when working in WS mode. +# require start with '/', no space. By default, this value is "/~!frp". +websocket_path = /~!frp + # specify which address proxy will listen for, default value is same with bind_addr # proxy_bind_addr = 127.0.0.1 diff --git a/pkg/config/client.go b/pkg/config/client.go index e65e1064..c899a5d0 100644 --- a/pkg/config/client.go +++ b/pkg/config/client.go @@ -115,6 +115,9 @@ type ClientCommonConf struct { // Valid values are "tcp", "kcp" and "websocket". By default, this value // is "tcp". Protocol string `ini:"protocol" json:"protocol"` + // WebsocketPath specifies the websocket PATH when working in WS mode. + // require start with '/', no space. By default, this value is "/~!frp". + WebsocketPath string `ini:"websocket_path" json:"websocket_path"` // TLSEnable specifies whether or not TLS should be used when communicating // with the server. If "tls_cert_file" and "tls_key_file" are valid, // client will load the supplied tls configuration. @@ -179,6 +182,7 @@ func GetDefaultClientConf() ClientCommonConf { LoginFailExit: true, Start: make([]string, 0), Protocol: "tcp", + WebsocketPath: "/~!frp", TLSEnable: false, TLSCertFile: "", TLSKeyFile: "", diff --git a/pkg/config/server.go b/pkg/config/server.go index d002f9ff..6b3b32a2 100644 --- a/pkg/config/server.go +++ b/pkg/config/server.go @@ -46,6 +46,9 @@ type ServerCommonConf struct { // value is 0, the server will not listen for KCP connections. By default, // this value is 0. KCPBindPort int `ini:"kcp_bind_port" json:"kcp_bind_port" validate:"gte=0,lte=65535"` + // WebsocketPath specifies the websocket PATH when working in WS mode. + // require start with '/', no space. By default, this value is "/~!frp". + WebsocketPath string `ini:"websocket_path" json:"websocket_path"` // ProxyBindAddr specifies the address that the proxy binds to. This value // may be the same as BindAddr. ProxyBindAddr string `ini:"proxy_bind_addr" json:"proxy_bind_addr"` @@ -178,6 +181,7 @@ func GetDefaultServerConf() ServerCommonConf { BindPort: 7000, BindUDPPort: 0, KCPBindPort: 0, + WebsocketPath: "/~!frp", ProxyBindAddr: "", VhostHTTPPort: 0, VhostHTTPSPort: 0, diff --git a/pkg/util/net/dial.go b/pkg/util/net/dial.go index 251ebbff..d8b1e0e6 100644 --- a/pkg/util/net/dial.go +++ b/pkg/util/net/dial.go @@ -21,9 +21,9 @@ func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) li } } -func DialHookWebsocket() libdial.AfterHookFunc { +func DialHookWebsocket(websocketPath string) libdial.AfterHookFunc { return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) { - addr = "ws://" + addr + FrpWebsocketPath + addr = "ws://" + addr + websocketPath uri, err := url.Parse(addr) if err != nil { return nil, nil, err diff --git a/pkg/util/net/websocket.go b/pkg/util/net/websocket.go index 4ec5c9fe..f28194c4 100644 --- a/pkg/util/net/websocket.go +++ b/pkg/util/net/websocket.go @@ -13,10 +13,6 @@ var ( ErrWebsocketListenerClosed = errors.New("websocket listener closed") ) -const ( - FrpWebsocketPath = "/~!frp" -) - type WebsocketListener struct { ln net.Listener acceptCh chan net.Conn @@ -27,13 +23,13 @@ type WebsocketListener struct { // NewWebsocketListener to handle websocket connections // ln: tcp listener for websocket connections -func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) { +func NewWebsocketListener(ln net.Listener, websocketPath string) (wl *WebsocketListener) { wl = &WebsocketListener{ acceptCh: make(chan net.Conn), } muxer := http.NewServeMux() - muxer.Handle(FrpWebsocketPath, websocket.Handler(func(c *websocket.Conn) { + muxer.Handle(websocketPath, websocket.Handler(func(c *websocket.Conn) { notifyCh := make(chan struct{}) conn := WrapCloseNotifyConn(c, func() { close(notifyCh) @@ -56,7 +52,7 @@ func ListenWebsocket(bindAddr string, bindPort int) (*WebsocketListener, error) if err != nil { return nil, err } - l := NewWebsocketListener(tcpLn) + l := NewWebsocketListener(tcpLn, "/~!frp") return l, nil } diff --git a/server/service.go b/server/service.go index c3c45488..fd0c15fd 100644 --- a/server/service.go +++ b/server/service.go @@ -204,11 +204,11 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) { } // Listen for accepting connections from client using websocket protocol. - websocketPrefix := []byte("GET " + frpNet.FrpWebsocketPath) + websocketPrefix := []byte("GET " + cfg.WebsocketPath) websocketLn := svr.muxer.Listen(0, uint32(len(websocketPrefix)), func(data []byte) bool { return bytes.Equal(data, websocketPrefix) }) - svr.websocketListener = frpNet.NewWebsocketListener(websocketLn) + svr.websocketListener = frpNet.NewWebsocketListener(websocketLn, cfg.WebsocketPath) // Create http vhost muxer. if cfg.VhostHTTPPort > 0 {