2025-03-07 15:50:57 +08:00
|
|
|
package fwd
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
|
|
|
|
"context"
|
2025-05-14 17:46:34 +08:00
|
|
|
"encoding/binary"
|
2025-05-16 15:13:16 +08:00
|
|
|
"errors"
|
2025-05-14 17:46:34 +08:00
|
|
|
"fmt"
|
|
|
|
|
"io"
|
2025-03-07 15:50:57 +08:00
|
|
|
"log/slog"
|
|
|
|
|
"net"
|
|
|
|
|
"proxy-server/pkg/utils"
|
2025-05-15 15:56:20 +08:00
|
|
|
"proxy-server/server/app"
|
|
|
|
|
"proxy-server/server/env"
|
2025-05-14 17:46:34 +08:00
|
|
|
"proxy-server/server/report"
|
2025-03-07 15:50:57 +08:00
|
|
|
"strconv"
|
|
|
|
|
)
|
|
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
type CtrlCmdType int
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
const (
|
|
|
|
|
CtrlCmdPong CtrlCmdType = iota + 1
|
|
|
|
|
CtrlCmdPing
|
|
|
|
|
CtrlCmdOpen
|
|
|
|
|
CtrlCmdClose
|
|
|
|
|
CtrlCmdProxy
|
|
|
|
|
)
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
func (s *Service) listenCtrl() error {
|
2025-03-07 15:50:57 +08:00
|
|
|
ctrlPort := env.AppCtrlPort
|
|
|
|
|
slog.Debug("监听控制通道", slog.Uint64("port", uint64(ctrlPort)))
|
|
|
|
|
|
|
|
|
|
// 监听端口
|
|
|
|
|
ls, err := net.Listen("tcp", ":"+strconv.Itoa(int(ctrlPort)))
|
|
|
|
|
if err != nil {
|
2025-05-14 17:46:34 +08:00
|
|
|
return fmt.Errorf("监听控制通道失败: %w", err)
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
|
|
|
|
defer utils.Close(ls)
|
|
|
|
|
|
|
|
|
|
// 处理连接
|
2025-05-16 16:59:33 +08:00
|
|
|
// 异步等待连接
|
|
|
|
|
var connCh = make(chan net.Conn)
|
|
|
|
|
go func() {
|
|
|
|
|
for {
|
|
|
|
|
conn, err := ls.Accept()
|
|
|
|
|
if errors.Is(err, net.ErrClosed) {
|
|
|
|
|
slog.Debug("控制通道监听关闭")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("接受控制通道连接失败", "err", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
select {
|
|
|
|
|
case connCh <- conn:
|
|
|
|
|
case <-s.ctx.Done():
|
|
|
|
|
utils.Close(conn)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2025-03-07 15:50:57 +08:00
|
|
|
err = nil
|
2025-05-16 16:59:33 +08:00
|
|
|
for {
|
2025-03-07 15:50:57 +08:00
|
|
|
select {
|
|
|
|
|
case <-s.ctx.Done():
|
2025-05-16 16:59:33 +08:00
|
|
|
return nil
|
|
|
|
|
case conn := <-connCh:
|
2025-03-07 15:50:57 +08:00
|
|
|
s.ctrlConnWg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
defer s.ctrlConnWg.Done()
|
|
|
|
|
defer utils.Close(conn)
|
2025-05-16 15:13:16 +08:00
|
|
|
err := s.processCtrlConn(s.ctx, conn)
|
2025-03-07 15:50:57 +08:00
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("处理控制通道连接失败", "err", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
func (s *Service) processCtrlConn(ctx context.Context, conn net.Conn) (err error) {
|
2025-03-07 15:50:57 +08:00
|
|
|
reader := bufio.NewReader(conn)
|
2025-05-16 15:13:16 +08:00
|
|
|
for {
|
|
|
|
|
// 循环等待直到服务关闭
|
|
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
return nil
|
|
|
|
|
default:
|
|
|
|
|
}
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
// 读取命令
|
|
|
|
|
cmdByte, err := reader.ReadByte()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("读取节点命令失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
var cmd = CtrlCmdType(cmdByte)
|
|
|
|
|
switch cmd {
|
|
|
|
|
|
|
|
|
|
// 连接建立命令
|
|
|
|
|
case CtrlCmdOpen:
|
|
|
|
|
var recv = make([]byte, 4)
|
|
|
|
|
_, err = io.ReadFull(reader, recv)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("读取节点 ID 失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
var client = int32(binary.BigEndian.Uint32(recv))
|
|
|
|
|
err = s.onOpen(conn, client)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("处理连接建立命令失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 心跳命令
|
|
|
|
|
case CtrlCmdPing:
|
|
|
|
|
err = s.onPing(conn)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("处理心跳命令失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 连接关闭命令
|
|
|
|
|
case CtrlCmdClose:
|
|
|
|
|
err = s.onClose(conn)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("处理关闭命令失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
|
|
// 忽略其他不应该由节点发起的命令
|
|
|
|
|
default:
|
|
|
|
|
return fmt.Errorf("无法处理控制命令: %d", cmd)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Service) onPing(conn net.Conn) (err error) {
|
|
|
|
|
return s.sendPong(conn)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Service) onOpen(conn net.Conn, client int32) (err error) {
|
|
|
|
|
// open 命令全局只执行一次
|
|
|
|
|
_, ok := app.Clients.Load(client)
|
|
|
|
|
if ok {
|
|
|
|
|
return fmt.Errorf("节点 ID %d 已经连接", client)
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
2025-05-14 17:46:34 +08:00
|
|
|
|
|
|
|
|
// 分配端口
|
|
|
|
|
var minim uint16 = 20000
|
|
|
|
|
var maxim uint16 = 60000
|
2025-05-15 15:56:20 +08:00
|
|
|
var port uint16
|
2025-05-14 17:46:34 +08:00
|
|
|
for i := minim; i < maxim; i++ {
|
2025-05-16 15:13:16 +08:00
|
|
|
var _, ok = app.Assigns.Load(i)
|
2025-05-14 17:46:34 +08:00
|
|
|
if !ok {
|
2025-05-15 15:56:20 +08:00
|
|
|
port = i
|
2025-05-16 15:13:16 +08:00
|
|
|
app.Assigns.Store(i, client)
|
|
|
|
|
app.Clients.Store(client, i)
|
2025-05-14 17:46:34 +08:00
|
|
|
break
|
|
|
|
|
}
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
2025-05-15 15:56:20 +08:00
|
|
|
if port == 0 {
|
2025-05-14 17:46:34 +08:00
|
|
|
return errors.New("没有可用的端口")
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
|
|
|
|
|
2025-05-14 17:46:34 +08:00
|
|
|
// 报告端口分配
|
2025-05-16 15:13:16 +08:00
|
|
|
if err = report.Assigned(client, port); err != nil {
|
2025-05-14 17:46:34 +08:00
|
|
|
return fmt.Errorf("报告端口分配失败: %w", err)
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
|
|
|
|
|
2025-05-14 17:46:34 +08:00
|
|
|
// 响应客户端
|
2025-05-16 15:13:16 +08:00
|
|
|
if err = s.sendPong(conn); err != nil {
|
2025-05-14 17:46:34 +08:00
|
|
|
return fmt.Errorf("响应客户端失败: %w", err)
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 启动转发服务
|
|
|
|
|
s.fwdLesWg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
defer s.fwdLesWg.Done()
|
2025-05-16 15:13:16 +08:00
|
|
|
slog.Info("监听转发端口", "port", port, "client", client)
|
|
|
|
|
err = s.listenUser(port, conn)
|
2025-03-07 15:50:57 +08:00
|
|
|
if err != nil {
|
2025-05-16 15:13:16 +08:00
|
|
|
slog.Error("监听转发端口失败", "port", port, "client", client, "err", err)
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
return nil
|
|
|
|
|
}
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
func (s *Service) onClose(conn net.Conn) (err error) {
|
|
|
|
|
_, portStr, err := net.SplitHostPort(conn.LocalAddr().String())
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
port, err := strconv.ParseUint(portStr, 10, 16)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
id, _ := app.Assigns.LoadAndDelete(uint16(port))
|
|
|
|
|
app.Clients.Delete(id)
|
|
|
|
|
app.Assigns.Delete(uint16(port))
|
|
|
|
|
app.Permits.Delete(uint16(port))
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
err = s.sendPong(conn)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
return nil
|
|
|
|
|
}
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
func (s *Service) sendPong(conn net.Conn) (err error) {
|
|
|
|
|
_, err = conn.Write([]byte{byte(CtrlCmdPong)})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("响应客户端失败: %w", err)
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
2025-05-16 15:13:16 +08:00
|
|
|
return nil
|
|
|
|
|
}
|
2025-03-07 15:50:57 +08:00
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
func (s *Service) sendProxy(conn net.Conn, tag [16]byte, addr string) (err error) {
|
|
|
|
|
if len(addr) > 65535 {
|
|
|
|
|
return fmt.Errorf("代理地址过长: %s", addr)
|
2025-03-07 15:50:57 +08:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:13:16 +08:00
|
|
|
buf := make([]byte, 1+16+2+len(addr))
|
|
|
|
|
buf[0] = byte(CtrlCmdProxy)
|
|
|
|
|
copy(buf[1:], tag[:])
|
|
|
|
|
binary.BigEndian.PutUint16(buf[17:], uint16(len(addr)))
|
|
|
|
|
copy(buf[19:], addr)
|
|
|
|
|
|
|
|
|
|
_, err = conn.Write(buf)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("发送代理命令失败: %w", err)
|
|
|
|
|
}
|
2025-03-07 15:50:57 +08:00
|
|
|
return nil
|
|
|
|
|
}
|