Skip to content

Commit 4e8e9e1

Browse files
authored
Merge pull request #4205 from fatedier/dev
bump version
2 parents 8f23733 + 92cb0b3 commit 4e8e9e1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+493
-243
lines changed

.golangci.yml

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
service:
22
golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly
3-
3+
44
run:
55
concurrency: 4
66
# timeout for analysis, e.g. 30s, 5m, default is 1m
@@ -86,12 +86,8 @@ linters-settings:
8686
severity: "low"
8787
confidence: "low"
8888
excludes:
89-
- G102
90-
- G112
91-
- G306
9289
- G401
9390
- G402
94-
- G404
9591
- G501
9692

9793
issues:

Makefile.cross-compiles

+22-10
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,34 @@ export PATH := $(PATH):`go env GOPATH`/bin
22
export GO111MODULE=on
33
LDFLAGS := -s -w
44

5-
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
5+
os-archs=darwin:amd64 darwin:arm64 freebsd:amd64 linux:amd64 linux:arm:7 linux:arm:5 linux:arm64 windows:amd64 windows:arm64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat linux:riscv64 android:arm64
66

77
all: build
88

99
build: app
1010

1111
app:
12-
@$(foreach n, $(os-archs),\
13-
os=$(shell echo "$(n)" | cut -d : -f 1);\
14-
arch=$(shell echo "$(n)" | cut -d : -f 2);\
15-
gomips=$(shell echo "$(n)" | cut -d : -f 3);\
16-
target_suffix=$${os}_$${arch};\
17-
echo "Build $${os}-$${arch}...";\
18-
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} GOMIPS=$${gomips} go build -trimpath -ldflags "$(LDFLAGS)" -tags frpc -o ./release/frpc_$${target_suffix} ./cmd/frpc;\
19-
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} GOMIPS=$${gomips} go build -trimpath -ldflags "$(LDFLAGS)" -tags frps -o ./release/frps_$${target_suffix} ./cmd/frps;\
20-
echo "Build $${os}-$${arch} done";\
12+
@$(foreach n, $(os-archs), \
13+
os=$(shell echo "$(n)" | cut -d : -f 1); \
14+
arch=$(shell echo "$(n)" | cut -d : -f 2); \
15+
extra=$(shell echo "$(n)" | cut -d : -f 3); \
16+
flags=''; \
17+
target_suffix=$${os}_$${arch}; \
18+
if [ "$${os}" = "linux" ] && [ "$${arch}" = "arm" ] && [ "$${extra}" != "" ] ; then \
19+
if [ "$${extra}" = "7" ]; then \
20+
flags=GOARM=7; \
21+
target_suffix=$${os}_arm_hf; \
22+
elif [ "$${extra}" = "5" ]; then \
23+
flags=GOARM=5; \
24+
target_suffix=$${os}_arm; \
25+
fi; \
26+
elif [ "$${os}" = "linux" ] && ([ "$${arch}" = "mips" ] || [ "$${arch}" = "mipsle" ]) && [ "$${extra}" != "" ] ; then \
27+
flags=GOMIPS=$${extra}; \
28+
fi; \
29+
echo "Build $${os}-$${arch}$${extra:+ ($${extra})}..."; \
30+
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $${flags} go build -trimpath -ldflags "$(LDFLAGS)" -tags frpc -o ./release/frpc_$${target_suffix} ./cmd/frpc; \
31+
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $${flags} go build -trimpath -ldflags "$(LDFLAGS)" -tags frps -o ./release/frps_$${target_suffix} ./cmd/frps; \
32+
echo "Build $${os}-$${arch}$${extra:+ ($${extra})} done"; \
2133
)
2234
@mv ./release/frpc_windows_amd64 ./release/frpc_windows_amd64.exe
2335
@mv ./release/frps_windows_amd64 ./release/frps_windows_amd64.exe

README.md

