227 lines
5.6 KiB
Go
227 lines
5.6 KiB
Go
package server
|
||
|
||
import (
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"net"
|
||
"sync"
|
||
"time"
|
||
|
||
"net-tunnel/pkg/proto"
|
||
)
|
||
|
||
// ProxyEntry 表示一个代理条目
|
||
type ProxyEntry struct {
|
||
Config *proto.ProxyConfig
|
||
ClientID string
|
||
TCPListener net.Listener // 用于 TCP 代理
|
||
TCPConns sync.Map // map[remoteAddr]net.Conn 用于 TCP 代理
|
||
UDPConn *net.UDPConn // 用于 UDP 代理
|
||
}
|
||
|
||
// ProxyManager 管理所有代理
|
||
type ProxyManager struct {
|
||
proxies sync.Map // map[proxyName]*ProxyEntry
|
||
connManager *ConnectionManager
|
||
}
|
||
|
||
// NewProxyManager 创建新的代理管理器
|
||
func NewProxyManager(connManager *ConnectionManager) *ProxyManager {
|
||
return &ProxyManager{
|
||
proxies: sync.Map{},
|
||
connManager: connManager,
|
||
}
|
||
}
|
||
|
||
// RegisterProxy 注册一个新的代理
|
||
func (m *ProxyManager) RegisterProxy(clientID string, config *proto.ProxyConfig) error {
|
||
if _, exists := m.proxies.Load(config.Name); exists {
|
||
return fmt.Errorf("proxy %s already registered", config.Name)
|
||
}
|
||
|
||
entry := &ProxyEntry{
|
||
Config: config,
|
||
ClientID: clientID,
|
||
}
|
||
|
||
// 根据代理类型启动监听器
|
||
var err error
|
||
if config.Type == proto.ProxyType_TCP {
|
||
err = m.startTCPProxy(entry)
|
||
} else if config.Type == proto.ProxyType_UDP {
|
||
err = m.startUDPProxy(entry)
|
||
} else {
|
||
return fmt.Errorf("unsupported proxy type: %v", config.Type)
|
||
}
|
||
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
m.proxies.Store(config.Name, entry)
|
||
log.Printf("Registered proxy: %s (type: %s, port: %d)",
|
||
config.Name, config.Type, config.RemotePort)
|
||
|
||
return nil
|
||
}
|
||
|
||
// UnregisterProxy 注销一个代理
|
||
func (m *ProxyManager) UnregisterProxy(clientID, proxyName string) {
|
||
m.closeProxyLocked(proxyName)
|
||
}
|
||
|
||
// UnregisterAllProxies 注销客户端的所有代理
|
||
func (m *ProxyManager) UnregisterAllProxies(clientID string) {
|
||
m.proxies.Range(func(key, value interface{}) bool {
|
||
if entry, ok := value.(*ProxyEntry); ok && entry.ClientID == clientID {
|
||
m.closeProxyLocked(key.(string))
|
||
}
|
||
return true
|
||
})
|
||
}
|
||
|
||
// closeProxyLocked 关闭代理(在持有锁的情况下调用)
|
||
func (m *ProxyManager) closeProxyLocked(proxyID string) {
|
||
if entry, exists := m.proxies.Load(proxyID); exists {
|
||
entry := entry.(*ProxyEntry)
|
||
if entry.TCPListener != nil {
|
||
entry.TCPListener.Close()
|
||
}
|
||
if entry.UDPConn != nil {
|
||
entry.UDPConn.Close()
|
||
}
|
||
m.proxies.Delete(proxyID)
|
||
log.Printf("Unregistered proxy: %s", entry.Config.Name)
|
||
}
|
||
}
|
||
|
||
// startTCPProxy 启动一个 TCP 代理
|
||
func (m *ProxyManager) startTCPProxy(entry *ProxyEntry) error {
|
||
addr := fmt.Sprintf(":%d", entry.Config.RemotePort)
|
||
listener, err := net.Listen("tcp", addr)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to listen on port %d: %v", entry.Config.RemotePort, err)
|
||
}
|
||
|
||
entry.TCPListener = listener
|
||
|
||
// 启动协程接受连接
|
||
go m.handleTCPConnections(entry)
|
||
|
||
return nil
|
||
}
|
||
|
||
// startUDPProxy 启动一个 UDP 代理
|
||
func (m *ProxyManager) startUDPProxy(entry *ProxyEntry) error {
|
||
addr := fmt.Sprintf(":%d", entry.Config.RemotePort)
|
||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to resolve address %s: %v", addr, err)
|
||
}
|
||
|
||
conn, err := net.ListenUDP("udp", udpAddr)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to listen on UDP port %d: %v", entry.Config.RemotePort, err)
|
||
}
|
||
|
||
entry.UDPConn = conn
|
||
|
||
// 启动协程接收 UDP 数据包
|
||
go m.handleUDPPackets(entry)
|
||
|
||
return nil
|
||
}
|
||
|
||
// handleTCPConnections 处理传入的 TCP 连接
|
||
func (m *ProxyManager) handleTCPConnections(entry *ProxyEntry) {
|
||
for {
|
||
conn, err := entry.TCPListener.Accept()
|
||
if err != nil {
|
||
// 监听器可能已关闭
|
||
log.Printf("TCP listener for %s closed: %v", entry.Config.Name, err)
|
||
break
|
||
}
|
||
|
||
go m.handleTCPConnection(entry, conn)
|
||
}
|
||
}
|
||
|
||
// handleUDPPackets 处理传入的 UDP 数据包
|
||
func (m *ProxyManager) handleUDPPackets(entry *ProxyEntry) {
|
||
buffer := make([]byte, 4096)
|
||
for {
|
||
n, addr, err := entry.UDPConn.ReadFromUDP(buffer)
|
||
if err != nil {
|
||
// 连接可能已关闭
|
||
log.Printf("UDP connection for %s closed: %v", entry.Config.Name, err)
|
||
break
|
||
}
|
||
|
||
go m.handleUDPPacket(entry, buffer[:n], addr)
|
||
}
|
||
}
|
||
|
||
func (m *ProxyManager) handleTCPConnection(entry *ProxyEntry, conn net.Conn) {
|
||
if tcpConn, ok := conn.(*net.TCPConn); ok {
|
||
_ = tcpConn.SetKeepAlive(true)
|
||
_ = tcpConn.SetKeepAlivePeriod(30 * time.Second)
|
||
_ = tcpConn.SetNoDelay(true) // 对SSH协议很重要,避免数据包延迟
|
||
}
|
||
connID := fmt.Sprintf("%s_%d", conn.RemoteAddr().String(), time.Now().UnixNano())
|
||
|
||
defer func() {
|
||
conn.Close()
|
||
entry.TCPConns.Delete(connID)
|
||
log.Printf("TCP connection for %s closed", connID)
|
||
}()
|
||
|
||
// 获取客户端的控制连接
|
||
controlConn, ok := m.connManager.GetConnection(entry.ClientID)
|
||
if !ok {
|
||
log.Printf("Control connection not found for client %s", entry.ClientID)
|
||
return
|
||
}
|
||
|
||
entry.TCPConns.Store(connID, conn)
|
||
log.Printf("TCP connection for %s accepted", connID)
|
||
|
||
wg := sync.WaitGroup{}
|
||
wg.Add(1)
|
||
// 启动数据转发
|
||
go func() {
|
||
defer wg.Done()
|
||
buffer := make([]byte, 4096)
|
||
for {
|
||
n, err := conn.Read(buffer)
|
||
if err != nil {
|
||
if err == io.EOF {
|
||
log.Printf("TCP connection for %s closed", connID)
|
||
} else {
|
||
log.Printf("Failed to read from TCP connection: %v", err)
|
||
}
|
||
return
|
||
}
|
||
|
||
// 发送数据到客户端
|
||
err = controlConn.Send(&proto.Message{
|
||
Content: &proto.Message_ProxyData{
|
||
ProxyData: &proto.ProxyData{
|
||
ConnId: connID,
|
||
ProxyConfig: entry.Config,
|
||
Data: buffer[:n],
|
||
},
|
||
},
|
||
})
|
||
if err != nil {
|
||
log.Printf("Failed to send proxy data: %v", err)
|
||
return
|
||
}
|
||
}
|
||
}()
|
||
wg.Wait()
|
||
}
|
||
|
||
func (m *ProxyManager) handleUDPPacket(entry *ProxyEntry, data []byte, addr *net.UDPAddr) {
|
||
}
|