From 7678938c088c8d57367494ad53dd5c3b9e0cca35 Mon Sep 17 00:00:00 2001 From: fatedier Date: Sun, 18 Dec 2022 18:43:42 +0800 Subject: [PATCH] support quic options (#3211) --- README.md | 30 ++++++++++++++++++++++++++++++ Release.md | 3 ++- client/control.go | 2 +- client/service.go | 6 +++++- conf/frpc_full.ini | 5 +++++ conf/frps_full.ini | 4 ++++ pkg/config/client.go | 19 +++++++------------ pkg/config/client_test.go | 3 +++ pkg/config/server.go | 27 +++++++-------------------- pkg/config/server_test.go | 6 ++++++ pkg/util/version/version.go | 2 +- server/service.go | 6 +++++- 12 files changed, 76 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 2fabdca7..57a68949 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ frp also has a P2P connect mode. * [For Each Proxy](#for-each-proxy) * [TCP Stream Multiplexing](#tcp-stream-multiplexing) * [Support KCP Protocol](#support-kcp-protocol) + * [Support QUIC Protocol](#support-quic-protocol) * [Connection Pooling](#connection-pooling) * [Load balancing](#load-balancing) * [Service Health Check](#service-health-check) @@ -761,6 +762,35 @@ KCP mode uses UDP as the underlying transport. Using KCP in frp: protocol = kcp ``` +### Support QUIC Protocol + +QUIC is a new multiplexed transport built on top of UDP. + +Using QUIC in frp: + +1. Enable QUIC in frps: + + ```ini + # frps.ini + [common] + bind_port = 7000 + # Specify a UDP port for QUIC. + quic_bind_port = 7000 + ``` + + The `quic_bind_port` number can be the same number as `bind_port`, since `bind_port` field specifies a TCP port. + +2. Configure `frpc.ini` to use QUIC to connect to frps: + + ```ini + # frpc.ini + [common] + server_addr = x.x.x.x + # Same as the 'quic_bind_port' in frps.ini + server_port = 7000 + protocol = quic + ``` + ### Connection Pooling By default, frps creates a new frpc connection to the backend service upon a user request. With connection pooling, frps keeps a certain number of pre-established connections, reducing the time needed to establish a connection. diff --git a/Release.md b/Release.md index 5fac62df..bbcb8c5c 100644 --- a/Release.md +++ b/Release.md @@ -1,6 +1,7 @@ ### New -* Add oidc_scope parameter to frpc when authentication_method = oidc . +* Add `oidc_scope` parameter to frpc when `authentication_method = oidc`. +* Support quic protocol between frpc and frps. ### Improve diff --git a/client/control.go b/client/control.go index cc49883c..9fb15c01 100644 --- a/client/control.go +++ b/client/control.go @@ -147,7 +147,7 @@ func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) { var startMsg msg.StartWorkConn if err = msg.ReadMsgInto(workConn, &startMsg); err != nil { - xl.Error("work connection closed before response StartWorkConn message: %v", err) + xl.Trace("work connection closed before response StartWorkConn message: %v", err) workConn.Close() return } diff --git a/client/service.go b/client/service.go index f4a1e90d..b72fea77 100644 --- a/client/service.go +++ b/client/service.go @@ -374,7 +374,11 @@ func (cm *ConnectionManager) OpenConnection() error { conn, err := quic.DialAddr( net.JoinHostPort(cm.cfg.ServerAddr, strconv.Itoa(cm.cfg.ServerPort)), - tlsConfig, nil) + tlsConfig, &quic.Config{ + MaxIdleTimeout: time.Duration(cm.cfg.QUICMaxIdleTimeout) * time.Second, + MaxIncomingStreams: int64(cm.cfg.QUICMaxIncomingStreams), + KeepAlivePeriod: time.Duration(cm.cfg.QUICKeepalivePeriod) * time.Second, + }) if err != nil { return err } diff --git a/conf/frpc_full.ini b/conf/frpc_full.ini index 0dc2d5d5..8e39de1c 100644 --- a/conf/frpc_full.ini +++ b/conf/frpc_full.ini @@ -99,6 +99,11 @@ protocol = tcp # only when protocol = tcp or websocket, the value will be used. connect_server_local_ip = 0.0.0.0 +# quic protocol options +# quic_keepalive_period = 10 +# quic_max_idle_timeout = 30 +# quic_max_incoming_streams = 100000 + # if tls_enable is true, frpc will connect frps by tls tls_enable = true diff --git a/conf/frps_full.ini b/conf/frps_full.ini index 8a5c65dd..2d5e08e1 100644 --- a/conf/frps_full.ini +++ b/conf/frps_full.ini @@ -16,6 +16,10 @@ kcp_bind_port = 7000 # udp port used for quic protocol. # if not set, quic is disabled in frps. # quic_bind_port = 7002 +# quic protocol options +# quic_keepalive_period = 10 +# quic_max_idle_timeout = 30 +# quic_max_incoming_streams = 100000 # 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 ed020cf1..906ee985 100644 --- a/pkg/config/client.go +++ b/pkg/config/client.go @@ -118,6 +118,10 @@ type ClientCommonConf struct { // Valid values are "tcp", "kcp", "quic" and "websocket". By default, this value // is "tcp". Protocol string `ini:"protocol" json:"protocol"` + // QUIC protocol options + QUICKeepalivePeriod int `ini:"quic_keepalive_period" json:"quic_keepalive_period" validate:"gte=0"` + QUICMaxIdleTimeout int `ini:"quic_max_idle_timeout" json:"quic_max_idle_timeout" validate:"gte=0"` + QUICMaxIncomingStreams int `ini:"quic_max_incoming_streams" json:"quic_max_incoming_streams" validate:"gte=0"` // 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. @@ -172,30 +176,21 @@ func GetDefaultClientConf() ClientCommonConf { LogWay: "console", LogLevel: "info", LogMaxDays: 3, - DisableLogColor: false, AdminAddr: "127.0.0.1", - AdminPort: 0, - AdminUser: "", - AdminPwd: "", - AssetsDir: "", PoolCount: 1, TCPMux: true, TCPMuxKeepaliveInterval: 60, - User: "", - DNSServer: "", LoginFailExit: true, Start: make([]string, 0), Protocol: "tcp", - TLSEnable: false, - TLSCertFile: "", - TLSKeyFile: "", - TLSTrustedCaFile: "", + QUICKeepalivePeriod: 10, + QUICMaxIdleTimeout: 30, + QUICMaxIncomingStreams: 100000, HeartbeatInterval: 30, HeartbeatTimeout: 90, Metas: make(map[string]string), UDPPacketSize: 1500, IncludeConfigFiles: make([]string, 0), - PprofEnable: false, } } diff --git a/pkg/config/client_test.go b/pkg/config/client_test.go index ccff2293..9cf8c805 100644 --- a/pkg/config/client_test.go +++ b/pkg/config/client_test.go @@ -278,6 +278,9 @@ func Test_LoadClientCommonConf(t *testing.T) { User: "your_name", LoginFailExit: true, Protocol: "tcp", + QUICKeepalivePeriod: 10, + QUICMaxIdleTimeout: 30, + QUICMaxIncomingStreams: 100000, TLSEnable: true, TLSCertFile: "client.crt", TLSKeyFile: "client.key", diff --git a/pkg/config/server.go b/pkg/config/server.go index ecd32284..040eaf65 100644 --- a/pkg/config/server.go +++ b/pkg/config/server.go @@ -50,6 +50,10 @@ type ServerCommonConf struct { // Set this value to 0 will disable this feature. // By default, the value is 0. QUICBindPort int `ini:"quic_bind_port" json:"quic_bind_port" validate:"gte=0,lte=65535"` + // QUIC protocol options + QUICKeepalivePeriod int `ini:"quic_keepalive_period" json:"quic_keepalive_period" validate:"gte=0"` + QUICMaxIdleTimeout int `ini:"quic_max_idle_timeout" json:"quic_max_idle_timeout" validate:"gte=0"` + QUICMaxIncomingStreams int `ini:"quic_max_incoming_streams" json:"quic_max_incoming_streams" validate:"gte=0"` // 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"` @@ -199,43 +203,26 @@ func GetDefaultServerConf() ServerCommonConf { ServerConfig: auth.GetDefaultServerConf(), BindAddr: "0.0.0.0", BindPort: 7000, - BindUDPPort: 0, - KCPBindPort: 0, - ProxyBindAddr: "", - VhostHTTPPort: 0, - VhostHTTPSPort: 0, - TCPMuxHTTPConnectPort: 0, - TCPMuxPassthrough: false, + QUICKeepalivePeriod: 10, + QUICMaxIdleTimeout: 30, + QUICMaxIncomingStreams: 100000, VhostHTTPTimeout: 60, DashboardAddr: "0.0.0.0", - DashboardPort: 0, - DashboardUser: "", - DashboardPwd: "", - EnablePrometheus: false, - AssetsDir: "", LogFile: "console", LogWay: "console", LogLevel: "info", LogMaxDays: 3, - DisableLogColor: false, DetailedErrorsToClient: true, - SubDomainHost: "", TCPMux: true, TCPMuxKeepaliveInterval: 60, TCPKeepAlive: 7200, AllowPorts: make(map[int]struct{}), MaxPoolCount: 5, MaxPortsPerClient: 0, - TLSOnly: false, - TLSCertFile: "", - TLSKeyFile: "", - TLSTrustedCaFile: "", HeartbeatTimeout: 90, UserConnTimeout: 10, - Custom404Page: "", HTTPPlugins: make(map[string]plugin.HTTPPluginOptions), UDPPacketSize: 1500, - PprofEnable: false, } } diff --git a/pkg/config/server_test.go b/pkg/config/server_test.go index 5dee66db..475a86b6 100644 --- a/pkg/config/server_test.go +++ b/pkg/config/server_test.go @@ -106,6 +106,9 @@ func Test_LoadServerCommonConf(t *testing.T) { BindPort: 7009, BindUDPPort: 7008, KCPBindPort: 7007, + QUICKeepalivePeriod: 10, + QUICMaxIdleTimeout: 30, + QUICMaxIncomingStreams: 100000, ProxyBindAddr: "127.0.0.9", VhostHTTPPort: 89, VhostHTTPSPort: 449, @@ -179,6 +182,9 @@ func Test_LoadServerCommonConf(t *testing.T) { BindAddr: "0.0.0.9", BindPort: 7009, BindUDPPort: 7008, + QUICKeepalivePeriod: 10, + QUICMaxIdleTimeout: 30, + QUICMaxIncomingStreams: 100000, ProxyBindAddr: "0.0.0.9", VhostHTTPTimeout: 60, DashboardAddr: "0.0.0.0", diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go index f2805c51..6228c092 100644 --- a/pkg/util/version/version.go +++ b/pkg/util/version/version.go @@ -19,7 +19,7 @@ import ( "strings" ) -var version = "0.45.0" +var version = "0.46.0" func Full() string { return version diff --git a/server/service.go b/server/service.go index 0cbb0959..fc59b39c 100644 --- a/server/service.go +++ b/server/service.go @@ -214,7 +214,11 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) { address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.QUICBindPort)) quicTLSCfg := tlsConfig.Clone() quicTLSCfg.NextProtos = []string{"frp"} - svr.quicListener, err = quic.ListenAddr(address, quicTLSCfg, nil) + svr.quicListener, err = quic.ListenAddr(address, quicTLSCfg, &quic.Config{ + MaxIdleTimeout: time.Duration(cfg.QUICMaxIdleTimeout) * time.Second, + MaxIncomingStreams: int64(cfg.QUICMaxIncomingStreams), + KeepAlivePeriod: time.Duration(cfg.QUICKeepalivePeriod) * time.Second, + }) if err != nil { err = fmt.Errorf("listen on quic udp address %s error: %v", address, err) return