optimize the code of the command line (#3614)

This commit is contained in:
fatedier 2023-09-15 10:33:32 +08:00 committed by GitHub
parent 74255f711e
commit bae0b4d7c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 566 additions and 1363 deletions

View File

@ -1,3 +1,8 @@
### Features
* Configuration: We now support TOML, YAML, and JSON for configuration. Please note that INI is deprecated and will be removed in future releases. New features will only be available in TOML, YAML, or JSON. Users wanting these new features should switch their configuration format accordingly. #2521
### Breaking Changes
* Change the way to start the visitor through the command line from `frpc stcp --role=visitor xxx` to `frpc stcp visitor xxx`.
* Modified the semantics of the `server_addr` in the command line, no longer including the port. Added the `server_port` parameter to configure the port.

117
cmd/frpc/sub/admin.go Normal file
View File

@ -0,0 +1,117 @@
// 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 sub
import (
"fmt"
"os"
"strings"
"github.com/rodaine/table"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config"
v1 "github.com/fatedier/frp/pkg/config/v1"
clientsdk "github.com/fatedier/frp/pkg/sdk/client"
)
func init() {
rootCmd.AddCommand(NewAdminCommand(
"reload",
"Hot-Reload frpc configuration",
ReloadHandler,
))
rootCmd.AddCommand(NewAdminCommand(
"status",
"Overview of all proxies status",
StatusHandler,
))
rootCmd.AddCommand(NewAdminCommand(
"stop",
"Stop the running frpc",
StopHandler,
))
}
func NewAdminCommand(name, short string, handler func(*v1.ClientCommonConfig) error) *cobra.Command {
return &cobra.Command{
Use: name,
Short: short,
Run: func(cmd *cobra.Command, args []string) {
cfg, _, _, _, err := config.LoadClientConfig(cfgFile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if cfg.WebServer.Port <= 0 {
fmt.Println("web server port should be set if you want to use this feature")
os.Exit(1)
}
if err := handler(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
},
}
}
func ReloadHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
if err := client.Reload(); err != nil {
return err
}
fmt.Println("reload success")
return nil
}
func StatusHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
res, err := client.GetAllProxyStatus()
if err != nil {
return err
}
fmt.Printf("Proxy Status...\n\n")
for _, typ := range proxyTypes {
arrs := res[typ]
if len(arrs) == 0 {
continue
}
fmt.Println(strings.ToUpper(typ))
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
for _, ps := range arrs {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
}
tbl.Print()
fmt.Println("")
}
return nil
}
func StopHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
if err := client.Stop(); err != nil {
return err
}
fmt.Println("stop success")
return nil
}

125
cmd/frpc/sub/flags.go Normal file
View File

