Skip to content

Обзор транспортного уровня

Исходный код: transport/v2ray/, common/tls/, common/mux/, common/uot/, common/tlsfragment/

Архитектура

Транспортный уровень sing-box располагается между уровнем прокси-протокола и необработанной сетью, обеспечивая подключаемые потоковые транспорты (WebSocket, gRPC, HTTP, QUIC, HTTP Upgrade), варианты TLS (stdlib, uTLS, Reality, ECH, kTLS), мультиплексирование соединений (sing-mux), туннелирование UDP-over-TCP и фрагментацию TLS-отпечатков.

Карта компонентов

Proxy Protocol (VMess, Trojan, etc.)
    |
    v
+--------------------+
| V2Ray Transport    |  <-- WebSocket, gRPC, HTTP, QUIC, HTTPUpgrade
+--------------------+
    |
    v
+--------------------+
| TLS Layer          |  <-- STD, uTLS, Reality, ECH, kTLS
+--------------------+
    |
    v
+--------------------+
| Multiplexing       |  <-- sing-mux, UoT
+--------------------+
    |
    v
+--------------------+
| TLS Fragment       |  <-- ClientHello splitting
+--------------------+
    |
    v
  Raw TCP/UDP

Ключевые интерфейсы

Транспортный уровень организован вокруг двух интерфейсов-адаптеров:

go
// Server-side transport
type V2RayServerTransport interface {
    Network() []string
    Serve(listener net.Listener) error
    ServePacket(listener net.PacketConn) error
    Close() error
}

// Client-side transport
type V2RayClientTransport interface {
    DialContext(ctx context.Context) (net.Conn, error)
    Close() error
}

Каждая реализация транспорта (WebSocket, gRPC, HTTP, QUIC, HTTP Upgrade) предоставляет как серверный, так и клиентский тип, удовлетворяющий этим интерфейсам.

Выбор транспорта

Тип транспорта выбирается строковой константой в конфигурации:

json
{
  "transport": {
    "type": "ws",          // "http", "grpc", "quic", "httpupgrade"
    "path": "/path",
    "headers": {}
  }
}

Фабрика v2ray/transport.go выполняет диспетчеризацию на основе этой строки типа через type-switch в NewServerTransport и NewClientTransport.

Зависимости от тегов сборки

Не все транспорты доступны всегда:

ТранспортТребуемый тег сборкиПримечания
WebSocketнетВсегда доступен
HTTPнетВсегда доступен
HTTP UpgradeнетВсегда доступен
gRPC (полный)with_grpcИспользует google.golang.org/grpc
gRPC (облегченный)нетНеобработанный HTTP/2, всегда доступен как запасной вариант
QUICwith_quicИспользует github.com/sagernet/quic-go
uTLSwith_utlsТребуется для Reality
ACMEwith_acmeИспользует certmagic
kTLSLinux + go1.25 + badlinknameВыгрузка TLS в ядро
ECHgo1.24+Поддержка ECH в стандартной библиотеке Go

Поток соединения

Клиентская сторона (исходящее соединение):

  1. Уровень протокола вызывает transport.DialContext(ctx) для получения net.Conn
  2. Транспорт устанавливает базовое TCP/UDP-соединение через предоставленный N.Dialer
  3. Выполняется TLS-рукопожатие, если настроено (обёртывается через tls.NewDialer)
  4. Применяется транспортно-специфичное кадрирование (WebSocket upgrade, HTTP/2-поток и т.д.)
  5. Результирующее соединение возвращается для использования на уровне протокола

Серверная сторона (входящее соединение):

  1. Входящий слушатель принимает необработанные соединения
  2. transport.Serve(listener) запускает транспортный сервер (HTTP-сервер, gRPC-сервер и т.д.)
  3. Транспорт валидирует входящие запросы (путь, заголовки, протокол обновления)
  4. При успехе вызывается handler.NewConnectionEx() с развёрнутым соединением
  5. Обработчик направляет соединение к декодеру прокси-протокола

Паттерны потокобезопасности

В транспортном уровне встречаются несколько повторяющихся паттернов:

  • Атомарный указатель + мьютекс для кэширования соединений: Используется в клиенте gRPC, клиенте QUIC и WebSocket с ранними данными. Быстрый путь читает атомарный указатель; медленный путь захватывает мьютекс для установления соединения.
  • Ленивое соединение с сигнализацией через канал: EarlyWebsocketConn, GunConn (облегченный) и HTTP2Conn откладывают установку соединения до первой записи, используя канал для сигнализации параллельным читателям о завершении.
  • HTTP2ConnWrapper для потокобезопасной записи: HTTP/2-потоки требуют синхронизированных записей; обёртка использует мьютекс и флаг closed для предотвращения записи после закрытия.
  • DupContext для отсоединения контекста: Контексты HTTP-обработчиков привязаны к времени жизни запроса; DupContext извлекает идентификатор журнала и создаёт новый фоновый контекст для долгоживущих соединений.

Обработка ошибок

Ошибки транспорта нормализуются через несколько обёрток:

  • wrapWsError: Преобразует кадры закрытия WebSocket (нормальное закрытие, отсутствие статуса) в io.EOF
  • baderror.WrapGRPC: Нормализует ошибки потоков gRPC
  • baderror.WrapH2: Нормализует ошибки потоков HTTP/2
  • qtls.WrapError: Нормализует ошибки QUIC

Все транспортные соединения возвращают os.ErrInvalid для операций, связанных с дедлайнами (SetDeadline, SetReadDeadline, SetWriteDeadline), и устанавливают NeedAdditionalReadDeadline() bool в true, сигнализируя вызывающей стороне о необходимости управлять таймаутами чтения извне.