Sockopt
Sockopt используется для настройки низкоуровневого сетевого поведения.
С его помощью можно управлять прозрачным проксированием, стратегией DNS-разрешения и различными параметрами socket.
SockoptObject
SockoptObject соответствует полю sockopt в StreamSettingsObject.
{
// пример для outbound, аналогично применимо к inbound
"outbounds": [
{
// ...
"streamSettings": {
"sockopt": {
"mark": 0,
"tcpMaxSeg": 1440,
"tcpFastOpen": false,
"tproxy": "off",
"domainStrategy": "AsIs",
"happyEyeballs": {},
"dialerProxy": "",
"acceptProxyProtocol": false,
"tcpKeepAliveInterval": 0,
"tcpKeepAliveIdle": 300,
"tcpUserTimeout": 10000,
"tcpcongestion": "bbr",
"interface": "wg0",
"V6Only": false,
"tcpWindowClamp": 600,
"tcpMptcp": false,
"addressPortStrategy": "",
"customSockopt": []
}
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
mark: number
Целое число. Если значение не равно нулю, исходящие соединения помечаются через SO_MARK.
- Только Linux.
- Требуются права
CAP_NET_ADMIN.
tcpMaxSeg: number
Используется для задания максимального размера сегмента TCP.
tcpFastOpen: true | false | number
Включает или отключает 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, тоже требуется проверка
- Linux 3.16: требует настройки
Для inbound положительное число означает максимальное число ожидающих TFO-соединений. Не все ОС позволяют задавать это здесь:
- Linux / FreeBSD: положительное число используется как лимит. Максимум — 2147483647. Если задано
true, используется256. В Linux сверху это также ограничиваетnet.core.somaxconn. - Mac OS:
trueили положительное число лишь включает TFO. Размер очереди задается отдельно черезnet.inet.tcp.fastopen_backlog. - Windows:
trueили положительное число только включает TFO.
- Linux / FreeBSD: положительное число используется как лимит. Максимум — 2147483647. Если задано
Для 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
Если в Dokodemo-door параметр 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. Если
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
Если используется "UseIP" или "ForceIP" и в OutboundObject задан sendThrough, ядро автоматически определяет нужное семейство адресов по локальному адресу. Если вручную зафиксировать, например, UseIPv4, а sendThrough указывает на IPv6-адрес, соединение завершится ошибкой.
DANGER
Неправильная настройка этой функции может привести к бесконечному циклу.
Коротко: чтобы подключиться к серверу, нужно дождаться DNS-результата, а чтобы завершить DNS-запрос, нужно подключиться к серверу.
Подробно:
- Есть прокси-сервер
proxy.comи встроенный DNS в не-Local режиме. - Перед подключением к
proxy.comXray сначала пытается разрешитьproxy.comчерез встроенный DNS. - Встроенный DNS устанавливает соединение с
dns.com, чтобы узнать IP-адресproxy.com. - Неудачные правила маршрутизации отправляют запрос из шага 3 через
proxy.com. - Xray снова пытается подключиться к
proxy.com. - Перед этим он опять пытается разрешить
proxy.comчерез встроенный DNS. - Встроенный DNS переиспользует соединение из шага 3 и отправляет новый запрос.
- Возникает тупик: соединение из шага 3 ждет результат запроса из шага 7, а запрос из шага 7 не завершится, пока соединение из шага 3 не установится полностью.
- Game over.
Возможные решения:
- Исправить маршрутизацию для встроенного DNS.
- Использовать hosts.
Если вы до сих пор не понимаете решение, не включайте эту функцию.
Поэтому неопытным пользователям использовать эту возможность без понимания маршрутизации не рекомендуется.
dialerProxy: ""
Идентификатор outbound. Если поле не пустое, для установления соединения используется указанный outbound. Это позволяет делать цепочку с учетом транспортных настроек.
DANGER
Эта настройка несовместима с ProxySettingsObject.Tag.
acceptProxyProtocol: true | false
Только для inbound. Определяет, принимать ли PROXY protocol.
PROXY protocol используется для передачи реального IP-адреса и порта источника. Если вы не знаете, что это такое, просто игнорируйте параметр.
Его умеют отправлять обычные reverse proxy, например HAProxy и Nginx, а также VLESS fallback с xver.
Если значение равно true, после установления TCP-соединения удаленная сторона обязана сразу отправить PROXY protocol v1 или v2, иначе соединение будет закрыто.
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. Если значение не задано, используется системное значение по умолчанию.
Часто используемые алгоритмы
bbr(рекомендуется)cubicreno
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. Параметр относится только к клиентской стороне, поскольку начиная с 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.
"customSockopt": [
{
"system": "linux",
"type": "str",
"level": "6",
"opt": "13",
"value": "bbr"
}
]2
3
4
5
6
7
8
9
system: ""
Необязательный параметр. Ограничивает применение конкретной ОС. Если текущая система не совпадает, эта настройка пропускается. Поддерживаются linux, windows и darwin, все в нижнем регистре. Если поле пустое, настройка применяется напрямую.
type: ""
Обязательный параметр. Тип значения. Сейчас поддерживаются int и str.
level: ""
Необязательный параметр. Уровень протокола. По умолчанию используется 6, то есть TCP.
opt: ""
Номер socket option в десятичной форме. В примере выше 13 — это десятичная форма значения TCP_CONGESTION, которое в hex записывается как 0xd.
value: ""
Значение, которое нужно установить. В примере выше это bbr.
Если type равно int, значение должно быть задано десятичным числом.
happyEyeballs: HappyEyeballsObject
Реализация Happy Eyeballs по RFC 8305, только для TCP. Когда целью является доменное имя, Xray запускает гонку между разрешенными адресами и выбирает первый успешный. Работает только если Sockopt.domainStrategy не равен AsIs.
Значения UseIPv4v6 и ForceIPv4v6 фактически сводят список к IPv4 и только при неудаче обращаются к IPv6. Это не рекомендуется. Лучше использовать UseIP или ForceIP вместе с HappyEyeballs.interleave.
WARNING
Не используйте это вместе с domainStrategy у Freedom, потому что тогда Sockopt видит уже конечный IP после подмены.
HappyEyeballsObject
"happyEyeballs": {
"tryDelayMs": 250,
"prioritizeIPv6": false,
"interleave": 1,
"maxConcurrentTry": 4
}2
3
4
5
6
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.