+11-5
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ frp also offers a P2P connect mode.
8282
* [Client Plugins](#client-plugins)
8383
* [Server Manage Plugins](#server-manage-plugins)
8484
* [SSH Tunnel Gateway](#ssh-tunnel-gateway)
85+
* [Releated Projects](#releated-projects)
8586
* [Contributing](#contributing)
8687
* [Donation](#donation)
8788
* [GitHub Sponsors](#github-sponsors)
@@ -351,7 +352,6 @@ You may substitute `https2https` for the plugin, and point the `localAddr` to a
351352
# frpc.toml
352353
serverAddr = "x.x.x.x"
353354
serverPort = 7000
354-
vhostHTTPSPort = 443
355355

356356
[[proxies]]
357357
name = "test_https2http"
@@ -804,7 +804,7 @@ You can disable this feature by modify `frps.toml` and `frpc.toml`:
804804

805805
```toml
806806
# frps.toml and frpc.toml, must be same
807-
tcpMux = false
807+
transport.tcpMux = false
808808
```
809809

810810
### Support KCP Protocol
@@ -983,7 +983,7 @@ The HTTP request will have the `Host` header rewritten to `Host: dev.example.com
983983

984984
### Setting other HTTP Headers
985985

986-
Similar to `Host`, You can override other HTTP request headers with proxy type `http`.
986+
Similar to `Host`, You can override other HTTP request and response headers with proxy type `http`.
987987

988988
```toml
989989
# frpc.toml
@@ -995,15 +995,16 @@ localPort = 80
995995
customDomains = ["test.example.com"]
996996
hostHeaderRewrite = "dev.example.com"
997997
requestHeaders.set.x-from-where = "frp"
998+
responseHeaders.set.foo = "bar"
998999
```
9991000

1000-
In this example, it will set header `x-from-where: frp` in the HTTP request.
1001+
In this example, it will set header `x-from-where: frp` in the HTTP request and `foo: bar` in the HTTP response.
10011002

10021003
### Get Real IP
10031004

10041005
#### HTTP X-Forwarded-For
10051006

1006-
This feature is for http proxy only.
1007+
This feature is for `http` proxies or proxies with the `https2http` and `https2https` plugins enabled.
10071008

10081009
You can get user's real IP from HTTP request headers `X-Forwarded-For`.
10091010

@@ -1244,6 +1245,11 @@ frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote
12441245

12451246
Please refer to this [document](/doc/ssh_tunnel_gateway.md) for more information.
12461247

1248+
## Releated Projects
1249+
1250+
* [gofrp/plugin](https://github.com/gofrp/plugin) - A repository for frp plugins that contains a variety of plugins implemented based on the frp extension mechanism, meeting the customization needs of different scenarios.
1251+
* [gofrp/tiny-frpc](https://github.com/gofrp/tiny-frpc) - A lightweight version of the frp client (around 3.5MB at minimum) implemented using the ssh protocol, supporting some of the most commonly used features, suitable for devices with limited resources.
1252+
12471253
## Contributing
12481254

12491255
Interested in getting involved? We would like to help you!

README_zh.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进
7272
* 贡献代码请提交 PR 至 dev 分支,master 分支仅用于发布稳定可用版本。
7373
* 如果你有任何其他方面的问题或合作,欢迎发送邮件至 [email protected]
7474

75-
**提醒:和项目相关的问题最好在 [issues](https://github.com/fatedier/frp/issues) 中反馈,这样方便其他有类似问题的人可以快速查找解决方法,并且也避免了我们重复回答一些问题。**
75+
**提醒:和项目相关的问题请在 [issues](https://github.com/fatedier/frp/issues) 中反馈,这样方便其他有类似问题的人可以快速查找解决方法,并且也避免了我们重复回答一些问题。**
76+
77+
## 关联项目
78+
79+
* [gofrp/plugin](https://github.com/gofrp/plugin) - frp 插件仓库,收录了基于 frp 扩展机制实现的各种插件,满足各种场景下的定制化需求。
80+
* [gofrp/tiny-frpc](https://github.com/gofrp/tiny-frpc) - 基于 ssh 协议实现的 frp 客户端的精简版本(最低约 3.5MB 左右),支持常用的部分功能,适用于资源有限的设备。
7681

7782
## 赞助
7883

@@ -93,7 +98,3 @@ frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进
9398
如果您想了解更多 frp 相关技术以及更新详解,或者寻求任何 frp 使用方面的帮助,都可以通过微信扫描下方的二维码付费加入知识星球的官方社群:
9499

95100
![zsxq](/doc/pic/zsxq.jpg)
96-
97-
### 微信支付捐赠
98-
99-
![donate-wechatpay](/doc/pic/donate-wechatpay.png)

Release.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
### Notable Changes
2+
3+
We have optimized the heartbeat mechanism when tcpmux is enabled (enabled by default). The default value of `heartbeatInterval` has been adjusted to -1. This update ensures that when tcpmux is active, the client does not send additional heartbeats to the server. Since tcpmux incorporates its own heartbeat system, this change effectively reduces unnecessary data consumption, streamlining communication efficiency between client and server.
4+
5+
When connecting to frps versions older than v0.39.0 might encounter compatibility issues due to changes in the heartbeat mechanism. As a temporary workaround, setting the `heartbeatInterval` to 30 can help maintain stable connectivity with these older versions. We recommend updating to the latest frps version to leverage full functionality and improvements.
6+
17
### Features
28

3-
* `https2http` and `https2https` plugin now supports `X-Forwared-For` header.
9+
* Show tcpmux proxies on the frps dashboard.
10+
* `http` proxy can modify the response header. For example, `responseHeaders.set.foo = "bar"` will add a new header `foo: bar` to the response.
411

512
### Fixes
613

7-
* `X-Forwared-For` header is now correctly set in the request to the backend server for proxy type http.
14+
* When an HTTP proxy request times out, it returns 504 instead of 404 now.

assets/frps/static/index-Q42Pu2_S.js assets/frps/static/index-82-40HIG.js

+16-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/frps/static/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<head>
55
<meta charset="utf-8">
66
<title>frps dashboard</title>
7-
<script type="module" crossorigin src="./index-Q42Pu2_S.js"></script>
7+
<script type="module" crossorigin src="./index-82-40HIG.js"></script>
88
<link rel="stylesheet" crossorigin href="./index-rzPDshRD.css">
99
</head>
1010

client/admin_api.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
253253
return
254254
}
255255

256-
if err := os.WriteFile(svr.configFilePath, body, 0o644); err != nil {
256+
if err := os.WriteFile(svr.configFilePath, body, 0o600); err != nil {
257257
res.Code = 500
258258
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)
259259
log.Warnf("%s", res.Msg)

client/connector.go

+17-17
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
"sync"
2525
"time"
2626

27-
libdial "github.com/fatedier/golib/net/dial"
27+
libnet "github.com/fatedier/golib/net"
2828
fmux "github.com/hashicorp/yamux"
2929
quic "github.com/quic-go/quic-go"
3030
"github.com/samber/lo"
@@ -169,44 +169,44 @@ func (c *defaultConnectorImpl) realConnect() (net.Conn, error) {
169169
}
170170
}
171171

172-
proxyType, addr, auth, err := libdial.ParseProxyURL(c.cfg.Transport.ProxyURL)
172+
proxyType, addr, auth, err := libnet.ParseProxyURL(c.cfg.Transport.ProxyURL)
173173
if err != nil {
174174
xl.Errorf("fail to parse proxy url")
175175
return nil, err
176176
}
177-
dialOptions := []libdial.DialOption{}
177+
dialOptions := []libnet.DialOption{}
178178
protocol := c.cfg.Transport.Protocol
179179
switch protocol {
180180
case "websocket":
181181
protocol = "tcp"
182-
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, "")}))
183-
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
182+
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, "")}))
183+
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{
184184
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
185185
}))
186-
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
186+
dialOptions = append(dialOptions, libnet.WithTLSConfig(tlsConfig))
187187
case "wss":
188188
protocol = "tcp"
189-
dialOptions = append(dialOptions, libdial.WithTLSConfigAndPriority(100, tlsConfig))
189+
dialOptions = append(dialOptions, libnet.WithTLSConfigAndPriority(100, tlsConfig))
190190
// Make sure that if it is wss, the websocket hook is executed after the tls hook.
191-
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
191+
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
192192
default:
193-
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
193+
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{
194194
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
195195
}))
196-
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
196+
dialOptions = append(dialOptions, libnet.WithTLSConfig(tlsConfig))
197197
}
198198

199199
if c.cfg.Transport.ConnectServerLocalIP != "" {
200-
dialOptions = append(dialOptions, libdial.WithLocalAddr(c.cfg.Transport.ConnectServerLocalIP))
200+
dialOptions = append(dialOptions, libnet.WithLocalAddr(c.cfg.Transport.ConnectServerLocalIP))
201201
}
202202
dialOptions = append(dialOptions,
203-
libdial.WithProtocol(protocol),
204-
libdial.WithTimeout(time.Duration(c.cfg.Transport.DialServerTimeout)*time.Second),
205-
libdial.WithKeepAlive(time.Duration(c.cfg.Transport.DialServerKeepAlive)*time.Second),
206-
libdial.WithProxy(proxyType, addr),
207-
libdial.WithProxyAuth(auth),
203+
libnet.WithProtocol(protocol),
204+
libnet.WithTimeout(time.Duration(c.cfg.Transport.DialServerTimeout)*time.Second),
205+
libnet.WithKeepAlive(time.Duration(c.cfg.Transport.DialServerKeepAlive)*time.Second),
206+
libnet.WithProxy(proxyType, addr),
207+
libnet.WithProxyAuth(auth),
208208
)
209-
conn, err := libdial.DialContext(
209+
conn, err := libnet.DialContext(
210210
c.ctx,
211211
net.JoinHostPort(c.cfg.ServerAddr, strconv.Itoa(c.cfg.ServerPort)),
212212
dialOptions...,

client/control.go

+3-9
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import (
2020
"sync/atomic"
2121
"time"
2222

23-
"github.com/samber/lo"
24-
2523
"github.com/fatedier/frp/client/proxy"
2624
"github.com/fatedier/frp/client/visitor"
2725
"github.com/fatedier/frp/pkg/auth"
@@ -236,10 +234,8 @@ func (ctl *Control) registerMsgHandlers() {
236234
func (ctl *Control) heartbeatWorker() {
237235
xl := ctl.xl
238236

239-
// TODO(fatedier): Change default value of HeartbeatInterval to -1 if tcpmux is enabled.
240-
// Users can still enable heartbeat feature by setting HeartbeatInterval to a positive value.
241237
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 {
242-
// send heartbeat to server
238+
// Send heartbeat to server.
243239
sendHeartBeat := func() (bool, error) {
244240
xl.Debugf("send heartbeat to server")
245241
pingMsg := &msg.Ping{}
@@ -263,10 +259,8 @@ func (ctl *Control) heartbeatWorker() {
263259
)
264260
}
265261

266-
// Check heartbeat timeout only if TCPMux is not enabled and users don't disable heartbeat feature.
267-
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 && ctl.sessionCtx.Common.Transport.HeartbeatTimeout > 0 &&
268-
!lo.FromPtr(ctl.sessionCtx.Common.Transport.TCPMux) {
269-
262+
// Check heartbeat timeout.
263+
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 && ctl.sessionCtx.Common.Transport.HeartbeatTimeout > 0 {
270264
go wait.Until(func() {
271265
if time.Since(ctl.lastPong.Load().(time.Time)) > time.Duration(ctl.sessionCtx.Common.Transport.HeartbeatTimeout)*time.Second {
272266
xl.Warnf("heartbeat timeout")

client/proxy/proxy.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
"time"
2626

2727
libio "github.com/fatedier/golib/io"
28-
libdial "github.com/fatedier/golib/net/dial"
28+
libnet "github.com/fatedier/golib/net"
2929
pp "github.com/pires/go-proxyproto"
3030
"golang.org/x/time/rate"
3131

@@ -197,9 +197,9 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
197197
return
198198
}
199199

200-
localConn, err := libdial.Dial(
200+
localConn, err := libnet.Dial(
201201
net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort)),
202-
libdial.WithTimeout(10*time.Second),
202+
libnet.WithTimeout(10*time.Second),
203203
)
204204
if err != nil {
205205
workConn.Close()

client/service.go

+20-7
Original file line numberDiff line numberDiff line change
@@ -380,18 +380,31 @@ func (svr *Service) stop() {
380380
}
381381
}
382382

383-
// TODO(fatedier): Use StatusExporter to provide query interfaces instead of directly using methods from the Service.
384-
func (svr *Service) GetProxyStatus(name string) (*proxy.WorkingStatus, error) {
383+
func (svr *Service) getProxyStatus(name string) (*proxy.WorkingStatus, bool) {
385384
svr.ctlMu.RLock()
386385
ctl := svr.ctl
387386
svr.ctlMu.RUnlock()
388387

389388
if ctl == nil {
390-
return nil, fmt.Errorf("control is not running")
389+
return nil, false
391390
}
392-
ws, ok := ctl.pm.GetProxyStatus(name)
393-
if !ok {
394-
return nil, fmt.Errorf("proxy [%s] is not found", name)
391+
return ctl.pm.GetProxyStatus(name)
392+
}
393+
394+
func (svr *Service) StatusExporter() StatusExporter {
395+
return &statusExporterImpl{
396+
getProxyStatusFunc: svr.getProxyStatus,
395397
}
396-
return ws, nil
398+
}
399+
400+
type StatusExporter interface {
401+
GetProxyStatus(name string) (*proxy.WorkingStatus, bool)
402+
}
403+
404+
type statusExporterImpl struct {
405+
getProxyStatusFunc func(name string) (*proxy.WorkingStatus, bool)
406+
}
407+
408+
func (s *statusExporterImpl) GetProxyStatus(name string) (*proxy.WorkingStatus, bool) {
409+
return s.getProxyStatusFunc(name)
397410
}

conf/frpc_full_example.toml

+1
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ locations = ["/", "/pic"]
209209
# routeByHTTPUser = abc
210210
hostHeaderRewrite = "example.com"
211211
requestHeaders.set.x-from-where = "frp"
212+
responseHeaders.set.foo = "bar"
212213
healthCheck.type = "http"
213214
# frpc will send a GET http request '/status' to local http service
214215
# http service is alive when it return 2xx http response code

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ go 1.22
55
require (
66
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
77
github.com/coreos/go-oidc/v3 v3.10.0
8-
github.com/fatedier/golib v0.4.2
8+
github.com/fatedier/golib v0.5.0
99
github.com/google/uuid v1.6.0
1010
github.com/gorilla/mux v1.8.1
11-
github.com/gorilla/websocket v1.5.1
11+
github.com/gorilla/websocket v1.5.0
1212
github.com/hashicorp/yamux v0.1.1
1313
github.com/onsi/ginkgo/v2 v2.17.1
1414
github.com/onsi/gomega v1.32.0
@@ -35,7 +35,7 @@ require (
3535
)
3636

3737
require (
38-
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
38+
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
3939
github.com/beorn7/perks v1.0.1 // indirect
4040
github.com/cespare/xxhash/v2 v2.2.0 // indirect
4141
github.com/davecgh/go-spew v1.1.1 // indirect

0 commit comments

Comments
 (0)