Обзор транспортного уровня
Исходный код: 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Ключевые интерфейсы
Транспортный уровень организован вокруг двух интерфейсов-адаптеров:
// 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) предоставляет как серверный, так и клиентский тип, удовлетворяющий этим интерфейсам.
Выбор транспорта
Тип транспорта выбирается строковой константой в конфигурации:
{
"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, всегда доступен как запасной вариант |
| QUIC | with_quic | Использует github.com/sagernet/quic-go |
| uTLS | with_utls | Требуется для Reality |
| ACME | with_acme | Использует certmagic |
| kTLS | Linux + go1.25 + badlinkname | Выгрузка TLS в ядро |
| ECH | go1.24+ | Поддержка ECH в стандартной библиотеке Go |
Поток соединения
Клиентская сторона (исходящее соединение):
- Уровень протокола вызывает
transport.DialContext(ctx)для полученияnet.Conn - Транспорт устанавливает базовое TCP/UDP-соединение через предоставленный
N.Dialer - Выполняется TLS-рукопожатие, если настроено (обёртывается через
tls.NewDialer) - Применяется транспортно-специфичное кадрирование (WebSocket upgrade, HTTP/2-поток и т.д.)
- Результирующее соединение возвращается для использования на уровне протокола
Серверная сторона (входящее соединение):
- Входящий слушатель принимает необработанные соединения
transport.Serve(listener)запускает транспортный сервер (HTTP-сервер, gRPC-сервер и т.д.)- Транспорт валидирует входящие запросы (путь, заголовки, протокол обновления)
- При успехе вызывается
handler.NewConnectionEx()с развёрнутым соединением - Обработчик направляет соединение к декодеру прокси-протокола
Паттерны потокобезопасности
В транспортном уровне встречаются несколько повторяющихся паттернов:
- Атомарный указатель + мьютекс для кэширования соединений: Используется в клиенте gRPC, клиенте QUIC и WebSocket с ранними данными. Быстрый путь читает атомарный указатель; медленный путь захватывает мьютекс для установления соединения.
- Ленивое соединение с сигнализацией через канал:
EarlyWebsocketConn,GunConn(облегченный) иHTTP2Connоткладывают установку соединения до первой записи, используя канал для сигнализации параллельным читателям о завершении. HTTP2ConnWrapperдля потокобезопасной записи: HTTP/2-потоки требуют синхронизированных записей; обёртка использует мьютекс и флагclosedдля предотвращения записи после закрытия.DupContextдля отсоединения контекста: Контексты HTTP-обработчиков привязаны к времени жизни запроса;DupContextизвлекает идентификатор журнала и создаёт новый фоновый контекст для долгоживущих соединений.
Обработка ошибок
Ошибки транспорта нормализуются через несколько обёрток:
wrapWsError: Преобразует кадры закрытия WebSocket (нормальное закрытие, отсутствие статуса) вio.EOFbaderror.WrapGRPC: Нормализует ошибки потоков gRPCbaderror.WrapH2: Нормализует ошибки потоков HTTP/2qtls.WrapError: Нормализует ошибки QUIC
Все транспортные соединения возвращают os.ErrInvalid для операций, связанных с дедлайнами (SetDeadline, SetReadDeadline, SetWriteDeadline), и устанавливают NeedAdditionalReadDeadline() bool в true, сигнализируя вызывающей стороне о необходимости управлять таймаутами чтения извне.