2025-05-16 15:13:16 +08:00
|
|
|
package fwd
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
"errors"
|
2025-05-17 11:02:18 +08:00
|
|
|
"fmt"
|
2025-05-17 10:00:28 +08:00
|
|
|
"io"
|
2025-05-16 15:13:16 +08:00
|
|
|
"log/slog"
|
2025-05-19 09:41:41 +08:00
|
|
|
"proxy-server/gateway/app"
|
2025-05-16 17:04:03 +08:00
|
|
|
"proxy-server/gateway/core"
|
|
|
|
|
"proxy-server/gateway/env"
|
|
|
|
|
"proxy-server/gateway/fwd/dispatcher"
|
|
|
|
|
"proxy-server/gateway/fwd/metrics"
|
2025-05-17 10:00:28 +08:00
|
|
|
"proxy-server/utils"
|
2025-05-16 15:13:16 +08:00
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2025-05-19 09:41:41 +08:00
|
|
|
func ListenUser(ctx context.Context, port uint16, ctrl io.Writer) error {
|
2025-05-16 15:13:16 +08:00
|
|
|
dspt, err := dispatcher.New(port, time.Duration(env.AppUserTimeout)*time.Second)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2025-05-17 11:02:18 +08:00
|
|
|
defer dspt.Stop()
|
2025-05-16 15:13:16 +08:00
|
|
|
|
2025-05-17 11:02:18 +08:00
|
|
|
var errCh = make(chan error)
|
2025-05-16 15:13:16 +08:00
|
|
|
go func() {
|
|
|
|
|
err := dspt.Run()
|
|
|
|
|
if err != nil {
|
2025-05-17 11:02:18 +08:00
|
|
|
// slog.Error("代理服务运行失败", "err", err)
|
|
|
|
|
err = fmt.Errorf("协议嗅探服务运行失败: %w", err)
|
2025-05-16 15:13:16 +08:00
|
|
|
}
|
2025-05-17 11:02:18 +08:00
|
|
|
errCh <- err
|
2025-05-16 15:13:16 +08:00
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// 处理连接
|
|
|
|
|
for {
|
|
|
|
|
select {
|
2025-05-17 11:02:18 +08:00
|
|
|
case <-ctx.Done():
|
2025-05-16 15:13:16 +08:00
|
|
|
return nil
|
2025-05-17 11:02:18 +08:00
|
|
|
case err := <-errCh:
|
|
|
|
|
if err != nil {
|
|
|
|
|
err = fmt.Errorf("监听转发端口失败: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return err
|
2025-05-16 15:13:16 +08:00
|
|
|
case user := <-dspt.Conn:
|
|
|
|
|
metrics.TimerAuth.Store(user.Conn, time.Now())
|
2025-05-19 09:41:41 +08:00
|
|
|
app.UserConnWg.Add(1)
|
2025-05-16 15:13:16 +08:00
|
|
|
go func() {
|
2025-05-19 09:41:41 +08:00
|
|
|
defer app.UserConnWg.Done()
|
|
|
|
|
err := processUserConn(ctx, user, ctrl)
|
2025-05-16 15:13:16 +08:00
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("处理用户连接失败", "err", err)
|
|
|
|
|
utils.Close(user)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-19 09:41:41 +08:00
|
|
|
func processUserConn(ctx context.Context, user *core.Conn, ctrl io.Writer) (err error) {
|
2025-05-16 15:13:16 +08:00
|
|
|
|
|
|
|
|
// 发送代理命令
|
2025-05-19 09:41:41 +08:00
|
|
|
err = sendProxy(ctrl, user.Tag, user.Dest.String())
|
2025-05-16 15:13:16 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存用户连接
|
2025-05-23 18:59:53 +08:00
|
|
|
var tag = hex.EncodeToString(user.Tag[:])
|
|
|
|
|
app.UserConnMap.Store(tag, user)
|
2025-05-16 15:13:16 +08:00
|
|
|
|
|
|
|
|
// 如果限定时间内没有建立数据通道,则关闭连接
|
|
|
|
|
var timeout, cancel = context.WithTimeout(context.Background(), time.Duration(env.AppDataTimeout)*time.Second)
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
case <-timeout.Done():
|
|
|
|
|
err = timeout.Err()
|
2025-05-19 09:41:41 +08:00
|
|
|
case <-ctx.Done():
|
|
|
|
|
err = ctx.Err()
|
2025-05-16 15:13:16 +08:00
|
|
|
}
|
|
|
|
|
|
2025-05-23 18:59:53 +08:00
|
|
|
_, ok := app.UserConnMap.LoadAndDelete(tag)
|
2025-05-16 15:13:16 +08:00
|
|
|
if ok {
|
|
|
|
|
utils.Close(user)
|
|
|
|
|
if errors.Is(err, context.DeadlineExceeded) {
|
2025-05-23 18:59:53 +08:00
|
|
|
slog.Error("用户连接超时", "tag", tag, "addr", user.RemoteAddr().String())
|
2025-05-16 15:13:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|