From 86c2ad78c859bc2172404d7327336bab230b8660 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 13 Mar 2024 21:53:09 +0800 Subject: [PATCH 01/10] disable quic-go's receive buffer warning (#4063) --- Release.md | 1 - client/service.go | 3 +++ server/service.go | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Release.md b/Release.md index bf512ca5..e69de29b 100644 --- a/Release.md +++ b/Release.md @@ -1 +0,0 @@ -No feature changes, just a fix for the issue of no released assets in version 0.55.0. diff --git a/client/service.go b/client/service.go index 25e108fc..e24e16d7 100644 --- a/client/service.go +++ b/client/service.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" "net" + "os" "runtime" "sync" "time" @@ -40,6 +41,8 @@ import ( func init() { crypto.DefaultSalt = "frp" + // Disable quic-go's receive buffer warning. + os.Setenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING", "true") } type cancelErr struct { diff --git a/server/service.go b/server/service.go index 12564325..4c3ee125 100644 --- a/server/service.go +++ b/server/service.go @@ -22,6 +22,7 @@ import ( "io" "net" "net/http" + "os" "strconv" "time" @@ -59,6 +60,11 @@ const ( vhostReadWriteTimeout time.Duration = 30 * time.Second ) +func init() { + // Disable quic-go's receive buffer warning. + os.Setenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING", "true") +} + // Server service type Service struct { // Dispatch connections to different handlers listen on same port From fa977c839f0863f2dd4b7ce560552d85a6fff777 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 14 Mar 2024 19:49:58 +0800 Subject: [PATCH 02/10] fix daily log rotate (#4066) --- Release.md | 3 +++ go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Release.md b/Release.md index e69de29b..3f4af070 100644 --- a/Release.md +++ b/Release.md @@ -0,0 +1,3 @@ +### Fixes + +* Fix the issue of incorrect interval time for rotating the log by day. diff --git a/go.mod b/go.mod index 3d82efe4..977c436b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22 require ( github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 github.com/coreos/go-oidc/v3 v3.6.0 - github.com/fatedier/golib v0.4.0 + github.com/fatedier/golib v0.4.1 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 diff --git a/go.sum b/go.sum index 474da7b4..0c472ae6 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatedier/golib v0.4.0 h1:lafvYRMhFmqrfIUChKy/f5AXqs1eDSk+GAUtLexN5bU= -github.com/fatedier/golib v0.4.0/go.mod h1:gpu+1vXxtJ072NYaNsn/YWgojDL8Ap2kFZQtbzT2qkg= +github.com/fatedier/golib v0.4.1 h1:C37VN3M+F3nUdh13laZsiyb5EXNe3tZnUdoHi+7rx+Q= +github.com/fatedier/golib v0.4.1/go.mod h1:gpu+1vXxtJ072NYaNsn/YWgojDL8Ap2kFZQtbzT2qkg= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= From 8383d528d982fdb746e939dfb9d170b53ef93f7b Mon Sep 17 00:00:00 2001 From: fatedier Date: Fri, 15 Mar 2024 14:22:03 +0800 Subject: [PATCH 03/10] disable quic-go's ECN support by default (#4069) --- Release.md | 1 + client/service.go | 4 ++++ server/service.go | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/Release.md b/Release.md index 3f4af070..a699be85 100644 --- a/Release.md +++ b/Release.md @@ -1,3 +1,4 @@ ### Fixes * Fix the issue of incorrect interval time for rotating the log by day. +* Disable quic-go's ECN support by default. It may cause issues on certain operating systems. diff --git a/client/service.go b/client/service.go index e24e16d7..7a7f6dc8 100644 --- a/client/service.go +++ b/client/service.go @@ -43,6 +43,10 @@ func init() { crypto.DefaultSalt = "frp" // Disable quic-go's receive buffer warning. os.Setenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING", "true") + // Disable quic-go's ECN support by default. It may cause issues on certain operating systems. + if os.Getenv("QUIC_GO_DISABLE_ECN") == "" { + os.Setenv("QUIC_GO_DISABLE_ECN", "true") + } } type cancelErr struct { diff --git a/server/service.go b/server/service.go index 4c3ee125..4fdb2166 100644 --- a/server/service.go +++ b/server/service.go @@ -63,6 +63,10 @@ const ( func init() { // Disable quic-go's receive buffer warning. os.Setenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING", "true") + // Disable quic-go's ECN support by default. It may cause issues on certain operating systems. + if os.Getenv("QUIC_GO_DISABLE_ECN") == "" { + os.Setenv("QUIC_GO_DISABLE_ECN", "true") + } } // Server service From 3585f5c0c08a23cc840df1c16e4deb8c4ad719b9 Mon Sep 17 00:00:00 2001 From: fatedier Date: Fri, 15 Mar 2024 17:23:16 +0800 Subject: [PATCH 04/10] support range ports mapping by go template (#4073) --- pkg/config/load.go | 5 +++- pkg/config/template.go | 52 +++++++++++++++++++++++++++++++++ test/e2e/framework/client.go | 12 ++++---- test/e2e/framework/expect.go | 4 +++ test/e2e/framework/framework.go | 2 +- test/e2e/legacy/basic/client.go | 5 ++-- test/e2e/legacy/basic/server.go | 3 +- test/e2e/v1/basic/client.go | 5 ++-- test/e2e/v1/basic/config.go | 45 ++++++++++++++++++++++++++++ test/e2e/v1/basic/server.go | 3 +- 10 files changed, 117 insertions(+), 19 deletions(-) create mode 100644 pkg/config/template.go diff --git a/pkg/config/load.go b/pkg/config/load.go index cdbb8e91..f9a705eb 100644 --- a/pkg/config/load.go +++ b/pkg/config/load.go @@ -80,7 +80,10 @@ func DetectLegacyINIFormatFromFile(path string) bool { } func RenderWithTemplate(in []byte, values *Values) ([]byte, error) { - tmpl, err := template.New("frp").Parse(string(in)) + tmpl, err := template.New("frp").Funcs(template.FuncMap{ + "parseNumberRange": parseNumberRange, + "parseNumberRangePair": parseNumberRangePair, + }).Parse(string(in)) if err != nil { return nil, err } diff --git a/pkg/config/template.go b/pkg/config/template.go new file mode 100644 index 00000000..44bc456d --- /dev/null +++ b/pkg/config/template.go @@ -0,0 +1,52 @@ +// Copyright 2024 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 config + +import ( + "fmt" + + "github.com/fatedier/frp/pkg/util/util" +) + +type NumberPair struct { + First int64 + Second int64 +} + +func parseNumberRangePair(firstRangeStr, secondRangeStr string) ([]NumberPair, error) { + firstRangeNumbers, err := util.ParseRangeNumbers(firstRangeStr) + if err != nil { + return nil, err + } + secondRangeNumbers, err := util.ParseRangeNumbers(secondRangeStr) + if err != nil { + return nil, err + } + if len(firstRangeNumbers) != len(secondRangeNumbers) { + return nil, fmt.Errorf("first and second range numbers are not in pairs") + } + pairs := make([]NumberPair, 0, len(firstRangeNumbers)) + for i := 0; i < len(firstRangeNumbers); i++ { + pairs = append(pairs, NumberPair{ + First: firstRangeNumbers[i], + Second: secondRangeNumbers[i], + }) + } + return pairs, nil +} + +func parseNumberRange(firstRangeStr string) ([]int64, error) { + return util.ParseRangeNumbers(firstRangeStr) +} diff --git a/test/e2e/framework/client.go b/test/e2e/framework/client.go index 76614354..c13cee10 100644 --- a/test/e2e/framework/client.go +++ b/test/e2e/framework/client.go @@ -1,11 +1,9 @@ package framework -type FRPClient struct { - port int -} +import ( + clientsdk "github.com/fatedier/frp/pkg/sdk/client" +) -func (f *Framework) FRPClient(port int) *FRPClient { - return &FRPClient{ - port: port, - } +func (f *Framework) APIClientForFrpc(port int) *clientsdk.Client { + return clientsdk.New("127.0.0.1", port) } diff --git a/test/e2e/framework/expect.go b/test/e2e/framework/expect.go index dab6da70..3c357bb0 100644 --- a/test/e2e/framework/expect.go +++ b/test/e2e/framework/expect.go @@ -43,6 +43,10 @@ func ExpectNoErrorWithOffset(offset int, err error, explain ...interface{}) { gomega.ExpectWithOffset(1+offset, err).NotTo(gomega.HaveOccurred(), explain...) } +func ExpectContainSubstring(actual, substr string, explain ...interface{}) { + gomega.ExpectWithOffset(1, actual).To(gomega.ContainSubstring(substr), explain...) +} + // ExpectConsistOf expects actual contains precisely the extra elements. The ordering of the elements does not matter. func ExpectConsistOf(actual interface{}, extra interface{}, explain ...interface{}) { gomega.ExpectWithOffset(1, actual).To(gomega.ConsistOf(extra), explain...) diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index e0be5af1..527096cd 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -217,7 +217,7 @@ func (f *Framework) RenderTemplates(templates []string) (outs []string, ports ma } for _, t := range templates { - tmpl, err := template.New("").Parse(t) + tmpl, err := template.New("frp-e2e").Parse(t) if err != nil { return nil, nil, err } diff --git a/test/e2e/legacy/basic/client.go b/test/e2e/legacy/basic/client.go index d4862e52..98f675b8 100644 --- a/test/e2e/legacy/basic/client.go +++ b/test/e2e/legacy/basic/client.go @@ -8,7 +8,6 @@ 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" @@ -54,7 +53,7 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() { framework.NewRequestExpect(f).Port(p2Port).Ensure() framework.NewRequestExpect(f).Port(p3Port).Ensure() - client := clientsdk.New("127.0.0.1", adminPort) + client := f.APIClientForFrpc(adminPort) conf, err := client.GetConfig() framework.ExpectNoError(err) @@ -120,7 +119,7 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() { framework.NewRequestExpect(f).Port(testPort).Ensure() - client := clientsdk.New("127.0.0.1", adminPort) + client := f.APIClientForFrpc(adminPort) err := client.Stop() framework.ExpectNoError(err) diff --git a/test/e2e/legacy/basic/server.go b/test/e2e/legacy/basic/server.go index ca6717c6..62bfd62a 100644 --- a/test/e2e/legacy/basic/server.go +++ b/test/e2e/legacy/basic/server.go @@ -7,7 +7,6 @@ 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" @@ -99,7 +98,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { f.RunProcesses([]string{serverConf}, []string{clientConf}) - client := clientsdk.New("127.0.0.1", adminPort) + client := f.APIClientForFrpc(adminPort) // tcp random port status, err := client.GetProxyStatus("tcp") diff --git a/test/e2e/v1/basic/client.go b/test/e2e/v1/basic/client.go index b0b258db..ef5e262f 100644 --- a/test/e2e/v1/basic/client.go +++ b/test/e2e/v1/basic/client.go @@ -8,7 +8,6 @@ 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" @@ -57,7 +56,7 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() { framework.NewRequestExpect(f).Port(p2Port).Ensure() framework.NewRequestExpect(f).Port(p3Port).Ensure() - client := clientsdk.New("127.0.0.1", adminPort) + client := f.APIClientForFrpc(adminPort) conf, err := client.GetConfig() framework.ExpectNoError(err) @@ -124,7 +123,7 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() { framework.NewRequestExpect(f).Port(testPort).Ensure() - client := clientsdk.New("127.0.0.1", adminPort) + client := f.APIClientForFrpc(adminPort) err := client.Stop() framework.ExpectNoError(err) diff --git a/test/e2e/v1/basic/config.go b/test/e2e/v1/basic/config.go index 686b3c5c..7dc3cedb 100644 --- a/test/e2e/v1/basic/config.go +++ b/test/e2e/v1/basic/config.go @@ -38,6 +38,51 @@ var _ = ginkgo.Describe("[Feature: Config]", func() { framework.NewRequestExpect(f).PortName(portName).Ensure() }) + + ginkgo.It("Range ports mapping", func() { + serverConf := consts.DefaultServerConfig + clientConf := consts.DefaultClientConfig + + adminPort := f.AllocPort() + + localPortsRange := "13010-13012,13014" + remotePortsRange := "23010-23012,23014" + escapeTemplate := func(s string) string { + return "{{ `" + s + "` }}" + } + clientConf += fmt.Sprintf(` + webServer.port = %d + + %s + [[proxies]] + name = "tcp-%s" + type = "tcp" + localPort = %s + remotePort = %s + %s + `, adminPort, + escapeTemplate(fmt.Sprintf(`{{- range $_, $v := parseNumberRangePair "%s" "%s" }}`, localPortsRange, remotePortsRange)), + escapeTemplate("{{ $v.First }}"), + escapeTemplate("{{ $v.First }}"), + escapeTemplate("{{ $v.Second }}"), + escapeTemplate("{{- end }}"), + ) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + client := f.APIClientForFrpc(adminPort) + checkProxyFn := func(name string, localPort, remotePort int) { + status, err := client.GetProxyStatus(name) + framework.ExpectNoError(err) + + framework.ExpectContainSubstring(status.LocalAddr, fmt.Sprintf(":%d", localPort)) + framework.ExpectContainSubstring(status.RemoteAddr, fmt.Sprintf(":%d", remotePort)) + } + checkProxyFn("tcp-13010", 13010, 23010) + checkProxyFn("tcp-13011", 13011, 23011) + checkProxyFn("tcp-13012", 13012, 23012) + checkProxyFn("tcp-13014", 13014, 23014) + }) }) ginkgo.Describe("Includes", func() { diff --git a/test/e2e/v1/basic/server.go b/test/e2e/v1/basic/server.go index f2f4e0a5..fe8af4d1 100644 --- a/test/e2e/v1/basic/server.go +++ b/test/e2e/v1/basic/server.go @@ -7,7 +7,6 @@ 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" @@ -110,7 +109,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { f.RunProcesses([]string{serverConf}, []string{clientConf}) - client := clientsdk.New("127.0.0.1", adminPort) + client := f.APIClientForFrpc(adminPort) // tcp random port status, err := client.GetProxyStatus("tcp") From acf33db4e4b6c9cf9182d93280299010637b6324 Mon Sep 17 00:00:00 2001 From: fatedier Date: Fri, 15 Mar 2024 17:50:58 +0800 Subject: [PATCH 05/10] update release notes (#4074) --- Release.md | 18 ++++++++++++++++++ pkg/util/version/version.go | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Release.md b/Release.md index a699be85..f106d802 100644 --- a/Release.md +++ b/Release.md @@ -1,3 +1,21 @@ +### Features + +* Support range ports mapping in TOML/YAML/JSON configuration file by using go template syntax. + + For example: + + ``` + {{- range $_, $v := parseNumberRangePair "6000-6006,6007" "6000-6006,6007" }} + [[proxies]] + name = "tcp-{{ $v.First }}" + type = "tcp" + localPort = {{ $v.First }} + remotePort = {{ $v.Second }} + {{- end }} + ``` + + This will create 8 proxies such as `tcp-6000, tcp-6001, ... tcp-6007`. + ### Fixes * Fix the issue of incorrect interval time for rotating the log by day. diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go index f5bac1bc..90af7813 100644 --- a/pkg/util/version/version.go +++ b/pkg/util/version/version.go @@ -14,7 +14,7 @@ package version -var version = "0.55.1" +var version = "0.56.0" func Full() string { return version From 002831ea823edfa2ab3695b3f4fc0404979bcedf Mon Sep 17 00:00:00 2001 From: fatedier Date: Tue, 19 Mar 2024 13:22:29 +0800 Subject: [PATCH 06/10] add doc for port range mapping (#4081) --- README.md | 19 +++++++++++++++++++ go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8dbf45ad..69cce9dd 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ frp also offers a P2P connect mode. * [URL Routing](#url-routing) * [TCP Port Multiplexing](#tcp-port-multiplexing) * [Connecting to frps via PROXY](#connecting-to-frps-via-proxy) + * [Port range mapping](#port-range-mapping) * [Client Plugins](#client-plugins) * [Server Manage Plugins](#server-manage-plugins) * [SSH Tunnel Gateway](#ssh-tunnel-gateway) @@ -1158,6 +1159,24 @@ serverPort = 7000 transport.proxyURL = "http://user:pwd@192.168.1.128:8080" ``` +### Port range mapping + +*Added in v0.56.0* + +We can use the range syntax of Go template combined with the built-in `parseNumberRangePair` function to achieve port range mapping. + +The following example, when run, will create 8 proxies named `test-6000, test-6001 ... test-6007`, each mapping the remote port to the local port. + +``` +{{- range $_, $v := parseNumberRangePair "6000-6006,6007" "6000-6006,6007" }} +[[proxies]] +name = "tcp-{{ $v.First }}" +type = "tcp" +localPort = {{ $v.First }} +remotePort = {{ $v.Second }} +{{- end }} +``` + ### Client Plugins frpc only forwards requests to local TCP or UDP ports by default. diff --git a/go.mod b/go.mod index 977c436b..d820b96c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22 require ( github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 github.com/coreos/go-oidc/v3 v3.6.0 - github.com/fatedier/golib v0.4.1 + github.com/fatedier/golib v0.4.2 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 diff --git a/go.sum b/go.sum index 0c472ae6..b00cb78f 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatedier/golib v0.4.1 h1:C37VN3M+F3nUdh13laZsiyb5EXNe3tZnUdoHi+7rx+Q= -github.com/fatedier/golib v0.4.1/go.mod h1:gpu+1vXxtJ072NYaNsn/YWgojDL8Ap2kFZQtbzT2qkg= +github.com/fatedier/golib v0.4.2 h1:k+ZBdUFTTipnP1RHfEhGbzyShRdz/rZtFGnjpXG9D9c= +github.com/fatedier/golib v0.4.2/go.mod h1:gpu+1vXxtJ072NYaNsn/YWgojDL8Ap2kFZQtbzT2qkg= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= From bc5fb91c055eb1befdad5d5051c91290fab3d816 Mon Sep 17 00:00:00 2001 From: Kaive Young Date: Wed, 20 Mar 2024 14:58:03 +0800 Subject: [PATCH 07/10] add header for http healthcheck (#4085) --- client/health/health.go | 12 ++++++++++-- conf/frpc_full_example.toml | 4 ++++ pkg/config/v1/common.go | 5 +++++ pkg/config/v1/proxy.go | 3 +++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/client/health/health.go b/client/health/health.go index 7147f779..d298e615 100644 --- a/client/health/health.go +++ b/client/health/health.go @@ -40,8 +40,8 @@ type Monitor struct { addr string // For http - url string - + url string + header http.Header failedTimes uint64 statusOK bool statusNormalFn func() @@ -73,6 +73,11 @@ func NewMonitor(ctx context.Context, cfg v1.HealthCheckConfig, addr string, } url = s + cfg.Path } + header := make(http.Header) + for _, h := range cfg.HTTPHeaders { + header.Set(h.Name, h.Value) + } + return &Monitor{ checkType: cfg.Type, interval: time.Duration(cfg.IntervalSeconds) * time.Second, @@ -80,6 +85,7 @@ func NewMonitor(ctx context.Context, cfg v1.HealthCheckConfig, addr string, maxFailedTimes: cfg.MaxFailed, addr: addr, url: url, + header: header, statusOK: false, statusNormalFn: statusNormalFn, statusFailedFn: statusFailedFn, @@ -163,6 +169,8 @@ func (monitor *Monitor) doHTTPCheck(ctx context.Context) error { if err != nil { return err } + req.Header = monitor.header + req.Host = monitor.header.Get("Host") resp, err := http.DefaultClient.Do(req) if err != nil { return err diff --git a/conf/frpc_full_example.toml b/conf/frpc_full_example.toml index 59de6fa4..4dae6b3c 100644 --- a/conf/frpc_full_example.toml +++ b/conf/frpc_full_example.toml @@ -216,6 +216,10 @@ healthCheck.path = "/status" healthCheck.intervalSeconds = 10 healthCheck.maxFailed = 3 healthCheck.timeoutSeconds = 3 +# set health check headers +healthCheck.httpheaders=[ + { name = "x-from-where", value = "frp" } +] [[proxies]] name = "web02" diff --git a/pkg/config/v1/common.go b/pkg/config/v1/common.go index 24ec9b0d..ddb23356 100644 --- a/pkg/config/v1/common.go +++ b/pkg/config/v1/common.go @@ -129,3 +129,8 @@ type HTTPPluginOptions struct { type HeaderOperations struct { Set map[string]string `json:"set,omitempty"` } + +type HTTPHeader struct { + Name string `json:"name"` + Value string `json:"value"` +} diff --git a/pkg/config/v1/proxy.go b/pkg/config/v1/proxy.go index c9065432..9d91b585 100644 --- a/pkg/config/v1/proxy.go +++ b/pkg/config/v1/proxy.go @@ -97,6 +97,9 @@ type HealthCheckConfig struct { // Path specifies the path to send health checks to if the // health check type is "http". Path string `json:"path,omitempty"` + // Headers specifies the headers to send health checks to if the + // health check type is "http". + HTTPHeaders []HTTPHeader `json:"httpHeaders,omitempty"` } type DomainConfig struct { From c08be0fd926f46f1f5fd9b2105b9ba3753522548 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 20 Mar 2024 15:16:01 +0800 Subject: [PATCH 08/10] update release notes (#4086) --- Release.md | 2 ++ conf/frpc_full_example.toml | 2 +- pkg/config/v1/proxy.go | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Release.md b/Release.md index f106d802..ca58a04d 100644 --- a/Release.md +++ b/Release.md @@ -16,6 +16,8 @@ This will create 8 proxies such as `tcp-6000, tcp-6001, ... tcp-6007`. +* Health check supports custom request headers. + ### Fixes * Fix the issue of incorrect interval time for rotating the log by day. diff --git a/conf/frpc_full_example.toml b/conf/frpc_full_example.toml index 4dae6b3c..0528ddea 100644 --- a/conf/frpc_full_example.toml +++ b/conf/frpc_full_example.toml @@ -217,7 +217,7 @@ healthCheck.intervalSeconds = 10 healthCheck.maxFailed = 3 healthCheck.timeoutSeconds = 3 # set health check headers -healthCheck.httpheaders=[ +healthCheck.httpHeaders=[ { name = "x-from-where", value = "frp" } ] diff --git a/pkg/config/v1/proxy.go b/pkg/config/v1/proxy.go index 9d91b585..1949cfd3 100644 --- a/pkg/config/v1/proxy.go +++ b/pkg/config/v1/proxy.go @@ -97,8 +97,8 @@ type HealthCheckConfig struct { // Path specifies the path to send health checks to if the // health check type is "http". Path string `json:"path,omitempty"` - // Headers specifies the headers to send health checks to if the - // health check type is "http". + // HTTPHeaders specifies the headers to send with the health request, if + // the health check type is "http". HTTPHeaders []HTTPHeader `json:"httpHeaders,omitempty"` } From b36f3834eb5cefbd25c85777df9b362ddc6c2820 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 20 Mar 2024 15:48:31 +0800 Subject: [PATCH 09/10] use math/rand/v2 (#4020) --- .github/workflows/golangci-lint.yml | 2 +- .golangci.yml | 27 +++++++++------------------ pkg/nathole/nathole.go | 6 +++--- pkg/util/util/util.go | 4 ++-- pkg/util/wait/backoff.go | 2 +- 5 files changed, 16 insertions(+), 25 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 18f69d52..b3e2cb43 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -23,7 +23,7 @@ jobs: uses: golangci/golangci-lint-action@v4 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: v1.56 + version: v1.57 # Optional: golangci-lint command line arguments. # args: --issues-exit-code=0 diff --git a/.golangci.yml b/.golangci.yml index cd92e43c..e2f8a240 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,5 @@ service: - golangci-lint-version: 1.56.x # use the fixed version to not introduce new linters unexpectedly + golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly run: concurrency: 4 @@ -8,23 +8,6 @@ run: build-tags: - integ - integfuzz - # which dirs to skip: they won't be analyzed; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but next dirs are always skipped independently - # from this option's value: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs: - - genfiles$ - - vendor$ - - bin$ - - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. - skip-files: - - ".*\\.pb\\.go" - - ".*\\.gen\\.go" linters: disable-all: true @@ -136,6 +119,14 @@ issues: - unparam text: "is always false" + exclude-dirs: + - genfiles$ + - vendor$ + - bin$ + exclude-files: + - ".*\\.pb\\.go" + - ".*\\.gen\\.go" + # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all # excluded by default patterns execute `golangci-lint run --help`. diff --git a/pkg/nathole/nathole.go b/pkg/nathole/nathole.go index 18cd12bc..bdd0ee83 100644 --- a/pkg/nathole/nathole.go +++ b/pkg/nathole/nathole.go @@ -17,7 +17,7 @@ package nathole import ( "context" "fmt" - "math/rand" + "math/rand/v2" "net" "slices" "strconv" @@ -341,7 +341,7 @@ func sendSidMessage( TransactionID: transactionID, Sid: sid, Response: false, - Nonce: strings.Repeat("0", rand.Intn(20)), + Nonce: strings.Repeat("0", rand.IntN(20)), } buf, err := EncodeMessage(m, key) if err != nil { @@ -398,7 +398,7 @@ func sendSidMessageToRandomPorts( used := sets.New[int]() getUnusedPort := func() int { for i := 0; i < 10; i++ { - port := rand.Intn(65535-1024) + 1024 + port := rand.IntN(65535-1024) + 1024 if !used.Has(port) { used.Insert(port) return port diff --git a/pkg/util/util/util.go b/pkg/util/util/util.go index c7fd9971..7758054d 100644 --- a/pkg/util/util/util.go +++ b/pkg/util/util/util.go @@ -20,7 +20,7 @@ import ( "crypto/subtle" "encoding/hex" "fmt" - mathrand "math/rand" + mathrand "math/rand/v2" "net" "strconv" "strings" @@ -124,7 +124,7 @@ func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Durati if max <= min { n = min } else { - n = mathrand.Int63n(max-min) + min + n = mathrand.Int64N(max-min) + min } d := duration * time.Duration(n) / time.Duration(1000) time.Sleep(d) diff --git a/pkg/util/wait/backoff.go b/pkg/util/wait/backoff.go index 16d9dd6a..4d01ace3 100644 --- a/pkg/util/wait/backoff.go +++ b/pkg/util/wait/backoff.go @@ -15,7 +15,7 @@ package wait import ( - "math/rand" + "math/rand/v2" "time" "github.com/fatedier/frp/pkg/util/util" From f16ef0097565f4835fb1fd04074c9310fa22a30b Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 21 Mar 2024 17:34:09 +0800 Subject: [PATCH 10/10] set CompatibilityMode for android (#4091) --- Makefile.cross-compiles | 2 +- Release.md | 1 + cmd/frpc/main.go | 2 + cmd/frps/main.go | 5 +-- pkg/util/net/dns.go | 4 +- pkg/util/system/system.go | 22 +++++++++++ pkg/util/system/system_android.go | 66 +++++++++++++++++++++++++++++++ server/service.go | 2 + 8 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 pkg/util/system/system.go create mode 100644 pkg/util/system/system_android.go diff --git a/Makefile.cross-compiles b/Makefile.cross-compiles index 1040ef2c..8887cad4 100644 --- a/Makefile.cross-compiles +++ b/Makefile.cross-compiles @@ -2,7 +2,7 @@ export PATH := $(PATH):`go env GOPATH`/bin export GO111MODULE=on LDFLAGS := -s -w -os-archs=darwin:amd64 darwin:arm64 freebsd:amd64 linux:amd64 linux:arm linux:arm64 windows:amd64 windows:arm64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat linux:riscv64 +os-archs=darwin:amd64 darwin:arm64 freebsd:amd64 linux:amd64 linux:arm linux:arm64 windows:amd64 windows:arm64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat linux:riscv64 android:arm64 all: build diff --git a/Release.md b/Release.md index ca58a04d..9682800f 100644 --- a/Release.md +++ b/Release.md @@ -17,6 +17,7 @@ This will create 8 proxies such as `tcp-6000, tcp-6001, ... tcp-6007`. * Health check supports custom request headers. +* Enable compatibility mode for the Android system to solve the issues of incorrect log time caused by time zone problems and default DNS resolution failures. ### Fixes diff --git a/cmd/frpc/main.go b/cmd/frpc/main.go index f9a6c252..f7651bca 100644 --- a/cmd/frpc/main.go +++ b/cmd/frpc/main.go @@ -17,8 +17,10 @@ package main import ( _ "github.com/fatedier/frp/assets/frpc" "github.com/fatedier/frp/cmd/frpc/sub" + "github.com/fatedier/frp/pkg/util/system" ) func main() { + system.EnableCompatibilityMode() sub.Execute() } diff --git a/cmd/frps/main.go b/cmd/frps/main.go index 34676a2b..3cb398d8 100644 --- a/cmd/frps/main.go +++ b/cmd/frps/main.go @@ -15,13 +15,12 @@ package main import ( - "github.com/fatedier/golib/crypto" - _ "github.com/fatedier/frp/assets/frps" _ "github.com/fatedier/frp/pkg/metrics" + "github.com/fatedier/frp/pkg/util/system" ) func main() { - crypto.DefaultSalt = "frp" + system.EnableCompatibilityMode() Execute() } diff --git a/pkg/util/net/dns.go b/pkg/util/net/dns.go index 5e1d5ccb..441b1e67 100644 --- a/pkg/util/net/dns.go +++ b/pkg/util/net/dns.go @@ -26,8 +26,8 @@ func SetDefaultDNSAddress(dnsAddress string) { // 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) + Dial: func(ctx context.Context, network, _ string) (net.Conn, error) { + return net.Dial(network, dnsAddress) }, } } diff --git a/pkg/util/system/system.go b/pkg/util/system/system.go new file mode 100644 index 00000000..ae40e85e --- /dev/null +++ b/pkg/util/system/system.go @@ -0,0 +1,22 @@ +// Copyright 2024 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. + +//go:build !android + +package system + +// EnableCompatibilityMode enables compatibility mode for different system. +// For example, on Android, the inability to obtain the correct time zone will result in incorrect log time output. +func EnableCompatibilityMode() { +} diff --git a/pkg/util/system/system_android.go b/pkg/util/system/system_android.go new file mode 100644 index 00000000..bfcf401d --- /dev/null +++ b/pkg/util/system/system_android.go @@ -0,0 +1,66 @@ +// Copyright 2024 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 system + +import ( + "context" + "net" + "os/exec" + "strings" + "time" +) + +func EnableCompatibilityMode() { + fixTimezone() + fixDNSResolver() +} + +// fixTimezone is used to try our best to fix timezone issue on some Android devices. +func fixTimezone() { + out, err := exec.Command("/system/bin/getprop", "persist.sys.timezone").Output() + if err != nil { + return + } + loc, err := time.LoadLocation(strings.TrimSpace(string(out))) + if err != nil { + return + } + time.Local = loc +} + +// fixDNSResolver will first attempt to resolve google.com to check if the current DNS is available. +// If it is not available, it will default to using 8.8.8.8 as the DNS server. +// This is a workaround for the issue that golang can't get the default DNS servers on Android. +func fixDNSResolver() { + // First, we attempt to resolve a domain. If resolution is successful, no modifications are necessary. + // In real-world scenarios, users may have already configured /etc/resolv.conf, or compiled directly + // in the Android environment instead of using cross-platform compilation, so this issue does not arise. + if net.DefaultResolver != nil { + timeoutCtx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + _, err := net.DefaultResolver.LookupHost(timeoutCtx, "google.com") + if err == nil { + return + } + } + // If the resolution fails, use 8.8.8.8 as the DNS server. + // Note: If there are other methods to obtain the default DNS servers, the default DNS servers should be used preferentially. + net.DefaultResolver = &net.Resolver{ + PreferGo: true, + Dial: func(ctx context.Context, network, _ string) (net.Conn, error) { + return net.Dial(network, "8.8.8.8:53") + }, + } +} diff --git a/server/service.go b/server/service.go index 4fdb2166..325f7f6c 100644 --- a/server/service.go +++ b/server/service.go @@ -26,6 +26,7 @@ import ( "strconv" "time" + "github.com/fatedier/golib/crypto" "github.com/fatedier/golib/net/mux" fmux "github.com/hashicorp/yamux" quic "github.com/quic-go/quic-go" @@ -61,6 +62,7 @@ const ( ) func init() { + crypto.DefaultSalt = "frp" // Disable quic-go's receive buffer warning. os.Setenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING", "true") // Disable quic-go's ECN support by default. It may cause issues on certain operating systems.