package edge import ( "bufio" "context" "encoding/binary" "errors" "fmt" "io" "log/slog" "net" _ "net/http/pprof" "os" "os/signal" "proxy-server/edge/core" "proxy-server/edge/env" "proxy-server/edge/geo" "proxy-server/edge/report" "proxy-server/pkg/utils" "time" ) func Start() error { // 初始化环境变量 slog.Debug("初始化环境变量...") err := env.Init() if err != nil { return fmt.Errorf("初始化环境变量失败: %w", err) } // 获取归属地 slog.Debug("获取节点归属地...") err = geo.Query() if err != nil { return fmt.Errorf("获取节点归属地失败: %w", err) } // 注册节点 slog.Debug("注册节点...") id, host, err := report.Online(geo.Prov, geo.City, geo.Isp) if err != nil { return fmt.Errorf("注册节点失败: %w", err) } // 连接到网关 var ctx, cancel = signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) defer cancel() var errCh = make(chan error) go func() { for { err = ctrl(ctx, id, host) if err == nil { errCh <- nil return } select { case <-ctx.Done(): return default: slog.Error("建立控制通道失败", "err", err) slog.Info(fmt.Sprintf("%d 秒后重试", core.RetryInterval)) } select { case <-ctx.Done(): return case <-time.After(time.Duration(core.RetryInterval) * time.Second): } } }() // 等待退出 select { case err := <-errCh: if err != nil { slog.Error("控制通道发生错误", "err", err) } } // 下线节点 slog.Debug("下线节点...") err = report.Offline() if err != nil { slog.Error("下线节点失败", "err", err) } return ctx.Err() } func ctrl(ctx context.Context, id int32, host string) error { ctrlAddr := net.JoinHostPort(host, fmt.Sprintf("%d", core.FwdCtrlPort)) dataAddr := net.JoinHostPort(host, fmt.Sprintf("%d", core.FwdDataPort)) slog.Info("建立控制通道", "addr", ctrlAddr) conn, err := net.Dial("tcp", ctrlAddr) if err != nil { return errors.New("连接失败") } defer utils.Close(conn) var reader = bufio.NewReader(conn) // 发送节点连接命令 err = sendOpen(reader, conn, id) if err != nil { return fmt.Errorf("发送节点信息失败: %w", err) } // 异步定时发送心跳 go func() { ticker := time.NewTicker(time.Duration(core.HeartbeatInterval) * time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): return case tick := <-ticker.C: err := sendPing(reader, conn) if err != nil { slog.Error("发送心跳失败", "time", tick, "err", err) } } } }() // 等待用户连接 // 读写失败后退出重连,防止后续数据读写顺序错位导致卡死控制通道 slog.Info("等待用户连接") for loop := true; loop; { select { case <-ctx.Done(): loop = false default: // 接收 dst tag, addr, err := onConn(reader) if err != nil { return fmt.Errorf("接收连接命令失败: %w", err) } // 建立数据通道 go func() { err := data(dataAddr, addr, tag) if err != nil { slog.Error("建立数据通道失败", "err", err) } }() } } // 发送关闭连接(不 return err,否则会重新连接) err = sendClose(reader, conn) if err != nil { slog.Error("发送关闭连接失败", "err", err) } return nil } func data(proxy string, dest string, tag [16]byte) error { // 向目标地址建立连接 var result = 1 var dstErr error dst, err := net.Dial("tcp", dest) if err != nil { dstErr = fmt.Errorf("连接目标地址失败: %w", dstErr) result = 0 } defer utils.Close(dst) // 向服务端建立连接 src, err := net.Dial("tcp", proxy) if err != nil { return errors.New("连接服务端失败") } defer utils.Close(src) // 发送连接状态 var buf = make([]byte, 17) copy(buf[0:16], tag[:]) buf[16] = byte(result) _, err = src.Write(buf) if err != nil { return errors.New("发送连接状态失败") } if result == 0 { return dstErr } go func() { defer utils.Close(dst) _, err := io.Copy(dst, src) if err != nil && !errors.Is(err, net.ErrClosed) { slog.Error("上行流量代理失败", "err", err) } }() go func() { defer utils.Close(src) _, err := io.Copy(src, dst) if err != nil && !errors.Is(err, net.ErrClosed) { slog.Error("下行流量代理失败", "err", err) } }() return nil } func sendOpen(reader io.Reader, writer io.Writer, id int32) error { // 发送打开连接 var buf = make([]byte, 5) buf[0] = 3 binary.BigEndian.PutUint32(buf[1:], uint32(id)) _, err := writer.Write(buf) if err != nil { return fmt.Errorf("发送打开连接失败: %w", err) } // 等待服务端响应 respBuf := make([]byte, 1) _, err = io.ReadFull(reader, respBuf) if err != nil { return fmt.Errorf("接收服务端响应失败: %w", err) } if respBuf[0] != 1 { return errors.New("服务端响应失败") } return nil } func sendClose(reader io.Reader, writer io.Writer) error { // 发送关闭连接 _, err := writer.Write([]byte{4}) if err != nil { return err } // 等待服务端响应 respBuf := make([]byte, 1) _, err = io.ReadFull(reader, respBuf) if err != nil { return fmt.Errorf("接收服务端响应失败: %w", err) } if respBuf[0] != 1 { return errors.New("服务端响应失败") } return nil } func sendPing(reader io.Reader, writer io.Writer) error { _, err := writer.Write([]byte{2}) if err != nil { return err } // 等待服务端响应 respBuf := make([]byte, 1) _, err = io.ReadFull(reader, respBuf) if err != nil { return fmt.Errorf("接收服务端响应失败: %w", err) } if respBuf[0] != 1 { return errors.New("服务端响应失败") } return nil } func onConn(reader io.Reader) (tag [16]byte, addr string, err error) { var buf = make([]byte, 1+16+2) _, err = io.ReadFull(reader, buf) if err != nil { return [16]byte{}, "", err } if buf[0] != 5 { return [16]byte{}, "", errors.New("命令错误") } tag = [16]byte(buf[1:17]) var addrLen = binary.BigEndian.Uint16(buf[17:19]) var addrBuf = make([]byte, addrLen) _, err = io.ReadFull(reader, addrBuf) if err != nil { return [16]byte{}, "", err } addr = string(addrBuf) return tag, addr, nil }