@ -0,0 +1,125 @@
// 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 sub
import (
"fmt"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
)
type BandwidthQuantityFlag struct {
V *types.BandwidthQuantity
}
func (f *BandwidthQuantityFlag) Set(s string) error {
return f.V.UnmarshalString(s)
}
func (f *BandwidthQuantityFlag) String() string {
return f.V.String()
}
func (f *BandwidthQuantityFlag) Type() string {
return "string"
}
func RegisterProxyFlags(cmd *cobra.Command, c v1.ProxyConfigurer) {
registerProxyBaseConfigFlags(cmd, c.GetBaseConfig())
switch cc := c.(type) {
case *v1.TCPProxyConfig:
cmd.Flags().IntVarP(&cc.RemotePort, "remote_port", "r", 0, "remote port")
case *v1.UDPProxyConfig:
cmd.Flags().IntVarP(&cc.RemotePort, "remote_port", "r", 0, "remote port")
case *v1.HTTPProxyConfig:
registerProxyDomainConfigFlags(cmd, &cc.DomainConfig)
cmd.Flags().StringSliceVarP(&cc.Locations, "locations", "", []string{}, "locations")
cmd.Flags().StringVarP(&cc.HTTPUser, "http_user", "", "", "http auth user")
cmd.Flags().StringVarP(&cc.HTTPPassword, "http_pwd", "", "", "http auth password")
cmd.Flags().StringVarP(&cc.HostHeaderRewrite, "host_header_rewrite", "", "", "host header rewrite")
case *v1.HTTPSProxyConfig:
registerProxyDomainConfigFlags(cmd, &cc.DomainConfig)
case *v1.TCPMuxProxyConfig:
registerProxyDomainConfigFlags(cmd, &cc.DomainConfig)
cmd.Flags().StringVarP(&cc.Multiplexer, "mux", "", "", "multiplexer")
case *v1.STCPProxyConfig:
cmd.Flags().StringVarP(&cc.Secretkey, "sk", "", "", "secret key")
case *v1.SUDPProxyConfig:
cmd.Flags().StringVarP(&cc.Secretkey, "sk", "", "", "secret key")
case *v1.XTCPProxyConfig:
cmd.Flags().StringVarP(&cc.Secretkey, "sk", "", "", "secret key")
}
}
func registerProxyBaseConfigFlags(cmd *cobra.Command, c *v1.ProxyBaseConfig) {
if c == nil {
return
}
cmd.Flags().StringVarP(&c.Name, "proxy_name", "n", "", "proxy name")
cmd.Flags().StringVarP(&c.LocalIP, "local_ip", "i", "127.0.0.1", "local ip")
cmd.Flags().IntVarP(&c.LocalPort, "local_port", "l", 0, "local port")
cmd.Flags().BoolVarP(&c.Transport.UseEncryption, "ue", "", false, "use encryption")
cmd.Flags().BoolVarP(&c.Transport.UseCompression, "uc", "", false, "use compression")
cmd.Flags().StringVarP(&c.Transport.BandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
cmd.Flags().VarP(&BandwidthQuantityFlag{V: &c.Transport.BandwidthLimit}, "bandwidth_limit", "", "bandwidth limit (e.g. 100KB or 1MB)")
}
func registerProxyDomainConfigFlags(cmd *cobra.Command, c *v1.DomainConfig) {
if c == nil {
return
}
cmd.Flags().StringSliceVarP(&c.CustomDomains, "custom_domain", "d", []string{}, "custom domains")
cmd.Flags().StringVarP(&c.SubDomain, "sd", "", "", "sub domain")
}
func RegisterVisitorFlags(cmd *cobra.Command, c v1.VisitorConfigurer) {
registerVisitorBaseConfigFlags(cmd, c.GetBaseConfig())
// add visitor flags if exist
}
func registerVisitorBaseConfigFlags(cmd *cobra.Command, c *v1.VisitorBaseConfig) {
if c == nil {
return
}
cmd.Flags().StringVarP(&c.Name, "visitor_name", "n", "", "visitor name")
cmd.Flags().BoolVarP(&c.Transport.UseEncryption, "ue", "", false, "use encryption")
cmd.Flags().BoolVarP(&c.Transport.UseCompression, "uc", "", false, "use compression")
cmd.Flags().StringVarP(&c.SecretKey, "sk", "", "", "secret key")
cmd.Flags().StringVarP(&c.ServerName, "server_name", "", "", "server name")
cmd.Flags().StringVarP(&c.BindAddr, "bind_addr", "", "", "bind addr")
cmd.Flags().IntVarP(&c.BindPort, "bind_port", "", 0, "bind port")
}
func RegisterClientCommonConfigFlags(cmd *cobra.Command, c *v1.ClientCommonConfig) {
cmd.PersistentFlags().StringVarP(&c.ServerAddr, "server_addr", "s", "127.0.0.1", "frp server's address")
cmd.PersistentFlags().IntVarP(&c.ServerPort, "server_port", "P", 7000, "frp server's port")
cmd.PersistentFlags().StringVarP(&c.User, "user", "u", "", "user")
cmd.PersistentFlags().StringVarP(&c.Transport.Protocol, "protocol", "p", "tcp",
fmt.Sprintf("optional values are %v", validation.SupportedTransportProtocols))
cmd.PersistentFlags().StringVarP(&c.Auth.Token, "token", "t", "", "auth token")
cmd.PersistentFlags().StringVarP(&c.Log.Level, "log_level", "", "info", "log level")
cmd.PersistentFlags().StringVarP(&c.Log.To, "log_file", "", "console", "console or file path")
cmd.PersistentFlags().Int64VarP(&c.Log.MaxDays, "log_max_days", "", 3, "log file reversed days")
cmd.PersistentFlags().BoolVarP(&c.Log.DisablePrintColor, "disable_log_color", "", false, "disable log color in console")
cmd.PersistentFlags().StringVarP(&c.Transport.TLS.ServerName, "tls_server_name", "", "", "specify the custom server name of tls certificate")
cmd.PersistentFlags().StringVarP(&c.DNSServer, "dns_server", "", "", "specify dns server instead of using system default one")
c.Transport.TLS.Enable = cmd.PersistentFlags().BoolP("tls_enable", "", true, "enable frpc tls")
}

View File

@ -1,96 +0,0 @@
// 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 sub
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
func init() {
RegisterCommonFlags(httpCmd)
httpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
httpCmd.PersistentFlags().StringVarP(&localIP, "local_ip", "i", "127.0.0.1", "local ip")
httpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
httpCmd.PersistentFlags().StringVarP(&customDomains, "custom_domain", "d", "", "custom domain")
httpCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain")
httpCmd.PersistentFlags().StringVarP(&locations, "locations", "", "", "locations")
httpCmd.PersistentFlags().StringVarP(&httpUser, "http_user", "", "", "http auth user")
httpCmd.PersistentFlags().StringVarP(&httpPwd, "http_pwd", "", "", "http auth password")
httpCmd.PersistentFlags().StringVarP(&hostHeaderRewrite, "host_header_rewrite", "", "", "host header rewrite")
httpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
httpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
httpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
httpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(httpCmd)
}
var httpCmd = &cobra.Command{
Use: "http",
Short: "Run frpc with a single http proxy",
RunE: func(cmd *cobra.Command, args []string) error {
clientCfg, err := parseClientCommonCfgFromCmd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg := &v1.HTTPProxyConfig{}
var prefix string
if user != "" {
prefix = user + "."
}
cfg.Name = prefix + proxyName
cfg.Type = consts.HTTPProxy
cfg.LocalIP = localIP
cfg.LocalPort = localPort
cfg.CustomDomains = strings.Split(customDomains, ",")
cfg.SubDomain = subDomain
cfg.Locations = strings.Split(locations, ",")
cfg.HTTPUser = httpUser
cfg.HTTPPassword = httpPwd
cfg.HostHeaderRewrite = hostHeaderRewrite
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.Transport.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.Transport.BandwidthLimitMode = bandwidthLimitMode
if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
err = startService(clientCfg, []v1.ProxyConfigurer{cfg}, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}

View File

@ -1,88 +0,0 @@
// 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 sub
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
func init() {
RegisterCommonFlags(httpsCmd)
httpsCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
httpsCmd.PersistentFlags().StringVarP(&localIP, "local_ip", "i", "127.0.0.1", "local ip")
httpsCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
httpsCmd.PersistentFlags().StringVarP(&customDomains, "custom_domain", "d", "", "custom domain")
httpsCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain")
httpsCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
httpsCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
httpsCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
httpsCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(httpsCmd)
}
var httpsCmd = &cobra.Command{
Use: "https",
Short: "Run frpc with a single https proxy",
RunE: func(cmd *cobra.Command, args []string) error {
clientCfg, err := parseClientCommonCfgFromCmd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg := &v1.HTTPSProxyConfig{}
var prefix string
if user != "" {
prefix = user + "."
}
cfg.Name = prefix + proxyName
cfg.Type = consts.HTTPSProxy
cfg.LocalIP = localIP
cfg.LocalPort = localPort
cfg.CustomDomains = strings.Split(customDomains, ",")
cfg.SubDomain = subDomain
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.Transport.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.Transport.BandwidthLimitMode = bandwidthLimitMode
if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
err = startService(clientCfg, []v1.ProxyConfigurer{cfg}, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}

View File

@ -31,8 +31,6 @@ var (
)
func init() {
RegisterCommonFlags(natholeCmd)
rootCmd.AddCommand(natholeCmd)
natholeCmd.AddCommand(natholeDiscoveryCmd)

121
cmd/frpc/sub/proxy.go Normal file
View File

@ -0,0 +1,121 @@
// 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 sub
import (
"fmt"
"os"
"github.com/samber/lo"
"github.com/spf13/cobra"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
var proxyTypes = []string{
consts.TCPProxy,
consts.UDPProxy,
consts.TCPMuxProxy,
consts.HTTPProxy,
consts.HTTPSProxy,
consts.STCPProxy,
consts.SUDPProxy,
consts.XTCPProxy,
}
var visitorTypes = []string{
consts.STCPProxy,
consts.SUDPProxy,
consts.XTCPProxy,
}
func init() {
for _, typ := range proxyTypes {
c := v1.NewProxyConfigurerByType(typ)
if c == nil {
panic("proxy type: " + typ + " not support")
}
clientCfg := v1.ClientCommonConfig{}
cmd := NewProxyCommand(typ, c, &clientCfg)
RegisterClientCommonConfigFlags(cmd, &clientCfg)
RegisterProxyFlags(cmd, c)
// add sub command for visitor
if lo.Contains(visitorTypes, typ) {
vc := v1.NewVisitorConfigurerByType(typ)
if vc == nil {
panic("visitor type: " + typ + " not support")
}
visitorCmd := NewVisitorCommand(typ, vc, &clientCfg)
RegisterVisitorFlags(visitorCmd, vc)
cmd.AddCommand(visitorCmd)
}
rootCmd.AddCommand(cmd)
}
}
func NewProxyCommand(name string, c v1.ProxyConfigurer, clientCfg *v1.ClientCommonConfig) *cobra.Command {
return &cobra.Command{
Use: name,
Short: fmt.Sprintf("Run frpc with a single %s proxy", name),
Run: func(cmd *cobra.Command, args []string) {
clientCfg.Complete()
if _, err := validation.ValidateClientCommonConfig(clientCfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
c.Complete(clientCfg.User)
c.GetBaseConfig().Type = name
if err := validation.ValidateProxyConfigurerForClient(c); err != nil {
fmt.Println(err)
os.Exit(1)
}
err := startService(clientCfg, []v1.ProxyConfigurer{c}, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
},
}
}
func NewVisitorCommand(name string, c v1.VisitorConfigurer, clientCfg *v1.ClientCommonConfig) *cobra.Command {
return &cobra.Command{
Use: "visitor",
Short: fmt.Sprintf("Run frpc with a single %s visitor", name),
Run: func(cmd *cobra.Command, args []string) {
clientCfg.Complete()
if _, err := validation.ValidateClientCommonConfig(clientCfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
c.Complete(clientCfg)
c.GetBaseConfig().Type = name
if err := validation.ValidateVisitorConfigurer(c); err != nil {
fmt.Println(err)
os.Exit(1)
}
err := startService(clientCfg, nil, []v1.VisitorConfigurer{c}, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
},
}
}

View File

@ -1,86 +0,0 @@
// 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 sub
import (
"encoding/base64"
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config"
v1 "github.com/fatedier/frp/pkg/config/v1"
)
func init() {
rootCmd.AddCommand(reloadCmd)
}
var reloadCmd = &cobra.Command{
Use: "reload",
Short: "Hot-Reload frpc configuration",
RunE: func(cmd *cobra.Command, args []string) error {
cfg, _, _, _, err := config.LoadClientConfig(cfgFile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = reload(cfg)
if err != nil {
fmt.Printf("frpc reload error: %v\n", err)
os.Exit(1)
}
fmt.Printf("reload success\n")
return nil
},
}
func reload(clientCfg *v1.ClientCommonConfig) error {
if clientCfg.WebServer.Port == 0 {
return fmt.Errorf("the port of web server shoud be set if you want to use reload feature")
}
req, err := http.NewRequest("GET", "http://"+
clientCfg.WebServer.Addr+":"+
fmt.Sprintf("%d", clientCfg.WebServer.Port)+"/api/reload", nil)
if err != nil {
return err
}
authStr := "Basic " + base64.StdEncoding.EncodeToString(
[]byte(clientCfg.WebServer.User+":"+clientCfg.WebServer.Password))
req.Header.Add("Authorization", authStr)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
return nil
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("code [%d], %s", resp.StatusCode, strings.TrimSpace(string(body)))
}

View File

@ -18,16 +18,13 @@ import (
"context"
"fmt"
"io/fs"
"net"
"os"
"os/signal"
"path/filepath"
"strconv"
"sync"
"syscall"
"time"
"github.com/samber/lo"
"github.com/spf13/cobra"
"github.com/fatedier/frp/client"
@ -42,40 +39,6 @@ var (
cfgFile string
cfgDir string
showVersion bool
serverAddr string
user string
protocol string
token string
logLevel string
logFile string
logMaxDays int
disableLogColor bool
dnsServer string
proxyName string
localIP string
localPort int
remotePort int
useEncryption bool
useCompression bool
bandwidthLimit string
bandwidthLimitMode string
customDomains string
subDomain string
httpUser string
httpPwd string
locations string
hostHeaderRewrite string
role string
sk string
multiplexer string
serverName string
bindAddr string
bindPort int
tlsEnable bool
tlsServerName string
)
func init() {
@ -84,20 +47,6 @@ func init() {
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
}
func RegisterCommonFlags(cmd *cobra.Command) {
cmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
cmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
cmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp, kcp, quic, websocket, wss")
cmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
cmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
cmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
cmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
cmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
cmd.PersistentFlags().BoolVarP(&tlsEnable, "tls_enable", "", true, "enable frpc tls")
cmd.PersistentFlags().StringVarP(&tlsServerName, "tls_server_name", "", "", "specify the custom server name of tls certificate")
cmd.PersistentFlags().StringVarP(&dnsServer, "dns_server", "", "", "specify dns server instead of using system default one")
}
var rootCmd = &cobra.Command{
Use: "frpc",
Short: "frpc is the client of frp (https://github.com/fatedier/frp)",
@ -158,45 +107,6 @@ func handleTermSignal(svr *client.Service) {
svr.GracefulClose(500 * time.Millisecond)
}
func parseClientCommonCfgFromCmd() (*v1.ClientCommonConfig, error) {
cfg := &v1.ClientCommonConfig{}
ipStr, portStr, err := net.SplitHostPort(serverAddr)
if err != nil {
return nil, fmt.Errorf("invalid server_addr: %v", err)
}
cfg.ServerAddr = ipStr
cfg.ServerPort, err = strconv.Atoi(portStr)
if err != nil {
return nil, fmt.Errorf("invalid server_addr: %v", err)
}
cfg.User = user
cfg.Transport.Protocol = protocol
cfg.Log.Level = logLevel
cfg.Log.To = logFile
cfg.Log.MaxDays = int64(logMaxDays)
cfg.Log.DisablePrintColor = disableLogColor
cfg.DNSServer = dnsServer
// Only token authentication is supported in cmd mode
cfg.Auth.Token = token
cfg.Transport.TLS.Enable = lo.ToPtr(tlsEnable)
cfg.Transport.TLS.ServerName = tlsServerName
cfg.Complete()
warning, err := validation.ValidateClientCommonConfig(cfg)
if warning != nil {
fmt.Printf("WARNING: %v\n", warning)
}
if err != nil {
return nil, fmt.Errorf("parse config error: %v", err)
}
return cfg, nil
}
func runClient(cfgFilePath string) error {
cfg, pxyCfgs, visitorCfgs, isLegacyFormat, err := config.LoadClientConfig(cfgFilePath)
if err != nil {

View File

@ -1,108 +0,0 @@
// 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 sub
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/rodaine/table"
"github.com/spf13/cobra"
"github.com/fatedier/frp/client"
"github.com/fatedier/frp/pkg/config"
v1 "github.com/fatedier/frp/pkg/config/v1"
)
func init() {
rootCmd.AddCommand(statusCmd)
}
var statusCmd = &cobra.Command{
Use: "status",
Short: "Overview of all proxies status",
RunE: func(cmd *cobra.Command, args []string) error {
cfg, _, _, _, err := config.LoadClientConfig(cfgFile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if err = status(cfg); err != nil {
fmt.Printf("frpc get status error: %v\n", err)
os.Exit(1)
}
return nil
},
}
func status(clientCfg *v1.ClientCommonConfig) error {
if clientCfg.WebServer.Port == 0 {
return fmt.Errorf("the port of web server shoud be set if you want to get proxy status")
}
req, err := http.NewRequest("GET", "http://"+
clientCfg.WebServer.Addr+":"+fmt.Sprintf("%d", clientCfg.WebServer.Port)+"/api/status", nil)
if err != nil {
return err
}
authStr := "Basic " + base64.StdEncoding.EncodeToString(
[]byte(clientCfg.WebServer.User+":"+clientCfg.WebServer.Password))
req.Header.Add("Authorization", authStr)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("admin api status code [%d]", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
res := make(client.StatusResp)
err = json.Unmarshal(body, &res)
if err != nil {
return fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(string(body)))
}
fmt.Println("Proxy Status...")
types := []string{"tcp", "udp", "tcpmux", "http", "https", "stcp", "sudp", "xtcp"}
for _, pxyType := range types {
arrs := res[pxyType]
if len(arrs) == 0 {
continue
}
fmt.Println(strings.ToUpper(pxyType))
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
for _, ps := range arrs {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
}
tbl.Print()
fmt.Println("")
}
return nil
}

View File

@ -1,114 +0,0 @@
// 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 sub
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
func init() {
RegisterCommonFlags(stcpCmd)
stcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
stcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
stcpCmd.PersistentFlags().StringVarP(&sk, "sk", "", "", "secret key")
stcpCmd.PersistentFlags().StringVarP(&serverName, "server_name", "", "", "server name")
stcpCmd.PersistentFlags().StringVarP(&localIP, "local_ip", "i", "127.0.0.1", "local ip")
stcpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
stcpCmd.PersistentFlags().StringVarP(&bindAddr, "bind_addr", "", "", "bind addr")
stcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
stcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
stcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
stcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
stcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(stcpCmd)
}
var stcpCmd = &cobra.Command{
Use: "stcp",
Short: "Run frpc with a single stcp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
clientCfg, err := parseClientCommonCfgFromCmd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
pxyCfgs := make([]v1.ProxyConfigurer, 0)
visitorCfgs := make([]v1.VisitorConfigurer, 0)
var prefix string
if user != "" {
prefix = user + "."
}
switch role {
case "server":
cfg := &v1.STCPProxyConfig{}
cfg.Name = prefix + proxyName
cfg.Type = consts.STCPProxy
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.Secretkey = sk
cfg.LocalIP = localIP
cfg.LocalPort = localPort
cfg.Transport.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.Transport.BandwidthLimitMode = bandwidthLimitMode
if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
pxyCfgs = append(pxyCfgs, cfg)
case "visitor":
cfg := &v1.STCPVisitorConfig{}
cfg.Name = prefix + proxyName
cfg.Type = consts.STCPProxy
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.SecretKey = sk
cfg.ServerName = serverName
cfg.BindAddr = bindAddr
cfg.BindPort = bindPort
if err := validation.ValidateVisitorConfigurer(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
visitorCfgs = append(visitorCfgs, cfg)
default:
fmt.Println("invalid role")
os.Exit(1)
}
err = startService(clientCfg, pxyCfgs, visitorCfgs, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}

View File

@ -1,86 +0,0 @@
// 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 sub
import (
"encoding/base64"
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config"
v1 "github.com/fatedier/frp/pkg/config/v1"
)
func init() {
rootCmd.AddCommand(stopCmd)
}
var stopCmd = &cobra.Command{
Use: "stop",
Short: "Stop the running frpc",
RunE: func(cmd *cobra.Command, args []string) error {
cfg, _, _, _, err := config.LoadClientConfig(cfgFile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = stopClient(cfg)
if err != nil {
fmt.Printf("frpc stop error: %v\n", err)
os.Exit(1)
}
fmt.Printf("stop success\n")
return nil
},
}
func stopClient(clientCfg *v1.ClientCommonConfig) error {
if clientCfg.WebServer.Port == 0 {
return fmt.Errorf("the port of web server shoud be set if you want to use stop feature")
}
req, err := http.NewRequest("POST", "http://"+
clientCfg.WebServer.Addr+":"+
fmt.Sprintf("%d", clientCfg.WebServer.Port)+"/api/stop", nil)
if err != nil {
return err
}
authStr := "Basic " + base64.StdEncoding.EncodeToString(
[]byte(clientCfg.WebServer.User+":"+clientCfg.WebServer.Password))
req.Header.Add("Authorization", authStr)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
return nil
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("code [%d], %s", resp.StatusCode, strings.TrimSpace(string(body)))
}

View File

@ -1,113 +0,0 @@
// 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 sub
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
func init() {
RegisterCommonFlags(sudpCmd)
sudpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
sudpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
sudpCmd.PersistentFlags().StringVarP(&sk, "sk", "", "", "secret key")
sudpCmd.PersistentFlags().StringVarP(&serverName, "server_name", "", "", "server name")
sudpCmd.PersistentFlags().StringVarP(&localIP, "local_ip", "i", "127.0.0.1", "local ip")
sudpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
sudpCmd.PersistentFlags().StringVarP(&bindAddr, "bind_addr", "", "", "bind addr")
sudpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
sudpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
sudpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
sudpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
sudpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(sudpCmd)
}
var sudpCmd = &cobra.Command{
Use: "sudp",
Short: "Run frpc with a single sudp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
clientCfg, err := parseClientCommonCfgFromCmd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
pxyCfgs := make([]v1.ProxyConfigurer, 0)
visitorCfgs := make([]v1.VisitorConfigurer, 0)
var prefix string
if user != "" {
prefix = user + "."
}
switch role {
case "server":
cfg := &v1.SUDPProxyConfig{}
cfg.Name = prefix + proxyName
cfg.Type = consts.SUDPProxy
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.Secretkey = sk
cfg.LocalIP = localIP
cfg.LocalPort = localPort
cfg.Transport.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.Transport.BandwidthLimitMode = bandwidthLimitMode
if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
pxyCfgs = append(pxyCfgs, cfg)
case "visitor":
cfg := &v1.SUDPVisitorConfig{}
cfg.Name = prefix + proxyName
cfg.Type = consts.SUDPProxy
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.SecretKey = sk
cfg.ServerName = serverName
cfg.BindAddr = bindAddr
cfg.BindPort = bindPort
if err := validation.ValidateVisitorConfigurer(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
visitorCfgs = append(visitorCfgs, cfg)
default:
fmt.Println("invalid role")
os.Exit(1)
}
err = startService(clientCfg, pxyCfgs, visitorCfgs, "")
if err != nil {
os.Exit(1)
}
return nil
},
}

View File

@ -1,84 +0,0 @@
// 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 sub
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
func init() {
RegisterCommonFlags(tcpCmd)
tcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
tcpCmd.PersistentFlags().StringVarP(&localIP, "local_ip", "i", "127.0.0.1", "local ip")
tcpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
tcpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port")
tcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
tcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
tcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
tcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(tcpCmd)
}
var tcpCmd = &cobra.Command{
Use: "tcp",
Short: "Run frpc with a single tcp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
clientCfg, err := parseClientCommonCfgFromCmd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg := &v1.TCPProxyConfig{}
var prefix string
if user != "" {
prefix = user + "."
}
cfg.Name = prefix + proxyName
cfg.Type = consts.TCPProxy
cfg.LocalIP = localIP
cfg.LocalPort = localPort
cfg.RemotePort = remotePort
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.Transport.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.Transport.BandwidthLimitMode = bandwidthLimitMode
if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
err = startService(clientCfg, []v1.ProxyConfigurer{cfg}, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}

View File

@ -1,90 +0,0 @@
// Copyright 2020 guylewin, guy@lewin.co.il
//
// 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 sub
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
func init() {
RegisterCommonFlags(tcpMuxCmd)
tcpMuxCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
tcpMuxCmd.PersistentFlags().StringVarP(&localIP, "local_ip", "i", "127.0.0.1", "local ip")
tcpMuxCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
tcpMuxCmd.PersistentFlags().StringVarP(&customDomains, "custom_domain", "d", "", "custom domain")
tcpMuxCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain")
tcpMuxCmd.PersistentFlags().StringVarP(&multiplexer, "mux", "", "", "multiplexer")
tcpMuxCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
tcpMuxCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
tcpMuxCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
tcpMuxCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(tcpMuxCmd)
}
var tcpMuxCmd = &cobra.Command{
Use: "tcpmux",
Short: "Run frpc with a single tcpmux proxy",
RunE: func(cmd *cobra.Command, args []string) error {
clientCfg, err := parseClientCommonCfgFromCmd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg := &v1.TCPMuxProxyConfig{}
var prefix string
if user != "" {
prefix = user + "."
}
cfg.Name = prefix + proxyName
cfg.Type = consts.TCPMuxProxy
cfg.LocalIP = localIP
cfg.LocalPort = localPort
cfg.CustomDomains = strings.Split(customDomains, ",")
cfg.SubDomain = subDomain
cfg.Multiplexer = multiplexer
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.Transport.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.Transport.BandwidthLimitMode = bandwidthLimitMode
if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
err = startService(clientCfg, []v1.ProxyConfigurer{cfg}, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}

View File

@ -1,85 +0,0 @@
// 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 sub
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
func init() {
RegisterCommonFlags(udpCmd)
udpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
udpCmd.PersistentFlags().StringVarP(&localIP, "local_ip", "i", "127.0.0.1", "local ip")
udpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
udpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port")
udpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
udpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
udpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
udpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(udpCmd)
}
var udpCmd = &cobra.Command{
Use: "udp",
Short: "Run frpc with a single udp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
clientCfg, err := parseClientCommonCfgFromCmd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg := &v1.UDPProxyConfig{}
var prefix string
if user != "" {
prefix = user + "."
}
cfg.Name = prefix + proxyName
cfg.Type = consts.UDPProxy
cfg.LocalIP = localIP
cfg.LocalPort = localPort
cfg.RemotePort = remotePort
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.Transport.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.Transport.BandwidthLimitMode = bandwidthLimitMode
if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
err = startService(clientCfg, []v1.ProxyConfigurer{cfg}, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}

View File

@ -1,116 +0,0 @@
// 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 sub
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/consts"
)
func init() {
RegisterCommonFlags(xtcpCmd)
xtcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
xtcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
xtcpCmd.PersistentFlags().StringVarP(&sk, "sk", "", "", "secret key")
xtcpCmd.PersistentFlags().StringVarP(&serverName, "server_name", "", "", "server name")
xtcpCmd.PersistentFlags().StringVarP(&localIP, "local_ip", "i", "127.0.0.1", "local ip")
xtcpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
xtcpCmd.PersistentFlags().StringVarP(&bindAddr, "bind_addr", "", "", "bind addr")
xtcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
xtcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
xtcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
xtcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
xtcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", types.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(xtcpCmd)
}
var xtcpCmd = &cobra.Command{
Use: "xtcp",
Short: "Run frpc with a single xtcp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
clientCfg, err := parseClientCommonCfgFromCmd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
pxyCfgs := make([]v1.ProxyConfigurer, 0)
visitorCfgs := make([]v1.VisitorConfigurer, 0)
var prefix string
if user != "" {
prefix = user + "."
}
switch role {
case "server":
cfg := &v1.XTCPProxyConfig{}
cfg.Name = prefix + proxyName
cfg.Type = consts.XTCPProxy
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.Secretkey = sk
cfg.LocalIP = localIP
cfg.LocalPort = localPort
cfg.Transport.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.Transport.BandwidthLimitMode = bandwidthLimitMode
if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
pxyCfgs = append(pxyCfgs, cfg)
case "visitor":
cfg := &v1.XTCPVisitorConfig{}
cfg.Name = prefix + proxyName
cfg.Type = consts.XTCPProxy
cfg.Transport.UseEncryption = useEncryption
cfg.Transport.UseCompression = useCompression
cfg.SecretKey = sk
cfg.ServerName = serverName
cfg.BindAddr = bindAddr
cfg.BindPort = bindPort
if err := validation.ValidateVisitorConfigurer(cfg); err != nil {
fmt.Println(err)
os.Exit(1)
}
visitorCfgs = append(visitorCfgs, cfg)
default:
fmt.Println("invalid role")
os.Exit(1)
}
err = startService(clientCfg, pxyCfgs, visitorCfgs, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}

110
cmd/frps/flags.go Normal file
View File

@ -0,0 +1,110 @@
// 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 main
import (
"strconv"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
)
type PortsRangeSliceFlag struct {
V *[]types.PortsRange
}
func (f *PortsRangeSliceFlag) String() string {
if f.V == nil {
return ""
}
return types.PortsRangeSlice(*f.V).String()
}
func (f *PortsRangeSliceFlag) Set(s string) error {
slice, err := types.NewPortsRangeSliceFromString(s)
if err != nil {
return err
}
*f.V = slice
return nil
}
func (f *PortsRangeSliceFlag) Type() string {
return "string"
}
type BoolFuncFlag struct {
TrueFunc func()
FalseFunc func()
v bool
}
func (f *BoolFuncFlag) String() string {
return strconv.FormatBool(f.v)
}
func (f *BoolFuncFlag) Set(s string) error {
f.v = strconv.FormatBool(f.v) == "true"
if !f.v {
if f.FalseFunc != nil {
f.FalseFunc()
}
return nil
}
if f.TrueFunc != nil {
f.TrueFunc()
}
return nil
}
func (f *BoolFuncFlag) Type() string {
return "bool"
}
func RegisterServerConfigFlags(cmd *cobra.Command, c *v1.ServerConfig) {
cmd.PersistentFlags().StringVarP(&c.BindAddr, "bind_addr", "", "0.0.0.0", "bind address")
cmd.PersistentFlags().IntVarP(&c.BindPort, "bind_port", "p", 7000, "bind port")
cmd.PersistentFlags().IntVarP(&c.KCPBindPort, "kcp_bind_port", "", 0, "kcp bind udp port")
cmd.PersistentFlags().StringVarP(&c.ProxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address")
cmd.PersistentFlags().IntVarP(&c.VhostHTTPPort, "vhost_http_port", "", 0, "vhost http port")
cmd.PersistentFlags().IntVarP(&c.VhostHTTPSPort, "vhost_https_port", "", 0, "vhost https port")
cmd.PersistentFlags().Int64VarP(&c.VhostHTTPTimeout, "vhost_http_timeout", "", 60, "vhost http response header timeout")
cmd.PersistentFlags().StringVarP(&c.WebServer.Addr, "dashboard_addr", "", "0.0.0.0", "dashboard address")
cmd.PersistentFlags().IntVarP(&c.WebServer.Port, "dashboard_port", "", 0, "dashboard port")
cmd.PersistentFlags().StringVarP(&c.WebServer.User, "dashboard_user", "", "admin", "dashboard user")
cmd.PersistentFlags().StringVarP(&c.WebServer.Password, "dashboard_pwd", "", "admin", "dashboard password")
cmd.PersistentFlags().BoolVarP(&c.EnablePrometheus, "enable_prometheus", "", false, "enable prometheus dashboard")
cmd.PersistentFlags().StringVarP(&c.Log.To, "log_file", "", "console", "log file")
cmd.PersistentFlags().StringVarP(&c.Log.Level, "log_level", "", "info", "log level")
cmd.PersistentFlags().Int64VarP(&c.Log.MaxDays, "log_max_days", "", 3, "log max days")
cmd.PersistentFlags().BoolVarP(&c.Log.DisablePrintColor, "disable_log_color", "", false, "disable log color in console")
cmd.PersistentFlags().StringVarP(&c.Auth.Token, "token", "t", "", "auth token")
cmd.PersistentFlags().StringVarP(&c.SubDomainHost, "subdomain_host", "", "", "subdomain host")
cmd.PersistentFlags().VarP(&PortsRangeSliceFlag{V: &c.AllowPorts}, "allow_ports", "", "allow ports")
cmd.PersistentFlags().Int64VarP(&c.MaxPortsPerClient, "max_ports_per_client", "", 0, "max ports per client")
cmd.PersistentFlags().BoolVarP(&c.Transport.TLS.Force, "tls_only", "", false, "frps tls only")
webServerTLS := v1.TLSConfig{}
cmd.PersistentFlags().StringVarP(&webServerTLS.CertFile, "dashboard_tls_cert_file", "", "", "dashboard tls cert file")
cmd.PersistentFlags().StringVarP(&webServerTLS.KeyFile, "dashboard_tls_key_file", "", "", "dashboard tls key file")
cmd.PersistentFlags().VarP(&BoolFuncFlag{
TrueFunc: func() { c.WebServer.TLS = &webServerTLS },
}, "dashboard_tls_mode", "", "if enable dashboard tls mode")
}

View File

@ -22,7 +22,6 @@ import (
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
"github.com/fatedier/frp/pkg/util/log"
@ -34,61 +33,14 @@ var (
cfgFile string
showVersion bool
bindAddr string
bindPort int
kcpBindPort int
proxyBindAddr string
vhostHTTPPort int
vhostHTTPSPort int
vhostHTTPTimeout int64
dashboardAddr string
dashboardPort int
dashboardUser string
dashboardPwd string
enablePrometheus bool
logFile string
logLevel string
logMaxDays int64
disableLogColor bool
token string
subDomainHost string
allowPorts string
maxPortsPerClient int64
tlsOnly bool
dashboardTLSMode bool
dashboardTLSCertFile string
dashboardTLSKeyFile string
serverCfg v1.ServerConfig
)
func init() {
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file of frps")
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frps")
rootCmd.PersistentFlags().StringVarP(&bindAddr, "bind_addr", "", "0.0.0.0", "bind address")
rootCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "p", 7000, "bind port")
rootCmd.PersistentFlags().IntVarP(&kcpBindPort, "kcp_bind_port", "", 0, "kcp bind udp port")
rootCmd.PersistentFlags().StringVarP(&proxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address")
rootCmd.PersistentFlags().IntVarP(&vhostHTTPPort, "vhost_http_port", "", 0, "vhost http port")
rootCmd.PersistentFlags().IntVarP(&vhostHTTPSPort, "vhost_https_port", "", 0, "vhost https port")
rootCmd.PersistentFlags().Int64VarP(&vhostHTTPTimeout, "vhost_http_timeout", "", 60, "vhost http response header timeout")
rootCmd.PersistentFlags().StringVarP(&dashboardAddr, "dashboard_addr", "", "0.0.0.0", "dashboard address")
rootCmd.PersistentFlags().IntVarP(&dashboardPort, "dashboard_port", "", 0, "dashboard port")
rootCmd.PersistentFlags().StringVarP(&dashboardUser, "dashboard_user", "", "admin", "dashboard user")
rootCmd.PersistentFlags().StringVarP(&dashboardPwd, "dashboard_pwd", "", "admin", "dashboard password")
rootCmd.PersistentFlags().BoolVarP(&enablePrometheus, "enable_prometheus", "", false, "enable prometheus dashboard")
rootCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "log file")
rootCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
rootCmd.PersistentFlags().Int64VarP(&logMaxDays, "log_max_days", "", 3, "log max days")
rootCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
rootCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
rootCmd.PersistentFlags().StringVarP(&subDomainHost, "subdomain_host", "", "", "subdomain host")
rootCmd.PersistentFlags().StringVarP(&allowPorts, "allow_ports", "", "", "allow ports")
rootCmd.PersistentFlags().Int64VarP(&maxPortsPerClient, "max_ports_per_client", "", 0, "max ports per client")
rootCmd.PersistentFlags().BoolVarP(&tlsOnly, "tls_only", "", false, "frps tls only")
rootCmd.PersistentFlags().BoolVarP(&dashboardTLSMode, "dashboard_tls_mode", "", false, "dashboard tls mode")
rootCmd.PersistentFlags().StringVarP(&dashboardTLSCertFile, "dashboard_tls_cert_file", "", "", "dashboard tls cert file")
rootCmd.PersistentFlags().StringVarP(&dashboardTLSKeyFile, "dashboard_tls_key_file", "", "", "dashboard tls key file")
RegisterServerConfigFlags(rootCmd, &serverCfg)
}
var rootCmd = &cobra.Command{
@ -116,10 +68,8 @@ var rootCmd = &cobra.Command{
"please use yaml/json/toml format instead!\n")
}
} else {
if svrCfg, err = parseServerConfigFromCmd(); err != nil {
fmt.Println(err)
os.Exit(1)
}
serverCfg.Complete()
svrCfg = &serverCfg
}
warning, err := validation.ValidateServerConfig(svrCfg)
@ -145,50 +95,6 @@ func Execute() {
}
}
func parseServerConfigFromCmd() (*v1.ServerConfig, error) {
cfg := &v1.ServerConfig{}
cfg.BindAddr = bindAddr
cfg.BindPort = bindPort
cfg.KCPBindPort = kcpBindPort
cfg.ProxyBindAddr = proxyBindAddr
cfg.VhostHTTPPort = vhostHTTPPort
cfg.VhostHTTPSPort = vhostHTTPSPort
cfg.VhostHTTPTimeout = vhostHTTPTimeout
cfg.WebServer.Addr = dashboardAddr
cfg.WebServer.Port = dashboardPort
cfg.WebServer.User = dashboardUser
cfg.WebServer.Password = dashboardPwd
cfg.EnablePrometheus = enablePrometheus
if dashboardTLSMode {
cfg.WebServer.TLS = &v1.TLSConfig{
CertFile: dashboardTLSCertFile,
KeyFile: dashboardTLSKeyFile,
}
}
cfg.Log.To = logFile
cfg.Log.Level = logLevel
cfg.Log.MaxDays = logMaxDays
cfg.Log.DisablePrintColor = disableLogColor
cfg.SubDomainHost = subDomainHost
cfg.Transport.TLS.Force = tlsOnly
cfg.MaxPortsPerClient = maxPortsPerClient
// Only token authentication is supported in cmd mode
cfg.Auth.Token = token
if len(allowPorts) > 0 {
portsRanges, err := types.NewPortsRangeSliceFromString(allowPorts)
if err != nil {
return cfg, fmt.Errorf("allow_ports format error: %v", err)
}
cfg.AllowPorts = portsRanges
}
cfg.Complete()
return cfg, nil
}
func runServer(cfg *v1.ServerConfig) (err error) {
log.InitLog(cfg.Log.To, cfg.Log.Level, cfg.Log.MaxDays, cfg.Log.DisablePrintColor)

View File

@ -134,6 +134,9 @@ type PortsRange struct {
type PortsRangeSlice []PortsRange
func (p PortsRangeSlice) String() string {
if len(p) == 0 {
return ""
}
strs := []string{}
for _, v := range p {
if v.Single > 0 {

View File

@ -29,11 +29,11 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig) (Warning, error) {
warnings Warning
errs error
)
if !lo.Contains(supportedAuthMethods, c.Auth.Method) {
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", supportedAuthMethods))
if !lo.Contains(SupportedAuthMethods, c.Auth.Method) {
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods))
}
if !lo.Every(supportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {
errs = AppendError(errs, fmt.Errorf("invalid auth additional scopes, optional values are %v", supportedAuthAdditionalScopes))
if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {
errs = AppendError(errs, fmt.Errorf("invalid auth additional scopes, optional values are %v", SupportedAuthAdditionalScopes))
}
if err := validateLogConfig(&c.Log); err != nil {
@ -63,8 +63,8 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig) (Warning, error) {
warnings = AppendError(warnings, checkTLSConfig("transport.tls.trustedCaFile", c.Transport.TLS.TrustedCaFile))
}
if !lo.Contains(supportedTransportProtocols, c.Transport.Protocol) {
errs = AppendError(errs, fmt.Errorf("invalid transport.protocol, optional values are %v", supportedTransportProtocols))
if !lo.Contains(SupportedTransportProtocols, c.Transport.Protocol) {
errs = AppendError(errs, fmt.Errorf("invalid transport.protocol, optional values are %v", SupportedTransportProtocols))
}
for _, f := range c.IncludeConfigFiles {

View File

@ -44,8 +44,8 @@ func ValidatePort(port int, fieldPath string) error {
}
func validateLogConfig(c *v1.LogConfig) error {
if !lo.Contains(supportedLogLevels, c.Level) {
return fmt.Errorf("invalid log level, optional values are %v", supportedLogLevels)
if !lo.Contains(SupportedLogLevels, c.Level) {
return fmt.Errorf("invalid log level, optional values are %v", SupportedLogLevels)
}
return nil
}

View File

@ -27,11 +27,11 @@ func ValidateServerConfig(c *v1.ServerConfig) (Warning, error) {
warnings Warning
errs error
)
if !lo.Contains(supportedAuthMethods, c.Auth.Method) {
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", supportedAuthMethods))
if !lo.Contains(SupportedAuthMethods, c.Auth.Method) {
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods))
}
if !lo.Every(supportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {
errs = AppendError(errs, fmt.Errorf("invalid auth additional scopes, optional values are %v", supportedAuthAdditionalScopes))
if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {
errs = AppendError(errs, fmt.Errorf("invalid auth additional scopes, optional values are %v", SupportedAuthAdditionalScopes))
}
if err := validateLogConfig(&c.Log); err != nil {
@ -50,8 +50,8 @@ func ValidateServerConfig(c *v1.ServerConfig) (Warning, error) {
errs = AppendError(errs, ValidatePort(c.TCPMuxHTTPConnectPort, "tcpMuxHTTPConnectPort"))
for _, p := range c.HTTPPlugins {
if !lo.Every(supportedHTTPPluginOps, p.Ops) {
errs = AppendError(errs, fmt.Errorf("invalid http plugin ops, optional values are %v", supportedHTTPPluginOps))
if !lo.Every(SupportedHTTPPluginOps, p.Ops) {
errs = AppendError(errs, fmt.Errorf("invalid http plugin ops, optional values are %v", SupportedHTTPPluginOps))
}
}
return warnings, errs

View File

@ -22,7 +22,7 @@ import (
)
var (
supportedTransportProtocols = []string{
SupportedTransportProtocols = []string{
"tcp",
"kcp",
"quic",
@ -30,17 +30,17 @@ var (
"wss",
}
supportedAuthMethods = []string{
SupportedAuthMethods = []string{
"token",
"oidc",
}
supportedAuthAdditionalScopes = []v1.AuthScope{
SupportedAuthAdditionalScopes = []v1.AuthScope{
"HeartBeats",
"NewWorkConns",
}
supportedLogLevels = []string{
SupportedLogLevels = []string{
"trace",
"debug",
"info",
@ -48,7 +48,7 @@ var (
"error",
}
supportedHTTPPluginOps = []string{
SupportedHTTPPluginOps = []string{
splugin.OpLogin,
splugin.OpNewProxy,
splugin.OpCloseProxy,

View File

@ -42,7 +42,11 @@ func ValidateVisitorConfigurer(c v1.VisitorConfigurer) error {
func validateVisitorBaseConfig(c *v1.VisitorBaseConfig) error {
if c.Name == "" {
return errors.New("name should not be empty")
return errors.New("name is required")
}
if c.ServerName == "" {
return errors.New("server name is required")
}
if c.BindPort == 0 {

View File

@ -10,7 +10,7 @@ import (
"strings"
"github.com/fatedier/frp/client"
"github.com/fatedier/frp/test/e2e/pkg/utils"
"github.com/fatedier/frp/pkg/util/util"
)
type Client struct {
@ -53,6 +53,22 @@ func (c *Client) GetProxyStatus(name string) (*client.ProxyStatusResp, error) {
return nil, fmt.Errorf("no proxy status found")
}
func (c *Client) GetAllProxyStatus() (client.StatusResp, error) {
req, err := http.NewRequest("GET", "http://"+c.address+"/api/status", nil)
if err != nil {
return nil, err
}
content, err := c.do(req)
if err != nil {
return nil, err
}
allStatus := make(client.StatusResp)
if err = json.Unmarshal([]byte(content), &allStatus); err != nil {
return nil, fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(content))
}
return allStatus, nil
}
func (c *Client) Reload() error {
req, err := http.NewRequest("GET", "http://"+c.address+"/api/reload", nil)
if err != nil {
@ -90,7 +106,7 @@ func (c *Client) UpdateConfig(content string) error {
func (c *Client) setAuthHeader(req *http.Request) {
if c.authUser != "" || c.authPwd != "" {
req.Header.Set("Authorization", utils.BasicAuth(c.authUser, c.authPwd))
req.Header.Set("Authorization", util.BasicAuth(c.authUser, c.authPwd))
}
}

View File

@ -95,3 +95,8 @@ func ParseBasicAuth(auth string) (username, password string, ok bool) {
}
return cs[:s], cs[s+1:], true
}
func BasicAuth(username, passwd string) string {
auth := username + ":" + passwd
return "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
}

View File

@ -8,10 +8,10 @@ import (
"github.com/onsi/ginkgo/v2"
clientsdk "github.com/fatedier/frp/pkg/sdk/client"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/request"
clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client"
)
var _ = ginkgo.Describe("[Feature: ClientManage]", func() {

View File

@ -1,7 +1,6 @@
package basic
import (
"fmt"
"strconv"
"strings"
@ -70,7 +69,7 @@ var _ = ginkgo.Describe("[Feature: Cmd]", func() {
localPort := f.PortByName(framework.TCPEchoServerPort)
remotePort := f.AllocPort()
_, _, err = f.RunFrpc("tcp", "-s", fmt.Sprintf("127.0.0.1:%d", serverPort), "-t", "123", "-u", "test",
_, _, err = f.RunFrpc("tcp", "-s", "127.0.0.1", "-P", strconv.Itoa(serverPort), "-t", "123", "-u", "test",
"-l", strconv.Itoa(localPort), "-r", strconv.Itoa(remotePort), "-n", "tcp_test")
framework.ExpectNoError(err)
@ -84,7 +83,7 @@ var _ = ginkgo.Describe("[Feature: Cmd]", func() {
localPort := f.PortByName(framework.UDPEchoServerPort)
remotePort := f.AllocPort()
_, _, err = f.RunFrpc("udp", "-s", fmt.Sprintf("127.0.0.1:%d", serverPort), "-t", "123", "-u", "test",
_, _, err = f.RunFrpc("udp", "-s", "127.0.0.1", "-P", strconv.Itoa(serverPort), "-t", "123", "-u", "test",
"-l", strconv.Itoa(localPort), "-r", strconv.Itoa(remotePort), "-n", "udp_test")
framework.ExpectNoError(err)
@ -98,7 +97,7 @@ var _ = ginkgo.Describe("[Feature: Cmd]", func() {
_, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort), "--vhost_http_port", strconv.Itoa(vhostHTTPPort))
framework.ExpectNoError(err)
_, _, err = f.RunFrpc("http", "-s", "127.0.0.1:"+strconv.Itoa(serverPort), "-t", "123", "-u", "test",
_, _, err = f.RunFrpc("http", "-s", "127.0.0.1", "-P", strconv.Itoa(serverPort), "-t", "123", "-u", "test",
"-n", "udp_test", "-l", strconv.Itoa(f.PortByName(framework.HTTPSimpleServerPort)),
"--custom_domain", "test.example.com")
framework.ExpectNoError(err)

View File

@ -7,11 +7,11 @@ import (
"github.com/onsi/ginkgo/v2"
clientsdk "github.com/fatedier/frp/pkg/sdk/client"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/port"
"github.com/fatedier/frp/test/e2e/pkg/request"
clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client"
)
var _ = ginkgo.Describe("[Feature: Server Manager]", func() {

View File

@ -10,8 +10,8 @@ import (
plugin "github.com/fatedier/frp/pkg/plugin/server"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
plugintest "github.com/fatedier/frp/test/e2e/legacy/plugin"
"github.com/fatedier/frp/test/e2e/mock/server/streamserver"
pluginpkg "github.com/fatedier/frp/test/e2e/pkg/plugin"
"github.com/fatedier/frp/test/e2e/pkg/request"
)
@ -65,7 +65,7 @@ var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() {
ret.Content = content
return &ret
}
pluginServer := plugintest.NewHTTPPluginServer(pluginPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(pluginPort, newFunc, handler, nil)
f.RunServer("", pluginServer)

View File

@ -10,6 +10,7 @@ import (
"github.com/fatedier/frp/pkg/transport"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
pluginpkg "github.com/fatedier/frp/test/e2e/pkg/plugin"
)
var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
@ -40,7 +41,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
}
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -98,7 +99,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
}
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -133,7 +134,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
ret.Content = content
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -174,7 +175,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
recordProxyName = content.ProxyName
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -226,7 +227,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
ret.Unchange = true
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -276,7 +277,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
ret.Unchange = true
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -321,7 +322,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
ret.Unchange = true
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -368,7 +369,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
}
tlsConfig, err := transport.NewServerTLSConfig("", "", "")
framework.ExpectNoError(err)
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, tlsConfig)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, tlsConfig)
f.RunServer("", pluginServer)

View File

@ -14,8 +14,8 @@ import (
libdial "github.com/fatedier/golib/net/dial"
"github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/test/e2e/pkg/rpc"
"github.com/fatedier/frp/test/e2e/pkg/utils"
)
type Request struct {
@ -115,7 +115,7 @@ func (r *Request) HTTPHeaders(headers map[string]string) *Request {
}
func (r *Request) HTTPAuth(user, password string) *Request {
r.authValue = utils.BasicAuth(user, password)
r.authValue = util.BasicAuth(user, password)
return r
}

View File

@ -1,10 +0,0 @@
package utils
import (
"encoding/base64"
)
func BasicAuth(username, passwd string) string {
auth := username + ":" + passwd
return "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
}

View File

@ -8,10 +8,10 @@ import (
"github.com/onsi/ginkgo/v2"
clientsdk "github.com/fatedier/frp/pkg/sdk/client"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/request"
clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client"
)
var _ = ginkgo.Describe("[Feature: ClientManage]", func() {

View File

@ -1,7 +1,6 @@
package basic
import (
"fmt"
"strconv"
"strings"
@ -66,7 +65,7 @@ var _ = ginkgo.Describe("[Feature: Cmd]", func() {
localPort := f.PortByName(framework.TCPEchoServerPort)
remotePort := f.AllocPort()
_, _, err = f.RunFrpc("tcp", "-s", fmt.Sprintf("127.0.0.1:%d", serverPort), "-t", "123", "-u", "test",
_, _, err = f.RunFrpc("tcp", "-s", "127.0.0.1", "-P", strconv.Itoa(serverPort), "-t", "123", "-u", "test",
"-l", strconv.Itoa(localPort), "-r", strconv.Itoa(remotePort), "-n", "tcp_test")
framework.ExpectNoError(err)
@ -80,7 +79,7 @@ var _ = ginkgo.Describe("[Feature: Cmd]", func() {
localPort := f.PortByName(framework.UDPEchoServerPort)
remotePort := f.AllocPort()
_, _, err = f.RunFrpc("udp", "-s", fmt.Sprintf("127.0.0.1:%d", serverPort), "-t", "123", "-u", "test",
_, _, err = f.RunFrpc("udp", "-s", "127.0.0.1", "-P", strconv.Itoa(serverPort), "-t", "123", "-u", "test",
"-l", strconv.Itoa(localPort), "-r", strconv.Itoa(remotePort), "-n", "udp_test")
framework.ExpectNoError(err)
@ -94,7 +93,7 @@ var _ = ginkgo.Describe("[Feature: Cmd]", func() {
_, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort), "--vhost_http_port", strconv.Itoa(vhostHTTPPort))
framework.ExpectNoError(err)
_, _, err = f.RunFrpc("http", "-s", "127.0.0.1:"+strconv.Itoa(serverPort), "-t", "123", "-u", "test",
_, _, err = f.RunFrpc("http", "-s", "127.0.0.1", "-P", strconv.Itoa(serverPort), "-t", "123", "-u", "test",
"-n", "udp_test", "-l", strconv.Itoa(f.PortByName(framework.HTTPSimpleServerPort)),
"--custom_domain", "test.example.com")
framework.ExpectNoError(err)

View File

@ -7,11 +7,11 @@ import (
"github.com/onsi/ginkgo/v2"
clientsdk "github.com/fatedier/frp/pkg/sdk/client"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/port"
"github.com/fatedier/frp/test/e2e/pkg/request"
clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client"
)
var _ = ginkgo.Describe("[Feature: Server Manager]", func() {

View File

@ -10,8 +10,8 @@ import (
plugin "github.com/fatedier/frp/pkg/plugin/server"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
plugintest "github.com/fatedier/frp/test/e2e/legacy/plugin"
"github.com/fatedier/frp/test/e2e/mock/server/streamserver"
pluginpkg "github.com/fatedier/frp/test/e2e/pkg/plugin"
"github.com/fatedier/frp/test/e2e/pkg/request"
)
@ -66,7 +66,7 @@ var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() {
ret.Content = content
return &ret
}
pluginServer := plugintest.NewHTTPPluginServer(pluginPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(pluginPort, newFunc, handler, nil)
f.RunServer("", pluginServer)

View File

@ -10,6 +10,7 @@ import (
"github.com/fatedier/frp/pkg/transport"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
pluginpkg "github.com/fatedier/frp/test/e2e/pkg/plugin"
)
var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
@ -40,7 +41,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
}
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -101,7 +102,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
}
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -138,7 +139,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
ret.Content = content
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -181,7 +182,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
recordProxyName = content.ProxyName
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -235,7 +236,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
ret.Unchange = true
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -287,7 +288,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
ret.Unchange = true
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -334,7 +335,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
ret.Unchange = true
return &ret
}
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, nil)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
@ -383,7 +384,7 @@ var _ = ginkgo.Describe("[Feature: Server-Plugins]", func() {
}
tlsConfig, err := transport.NewServerTLSConfig("", "", "")
framework.ExpectNoError(err)
pluginServer := NewHTTPPluginServer(localPort, newFunc, handler, tlsConfig)
pluginServer := pluginpkg.NewHTTPPluginServer(localPort, newFunc, handler, tlsConfig)
f.RunServer("", pluginServer)

View File

@ -1,41 +0,0 @@
package plugin
import (
"crypto/tls"
"encoding/json"
"io"
"net/http"
plugin "github.com/fatedier/frp/pkg/plugin/server"
"github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/test/e2e/mock/server/httpserver"
)
type Handler func(req *plugin.Request) *plugin.Response
type NewPluginRequest func() *plugin.Request
func NewHTTPPluginServer(port int, newFunc NewPluginRequest, handler Handler, tlsConfig *tls.Config) *httpserver.Server {
return httpserver.New(
httpserver.WithBindPort(port),
httpserver.WithTLSConfig(tlsConfig),
httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
r := newFunc()
buf, err := io.ReadAll(req.Body)
if err != nil {
w.WriteHeader(500)
return
}
log.Trace("plugin request: %s", string(buf))
err = json.Unmarshal(buf, &r)
if err != nil {
w.WriteHeader(500)
return
}
resp := handler(r)
buf, _ = json.Marshal(resp)
log.Trace("plugin response: %s", string(buf))
_, _ = w.Write(buf)
})),
)
}