Update On Wed Nov 5 19:38:45 CET 2025

This commit is contained in:
github-action[bot]
2025-11-05 19:38:45 +01:00
parent bb569cc785
commit 4a37a53ca8
99 changed files with 2200 additions and 1709 deletions

View File

@@ -1582,4 +1582,5 @@ Examples:
| `rate` | Bandwidth rate limit | Integer (Mbps), 0=unlimited | `0` | Both |
| `slot` | Connection slot count | Integer (1-65536) | `65536` | Both |
| `proxy` | PROXY protocol support | `0`(disabled), `1`(enabled) | `0` | Both |
| `notcp` | TCP support control | `0`(enabled), `1`(disabled) | `0` | Both |
| `noudp` | UDP support control | `0`(enabled), `1`(disabled) | `0` | Both |

View File

@@ -262,6 +262,43 @@ nodepass "server://0.0.0.0:10101/0.0.0.0:8080?log=info&tls=1&proxy=1&rate=100"
- The header format follows the HAProxy PROXY protocol v1 specification
- If the target service doesn't support PROXY protocol, connections may fail or behave unexpectedly
## TCP Support Control
NodePass supports TCP traffic tunneling by default. The `notcp` parameter allows you to disable TCP support when only UDP traffic needs to be handled, which can reduce resource usage and simplify configuration.
- `notcp`: TCP support control (default: 0)
- Value 0: TCP support enabled - both TCP and UDP traffic will be tunneled
- Value 1: TCP support disabled - only UDP traffic will be tunneled, TCP connections are ignored
- Applies to both client and server modes
- When disabled, TCP-related resources (buffers, connections, sessions) are not allocated
Example:
```bash
# Enable TCP support (default behavior)
nodepass "server://0.0.0.0:10101/0.0.0.0:8080?notcp=0"
# Disable TCP support for UDP-only scenarios
nodepass "server://0.0.0.0:10101/0.0.0.0:8080?notcp=1"
# Client with TCP disabled
nodepass "client://server.example.com:10101/127.0.0.1:8080?notcp=1"
# Combined with other parameters
nodepass "server://0.0.0.0:10101/0.0.0.0:8080?log=info&tls=1&notcp=1"
```
**TCP Support Control Use Cases:**
- **UDP-Only Services**: Disable TCP when tunneling only UDP-based applications
- **Resource Optimization**: Reduce memory and CPU usage by avoiding TCP processing overhead
- **Security**: Prevent TCP-based attacks or unwanted traffic in restricted environments
- **Simplified Configuration**: Easier setup when TCP tunneling is not required
- **Network Isolation**: Isolate TCP and UDP traffic handling for better control
**Important Notes:**
- When TCP is disabled, any TCP connections sent to the tunnel will be silently dropped
- Existing TCP sessions will be terminated when switching to notcp=1
- TCP buffer pools and session management are disabled when notcp=1
## UDP Support Control
NodePass supports UDP traffic tunneling in addition to TCP. The `noudp` parameter allows you to disable UDP support when only TCP traffic needs to be handled, which can reduce resource usage and simplify configuration.
@@ -373,6 +410,7 @@ NodePass allows flexible configuration via URL query parameters. The following t
| `rate` | Bandwidth rate limit | `0` | O | O | X |
| `slot` | Maximum connection limit | `65536` | O | O | X |
| `proxy` | PROXY protocol support| `0` | O | O | X |
| `notcp` | TCP support control | `0` | O | O | X |
| `noudp` | UDP support control | `0` | O | O | X |
- O: Parameter is valid and recommended for configuration
@@ -383,6 +421,7 @@ NodePass allows flexible configuration via URL query parameters. The following t
- For client/server dual-end handshake modes, adjust connection pool capacity (`min`, `max`) based on traffic and resource constraints for optimal performance.
- Use run mode control (`mode`) when automatic detection doesn't match your deployment requirements or for consistent behavior across environments.
- Configure rate limiting (`rate`) to control bandwidth usage and prevent network congestion in shared environments.
- Set `notcp=1` when only UDP traffic needs to be tunneled to reduce resource usage and simplify configuration.
- Set `noudp=1` when only TCP traffic needs to be tunneled to reduce resource usage and simplify configuration.
- Log level (`log`) can be set in all modes for easier operations and troubleshooting.

