Compare commits

...

14 Commits

Author SHA1 Message Date
fatedier
c9ca9353cf Merge pull request #3714 from fatedier/dev
bump version
2023-10-23 10:51:50 +08:00
fatedier
496b1f1078 remove configuration files in release assets (#3713) 2023-10-23 10:47:59 +08:00
fatedier
9cb0726ebc fix example config (#3701) 2023-10-19 17:28:35 +08:00
fatedier
31190c703d fix doc link (#3694) 2023-10-19 11:22:40 +08:00
fatedier
1452facf77 README typo (#3683) 2023-10-16 11:29:51 +08:00
fatedier
6d4d8e616d fix encryption and compresion in dashboard (#3682) 2023-10-16 11:22:12 +08:00
fatedier
a7ad967231 update README (#3670) 2023-10-12 19:57:59 +08:00
fatedier
31fa3f021a Merge pull request #3668 from fatedier/dev
bump version to v0.52.1
2023-10-11 17:16:07 +08:00
fatedier
01a0d557ef fix legacy ini proxy conversion panic (#3667) 2023-10-11 16:53:03 +08:00
fatedier
b9c24e9b69 natHoleSTUNServer set default value (#3664) 2023-10-11 15:46:22 +08:00
fatedier
df12cc2b9d fix broken server api and dashboard info (#3662) 2023-10-11 15:01:07 +08:00
fatedier
7cc67e852e fix that transport.tls.disableCustomTLSFirstByte doesn't take effect (#3660) 2023-10-11 11:49:40 +08:00
沈鸿飞
307d1bfa3f Fix log.level configuration in frps.toml (#3655)
```toml
log.level = info
```
changed to
```toml
log.level = "info"
```
2023-10-10 19:45:33 +08:00
fatedier
5eb8f3db03 fix tlsVerify json tag (#3654) 2023-10-10 19:02:52 +08:00
30 changed files with 281 additions and 271 deletions

View File

@@ -91,8 +91,6 @@ We will transition from version 0 to version 1 at the appropriate time and will
### About V2 ### About V2
The overall situation is currently unfavorable, and there is significant pressure in both personal and professional aspects.
The complexity and difficulty of the v2 version are much higher than anticipated. I can only work on its development during fragmented time periods, and the constant interruptions disrupt productivity significantly. Given this situation, we will continue to optimize and iterate on the current version until we have more free time to proceed with the major version overhaul. The complexity and difficulty of the v2 version are much higher than anticipated. I can only work on its development during fragmented time periods, and the constant interruptions disrupt productivity significantly. Given this situation, we will continue to optimize and iterate on the current version until we have more free time to proceed with the major version overhaul.
The concept behind v2 is based on my years of experience and reflection in the cloud-native domain, particularly in K8s and ServiceMesh. Its core is a modernized four-layer and seven-layer proxy, similar to envoy. This proxy itself is highly scalable, not only capable of implementing the functionality of intranet penetration but also applicable to various other domains. Building upon this highly scalable core, we aim to implement all the capabilities of frp v1 while also addressing the functionalities that were previously unachievable or difficult to implement in an elegant manner. Furthermore, we will maintain efficient development and iteration capabilities. The concept behind v2 is based on my years of experience and reflection in the cloud-native domain, particularly in K8s and ServiceMesh. Its core is a modernized four-layer and seven-layer proxy, similar to envoy. This proxy itself is highly scalable, not only capable of implementing the functionality of intranet penetration but also applicable to various other domains. Building upon this highly scalable core, we aim to implement all the capabilities of frp v1 while also addressing the functionalities that were previously unachievable or difficult to implement in an elegant manner. Furthermore, we will maintain efficient development and iteration capabilities.
@@ -218,7 +216,7 @@ Unfortunately, we cannot resolve a domain name to a local IP. However, we can us
vhostHTTPPort = 8080 vhostHTTPPort = 8080
``` ```
If you want to configure an https proxy, you need to set up the `vhost_https_port`. If you want to configure an https proxy, you need to set up the `vhostHTTPSPort`.
2. Start `frps`: 2. Start `frps`:
@@ -337,7 +335,7 @@ Configure `frps` as described above, then:
### Enable HTTPS for a local HTTP(S) service ### Enable HTTPS for a local HTTP(S) service
You may substitute `https2https` for the plugin, and point the `plugin_local_addr` to a HTTPS endpoint. You may substitute `https2https` for the plugin, and point the `localAddr` to a HTTPS endpoint.
1. Start `frpc` with the following configuration: 1. Start `frpc` with the following configuration:
@@ -369,7 +367,7 @@ To mitigate risks associated with exposing certain services directly to the publ
Configure `frps` same as above. Configure `frps` same as above.
1. Start `frpc` on machine B with the following config. This example is for exposing the SSH service (port 22), and note the `sk` field for the preshared key, and that the `remote_port` field is removed here: 1. Start `frpc` on machine B with the following config. This example is for exposing the SSH service (port 22), and note the `secretKey` field for the preshared key, and that the `remotePort` field is removed here:
```toml ```toml
# frpc.toml # frpc.toml
@@ -384,7 +382,7 @@ Configure `frps` same as above.
localPort = 22 localPort = 22
``` ```
2. Start another `frpc` (typically on another machine C) with the following config to access the SSH service with a security key (`sk` field): 2. Start another `frpc` (typically on another machine C) with the following config to access the SSH service with a security key (`secretKey` field):
```toml ```toml
# frpc.toml # frpc.toml
@@ -526,7 +524,7 @@ webServer.user = "admin"
webServer.password = "admin" webServer.password = "admin"
``` ```
Then visit `http://[server_addr]:7500` to see the dashboard, with username and password both being `admin`. Then visit `http://[serverAddr]:7500` to see the dashboard, with username and password both being `admin`.
Additionally, you can use HTTPS port by using your domains wildcard or normal SSL certificate: Additionally, you can use HTTPS port by using your domains wildcard or normal SSL certificate:
@@ -539,7 +537,7 @@ webServer.tls.certFile = "server.crt"
webServer.tls.keyFile = "server.key" webServer.tls.keyFile = "server.key"
``` ```
Then visit `https://[server_addr]:7500` to see the dashboard in secure HTTPS connection, with username and password both being `admin`. Then visit `https://[serverAddr]:7500` to see the dashboard in secure HTTPS connection, with username and password both being `admin`.
![dashboard](/doc/pic/dashboard.png) ![dashboard](/doc/pic/dashboard.png)
@@ -761,6 +759,8 @@ allowPorts = [
`vhostHTTPPort` and `vhostHTTPSPort` in frps can use same port with `bindPort`. frps will detect the connection's protocol and handle it correspondingly. `vhostHTTPPort` and `vhostHTTPSPort` in frps can use same port with `bindPort`. frps will detect the connection's protocol and handle it correspondingly.
What you need to pay attention to is that if you want to configure `vhostHTTPSPort` and `bindPort` to the same port, you need to first set `transport.tls.disableCustomTLSFirstByte` to false.
We would like to try to allow multiple proxies bind a same remote port with different protocols in the future. We would like to try to allow multiple proxies bind a same remote port with different protocols in the future.
### Bandwidth Limit ### Bandwidth Limit
@@ -834,7 +834,7 @@ Using QUIC in frp:
quicBindPort = 7000 quicBindPort = 7000
``` ```
The `quicBindPort` number can be the same number as `bind_port`, since `bind_port` field specifies a TCP port. The `quicBindPort` number can be the same number as `bindPort`, since `bindPort` field specifies a TCP port.
2. Configure `frpc.toml` to use QUIC to connect to frps: 2. Configure `frpc.toml` to use QUIC to connect to frps:

View File

@@ -41,9 +41,7 @@ master 分支用于发布稳定版本dev 分支用于开发,您可以尝试
### 关于 v2 的一些说明 ### 关于 v2 的一些说明
当前整体形势不佳,面临的生活工作压力很大 v2 版本的复杂度和难度比我们预期的要高得多。我只能利用零散的时间进行开发,而且由于上下文经常被打断,效率极低。由于这种情况可能会持续一段时间,我们仍然会在当前版本上进行一些优化和迭代,直到我们有更多空闲时间来推进大版本的重构,或者也有可能放弃一次性的重构,而是采用渐进的方式在当前版本上逐步做一些可能会导致不兼容的修改
v2 版本的复杂度和难度比我们预期的要高得多。我只能利用零散的时间进行开发,而且由于上下文经常被打断,效率极低。由于这种情况可能会持续一段时间,我们仍然会在当前版本上进行一些优化和迭代,直到我们有更多空闲时间来推进大版本的重构。
v2 的构想是基于我多年在云原生领域,特别是在 K8s 和 ServiceMesh 方面的工作经验和思考。它的核心是一个现代化的四层和七层代理,类似于 envoy。这个代理本身高度可扩展不仅可以用于实现内网穿透的功能还可以应用于更多领域。在这个高度可扩展的内核基础上我们将实现 frp v1 中的所有功能,并且能够以一种更加优雅的方式实现原先架构中无法实现或不易实现的功能。同时,我们将保持高效的开发和迭代能力。 v2 的构想是基于我多年在云原生领域,特别是在 K8s 和 ServiceMesh 方面的工作经验和思考。它的核心是一个现代化的四层和七层代理,类似于 envoy。这个代理本身高度可扩展不仅可以用于实现内网穿透的功能还可以应用于更多领域。在这个高度可扩展的内核基础上我们将实现 frp v1 中的所有功能,并且能够以一种更加优雅的方式实现原先架构中无法实现或不易实现的功能。同时,我们将保持高效的开发和迭代能力。
@@ -55,7 +53,7 @@ v2 的构想是基于我多年在云原生领域,特别是在 K8s 和 ServiceM
## 文档 ## 文档
完整文档已经迁移至 [https://gofrp.org](https://gofrp.org/docs)。 完整文档已经迁移至 [https://gofrp.org](https://gofrp.org)。
## 为 frp 做贡献 ## 为 frp 做贡献

View File

@@ -1,9 +1,3 @@
### Features ### Fixes
* 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 * Encryption and compression are not displayed correctly in the dashboard.
### 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.
* No longer support range ports mapping in TOML/YAML/JSON.

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>frps dashboard</title> <title>frps dashboard</title>
<script type="module" crossorigin src="./index-ea3edf22.js"></script> <script type="module" crossorigin src="./index-c322b7dd.js"></script>
<link rel="stylesheet" href="./index-1e0c7400.css"> <link rel="stylesheet" href="./index-1e0c7400.css">
</head> </head>

View File

@@ -476,6 +476,9 @@ func (cm *ConnectionManager) realConnect() (net.Conn, error) {
// Make sure that if it is wss, the websocket hook is executed after the tls hook. // Make sure that if it is wss, the websocket hook is executed after the tls hook.
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: utilnet.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110})) dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: utilnet.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
default: default:
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
Hook: utilnet.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(cm.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
}))
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig)) dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
} }

View File

@@ -1,3 +1,5 @@
# This configuration file is for reference only. Please do not use this configuration directly to run the program as it may have various issues.
# your proxy name will be changed to {user}.{proxy} # your proxy name will be changed to {user}.{proxy}
user = "your_name" user = "your_name"
@@ -36,7 +38,7 @@ auth.token = "12345678"
# auth.oidc.clientSecret = "" # auth.oidc.clientSecret = ""
# oidc.audience specifies the audience of the token in OIDC authentication. # oidc.audience specifies the audience of the token in OIDC authentication.
# auth.oidc.audience = "" # auth.oidc.audience = ""
# oidc_scope specifies the permisssions of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "". # oidc.scope specifies the permisssions of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
# auth.oidc.scope = "" # auth.oidc.scope = ""
# oidc.tokenEndpointURL specifies the URL which implements OIDC Token Endpoint. # oidc.tokenEndpointURL specifies the URL which implements OIDC Token Endpoint.
# It will be used to get an OIDC token. # It will be used to get an OIDC token.
@@ -110,7 +112,7 @@ transport.tls.enable = true
# transport.tls.disableCustomTLSFirstByte = true # transport.tls.disableCustomTLSFirstByte = true
# Heartbeat configure, it's not recommended to modify the default value. # Heartbeat configure, it's not recommended to modify the default value.
# The default value of heartbeat_interval is 10 and heartbeat_timeout is 90. Set negative value # The default value of heartbeatInterval is 10 and heartbeatTimeout is 90. Set negative value
# to disable it. # to disable it.
# transport.heartbeatInterval = 30 # transport.heartbeatInterval = 30
# transport.heartbeatTimeout = 90 # transport.heartbeatTimeout = 90
@@ -173,7 +175,7 @@ name = "ssh_random"
type = "tcp" type = "tcp"
localIP = "192.168.31.100" localIP = "192.168.31.100"
localPort = 22 localPort = 22
# If remote_port is 0, frps will assign a random port for you # If remotePort is 0, frps will assign a random port for you
remotePort = 0 remotePort = 0
[[proxies]] [[proxies]]
@@ -183,14 +185,14 @@ localIP = "114.114.114.114"
localPort = 53 localPort = 53
remotePort = 6002 remotePort = 6002
# Resolve your domain names to [server_addr] so you can use http://web01.yourdomain.com to browse web01 and http://web02.yourdomain.com to browse web02 # Resolve your domain names to [serverAddr] so you can use http://web01.yourdomain.com to browse web01 and http://web02.yourdomain.com to browse web02
[[proxies]] [[proxies]]
name = "web01" name = "web01"
type = "http" type = "http"
localIP = "127.0.0.1" localIP = "127.0.0.1"
localPort = 80 localPort = 80
# http username and password are safety certification for http protocol # http username and password are safety certification for http protocol
# if not set, you can access this custom_domains without certification # if not set, you can access this customDomains without certification
httpUser = "admin" httpUser = "admin"
httpPassword = "admin" httpPassword = "admin"
# if domain for frps is frps.com, then you can access [web01] proxy by URL http://web01.frps.com # if domain for frps is frps.com, then you can access [web01] proxy by URL http://web01.frps.com
@@ -199,9 +201,8 @@ customDomains = ["web01.yourdomain.com"]
# locations is only available for http type # locations is only available for http type
locations = ["/", "/pic"] locations = ["/", "/pic"]
# route requests to this service if http basic auto user is abc # route requests to this service if http basic auto user is abc
# route_by_http_user = abc # routeByHTTPUser = abc
hostHeaderRewrite = "example.com" hostHeaderRewrite = "example.com"
# params with prefix "header_" will be used to update http request headers
requestHeaders.set.x-from-where = "frp" requestHeaders.set.x-from-where = "frp"
healthCheck.type = "http" healthCheck.type = "http"
# frpc will send a GET http request '/status' to local http service # frpc will send a GET http request '/status' to local http service
@@ -235,7 +236,7 @@ customDomains = ["tunnel1"]
name = "plugin_unix_domain_socket" name = "plugin_unix_domain_socket"
type = "tcp" type = "tcp"
remotePort = 6003 remotePort = 6003
# if plugin is defined, local_ip and local_port is useless # if plugin is defined, localIP and localPort is useless
# plugin will handle connections got from frps # plugin will handle connections got from frps
[proxies.plugin] [proxies.plugin]
type = "unix_domain_socket" type = "unix_domain_socket"
@@ -306,7 +307,7 @@ requestHeaders.set.x-from-where = "frp"
[[proxies]] [[proxies]]
name = "secret_tcp" name = "secret_tcp"
# If the type is secret tcp, remote_port is useless # If the type is secret tcp, remotePort is useless
# Who want to connect local port should deploy another frpc with stcp proxy and role is visitor # Who want to connect local port should deploy another frpc with stcp proxy and role is visitor
type = "stcp" type = "stcp"
# secretKey is used for authentication for visitors # secretKey is used for authentication for visitors
@@ -353,7 +354,7 @@ bindAddr = "127.0.0.1"
bindPort = 9001 bindPort = 9001
# when automatic tunnel persistence is required, set it to true # when automatic tunnel persistence is required, set it to true
keepTunnelOpen = false keepTunnelOpen = false
# effective when keep_tunnel_open is set to true, the number of attempts to punch through per hour # effective when keepTunnelOpen is set to true, the number of attempts to punch through per hour
maxRetriesAnHour = 8 maxRetriesAnHour = 8
minRetryInterval = 90 minRetryInterval = 90
# fallbackTo = "stcp_visitor" # fallbackTo = "stcp_visitor"

View File

@@ -1,10 +1,12 @@
# This configuration file is for reference only. Please do not use this configuration directly to run the program as it may have various issues.
# A literal address or host name for IPv6 must be enclosed # A literal address or host name for IPv6 must be enclosed
# in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80" # in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80"
# For single "bind_addr" field, no need square brackets, like "bind_addr = ::". # For single "bindAddr" field, no need square brackets, like `bindAddr = "::"`.
bindAddr = "0.0.0.0" bindAddr = "0.0.0.0"
bindPort = 7000 bindPort = 7000
# udp port used for kcp protocol, it can be same with 'bind_port'. # udp port used for kcp protocol, it can be same with 'bindPort'.
# if not set, kcp is disabled in frps. # if not set, kcp is disabled in frps.
kcpBindPort = 7000 kcpBindPort = 7000
@@ -12,8 +14,8 @@ kcpBindPort = 7000
# if not set, quic is disabled in frps. # if not set, quic is disabled in frps.
# quicBindPort = 7002 # quicBindPort = 7002
# Specify which address proxy will listen for, default value is same with bind_addr # Specify which address proxy will listen for, default value is same with bindAddr
# proxy_bind_addr = "127.0.0.1" # proxyBindAddr = "127.0.0.1"
# quic protocol options # quic protocol options
# transport.quic.keepalivePeriod = 10 # transport.quic.keepalivePeriod = 10
@@ -21,7 +23,7 @@ kcpBindPort = 7000
# transport.quic.maxIncomingStreams = 100000 # transport.quic.maxIncomingStreams = 100000
# Heartbeat configure, it's not recommended to modify the default value # Heartbeat configure, it's not recommended to modify the default value
# The default value of heartbeat_timeout is 90. Set negative value to disable it. # The default value of heartbeatTimeout is 90. Set negative value to disable it.
# transport.heartbeatTimeout = 90 # transport.heartbeatTimeout = 90
# Pool count in each proxy will keep no more than maxPoolCount. # Pool count in each proxy will keep no more than maxPoolCount.
@@ -46,7 +48,7 @@ tls.force = false
# transport.tls.trustedCaFile = "ca.crt" # transport.tls.trustedCaFile = "ca.crt"
# If you want to support virtual host, you must set the http port for listening (optional) # If you want to support virtual host, you must set the http port for listening (optional)
# Note: http port and https port can be same with bind_port # Note: http port and https port can be same with bindPort
vhostHTTPPort = 80 vhostHTTPPort = 80
vhostHTTPSPort = 443 vhostHTTPSPort = 443
@@ -59,7 +61,7 @@ vhostHTTPSPort = 443
# HTTP CONNECT requests. By default, this value is 0. # HTTP CONNECT requests. By default, this value is 0.
# tcpmuxHTTPConnectPort = 1337 # tcpmuxHTTPConnectPort = 1337
# If tcpmux_passthrough is true, frps won't do any update on traffic. # If tcpmuxPassthrough is true, frps won't do any update on traffic.
# tcpmuxPassthrough = false # tcpmuxPassthrough = false
# Configure the web server to enable the dashboard for frps. # Configure the web server to enable the dashboard for frps.
@@ -83,7 +85,7 @@ enablePrometheus = true
# console or real logFile path like ./frps.log # console or real logFile path like ./frps.log
log.to = "./frps.log" log.to = "./frps.log"
# trace, debug, info, warn, error # trace, debug, info, warn, error
log.level = info log.level = "info"
log.maxDays = 3 log.maxDays = 3
# disable log colors when log.to is console, default is false # disable log colors when log.to is console, default is false
log.disablePrintColor = false log.disablePrintColor = false

View File

@@ -46,8 +46,6 @@ for os in $os_all; do
mv ./frps_${os}_${arch} ${frp_path}/frps mv ./frps_${os}_${arch} ${frp_path}/frps
fi fi
cp ../LICENSE ${frp_path} cp ../LICENSE ${frp_path}
cp -rf ../conf/* ${frp_path}
rm -rf ${frp_path}/legacy
# packages # packages
cd ./packages cd ./packages

View File

@@ -306,6 +306,7 @@ func Convert_ProxyConf_To_v1(conf ProxyConf) v1.ProxyConfigurer {
c := &v1.XTCPProxyConfig{ProxyBaseConfig: *outBase} c := &v1.XTCPProxyConfig{ProxyBaseConfig: *outBase}
c.Secretkey = v.Sk c.Secretkey = v.Sk
c.AllowUsers = v.AllowUsers c.AllowUsers = v.AllowUsers
out = c
} }
return out return out
} }

View File

@@ -27,7 +27,7 @@ type HTTPPluginOptions struct {
Addr string `ini:"addr"` Addr string `ini:"addr"`
Path string `ini:"path"` Path string `ini:"path"`
Ops []string `ini:"ops"` Ops []string `ini:"ops"`
TLSVerify bool `ini:"tls_verify"` TLSVerify bool `ini:"tlsVerify"`
} }
// ServerCommonConf contains information for a server service. It is // ServerCommonConf contains information for a server service. It is

View File

@@ -76,6 +76,7 @@ func (c *ClientCommonConfig) Complete() {
c.ServerAddr = util.EmptyOr(c.ServerAddr, "0.0.0.0") c.ServerAddr = util.EmptyOr(c.ServerAddr, "0.0.0.0")
c.ServerPort = util.EmptyOr(c.ServerPort, 7000) c.ServerPort = util.EmptyOr(c.ServerPort, 7000)
c.LoginFailExit = util.EmptyOr(c.LoginFailExit, lo.ToPtr(true)) c.LoginFailExit = util.EmptyOr(c.LoginFailExit, lo.ToPtr(true))
c.NatHoleSTUNServer = util.EmptyOr(c.NatHoleSTUNServer, "stun.easyvoip.com:3478")
c.Auth.Complete() c.Auth.Complete()
c.Log.Complete() c.Log.Complete()

View File

@@ -31,4 +31,5 @@ func TestClientConfigComplete(t *testing.T) {
require.Equal(true, lo.FromPtr(c.LoginFailExit)) require.Equal(true, lo.FromPtr(c.LoginFailExit))
require.Equal(true, lo.FromPtr(c.Transport.TLS.Enable)) require.Equal(true, lo.FromPtr(c.Transport.TLS.Enable))
require.Equal(true, lo.FromPtr(c.Transport.TLS.DisableCustomTLSFirstByte)) require.Equal(true, lo.FromPtr(c.Transport.TLS.DisableCustomTLSFirstByte))
require.NotEmpty(c.NatHoleSTUNServer)
} }

View File

@@ -109,7 +109,7 @@ type HTTPPluginOptions struct {
Addr string `json:"addr"` Addr string `json:"addr"`
Path string `json:"path"` Path string `json:"path"`
Ops []string `json:"ops"` Ops []string `json:"ops"`
TLSVerify bool `json:"tls_verify,omitempty"` TLSVerify bool `json:"tlsVerify,omitempty"`
} }
type HeaderOperations struct { type HeaderOperations struct {

View File

@@ -16,7 +16,6 @@ package v1
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"reflect" "reflect"
) )
@@ -30,7 +29,7 @@ type TypedClientPluginOptions struct {
func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error { func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error {
if len(b) == 4 && string(b) == "null" { if len(b) == 4 && string(b) == "null" {
return errors.New("type is required") return nil
} }
typeStruct := struct { typeStruct := struct {
@@ -41,6 +40,9 @@ func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error {
} }
c.Type = typeStruct.Type c.Type = typeStruct.Type
if c.Type == "" {
return nil
}
v, ok := clientPluginOptionsTypeMap[typeStruct.Type] v, ok := clientPluginOptionsTypeMap[typeStruct.Type]
if !ok { if !ok {

View File

@@ -150,6 +150,7 @@ type ServerTransportConfig struct {
// TCPMux toggles TCP stream multiplexing. This allows multiple requests // TCPMux toggles TCP stream multiplexing. This allows multiple requests
// from a client to share a single TCP connection. By default, this value // from a client to share a single TCP connection. By default, this value
// is true. // is true.
// $HideFromDoc
TCPMux *bool `json:"tcpMux,omitempty"` TCPMux *bool `json:"tcpMux,omitempty"`
// TCPMuxKeepaliveInterval specifies the keep alive interval for TCP stream multipler. // TCPMuxKeepaliveInterval specifies the keep alive interval for TCP stream multipler.
// If TCPMux is true, heartbeat of application layer is unnecessary because it can only rely on heartbeat in TCPMux. // If TCPMux is true, heartbeat of application layer is unnecessary because it can only rely on heartbeat in TCPMux.

View File

@@ -19,7 +19,7 @@ import (
"strings" "strings"
) )
var version = "0.52.0" var version = "0.52.2"
func Full() string { func Full() string {
return version return version

View File

@@ -34,24 +34,24 @@ type GeneralResponse struct {
type serverInfoResp struct { type serverInfoResp struct {
Version string `json:"version"` Version string `json:"version"`
BindPort int `json:"bind_port"` BindPort int `json:"bindPort"`
VhostHTTPPort int `json:"vhost_http_port"` VhostHTTPPort int `json:"vhostHTTPPort"`
VhostHTTPSPort int `json:"vhost_https_port"` VhostHTTPSPort int `json:"vhostHTTPSPort"`
TCPMuxHTTPConnectPort int `json:"tcpmux_httpconnect_port"` TCPMuxHTTPConnectPort int `json:"tcpmuxHTTPConnectPort"`
KCPBindPort int `json:"kcp_bind_port"` KCPBindPort int `json:"kcpBindPort"`
QUICBindPort int `json:"quic_bind_port"` QUICBindPort int `json:"quicBindPort"`
SubdomainHost string `json:"subdomain_host"` SubdomainHost string `json:"subdomainHost"`
MaxPoolCount int64 `json:"max_pool_count"` MaxPoolCount int64 `json:"maxPoolCount"`
MaxPortsPerClient int64 `json:"max_ports_per_client"` MaxPortsPerClient int64 `json:"maxPortsPerClient"`
HeartBeatTimeout int64 `json:"heart_beat_timeout"` HeartBeatTimeout int64 `json:"heartbeatTimeout"`
AllowPortsStr string `json:"allow_ports_str,omitempty"` AllowPortsStr string `json:"allowPortsStr,omitempty"`
TLSOnly bool `json:"tls_only,omitempty"` TLSForce bool `json:"tlsForce,omitempty"`
TotalTrafficIn int64 `json:"total_traffic_in"` TotalTrafficIn int64 `json:"totalTrafficIn"`
TotalTrafficOut int64 `json:"total_traffic_out"` TotalTrafficOut int64 `json:"totalTrafficOut"`
CurConns int64 `json:"cur_conns"` CurConns int64 `json:"curConns"`
ClientCounts int64 `json:"client_counts"` ClientCounts int64 `json:"clientCounts"`
ProxyTypeCounts map[string]int64 `json:"proxy_type_count"` ProxyTypeCounts map[string]int64 `json:"proxyTypeCount"`
} }
// /healthz // /healthz
@@ -85,7 +85,7 @@ func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
MaxPortsPerClient: svr.cfg.MaxPortsPerClient, MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
HeartBeatTimeout: svr.cfg.Transport.HeartbeatTimeout, HeartBeatTimeout: svr.cfg.Transport.HeartbeatTimeout,
AllowPortsStr: types.PortsRangeSlice(svr.cfg.AllowPorts).String(), AllowPortsStr: types.PortsRangeSlice(svr.cfg.AllowPorts).String(),
TLSOnly: svr.cfg.Transport.TLS.Force, TLSForce: svr.cfg.Transport.TLS.Force,
TotalTrafficIn: serverStats.TotalTrafficIn, TotalTrafficIn: serverStats.TotalTrafficIn,
TotalTrafficOut: serverStats.TotalTrafficOut, TotalTrafficOut: serverStats.TotalTrafficOut,
@@ -104,7 +104,7 @@ type BaseOutConf struct {
type TCPOutConf struct { type TCPOutConf struct {
BaseOutConf BaseOutConf
RemotePort int `json:"remote_port"` RemotePort int `json:"remotePort"`
} }
type TCPMuxOutConf struct { type TCPMuxOutConf struct {
@@ -115,14 +115,14 @@ type TCPMuxOutConf struct {
type UDPOutConf struct { type UDPOutConf struct {
BaseOutConf BaseOutConf
RemotePort int `json:"remote_port"` RemotePort int `json:"remotePort"`
} }
type HTTPOutConf struct { type HTTPOutConf struct {
BaseOutConf BaseOutConf
v1.DomainConfig v1.DomainConfig
Locations []string `json:"locations"` Locations []string `json:"locations"`
HostHeaderRewrite string `json:"host_header_rewrite"` HostHeaderRewrite string `json:"hostHeaderRewrite"`
} }
type HTTPSOutConf struct { type HTTPSOutConf struct {
@@ -163,12 +163,12 @@ func getConfByType(proxyType string) any {
type ProxyStatsInfo struct { type ProxyStatsInfo struct {
Name string `json:"name"` Name string `json:"name"`
Conf interface{} `json:"conf"` Conf interface{} `json:"conf"`
ClientVersion string `json:"client_version,omitempty"` ClientVersion string `json:"clientVersion,omitempty"`
TodayTrafficIn int64 `json:"today_traffic_in"` TodayTrafficIn int64 `json:"todayTrafficIn"`
TodayTrafficOut int64 `json:"today_traffic_out"` TodayTrafficOut int64 `json:"todayTrafficOut"`
CurConns int64 `json:"cur_conns"` CurConns int64 `json:"curConns"`
LastStartTime string `json:"last_start_time"` LastStartTime string `json:"lastStartTime"`
LastCloseTime string `json:"last_close_time"` LastCloseTime string `json:"lastCloseTime"`
Status string `json:"status"` Status string `json:"status"`
} }
@@ -236,11 +236,11 @@ func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxySt
type GetProxyStatsResp struct { type GetProxyStatsResp struct {
Name string `json:"name"` Name string `json:"name"`
Conf interface{} `json:"conf"` Conf interface{} `json:"conf"`
TodayTrafficIn int64 `json:"today_traffic_in"` TodayTrafficIn int64 `json:"todayTrafficIn"`
TodayTrafficOut int64 `json:"today_traffic_out"` TodayTrafficOut int64 `json:"todayTrafficOut"`
CurConns int64 `json:"cur_conns"` CurConns int64 `json:"curConns"`
LastStartTime string `json:"last_start_time"` LastStartTime string `json:"lastStartTime"`
LastCloseTime string `json:"last_close_time"` LastCloseTime string `json:"lastCloseTime"`
Status string `json:"status"` Status string `json:"status"`
} }
@@ -310,8 +310,8 @@ func (svr *Service) getProxyStatsByTypeAndName(proxyType string, proxyName strin
// /api/traffic/:name // /api/traffic/:name
type GetProxyTrafficResp struct { type GetProxyTrafficResp struct {
Name string `json:"name"` Name string `json:"name"`
TrafficIn []int64 `json:"traffic_in"` TrafficIn []int64 `json:"trafficIn"`
TrafficOut []int64 `json:"traffic_out"` TrafficOut []int64 `json:"trafficOut"`
} }
func (svr *Service) APIProxyTraffic(w http.ResponseWriter, r *http.Request) { func (svr *Service) APIProxyTraffic(w http.ResponseWriter, r *http.Request) {

View File

@@ -25,6 +25,7 @@ log.level = "trace"
DefaultClientConfig = ` DefaultClientConfig = `
serverAddr = "127.0.0.1" serverAddr = "127.0.0.1"
serverPort = {{ .%s }} serverPort = {{ .%s }}
loginFailExit = false
log.level = "trace" log.level = "trace"
` `
@@ -38,6 +39,7 @@ log.level = "trace"
[common] [common]
server_addr = 127.0.0.1 server_addr = 127.0.0.1
server_port = {{ .%s }} server_port = {{ .%s }}
login_fail_exit = false
log_level = trace log_level = trace
` `
) )

View File

@@ -40,6 +40,7 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str
currentServerProcesses = append(currentServerProcesses, p) currentServerProcesses = append(currentServerProcesses, p)
err = p.Start() err = p.Start()
ExpectNoError(err) ExpectNoError(err)
time.Sleep(500 * time.Millisecond)
} }
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)

View File

@@ -291,7 +291,7 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
}) })
}) })
ginkgo.Describe("TLS with disable_custom_tls_first_byte set to false", func() { ginkgo.Describe("TLS with disableCustomTLSFirstByte set to false", func() {
supportProtocols := []string{"tcp", "kcp", "quic", "websocket"} supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol
@@ -322,4 +322,22 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
}) })
} }
}) })
ginkgo.Describe("Use same port for bindPort and vhostHTTPSPort", func() {
supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
for _, protocol := range supportProtocols {
tmp := protocol
defineClientServerTest("Use same port for bindPort and vhostHTTPSPort: "+strings.ToUpper(tmp), f, &generalTestConfigures{
server: fmt.Sprintf(`
vhostHTTPSPort = {{ .%s }}
%s
`, consts.PortServerName, renderBindPortConfig(protocol)),
// transport.tls.disableCustomTLSFirstByte should set to false when vhostHTTPSPort is same as bindPort
client: fmt.Sprintf(`
transport.protocol = "%s"
transport.tls.disableCustomTLSFirstByte = false
`, protocol),
})
}
})
}) })

View File

@@ -1,3 +1,5 @@
// Generated by 'unplugin-auto-import' // Generated by 'unplugin-auto-import'
export {} export {}
declare global {} declare global {
}

View File

@@ -10,16 +10,16 @@ import ProxyView from './ProxyView.vue'
let proxies = ref<HTTPProxy[]>([]) let proxies = ref<HTTPProxy[]>([])
const fetchData = () => { const fetchData = () => {
let vhost_http_port: number let vhostHTTPPort: number
let subdomain_host: string let subdomainHost: string
fetch('../api/serverinfo', { credentials: 'include' }) fetch('../api/serverinfo', { credentials: 'include' })
.then((res) => { .then((res) => {
return res.json() return res.json()
}) })
.then((json) => { .then((json) => {
vhost_http_port = json.vhost_http_port vhostHTTPPort = json.vhostHTTPPort
subdomain_host = json.subdomain_host subdomainHost = json.subdomainHost
if (vhost_http_port == null || vhost_http_port == 0) { if (vhostHTTPPort == null || vhostHTTPPort == 0) {
return return
} }
fetch('../api/proxy/http', { credentials: 'include' }) fetch('../api/proxy/http', { credentials: 'include' })
@@ -29,7 +29,7 @@ const fetchData = () => {
.then((json) => { .then((json) => {
for (let proxyStats of json.proxies) { for (let proxyStats of json.proxies) {
proxies.value.push( proxies.value.push(
new HTTPProxy(proxyStats, vhost_http_port, subdomain_host) new HTTPProxy(proxyStats, vhostHTTPPort, subdomainHost)
) )
} }
}) })

View File

@@ -10,16 +10,16 @@ import ProxyView from './ProxyView.vue'
let proxies = ref<HTTPSProxy[]>([]) let proxies = ref<HTTPSProxy[]>([])
const fetchData = () => { const fetchData = () => {
let vhost_https_port: number let vhostHTTPSPort: number
let subdomain_host: string let subdomainHost: string
fetch('../api/serverinfo', { credentials: 'include' }) fetch('../api/serverinfo', { credentials: 'include' })
.then((res) => { .then((res) => {
return res.json() return res.json()
}) })
.then((json) => { .then((json) => {
vhost_https_port = json.vhost_https_port vhostHTTPSPort = json.vhostHTTPSPort
subdomain_host = json.subdomain_host subdomainHost = json.subdomainHost
if (vhost_https_port == null || vhost_https_port == 0) { if (vhostHTTPSPort == null || vhostHTTPSPort == 0) {
return return
} }
fetch('../api/proxy/https', { credentials: 'include' }) fetch('../api/proxy/https', { credentials: 'include' })
@@ -29,7 +29,7 @@ const fetchData = () => {
.then((json) => { .then((json) => {
for (let proxyStats of json.proxies) { for (let proxyStats of json.proxies) {
proxies.value.push( proxies.value.push(
new HTTPSProxy(proxyStats, vhost_https_port, subdomain_host) new HTTPSProxy(proxyStats, vhostHTTPSPort, subdomainHost)
) )
} }
}) })

View File

@@ -14,7 +14,7 @@
trigger="click" trigger="click"
> >
<template #default> <template #default>
<Traffic :proxy_name="props.row.name" /> <Traffic :proxyName="props.row.name" />
</template> </template>
<template #reference> <template #reference>
@@ -37,19 +37,19 @@
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="Traffic In" label="Traffic In"
prop="traffic_in" prop="trafficIn"
:formatter="formatTrafficIn" :formatter="formatTrafficIn"
sortable sortable
> >
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="Traffic Out" label="Traffic Out"
prop="traffic_out" prop="trafficOut"
:formatter="formatTrafficOut" :formatter="formatTrafficOut"
sortable sortable
> >
</el-table-column> </el-table-column>
<el-table-column label="ClientVersion" prop="client_version" sortable> <el-table-column label="ClientVersion" prop="clientVersion" sortable>
</el-table-column> </el-table-column>
<el-table-column label="Status" prop="status" sortable> <el-table-column label="Status" prop="status" sortable>
<template #default="scope"> <template #default="scope">
@@ -75,10 +75,10 @@ defineProps<{
}>() }>()
const formatTrafficIn = (row: BaseProxy, _: TableColumnCtx<BaseProxy>) => { const formatTrafficIn = (row: BaseProxy, _: TableColumnCtx<BaseProxy>) => {
return Humanize.fileSize(row.traffic_in) return Humanize.fileSize(row.trafficIn)
} }
const formatTrafficOut = (row: BaseProxy, _: TableColumnCtx<BaseProxy>) => { const formatTrafficOut = (row: BaseProxy, _: TableColumnCtx<BaseProxy>) => {
return Humanize.fileSize(row.traffic_out) return Humanize.fileSize(row.trafficOut)
} }
</script> </script>

View File

@@ -12,7 +12,7 @@
<span>{{ row.type }}</span> <span>{{ row.type }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Domains"> <el-form-item label="Domains">
<span>{{ row.custom_domains }}</span> <span>{{ row.customDomains }}</span>
</el-form-item> </el-form-item>
<el-form-item label="SubDomain"> <el-form-item label="SubDomain">
<span>{{ row.subdomain }}</span> <span>{{ row.subdomain }}</span>
@@ -21,7 +21,7 @@
<span>{{ row.locations }}</span> <span>{{ row.locations }}</span>
</el-form-item> </el-form-item>
<el-form-item label="HostRewrite"> <el-form-item label="HostRewrite">
<span>{{ row.host_header_rewrite }}</span> <span>{{ row.hostHeaderRewrite }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Encryption"> <el-form-item label="Encryption">
<span>{{ row.encryption }}</span> <span>{{ row.encryption }}</span>
@@ -30,10 +30,10 @@
<span>{{ row.compression }}</span> <span>{{ row.compression }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Last Start"> <el-form-item label="Last Start">
<span>{{ row.last_start_time }}</span> <span>{{ row.lastStartTime }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ row.last_close_time }}</span> <span>{{ row.lastCloseTime }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -54,10 +54,10 @@
<span>{{ row.compression }}</span> <span>{{ row.compression }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Last Start"> <el-form-item label="Last Start">
<span>{{ row.last_start_time }}</span> <span>{{ row.lastStartTime }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ row.last_close_time }}</span> <span>{{ row.lastCloseTime }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>

View File

@@ -12,58 +12,58 @@
<span>{{ data.version }}</span> <span>{{ data.version }}</span>
</el-form-item> </el-form-item>
<el-form-item label="BindPort"> <el-form-item label="BindPort">
<span>{{ data.bind_port }}</span> <span>{{ data.bindPort }}</span>
</el-form-item> </el-form-item>
<el-form-item label="KCP Bind Port" v-if="data.kcp_bind_port != 0"> <el-form-item label="KCP Bind Port" v-if="data.kcpBindPort != 0">
<span>{{ data.kcp_bind_port }}</span> <span>{{ data.kcpBindPort }}</span>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="QUIC Bind Port" label="QUIC Bind Port"
v-if="data.quic_bind_port != 0" v-if="data.quicBindPort != 0"
> >
<span>{{ data.quic_bind_port }}</span> <span>{{ data.quicBindPort }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Http Port" v-if="data.vhost_http_port != 0"> <el-form-item label="Http Port" v-if="data.vhostHTTPPort != 0">
<span>{{ data.vhost_http_port }}</span> <span>{{ data.vhostHTTPPort }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Https Port" v-if="data.vhost_https_port != 0"> <el-form-item label="Https Port" v-if="data.vhostHTTPSPort != 0">
<span>{{ data.vhost_https_port }}</span> <span>{{ data.vhostHTTPSPort }}</span>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="TCPMux HTTPConnect Port" label="TCPMux HTTPConnect Port"
v-if="data.tcpmux_httpconnect_port != 0" v-if="data.tcpmuxHTTPConnectPort != 0"
> >
<span>{{ data.tcpmux_httpconnect_port }}</span> <span>{{ data.tcpmuxHTTPConnectPort }}</span>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="Subdomain Host" label="Subdomain Host"
v-if="data.subdomain_host != ''" v-if="data.subdomainHost != ''"
> >
<LongSpan :content="data.subdomain_host" :length="30"></LongSpan> <LongSpan :content="data.subdomainHost" :length="30"></LongSpan>
</el-form-item> </el-form-item>
<el-form-item label="Max PoolCount"> <el-form-item label="Max PoolCount">
<span>{{ data.max_pool_count }}</span> <span>{{ data.maxPoolCount }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Max Ports Per Client"> <el-form-item label="Max Ports Per Client">
<span>{{ data.max_ports_per_client }}</span> <span>{{ data.maxPortsPerClient }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Allow Ports" v-if="data.allow_ports_str != ''"> <el-form-item label="Allow Ports" v-if="data.allowPortsStr != ''">
<LongSpan :content="data.allow_ports_str" :length="30"></LongSpan> <LongSpan :content="data.allowPortsStr" :length="30"></LongSpan>
</el-form-item> </el-form-item>
<el-form-item label="TLS Only" v-if="data.tls_only === true"> <el-form-item label="TLS Force" v-if="data.tlsForce === true">
<span>{{ data.tls_only }}</span> <span>{{ data.tlsForce }}</span>
</el-form-item> </el-form-item>
<el-form-item label="HeartBeat Timeout"> <el-form-item label="HeartBeat Timeout">
<span>{{ data.heart_beat_timeout }}</span> <span>{{ data.heartbeatTimeout }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Client Counts"> <el-form-item label="Client Counts">
<span>{{ data.client_counts }}</span> <span>{{ data.clientCounts }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Current Connections"> <el-form-item label="Current Connections">
<span>{{ data.cur_conns }}</span> <span>{{ data.curConns }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Proxy Counts"> <el-form-item label="Proxy Counts">
<span>{{ data.proxy_counts }}</span> <span>{{ data.proxyCounts }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@@ -87,21 +87,21 @@ import LongSpan from './LongSpan.vue'
let data = ref({ let data = ref({
version: '', version: '',
bind_port: 0, bindPort: 0,
kcp_bind_port: 0, kcpBindPort: 0,
quic_bind_port: 0, quicBindPort: 0,
vhost_http_port: 0, vhostHTTPPort: 0,
vhost_https_port: 0, vhostHTTPSPort: 0,
tcpmux_httpconnect_port: 0, tcpmuxHTTPConnectPort: 0,
subdomain_host: '', subdomainHost: '',
max_pool_count: 0, maxPoolCount: 0,
max_ports_per_client: '', maxPortsPerClient: '',
allow_ports_str: '', allowPortsStr: '',
tls_only: false, tlsForce: false,
heart_beat_timeout: 0, heartbeatTimeout: 0,
client_counts: 0, clientCounts: 0,
cur_conns: 0, curConns: 0,
proxy_counts: 0, proxyCounts: 0,
}) })
const fetchData = () => { const fetchData = () => {
@@ -109,50 +109,50 @@ const fetchData = () => {
.then((res) => res.json()) .then((res) => res.json())
.then((json) => { .then((json) => {
data.value.version = json.version data.value.version = json.version
data.value.bind_port = json.bind_port data.value.bindPort = json.bindPort
data.value.kcp_bind_port = json.kcp_bind_port data.value.kcpBindPort = json.kcpBindPort
data.value.quic_bind_port = json.quic_bind_port data.value.quicBindPort = json.quicBindPort
data.value.vhost_http_port = json.vhost_http_port data.value.vhostHTTPPort = json.vhostHTTPPort
data.value.vhost_https_port = json.vhost_https_port data.value.vhostHTTPSPort = json.vhostHTTPSPort
data.value.tcpmux_httpconnect_port = json.tcpmux_httpconnect_port data.value.tcpmuxHTTPConnectPort = json.tcpmuxHTTPConnectPort
data.value.subdomain_host = json.subdomain_host data.value.subdomainHost = json.subdomainHost
data.value.max_pool_count = json.max_pool_count data.value.maxPoolCount = json.maxPoolCount
data.value.max_ports_per_client = json.max_ports_per_client data.value.maxPortsPerClient = json.maxPortsPerClient
if (data.value.max_ports_per_client == '0') { if (data.value.maxPortsPerClient == '0') {
data.value.max_ports_per_client = 'no limit' data.value.maxPortsPerClient = 'no limit'
} }
data.value.allow_ports_str = json.allow_ports_str data.value.allowPortsStr = json.allowPortsStr
data.value.tls_only = json.tls_only data.value.tlsForce = json.tlsForce
data.value.heart_beat_timeout = json.heart_beat_timeout data.value.heartbeatTimeout = json.heartbeatTimeout
data.value.client_counts = json.client_counts data.value.clientCounts = json.clientCounts
data.value.cur_conns = json.cur_conns data.value.curConns = json.curConns
data.value.proxy_counts = 0 data.value.proxyCounts = 0
if (json.proxy_type_count != null) { if (json.proxyTypeCount != null) {
if (json.proxy_type_count.tcp != null) { if (json.proxyTypeCount.tcp != null) {
data.value.proxy_counts += json.proxy_type_count.tcp data.value.proxyCounts += json.proxyTypeCount.tcp
} }
if (json.proxy_type_count.udp != null) { if (json.proxyTypeCount.udp != null) {
data.value.proxy_counts += json.proxy_type_count.udp data.value.proxyCounts += json.proxyTypeCount.udp
} }
if (json.proxy_type_count.http != null) { if (json.proxyTypeCount.http != null) {
data.value.proxy_counts += json.proxy_type_count.http data.value.proxyCounts += json.proxyTypeCount.http
} }
if (json.proxy_type_count.https != null) { if (json.proxyTypeCount.https != null) {
data.value.proxy_counts += json.proxy_type_count.https data.value.proxyCounts += json.proxyTypeCount.https
} }
if (json.proxy_type_count.stcp != null) { if (json.proxyTypeCount.stcp != null) {
data.value.proxy_counts += json.proxy_type_count.stcp data.value.proxyCounts += json.proxyTypeCount.stcp
} }
if (json.proxy_type_count.sudp != null) { if (json.proxyTypeCount.sudp != null) {
data.value.proxy_counts += json.proxy_type_count.sudp data.value.proxyCounts += json.proxyTypeCount.sudp
} }
if (json.proxy_type_count.xtcp != null) { if (json.proxyTypeCount.xtcp != null) {
data.value.proxy_counts += json.proxy_type_count.xtcp data.value.proxyCounts += json.proxyTypeCount.xtcp
} }
} }
// draw chart // draw chart
DrawTrafficChart('traffic', json.total_traffic_in, json.total_traffic_out) DrawTrafficChart('traffic', json.totalTrafficIn, json.totalTrafficOut)
DrawProxyChart('proxies', json) DrawProxyChart('proxies', json)
}) })
.catch(() => { .catch(() => {

View File

@@ -1,5 +1,5 @@
<template> <template>
<div :id="proxy_name" style="width: 600px; height: 400px"></div> <div :id="proxyName" style="width: 600px; height: 400px"></div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -7,17 +7,17 @@ import { ElMessage } from 'element-plus'
import { DrawProxyTrafficChart } from '../utils/chart.js' import { DrawProxyTrafficChart } from '../utils/chart.js'
const props = defineProps<{ const props = defineProps<{
proxy_name: string proxyName: string
}>() }>()
const fetchData = () => { const fetchData = () => {
let url = '../api/traffic/' + props.proxy_name let url = '../api/traffic/' + props.proxyName
fetch(url, { credentials: 'include' }) fetch(url, { credentials: 'include' })
.then((res) => { .then((res) => {
return res.json() return res.json()
}) })
.then((json) => { .then((json) => {
DrawProxyTrafficChart(props.proxy_name, json.traffic_in, json.traffic_out) DrawProxyTrafficChart(props.proxyName, json.trafficIn, json.trafficOut)
}) })
.catch((err) => { .catch((err) => {
ElMessage({ ElMessage({

View File

@@ -121,71 +121,71 @@ function DrawProxyChart(elementId: string, serverInfo: any) {
} }
if ( if (
serverInfo.proxy_type_count.tcp != null && serverInfo.proxyTypeCount.tcp != null &&
serverInfo.proxy_type_count.tcp != 0 serverInfo.proxyTypeCount.tcp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.tcp, value: serverInfo.proxyTypeCount.tcp,
name: 'TCP', name: 'TCP',
}) })
option.legend.data.push('TCP') option.legend.data.push('TCP')
} }
if ( if (
serverInfo.proxy_type_count.udp != null && serverInfo.proxyTypeCount.udp != null &&
serverInfo.proxy_type_count.udp != 0 serverInfo.proxyTypeCount.udp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.udp, value: serverInfo.proxyTypeCount.udp,
name: 'UDP', name: 'UDP',
}) })
option.legend.data.push('UDP') option.legend.data.push('UDP')
} }
if ( if (
serverInfo.proxy_type_count.http != null && serverInfo.proxyTypeCount.http != null &&
serverInfo.proxy_type_count.http != 0 serverInfo.proxyTypeCount.http != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.http, value: serverInfo.proxyTypeCount.http,
name: 'HTTP', name: 'HTTP',
}) })
option.legend.data.push('HTTP') option.legend.data.push('HTTP')
} }
if ( if (
serverInfo.proxy_type_count.https != null && serverInfo.proxyTypeCount.https != null &&
serverInfo.proxy_type_count.https != 0 serverInfo.proxyTypeCount.https != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.https, value: serverInfo.proxyTypeCount.https,
name: 'HTTPS', name: 'HTTPS',
}) })
option.legend.data.push('HTTPS') option.legend.data.push('HTTPS')
} }
if ( if (
serverInfo.proxy_type_count.stcp != null && serverInfo.proxyTypeCount.stcp != null &&
serverInfo.proxy_type_count.stcp != 0 serverInfo.proxyTypeCount.stcp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.stcp, value: serverInfo.proxyTypeCount.stcp,
name: 'STCP', name: 'STCP',
}) })
option.legend.data.push('STCP') option.legend.data.push('STCP')
} }
if ( if (
serverInfo.proxy_type_count.sudp != null && serverInfo.proxyTypeCount.sudp != null &&
serverInfo.proxy_type_count.sudp != 0 serverInfo.proxyTypeCount.sudp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.sudp, value: serverInfo.proxyTypeCount.sudp,
name: 'SUDP', name: 'SUDP',
}) })
option.legend.data.push('SUDP') option.legend.data.push('SUDP')
} }
if ( if (
serverInfo.proxy_type_count.xtcp != null && serverInfo.proxyTypeCount.xtcp != null &&
serverInfo.proxy_type_count.xtcp != 0 serverInfo.proxyTypeCount.xtcp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.xtcp, value: serverInfo.proxyTypeCount.xtcp,
name: 'XTCP', name: 'XTCP',
}) })
option.legend.data.push('XTCP') option.legend.data.push('XTCP')

View File

@@ -4,42 +4,39 @@ class BaseProxy {
encryption: boolean encryption: boolean
compression: boolean compression: boolean
conns: number conns: number
traffic_in: number trafficIn: number
traffic_out: number trafficOut: number
last_start_time: string lastStartTime: string
last_close_time: string lastCloseTime: string
status: string status: string
client_version: string clientVersion: string
addr: string addr: string
port: number port: number
custom_domains: string customDomains: string
host_header_rewrite: string hostHeaderRewrite: string
locations: string locations: string
subdomain: string subdomain: string
constructor(proxyStats: any) { constructor(proxyStats: any) {
this.name = proxyStats.name this.name = proxyStats.name
this.type = '' this.type = ''
if (proxyStats.conf != null) { this.encryption = false
this.encryption = proxyStats.conf.use_encryption this.compression = false
this.compression = proxyStats.conf.use_compression this.encryption = (proxyStats.conf?.transport?.useEncryption) || this.encryption;
} else { this.compression = (proxyStats.conf?.transport?.useCompression) || this.compression;
this.encryption = false this.conns = proxyStats.curConns
this.compression = false this.trafficIn = proxyStats.todayTrafficIn
} this.trafficOut = proxyStats.todayTrafficOut
this.conns = proxyStats.cur_conns this.lastStartTime = proxyStats.lastStartTime
this.traffic_in = proxyStats.today_traffic_in this.lastCloseTime = proxyStats.lastCloseTime
this.traffic_out = proxyStats.today_traffic_out
this.last_start_time = proxyStats.last_start_time
this.last_close_time = proxyStats.last_close_time
this.status = proxyStats.status this.status = proxyStats.status
this.client_version = proxyStats.client_version this.clientVersion = proxyStats.clientVersion
this.addr = '' this.addr = ''
this.port = 0 this.port = 0
this.custom_domains = '' this.customDomains = ''
this.host_header_rewrite = '' this.hostHeaderRewrite = ''
this.locations = '' this.locations = ''
this.subdomain = '' this.subdomain = ''
} }
@@ -50,8 +47,8 @@ class TCPProxy extends BaseProxy {
super(proxyStats) super(proxyStats)
this.type = 'tcp' this.type = 'tcp'
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.addr = ':' + proxyStats.conf.remote_port this.addr = ':' + proxyStats.conf.remotePort
this.port = proxyStats.conf.remote_port this.port = proxyStats.conf.remotePort
} else { } else {
this.addr = '' this.addr = ''
this.port = 0 this.port = 0
@@ -64,8 +61,8 @@ class UDPProxy extends BaseProxy {
super(proxyStats) super(proxyStats)
this.type = 'udp' this.type = 'udp'
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.addr = ':' + proxyStats.conf.remote_port this.addr = ':' + proxyStats.conf.remotePort
this.port = proxyStats.conf.remote_port this.port = proxyStats.conf.remotePort
} else { } else {
this.addr = '' this.addr = ''
this.port = 0 this.port = 0
@@ -74,43 +71,31 @@ class UDPProxy extends BaseProxy {
} }
class HTTPProxy extends BaseProxy { class HTTPProxy extends BaseProxy {
constructor(proxyStats: any, port: number, subdomain_host: string) { constructor(proxyStats: any, port: number, subdomainHost: string) {
super(proxyStats) super(proxyStats)
this.type = 'http' this.type = 'http'
this.port = port this.port = port
if (proxyStats.conf != null) { if (proxyStats.conf) {
this.custom_domains = proxyStats.conf.custom_domains this.customDomains = proxyStats.conf.customDomains || this.customDomains;
this.host_header_rewrite = proxyStats.conf.host_header_rewrite this.hostHeaderRewrite = proxyStats.conf.hostHeaderRewrite
this.locations = proxyStats.conf.locations this.locations = proxyStats.conf.locations
if (proxyStats.conf.subdomain != '') { if (proxyStats.conf.subdomain) {
this.subdomain = proxyStats.conf.subdomain + '.' + subdomain_host this.subdomain = `${proxyStats.conf.subdomain}.${subdomainHost}`
} else { }
this.subdomain = ''
}
} else {
this.custom_domains = ''
this.host_header_rewrite = ''
this.subdomain = ''
this.locations = ''
} }
} }
} }
class HTTPSProxy extends BaseProxy { class HTTPSProxy extends BaseProxy {
constructor(proxyStats: any, port: number, subdomain_host: string) { constructor(proxyStats: any, port: number, subdomainHost: string) {
super(proxyStats) super(proxyStats)
this.type = 'https' this.type = 'https'
this.port = port this.port = port
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.custom_domains = proxyStats.conf.custom_domains this.customDomains = proxyStats.conf.customDomains || this.customDomains;
if (proxyStats.conf.subdomain != '') { if (proxyStats.conf.subdomain) {
this.subdomain = proxyStats.conf.subdomain + '.' + subdomain_host this.subdomain = `${proxyStats.conf.subdomain}.${subdomainHost}`
} else {
this.subdomain = ''
} }
} else {
this.custom_domains = ''
this.subdomain = ''
} }
} }
} }