254 lines
5.7 KiB
Go
254 lines
5.7 KiB
Go
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 支持时再完善
|
||
}
|