View File

@@ -1582,4 +1582,5 @@ client://<server_host>:<server_port>/<local_host>:<local_port>?<parameters>
| `rate` | 带宽速率限制 | 整数 (Mbps), 0=无限制 | `0` | 两者 |
| `slot` | 连接槽位数 | 整数 (1-65536) | `65536` | 两者 |
| `proxy` | PROXY协议支持 | `0`(禁用), `1`(启用) | `0` | 两者 |
| `notcp` | TCP支持控制 | `0`(启用), `1`(禁用) | `0` | 两者 |
| `noudp` | UDP支持控制 | `0`(启用), `1`(禁用) | `0` | 两者 |

View File

@@ -262,6 +262,43 @@ nodepass "server://0.0.0.0:10101/0.0.0.0:8080?log=info&tls=1&proxy=1&rate=100"
- 头部格式遵循HAProxy PROXY协议v1规范
- 如果目标服务不支持PROXY协议将导致连接失败
## TCP支持控制
NodePass默认支持TCP流量隧道。`notcp`参数允许您在只需要处理UDP流量时禁用TCP支持这样可以减少资源使用并简化配置。
- `notcp`: TCP支持控制默认: 0
- 值为0启用TCP支持 - TCP和UDP流量都将被隧道传输
- 值为1禁用TCP支持 - 仅UDP流量将被隧道传输TCP连接被忽略
- 适用于客户端和服务器模式
- 禁用时不分配TCP相关资源缓冲区、连接、会话
示例:
```bash
# 启用TCP支持默认行为
nodepass "server://0.0.0.0:10101/0.0.0.0:8080?notcp=0"
# 禁用TCP支持仅处理UDP场景
nodepass "server://0.0.0.0:10101/0.0.0.0:8080?notcp=1"
# 客户端禁用TCP
nodepass "client://server.example.com:10101/127.0.0.1:8080?notcp=1"
# 与其他参数结合
nodepass "server://0.0.0.0:10101/0.0.0.0:8080?log=info&tls=1&notcp=1"
```
**TCP支持控制使用场景**
- **仅UDP服务**仅需要隧道传输UDP应用时禁用TCP
- **资源优化**通过避免TCP处理开销减少内存和CPU使用
- **安全性**防止受限环境中的TCP攻击或不需要的流量
- **简化配置**不需要TCP隧道时更容易设置
- **网络隔离**更好地控制TCP和UDP流量处理
**重要说明:**
- 禁用TCP时发送到隧道的任何TCP连接将被静默丢弃
- 切换到notcp=1时现有的TCP会话将被终止
- 当notcp=1时TCP缓冲池和会话管理被禁用
## UDP支持控制
除了TCP之外NodePass还支持UDP流量隧道。`noudp`参数允许您在只需要处理TCP流量时禁用UDP支持这样可以减少资源使用并简化配置。
@@ -373,6 +410,7 @@ NodePass支持通过URL查询参数进行灵活配置不同参数在 server
| `rate` | 带宽速率限制 | `0` | O | O | X |
| `slot` | 最大连接数限制 | `65536` | O | O | X |
| `proxy` | PROXY协议支持 | `0` | O | O | X |
| `notcp` | TCP支持控制 | `0` | O | O | X |
| `noudp` | UDP支持控制 | `0` | O | O | X |
- O参数有效推荐根据实际场景配置
@@ -383,6 +421,7 @@ NodePass支持通过URL查询参数进行灵活配置不同参数在 server
- client/server 双端握手模式建议根据流量和资源情况调整连接池容量min/max优化性能。
- 当自动检测不符合部署需求时或需要跨环境一致行为时使用运行模式控制mode
- 配置速率限制rate以控制带宽使用防止共享环境中的网络拥塞。
- 仅需要隧道传输UDP流量时设置`notcp=1`,以减少资源使用并简化配置。
- 仅需要隧道传输TCP流量时设置`noudp=1`,以减少资源使用并简化配置。
- 日志级别log可在所有模式下灵活调整便于运维和排查。

