From b4d5d8c756bfa7c5f4fc73c3dff48678d0110fce Mon Sep 17 00:00:00 2001 From: fatedier Date: Tue, 9 Jul 2024 10:50:16 +0800 Subject: [PATCH] plugin https2http&https2https: return 421 if host not match sni (#4323) --- Release.md | 5 ++++ pkg/config/v1/plugin.go | 47 +++++++++++++++++++++++++------- pkg/config/v1/proxy.go | 4 +++ pkg/plugin/client/https2http.go | 18 +++++++++++- pkg/plugin/client/https2https.go | 18 +++++++++++- pkg/util/version/version.go | 2 +- 6 files changed, 81 insertions(+), 13 deletions(-) diff --git a/Release.md b/Release.md index 2dcfc566..6e142def 100644 --- a/Release.md +++ b/Release.md @@ -1,3 +1,8 @@ ### Features * Added a new plugin "http2http" which allows forwarding HTTP requests to another HTTP server, supporting options like local address binding, host header rewrite, and custom request headers. +* Added `enableHTTP2` option to control whether to enable HTTP/2 in plugin https2http and https2https, default is true. + +### Changes + +* Plugin https2http & https2https: return 421 `Misdirected Request` if host not match sni. diff --git a/pkg/config/v1/plugin.go b/pkg/config/v1/plugin.go index 333b020a..7ae4a4d4 100644 --- a/pkg/config/v1/plugin.go +++ b/pkg/config/v1/plugin.go @@ -20,9 +20,15 @@ import ( "errors" "fmt" "reflect" + + "github.com/samber/lo" + + "github.com/fatedier/frp/pkg/util/util" ) -type ClientPluginOptions interface{} +type ClientPluginOptions interface { + Complete() +} type TypedClientPluginOptions struct { Type string `json:"type"` @@ -73,10 +79,10 @@ const ( PluginHTTPProxy = "http_proxy" PluginHTTPS2HTTP = "https2http" PluginHTTPS2HTTPS = "https2https" + PluginHTTP2HTTP = "http2http" PluginSocks5 = "socks5" PluginStaticFile = "static_file" PluginUnixDomainSocket = "unix_domain_socket" - PluginHTTP2HTTP = "http2http" ) var clientPluginOptionsTypeMap = map[string]reflect.Type{ @@ -84,10 +90,10 @@ var clientPluginOptionsTypeMap = map[string]reflect.Type{ PluginHTTPProxy: reflect.TypeOf(HTTPProxyPluginOptions{}), PluginHTTPS2HTTP: reflect.TypeOf(HTTPS2HTTPPluginOptions{}), PluginHTTPS2HTTPS: reflect.TypeOf(HTTPS2HTTPSPluginOptions{}), + PluginHTTP2HTTP: reflect.TypeOf(HTTP2HTTPPluginOptions{}), PluginSocks5: reflect.TypeOf(Socks5PluginOptions{}), PluginStaticFile: reflect.TypeOf(StaticFilePluginOptions{}), PluginUnixDomainSocket: reflect.TypeOf(UnixDomainSocketPluginOptions{}), - PluginHTTP2HTTP: reflect.TypeOf(HTTP2HTTPPluginOptions{}), } type HTTP2HTTPSPluginOptions struct { @@ -97,36 +103,61 @@ type HTTP2HTTPSPluginOptions struct { RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` } +func (o *HTTP2HTTPSPluginOptions) Complete() {} + type HTTPProxyPluginOptions struct { Type string `json:"type,omitempty"` HTTPUser string `json:"httpUser,omitempty"` HTTPPassword string `json:"httpPassword,omitempty"` } +func (o *HTTPProxyPluginOptions) Complete() {} + type HTTPS2HTTPPluginOptions struct { Type string `json:"type,omitempty"` LocalAddr string `json:"localAddr,omitempty"` HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"` RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` + EnableHTTP2 *bool `json:"enableHTTP2,omitempty"` CrtPath string `json:"crtPath,omitempty"` KeyPath string `json:"keyPath,omitempty"` } +func (o *HTTPS2HTTPPluginOptions) Complete() { + o.EnableHTTP2 = util.EmptyOr(o.EnableHTTP2, lo.ToPtr(true)) +} + type HTTPS2HTTPSPluginOptions struct { Type string `json:"type,omitempty"` LocalAddr string `json:"localAddr,omitempty"` HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"` RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` + EnableHTTP2 *bool `json:"enableHTTP2,omitempty"` CrtPath string `json:"crtPath,omitempty"` KeyPath string `json:"keyPath,omitempty"` } +func (o *HTTPS2HTTPSPluginOptions) Complete() { + o.EnableHTTP2 = util.EmptyOr(o.EnableHTTP2, lo.ToPtr(true)) +} + +type HTTP2HTTPPluginOptions struct { + Type string `json:"type,omitempty"` + LocalAddr string `json:"localAddr,omitempty"` + HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"` + RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` +} + +func (o *HTTP2HTTPPluginOptions) Complete() {} + type Socks5PluginOptions struct { Type string `json:"type,omitempty"` Username string `json:"username,omitempty"` Password string `json:"password,omitempty"` } +func (o *Socks5PluginOptions) Complete() {} + type StaticFilePluginOptions struct { Type string `json:"type,omitempty"` LocalPath string `json:"localPath,omitempty"` @@ -135,15 +166,11 @@ type StaticFilePluginOptions struct { HTTPPassword string `json:"httpPassword,omitempty"` } +func (o *StaticFilePluginOptions) Complete() {} + type UnixDomainSocketPluginOptions struct { Type string `json:"type,omitempty"` UnixPath string `json:"unixPath,omitempty"` } -// Added HTTP2HTTPPluginOptions struct -type HTTP2HTTPPluginOptions struct { - Type string `json:"type,omitempty"` - LocalAddr string `json:"localAddr,omitempty"` - HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"` - RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` -} +func (o *UnixDomainSocketPluginOptions) Complete() {} diff --git a/pkg/config/v1/proxy.go b/pkg/config/v1/proxy.go index 45c489f6..d53d05e3 100644 --- a/pkg/config/v1/proxy.go +++ b/pkg/config/v1/proxy.go @@ -127,6 +127,10 @@ func (c *ProxyBaseConfig) Complete(namePrefix string) { c.Name = lo.Ternary(namePrefix == "", "", namePrefix+".") + c.Name c.LocalIP = util.EmptyOr(c.LocalIP, "127.0.0.1") c.Transport.BandwidthLimitMode = util.EmptyOr(c.Transport.BandwidthLimitMode, types.BandwidthLimitModeClient) + + if c.Plugin.ClientPluginOptions != nil { + c.Plugin.ClientPluginOptions.Complete() + } } func (c *ProxyBaseConfig) MarshalToMsg(m *msg.NewProxy) { diff --git a/pkg/plugin/client/https2http.go b/pkg/plugin/client/https2http.go index 6d686361..3bb12c22 100644 --- a/pkg/plugin/client/https2http.go +++ b/pkg/plugin/client/https2http.go @@ -27,9 +27,11 @@ import ( "time" "github.com/fatedier/golib/pool" + "github.com/samber/lo" v1 "github.com/fatedier/frp/pkg/config/v1" "github.com/fatedier/frp/pkg/transport" + httppkg "github.com/fatedier/frp/pkg/util/http" "github.com/fatedier/frp/pkg/util/log" netpkg "github.com/fatedier/frp/pkg/util/net" ) @@ -71,6 +73,17 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) { BufferPool: pool.NewBuffer(32 * 1024), ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0), } + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.TLS != nil { + tlsServerName, _ := httppkg.CanonicalHost(r.TLS.ServerName) + host, _ := httppkg.CanonicalHost(r.Host) + if tlsServerName != "" && tlsServerName != host { + w.WriteHeader(http.StatusMisdirectedRequest) + return + } + } + rp.ServeHTTP(w, r) + }) var ( tlsConfig *tls.Config @@ -87,10 +100,13 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) { } p.s = &http.Server{ - Handler: rp, + Handler: handler, ReadHeaderTimeout: 60 * time.Second, TLSConfig: tlsConfig, } + if !lo.FromPtr(opts.EnableHTTP2) { + p.s.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler)) + } go func() { _ = p.s.ServeTLS(listener, "", "") diff --git a/pkg/plugin/client/https2https.go b/pkg/plugin/client/https2https.go index 5ddd4dd6..c315c8e3 100644 --- a/pkg/plugin/client/https2https.go +++ b/pkg/plugin/client/https2https.go @@ -27,9 +27,11 @@ import ( "time" "github.com/fatedier/golib/pool" + "github.com/samber/lo" v1 "github.com/fatedier/frp/pkg/config/v1" "github.com/fatedier/frp/pkg/transport" + httppkg "github.com/fatedier/frp/pkg/util/http" "github.com/fatedier/frp/pkg/util/log" netpkg "github.com/fatedier/frp/pkg/util/net" ) @@ -77,6 +79,17 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) { BufferPool: pool.NewBuffer(32 * 1024), ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0), } + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.TLS != nil { + tlsServerName, _ := httppkg.CanonicalHost(r.TLS.ServerName) + host, _ := httppkg.CanonicalHost(r.Host) + if tlsServerName != "" && tlsServerName != host { + w.WriteHeader(http.StatusMisdirectedRequest) + return + } + } + rp.ServeHTTP(w, r) + }) var ( tlsConfig *tls.Config @@ -93,10 +106,13 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) { } p.s = &http.Server{ - Handler: rp, + Handler: handler, ReadHeaderTimeout: 60 * time.Second, TLSConfig: tlsConfig, } + if !lo.FromPtr(opts.EnableHTTP2) { + p.s.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler)) + } go func() { _ = p.s.ServeTLS(listener, "", "") diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go index 11d140eb..561a52e7 100644 --- a/pkg/util/version/version.go +++ b/pkg/util/version/version.go @@ -14,7 +14,7 @@ package version -var version = "0.58.1" +var version = "0.59.0" func Full() string { return version