Skip to content

Commit

Permalink
Merge pull request #2834 from fatedier/dev
Browse files Browse the repository at this point in the history
bump version
  • Loading branch information
fatedier authored Mar 11, 2022
2 parents 88fcc07 + 1f88a7a commit ce67782
Show file tree
Hide file tree
Showing 21 changed files with 233 additions and 33 deletions.
12 changes: 11 additions & 1 deletion Release.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
### New

* Added `dial_server_timeout` in frpc to specify connect timeout to frps.
* Additional EndpointParams can be set for OIDC.
* Added CloseProxy operation in server plugin.

### Improve

* Added some randomness in reconnect delay.

### Fix

* Fixed IPv6 address parse issue.
* TLS server name is ignored when `tls_trusted_ca_file` isn’t set.
1 change: 1 addition & 0 deletions client/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ func (ctl *Control) connectServer() (conn net.Conn, err error) {
}
dialOptions = append(dialOptions,
libdial.WithProtocol(protocol),
libdial.WithTimeout(time.Duration(ctl.clientCfg.DialServerTimeout)*time.Second),
libdial.WithProxy(proxyType, addr),
libdial.WithProxyAuth(auth),
libdial.WithTLSConfig(tlsConfig),
Expand Down
5 changes: 4 additions & 1 deletion client/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,10 @@ func HandleTCPWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf
return
}