View File

@@ -6,5 +6,5 @@ require (
github.com/NodePassProject/cert v1.0.1
github.com/NodePassProject/conn v1.0.16
github.com/NodePassProject/logs v1.0.3
github.com/NodePassProject/pool v1.0.48
github.com/NodePassProject/pool v1.0.49
)

View File

@@ -4,5 +4,5 @@ github.com/NodePassProject/conn v1.0.16 h1:ojHfyBveZMcyOikdUs1SOW4yKp92NOBnNhfNe
github.com/NodePassProject/conn v1.0.16/go.mod h1:xfQ7ZLUxrtdLsljGHYYCToW+Hdg6DAbmL1Cs94n5h6E=
github.com/NodePassProject/logs v1.0.3 h1:CDUZVQ477vmmFQHazrQCWM0gJPNINm0C2N3FzC4jVyw=
github.com/NodePassProject/logs v1.0.3/go.mod h1:TwtPXOzLtb8iH+fdduQjEEywICXivsM39cy9AinMSks=
github.com/NodePassProject/pool v1.0.48 h1:99pCHQYtmH5sVIB0vY+KbV4zyWSH6ptHgkKtxDnjpqQ=
github.com/NodePassProject/pool v1.0.48/go.mod h1:joQFk1oocg56QpJ1QK/2g5Jv/AyqYUQgPXMG1gWe8iA=
github.com/NodePassProject/pool v1.0.49 h1:gktVmE+GsQ0/C0MF8qgRraR7eS3na4k0QrQfR6o4fkM=
github.com/NodePassProject/pool v1.0.49/go.mod h1:joQFk1oocg56QpJ1QK/2g5Jv/AyqYUQgPXMG1gWe8iA=

View File

