mirror of
https://github.com/fatedier/frp.git
synced 2026-01-11 22:23:12 +00:00
optimize some code (#3801)
This commit is contained in:
31
pkg/auth/pass.go
Normal file
31
pkg/auth/pass.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2023 The frp Authors
|
||||
//
|
||||
// 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 auth
|
||||
|
||||
import (
|
||||
"github.com/fatedier/frp/pkg/msg"
|
||||
)
|
||||
|
||||
var AlwaysPassVerifier = &alwaysPass{}
|
||||
|
||||
var _ Verifier = &alwaysPass{}
|
||||
|
||||
type alwaysPass struct{}
|
||||
|
||||
func (*alwaysPass) VerifyLogin(*msg.Login) error { return nil }
|
||||
|
||||
func (*alwaysPass) VerifyPing(*msg.Ping) error { return nil }
|
||||
|
||||
func (*alwaysPass) VerifyNewWorkConn(*msg.NewWorkConn) error { return nil }
|
||||
@@ -59,12 +59,17 @@ func RegisterProxyFlags(cmd *cobra.Command, c v1.ProxyConfigurer) {
|
||||
case *v1.TCPMuxProxyConfig:
|
||||
registerProxyDomainConfigFlags(cmd, &cc.DomainConfig)
|
||||
cmd.Flags().StringVarP(&cc.Multiplexer, "mux", "", "", "multiplexer")
|
||||
cmd.Flags().StringVarP(&cc.HTTPUser, "http_user", "", "", "http auth user")
|
||||
cmd.Flags().StringVarP(&cc.HTTPPassword, "http_pwd", "", "", "http auth password")
|
||||
case *v1.STCPProxyConfig:
|
||||
cmd.Flags().StringVarP(&cc.Secretkey, "sk", "", "", "secret key")
|
||||
cmd.Flags().StringSliceVarP(&cc.AllowUsers, "allow_users", "", []string{}, "allow visitor users")
|
||||
case *v1.SUDPProxyConfig:
|
||||
cmd.Flags().StringVarP(&cc.Secretkey, "sk", "", "", "secret key")
|
||||
cmd.Flags().StringSliceVarP(&cc.AllowUsers, "allow_users", "", []string{}, "allow visitor users")
|
||||
case *v1.XTCPProxyConfig:
|
||||
cmd.Flags().StringVarP(&cc.Secretkey, "sk", "", "", "secret key")
|
||||
cmd.Flags().StringSliceVarP(&cc.AllowUsers, "allow_users", "", []string{}, "allow visitor users")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
func ParseClientConfig(filePath string) (
|
||||
cfg ClientCommonConf,
|
||||
pxyCfgs map[string]ProxyConf,
|
||||
proxyCfgs map[string]ProxyConf,
|
||||
visitorCfgs map[string]VisitorConf,
|
||||
err error,
|
||||
) {
|
||||
@@ -56,7 +56,7 @@ func ParseClientConfig(filePath string) (
|
||||
configBuffer.Write(buf)
|
||||
|
||||
// Parse all proxy and visitor configs.
|
||||
pxyCfgs, visitorCfgs, err = LoadAllProxyConfsFromIni(cfg.User, configBuffer.Bytes(), cfg.Start)
|
||||
proxyCfgs, visitorCfgs, err = LoadAllProxyConfsFromIni(cfg.User, configBuffer.Bytes(), cfg.Start)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ func LoadConfigureFromFile(path string, c any, strict bool) error {
|
||||
|
||||
// LoadConfigure loads configuration from bytes and unmarshal into c.
|
||||
// Now it supports json, yaml and toml format.
|
||||
// TODO(fatedier): strict is not valide for ProxyConfigurer/VisitorConfigurer/ClientPluginOptions.
|
||||
func LoadConfigure(b []byte, c any, strict bool) error {
|
||||
var tomlObj interface{}
|
||||
// Try to unmarshal as TOML first; swallow errors from that (assume it's not valid TOML).
|
||||
@@ -188,19 +189,19 @@ func LoadClientConfig(path string, strict bool) (
|
||||
) {
|
||||
var (
|
||||
cliCfg *v1.ClientCommonConfig
|
||||
pxyCfgs = make([]v1.ProxyConfigurer, 0)
|
||||
proxyCfgs = make([]v1.ProxyConfigurer, 0)
|
||||
visitorCfgs = make([]v1.VisitorConfigurer, 0)
|
||||
isLegacyFormat bool
|
||||
)
|
||||
|
||||
if DetectLegacyINIFormatFromFile(path) {
|
||||
legacyCommon, legacyPxyCfgs, legacyVisitorCfgs, err := legacy.ParseClientConfig(path)
|
||||
legacyCommon, legacyProxyCfgs, legacyVisitorCfgs, err := legacy.ParseClientConfig(path)
|
||||
if err != nil {
|
||||
return nil, nil, nil, true, err
|
||||
}
|
||||
cliCfg = legacy.Convert_ClientCommonConf_To_v1(&legacyCommon)
|
||||
for _, c := range legacyPxyCfgs {
|
||||
pxyCfgs = append(pxyCfgs, legacy.Convert_ProxyConf_To_v1(c))
|
||||
for _, c := range legacyProxyCfgs {
|
||||
proxyCfgs = append(proxyCfgs, legacy.Convert_ProxyConf_To_v1(c))
|
||||
}
|
||||
for _, c := range legacyVisitorCfgs {
|
||||
visitorCfgs = append(visitorCfgs, legacy.Convert_VisitorConf_To_v1(c))
|
||||
@@ -213,7 +214,7 @@ func LoadClientConfig(path string, strict bool) (
|
||||
}
|
||||
cliCfg = &allCfg.ClientCommonConfig
|
||||
for _, c := range allCfg.Proxies {
|
||||
pxyCfgs = append(pxyCfgs, c.ProxyConfigurer)
|
||||
proxyCfgs = append(proxyCfgs, c.ProxyConfigurer)
|
||||
}
|
||||
for _, c := range allCfg.Visitors {
|
||||
visitorCfgs = append(visitorCfgs, c.VisitorConfigurer)
|
||||
@@ -223,18 +224,18 @@ func LoadClientConfig(path string, strict bool) (
|
||||
// Load additional config from includes.
|
||||
// legacy ini format already handle this in ParseClientConfig.
|
||||
if len(cliCfg.IncludeConfigFiles) > 0 && !isLegacyFormat {
|
||||
extPxyCfgs, extVisitorCfgs, err := LoadAdditionalClientConfigs(cliCfg.IncludeConfigFiles, isLegacyFormat, strict)
|
||||
extProxyCfgs, extVisitorCfgs, err := LoadAdditionalClientConfigs(cliCfg.IncludeConfigFiles, isLegacyFormat, strict)
|
||||
if err != nil {
|
||||
return nil, nil, nil, isLegacyFormat, err
|
||||
}
|
||||
pxyCfgs = append(pxyCfgs, extPxyCfgs...)
|
||||
proxyCfgs = append(proxyCfgs, extProxyCfgs...)
|
||||
visitorCfgs = append(visitorCfgs, extVisitorCfgs...)
|
||||
}
|
||||
|
||||
// Filter by start
|
||||
if len(cliCfg.Start) > 0 {
|
||||
startSet := sets.New(cliCfg.Start...)
|
||||
pxyCfgs = lo.Filter(pxyCfgs, func(c v1.ProxyConfigurer, _ int) bool {
|
||||
proxyCfgs = lo.Filter(proxyCfgs, func(c v1.ProxyConfigurer, _ int) bool {
|
||||
return startSet.Has(c.GetBaseConfig().Name)
|
||||
})
|
||||
visitorCfgs = lo.Filter(visitorCfgs, func(c v1.VisitorConfigurer, _ int) bool {
|
||||
@@ -245,17 +246,17 @@ func LoadClientConfig(path string, strict bool) (
|
||||
if cliCfg != nil {
|
||||
cliCfg.Complete()
|
||||
}
|
||||
for _, c := range pxyCfgs {
|
||||
for _, c := range proxyCfgs {
|
||||
c.Complete(cliCfg.User)
|
||||
}
|
||||
for _, c := range visitorCfgs {
|
||||
c.Complete(cliCfg)
|
||||
}
|
||||
return cliCfg, pxyCfgs, visitorCfgs, isLegacyFormat, nil
|
||||
return cliCfg, proxyCfgs, visitorCfgs, isLegacyFormat, nil
|
||||
}
|
||||
|
||||
func LoadAdditionalClientConfigs(paths []string, isLegacyFormat bool, strict bool) ([]v1.ProxyConfigurer, []v1.VisitorConfigurer, error) {
|
||||
pxyCfgs := make([]v1.ProxyConfigurer, 0)
|
||||
proxyCfgs := make([]v1.ProxyConfigurer, 0)
|
||||
visitorCfgs := make([]v1.VisitorConfigurer, 0)
|
||||
for _, path := range paths {
|
||||
absDir, err := filepath.Abs(filepath.Dir(path))
|
||||
@@ -281,7 +282,7 @@ func LoadAdditionalClientConfigs(paths []string, isLegacyFormat bool, strict boo
|
||||
return nil, nil, fmt.Errorf("load additional config from %s error: %v", absFile, err)
|
||||
}
|
||||
for _, c := range cfg.Proxies {
|
||||
pxyCfgs = append(pxyCfgs, c.ProxyConfigurer)
|
||||
proxyCfgs = append(proxyCfgs, c.ProxyConfigurer)
|
||||
}
|
||||
for _, c := range cfg.Visitors {
|
||||
visitorCfgs = append(visitorCfgs, c.VisitorConfigurer)
|
||||
@@ -289,5 +290,5 @@ func LoadAdditionalClientConfigs(paths []string, isLegacyFormat bool, strict boo
|
||||
}
|
||||
}
|
||||
}
|
||||
return pxyCfgs, visitorCfgs, nil
|
||||
return proxyCfgs, visitorCfgs, nil
|
||||
}
|
||||
|
||||
@@ -224,7 +224,9 @@ func NewProxyConfigurerByType(proxyType ProxyType) ProxyConfigurer {
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return reflect.New(v).Interface().(ProxyConfigurer)
|
||||
pc := reflect.New(v).Interface().(ProxyConfigurer)
|
||||
pc.GetBaseConfig().Type = string(proxyType)
|
||||
return pc
|
||||
}
|
||||
|
||||
var _ ProxyConfigurer = &TCPProxyConfig{}
|
||||
|
||||
@@ -80,7 +80,7 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig) (Warning, error) {
|
||||
return warnings, errs
|
||||
}
|
||||
|
||||
func ValidateAllClientConfig(c *v1.ClientCommonConfig, pxyCfgs []v1.ProxyConfigurer, visitorCfgs []v1.VisitorConfigurer) (Warning, error) {
|
||||
func ValidateAllClientConfig(c *v1.ClientCommonConfig, proxyCfgs []v1.ProxyConfigurer, visitorCfgs []v1.VisitorConfigurer) (Warning, error) {
|
||||
var warnings Warning
|
||||
if c != nil {
|
||||
warning, err := ValidateClientCommonConfig(c)
|
||||
@@ -90,7 +90,7 @@ func ValidateAllClientConfig(c *v1.ClientCommonConfig, pxyCfgs []v1.ProxyConfigu
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range pxyCfgs {
|
||||
for _, c := range proxyCfgs {
|
||||
if err := ValidateProxyConfigurerForClient(c); err != nil {
|
||||
return warnings, fmt.Errorf("proxy %s: %v", c.GetBaseConfig().Name, err)
|
||||
}
|
||||
|
||||
@@ -63,6 +63,15 @@ var msgTypeMap = map[byte]interface{}{
|
||||
|
||||
var TypeNameNatHoleResp = reflect.TypeOf(&NatHoleResp{}).Elem().Name()
|
||||
|
||||
type ClientSpec struct {
|
||||
// Due to the support of VirtualClient, frps needs to know the client type in order to
|
||||
// differentiate the processing logic.
|
||||
// Optional values: ssh-tunnel
|
||||
Type string `json:"type,omitempty"`
|
||||
// If the value is true, the client will not require authentication.
|
||||
AlwaysAuthPass bool `json:"always_auth_pass,omitempty"`
|
||||
}
|
||||
|
||||
// When frpc start, client send this message to login to server.
|
||||
type Login struct {
|
||||
Version string `json:"version,omitempty"`
|
||||
@@ -75,6 +84,9 @@ type Login struct {
|
||||
RunID string `json:"run_id,omitempty"`
|
||||
Metas map[string]string `json:"metas,omitempty"`
|
||||
|
||||
// Currently only effective for VirtualClient.
|
||||
ClientSpec ClientSpec `json:"client_spec,omitempty"`
|
||||
|
||||
// Some global configures.
|
||||
PoolCount int `json:"pool_count,omitempty"`
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
"net/http/httputil"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -79,7 +79,7 @@ func NewHTTP2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
}
|
||||
|
||||
func (p *HTTP2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
|
||||
wrapConn := utilnet.WrapReadWriteCloserToConn(conn, realConn)
|
||||
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
|
||||
_ = p.l.PutConn(wrapConn)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
libnet "github.com/fatedier/golib/net"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
)
|
||||
|
||||
@@ -68,7 +68,7 @@ func (hp *HTTPProxy) Name() string {
|
||||
}
|
||||
|
||||
func (hp *HTTPProxy) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
|
||||
wrapConn := utilnet.WrapReadWriteCloserToConn(conn, realConn)
|
||||
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
|
||||
|
||||
sc, rd := libnet.NewSharedConn(wrapConn)
|
||||
firstBytes := make([]byte, 7)
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
"github.com/fatedier/frp/pkg/transport"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -98,7 +98,7 @@ func (p *HTTPS2HTTPPlugin) genTLSConfig() (*tls.Config, error) {
|
||||
}
|
||||
|
||||
func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
|
||||
wrapConn := utilnet.WrapReadWriteCloserToConn(conn, realConn)
|
||||
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
|
||||
_ = p.l.PutConn(wrapConn)
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
"github.com/fatedier/frp/pkg/transport"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -104,7 +104,7 @@ func (p *HTTPS2HTTPSPlugin) genTLSConfig() (*tls.Config, error) {
|
||||
}
|
||||
|
||||
func (p *HTTPS2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
|
||||
wrapConn := utilnet.WrapReadWriteCloserToConn(conn, realConn)
|
||||
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
|
||||
_ = p.l.PutConn(wrapConn)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
gosocks5 "github.com/armon/go-socks5"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -52,7 +52,7 @@ func NewSocks5Plugin(options v1.ClientPluginOptions) (p Plugin, err error) {
|
||||
|
||||
func (sp *Socks5Plugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
|
||||
defer conn.Close()
|
||||
wrapConn := utilnet.WrapReadWriteCloserToConn(conn, realConn)
|
||||
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
|
||||
_ = sp.Server.ServeConn(wrapConn)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -57,8 +57,8 @@ func NewStaticFilePlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
}
|
||||
|
||||
router := mux.NewRouter()
|
||||
router.Use(utilnet.NewHTTPAuthMiddleware(opts.HTTPUser, opts.HTTPPassword).SetAuthFailDelay(200 * time.Millisecond).Middleware)
|
||||
router.PathPrefix(prefix).Handler(utilnet.MakeHTTPGzipHandler(http.StripPrefix(prefix, http.FileServer(http.Dir(opts.LocalPath))))).Methods("GET")
|
||||
router.Use(netpkg.NewHTTPAuthMiddleware(opts.HTTPUser, opts.HTTPPassword).SetAuthFailDelay(200 * time.Millisecond).Middleware)
|
||||
router.PathPrefix(prefix).Handler(netpkg.MakeHTTPGzipHandler(http.StripPrefix(prefix, http.FileServer(http.Dir(opts.LocalPath))))).Methods("GET")
|
||||
sp.s = &http.Server{
|
||||
Handler: router,
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func NewStaticFilePlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
}
|
||||
|
||||
func (sp *StaticFilePlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
|
||||
wrapConn := utilnet.WrapReadWriteCloserToConn(conn, realConn)
|
||||
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
|
||||
_ = sp.l.PutConn(wrapConn)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/fatedier/frp/client"
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
httppkg "github.com/fatedier/frp/pkg/util/http"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
@@ -115,7 +115,7 @@ func (c *Client) UpdateConfig(content string) error {
|
||||
|
||||
func (c *Client) setAuthHeader(req *http.Request) {
|
||||
if c.authUser != "" || c.authPwd != "" {
|
||||
req.Header.Set("Authorization", util.BasicAuth(c.authUser, c.authPwd))
|
||||
req.Header.Set("Authorization", httppkg.BasicAuth(c.authUser, c.authPwd))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,21 +26,21 @@ import (
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
"github.com/fatedier/frp/pkg/transport"
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
type Gateway struct {
|
||||
bindPort int
|
||||
ln net.Listener
|
||||
|
||||
serverPeerListener *utilnet.InternalListener
|
||||
peerServerListener *netpkg.InternalListener
|
||||
|
||||
sshConfig *ssh.ServerConfig
|
||||
}
|
||||
|
||||
func NewGateway(
|
||||
cfg v1.SSHTunnelGateway, bindAddr string,
|
||||
serverPeerListener *utilnet.InternalListener,
|
||||
peerServerListener *netpkg.InternalListener,
|
||||
) (*Gateway, error) {
|
||||
sshConfig := &ssh.ServerConfig{}
|
||||
|
||||
@@ -71,15 +71,8 @@ func NewGateway(
|
||||
}
|
||||
sshConfig.AddHostKey(privateKey)
|
||||
|
||||
sshConfig.NoClientAuth = cfg.AuthorizedKeysFile == ""
|
||||
sshConfig.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||
if cfg.AuthorizedKeysFile == "" {
|
||||
return &ssh.Permissions{
|
||||
Extensions: map[string]string{
|
||||
"user": "",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
authorizedKeysMap, err := loadAuthorizedKeysFromFile(cfg.AuthorizedKeysFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("internal error")
|
||||
@@ -103,7 +96,7 @@ func NewGateway(
|
||||
return &Gateway{
|
||||
bindPort: cfg.BindPort,
|
||||
ln: ln,
|
||||
serverPeerListener: serverPeerListener,
|
||||
peerServerListener: peerServerListener,
|
||||
sshConfig: sshConfig,
|
||||
}, nil
|
||||
}
|
||||
@@ -121,7 +114,7 @@ func (g *Gateway) Run() {
|
||||
func (g *Gateway) handleConn(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
ts, err := NewTunnelServer(conn, g.sshConfig, g.serverPeerListener)
|
||||
ts, err := NewTunnelServer(conn, g.sshConfig, g.peerServerListener)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ package ssh
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
libio "github.com/fatedier/golib/io"
|
||||
@@ -27,10 +29,12 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/fatedier/frp/client/proxy"
|
||||
"github.com/fatedier/frp/pkg/config"
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
"github.com/fatedier/frp/pkg/msg"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
"github.com/fatedier/frp/pkg/util/xlog"
|
||||
"github.com/fatedier/frp/pkg/virtual"
|
||||
@@ -64,15 +68,16 @@ type TunnelServer struct {
|
||||
sc *ssh.ServerConfig
|
||||
|
||||
vc *virtual.Client
|
||||
serverPeerListener *utilnet.InternalListener
|
||||
peerServerListener *netpkg.InternalListener
|
||||
doneCh chan struct{}
|
||||
closeDoneChOnce sync.Once
|
||||
}
|
||||
|
||||
func NewTunnelServer(conn net.Conn, sc *ssh.ServerConfig, serverPeerListener *utilnet.InternalListener) (*TunnelServer, error) {
|
||||
func NewTunnelServer(conn net.Conn, sc *ssh.ServerConfig, peerServerListener *netpkg.InternalListener) (*TunnelServer, error) {
|
||||
s := &TunnelServer{
|
||||
underlyingConn: conn,
|
||||
sc: sc,
|
||||
serverPeerListener: serverPeerListener,
|
||||
peerServerListener: peerServerListener,
|
||||
doneCh: make(chan struct{}),
|
||||
}
|
||||
return s, nil
|
||||
@@ -94,19 +99,35 @@ func (s *TunnelServer) Run() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientCfg.User = util.EmptyOr(sshConn.Permissions.Extensions["user"], clientCfg.User)
|
||||
clientCfg.Complete()
|
||||
if sshConn.Permissions != nil {
|
||||
clientCfg.User = util.EmptyOr(sshConn.Permissions.Extensions["user"], clientCfg.User)
|
||||
}
|
||||
pc.Complete(clientCfg.User)
|
||||
|
||||
s.vc = virtual.NewClient(clientCfg)
|
||||
// join workConn and ssh channel
|
||||
s.vc.SetInWorkConnCallback(func(base *v1.ProxyBaseConfig, workConn net.Conn, m *msg.StartWorkConn) bool {
|
||||
c, err := s.openConn(addr)
|
||||
if err != nil {
|
||||
vc, err := virtual.NewClient(virtual.ClientOptions{
|
||||
Common: clientCfg,
|
||||
Spec: &msg.ClientSpec{
|
||||
Type: "ssh-tunnel",
|
||||
// If ssh does not require authentication, then the virtual client needs to authenticate through a token.
|
||||
// Otherwise, once ssh authentication is passed, the virtual client does not need to authenticate again.
|
||||
AlwaysAuthPass: !s.sc.NoClientAuth,
|
||||
},
|
||||
HandleWorkConnCb: func(base *v1.ProxyBaseConfig, workConn net.Conn, m *msg.StartWorkConn) bool {
|
||||
// join workConn and ssh channel
|
||||
c, err := s.openConn(addr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
libio.Join(c, workConn)
|
||||
return false
|
||||
}
|
||||
libio.Join(c, workConn)
|
||||
return false
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.vc = vc
|
||||
|
||||
// transfer connection from virtual client to server peer listener
|
||||
go func() {
|
||||
l := s.vc.PeerListener()
|
||||
@@ -115,21 +136,35 @@ func (s *TunnelServer) Run() error {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = s.serverPeerListener.PutConn(conn)
|
||||
_ = s.peerServerListener.PutConn(conn)
|
||||
}
|
||||
}()
|
||||
xl := xlog.New().AddPrefix(xlog.LogPrefix{Name: "sshVirtualClient", Value: "sshVirtualClient", Priority: 100})
|
||||
ctx := xlog.NewContext(context.Background(), xl)
|
||||
go func() {
|
||||
_ = s.vc.Run(ctx)
|
||||
// If vc.Run returns, it means that the virtual client has been closed, and the ssh tunnel connection should be closed.
|
||||
// One scenario is that the virtual client exits due to login failure.
|
||||
s.closeDoneChOnce.Do(func() {
|
||||
_ = sshConn.Close()
|
||||
close(s.doneCh)
|
||||
})
|
||||
}()
|
||||
|
||||
s.vc.UpdateProxyConfigurer([]v1.ProxyConfigurer{pc})
|
||||
|
||||
_ = sshConn.Wait()
|
||||
_ = sshConn.Close()
|
||||
if err := s.waitProxyStatusReady(pc.GetBaseConfig().Name, time.Second); err != nil {
|
||||
log.Warn("wait proxy status ready error: %v", err)
|
||||
} else {
|
||||
_ = sshConn.Wait()
|
||||
}
|
||||
|
||||
s.vc.Close()
|
||||
close(s.doneCh)
|
||||
log.Trace("ssh tunnel connection from %v closed", sshConn.RemoteAddr())
|
||||
s.closeDoneChOnce.Do(func() {
|
||||
_ = sshConn.Close()
|
||||
close(s.doneCh)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -217,6 +252,14 @@ func (s *TunnelServer) parseClientAndProxyConfigurer(_ *tcpipForward, extraPaylo
|
||||
if err := cmd.ParseFlags(args); err != nil {
|
||||
return nil, nil, fmt.Errorf("parse flags from ssh client error: %v", err)
|
||||
}
|
||||
// if name is not set, generate a random one
|
||||
if pc.GetBaseConfig().Name == "" {
|
||||
id, err := util.RandIDWithLen(8)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("generate random id error: %v", err)
|
||||
}
|
||||
pc.GetBaseConfig().Name = fmt.Sprintf("sshtunnel-%s-%s", proxyType, id)
|
||||
}
|
||||
return &clientCfg, pc, nil
|
||||
}
|
||||
|
||||
@@ -274,6 +317,34 @@ func (s *TunnelServer) openConn(addr *tcpipForward) (net.Conn, error) {
|
||||
}
|
||||
go ssh.DiscardRequests(reqs)
|
||||
|
||||
conn := utilnet.WrapReadWriteCloserToConn(channel, s.underlyingConn)
|
||||
conn := netpkg.WrapReadWriteCloserToConn(channel, s.underlyingConn)
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *TunnelServer) waitProxyStatusReady(name string, timeout time.Duration) error {
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
timer := time.NewTimer(timeout)
|
||||
defer timer.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
ps, err := s.vc.Service().GetProxyStatus(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
switch ps.Phase {
|
||||
case proxy.ProxyPhaseRunning:
|
||||
return nil
|
||||
case proxy.ProxyPhaseStartErr, proxy.ProxyPhaseClosed:
|
||||
return errors.New(ps.Err)
|
||||
}
|
||||
case <-timer.C:
|
||||
return fmt.Errorf("wait proxy status ready timeout")
|
||||
case <-s.doneCh:
|
||||
return fmt.Errorf("ssh tunnel server closed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package util
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
128
pkg/util/http/server.go
Normal file
128
pkg/util/http/server.go
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright 2023 The frp Authors
|
||||
//
|
||||
// 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 http
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/fatedier/frp/assets"
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultReadTimeout = 60 * time.Second
|
||||
defaultWriteTimeout = 60 * time.Second
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
addr string
|
||||
ln net.Listener
|
||||
tlsCfg *tls.Config
|
||||
|
||||
router *mux.Router
|
||||
hs *http.Server
|
||||
|
||||
authMiddleware mux.MiddlewareFunc
|
||||
}
|
||||
|
||||
func NewServer(cfg v1.WebServerConfig) (*Server, error) {
|
||||
if cfg.AssetsDir != "" {
|
||||
assets.Load(cfg.AssetsDir)
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(cfg.Addr, strconv.Itoa(cfg.Port))
|
||||
if addr == ":" {
|
||||
addr = ":http"
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
router := mux.NewRouter()
|
||||
hs := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: router,
|
||||
ReadTimeout: defaultReadTimeout,
|
||||
WriteTimeout: defaultWriteTimeout,
|
||||
}
|
||||
s := &Server{
|
||||
addr: addr,
|
||||
ln: ln,
|
||||
hs: hs,
|
||||
router: router,
|
||||
}
|
||||
if cfg.PprofEnable {
|
||||
s.registerPprofHandlers()
|
||||
}
|
||||
if cfg.TLS != nil {
|
||||
cert, err := tls.LoadX509KeyPair(cfg.TLS.CertFile, cfg.TLS.KeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.tlsCfg = &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
}
|
||||
s.authMiddleware = netpkg.NewHTTPAuthMiddleware(cfg.User, cfg.Password).SetAuthFailDelay(200 * time.Millisecond).Middleware
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) Address() string {
|
||||
return s.addr
|
||||
}
|
||||
|
||||
func (s *Server) Run() error {
|
||||
ln := s.ln
|
||||
if s.tlsCfg != nil {
|
||||
ln = tls.NewListener(ln, s.tlsCfg)
|
||||
}
|
||||
return s.hs.Serve(ln)
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
return s.hs.Close()
|
||||
}
|
||||
|
||||
type RouterRegisterHelper struct {
|
||||
Router *mux.Router
|
||||
AssetsFS http.FileSystem
|
||||
AuthMiddleware mux.MiddlewareFunc
|
||||
}
|
||||
|
||||
func (s *Server) RouteRegister(register func(helper *RouterRegisterHelper)) {
|
||||
register(&RouterRegisterHelper{
|
||||
Router: s.router,
|
||||
AssetsFS: assets.FileSystem,
|
||||
AuthMiddleware: s.authMiddleware,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) registerPprofHandlers() {
|
||||
s.router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||
s.router.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
s.router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
s.router.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
s.router.PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index)
|
||||
}
|
||||
33
pkg/util/net/dns.go
Normal file
33
pkg/util/net/dns.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 The frp Authors
|
||||
//
|
||||
// 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 net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
func SetDefaultDNSAddress(dnsAddress string) {
|
||||
if _, _, err := net.SplitHostPort(dnsAddress); err != nil {
|
||||
dnsAddress = net.JoinHostPort(dnsAddress, "53")
|
||||
}
|
||||
// Change default dns server
|
||||
net.DefaultResolver = &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return net.Dial("udp", dnsAddress)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,10 @@ func (l *InternalListener) PutConn(conn net.Conn) error {
|
||||
conn.Close()
|
||||
}
|
||||
})
|
||||
return err
|
||||
if err != nil {
|
||||
return fmt.Errorf("put conn error: listener is closed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *InternalListener) Close() error {
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
libnet "github.com/fatedier/golib/net"
|
||||
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
httppkg "github.com/fatedier/frp/pkg/util/http"
|
||||
"github.com/fatedier/frp/pkg/util/vhost"
|
||||
)
|
||||
|
||||
@@ -59,10 +59,10 @@ func (muxer *HTTPConnectTCPMuxer) readHTTPConnectRequest(rd io.Reader) (host, ht
|
||||
return
|
||||
}
|
||||
|
||||
host, _ = util.CanonicalHost(req.Host)
|
||||
host, _ = httppkg.CanonicalHost(req.Host)
|
||||
proxyAuth := req.Header.Get("Proxy-Authorization")
|
||||
if proxyAuth != "" {
|
||||
httpUser, httpPwd, _ = util.ParseBasicAuth(proxyAuth)
|
||||
httpUser, httpPwd, _ = httppkg.ParseBasicAuth(proxyAuth)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func (muxer *HTTPConnectTCPMuxer) sendConnectResponse(c net.Conn, _ map[string]s
|
||||
if muxer.passthrough {
|
||||
return nil
|
||||
}
|
||||
res := util.OkResponse()
|
||||
res := httppkg.OkResponse()
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func (muxer *HTTPConnectTCPMuxer) auth(c net.Conn, username, password string, re
|
||||
return true, nil
|
||||
}
|
||||
|
||||
resp := util.ProxyUnauthorizedResponse()
|
||||
resp := httppkg.ProxyUnauthorizedResponse()
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ import (
|
||||
libio "github.com/fatedier/golib/io"
|
||||
"github.com/fatedier/golib/pool"
|
||||
|
||||
frpLog "github.com/fatedier/frp/pkg/util/log"
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
httppkg "github.com/fatedier/frp/pkg/util/http"
|
||||
logpkg "github.com/fatedier/frp/pkg/util/log"
|
||||
)
|
||||
|
||||
var ErrNoRouteFound = errors.New("no route found")
|
||||
@@ -61,7 +61,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
Director: func(req *http.Request) {
|
||||
req.URL.Scheme = "http"
|
||||
reqRouteInfo := req.Context().Value(RouteInfoKey).(*RequestRouteInfo)
|
||||
oldHost, _ := util.CanonicalHost(reqRouteInfo.Host)
|
||||
oldHost, _ := httppkg.CanonicalHost(reqRouteInfo.Host)
|
||||
|
||||
rc := rp.GetRouteConfig(oldHost, reqRouteInfo.URL, reqRouteInfo.HTTPUser)
|
||||
if rc != nil {
|
||||
@@ -74,7 +74,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
// ignore error here, it will use CreateConnFn instead later
|
||||
endpoint, _ = rc.ChooseEndpointFn()
|
||||
reqRouteInfo.Endpoint = endpoint
|
||||
frpLog.Trace("choose endpoint name [%s] for http request host [%s] path [%s] httpuser [%s]",
|
||||
logpkg.Trace("choose endpoint name [%s] for http request host [%s] path [%s] httpuser [%s]",
|
||||
endpoint, oldHost, reqRouteInfo.URL, reqRouteInfo.HTTPUser)
|
||||
}
|
||||
// Set {domain}.{location}.{routeByHTTPUser}.{endpoint} as URL host here to let http transport reuse connections.
|
||||
@@ -116,7 +116,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
BufferPool: newWrapPool(),
|
||||
ErrorLog: log.New(newWrapLogger(), "", 0),
|
||||
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
|
||||
frpLog.Warn("do http proxy request [host: %s] error: %v", req.Host, err)
|
||||
logpkg.Warn("do http proxy request [host: %s] error: %v", req.Host, err)
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
_, _ = rw.Write(getNotFoundPageContent())
|
||||
},
|
||||
@@ -143,7 +143,7 @@ func (rp *HTTPReverseProxy) UnRegister(routeCfg RouteConfig) {
|
||||
func (rp *HTTPReverseProxy) GetRouteConfig(domain, location, routeByHTTPUser string) *RouteConfig {
|
||||
vr, ok := rp.getVhost(domain, location, routeByHTTPUser)
|
||||
if ok {
|
||||
frpLog.Debug("get new HTTP request host [%s] path [%s] httpuser [%s]", domain, location, routeByHTTPUser)
|
||||
logpkg.Debug("get new HTTP request host [%s] path [%s] httpuser [%s]", domain, location, routeByHTTPUser)
|
||||
return vr.payload.(*RouteConfig)
|
||||
}
|
||||
return nil
|
||||
@@ -159,7 +159,7 @@ func (rp *HTTPReverseProxy) GetHeaders(domain, location, routeByHTTPUser string)
|
||||
|
||||
// CreateConnection create a new connection by route config
|
||||
func (rp *HTTPReverseProxy) CreateConnection(reqRouteInfo *RequestRouteInfo, byEndpoint bool) (net.Conn, error) {
|
||||
host, _ := util.CanonicalHost(reqRouteInfo.Host)
|
||||
host, _ := httppkg.CanonicalHost(reqRouteInfo.Host)
|
||||
vr, ok := rp.getVhost(host, reqRouteInfo.URL, reqRouteInfo.HTTPUser)
|
||||
if ok {
|
||||
if byEndpoint {
|
||||
@@ -303,7 +303,7 @@ func (rp *HTTPReverseProxy) injectRequestInfoToCtx(req *http.Request) *http.Requ
|
||||
}
|
||||
|
||||
func (rp *HTTPReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
domain, _ := util.CanonicalHost(req.Host)
|
||||
domain, _ := httppkg.CanonicalHost(req.Host)
|
||||
location := req.URL.Path
|
||||
user, passwd, _ := req.BasicAuth()
|
||||
if !rp.CheckAuth(domain, location, user, user, passwd) {
|
||||
@@ -333,6 +333,6 @@ type wrapLogger struct{}
|
||||
func newWrapLogger() *wrapLogger { return &wrapLogger{} }
|
||||
|
||||
func (l *wrapLogger) Write(p []byte) (n int, err error) {
|
||||
frpLog.Warn("%s", string(bytes.TrimRight(p, "\n")))
|
||||
logpkg.Warn("%s", string(bytes.TrimRight(p, "\n")))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
frpLog "github.com/fatedier/frp/pkg/util/log"
|
||||
logpkg "github.com/fatedier/frp/pkg/util/log"
|
||||
"github.com/fatedier/frp/pkg/util/version"
|
||||
)
|
||||
|
||||
@@ -58,7 +58,7 @@ func getNotFoundPageContent() []byte {
|
||||
if NotFoundPagePath != "" {
|
||||
buf, err = os.ReadFile(NotFoundPagePath)
|
||||
if err != nil {
|
||||
frpLog.Warn("read custom 404 page error: %v", err)
|
||||
logpkg.Warn("read custom 404 page error: %v", err)
|
||||
buf = []byte(NotFound)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/fatedier/golib/errors"
|
||||
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
"github.com/fatedier/frp/pkg/util/xlog"
|
||||
)
|
||||
|
||||
@@ -284,7 +284,7 @@ func (l *Listener) Accept() (net.Conn, error) {
|
||||
xl.Debug("rewrite host to [%s] success", l.rewriteHost)
|
||||
conn = sConn
|
||||
}
|
||||
return utilnet.NewContextConn(l.ctx, conn), nil
|
||||
return netpkg.NewContextConn(l.ctx, conn), nil
|
||||
}
|
||||
|
||||
func (l *Listener) Close() error {
|
||||
|
||||
@@ -21,55 +21,70 @@ import (
|
||||
"github.com/fatedier/frp/client"
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
"github.com/fatedier/frp/pkg/msg"
|
||||
utilnet "github.com/fatedier/frp/pkg/util/net"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
type ClientOptions struct {
|
||||
Common *v1.ClientCommonConfig
|
||||
Spec *msg.ClientSpec
|
||||
HandleWorkConnCb func(*v1.ProxyBaseConfig, net.Conn, *msg.StartWorkConn) bool
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
l *utilnet.InternalListener
|
||||
l *netpkg.InternalListener
|
||||
svr *client.Service
|
||||
}
|
||||
|
||||
func NewClient(cfg *v1.ClientCommonConfig) *Client {
|
||||
cfg.Complete()
|
||||
func NewClient(options ClientOptions) (*Client, error) {
|
||||
if options.Common != nil {
|
||||
options.Common.Complete()
|
||||
}
|
||||
|
||||
ln := utilnet.NewInternalListener()
|
||||
|
||||
svr := client.NewService(cfg, nil, nil, "")
|
||||
svr.SetConnectorCreator(func(context.Context, *v1.ClientCommonConfig) client.Connector {
|
||||
return &pipeConnector{
|
||||
peerListener: ln,
|
||||
}
|
||||
})
|
||||
ln := netpkg.NewInternalListener()
|
||||
|
||||
serviceOptions := client.ServiceOptions{
|
||||
Common: options.Common,
|
||||
ClientSpec: options.Spec,
|
||||
ConnectorCreator: func(context.Context, *v1.ClientCommonConfig) client.Connector {
|
||||
return &pipeConnector{
|
||||
peerListener: ln,
|
||||
}
|
||||
},
|
||||
HandleWorkConnCb: options.HandleWorkConnCb,
|
||||
}
|
||||
svr, err := client.NewService(serviceOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Client{
|
||||
l: ln,
|
||||
svr: svr,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) PeerListener() net.Listener {
|
||||
return c.l
|
||||
}
|
||||
|
||||
func (c *Client) SetInWorkConnCallback(cb func(*v1.ProxyBaseConfig, net.Conn, *msg.StartWorkConn) bool) {
|
||||
c.svr.SetInWorkConnCallback(cb)
|
||||
}
|
||||
|
||||
func (c *Client) UpdateProxyConfigurer(proxyCfgs []v1.ProxyConfigurer) {
|
||||
_ = c.svr.ReloadConf(proxyCfgs, nil)
|
||||
_ = c.svr.UpdateAllConfigurer(proxyCfgs, nil)
|
||||
}
|
||||
|
||||
func (c *Client) Run(ctx context.Context) error {
|
||||
return c.svr.Run(ctx)
|
||||
}
|
||||
|
||||
func (c *Client) Service() *client.Service {
|
||||
return c.svr
|
||||
}
|
||||
|
||||
func (c *Client) Close() {
|
||||
c.l.Close()
|
||||
c.svr.Close()
|
||||
c.l.Close()
|
||||
}
|
||||
|
||||
type pipeConnector struct {
|
||||
peerListener *utilnet.InternalListener
|
||||
peerListener *netpkg.InternalListener
|
||||
}
|
||||
|
||||
func (pc *pipeConnector) Open() error {
|
||||
|
||||
Reference in New Issue
Block a user