Update On Wed Jul 16 20:42:02 CEST 2025

This commit is contained in:
github-action[bot]
2025-07-16 20:42:02 +02:00
parent 91f20f1ca8
commit c862c33495
82 changed files with 547 additions and 374 deletions

View File

@@ -1,7 +1,7 @@
<div align="center">
<img src="https://cdn.yobc.de/assets/np-gopher.png" alt="nodepass" width="300">
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#networking)
[![GitHub release](https://img.shields.io/github/v/release/yosebyte/nodepass)](https://github.com/yosebyte/nodepass/releases)
[![GitHub downloads](https://img.shields.io/github/downloads/yosebyte/nodepass/total.svg)](https://github.com/yosebyte/nodepass/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/yosebyte/nodepass)](https://goreportcard.com/report/github.com/yosebyte/nodepass)
@@ -18,7 +18,7 @@ English | [简体中文](README_zh.md)
## 💎 Key Features
- **🌐 Universal Functionality**
- Supports TCP/UDP tunneling and protocol conversion across diverse networks.
- Basic TCP/UDP tunneling and protocol conversion across diverse networks.
- Compatible with port mapping, NAT traversal, and traffic relay.
- Cross-platform, multi-architecture, single binary or container.
@@ -27,20 +27,20 @@ English | [简体中文](README_zh.md)
- Eliminates handshake delays, boosts performance.
- Auto-scaling with real-time capacity adjustment.
- **⚙️ Zero-Config**
- No config files required, ready to use via CLI.
- Optimized for CI/CD and containers.
- Flexible tuning via environment variables.
- **🧬 Innovative Architecture**
- Integrated S/C/M architecture, flexible mode switching.
- Full decoupling of control/data channels.
- API-instance management, multi-instance collaboration.
- **🔐 Multi-level Security**
- Three TLS modes: plaintext, self-signed, strict validation.
- Covers development to enterprise security needs.
- Hot-reload certificates with zero downtime.
- **🧠 Innovative Architecture**
- Integrated S/C/M architecture, flexible mode switching.
- Full decoupling of control/data channels.
- API-instance management, multi-instance collaboration.
- **⚙️ Minimal Configuration**
- No config files required, ready to use via CLI.
- Optimized for CI/CD and containers.
- Flexible tuning via environment variables.
- **📈 Performance**
- Intelligent scheduling, auto-tuning, ultra-low resource usage.
@@ -88,7 +88,7 @@ Explore the complete documentation to learn more about NodePass:
- [How It Works](/docs/en/how-it-works.md)
- [Troubleshooting](/docs/en/troubleshooting.md)
## 🌐 Ecosystem
## 🌱 Ecosystem
The [NodePassProject](https://github.com/NodePassProject) organization develops various frontend applications and auxiliary tools to enhance the NodePass experience:

View File

@@ -1,7 +1,7 @@
<div align="center">
<img src="https://cdn.yobc.de/assets/np-gopher.png" alt="nodepass" width="300">
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#networking)
[![GitHub release](https://img.shields.io/github/v/release/yosebyte/nodepass)](https://github.com/yosebyte/nodepass/releases)
[![GitHub downloads](https://img.shields.io/github/downloads/yosebyte/nodepass/total.svg)](https://github.com/yosebyte/nodepass/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/yosebyte/nodepass)](https://goreportcard.com/report/github.com/yosebyte/nodepass)
@@ -18,7 +18,7 @@
## 💎 核心功能
- **🌐 通用网络隧道**
- 支持 TCP/UDP 隧道,具备协议转换能力,适配多种网络结构。
- 基础 TCP/UDP 隧道,具备协议转换能力,适配多种网络结构。
- 完整适配端口映射、内网穿透、流量中转等多场景应用需求。
- 多平台、多架构支持,支持独立二进制文件、容器灵活部署。
@@ -27,27 +27,27 @@
- 消除连接的握手等待,显著提升了性能体验。
- 支持实时容量自适应,动态调整连接池规模。
- **⚙️ 零配置启动**
- 无需配置文件,仅命令行参数即可运行,适合自动化和快速迭代
- 适配 CI/CD 流程与容器环境,极大提升部署和运维效率
- 支持环境变量性能调优,灵活适应不同运行环境
- **🧬 创新架构设计**
- Server-Client-Master 多模式整合架构设计,灵活切换
- 将 S/C 控制通道与数据通道完全解耦,相互独立、各司其职
- 主控-实例的管理方式,支持动态扩容、多实例协作和集中控制
- **🔐 多级安全策略**
- 三种 TLS 模式:明文、自签名、严格验证,适配不同安全等级。
- 满足从开发测试到企业级高安全部署的全场景需求。
- 支持证书文件的热重载,免停运、无缝处理证书更新问题。
- **🧠 创新架构设计**
- Server-Client-Master 多模式整合架构设计,灵活切换
- 将 S/C 控制通道与数据通道完全解耦,相互独立、各司其职
- 主控-实例的管理方式,支持动态扩容、多实例协作和集中控制
- **⚙️ 极简配置方式**
- 无需配置文件,仅命令行参数即可运行,适合自动化和快速迭代
- 适配 CI/CD 流程与容器环境,极大提升部署和运维效率
- 支持环境变量性能调优,灵活适应不同运行环境
- **📈 高性能优化**
- 智能流量调度与自动连接调优,极低资源占用。
- 高并发、高负载状态下卓越的系统稳定性能。
- 健康检查、断线重连、故障自愈,确保持续高可用。
- **💡 可视化生态**
- **💡 可视化管理**
- 配套跨平台、多样化的管理前端应用,具备可视化配置能力。
- 主流平台支持一键部署脚本,支撑灵活配置和辅助管理。
- 具备实时隧道监控、实例管理、主控管理、流量统计等丰富功能。
@@ -88,7 +88,7 @@ nodepass "master://:10101/api?log=debug&tls=1"
- [工作原理](/docs/zh/how-it-works.md)
- [故障排除](/docs/zh/troubleshooting.md)
## 🌐 生态系统
## 🌱 生态系统
[NodePassProject](https://github.com/NodePassProject) 组织开发了各种前端应用和辅助工具来增强 NodePass 体验:

View File

@@ -6,5 +6,5 @@ require (
github.com/NodePassProject/cert v1.0.0
github.com/NodePassProject/conn v1.0.1
github.com/NodePassProject/logs v1.0.1
github.com/NodePassProject/pool v1.0.8
github.com/NodePassProject/pool v1.0.9
)

View File

@@ -4,5 +4,5 @@ github.com/NodePassProject/conn v1.0.1 h1:vuzcQQj+cqENagzEYPwse9Vvlj/8vfkyNZCp5R
github.com/NodePassProject/conn v1.0.1/go.mod h1:mWe3Rylunp6Sx4v6pkSGgYZe2R+I/O+7nZ2od0yJ3aQ=
github.com/NodePassProject/logs v1.0.1 h1:WDHY1DcTO+7NydBzuRpxhEw6pWYayBdDjjZzU1uDKac=
github.com/NodePassProject/logs v1.0.1/go.mod h1:ocFTMNXBTnQFJFAhF+qobAzu7+y+wYPik7D+a1jPfis=
github.com/NodePassProject/pool v1.0.8 h1:zuqVdQj0OBarIo/P/BdpTxXk8kbjU2GYJJaVA5T+LwQ=
github.com/NodePassProject/pool v1.0.8/go.mod h1:kdRAEDK45j/+iHH4kRTpXt/wI28NIguJ13n/5NDXxkw=
github.com/NodePassProject/pool v1.0.9 h1:8VKKv8kJqg1FX9Odx9Vu2eTUOpO2G84uSfiyDTuHvvA=
github.com/NodePassProject/pool v1.0.9/go.mod h1:kdRAEDK45j/+iHH4kRTpXt/wI28NIguJ13n/5NDXxkw=

View File

@@ -401,12 +401,6 @@ func (c *Common) commonTCPLoop() {
continue
}
defer func() {
if targetConn != nil {
targetConn.Close()
}
}()
c.targetTCPConn = targetConn.(*net.TCPConn)
c.logger.Debug("Target connection: %v <-> %v", targetConn.LocalAddr(), targetConn.RemoteAddr())
@@ -414,7 +408,12 @@ func (c *Common) commonTCPLoop() {
c.semaphore <- struct{}{}
go func(targetConn net.Conn) {
defer func() { <-c.semaphore }()
defer func() {
if targetConn != nil {
targetConn.Close()
}
<-c.semaphore
}()
// 从连接池获取连接
id, remoteConn := c.tunnelPool.ServerGet()
@@ -448,7 +447,7 @@ func (c *Common) commonTCPLoop() {
return
}
c.logger.Debug("TCP launch signal: %v -> %v", id, c.tunnelTCPConn.RemoteAddr())
c.logger.Debug("TCP launch signal: pid %v -> %v", id, c.tunnelTCPConn.RemoteAddr())
c.logger.Debug("Starting exchange: %v <-> %v", remoteConn.LocalAddr(), targetConn.LocalAddr())
// 交换数据
@@ -468,8 +467,9 @@ func (c *Common) commonUDPLoop() {
case <-c.ctx.Done():
return
default:
// 读取来自目标的UDP数据
buffer := make([]byte, udpDataBufSize)
// 读取来自目标的UDP数据
n, clientAddr, err := c.targetUDPConn.ReadFromUDP(buffer)
if err != nil {
continue
@@ -477,7 +477,7 @@ func (c *Common) commonUDPLoop() {
c.logger.Debug("Target connection: %v <-> %v", c.targetUDPConn.LocalAddr(), clientAddr)
// 从连接池获取连接
// 获取连接
id, remoteConn := c.tunnelPool.ServerGet()
if remoteConn == nil {
c.logger.Error("Get failed: %v not found", id)
@@ -486,51 +486,84 @@ func (c *Common) commonUDPLoop() {
}
c.logger.Debug("Tunnel connection: get %v <- pool active %v", id, c.tunnelPool.Active())
defer func() {
c.tunnelPool.Put(id, remoteConn)
c.logger.Debug("Tunnel connection: put %v -> pool active %v", id, c.tunnelPool.Active())
}()
c.logger.Debug("Tunnel connection: %v <-> %v", remoteConn.LocalAddr(), remoteConn.RemoteAddr())
// 使用信号量限制并发数
c.semaphore <- struct{}{}
go func(buffer []byte, n int, clientAddr *net.UDPAddr, remoteConn net.Conn) {
defer func() { <-c.semaphore }()
go func(remoteConn net.Conn, clientAddr *net.UDPAddr, id string) {
defer func() {
c.tunnelPool.Put(id, remoteConn)
c.logger.Debug("Tunnel connection: put %v -> pool active %v", id, c.tunnelPool.Active())
<-c.semaphore
}()
// 构建并发送启动URL到客户端
launchURL := &url.URL{
Host: id,
Fragment: "2", // UDP模式
buffer := make([]byte, udpDataBufSize)
for {
select {
case <-c.ctx.Done():
return
default:
// 设置TCP读取超时
if err := remoteConn.SetReadDeadline(time.Now().Add(tcpReadTimeout)); err != nil {
c.logger.Error("SetReadDeadline failed: %v", err)
return
}
// 从池连接读取数据
x, err := remoteConn.Read(buffer)
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
c.logger.Debug("UDP session abort: %v", err)
} else if strings.Contains(err.Error(), "use of closed network connection") {
c.logger.Debug("Read closed: %v", err)
} else {
c.logger.Error("Read failed: %v", err)
}
return
}
// 将数据写入目标UDP连接
tx, err := c.targetUDPConn.WriteToUDP(buffer[:x], clientAddr)
if err != nil {
c.logger.Error("WriteToUDP failed: %v", err)
return
}
// 传输完成,广播统计信息
c.logger.Event("Transfer complete: TRAFFIC_STATS|TCP_RX=0|TCP_TX=0|UDP_RX=0|UDP_TX=%v", tx)
}
}
}(remoteConn, clientAddr, id)
c.mu.Lock()
_, err = c.tunnelTCPConn.Write(append(c.xor([]byte(launchURL.String())), '\n'))
c.mu.Unlock()
// 构建并发送启动URL到客户端
launchURL := &url.URL{
Host: clientAddr.String(),
Path: id,
Fragment: "2", // UDP模式
}
if err != nil {
c.logger.Error("Write failed: %v", err)
return
}
c.mu.Lock()
_, err = c.tunnelTCPConn.Write(append(c.xor([]byte(launchURL.String())), '\n'))
c.mu.Unlock()
if err != nil {
c.logger.Error("Write failed: %v", err)
continue
}
c.logger.Debug("UDP launch signal: %v -> %v", id, c.tunnelTCPConn.RemoteAddr())
c.logger.Debug("Starting transfer: %v <-> %v", remoteConn.LocalAddr(), c.targetUDPConn.LocalAddr())
c.logger.Debug("UDP launch signal: pid %v -> %v", id, c.tunnelTCPConn.RemoteAddr())
c.logger.Debug("Starting transfer: %v <-> %v", remoteConn.LocalAddr(), c.targetUDPConn.LocalAddr())
// 处理UDP/TCP数据传输
rx, tx, _ := conn.DataTransfer(
c.targetUDPConn,
remoteConn,
clientAddr,
buffer[:n],
udpDataBufSize,
tcpReadTimeout,
)
// 将原始数据写入池连接
rx, err := remoteConn.Write(buffer[:n])
if err != nil {
c.logger.Error("Write failed: %v", err)
remoteConn.Close()
continue
}
// 传输完成,广播统计信息
c.logger.Event("Transfer complete: TRAFFIC_STATS|TCP_RX=0|TCP_TX=0|UDP_RX=%v|UDP_TX=%v", rx, tx)
}(buffer, n, clientAddr, remoteConn)
// 传输完成,广播统计信息
c.logger.Event("Transfer complete: TRAFFIC_STATS|TCP_RX=0|TCP_TX=0|UDP_RX=%v|UDP_TX=0", rx)
}
}
}
@@ -566,7 +599,7 @@ func (c *Common) commonOnce() {
case "1": // TCP
go c.commonTCPOnce(signalURL.Host)
case "2": // UDP
go c.commonUDPOnce(signalURL.Host)
go c.commonUDPOnce(signalURL)
default:
// 健康检查或无效信号
}
@@ -576,7 +609,7 @@ func (c *Common) commonOnce() {
// commonTCPOnce 共用处理单个TCP请求
func (c *Common) commonTCPOnce(id string) {
c.logger.Debug("TCP launch signal: %v <- %v", id, c.tunnelTCPConn.RemoteAddr())
c.logger.Debug("TCP launch signal: pid %v <- %v", id, c.tunnelTCPConn.RemoteAddr())
// 从连接池获取连接
remoteConn := c.tunnelPool.ClientGet(id)
@@ -619,54 +652,125 @@ func (c *Common) commonTCPOnce(id string) {
}
// commonUDPOnce 共用处理单个UDP请求
func (c *Common) commonUDPOnce(id string) {
c.logger.Debug("UDP launch signal: %v <- %v", id, c.tunnelTCPConn.RemoteAddr())
func (c *Common) commonUDPOnce(signalURL *url.URL) {
id := strings.TrimPrefix(signalURL.Path, "/")
c.logger.Debug("UDP launch signal: pid %v <- %v", id, c.tunnelTCPConn.RemoteAddr())
// 从连接池获取连接
// 获取连接
remoteConn := c.tunnelPool.ClientGet(id)
if remoteConn == nil {
c.logger.Error("Get failed: %v not found", id)
return
}
c.logger.Debug("Tunnel connection: get %v <- pool active %v", id, c.tunnelPool.Active())
defer func() {
c.tunnelPool.Put(id, remoteConn)
c.logger.Debug("Tunnel connection: put %v -> pool active %v", id, c.tunnelPool.Active())
}()
c.logger.Debug("Tunnel connection: %v <-> %v", remoteConn.LocalAddr(), remoteConn.RemoteAddr())
// 连接到目标UDP地址
targetConn, err := net.DialTimeout("udp", c.targetUDPAddr.String(), udpDialTimeout)
if err != nil {
c.logger.Error("Dial failed: %v", err)
return
var targetConn *net.UDPConn
sessionKey := signalURL.Host
// 获取或创建目标UDP会话
if session, ok := c.targetUDPSession.Load(sessionKey); ok {
targetConn = session.(*net.UDPConn)
c.logger.Debug("Using UDP session: %v <-> %v", targetConn.LocalAddr(), targetConn.RemoteAddr())
} else {
// 创建新的会话
session, err := net.DialTimeout("udp", c.targetUDPAddr.String(), udpDialTimeout)
if err != nil {
c.logger.Error("Dial failed: %v", err)
return
}
c.targetUDPSession.Store(sessionKey, session)
targetConn = session.(*net.UDPConn)
c.logger.Debug("Target connection: %v <-> %v", targetConn.LocalAddr(), targetConn.RemoteAddr())
}
defer func() {
if targetConn != nil {
targetConn.Close()
done := make(chan struct{}, 2)
go func() {
defer func() { done <- struct{}{} }()
buffer := make([]byte, udpDataBufSize)
for {
select {
case <-c.ctx.Done():
return
default:
// 设置TCP读取超时
if err := remoteConn.SetReadDeadline(time.Now().Add(tcpReadTimeout)); err != nil {
c.logger.Error("SetReadDeadline failed: %v", err)
return
}
// 从隧道连接读取数据
x, err := remoteConn.Read(buffer)
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
c.logger.Debug("Read timeout: %v", err)
} else if strings.Contains(err.Error(), "use of closed network connection") {
c.logger.Debug("Read closed: %v", err)
} else {
c.logger.Error("Read failed: %v", err)
}
return
}
// 将数据写入目标UDP连接
rx, err := targetConn.Write(buffer[:x])
if err != nil {
c.logger.Error("Write failed: %v", err)
return
}
// 传输完成,广播统计信息
c.logger.Event("Transfer complete: TRAFFIC_STATS|TCP_RX=0|TCP_TX=0|UDP_RX=%v|UDP_TX=0", rx)
}
}
}()
c.targetUDPConn = targetConn.(*net.UDPConn)
c.logger.Debug("Target connection: %v <-> %v", targetConn.LocalAddr(), targetConn.RemoteAddr())
c.logger.Debug("Starting transfer: %v <-> %v", remoteConn.LocalAddr(), targetConn.LocalAddr())
go func() {
defer func() { done <- struct{}{} }()
buffer := make([]byte, udpDataBufSize)
for {
select {
case <-c.ctx.Done():
return
default:
// 设置UDP读取超时
if err := targetConn.SetReadDeadline(time.Now().Add(udpReadTimeout)); err != nil {
c.logger.Error("SetReadDeadline failed: %v", err)
return
}
// 处理UDP/TCP数据传输
rx, tx, _ := conn.DataTransfer(
c.targetUDPConn,
remoteConn,
nil,
nil,
udpDataBufSize,
udpReadTimeout,
)
// 从目标UDP连接读取数据
x, err := targetConn.Read(buffer)
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
c.logger.Debug("Read timeout: %v", err)
} else if strings.Contains(err.Error(), "use of closed network connection") {
c.logger.Debug("Read closed: %v", err)
} else {
c.logger.Error("Read failed: %v", err)
}
return
}
// 传输完成,广播统计信息
c.logger.Event("Transfer complete: TRAFFIC_STATS|TCP_RX=0|TCP_TX=0|UDP_RX=%v|UDP_TX=%v", rx, tx)
// 将数据写回隧道连接
tx, err := remoteConn.Write(buffer[:x])
if err != nil {
c.logger.Error("Write failed: %v", err)
return
}
// 传输完成,广播统计信息
c.logger.Event("Transfer complete: TRAFFIC_STATS|TCP_RX=0|TCP_TX=0|UDP_RX=0|UDP_TX=%v", tx)
}
}
}()
// 等待任一协程完成
<-done
c.tunnelPool.Put(id, remoteConn)
c.logger.Debug("Tunnel connection: put %v -> pool active %v", id, c.tunnelPool.Active())
}
// singleLoop 单端转发处理循环
@@ -700,12 +804,6 @@ func (c *Common) singleTCPLoop() error {
continue
}
defer func() {
if tunnelConn != nil {
tunnelConn.Close()
}
}()
c.tunnelTCPConn = tunnelConn.(*net.TCPConn)
c.logger.Debug("Tunnel connection: %v <-> %v", tunnelConn.LocalAddr(), tunnelConn.RemoteAddr())
@@ -713,21 +811,26 @@ func (c *Common) singleTCPLoop() error {
c.semaphore <- struct{}{}
go func(tunnelConn net.Conn) {
defer func() { <-c.semaphore }()
defer func() {
if tunnelConn != nil {
tunnelConn.Close()
}
<-c.semaphore
}()
// 从连接池中获取连接
targetConn := c.tunnelPool.ClientGet("")
if targetConn == nil {
c.logger.Error("Get failed: no target connection available")
time.Sleep(100 * time.Millisecond)
return
}
c.logger.Debug("Target connection: pool active %v / %v per %v", c.tunnelPool.Active(), c.tunnelPool.Capacity(), c.tunnelPool.Interval())
c.logger.Debug("Target connection: get relay-id <- pool active %v", c.tunnelPool.Active())
defer func() {
if targetConn != nil {
targetConn.Close()
}
c.tunnelPool.Put("", targetConn)
c.logger.Debug("Tunnel connection: put relay-id -> pool active %v", c.tunnelPool.Active())
}()
c.targetTCPConn = targetConn.(*net.TCPConn)
@@ -785,7 +888,12 @@ func (c *Common) singleUDPLoop() error {
c.semaphore <- struct{}{}
go func(targetConn *net.UDPConn, clientAddr *net.UDPAddr, sessionKey string) {
defer func() { <-c.semaphore }()
defer func() {
if targetConn != nil {
targetConn.Close()
}
<-c.semaphore
}()
buffer := make([]byte, udpDataBufSize)
@@ -805,9 +913,10 @@ func (c *Common) singleUDPLoop() error {
// 从UDP读取响应
n, err := targetConn.Read(buffer)
if err != nil {
// 检查是否为超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
c.logger.Debug("UDP session abort: %v", err)
} else if strings.Contains(err.Error(), "use of closed network connection") {
c.logger.Debug("Read closed: %v", err)
} else {
c.logger.Error("Read failed: %v", err)
}