@@ -45,7 +45,6 @@ func NewClient(parsedURL *url.URL, logger *logs.Logger) (*Client, error) {
return &buf
},
},
cleanURL: &url.URL{Scheme: "np", Fragment: "c"},
flushURL: &url.URL{Scheme: "np", Fragment: "f"},
pingURL: &url.URL{Scheme: "np", Fragment: "i"},
pongURL: &url.URL{Scheme: "np", Fragment: "o"},
@@ -62,9 +61,9 @@ func NewClient(parsedURL *url.URL, logger *logs.Logger) (*Client, error) {
// Run 管理客户端生命周期
func (c *Client) Run() {
logInfo := func(prefix string) {
c.logger.Info("%v: client://%v@%v/%v?min=%v&mode=%v&read=%v&rate=%v&slot=%v&proxy=%v&noudp=%v",
c.logger.Info("%v: client://%v@%v/%v?min=%v&mode=%v&read=%v&rate=%v&slot=%v&proxy=%v&notcp=%v&noudp=%v",
prefix, c.tunnelKey, c.tunnelTCPAddr, c.getTargetAddrsString(),
c.minPoolCapacity, c.runMode, c.readTimeout, c.rateLimit/125000, c.slotLimit, c.proxyProtocol, c.disableUDP)
c.minPoolCapacity, c.runMode, c.readTimeout, c.rateLimit/125000, c.slotLimit, c.proxyProtocol, c.disableTCP, c.disableUDP)
}
logInfo("Client started")
@@ -157,13 +156,15 @@ func (c *Client) commonStart() error {
})
go c.tunnelPool.ClientManager()
// 判断数据流向
if c.dataFlow == "+" {
// 初始化目标监听器
if err := c.initTargetListener(); err != nil {
return fmt.Errorf("commonStart: initTargetListener failed: %w", err)
}
go c.commonLoop()
}
// 启动共用控制
if err := c.commonControl(); err != nil {
return fmt.Errorf("commonStart: commonControl failed: %w", err)
}

View File

@@ -5,6 +5,8 @@ import (
"bufio"
"bytes"
"context"
"crypto/sha256"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"fmt"
@@ -29,6 +31,7 @@ type Common struct {
mu sync.Mutex // 互斥锁
logger *logs.Logger // 日志记录器
tlsCode string // TLS模式代码
tlsConfig *tls.Config // TLS配置
runMode string // 运行模式
dataFlow string // 数据流向
tunnelKey string // 隧道密钥
@@ -47,6 +50,7 @@ type Common struct {
minPoolCapacity int // 最小池容量
maxPoolCapacity int // 最大池容量
proxyProtocol string // 代理协议
disableTCP string // 禁用TCP
disableUDP string // 禁用UDP
rateLimit int // 速率限制
rateLimiter *conn.RateLimiter // 全局限速器
@@ -56,8 +60,6 @@ type Common struct {
udpBufferPool *sync.Pool // UDP缓冲区池
signalChan chan string // 信号通道
checkPoint time.Time // 检查点时间
lastClean time.Time // 上次清理时间
cleanURL *url.URL // 清理信号
flushURL *url.URL // 重置信号
pingURL *url.URL // PING信号
pongURL *url.URL // PONG信号
@@ -99,6 +101,7 @@ const (
defaultRateLimit = 0 // 默认速率限制
defaultSlotLimit = 65536 // 默认槽位限制
defaultProxyProtocol = "0" // 默认代理协议
defaultTCPStrategy = "0" // 默认TCP策略
defaultUDPStrategy = "0" // 默认UDP策略
)
@@ -184,6 +187,22 @@ func getEnvAsDuration(name string, defaultValue time.Duration) time.Duration {
return defaultValue
}
// formatCertFingerprint 格式化证书指纹为标准格式
func (c *Common) formatCertFingerprint(certRaw []byte) string {
hash := sha256.Sum256(certRaw)
hashHex := hex.EncodeToString(hash[:])
var formatted strings.Builder
for i := 0; i < len(hashHex); i += 2 {
if i > 0 {
formatted.WriteByte(':')
}
formatted.WriteString(strings.ToUpper(hashHex[i : i+2]))
}
return "sha256:" + formatted.String()
}
// xor 对数据进行异或处理
func (c *Common) xor(data []byte) []byte {
for i := range data {
@@ -404,6 +423,15 @@ func (c *Common) getProxyProtocol(parsedURL *url.URL) {
}
}
// getTCPStrategy 获取TCP策略
func (c *Common) getTCPStrategy(parsedURL *url.URL) {
if tcpStrategy := parsedURL.Query().Get("notcp"); tcpStrategy != "" {
c.disableTCP = tcpStrategy
} else {
c.disableTCP = defaultTCPStrategy
}
}
// getUDPStrategy 获取UDP策略
func (c *Common) getUDPStrategy(parsedURL *url.URL) {
if udpStrategy := parsedURL.Query().Get("noudp"); udpStrategy != "" {
@@ -426,6 +454,7 @@ func (c *Common) initConfig(parsedURL *url.URL) error {
c.getRateLimit(parsedURL)
c.getSlotLimit(parsedURL)
c.getProxyProtocol(parsedURL)
c.getTCPStrategy(parsedURL)
c.getUDPStrategy(parsedURL)
return nil
@@ -490,7 +519,7 @@ func (c *Common) initTunnelListener() error {
}
// 初始化隧道TCP监听器
if c.tunnelTCPAddr != nil {
if c.tunnelTCPAddr != nil && c.disableTCP != "1" {
tunnelListener, err := net.ListenTCP("tcp", c.tunnelTCPAddr)
if err != nil {
return fmt.Errorf("initTunnelListener: listenTCP failed: %w", err)
@@ -517,7 +546,7 @@ func (c *Common) initTargetListener() error {
}
// 初始化目标TCP监听器
if len(c.targetTCPAddrs) > 0 {
if len(c.targetTCPAddrs) > 0 && c.disableTCP != "1" {
targetListener, err := net.ListenTCP("tcp", c.targetTCPAddrs[0])
if err != nil {
return fmt.Errorf("initTargetListener: listenTCP failed: %w", err)
@@ -686,27 +715,20 @@ func (c *Common) healthCheck() error {
ticker := time.NewTicker(reportInterval)
defer ticker.Stop()
go func() {
select {
case <-c.ctx.Done():
case <-ticker.C:
c.incomingVerify()
}
}()
for c.ctx.Err() == nil {
// 尝试获取锁
if !c.mu.TryLock() {
continue
}
// 连接池定期清理
if time.Since(c.lastClean) >= ReloadInterval {
// 发送清理信号到对端
if c.ctx.Err() == nil && c.tunnelTCPConn != nil {
_, err := c.tunnelTCPConn.Write(c.encode([]byte(c.cleanURL.String())))
if err != nil {
c.mu.Unlock()
return fmt.Errorf("healthCheck: write clean signal failed: %w", err)
}
}
c.tunnelPool.Clean()
c.lastClean = time.Now()
c.logger.Debug("Tunnel pool cleaned: %v active connections", c.tunnelPool.Active())
}
// 连接池健康度检查
if c.tunnelPool.ErrorCount() > c.tunnelPool.Active()/2 {
// 发送刷新信号到对端
@@ -750,6 +772,57 @@ func (c *Common) healthCheck() error {
return fmt.Errorf("healthCheck: context error: %w", c.ctx.Err())
}
// incomingVerify 入口连接验证
func (c *Common) incomingVerify() {
for c.ctx.Err() == nil {
if c.tunnelPool.Ready() {
break
}
select {
case <-c.ctx.Done():
continue
case <-time.After(50 * time.Millisecond):
}
}
if c.tlsConfig == nil || len(c.tlsConfig.Certificates) == 0 {
return
}
cert := c.tlsConfig.Certificates[0]
if len(cert.Certificate) == 0 {
return
}
// 打印证书指纹
c.logger.Info("TLS cert verified: %v", c.formatCertFingerprint(cert.Certificate[0]))
id, testConn, err := c.tunnelPool.IncomingGet(poolGetTimeout)
if err != nil {
return
}
defer testConn.Close()
// 构建并发送验证信号
verifyURL := &url.URL{
Scheme: "np",
Host: c.tunnelTCPConn.RemoteAddr().String(),
Path: url.PathEscape(id),
Fragment: "v", // TLS验证
}
if c.ctx.Err() == nil && c.tunnelTCPConn != nil {
c.mu.Lock()
_, err = c.tunnelTCPConn.Write(c.encode([]byte(verifyURL.String())))
c.mu.Unlock()
if err != nil {
return
}
}
c.logger.Debug("TLS verify signal: cid %v -> %v", id, c.tunnelTCPConn.RemoteAddr())
}
// commonLoop 共用处理循环
func (c *Common) commonLoop() {
for c.ctx.Err() == nil {
@@ -1029,26 +1102,18 @@ func (c *Common) commonOnce() error {
// 处理信号
switch signalURL.Fragment {
case "v": // 验证
if c.tlsCode == "1" || c.tlsCode == "2" {
go c.outgoingVerify(signalURL)
}
case "1": // TCP
if len(c.targetTCPAddrs) > 0 {
if c.disableTCP != "1" {
go c.commonTCPOnce(signalURL)
}
case "2": // UDP
if c.disableUDP != "1" {
go c.commonUDPOnce(signalURL)
}
case "c": // 连接池清理
go func() {
c.tunnelPool.Clean()
select {
case <-c.ctx.Done():
return
case <-time.After(reportInterval):
}
c.logger.Debug("Tunnel pool cleaned: %v active connections", c.tunnelPool.Active())
}()
case "f": // 连接池刷新
go func() {
c.tunnelPool.Flush()
@@ -1087,6 +1152,54 @@ func (c *Common) commonOnce() error {
return fmt.Errorf("commonOnce: context error: %w", c.ctx.Err())
}
// outgoingVerify 出口连接验证
func (c *Common) outgoingVerify(signalURL *url.URL) {
for c.ctx.Err() == nil {
if c.tunnelPool.Ready() {
break
}
select {
case <-c.ctx.Done():
continue
case <-time.After(50 * time.Millisecond):
}
}
id := strings.TrimPrefix(signalURL.Path, "/")
if unescapedID, err := url.PathUnescape(id); err != nil {
c.logger.Error("outgoingVerify: unescape id failed: %v", err)
return
} else {
id = unescapedID
}
c.logger.Debug("TLS verify signal: cid %v <- %v", id, c.tunnelTCPConn.RemoteAddr())
testConn, err := c.tunnelPool.OutgoingGet(id, poolGetTimeout)
if err != nil {
c.logger.Error("outgoingVerify: request timeout: %v", err)
c.tunnelPool.AddError()
return
}
defer testConn.Close()
if testConn != nil {
tlsConn, ok := testConn.(*tls.Conn)
if !ok {
c.logger.Error("outgoingVerify: connection is not TLS")
return
}
state := tlsConn.ConnectionState()
if len(state.PeerCertificates) == 0 {
c.logger.Error("outgoingVerify: no peer certificates found")
return
}
// 打印证书指纹
c.logger.Info("TLS cert verified: %v", c.formatCertFingerprint(state.PeerCertificates[0].Raw))
}
}
// commonTCPOnce 共用处理单个TCP请求
func (c *Common) commonTCPOnce(signalURL *url.URL) {
id := strings.TrimPrefix(signalURL.Path, "/")

View File

@@ -31,14 +31,15 @@ import (
// 常量定义
const (
openAPIVersion = "v1" // OpenAPI版本
stateFilePath = "gob" // 实例状态持久化文件路径
stateFileName = "nodepass.gob" // 实例状态持久化文件名
sseRetryTime = 3000 // 重试间隔时间(毫秒)
apiKeyID = "********" // API Key的特殊ID
tcpingSemLimit = 10 // TCPing最大并发数
baseDuration = 100 * time.Millisecond // 基准持续时间
maxValueLen = 256 // 字符长度限制
openAPIVersion = "v1" // OpenAPI版本
stateFilePath = "gob" // 实例状态持久化文件路径
stateFileName = "nodepass.gob" // 实例状态持久化文件名
sseRetryTime = 3000 // 重试间隔时间(毫秒)
apiKeyID = "********" // API Key的特殊ID
tcpingSemLimit = 10 // TCPing最大并发数
baseDuration = 100 * time.Millisecond // 基准持续时间
gracefulTimeout = 5 * time.Second // 优雅关闭超时
maxValueLen = 256 // 字符长度限制
)
// Swagger UI HTML模板
@@ -1662,30 +1663,39 @@ func (m *Master) stopInstance(instance *Instance) {
return
}
// 发送终止信号
if instance.cmd.Process != nil {
if runtime.GOOS == "windows" {
instance.cmd.Process.Signal(os.Interrupt)
} else {
instance.cmd.Process.Signal(syscall.SIGTERM)
}
time.Sleep(baseDuration)
// 关闭停止通道
select {
case <-instance.stopped:
default:
close(instance.stopped)
}
// 关闭停止通道
close(instance.stopped)
// 取消执行或强制终止
// 发送终止信号并取消上下文
process := instance.cmd.Process
if runtime.GOOS == "windows" {
process.Signal(os.Interrupt)
} else {
process.Signal(syscall.SIGTERM)
}
if instance.cancelFunc != nil {
instance.cancelFunc()
} else {
err := instance.cmd.Process.Kill()
if err != nil {
m.logger.Error("stopInstance: instance error: %v [%v]", err, instance.ID)
}
}
m.logger.Info("Instance stopped [%v]", instance.ID)
// 等待优雅退出或超时强制终止
done := make(chan struct{})
go func() {
process.Wait()
close(done)
}()
select {
case <-done:
m.logger.Info("Instance stopped [%v]", instance.ID)
case <-time.After(gracefulTimeout):
process.Kill()
<-done
m.logger.Warn("Instance force killed [%v]", instance.ID)
}
// 重置实例状态
instance.Status = "stopped"
@@ -1775,7 +1785,7 @@ func (m *Master) generateConfigURL(instance *Instance) string {
// 根据实例类型设置默认参数
switch instance.Type {
case "client":
// client参数: min, mode, read, rate, slot, proxy, noudp
// client参数: min, mode, read, rate, slot, proxy, notcp, noudp
if query.Get("min") == "" {
query.Set("min", strconv.Itoa(defaultMinPool))
}
@@ -1794,11 +1804,14 @@ func (m *Master) generateConfigURL(instance *Instance) string {
if query.Get("proxy") == "" {
query.Set("proxy", defaultProxyProtocol)
}
if query.Get("notcp") == "" {
query.Set("notcp", defaultTCPStrategy)
}
if query.Get("noudp") == "" {
query.Set("noudp", defaultUDPStrategy)
}
case "server":
// server参数: max, mode, read, rate, slot, proxy, noudp
// server参数: max, mode, read, rate, slot, proxy, notcp, noudp
if query.Get("max") == "" {
query.Set("max", strconv.Itoa(defaultMaxPool))
}
@@ -1817,6 +1830,9 @@ func (m *Master) generateConfigURL(instance *Instance) string {
if query.Get("proxy") == "" {
query.Set("proxy", defaultProxyProtocol)
}
if query.Get("notcp") == "" {
query.Set("notcp", defaultTCPStrategy)
}
if query.Get("noudp") == "" {
query.Set("noudp", defaultUDPStrategy)
}

View File

@@ -23,9 +23,8 @@ import (
// Server 实现服务端模式功能
type Server struct {
Common // 继承共享功能
tlsConfig *tls.Config // TLS配置
clientIP string // 客户端IP
Common // 继承共享功能
clientIP string // 客户端IP
}
// NewServer 创建新的服务端实例
@@ -33,6 +32,7 @@ func NewServer(parsedURL *url.URL, tlsCode string, tlsConfig *tls.Config, logger
server := &Server{
Common: Common{
tlsCode: tlsCode,
tlsConfig: tlsConfig,
logger: logger,
signalChan: make(chan string, semaphoreLimit),
tcpBufferPool: &sync.Pool{
@@ -47,12 +47,10 @@ func NewServer(parsedURL *url.URL, tlsCode string, tlsConfig *tls.Config, logger
return &buf
},
},
cleanURL: &url.URL{Scheme: "np", Fragment: "c"},
flushURL: &url.URL{Scheme: "np", Fragment: "f"},
pingURL: &url.URL{Scheme: "np", Fragment: "i"},
pongURL: &url.URL{Scheme: "np", Fragment: "o"},
},
tlsConfig: tlsConfig,
}
if err := server.initConfig(parsedURL); err != nil {
return nil, fmt.Errorf("newServer: initConfig failed: %w", err)
@@ -64,9 +62,9 @@ func NewServer(parsedURL *url.URL, tlsCode string, tlsConfig *tls.Config, logger
// Run 管理服务端生命周期
func (s *Server) Run() {
logInfo := func(prefix string) {
s.logger.Info("%v: server://%v@%v/%v?max=%v&mode=%v&read=%v&rate=%v&slot=%v&proxy=%v&noudp=%v",
s.logger.Info("%v: server://%v@%v/%v?max=%v&mode=%v&read=%v&rate=%v&slot=%v&proxy=%v&notcp=%v&noudp=%v",
prefix, s.tunnelKey, s.tunnelTCPAddr, s.getTargetAddrsString(),
s.maxPoolCapacity, s.runMode, s.readTimeout, s.rateLimit/125000, s.slotLimit, s.proxyProtocol, s.disableUDP)
s.maxPoolCapacity, s.runMode, s.readTimeout, s.rateLimit/125000, s.slotLimit, s.proxyProtocol, s.disableTCP, s.disableUDP)
}
logInfo("Server started")
@@ -152,9 +150,12 @@ func (s *Server) start() error {
reportInterval)
go s.tunnelPool.ServerManager()
// 判断数据流向
if s.dataFlow == "-" {
go s.commonLoop()
}
// 启动共用控制
if err := s.commonControl(); err != nil {
return fmt.Errorf("start: commonControl failed: %w", err)
}