Configurable websocket PATH

This commit is contained in:
wwqgtxx 2022-03-12 07:31:33 +08:00
parent 1f88a7a0b8
commit 772c964d9a
9 changed files with 29 additions and 13 deletions

View File

@ -244,7 +244,9 @@ func (ctl *Control) connectServer() (conn net.Conn, err error) {
protocol := ctl.clientCfg.Protocol protocol := ctl.clientCfg.Protocol
if protocol == "websocket" { if protocol == "websocket" {
protocol = "tcp" 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 != "" { if ctl.clientCfg.ConnectServerLocalIP != "" {
dialOptions = append(dialOptions, libdial.WithLocalAddr(ctl.clientCfg.ConnectServerLocalIP)) dialOptions = append(dialOptions, libdial.WithLocalAddr(ctl.clientCfg.ConnectServerLocalIP))

View File

@ -235,7 +235,9 @@ func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) {
protocol := svr.cfg.Protocol protocol := svr.cfg.Protocol
if protocol == "websocket" { if protocol == "websocket" {
protocol = "tcp" 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 != "" { if svr.cfg.ConnectServerLocalIP != "" {
dialOptions = append(dialOptions, libdial.WithLocalAddr(svr.cfg.ConnectServerLocalIP)) dialOptions = append(dialOptions, libdial.WithLocalAddr(svr.cfg.ConnectServerLocalIP))

View File

@ -85,6 +85,10 @@ login_fail_exit = true
# now it supports tcp, kcp and websocket, default is tcp # now it supports tcp, kcp and websocket, default is tcp
protocol = 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. # set client binding ip when connect server, default is empty.
# only when protocol = tcp or websocket, the value will be used. # only when protocol = tcp or websocket, the value will be used.
connect_server_local_ip = 0.0.0.0 connect_server_local_ip = 0.0.0.0

View File

@ -13,6 +13,10 @@ bind_udp_port = 7001
# if not set, kcp is disabled in frps # if not set, kcp is disabled in frps
kcp_bind_port = 7000 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 # specify which address proxy will listen for, default value is same with bind_addr
# proxy_bind_addr = 127.0.0.1 # proxy_bind_addr = 127.0.0.1

View File

@ -115,6 +115,9 @@ type ClientCommonConf struct {
// Valid values are "tcp", "kcp" and "websocket". By default, this value // Valid values are "tcp", "kcp" and "websocket". By default, this value
// is "tcp". // is "tcp".
Protocol string `ini:"protocol" json:"protocol"` 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 // TLSEnable specifies whether or not TLS should be used when communicating
// with the server. If "tls_cert_file" and "tls_key_file" are valid, // with the server. If "tls_cert_file" and "tls_key_file" are valid,
// client will load the supplied tls configuration. // client will load the supplied tls configuration.
@ -179,6 +182,7 @@ func GetDefaultClientConf() ClientCommonConf {
LoginFailExit: true, LoginFailExit: true,
Start: make([]string, 0), Start: make([]string, 0),
Protocol: "tcp", Protocol: "tcp",
WebsocketPath: "/~!frp",
TLSEnable: false, TLSEnable: false,
TLSCertFile: "", TLSCertFile: "",
TLSKeyFile: "", TLSKeyFile: "",

View File

@ -46,6 +46,9 @@ type ServerCommonConf struct {
// value is 0, the server will not listen for KCP connections. By default, // value is 0, the server will not listen for KCP connections. By default,
// this value is 0. // this value is 0.
KCPBindPort int `ini:"kcp_bind_port" json:"kcp_bind_port" validate:"gte=0,lte=65535"` 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 // ProxyBindAddr specifies the address that the proxy binds to. This value
// may be the same as BindAddr. // may be the same as BindAddr.
ProxyBindAddr string `ini:"proxy_bind_addr" json:"proxy_bind_addr"` ProxyBindAddr string `ini:"proxy_bind_addr" json:"proxy_bind_addr"`
@ -178,6 +181,7 @@ func GetDefaultServerConf() ServerCommonConf {
BindPort: 7000, BindPort: 7000,
BindUDPPort: 0, BindUDPPort: 0,
KCPBindPort: 0, KCPBindPort: 0,
WebsocketPath: "/~!frp",
ProxyBindAddr: "", ProxyBindAddr: "",
VhostHTTPPort: 0, VhostHTTPPort: 0,
VhostHTTPSPort: 0, VhostHTTPSPort: 0,

View File

@ -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) { 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) uri, err := url.Parse(addr)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err

View File

@ -13,10 +13,6 @@ var (
ErrWebsocketListenerClosed = errors.New("websocket listener closed") ErrWebsocketListenerClosed = errors.New("websocket listener closed")
) )
const (
FrpWebsocketPath = "/~!frp"
)
type WebsocketListener struct { type WebsocketListener struct {
ln net.Listener ln net.Listener
acceptCh chan net.Conn acceptCh chan net.Conn
@ -27,13 +23,13 @@ type WebsocketListener struct {
// NewWebsocketListener to handle websocket connections // NewWebsocketListener to handle websocket connections
// ln: tcp listener for 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{ wl = &WebsocketListener{
acceptCh: make(chan net.Conn), acceptCh: make(chan net.Conn),
} }
muxer := http.NewServeMux() 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{}) notifyCh := make(chan struct{})
conn := WrapCloseNotifyConn(c, func() { conn := WrapCloseNotifyConn(c, func() {
close(notifyCh) close(notifyCh)
@ -56,7 +52,7 @@ func ListenWebsocket(bindAddr string, bindPort int) (*WebsocketListener, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
l := NewWebsocketListener(tcpLn) l := NewWebsocketListener(tcpLn, "/~!frp")
return l, nil return l, nil
} }

View File

@ -204,11 +204,11 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
} }
// Listen for accepting connections from client using websocket protocol. // 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 { websocketLn := svr.muxer.Listen(0, uint32(len(websocketPrefix)), func(data []byte) bool {
return bytes.Equal(data, websocketPrefix) return bytes.Equal(data, websocketPrefix)
}) })
svr.websocketListener = frpNet.NewWebsocketListener(websocketLn) svr.websocketListener = frpNet.NewWebsocketListener(websocketLn, cfg.WebsocketPath)
// Create http vhost muxer. // Create http vhost muxer.
if cfg.VhostHTTPPort > 0 { if cfg.VhostHTTPPort > 0 {