localConn, err := libdial.Dial(net.JoinHostPort(localInfo.LocalIP, strconv.Itoa(localInfo.LocalPort)))
localConn, err := libdial.Dial(
net.JoinHostPort(localInfo.LocalIP, strconv.Itoa(localInfo.LocalPort)),
libdial.WithTimeout(10*time.Second),
)
if err != nil {
workConn.Close()
xl.Error("connect to local service [%s:%d] error: %v", localInfo.LocalIP, localInfo.LocalPort, err)
Expand Down
28 changes: 13 additions & 15 deletions client/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package client
import (
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
Expand All @@ -34,6 +33,7 @@ import (
"github.com/fatedier/frp/pkg/transport"
"github.com/fatedier/frp/pkg/util/log"
frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/version"
"github.com/fatedier/frp/pkg/util/xlog"
libdial "github.com/fatedier/golib/net/dial"
Expand Down Expand Up @@ -109,7 +109,7 @@ func (svr *Service) Run() error {
if svr.cfg.LoginFailExit {
return err
}
time.Sleep(10 * time.Second)
util.RandomSleep(10*time.Second, 0.9, 1.1)
} else {
// login success
ctl := NewControl(svr.ctx, svr.runID, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort, svr.authSetter)
Expand Down Expand Up @@ -158,8 +158,11 @@ func (svr *Service) keepControllerWorking() {

// the first three retry with no delay
if reconnectCounts > 3 {
time.Sleep(reconnectDelay)
util.RandomSleep(reconnectDelay, 0.9, 1.1)
xl.Info("wait %v to reconnect", reconnectDelay)
reconnectDelay *= 2
} else {
util.RandomSleep(time.Second, 0, 0.5)
}
reconnectCounts++

Expand All @@ -175,18 +178,12 @@ func (svr *Service) keepControllerWorking() {
xl.Info("try to reconnect to server...")
conn, session, err := svr.login()
if err != nil {
xl.Warn("reconnect to server error: %v", err)
time.Sleep(delayTime)

opErr := &net.OpError{}
// quick retry for dial error
if errors.As(err, &opErr) && opErr.Op == "dial" {
delayTime = 2 * time.Second
} else {
delayTime = delayTime * 2
if delayTime > maxDelayTime {
delayTime = maxDelayTime
}
xl.Warn("reconnect to server error: %v, wait %v for another retry", err, delayTime)
util.RandomSleep(delayTime, 0.9, 1.1)

delayTime = delayTime * 2
if delayTime > maxDelayTime {
delayTime = maxDelayTime
}
continue
}
Expand Down Expand Up @@ -245,6 +242,7 @@ func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) {
}
dialOptions = append(dialOptions,
libdial.WithProtocol(protocol),
libdial.WithTimeout(time.Duration(svr.cfg.DialServerTimeout)*time.Second),
libdial.WithProxy(proxyType, addr),
libdial.WithProxyAuth(auth),
libdial.WithTLSConfig(tlsConfig),
Expand Down
9 changes: 9 additions & 0 deletions conf/frpc_full.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
server_addr = 0.0.0.0
server_port = 7000

# The maximum amount of time a dial to server will wait for a connect to complete. Default value is 10 seconds.
# dial_server_timeout = 10

# if you want to connect frps by http proxy or socks5 proxy or ntlm proxy, you can set http_proxy here or in global environment variables
# it only works when protocol is tcp
# http_proxy = http://user:passwd@192.168.1.128:8080
Expand Down Expand Up @@ -48,6 +51,12 @@ oidc_audience =
# It will be used to get an OIDC token if AuthenticationMethod == "oidc". By default, this value is "".
oidc_token_endpoint_url =

# oidc_additional_xxx specifies additional parameters to be sent to the OIDC Token Endpoint.
# For example, if you want to specify the "audience" parameter, you can set as follow.
# frp will add "audience=<value>" "var1=<value>" to the additional parameters.
# oidc_additional_audience = https://dev.auth.com/api/v2/
# oidc_additional_var1 = foobar

# set admin address for control frpc's action by http api such as reload
admin_addr = 127.0.0.1
admin_port = 7400
Expand Down
22 changes: 21 additions & 1 deletion doc/server_plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ The response can look like any of the following:

### Operation

Currently `Login`, `NewProxy`, `Ping`, `NewWorkConn` and `NewUserConn` operations are supported.
Currently `Login`, `NewProxy`, `CloseProxy`, `Ping`, `NewWorkConn` and `NewUserConn` operations are supported.

#### Login

Expand Down Expand Up @@ -136,6 +136,26 @@ Create new proxy
}
```

#### CloseProxy

A previously created proxy is closed.

Please note that one request will be sent for every proxy that is closed, do **NOT** use this
if you have too many proxies bound to a single client, as this may exhaust the server's resources.

```
{
"content": {
"user": {
"user": <string>,
"metas": map<string>string
"run_id": <string>
},
"proxy_name": <string>
}
}
```

#### Ping

Heartbeat from frpc
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb
github.com/fatedier/golib v0.1.1-0.20220119075718-78e5cf8c00ee
github.com/fatedier/golib v0.1.1-0.20220218075713-264f72dfbfd9
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible
github.com/go-playground/validator/v10 v10.6.1
github.com/google/uuid v1.2.0
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw=
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
github.com/fatedier/golib v0.1.1-0.20220119075718-78e5cf8c00ee h1:iS0wlj2uZPxh3pciAf/HTzi88Kqu7DPh1jNKgJaFhtI=
github.com/fatedier/golib v0.1.1-0.20220119075718-78e5cf8c00ee/go.mod h1:fLV0TLwHqrnB/L3jbNl67Gn6PCLggDGHniX1wLrA2Qo=
github.com/fatedier/golib v0.1.1-0.20220218073251-9509a597216b h1:5r5/G3NFsFK+7svxvxZYA8yy8Ubs4hWIq+QYYMgEBe8=
github.com/fatedier/golib v0.1.1-0.20220218073251-9509a597216b/go.mod h1:fLV0TLwHqrnB/L3jbNl67Gn6PCLggDGHniX1wLrA2Qo=
github.com/fatedier/golib v0.1.1-0.20220218075713-264f72dfbfd9 h1:AOGf9Z1ri+3MiyGIAYXe+shEXx6/uVGJlufb6ZfnZls=
github.com/fatedier/golib v0.1.1-0.20220218075713-264f72dfbfd9/go.mod h1:fLV0TLwHqrnB/L3jbNl67Gn6PCLggDGHniX1wLrA2Qo=
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1:ssXat9YXFvigNge/IkkZvFMn8yeYKFX+uI6wn2mLJ74=
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
Expand Down
28 changes: 20 additions & 8 deletions pkg/auth/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,20 @@ type OidcClientConfig struct {
// It will be used to get an OIDC token if AuthenticationMethod == "oidc".
// By default, this value is "".
OidcTokenEndpointURL string `ini:"oidc_token_endpoint_url" json:"oidc_token_endpoint_url"`

// OidcAdditionalEndpointParams specifies additional parameters to be sent
// this field will be transfer to map[string][]string in OIDC token generator
// The field will be set by prefix "oidc_additional_"
OidcAdditionalEndpointParams map[string]string `ini:"-" json:"oidc_additional_endpoint_params"`
}

func getDefaultOidcClientConf() OidcClientConfig {
return OidcClientConfig{
OidcClientID: "",
OidcClientSecret: "",
OidcAudience: "",
OidcTokenEndpointURL: "",
OidcClientID: "",
OidcClientSecret: "",
OidcAudience: "",
OidcTokenEndpointURL: "",
OidcAdditionalEndpointParams: make(map[string]string),
}
}

Expand Down Expand Up @@ -88,11 +94,17 @@ type OidcAuthProvider struct {
}

func NewOidcAuthSetter(baseCfg BaseConfig, cfg OidcClientConfig) *OidcAuthProvider {
eps := make(map[string][]string)
for k, v := range cfg.OidcAdditionalEndpointParams {
eps[k] = []string{v}
}

tokenGenerator := &clientcredentials.Config{
ClientID: cfg.OidcClientID,
ClientSecret: cfg.OidcClientSecret,
Scopes: []string{cfg.OidcAudience},
TokenURL: cfg.OidcTokenEndpointURL,
ClientID: cfg.OidcClientID,
ClientSecret: cfg.OidcClientSecret,
Scopes: []string{cfg.OidcAudience},
TokenURL: cfg.OidcTokenEndpointURL,
EndpointParams: eps,
}

return &OidcAuthProvider{
Expand Down
5 changes: 5 additions & 0 deletions pkg/config/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ type ClientCommonConf struct {
// ServerPort specifies the port to connect to the server on. By default,
// this value is 7000.
ServerPort int `ini:"server_port" json:"server_port"`
// The maximum amount of time a dial to server will wait for a connect to complete.
DialServerTimeout int64 `ini:"dial_server_timeout" json:"dial_server_timeout"`
// ConnectServerLocalIP specifies the address of the client bind when it connect to server.
// By default, this value is empty.
// this value only use in TCP/Websocket protocol. Not support in KCP protocol.
Expand Down Expand Up @@ -157,6 +159,7 @@ func GetDefaultClientConf() ClientCommonConf {
ClientConfig: auth.GetDefaultClientConf(),
ServerAddr: "0.0.0.0",
ServerPort: 7000,
DialServerTimeout: 10,
HTTPProxy: os.Getenv("http_proxy"),
LogFile: "console",
LogWay: "console",
Expand Down Expand Up @@ -258,6 +261,8 @@ func UnmarshalClientConfFromIni(source interface{}) (ClientCommonConf, error) {
}

common.Metas = GetMapWithoutPrefix(s.KeysHash(), "meta_")
common.ClientConfig.OidcAdditionalEndpointParams = GetMapWithoutPrefix(s.KeysHash(), "oidc_additional_")

return common, nil
}

Expand Down
1 change: 1 addition & 0 deletions pkg/config/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ func Test_LoadClientCommonConf(t *testing.T) {
},
ServerAddr: "0.0.0.9",
ServerPort: 7009,
DialServerTimeout: 10,
HTTPProxy: "http://user:passwd@192.168.1.128:8080",
LogFile: "./frpc.log9",
LogWay: "file",
Expand Down
32 changes: 32 additions & 0 deletions pkg/plugin/server/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"errors"
"fmt"
"strings"

"github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/xlog"
Expand All @@ -26,6 +27,7 @@ import (
type Manager struct {
loginPlugins []Plugin
newProxyPlugins []Plugin
closeProxyPlugins []Plugin
pingPlugins []Plugin
newWorkConnPlugins []Plugin
newUserConnPlugins []Plugin
Expand All @@ -35,6 +37,7 @@ func NewManager() *Manager {
return &Manager{
loginPlugins: make([]Plugin, 0),
newProxyPlugins: make([]Plugin, 0),
closeProxyPlugins: make([]Plugin, 0),
pingPlugins: make([]Plugin, 0),
newWorkConnPlugins: make([]Plugin, 0),
newUserConnPlugins: make([]Plugin, 0),
Expand All @@ -48,6 +51,9 @@ func (m *Manager) Register(p Plugin) {
if p.IsSupport(OpNewProxy) {
m.newProxyPlugins = append(m.newProxyPlugins, p)
}
if p.IsSupport(OpCloseProxy) {
m.closeProxyPlugins = append(m.closeProxyPlugins, p)
}
if p.IsSupport(OpPing) {
m.pingPlugins = append(m.pingPlugins, p)
}
Expand Down Expand Up @@ -127,6 +133,32 @@ func (m *Manager) NewProxy(content *NewProxyContent) (*NewProxyContent, error) {
return content, nil
}

func (m *Manager) CloseProxy(content *CloseProxyContent) error {
if len(m.closeProxyPlugins) == 0 {
return nil
}

errs := make([]string, 0)
reqid, _ := util.RandID()
xl := xlog.New().AppendPrefix("reqid: " + reqid)
ctx := xlog.NewContext(context.Background(), xl)
ctx = NewReqidContext(ctx, reqid)

for _, p := range m.closeProxyPlugins {
_, _, err := p.Handle(ctx, OpCloseProxy, *content)
if err != nil {
xl.Warn("send CloseProxy request to plugin [%s] error: %v", p.Name(), err)
errs = append(errs, fmt.Sprintf("[%s]: %v", p.Name(), err))
}
}

if len(errs) > 0 {
return fmt.Errorf("send CloseProxy request to plugin errors: %s", strings.Join(errs, "; "))
} else {
return nil
}
}

func (m *Manager) Ping(content *PingContent) (*PingContent, error) {
if len(m.pingPlugins) == 0 {
return content, nil
Expand Down
1 change: 1 addition & 0 deletions pkg/plugin/server/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (

OpLogin = "Login"
OpNewProxy = "NewProxy"
OpCloseProxy = "CloseProxy"
OpPing = "Ping"
OpNewWorkConn = "NewWorkConn"
OpNewUserConn = "NewUserConn"
Expand Down
5 changes: 5 additions & 0 deletions pkg/plugin/server/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ type NewProxyContent struct {
msg.NewProxy
}

type CloseProxyContent struct {
User UserInfo `json:"user"`
msg.CloseProxy
}

type PingContent struct {
User UserInfo `json:"user"`
msg.Ping
Expand Down
3 changes: 2 additions & 1 deletion pkg/transport/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,15 @@ func NewClientTLSConfig(certPath, keyPath, caPath, serverName string) (*tls.Conf
base.Certificates = []tls.Certificate{*cert}
}

base.ServerName = serverName

if caPath != "" {
pool, err := newCertPool(caPath)
if err != nil {
return nil, err
}

base.RootCAs = pool
base.ServerName = serverName
base.InsecureSkipVerify = false
} else {
base.InsecureSkipVerify = true
Expand Down
Loading

0 comments on commit ce67782

Please sign in to comment.