mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-25 10:31:30 +01:00
feat(agent): agent stream tunneling with TLS and dTLS (UDP); combined agent APIs
- Add `StreamPort` configuration to agent configuration and environment variables - Implement TCP and UDP stream client support in agent package - Update agent verification to test stream connectivity (TCP/UDP) - Add `/info` endpoint to agent HTTP handler for version, name, runtime, and stream port - Remove /version, /name, /runtime APIs, replaced by /info - Update agent compose template to expose stream port for TCP and UDP - Update agent creation API to optionally specify stream port (defaults to port + 1) - Modify `StreamRoute` to pass agent configuration to stream implementations - Update `TCPTCPStream` and `UDPUDPStream` to use agent stream tunneling when agent is configured - Add support for both direct connections and agent-tunneled connections in stream routes This enables agents to handle TCP and UDP route tunneling, expanding the proxy capabilities beyond HTTP-only connections.
This commit is contained in:
@@ -110,9 +110,9 @@ func (r *StreamRoute) initStream() (nettypes.Stream, error) {
|
||||
|
||||
switch rurl.Scheme {
|
||||
case "tcp":
|
||||
return stream.NewTCPTCPStream(laddr, rurl.Host)
|
||||
return stream.NewTCPTCPStream(laddr, rurl.Host, r.GetAgent())
|
||||
case "udp":
|
||||
return stream.NewUDPUDPStream(laddr, rurl.Host)
|
||||
return stream.NewUDPUDPStream(laddr, rurl.Host, r.GetAgent())
|
||||
}
|
||||
return nil, fmt.Errorf("unknown scheme: %s", rurl.Scheme)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/pires/go-proxyproto"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||
"github.com/yusing/godoxy/internal/acl"
|
||||
"github.com/yusing/godoxy/internal/entrypoint"
|
||||
nettypes "github.com/yusing/godoxy/internal/net/types"
|
||||
@@ -17,6 +18,7 @@ type TCPTCPStream struct {
|
||||
listener net.Listener
|
||||
laddr *net.TCPAddr
|
||||
dst *net.TCPAddr
|
||||
agent *agent.AgentConfig
|
||||
|
||||
preDial nettypes.HookFunc
|
||||
onRead nettypes.HookFunc
|
||||
@@ -24,7 +26,7 @@ type TCPTCPStream struct {
|
||||
closed atomic.Bool
|
||||
}
|
||||
|
||||
func NewTCPTCPStream(listenAddr, dstAddr string) (nettypes.Stream, error) {
|
||||
func NewTCPTCPStream(listenAddr, dstAddr string, agentCfg *agent.AgentConfig) (nettypes.Stream, error) {
|
||||
dst, err := net.ResolveTCPAddr("tcp", dstAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -33,7 +35,7 @@ func NewTCPTCPStream(listenAddr, dstAddr string) (nettypes.Stream, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TCPTCPStream{laddr: laddr, dst: dst}, nil
|
||||
return &TCPTCPStream{laddr: laddr, dst: dst, agent: agentCfg}, nil
|
||||
}
|
||||
|
||||
func (s *TCPTCPStream) ListenAndServe(ctx context.Context, preDial, onRead nettypes.HookFunc) {
|
||||
@@ -126,7 +128,15 @@ func (s *TCPTCPStream) handle(ctx context.Context, conn net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
dstConn, err := net.DialTCP("tcp", nil, s.dst)
|
||||
var (
|
||||
dstConn net.Conn
|
||||
err error
|
||||
)
|
||||
if s.agent != nil {
|
||||
dstConn, err = s.agent.NewTCPClient(s.dst.String())
|
||||
} else {
|
||||
dstConn, err = net.DialTCP("tcp", nil, s.dst)
|
||||
}
|
||||
if err != nil {
|
||||
if !s.closed.Load() {
|
||||
logErr(s, err, "failed to dial destination")
|
||||
@@ -140,7 +150,7 @@ func (s *TCPTCPStream) handle(ctx context.Context, conn net.Conn) {
|
||||
}
|
||||
|
||||
src := conn
|
||||
dst := net.Conn(dstConn)
|
||||
dst := dstConn
|
||||
if s.onRead != nil {
|
||||
src = &wrapperConn{
|
||||
Conn: conn,
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||
"github.com/yusing/godoxy/internal/acl"
|
||||
nettypes "github.com/yusing/godoxy/internal/net/types"
|
||||
"github.com/yusing/goutils/synk"
|
||||
@@ -22,6 +23,7 @@ type UDPUDPStream struct {
|
||||
|
||||
laddr *net.UDPAddr
|
||||
dst *net.UDPAddr
|
||||
agent *agent.AgentConfig
|
||||
|
||||
preDial nettypes.HookFunc
|
||||
onRead nettypes.HookFunc
|
||||
@@ -35,7 +37,7 @@ type UDPUDPStream struct {
|
||||
|
||||
type udpUDPConn struct {
|
||||
srcAddr *net.UDPAddr
|
||||
dstConn *net.UDPConn
|
||||
dstConn net.Conn
|
||||
listener net.PacketConn
|
||||
lastUsed atomic.Time
|
||||
closed atomic.Bool
|
||||
@@ -51,7 +53,7 @@ const (
|
||||
|
||||
var bufPool = synk.GetSizedBytesPool()
|
||||
|
||||
func NewUDPUDPStream(listenAddr, dstAddr string) (nettypes.Stream, error) {
|
||||
func NewUDPUDPStream(listenAddr, dstAddr string, agentCfg *agent.AgentConfig) (nettypes.Stream, error) {
|
||||
dst, err := net.ResolveUDPAddr("udp", dstAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -63,6 +65,7 @@ func NewUDPUDPStream(listenAddr, dstAddr string) (nettypes.Stream, error) {
|
||||
return &UDPUDPStream{
|
||||
laddr: laddr,
|
||||
dst: dst,
|
||||
agent: agentCfg,
|
||||
conns: make(map[string]*udpUDPConn),
|
||||
}, nil
|
||||
}
|
||||
@@ -189,8 +192,16 @@ func (s *UDPUDPStream) createConnection(ctx context.Context, srcAddr *net.UDPAdd
|
||||
}
|
||||
}
|
||||
|
||||
// Create UDP connection to destination
|
||||
dstConn, err := net.DialUDP("udp", nil, s.dst)
|
||||
// Create connection to destination (direct UDP or via agent stream tunnel)
|
||||
var (
|
||||
dstConn net.Conn
|
||||
err error
|
||||
)
|
||||
if s.agent != nil {
|
||||
dstConn, err = s.agent.NewUDPClient(s.dst.String())
|
||||
} else {
|
||||
dstConn, err = net.DialUDP("udp", nil, s.dst)
|
||||
}
|
||||
if err != nil {
|
||||
logErr(s, err, "failed to dial dst")
|
||||
return nil, false
|
||||
@@ -205,7 +216,7 @@ func (s *UDPUDPStream) createConnection(ctx context.Context, srcAddr *net.UDPAdd
|
||||
|
||||
// Send initial data before starting response handler
|
||||
if !conn.forwardToDestination(initialData) {
|
||||
dstConn.Close()
|
||||
_ = dstConn.Close()
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -328,6 +339,6 @@ func (conn *udpUDPConn) Close() {
|
||||
|
||||
conn.closed.Store(true)
|
||||
|
||||
conn.dstConn.Close()
|
||||
_ = conn.dstConn.Close()
|
||||
conn.dstConn = nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user