diff --git a/pkg/config/v1/plugin.go b/pkg/config/v1/plugin.go index 3a7c8344..333b020a 100644 --- a/pkg/config/v1/plugin.go +++ b/pkg/config/v1/plugin.go @@ -76,6 +76,7 @@ const ( PluginSocks5 = "socks5" PluginStaticFile = "static_file" PluginUnixDomainSocket = "unix_domain_socket" + PluginHTTP2HTTP = "http2http" ) var clientPluginOptionsTypeMap = map[string]reflect.Type{ @@ -86,6 +87,7 @@ var clientPluginOptionsTypeMap = map[string]reflect.Type{ PluginSocks5: reflect.TypeOf(Socks5PluginOptions{}), PluginStaticFile: reflect.TypeOf(StaticFilePluginOptions{}), PluginUnixDomainSocket: reflect.TypeOf(UnixDomainSocketPluginOptions{}), + PluginHTTP2HTTP: reflect.TypeOf(HTTP2HTTPPluginOptions{}), } type HTTP2HTTPSPluginOptions struct { @@ -137,3 +139,11 @@ 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"` +} diff --git a/pkg/plugin/client/http2http.go b/pkg/plugin/client/http2http.go new file mode 100644 index 00000000..2ff837e8 --- /dev/null +++ b/pkg/plugin/client/http2http.go @@ -0,0 +1,78 @@ +// Package plugin contains various client plugins for frp +package plugin + +import ( + "io" + stdlog "log" + "net" + "net/http" + "net/http/httputil" + + "github.com/fatedier/golib/pool" + + v1 "github.com/fatedier/frp/pkg/config/v1" + "github.com/fatedier/frp/pkg/util/log" + netpkg "github.com/fatedier/frp/pkg/util/net" +) + +func init() { + Register(v1.PluginHTTP2HTTP, NewHTTP2HTTPPlugin) +} + +type HTTP2HTTPPlugin struct { + opts *v1.HTTP2HTTPPluginOptions + + l *Listener + s *http.Server +} + +func NewHTTP2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) { + opts := options.(*v1.HTTP2HTTPPluginOptions) + + listener := NewProxyListener() + + p := &HTTP2HTTPPlugin{ + opts: opts, + l: listener, + } + + rp := &httputil.ReverseProxy{ + Rewrite: func(r *httputil.ProxyRequest) { + req := r.Out + req.URL.Scheme = "http" + req.URL.Host = p.opts.LocalAddr + if p.opts.HostHeaderRewrite != "" { + req.Host = p.opts.HostHeaderRewrite + } + for k, v := range p.opts.RequestHeaders.Set { + req.Header.Set(k, v) + } + }, + BufferPool: pool.NewBuffer(32 * 1024), + ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0), + } + + p.s = &http.Server{ + Handler: rp, + ReadHeaderTimeout: 0, + } + + go func() { + _ = p.s.Serve(listener) + }() + + return p, nil +} + +func (p *HTTP2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) { + wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn) + _ = p.l.PutConn(wrapConn) +} + +func (p *HTTP2HTTPPlugin) Name() string { + return v1.PluginHTTP2HTTP +} + +func (p *HTTP2HTTPPlugin) Close() error { + return p.s.Close() +}