From 68dfc89bce16cf6cd08ca94893d384fc8e5e4c70 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 24 Jan 2018 17:49:13 +0800 Subject: [PATCH] plugin: new plugin static_file for getting files by http protocol --- conf/frpc_full.ini | 27 +++++++++++ models/plugin/http_proxy.go | 44 ------------------ models/plugin/plugin.go | 44 ++++++++++++++++++ models/plugin/static_file.go | 87 ++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 44 deletions(-) create mode 100644 models/plugin/static_file.go diff --git a/conf/frpc_full.ini b/conf/frpc_full.ini index 78992c8..1b152ed 100644 --- a/conf/frpc_full.ini +++ b/conf/frpc_full.ini @@ -73,6 +73,16 @@ local_port = 22 # if remote_port is 0, frps will assgin a random port for you remote_port = 0 +# if you want tp expose multiple ports, add 'range:' prefix to the section name +# frpc will generate multiple proxies such as 'tcp_port_6010', 'tcp_port_6011' and so on. +[range:tcp_port] +type = tcp +local_ip = 127.0.0.1 +local_port = 6010-6020,6022,6024-6028 +remote_port = 6010-6020,6022,6024-6028 +use_encryption = false +use_compression = false + [dns] type = udp local_ip = 114.114.114.114 @@ -81,6 +91,14 @@ remote_port = 6002 use_encryption = false use_compression = false +[range:udp_port] +type = udp +local_ip = 127.0.0.1 +local_port = 6010-6020 +remote_port = 6010-6020 +use_encryption = false +use_compression = false + # Resolve your domain names to [server_addr] so you can use http://web01.yourdomain.com to browse web01 and http://web02.yourdomain.com to browse web02 [web01] type = http @@ -124,6 +142,15 @@ plugin = http_proxy plugin_http_user = abc plugin_http_passwd = abc +[plugin_static_file] +type = tcp +remote_port = 6005 +plugin = static_file +plugin_local_path = /var/www/blog +plugin_strip_prefix = static +plugin_http_user = abc +plugin_http_passwd = abc + [secret_tcp] # If the type is secret tcp, remote_port is useless # Who want to connect local port should deploy another frpc with stcp proxy and role is visitor diff --git a/models/plugin/http_proxy.go b/models/plugin/http_proxy.go index e5aefa8..41e6bdc 100644 --- a/models/plugin/http_proxy.go +++ b/models/plugin/http_proxy.go @@ -17,14 +17,11 @@ package plugin import ( "bufio" "encoding/base64" - "fmt" "io" "net" "net/http" "strings" - "sync" - "github.com/fatedier/frp/utils/errors" frpIo "github.com/fatedier/frp/utils/io" frpNet "github.com/fatedier/frp/utils/net" ) @@ -35,47 +32,6 @@ func init() { Register(PluginHttpProxy, NewHttpProxyPlugin) } -type Listener struct { - conns chan net.Conn - closed bool - mu sync.Mutex -} - -func NewProxyListener() *Listener { - return &Listener{ - conns: make(chan net.Conn, 64), - } -} - -func (l *Listener) Accept() (net.Conn, error) { - conn, ok := <-l.conns - if !ok { - return nil, fmt.Errorf("listener closed") - } - return conn, nil -} - -func (l *Listener) PutConn(conn net.Conn) error { - err := errors.PanicToError(func() { - l.conns <- conn - }) - return err -} - -func (l *Listener) Close() error { - l.mu.Lock() - defer l.mu.Unlock() - if !l.closed { - close(l.conns) - l.closed = true - } - return nil -} - -func (l *Listener) Addr() net.Addr { - return (*net.TCPAddr)(nil) -} - type HttpProxy struct { l *Listener s *http.Server diff --git a/models/plugin/plugin.go b/models/plugin/plugin.go index a0ae8e1..bd976d1 100644 --- a/models/plugin/plugin.go +++ b/models/plugin/plugin.go @@ -17,7 +17,10 @@ package plugin import ( "fmt" "io" + "net" + "sync" + "github.com/fatedier/frp/utils/errors" frpNet "github.com/fatedier/frp/utils/net" ) @@ -45,3 +48,44 @@ type Plugin interface { Handle(conn io.ReadWriteCloser, realConn frpNet.Conn) Close() error } + +type Listener struct { + conns chan net.Conn + closed bool + mu sync.Mutex +} + +func NewProxyListener() *Listener { + return &Listener{ + conns: make(chan net.Conn, 64), + } +} + +func (l *Listener) Accept() (net.Conn, error) { + conn, ok := <-l.conns + if !ok { + return nil, fmt.Errorf("listener closed") + } + return conn, nil +} + +func (l *Listener) PutConn(conn net.Conn) error { + err := errors.PanicToError(func() { + l.conns <- conn + }) + return err +} + +func (l *Listener) Close() error { + l.mu.Lock() + defer l.mu.Unlock() + if !l.closed { + close(l.conns) + l.closed = true + } + return nil +} + +func (l *Listener) Addr() net.Addr { + return (*net.TCPAddr)(nil) +} diff --git a/models/plugin/static_file.go b/models/plugin/static_file.go new file mode 100644 index 0000000..87290b6 --- /dev/null +++ b/models/plugin/static_file.go @@ -0,0 +1,87 @@ +// Copyright 2018 fatedier, fatedier@gmail.com +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package plugin + +import ( + "io" + "net/http" + + "github.com/julienschmidt/httprouter" + + frpNet "github.com/fatedier/frp/utils/net" +) + +const PluginStaticFile = "static_file" + +func init() { + Register(PluginStaticFile, NewStaticFilePlugin) +} + +type StaticFilePlugin struct { + localPath string + stripPrefix string + httpUser string + httpPasswd string + + l *Listener + s *http.Server +} + +func NewStaticFilePlugin(params map[string]string) (Plugin, error) { + localPath := params["plugin_local_path"] + stripPrefix := params["plugin_strip_prefix"] + httpUser := params["plugin_http_user"] + httpPasswd := params["plugin_http_passwd"] + + listener := NewProxyListener() + + sp := &StaticFilePlugin{ + localPath: localPath, + stripPrefix: stripPrefix, + httpUser: httpUser, + httpPasswd: httpPasswd, + + l: listener, + } + var prefix string + if stripPrefix != "" { + prefix = "/" + stripPrefix + "/" + } else { + prefix = "/" + } + router := httprouter.New() + router.Handler("GET", prefix+"*filepath", frpNet.MakeHttpGzipHandler( + frpNet.NewHttpBasicAuthWraper(http.StripPrefix(prefix, http.FileServer(http.Dir(localPath))), httpUser, httpPasswd))) + sp.s = &http.Server{ + Handler: router, + } + go sp.s.Serve(listener) + return sp, nil +} + +func (sp *StaticFilePlugin) Handle(conn io.ReadWriteCloser, realConn frpNet.Conn) { + wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn) + sp.l.PutConn(wrapConn) +} + +func (sp *StaticFilePlugin) Name() string { + return PluginStaticFile +} + +func (sp *StaticFilePlugin) Close() error { + sp.s.Close() + sp.l.Close() + return nil +}