# Sockopt
Sockopt используется для настройки низкоуровневого сетевого поведения.
С его помощью можно управлять прозрачным проксированием, стратегией DNS-разрешения и различными параметрами socket.
## SockoptObject
`SockoptObject` соответствует полю `sockopt` в [`StreamSettingsObject`](../transport.md#streamsettingsobject).
```json
{
// пример для outbound, аналогично применимо к inbound
"outbounds": [
{
// ...
"streamSettings": {
// [!code focus:21]
"sockopt": {
"mark": 0,
"tcpMaxSeg": 1440,
"tcpFastOpen": false,
"tproxy": "off",
"domainStrategy": "AsIs",
"happyEyeballs": {},
"dialerProxy": "",
"acceptProxyProtocol": false,
"trustedXForwardedFor": [],
"tcpKeepAliveInterval": 0,
"tcpKeepAliveIdle": 300,
"tcpUserTimeout": 10000,
"tcpcongestion": "bbr",
"interface": "wg0",
"V6Only": false,
"tcpWindowClamp": 600,
"tcpMptcp": false,
"addressPortStrategy": "",
"customSockopt": []
}
}
}
]
}
```
> `mark`: number
Целое число. Если значение не равно нулю, исходящие соединения помечаются через `SO_MARK`.
- Только Linux.
- Требуются права `CAP_NET_ADMIN`.
> `tcpMaxSeg`: number
Используется для задания максимального размера сегмента TCP.
> `tcpFastOpen`: true | false | number
Включает или отключает [TCP Fast Open](https://ru.wikipedia.org/wiki/TCP_Fast_Open).
Если указано `true` или положительное число, TFO включается. Если указано `false` или отрицательное число, TFO принудительно отключается. Если поле отсутствует или равно `0`, используется поведение системы по умолчанию. Параметр доступен и для inbound, и для outbound.
- Работает только на следующих версиях ОС и новее:
- Linux 3.16: требует настройки `net.ipv4.tcp_fastopen`. Это bitmap, где `0x1` разрешает клиентскую сторону, а `0x2` — серверную. По умолчанию используется `0x1`. Если TFO нужно на сервере, задайте `0x3`.
- ~~Windows 10 (1607)~~, но реализация некорректна
- Mac OS 10.11 / iOS 9, требуется проверка
- FreeBSD 10.3 на сервере / 12.0 на клиенте: нужны `net.inet.tcp.fastopen.server_enabled=1` и `net.inet.tcp.fastopen.client_enabled=1`, тоже требуется проверка
- Для inbound положительное число означает [максимальное число ожидающих TFO-соединений](https://tools.ietf.org/html/rfc7413#section-5.1). **Не все ОС позволяют задавать это здесь**:
- Linux / FreeBSD: положительное число используется как лимит. Максимум — 2147483647. Если задано `true`, используется `256`. В Linux сверху это также ограничивает `net.core.somaxconn`.
- Mac OS: `true` или положительное число лишь включает TFO. Размер очереди задается отдельно через `net.inet.tcp.fastopen_backlog`.
- Windows: `true` или положительное число только включает TFO.
- Для outbound `true` или положительное число просто означает включение TFO на поддерживаемой ОС.
> `tproxy`: "redirect" | "tproxy" | "off"
Включать ли прозрачное проксирование. Только Linux.
- `"redirect"`: режим Redirect, поддерживает все IPv4/IPv6 TCP-соединения
- `"tproxy"`: режим TProxy, поддерживает все IPv4/IPv6 TCP- и UDP-соединения
- `"off"`: прозрачное проксирование отключено
Для прозрачного проксирования нужны root или `CAP_NET_ADMIN`.
::: danger
Если в [tunnel](../inbounds/tunnel.md) параметр `followRedirect` равен `true`, а `tproxy` в Sockopt пустой, то значение `tproxy` будет автоматически установлено в `"redirect"`.
:::
> `domainStrategy`: "AsIs"
> "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
> "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
Значение по умолчанию — `"AsIs"`.
Когда целевой адрес является доменным именем, это поле управляет тем, как outbound будет его разрешать и использовать:
- При `"AsIs"` Xray никак специально не обрабатывает доменное имя и в конце использует обычный dialer Go. Приоритет фиксирован правилами RFC 6724 и обычно приводит к предпочтению IPv6.
- При любом другом значении Xray использует [встроенный DNS](../dns.md). Если `DNSObject` отсутствует, используется системный DNS. Если есть несколько подходящих IP-адресов, ядро случайным образом выбирает один.
- `"IPv4"` означает попытку использовать только IPv4. `"IPv4v6"` означает использование IPv4 или IPv6, но для dual-stack домена предпочитается IPv4. Аналогично работают и IPv6-first варианты.
- Если во встроенном DNS также задан `"queryStrategy"`, фактическое поведение определяется пересечением двух настроек. Например, `"queryStrategy": "UseIPv4"` вместе с `"domainStrategy": "UseIP"` фактически эквивалентно `"domainStrategy": "UseIPv4"`.
- Варианты `"Use*"` делают fallback к `"AsIs"`, если результат разрешения не соответствует нужному семейству адресов.
- Варианты `"Force*"` завершают соединение ошибкой, если получить нужный тип адреса не удалось.
::: tip TIP
Если используется `"UseIP"` или `"ForceIP"` и в [OutboundObject](../outbound.md#outboundobject) задан `sendThrough`, ядро автоматически определяет нужное семейство адресов по локальному адресу. Если вручную зафиксировать, например, `UseIPv4`, а `sendThrough` указывает на IPv6-адрес, соединение завершится ошибкой.
:::
::: danger
Неправильная настройка этой функции может привести к бесконечному циклу.
Коротко: чтобы подключиться к серверу, нужно дождаться DNS-результата, а чтобы завершить DNS-запрос, нужно подключиться к серверу.
Подробно:
1. Есть прокси-сервер `proxy.com` и встроенный DNS в не-Local режиме.
2. Перед подключением к `proxy.com` Xray сначала пытается разрешить `proxy.com` через встроенный DNS.
3. Встроенный DNS устанавливает соединение с `dns.com`, чтобы узнать IP-адрес `proxy.com`.
4. Неудачные правила маршрутизации отправляют запрос из шага 3 через `proxy.com`.
5. Xray снова пытается подключиться к `proxy.com`.
6. Перед этим он опять пытается разрешить `proxy.com` через встроенный DNS.
7. Встроенный DNS переиспользует соединение из шага 3 и отправляет новый запрос.
8. Возникает тупик: соединение из шага 3 ждет результат запроса из шага 7, а запрос из шага 7 не завершится, пока соединение из шага 3 не установится полностью.
9. Game over.
Возможные решения:
- Исправить маршрутизацию для встроенного DNS.
- Использовать hosts.
- ~~Если вы до сих пор не понимаете решение, не включайте эту функцию.~~
Поэтому неопытным пользователям использовать эту возможность без понимания маршрутизации не рекомендуется.
:::
> `dialerProxy`: ""
Идентификатор outbound. Если поле не пустое, для установления соединения используется указанный outbound. Это позволяет делать цепочку с учетом транспортных настроек.
::: danger
Эта настройка несовместима с `ProxySettingsObject.Tag`.
:::
> `acceptProxyProtocol`: true | false
Только для inbound. Определяет, принимать ли PROXY protocol.
[PROXY protocol](https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) используется для передачи реального IP-адреса и порта источника. Если вы не знаете, что это такое, просто игнорируйте параметр.
Его умеют отправлять обычные reverse proxy, например HAProxy и Nginx, а также VLESS fallback с `xver`.
Если значение равно `true`, после установления TCP-соединения удаленная сторона обязана сразу отправить PROXY protocol v1 или v2, иначе соединение будет закрыто.
> `trustedXForwardedFor`: [ string ]
Применяется только к трем HTTP-ориентированным inbound: `XHTTP`, `WebSocket` и `HTTPUpgrade`.
Позволяет ограничить, в каких случаях Xray будет доверять заголовку `X-Forwarded-For` и использовать его для подмены `SourceIP`.
Если поле не задано, сохраняется старое поведение: если в запросе есть `X-Forwarded-For`, Xray его читает.
После настройки этого поля каждый элемент массива рассматривается как имя дополнительного заголовка, которое должно присутствовать в запросе. Xray будет доверять `X-Forwarded-For` только если в запросе есть хотя бы один из этих заголовков. Их значения не важны, проверяется только наличие самого ключа.
> `tcpKeepAliveIdle`: number
Порог простоя TCP в секундах. После такого времени бездействия начинают отправляться Keep-Alive пакеты.
Для outbound Xray использует такие же значения по умолчанию, как Chrome: и idle, и interval равны 45 секундам. Если установить этот параметр или `tcpKeepAliveInterval` в отрицательное значение, keepalive по умолчанию отключается; положительное значение его переопределяет.
Для inbound Keep-Alive по умолчанию выключен. Он включается, если этот параметр или `tcpKeepAliveInterval` не равны нулю. Если задан только один из них, второй берется из настроек ОС.
> `tcpKeepAliveInterval`: number
Интервал в секундах между Keep-Alive пакетами после перехода TCP в keepalive-состояние. Остальное поведение описано выше.
> `tcpUserTimeout`: number
В миллисекундах. См.: https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md
> `tcpcongestion`: ""
Алгоритм управления перегрузкой TCP. Только Linux.
Если значение не задано, используется системное значение по умолчанию.
::: tip Часто используемые алгоритмы
- `bbr` (рекомендуется)
- `cubic`
- `reno`
:::
::: tip
Текущее системное значение можно посмотреть командой `sysctl net.ipv4.tcp_congestion_control`.
:::
> `interface`: ""
Привязывает исходящее соединение к конкретному имени сетевого интерфейса. Поддерживается в Linux, iOS, Mac OS и Windows.
> `V6Only`: true | false
Если значение равно `true`, прослушивание на `::` принимает только IPv6-соединения. Только Linux.
> `tcpWindowClamp`: number
Ограничивает объявляемый размер TCP-окна этим значением. Ядро выбирает максимум между ним и `SOCK_MIN_RCVBUF / 2`.
> `tcpMptcp`: true | false
Значение по умолчанию — `false`. Если установить `true`, включается [Multipath TCP](https://en.wikipedia.org/wiki/Multipath_TCP). Параметр относится только к клиентской стороне, поскольку начиная с Go 1.24 прослушивание уже включает MPTCP по умолчанию. Требуется Linux kernel 5.6 или новее.
> `tcpNoDelay`: true | false
Этот параметр удален, потому что Go и так включает TCP no delay по умолчанию. Если вам нужно отключить его, используйте `customSockopt`.
> `addressPortStrategy`: "none" | "SrvPortOnly" | "SrvAddressOnly" | "SrvPortAndAddress" | "TxtPortOnly" | "TxtAddressOnly" | "TxtPortAndAddress"
Позволяет использовать SRV- или TXT-записи для задания адреса и или порта цели для outbound. По умолчанию используется `none`, то есть функция выключена.
Эти запросы идут через системный DNS, а не через встроенный DNS Xray. В качестве имени для запроса берется домен outbound. Если запрос не удался, используется исходный адрес и порт.
Префикс `Srv` означает стандартный запрос SRV-записи. Префикс `Txt` означает TXT-запись в формате вроде `127.0.0.1:80`.
`PortOnly` заменяет только порт. `AddressOnly` — только адрес. `PortAndAddress` — и адрес, и порт.
Эта настройка применяется раньше `domainStrategy` внутри `sockopt`. После подмены адрес по-прежнему проходит через `domainStrategy`, если он задан. Но применяется она уже после `Freedom.domainStrategy`, поэтому если `Freedom` заранее разрешил домен в IP, этот механизм уже не сработает.
На практике это означает, что если обычный доменный трафик попадает в `Freedom` с `AsIs`, после включения этого параметра ядро начнет пытаться переписать адрес и порт, например через SRV-запись `google.com`.
> `customSockopt`: []
Массив для продвинутых пользователей, которым нужно вручную задать произвольные socket options. Теоретически через него можно воспроизвести все связанные с соединением настройки выше, а также выставить параметры, которые существуют на уровне socket, но не вынесены напрямую в ядре. Сейчас поддерживаются Linux, Windows и Darwin. Пример ниже эквивалентен `"tcpcongestion": "bbr"`.
Используйте этот механизм только если понимаете socket programming.
```json
{
"customSockopt": [
{
"system": "linux",
"network": "tcp",
"type": "str",
"level": "6",
"opt": "13",
"value": "bbr"
}
]
}
```
> `system`: ""
Необязательный параметр. Ограничивает применение конкретной ОС (в нижнем регистре). Если текущая система не совпадает, эта настройка пропускается. Если поле пустое, настройка применяется напрямую. Поддерживаются `linux`, `windows`, `darwin` и `android` (`android` используется только в специализированных сборках для Android; запуск сборки Linux на Android по-прежнему считается как `linux`).
> `network`: ""
Необязательный параметр. Ограничивает применение конкретным типом сети. Поддерживаются `tcp`, `tcp4`, `tcp6`, `udp`, `udp4`, `udp6`. Значение без числового суффикса означает, что sockopt применяется к обоим стекам. Обратите внимание: цель IPv4 **не означает**, что стандартная библиотека передаст network `tcp4`/`udp4` — например, система может использовать IPv6-сокет для подключения к IPv4-адресу. Перед использованием проверьте поведение стандартной библиотеки.
> `type`: ""
Обязательный параметр. Тип значения. Сейчас поддерживаются `int` и `str`.
> `level`: ""
Необязательный параметр. Уровень протокола. По умолчанию используется `6`, то есть TCP.
> `opt`: ""
Номер socket option в десятичной форме. В примере выше `13` — это десятичная форма значения `TCP_CONGESTION`, которое в hex записывается как `0xd`.
> `value`: ""
Значение, которое нужно установить. В примере выше это `bbr`.
Если `type` равно `int`, значение должно быть задано десятичным числом.
> `happyEyeballs`: [HappyEyeballsObject](#happyeyeballsobject)
Реализация Happy Eyeballs по RFC 8305, только для TCP. Когда целью является доменное имя, Xray запускает гонку между разрешенными адресами и выбирает первый успешный. Работает только если `Sockopt.domainStrategy` не равен `AsIs`.
Значения `UseIPv4v6` и `ForceIPv4v6` фактически сводят список к IPv4 и только при неудаче обращаются к IPv6. Это не рекомендуется. Лучше использовать `UseIP` или `ForceIP` вместе с `HappyEyeballs.interleave`.
::: warning
Не используйте это вместе с `domainStrategy` у `Freedom`, потому что тогда `Sockopt` видит уже конечный IP после подмены.
:::
### HappyEyeballsObject
```json
{
"happyEyeballs": {
"tryDelayMs": 250,
"prioritizeIPv6": false,
"interleave": 1,
"maxConcurrentTry": 4
}
}
```
> `tryDelayMs`: number
Задержка между попытками гонки в миллисекундах. Значение по умолчанию — `0`, то есть функция выключена. Рекомендуемое значение — `250`.
> `prioritizeIPv6`: bool
Определяет, какой тип адреса будет первым после сортировки. По умолчанию `false`, то есть IPv4 идет первым.
> `interleave`: number
Параметр RFC 8305 `First Address Family Count`. Значение по умолчанию — `1`. Он определяет, как IPv4 и IPv6 адреса чередуются в очереди.
Например, очередь может выглядеть как `46464646`, если значение равно `1`, или как `44664466`, если значение равно `2`, где `6` означает IPv6, а `4` — IPv4.
> `maxConcurrentTry`: number
Максимальное количество параллельных попыток. Это не дает ядру открыть слишком много соединений, если домен разрешился в большой список адресов и все они неудачны. Значение по умолчанию — `4`. Значение `0` отключает Happy Eyeballs.