Files
Meshray-Manager/core/connect/turn_quic.go
T
2026-06-30 15:14:37 +08:00

254 lines
5.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package connect
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"math/big"
"net"
"time"
"github.com/quic-go/quic-go"
"go.uber.org/zap"
)
// QUICListener QUIC 监听器
type QUICListener struct {
listener *quic.Listener
}
// NewQUICListener 创建 QUIC 监听器
func NewQUICListener(addr string, logger *zap.Logger) (*QUICListener, error) {
// 生成自签名证书(用于测试)
cert, err := generateSelfSignedCert()
if err != nil {
return nil, fmt.Errorf("生成证书失败:%w", err)
}
tlsConf := &tls.Config{
Certificates: []tls.Certificate{cert},
NextProtos: []string{"meshray-quic"},
}
udpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return nil, err
}
udpConn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
return nil, err
}
listener, err := quic.Listen(udpConn, tlsConf, nil)
if err != nil {
return nil, fmt.Errorf("创建 QUIC 监听器失败:%w", err)
}
logger.Info("QUIC 监听器已启动", zap.String("addr", addr))
return &QUICListener{
listener: listener,
}, nil
}
// Accept 接受 QUIC 连接
func (l *QUICListener) Accept(ctx context.Context) (*quic.Conn, error) {
return l.listener.Accept(ctx)
}
// Close 关闭监听器
func (l *QUICListener) Close() error {
return l.listener.Close()
}
// QUICClient QUIC 客户端
type QUICClient struct {
servers []string
logger *zap.Logger
}
// NewQUICClient 创建 QUIC 客户端
func NewQUICClient(servers []string, logger *zap.Logger) *QUICClient {
return &QUICClient{
servers: servers,
logger: logger,
}
}
// Connect 建立 QUIC 连接
func (c *QUICClient) Connect(ctx context.Context) (net.Conn, error) {
if len(c.servers) == 0 {
return nil, fmt.Errorf("未配置 QUIC 服务器")
}
// 使用不安全的 TLS 配置(跳过证书验证,用于测试)
tlsConf := &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"meshray-quic"},
}
// 尝试连接第一个服务器
for _, server := range c.servers {
_, err := net.ResolveUDPAddr("udp", server)
if err != nil {
c.logger.Warn("解析 QUIC 服务器地址失败",
zap.String("server", server),
zap.Error(err))
continue
}
var conn *quic.Conn
conn, err = quic.DialAddr(ctx, server, tlsConf, nil)
if err == nil {
c.logger.Info("QUIC 连接已建立",
zap.String("server", server),
zap.String("local_addr", conn.LocalAddr().String()))
return newQUICConn(conn), nil
}
c.logger.Warn("QUIC 连接失败",
zap.String("server", server),
zap.Error(err))
}
return nil, fmt.Errorf("所有 QUIC 服务器连接失败")
}
// quicConn QUIC 连接包装器(实现 net.Conn
type quicConn struct {
conn *quic.Conn // quic-go v0.59.0 使用 *quic.Conn
stream *quic.Stream // 使用 *quic.Stream
}
// newQUICConn 创建 QUIC 连接包装器
func newQUICConn(conn *quic.Conn) *quicConn {
return &quicConn{
conn: conn,
}
}
// OpenStream 打开流
func (c *quicConn) OpenStream() error {
stream, err := c.conn.OpenStreamSync(context.Background())
if err != nil {
return err
}
c.stream = stream
return nil
}
// Read 实现 net.Conn
func (c *quicConn) Read(b []byte) (n int, err error) {
if c.stream == nil {
stream, err := c.conn.OpenStreamSync(context.Background())
if err != nil {
return 0, err
}
c.stream = stream
}
return c.stream.Read(b)
}
// Write 实现 net.Conn
func (c *quicConn) Write(b []byte) (n int, err error) {
if c.stream == nil {
stream, err := c.conn.OpenStreamSync(context.Background())
if err != nil {
return 0, err
}
c.stream = stream
}
return c.stream.Write(b)
}
// Close 实现 net.Conn
func (c *quicConn) Close() error {
if c.stream != nil {
c.stream.Close()
}
return c.conn.CloseWithError(0, "closed")
}
// LocalAddr 实现 net.Conn
func (c *quicConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
// RemoteAddr 实现 net.Conn
func (c *quicConn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
// SetDeadline 实现 net.Conn
func (c *quicConn) SetDeadline(t time.Time) error {
if c.stream != nil {
return (*c.stream).SetDeadline(t)
}
return nil
}
// SetReadDeadline 实现 net.Conn
func (c *quicConn) SetReadDeadline(t time.Time) error {
if c.stream != nil {
return (*c.stream).SetReadDeadline(t)
}
return nil
}
// SetWriteDeadline 实现 net.Conn
func (c *quicConn) SetWriteDeadline(t time.Time) error {
if c.stream != nil {
return (*c.stream).SetWriteDeadline(t)
}
return nil
}
// generateSelfSignedCert 生成自签名证书(仅用于测试)
func generateSelfSignedCert() (tls.Certificate, error) {
// 生成私钥
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return tls.Certificate{}, err
}
// 生成证书模板
template := x509.Certificate{
SerialNumber: big.NewInt(1),
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * 24 * time.Hour),
DNSNames: []string{"localhost"},
}
// 自签名
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
return tls.Certificate{}, err
}
// 编码证书和私钥
certPEM := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: certDER,
})
keyPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(priv),
})
// 加载证书
return tls.X509KeyPair(certPEM, keyPEM)
}
// NewTURNFactoryQUIC 创建 QUIC TURN 工厂(用于 9 层降级策略)
// 注意:当前版本暂不启用 QUIC 支持,返回 nil
func NewTURNFactoryQUIC(servers []string, username, password string, logger *zap.Logger) *TURNFactory {
logger.Warn("QUIC 传输模式暂不支持,已跳过")
return nil // 暂时返回 nil,未来实现 QUIC 支持时再完善
}