feat(agent): agent stream tunneling with TLS and dTLS (UDP) (#188)

* **New Features**
  * Multiplexed TLS port: HTTP API and a custom stream protocol can share one port via ALPN.
  * Agent-side TCP and DTLS/UDP stream tunneling with health-check support and runtime capability detection.
  * Agents now advertise per-agent stream support (TCP/UDP).

* **Documentation**
  * Added comprehensive stream protocol documentation.

* **Tests**
  * Extended integration and concurrency tests covering multiplexing, TCP/UDP streams, and health checks.

* **Chores**
  * Compose/template updated to expose both TCP and UDP ports.
This commit is contained in:
Yuzerion
2026-01-09 10:52:35 +08:00
committed by GitHub
parent 4275cdae38
commit 6fac5d2d3e
29 changed files with 1877 additions and 123 deletions

View File

@@ -11,6 +11,7 @@ import (
"github.com/rs/zerolog"
"github.com/yusing/godoxy/internal/acl"
"github.com/yusing/godoxy/internal/agentpool"
nettypes "github.com/yusing/godoxy/internal/net/types"
"github.com/yusing/goutils/synk"
"go.uber.org/atomic"
@@ -24,6 +25,7 @@ type UDPUDPStream struct {
laddr *net.UDPAddr
dst *net.UDPAddr
agent *agentpool.Agent
preDial nettypes.HookFunc
onRead nettypes.HookFunc
@@ -53,7 +55,7 @@ const (
var bufPool = synk.GetSizedBytesPool()
func NewUDPUDPStream(network, dstNetwork, listenAddr, dstAddr string) (nettypes.Stream, error) {
func NewUDPUDPStream(network, dstNetwork, listenAddr, dstAddr string, agent *agentpool.Agent) (nettypes.Stream, error) {
dst, err := net.ResolveUDPAddr(dstNetwork, dstAddr)
if err != nil {
return nil, err
@@ -67,6 +69,7 @@ func NewUDPUDPStream(network, dstNetwork, listenAddr, dstAddr string) (nettypes.
dstNetwork: dstNetwork,
laddr: laddr,
dst: dst,
agent: agent,
conns: make(map[string]*udpUDPConn),
}, nil
}
@@ -195,7 +198,11 @@ func (s *UDPUDPStream) createConnection(ctx context.Context, srcAddr *net.UDPAdd
dstConn net.Conn
err error
)
dstConn, err = net.DialUDP(s.dstNetwork, nil, s.dst)
if s.agent != nil {
dstConn, err = s.agent.NewUDPClient(s.dst.String())
} else {
dstConn, err = net.DialUDP(s.dst.Network(), nil, s.dst)
}
if err != nil {
logErr(s, err, "failed to dial dst")
return nil, false