mirror of
https://github.com/XTLS/Xray-docs-next.git
synced 2026-10-11 16:58:22 +03:00
Xray-core: Add Lua script for dns and routing
https://github.com/XTLS/Xray-core/pull/6823
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# Среда выполнения и загрузка скриптов
|
||||
|
||||
## Среда Lua
|
||||
|
||||
Сейчас используется GopherLua, который поддерживает синтаксис Lua 5.1, оператор `goto` из Lua 5.2 и собственный [`channel`](https://github.com/yuin/gopher-lua#lua-api).
|
||||
|
||||
Xray загружает скрипты Lua согласно файлу конфигурации. Положение настройки определяет назначение скрипта и доступные Hook. Hook каждой точки входа и соглашения об их вызове описаны в [справочнике Hook](./index.md#hook).
|
||||
|
||||
## Загрузка модулей
|
||||
|
||||
Модули API организованы по назначению и загружаются через `require`:
|
||||
|
||||
```lua
|
||||
local geodata = require("xray.geodata")
|
||||
local log = require("xray.log")
|
||||
```
|
||||
|
||||
Список модулей приведён в разделе [API модулей](./index.md#api-модулеи), а использование функций — в соответствующих справочниках API.
|
||||
|
||||
Когда выполняется инициализация верхнего уровня, включая загрузку модулей Lua и создание объектов, описано в разделе [Экземпляры и жизненный цикл](./guide/lifecycle.md).
|
||||
|
||||
## Пути к файлам скриптов
|
||||
|
||||
Поле `script` в конфигурации задаёт путь к файлу скрипта Lua. Пустая строка или отсутствие поля отключает скрипт; абсолютный путь указывает файл напрямую.
|
||||
|
||||
Относительные пути проверяются в следующем порядке. Если путь не существует, поиск продолжается; если он существует, но не является обычным файлом, сразу возникает ошибка:
|
||||
|
||||
1. Каталог, указанный переменной окружения `XRAY_LOCATION_CONFDIR`;
|
||||
2. Каталог, указанный переменной окружения `XRAY_LOCATION_CONFIG`;
|
||||
3. Текущий рабочий каталог процесса Xray;
|
||||
4. Каталог исполняемого файла Xray.
|
||||
|
||||
Настройка этих каталогов описана в разделе [Переменные окружения](../../config/env.md). Относительные пути не отсчитываются автоматически от каталога файла конфигурации.
|
||||
|
||||
Например, если путь скрипта задан как `routing.lua`, Xray ищет файл в указанном выше порядке. Абсолютный путь Windows можно записать как `C:/Xray/routing.lua`; при использовании обратной косой черты экранируйте её согласно требованиям формата конфигурации.
|
||||
@@ -0,0 +1,155 @@
|
||||
# Скрипты DNS
|
||||
|
||||
Когда скрипт указан через [`dns.script`](../../../config/dns.md#dnsobject), обработка встроенного DNS передаётся функции Lua `HandleDNSQuery`.
|
||||
|
||||
## Минимальный пример
|
||||
|
||||
Добавьте в существующую конфигурацию:
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"script": "dns.lua",
|
||||
"servers": ["1.1.1.1"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Сохраните `dns.lua`:
|
||||
|
||||
```lua
|
||||
local dns = require("xray.dns")
|
||||
local server = dns.Servers[1]
|
||||
|
||||
function HandleDNSQuery(domain, ipv4, ipv6, fake)
|
||||
return server:Query(domain, ipv4, ipv6, fake)
|
||||
end
|
||||
```
|
||||
|
||||
Этот фрагмент нужно объединить с полной конфигурацией. Правила поиска файла описаны в разделе [Пути к файлам скриптов](../environment.md#пути-к-фаилам-скриптов).
|
||||
|
||||
Пример передаёт параметры вышестоящему серверу без изменений и напрямую возвращает результат запроса. Полный список параметров, ограничения возвращаемых значений и поведение при ошибках описаны в [HandleDNSQuery](../reference/hook-dns.md).
|
||||
|
||||
## Связь с конфигурацией DNS
|
||||
|
||||
До передачи запроса скрипту по-прежнему выполняются проверка домена встроенным DNS, глобальные ограничения типов запросов и обработка Hosts. Если Hosts уже вернул допустимые IP-адреса или явно отклонил запрос, скрипт не вызывается. Если Hosts заменил домен, скрипт запрашивает заменённый домен.
|
||||
|
||||
При включении скрипта он управляет выбором вышестоящего сервера, поэтому `domains`, `skipFallback`, `finalQuery`, `disableFallback`, `disableFallbackIfMatch` и `enableParallelQuery` больше не имеют практического значения.
|
||||
|
||||
Для запроса к конкретному серверу используйте [`serverObj:Query`](../reference/module-dns.md#query). Настройки отдельного сервера, которые продолжают действовать, перечислены в описании этого API.
|
||||
|
||||
::: tip Совет
|
||||
Если соответствие между серверами и правилами фильтрации постоянно, удобнее и быстрее настроить `expectedIPs` / `unexpectedIPs` напрямую. Можно также не задавать эти параметры и фильтровать результаты в Lua методами вроде [`ipMatcherObj:FilterIPs`](../reference/module-geodata.md#filterips), что даёт больше гибкости.
|
||||
:::
|
||||
|
||||
## Пример: выбор сервера по домену и фильтрация результатов
|
||||
|
||||
Следующий пример выбирает вышестоящие серверы по категории домена и при необходимости фильтрует китайские IP-адреса. Для каждого сервера задаётся `id`, по которому скрипт выполняет запросы и выбирает резервный сервер:
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"script": "dns.lua",
|
||||
"tag": "dns-proxy",
|
||||
"servers": [
|
||||
{ "id": "cf", "address": "1.1.1.1" },
|
||||
{ "id": "google", "address": "8.8.8.8" },
|
||||
{ "id": "cn114", "address": "114.114.114.114", "tag": "dns-direct" },
|
||||
{ "id": "cn223", "address": "223.5.5.5", "tag": "dns-direct" },
|
||||
{
|
||||
"id": "google-ecs",
|
||||
"address": "8.8.8.8",
|
||||
"clientIp": "222.85.85.85"
|
||||
},
|
||||
{
|
||||
"id": "google-alt-ecs",
|
||||
"address": "8.8.4.4",
|
||||
"clientIp": "222.85.85.85"
|
||||
}
|
||||
]
|
||||
},
|
||||
"routing": {
|
||||
"rules": [
|
||||
{ "inboundTag": ["dns-direct"], "outboundTag": "direct" },
|
||||
{ "inboundTag": ["dns-proxy"], "outboundTag": "proxy" }
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{ "tag": "direct", "protocol": "freedom" },
|
||||
{
|
||||
"tag": "proxy",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`dns-direct` и `dns-proxy` — входящие теги запросов к вышестоящим DNS-серверам. Правила маршрутизации выше выбирают для них прямое исходящее подключение `direct` и прокси VLESS `proxy` соответственно.
|
||||
|
||||
Скрипт сначала определяет порядок запросов по домену, затем последовательно опрашивает серверы. Если запрос завершился ошибкой или результат после фильтрации пуст, он пробует следующий сервер:
|
||||
|
||||
```lua
|
||||
local geodata = require("xray.geodata")
|
||||
local dns = require("xray.dns")
|
||||
local servers = {}
|
||||
for _, server in ipairs(dns.Servers) do
|
||||
servers[server.ID] = server
|
||||
end
|
||||
|
||||
local googleDomainMatcher = geodata.BuildDomainMatcher("geosite:google")
|
||||
local cnDomainMatcher = geodata.BuildDomainMatcher("geosite:cn")
|
||||
local foreignDomainMatcher = geodata.BuildDomainMatcher("geosite:geolocation-!cn")
|
||||
local cnIPMatcher = geodata.BuildIPMatcher("geoip:cn")
|
||||
|
||||
function HandleDNSQuery(domain, ipv4, ipv6, fake)
|
||||
local queries
|
||||
if googleDomainMatcher:MatchAny(domain) then
|
||||
-- Использовать публичный DNS для доменов Google.
|
||||
queries = {{"cf"}, {"google"}}
|
||||
elseif cnDomainMatcher:MatchAny(domain) then
|
||||
-- Для китайских доменов сначала запросить прямой DNS, оставить китайские IP, затем перейти к DNS через прокси.
|
||||
queries = {
|
||||
{"cn114", "cn"}, {"cn223", "cn"}, {"cf"}, {"google"}
|
||||
}
|
||||
elseif foreignDomainMatcher:MatchAny(domain) then
|
||||
-- Для некитайских доменов сначала исключить китайские IP, затем попробовать запросы с ECS.
|
||||
queries = {
|
||||
{"cf", "non-cn"}, {"google", "non-cn"},
|
||||
{"google-ecs"}, {"google-alt-ecs"}
|
||||
}
|
||||
else
|
||||
-- Для доменов вне списков сначала искать китайские IP через ECS, затем перейти к обычному публичному DNS.
|
||||
queries = {
|
||||
{"google-ecs", "cn"}, {"google-alt-ecs", "cn"},
|
||||
{"cf"}, {"google"}
|
||||
}
|
||||
end
|
||||
|
||||
local lastError = "Нет DNS-результатов, удовлетворяющих условиям"
|
||||
for _, query in ipairs(queries) do
|
||||
local ips, ttl, err =
|
||||
servers[query[1]]:Query(domain, ipv4, ipv6, fake)
|
||||
if err then
|
||||
lastError = err
|
||||
else
|
||||
if query[2] then
|
||||
local inCn, outsideCn = cnIPMatcher:FilterIPs(ips)
|
||||
if query[2] == "cn" then
|
||||
ips = inCn
|
||||
else
|
||||
ips = outsideCn
|
||||
end
|
||||
end
|
||||
if ips and #ips > 0 then
|
||||
return ips, ttl, nil
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil, 0, lastError
|
||||
end
|
||||
```
|
||||
|
||||
Инициализация верхнего уровня и сохранение состояния скриптов DNS описаны в разделе [Жизненный цикл пула](./lifecycle.md#жизненныи-цикл-пула).
|
||||
@@ -0,0 +1,67 @@
|
||||
# Экземпляры и жизненный цикл
|
||||
|
||||
Способ управления экземплярами в точке входа скрипта определяет создание экземпляров Lua, вызовы Hook, сохранение состояния и уничтожение экземпляров. На этой странице правила описаны по типам жизненного цикла.
|
||||
|
||||
## Жизненный цикл пула
|
||||
|
||||
Сейчас [HandleRoute](../reference/hook-routing.md) в [скриптах маршрутизации](./routing.md) и [HandleDNSQuery](../reference/hook-dns.md) в [скриптах DNS](./dns.md) используют экземпляры из пула. Следующие правила применяются к обоим Hook.
|
||||
|
||||
### Пулы экземпляров и инициализация
|
||||
|
||||
Скрипты маршрутизации и DNS подключаются через поле `script` в соответствующих настройках и управляют отдельными пулами экземпляров Lua. Даже если указан один и тот же файл, состояние внутри экземпляров Lua не разделяется.
|
||||
|
||||
При запуске Xray один раз читает и компилирует скрипт, затем создаёт первый экземпляр, выполняет код верхнего уровня и проверяет наличие обязательного обработчика. Ошибка чтения файла, синтаксиса, выполнения кода верхнего уровня или проверки обработчика препятствует запуску Xray.
|
||||
|
||||
### Вызовы Hook и возврат экземпляров
|
||||
|
||||
Каждый выбор маршрута или DNS-запрос получает экземпляр в исключительное пользование. Свободный экземпляр используется повторно; если параллельным вызовам нужны дополнительные экземпляры, они создаются из скомпилированного скрипта с повторным выполнением кода верхнего уровня.
|
||||
|
||||
После нормального завершения обработчика экземпляр может вернуться в пул для повторного использования. Необработанное исключение Lua или превышение времени выполнения уничтожает экземпляр. Сообщение об ошибке обработки через возвращаемые значения или ошибка их проверки не равнозначны исключению выполнения Lua: экземпляр можно использовать повторно. Лишние свободные экземпляры уничтожаются автоматически.
|
||||
|
||||
Если есть свободный экземпляр, путь вызова каждого Hook прост: **получить экземпляр → выполнить Hook → вернуть экземпляр**. Чтение и компиляция скрипта выполняются при запуске Xray. Зелёные узлы на схеме показывают этот обычный путь.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
LOAD["Запуск Xray<br/>Однократное чтение и компиляция основного скрипта"] --> INIT["Создать первый экземпляр Lua<br/>Выполнить код верхнего уровня и проверить Hook"]
|
||||
INIT --> POOL[("Пул свободных экземпляров")]
|
||||
|
||||
subgraph CALL["Вызов Hook из пула: простой путь повторного использования"]
|
||||
TAKE["Получить свободный экземпляр в исключительное пользование"] --> RUN["Выполнить HandleRoute / HandleDNSQuery"]
|
||||
RUN -->|Нормальное завершение| PUT["Вернуть экземпляр, сохранив состояние"]
|
||||
end
|
||||
|
||||
REQUEST["Выбор маршрута / DNS-запрос"] --> AVAILABLE{"Есть свободный экземпляр?"}
|
||||
POOL -.-> AVAILABLE
|
||||
AVAILABLE -->|Да| TAKE
|
||||
PUT --> POOL
|
||||
AVAILABLE -. Нет: расширить по необходимости .-> CREATE["Создать экземпляр из скомпилированного скрипта<br/>Выполнить код верхнего уровня и проверить Hook"]
|
||||
CREATE --> RUN
|
||||
RUN -. Необработанное исключение Lua / тайм-аут .-> DESTROY["Уничтожить экземпляр"]
|
||||
POOL -. Лишние свободные экземпляры / завершение Xray .-> DESTROY
|
||||
|
||||
classDef reuse fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
|
||||
class TAKE,RUN,PUT reuse
|
||||
```
|
||||
|
||||
### Состояние в экземплярах пула
|
||||
|
||||
Глобальные переменные, переменные `local` верхнего уровня, замыкания и кеш модулей `require` принадлежат текущему экземпляру. Они сохраняются между вызовами, которые он обрабатывает, и теряются при его уничтожении:
|
||||
|
||||
```lua
|
||||
local calls = 0
|
||||
|
||||
function HandleRoute()
|
||||
calls = calls + 1
|
||||
return "direct", "instance-call-" .. calls
|
||||
end
|
||||
```
|
||||
|
||||
Счётчик выше отражает только число вызовов, обработанных текущим экземпляром. У разных экземпляров независимые значения `calls`, и запросы не обязательно попадают в один экземпляр. Этот счётчик нельзя использовать как общий для всех соединений или как постоянное состояние отдельного соединения.
|
||||
|
||||
Рекомендуется размещать код инициализации, например загрузку модулей Lua, создание объектов сопоставления и сохранение объектов DNS-серверов, вне функции Hook, на верхнем уровне скрипта. Он выполняется один раз при создании каждого экземпляра, а результаты могут повторно использоваться его последующими вызовами Hook.
|
||||
|
||||
### Тайм-ауты и обновление скриптов
|
||||
|
||||
Сейчас тайм-аут инициализации каждого экземпляра маршрутизации и DNS составляет **120 секунд**, а выполнения каждого вызова обработчика — **6 секунд**. Тайм-аут вызова отсчитывается после получения экземпляра; отдельных полей конфигурации для этих значений пока нет. При вызовах API Xray фактическая отмена также зависит от того, реагирует ли API на сигнал отмены; отдельный DNS-сервер дополнительно ограничен настройкой `timeoutMs`.
|
||||
|
||||
Xray не отслеживает и не перекомпилирует основной скрипт автоматически. После его изменения перезапустите Xray, чтобы изменения вступили в силу. Экземпляры, созданные позже, также используют основной скрипт, скомпилированный при текущем запуске.
|
||||
@@ -0,0 +1,119 @@
|
||||
# Скрипты маршрутизации
|
||||
|
||||
Когда скрипт указан через [`routing.script`](../../../config/routing.md#routingobject), выбор исходящего подключения передаётся функции Lua `HandleRoute`.
|
||||
|
||||
## Минимальный пример
|
||||
|
||||
Следующий фрагмент конфигурации задаёт файл скрипта и настраивает исходящие подключения для прямого соединения и блокировки:
|
||||
|
||||
```json
|
||||
{
|
||||
"routing": {
|
||||
"script": "routing.lua"
|
||||
},
|
||||
"outbounds": [
|
||||
{ "tag": "direct", "protocol": "freedom" },
|
||||
{ "tag": "block", "protocol": "blackhole" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Сохраните `routing.lua`:
|
||||
|
||||
```lua
|
||||
function HandleRoute(ctx)
|
||||
local sourceIPs = ctx:GetSourceIPs()
|
||||
if sourceIPs and #sourceIPs > 0
|
||||
and sourceIPs[1]:String() == "127.0.0.1" then
|
||||
return "block"
|
||||
end
|
||||
return "direct"
|
||||
end
|
||||
```
|
||||
|
||||
Скрипт читает IP-адрес источника через `ctx`. При адресе `127.0.0.1` он возвращает `block`, в остальных случаях — `direct`. Эти значения соответствуют `tag` исходящих подключений в конфигурации выше.
|
||||
|
||||
Этот фрагмент нужно объединить с полной конфигурацией. Правила поиска файла описаны в разделе [Пути к файлам скриптов](../environment.md#пути-к-фаилам-скриптов).
|
||||
|
||||
`HandleRoute` также может получать дополнительные параметры и возвращать имя правила и ошибку. Полное соглашение о вызове и поведение при ошибках описаны в [HandleRoute](../reference/hook-routing.md).
|
||||
|
||||
## Связь с конфигурацией маршрутизации
|
||||
|
||||
При включении скрипта маршрутизации `rules` и `domainStrategy` не действуют. Если скрипт не выбрал исходящее подключение или возникла ошибка, встроенные правила маршрутизации также не проверяются.
|
||||
|
||||
Настройка `balancers` остаётся доступной. Скрипт выбирает исходящее подключение через [`router:PickOutbound`](../reference/module-router.md#router-pickoutbound):
|
||||
|
||||
```lua
|
||||
local router = require("xray.router")
|
||||
|
||||
function HandleRoute(ctx)
|
||||
local outboundTag, err = router:PickOutbound("balance")
|
||||
return outboundTag, "lua-balance", err
|
||||
end
|
||||
```
|
||||
|
||||
Замените `balance` в примере значением `tag` балансировщика, настроенного в `routing.balancers`.
|
||||
|
||||
## Пример: явный DNS-запрос для маршрутизации по IP
|
||||
|
||||
Следующий скрипт сначала обрабатывает трафик запросов к вышестоящим DNS-серверам, затем проверяет имеющиеся IP-адреса назначения запроса. При необходимости он явно разрешает домен и выбирает исходящее подключение по диапазонам частных адресов.
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"tag": "dns-query",
|
||||
"servers": ["1.1.1.1"]
|
||||
},
|
||||
"routing": {
|
||||
"script": "routing.lua"
|
||||
},
|
||||
"outbounds": [
|
||||
{ "tag": "direct", "protocol": "freedom" },
|
||||
{
|
||||
"tag": "proxy",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```lua
|
||||
local dns = require("xray.dns")
|
||||
local geodata = require("xray.geodata")
|
||||
local log = require("xray.log")
|
||||
local privateIPMatcher = geodata.BuildIPMatcher("geoip:private")
|
||||
|
||||
function HandleRoute(ctx, inboundTag, sourcePort, targetPort,
|
||||
localPort, targetDomain, network, protocol, user,
|
||||
vlessRoute, skipDNSResolve)
|
||||
if skipDNSResolve or inboundTag == "dns-query" then
|
||||
return "direct", "lua-dns"
|
||||
end
|
||||
|
||||
local ips = ctx:GetTargetIPs()
|
||||
if privateIPMatcher:AnyMatch(ips) then
|
||||
return "direct", "lua-private"
|
||||
end
|
||||
|
||||
if targetDomain ~= "" then
|
||||
local resolved, ttl, err =
|
||||
dns.Query(targetDomain, true, true, false)
|
||||
if err ~= nil then
|
||||
log.Warning("Разрешение ", targetDomain, " завершилось ошибкой: ", err)
|
||||
elseif privateIPMatcher:AnyMatch(resolved) then
|
||||
return "direct", "lua-resolved-private"
|
||||
end
|
||||
end
|
||||
|
||||
return "proxy", "lua-default"
|
||||
end
|
||||
```
|
||||
|
||||
Запросы к вышестоящим DNS-серверам в обычном режиме также проходят через маршрутизацию. В примере для запросов с `skipDNSResolve`, равным `true`, или `inboundTag`, равным `"dns-query"`, исходящее подключение выбирается сразу, чтобы повторный DNS-запрос не создал петлю.
|
||||
|
||||
Результат `dns.Query` используется только для принятия решения в скрипте. Он не меняет автоматически IP-адреса назначения в `ctx` или фактическую цель соединения. При ошибке разрешения пример выбирает `proxy`; при необходимости измените это поведение согласно своей политике.
|
||||
|
||||
Инициализация верхнего уровня и сохранение состояния скриптов маршрутизации описаны в разделе [Жизненный цикл пула](./lifecycle.md#жизненныи-цикл-пула).
|
||||
@@ -0,0 +1,46 @@
|
||||
# Скрипты Lua
|
||||
|
||||
Скрипты Lua позволяют гибко расширять Xray, реализовывать собственные функции и взаимодействовать с ядром.
|
||||
|
||||
## Начало работы
|
||||
|
||||
Сначала прочитайте [Среда выполнения и загрузка скриптов](./environment.md), чтобы узнать о поддержке Lua, загрузке модулей и правилах поиска файлов скриптов.
|
||||
|
||||
## Руководства по написанию
|
||||
|
||||
Выберите руководство для нужной функции, начните с минимального примера и постепенно создайте собственный скрипт:
|
||||
|
||||
| Руководство | Назначение | Содержание |
|
||||
| ------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
||||
| [Скрипты маршрутизации](./guide/routing.md) | Собственные правила маршрутизации | Выбор исходящего подключения, балансировка нагрузки и маршрутизация по IP после явного разрешения домена |
|
||||
| [Скрипты DNS](./guide/dns.md) | Собственная обработка DNS-запросов | Выбор вышестоящего сервера, резервные запросы и фильтрация результатов |
|
||||
|
||||
Текущие скрипты маршрутизации и DNS используют экземпляры из пула. При написании скриптов учитывайте [жизненный цикл пула](./guide/lifecycle.md#жизненныи-цикл-пула), чтобы понимать, когда выполняется инициализация верхнего уровня и как сохраняется состояние.
|
||||
|
||||
## Справочник
|
||||
|
||||
### Hook
|
||||
|
||||
Hook — это функция Lua, которую ядро вызывает в определённый момент. Точка входа скрипта определяет доступные Hook и соглашения об их вызове; одной точке входа могут соответствовать несколько Hook. Какие именно Hook нужно реализовать, указано в описании соответствующей точки входа.
|
||||
|
||||
Сейчас поддерживаются следующие точки входа и Hook. Параметры, возвращаемые значения и поведение при ошибках описаны на справочных страницах каждого Hook:
|
||||
|
||||
| Точка входа скрипта | Hook |
|
||||
| ------------------- | ------------------------------------------ |
|
||||
| `routing.script` | [HandleRoute](./reference/hook-routing.md) |
|
||||
| `dns.script` | [HandleDNSQuery](./reference/hook-dns.md) |
|
||||
|
||||
### Типы данных
|
||||
|
||||
Помимо встроенных типов Lua, Xray Lua использует `net.IP`, срезы Go и `error`. Их представление и способы работы с ними в Lua описаны в разделе [Типы данных](./reference/data-types.md).
|
||||
|
||||
### API модулей
|
||||
|
||||
Выберите API модуля по назначению:
|
||||
|
||||
| Модуль | Назначение |
|
||||
| --------------------------------------------- | --------------------------------------- |
|
||||
| [xray.router](./reference/module-router.md) | Маршрутизация по правилам |
|
||||
| [xray.dns](./reference/module-dns.md) | Разрешение доменных имён |
|
||||
| [xray.geodata](./reference/module-geodata.md) | Сопоставление и фильтрация доменов и IP |
|
||||
| [xray.log](./reference/module-log.md) | Запись журналов |
|
||||
@@ -0,0 +1,215 @@
|
||||
# Типы данных
|
||||
|
||||
На этой странице собраны типы данных, общие для модулей, и описаны их представление и использование в Lua. Типы, специфичные для отдельного модуля, описаны на его странице.
|
||||
|
||||
## net.IP
|
||||
|
||||
| Свойство | Описание |
|
||||
| ------------------- | ------------------------- |
|
||||
| Базовый тип Go | `net.IP`, `common/net.IP` |
|
||||
| Представление в Lua | `userdata` |
|
||||
|
||||
Обычно не нужно сравнивать значения `net.IP` по одному в Lua, особенно в часто выполняемом коде. Для сопоставления IP используйте прежде всего [`IPMatcher`](./module-geodata.md#ipmatcher), который напрямую работает со значениями `net.IP`, возвращаемыми API.
|
||||
|
||||
Если нужно работать с IP напрямую, учитывайте, что `net.IP` и строка IP-адреса — разные типы. Для преобразования и сравнения доступны следующие два метода:
|
||||
|
||||
### String
|
||||
|
||||
```lua
|
||||
local text = ip:String()
|
||||
```
|
||||
|
||||
Преобразует IP в текст адреса.
|
||||
|
||||
**Параметры**
|
||||
|
||||
Дополнительных параметров нет.
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | -------- | ---------------------------------- |
|
||||
| `text` | `string` | Строка IP-адреса; никогда не `nil` |
|
||||
|
||||
### Equal
|
||||
|
||||
```lua
|
||||
local equal = ip:Equal(otherIP)
|
||||
```
|
||||
|
||||
Проверяет равенство двух IP.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание |
|
||||
| --------- | ----------------------------- | ----------------------------------------- |
|
||||
| `otherIP` | [`net.IP`](#net-ip) или `nil` | IP для сравнения; допускается явный `nil` |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | --------- | ----------------------------------------------------- |
|
||||
| `equal` | `boolean` | `true` при равенстве, иначе `false`; никогда не `nil` |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Сравнение допустимого IP с `nil` возвращает `false`.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
if ip ~= nil then
|
||||
local text = ip:String()
|
||||
local equal = ip:Equal(otherIP)
|
||||
end
|
||||
```
|
||||
|
||||
## slice
|
||||
|
||||
Срез Go представлен в Lua как `userdata`, сохраняет тип элементов и индексируется начиная с **1**. Следующие два типа срезов используют одинаковые операции получения длины, доступа по индексу и перебора.
|
||||
|
||||
| Тип | Представление в Lua | Тип элемента |
|
||||
| ----------------------- | ------------------- | ------------------- |
|
||||
| [`[]net.IP`](#net-ip-1) | `userdata` | [`net.IP`](#net-ip) |
|
||||
| [`[]uint32`](#uint32) | `userdata` | `number` |
|
||||
|
||||
### []net.IP
|
||||
|
||||
Совет: для сопоставления или фильтрации списков IP используйте прежде всего [`IPMatcher`](./module-geodata.md#ipmatcher), который напрямую работает с `[]net.IP`.
|
||||
|
||||
### []uint32
|
||||
|
||||
Элементы — 32-битные целые числа без знака в диапазоне `0 .. 4294967295`.
|
||||
|
||||
### #values
|
||||
|
||||
```lua
|
||||
local count = #values
|
||||
```
|
||||
|
||||
Возвращает число элементов среза.
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | -------- | -------------------------------------------------- |
|
||||
| `count` | `number` | Неотрицательное целое число; `0` для пустого среза |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Списки, возвращаемые API, могут быть `nil` или срезами длины 0. Перед выполнением этих операций `values` не должен быть `nil`; одной проверки `if values then` недостаточно, чтобы определить наличие элементов.
|
||||
|
||||
### values[i]
|
||||
|
||||
```lua
|
||||
local value = values[i]
|
||||
```
|
||||
|
||||
Читает один элемент среза.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание |
|
||||
| -------- | -------- | -------------------------------------------------- |
|
||||
| `i` | `number` | Обязателен; целое число в диапазоне `1 .. #values` |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | -------------------------------- | ------------------------------------------------ |
|
||||
| `value` | [`net.IP`](#net-ip) или `number` | Элемент `[]net.IP` или `[]uint32` соответственно |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Выход за границы вызывает исключение Lua, а не возвращает `nil`. Избегайте прямого изменения срезов, возвращаемых API.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
if ips ~= nil and #ips > 0 then
|
||||
local firstIP = ips[1]:String()
|
||||
end
|
||||
```
|
||||
|
||||
### values()
|
||||
|
||||
```lua
|
||||
for i, value in values() do
|
||||
-- Используйте индекс i и элемент value
|
||||
end
|
||||
```
|
||||
|
||||
Возвращает итератор среза для обобщённого цикла `for`; индексы начинаются с 1.
|
||||
|
||||
**Параметры**
|
||||
|
||||
Дополнительных параметров нет.
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | ---------- | ----------------------------------------------------------------- |
|
||||
| Итератор | `function` | Последовательно предоставляет индекс и элемент, как показано выше |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Срезы не поддерживают `pairs` и `ipairs`; для перебора также можно использовать числовой цикл `for`.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
if ips ~= nil then
|
||||
for i = 1, #ips do
|
||||
local text = ips[i]:String()
|
||||
end
|
||||
|
||||
for i, ip in ips() do
|
||||
local text = ip:String()
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Ввод списка IP
|
||||
|
||||
При передаче списка IP в `IPMatcher` доступны следующие формы:
|
||||
|
||||
| Форма ввода | Представление в Lua | Описание |
|
||||
| -------------------------- | ------------------- | ------------------------------------------------------------------------------ |
|
||||
| [`[]net.IP`](#net-ip-1) | `userdata` | Список IP; допускается пустой срез |
|
||||
| Массив [`net.IP`](#net-ip) | `table` | IP последовательно с индекса 1; допускается пустой массив `{}`, но не пропуски |
|
||||
| `nil` | `nil` | Нужно передать явно; результат указан в описании каждого метода |
|
||||
|
||||
Строки IP-адресов не преобразуются в `net.IP`. Пустая строка `""` не является допустимым списком IP; её передача в `AnyMatch`, `Matches` или `FilterIPs` вызывает исключение Lua.
|
||||
|
||||
## error
|
||||
|
||||
| Свойство | Описание |
|
||||
| ------------------- | ---------------------------------------------- |
|
||||
| Базовый тип Go | `error` |
|
||||
| Представление в Lua | `userdata` при ошибке; `nil` при её отсутствии |
|
||||
|
||||
Если возвращаемое API значение `err` равно `nil`, ошибки нет; иначе это объект ошибки. Его можно без изменений вернуть как `err` из Hook, чтобы передать ошибку ядру Xray.
|
||||
|
||||
**Соглашение о возврате из Hook**
|
||||
|
||||
| Значение ошибки | Значение |
|
||||
| ----------------- | ------------------------------------------------------------------------ |
|
||||
| `nil` | Ошибки нет |
|
||||
| `userdata` ошибки | Сохраняет исходную ошибку |
|
||||
| `string` | Сообщение об ошибке от скрипта; пустая строка `""` также означает ошибку |
|
||||
|
||||
Строковые ошибки допустимы только в возвращаемых значениях Hook. Сами API Xray возвращают ошибку или `nil`. Проверка значений и поведение при ошибках описаны в соответствующем Hook.
|
||||
|
||||
**Вывод сообщений об ошибках**
|
||||
|
||||
Сообщение объекта ошибки Go нельзя получить через `tostring(err)`. Для вывода передайте `err` напрямую в [`xray.log`](./module-log.md).
|
||||
|
||||
```lua
|
||||
local log = require("xray.log")
|
||||
local ips, ttl, err = serverObj:Query(domain, ipv4, ipv6, fake)
|
||||
if err ~= nil then
|
||||
log.Warning("Ошибка DNS-запроса: ", err)
|
||||
elseif ips ~= nil and #ips > 0 then
|
||||
local firstIP = ips[1]:String()
|
||||
end
|
||||
```
|
||||
@@ -0,0 +1,67 @@
|
||||
# Hook DNS
|
||||
|
||||
Во время запросов встроенного DNS ядро вызывает глобальную функцию `HandleDNSQuery` из `dns.script`. Настройка и полные примеры приведены в [руководстве по скриптам DNS](../guide/dns.md).
|
||||
|
||||
## Указатель API
|
||||
|
||||
| Категория | Член API | Описание |
|
||||
| --------- | ---------------------------------------- | ---------------------- |
|
||||
| Hook | [`HandleDNSQuery(...)`](#handlednsquery) | Обработка DNS-запросов |
|
||||
|
||||
## Интерфейс Hook
|
||||
|
||||
### HandleDNSQuery(...)
|
||||
|
||||
```lua
|
||||
function HandleDNSQuery(domain, ipv4, ipv6, fake)
|
||||
return ips, ttl, err
|
||||
end
|
||||
```
|
||||
|
||||
Обрабатывает один DNS-запрос и возвращает срез IP, TTL или ошибку.
|
||||
|
||||
#### Параметры
|
||||
|
||||
Ядро всегда передаёт все четыре параметра; ни один из них не равен `nil`.
|
||||
|
||||
| Параметр | Тип | Описание |
|
||||
| -------- | --------- | ------------------------------------------------ |
|
||||
| `domain` | `string` | Запрашиваемый домен; непустой, в нижнем регистре |
|
||||
| `ipv4` | `boolean` | Разрешены ли запросы адресов IPv4 |
|
||||
| `ipv6` | `boolean` | Разрешены ли запросы адресов IPv6 |
|
||||
| `fake` | `boolean` | Разрешён ли FakeDNS для этого запроса |
|
||||
|
||||
`ipv4` и `ipv6` уже ограничены глобальным [`queryStrategy`](../../../config/dns.md#dnsobject); хотя бы один равен `true`. Обычно при запросах к вышестоящему серверу эти три булевых параметра передаются без изменений.
|
||||
|
||||
#### Возвращаемые значения
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
||||
| `ips` | [`[]net.IP`](./data-types.md#net-ip-1) или `nil` | Результаты запроса; нужен срез, массив Lua не принимается |
|
||||
| `ttl` | `number` или `nil` | TTL в секундах; при `err == nil` должен быть целым числом в диапазоне `0 .. 4294967295` |
|
||||
| `err` | [`error`](./data-types.md#error), `string` или `nil` | Только `nil` означает отсутствие ошибки |
|
||||
|
||||
#### Поведение
|
||||
|
||||
Ядро последовательно проверяет `err`, `ttl` и `ips`, останавливаясь при первой ошибке. Если `err` не равен `nil`, два остальных значения игнорируются. При отсутствии ошибки нужно указать допустимый TTL, даже если результат IP пуст.
|
||||
|
||||
Для пустого ответа используйте `return nil, 0, nil`. Ошибка должна быть в третьей позиции, например `return nil, nil, "ошибка запроса"`.
|
||||
|
||||
| Результат скрипта | Действие ядра |
|
||||
| ------------------------------------------------------------------ | -------------------------------------------- |
|
||||
| Проверка успешна, `ips` непустой | Запрос успешен |
|
||||
| `err == nil`, TTL допустим, но `ips` равен `nil` или пустому срезу | Запрос завершается неудачей с пустым ответом |
|
||||
| Возвращена ошибка, неверный тип значения или исключение выполнения | Запрос завершается неудачей |
|
||||
|
||||
#### Пример
|
||||
|
||||
Можно напрямую передать все три возвращаемых значения [`serverObj:Query`](./module-dns.md#query):
|
||||
|
||||
```lua
|
||||
local dns = require("xray.dns")
|
||||
local serverObj = dns.Servers[1]
|
||||
|
||||
function HandleDNSQuery(domain, ipv4, ipv6, fake)
|
||||
return serverObj:Query(domain, ipv4, ipv6, fake)
|
||||
end
|
||||
```
|
||||
@@ -0,0 +1,181 @@
|
||||
# Hook маршрутизации
|
||||
|
||||
При выборе исходящего подключения ядро вызывает глобальную функцию `HandleRoute` из `routing.script`. Настройка и полные примеры приведены в [руководстве по скриптам маршрутизации](../guide/routing.md).
|
||||
|
||||
## Указатель API
|
||||
|
||||
| Категория | Член API | Описание |
|
||||
| --------- | --------------------------------------- | ---------------------------------------- |
|
||||
| Hook | [`HandleRoute(...)`](#handleroute) | Выбор исходящего подключения для запроса |
|
||||
| Объект | [`routing.Context`](#routing-context) | Контекст маршрутизации текущего запроса |
|
||||
| Метод | [`ctx:GetSourceIPs()`](#getsourceips) | Получение IP источника |
|
||||
| Метод | [`ctx:GetTargetIPs()`](#gettargetips) | Получение IP назначения |
|
||||
| Метод | [`ctx:GetLocalIPs()`](#getlocalips) | Получение локальных IP |
|
||||
| Метод | [`ctx:GetAttributes()`](#getattributes) | Получение атрибутов запроса |
|
||||
|
||||
## Интерфейс Hook
|
||||
|
||||
### HandleRoute(...)
|
||||
|
||||
```lua
|
||||
function HandleRoute(ctx, inboundTag, sourcePort, targetPort,
|
||||
localPort, targetDomain, network, protocol, user,
|
||||
vlessRoute, skipDNSResolve)
|
||||
return outboundTag, ruleTag, err
|
||||
end
|
||||
```
|
||||
|
||||
Выбирает исходящее подключение для текущего запроса и при необходимости возвращает имя правила или ошибку.
|
||||
|
||||
#### Параметры
|
||||
|
||||
Ядро всегда передаёт все 11 параметров в указанном порядке; ни один из них не равен `nil`. В определении функции можно опустить неиспользуемые параметры в конце — это не меняет значения, передаваемые ядром.
|
||||
|
||||
| Параметр | Тип | Описание | Пустые значения и значения по умолчанию |
|
||||
| ---------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| `ctx` | [`routing.Context`](#routing-context) | Контекст текущего запроса | Всегда допустимый `userdata` |
|
||||
| `inboundTag` | `string` | Тег входящего подключения | `""`, если тег не задан или нет входящей информации |
|
||||
| `sourcePort` | `number` | Порт источника, `0 .. 65535` | `0`, если нет допустимого адреса источника |
|
||||
| `targetPort` | `number` | Порт назначения, `0 .. 65535` | `0`, если нет допустимого адреса назначения |
|
||||
| `localPort` | `number` | Локальный порт входящего соединения, `0 .. 65535` | `0`, если нет допустимого локального адреса |
|
||||
| `targetDomain` | `string` | Действующий домен, обнаруженный анализом трафика, имеет приоритет; иначе используется домен цели соединения. Значение приводится к нижнему регистру | `""`, если цель — IP без действующего обнаруженного домена или нет информации о цели |
|
||||
| `network` | `number` | Тип сети; сравнивается с константами вроде [`router.NetworkTCP`](./module-router.md#константы) | `NetworkUnknown` (`0`), если нет исходящей информации или тип сети неизвестен |
|
||||
| `protocol` | `string` | Протокол, обнаруженный анализом трафика | `""`, если нет информации об обнаруженном протоколе |
|
||||
| `user` | `string` | Email пользователя | `""`, если нет входящей информации, данных пользователя или email не задан |
|
||||
| `vlessRoute` | `number` | Значение маршрута из 7-го и 8-го байтов UUID VLESS, `0 .. 65535` | `0` при отсутствии информации; само значение также может быть 0 |
|
||||
| `skipDNSResolve` | `boolean` | При `true` нужно пропустить DNS-запросы, чтобы избежать петель | `false`, если нет этого флага или дополнительных данных запроса |
|
||||
|
||||
#### Возвращаемые значения
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| ------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| `outboundTag` | `string` или `nil` | Тег исходящего подключения; `nil` или `""` означает, что оно не выбрано |
|
||||
| `ruleTag` | `string` или `nil` | Необязательное имя правила; `nil`, отсутствие значения или `""` означает отсутствие имени |
|
||||
| `err` | [`error`](./data-types.md#error), `string` или `nil` | Только `nil` означает отсутствие ошибки |
|
||||
|
||||
#### Поведение
|
||||
|
||||
Ядро последовательно проверяет `err`, `outboundTag` и `ruleTag`, останавливаясь при первой ошибке. Если `err` не равен `nil`, первые два значения игнорируются. Если исходящее подключение не выбрано, `ruleTag` игнорируется.
|
||||
|
||||
При успехе значения `ruleTag` и `err` в конце можно опустить, например `return "direct"`. Ошибка должна быть в третьей позиции, например `return nil, nil, "ошибка маршрутизации"`; `return nil, "ошибка маршрутизации"` не сообщает об ошибке.
|
||||
|
||||
| Результат скрипта | Действие ядра |
|
||||
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
|
||||
| Проверка успешна, `outboundTag` непустой | Использует соответствующее исходящее подключение; если тег не существует, закрывает соединение |
|
||||
| Исходящее подключение не выбрано | Использует исходящее подключение по умолчанию |
|
||||
| Возвращена ошибка, неверный тип значения или исключение выполнения | Записывает ошибку в журнал и пробует исходящее подключение по умолчанию |
|
||||
|
||||
Исходящее подключение по умолчанию — первое в конфигурации; если оно недоступно, соединение закрывается. Для блокировки трафика явно возвращайте тег настроенного исходящего подключения [`blackhole`](../../../config/outbounds/blackhole.md), а не используйте это поведение с несуществующим тегом.
|
||||
|
||||
## Связанные объекты
|
||||
|
||||
### routing.Context
|
||||
|
||||
`routing.Context` представляет контекст маршрутизации текущего запроса и доступен в `HandleRoute` через параметр `ctx`.
|
||||
|
||||
| Свойство | Описание |
|
||||
| ------------------- | ------------------------------------------------- |
|
||||
| Базовый тип Go | Интерфейс `routing.Context` из `features/routing` |
|
||||
| Представление в Lua | `userdata` |
|
||||
| Получение | Первый параметр `HandleRoute`, передаваемый ядром |
|
||||
|
||||
Все методы ниже не принимают дополнительных параметров. Операции с IP и срезами описаны в разделе [Типы данных](./data-types.md).
|
||||
|
||||
#### GetSourceIPs
|
||||
|
||||
```lua
|
||||
local ips = ctx:GetSourceIPs()
|
||||
```
|
||||
|
||||
Получает IP-адреса источника запроса.
|
||||
|
||||
**Параметры**
|
||||
|
||||
Дополнительных параметров нет.
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | ------------------------------------------------ | --------------------------------- |
|
||||
| `ips` | [`[]net.IP`](./data-types.md#net-ip-1) или `nil` | Список IP соответствующего адреса |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Возвращает `nil`, если нет входящего подключения, адрес источника недопустим или не является IP-адресом.
|
||||
|
||||
#### GetTargetIPs
|
||||
|
||||
```lua
|
||||
local ips = ctx:GetTargetIPs()
|
||||
```
|
||||
|
||||
Получает IP-адреса назначения запроса.
|
||||
|
||||
**Параметры**
|
||||
|
||||
Дополнительных параметров нет.
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | ------------------------------------------------ | --------------------------------- |
|
||||
| `ips` | [`[]net.IP`](./data-types.md#net-ip-1) или `nil` | Список IP соответствующего адреса |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Возвращает `nil`, если нет исходящего подключения, адрес назначения недопустим или является доменным именем.
|
||||
|
||||
#### GetLocalIPs
|
||||
|
||||
```lua
|
||||
local ips = ctx:GetLocalIPs()
|
||||
```
|
||||
|
||||
Получает локальные IP-адреса входящего соединения.
|
||||
|
||||
**Параметры**
|
||||
|
||||
Дополнительных параметров нет.
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | ------------------------------------------------ | --------------------------------- |
|
||||
| `ips` | [`[]net.IP`](./data-types.md#net-ip-1) или `nil` | Список IP соответствующего адреса |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Возвращает `nil`, если нет входящего подключения, локальный адрес недопустим или не является IP-адресом.
|
||||
|
||||
#### GetAttributes
|
||||
|
||||
```lua
|
||||
local attributes = ctx:GetAttributes()
|
||||
```
|
||||
|
||||
Получает атрибуты текущего запроса.
|
||||
|
||||
**Параметры**
|
||||
|
||||
Дополнительных параметров нет.
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| ------------ | ------------------- | ----------------------------------- |
|
||||
| `attributes` | `map[string]string` | Всегда `userdata`; никогда не `nil` |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Читайте атрибуты через `attributes[key]`, где `key` должен быть строкой. Существующий ключ возвращает строку (возможно `""`), отсутствующий — `nil`.
|
||||
|
||||
Значение и использование атрибутов описаны в поле [`attrs`](../../../config/routing.md#ruleobject) конфигурации маршрутизации.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
local attributes = ctx:GetAttributes()
|
||||
if attributes[":method"] == "GET" then
|
||||
return "direct", "lua-get"
|
||||
end
|
||||
```
|
||||
@@ -0,0 +1,139 @@
|
||||
# xray.dns
|
||||
|
||||
Предоставляет интерфейсы DNS-запросов и доступа к вышестоящим серверам.
|
||||
|
||||
```lua
|
||||
local dns = require("xray.dns")
|
||||
```
|
||||
|
||||
## Указатель API
|
||||
|
||||
| Категория | Член API | Описание |
|
||||
| --------- | ----------------------------------------------------- | ---------------------------------- |
|
||||
| Функция | [`dns.Query(domain, ipv4, ipv6, fake)`](#dns-query) | Запрос через DNS-клиент Xray |
|
||||
| Поле | [`dns.Servers`](#dns-servers) | Массив вышестоящих серверов |
|
||||
| Объект | [`serverObj`](#server) | Отдельный вышестоящий DNS-сервер |
|
||||
| Поле | [`serverObj.ID`](#id) | Идентификатор сервера |
|
||||
| Метод | [`serverObj:Query(domain, ipv4, ipv6, fake)`](#query) | Прямой запрос к указанному серверу |
|
||||
|
||||
## Функции
|
||||
|
||||
### dns.Query
|
||||
|
||||
```lua
|
||||
local ips, ttl, err = dns.Query(domain, ipv4, ipv6, fake)
|
||||
```
|
||||
|
||||
Запрашивает домен через DNS-клиент Xray. В Hook DNS недоступен, поскольку скрипт заменяет именно этот процесс обработки запросов.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание |
|
||||
| -------- | --------- | ------------------------- |
|
||||
| `domain` | `string` | Запрашиваемый домен |
|
||||
| `ipv4` | `boolean` | Разрешены ли запросы IPv4 |
|
||||
| `ipv6` | `boolean` | Разрешены ли запросы IPv6 |
|
||||
| `fake` | `boolean` | Разрешён ли FakeDNS |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | ------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| `ips` | [`[]net.IP`](./data-types.md#net-ip-1) или `nil` | Результаты запроса |
|
||||
| `ttl` | `number` | TTL в секундах, диапазон `0 .. 4294967295`; никогда не `nil` |
|
||||
| `err` | [`error`](./data-types.md#error) или `nil` | Ошибка запроса; `nil` означает отсутствие ошибки |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Все четыре параметра нужно передать явно с правильными типами, иначе возникает исключение Lua.
|
||||
|
||||
Запрос учитывает глобальные ограничения типов запросов клиента, Hosts и настройки вышестоящих серверов. Если настроен [скрипт DNS](../guide/dns.md), запрос также передаётся ему. Если встроенный DNS не настроен, используется системный DNS.
|
||||
|
||||
При успехе возвращается непустой срез IP; при ошибке запроса или отсутствии доступных адресов — `nil, 0, err`.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
local ips, ttl, err = dns.Query("example.com", true, true, false)
|
||||
if err == nil and ips ~= nil and #ips > 0 then
|
||||
local firstIP = ips[1]:String()
|
||||
end
|
||||
```
|
||||
|
||||
## Поля
|
||||
|
||||
### dns.Servers
|
||||
|
||||
```lua
|
||||
local servers = dns.Servers
|
||||
```
|
||||
|
||||
| Имя | Тип | Описание |
|
||||
| ------------- | ------- | ------------------------------------------------------------------------------ |
|
||||
| `dns.Servers` | `table` | Массив [`serverObj`](#server), индексы с 1, порядок соответствует конфигурации |
|
||||
|
||||
При использовании встроенного DNS список содержит настроенные вышестоящие серверы. Если DNS или его серверы не настроены, список содержит только `localhost` (системный DNS).
|
||||
|
||||
Для перебора списка используйте `ipairs`; при выходе индекса за границы `servers[i]` равен `nil`.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
for _, serverObj in ipairs(dns.Servers) do
|
||||
local id = serverObj.ID
|
||||
end
|
||||
```
|
||||
|
||||
## Объекты
|
||||
|
||||
### server
|
||||
|
||||
`serverObj` представляет вышестоящий DNS-сервер с его идентификатором и методом запроса.
|
||||
|
||||
| Свойство | Описание |
|
||||
| ------------------- | --------------------------------------------- |
|
||||
| Реализация в Go | `luaDNSServer` из `app/dns` |
|
||||
| Представление в Lua | `table` |
|
||||
| Получение | Элемент массива [`dns.Servers`](#dns-servers) |
|
||||
|
||||
#### ID
|
||||
|
||||
```lua
|
||||
local id = serverObj.ID
|
||||
```
|
||||
|
||||
| Имя | Тип | Описание |
|
||||
| -------------- | -------- | ------------------------------------------------------------------------------------------------ |
|
||||
| `serverObj.ID` | `string` | Поле `id` в [конфигурации DNS-сервера](../../../config/dns.md#dnsserverobject); никогда не `nil` |
|
||||
|
||||
Если `id` не задан, значение равно `""`, в том числе у серверов, настроенных строками. Автоматически добавленный системный DNS имеет ID `"localhost"`.
|
||||
|
||||
Если нужно различать серверы по ID, самостоятельно задайте уникальные значения: ядро не проверяет дубликаты.
|
||||
|
||||
#### Query
|
||||
|
||||
```lua
|
||||
local ips, ttl, err = serverObj:Query(domain, ipv4, ipv6, fake)
|
||||
```
|
||||
|
||||
Запрашивает вышестоящий сервер, представленный `serverObj`.
|
||||
|
||||
**Параметры и возвращаемые значения**
|
||||
|
||||
Требования к параметрам и типы возвращаемых значений такие же, как у [`dns.Query`](#dns-query).
|
||||
|
||||
**Поведение**
|
||||
|
||||
Обычно настроенный сервер при успехе возвращает непустой срез IP, TTL и `nil`. При ошибке запроса, отсутствии адресов, удовлетворяющих условиям, или запросе FakeDNS с `fake == false` возвращается `nil, 0, err`.
|
||||
|
||||
Запрашивает этот сервер напрямую, обходя глобальные Hosts и скрипт DNS. Собственные настройки сервера `queryStrategy`, кеш, `timeoutMs`, `clientIP`, `tag`, а также `expectedIPs` / `unexpectedIPs` и соответствующие `actPrior` / `actUnprior` продолжают действовать.
|
||||
|
||||
**Пример**
|
||||
|
||||
Вернуть результат запроса к первому серверу напрямую из Hook DNS:
|
||||
|
||||
```lua
|
||||
function HandleDNSQuery(domain, ipv4, ipv6, fake)
|
||||
return dns.Servers[1]:Query(domain, ipv4, ipv6, fake)
|
||||
end
|
||||
```
|
||||
@@ -0,0 +1,344 @@
|
||||
# xray.geodata
|
||||
|
||||
Предоставляет сопоставление доменов и IP по правилам.
|
||||
|
||||
```lua
|
||||
local geodata = require("xray.geodata")
|
||||
```
|
||||
|
||||
## Указатель API
|
||||
|
||||
| Категория | Член API | Описание |
|
||||
| --------- | ---------------------------------------------------------------- | ------------------------------------------- |
|
||||
| Функция | [`geodata.BuildDomainMatcher(...)`](#geodata-builddomainmatcher) | Создание `DomainMatcher` |
|
||||
| Функция | [`geodata.BuildIPMatcher(...)`](#geodata-buildipmatcher) | Создание `IPMatcher` |
|
||||
| Объект | [`DomainMatcher`](#domainmatcher) | Объект сопоставления доменов |
|
||||
| Метод | [`domainMatcherObj:MatchAny(domain)`](#matchany) | Проверка совпадения домена с любым правилом |
|
||||
| Метод | [`domainMatcherObj:Match(domain)`](#match) | Получение номеров совпавших правил домена |
|
||||
| Объект | [`IPMatcher`](#ipmatcher) | Объект сопоставления IP |
|
||||
| Метод | [`ipMatcherObj:Match(ip)`](#match-1) | Сопоставление отдельного IP |
|
||||
| Метод | [`ipMatcherObj:AnyMatch(ips)`](#anymatch) | Проверка наличия совпавшего IP |
|
||||
| Метод | [`ipMatcherObj:Matches(ips)`](#matches) | Проверка совпадения всего списка IP |
|
||||
| Метод | [`ipMatcherObj:FilterIPs(ips)`](#filterips) | Разделение совпавших и несовпавших IP |
|
||||
| Метод | [`ipMatcherObj:SetReverse(reverse)`](#setreverse) | Установка флага инверсии |
|
||||
| Метод | [`ipMatcherObj:ToggleReverse()`](#togglereverse) | Переключение флага инверсии |
|
||||
|
||||
## Функции
|
||||
|
||||
### geodata.BuildDomainMatcher
|
||||
|
||||
```lua
|
||||
local domainMatcherObj = geodata.BuildDomainMatcher(rule1, rule2, ...)
|
||||
```
|
||||
|
||||
Создаёт [`DomainMatcher`](#domainmatcher) из правил доменов.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| ------------------- | -------- | -------------------------------------------------------------------- |
|
||||
| `rule1, rule2, ...` | `string` | Обязательны; хотя бы одно правило домена, каждое передаётся отдельно |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| ------------------ | --------------------------------- | ------------------------------- |
|
||||
| `domainMatcherObj` | [`DomainMatcher`](#domainmatcher) | Экземпляр сопоставления доменов |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Если правила не переданы, тип аргумента неверен или произошла ошибка разбора правил, загрузки ресурсов или создания объекта, возникает исключение Lua.
|
||||
|
||||
Поддерживаются `domain:`, `full:`, `keyword:`, `regexp:`, `dotless:`, `geosite:` и `ext:` (также `ext-domain:` / `ext-site:`). Форматы описаны в [правилах доменов маршрутизации](../../../config/routing.md#ruleobject). Файлы GeoSite загружаются из [каталога ресурсов](../../../config/env.md#путь-к-фаилам-ресурсов).
|
||||
|
||||
Строки без префикса по умолчанию используют правило `domain:`.
|
||||
|
||||
Кроме регулярных выражений, правила при создании приводятся к нижнему регистру.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
local sitesObj = geodata.BuildDomainMatcher(
|
||||
"example.com", "full:other.example"
|
||||
)
|
||||
```
|
||||
|
||||
### geodata.BuildIPMatcher
|
||||
|
||||
```lua
|
||||
local ipMatcherObj = geodata.BuildIPMatcher(rule1, rule2, ...)
|
||||
```
|
||||
|
||||
Создаёт [`IPMatcher`](#ipmatcher) из правил IP.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| ------------------- | -------- | ---------------------------------------------------------------- |
|
||||
| `rule1, rule2, ...` | `string` | Обязательны; хотя бы одно правило IP, каждое передаётся отдельно |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------------- | ------------------------- | -------------------------- |
|
||||
| `ipMatcherObj` | [`IPMatcher`](#ipmatcher) | Экземпляр сопоставления IP |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Если правила не переданы, тип аргумента неверен, правило является пустой строкой или произошла ошибка разбора правил, загрузки ресурсов или создания объекта, возникает исключение Lua.
|
||||
|
||||
Поддерживаются IP, CIDR, `geoip:`, `ext:` (также `ext-ip:`) и правила инверсии `!`. Сочетание правил описано в [правилах IP маршрутизации](../../../config/routing.md#ruleobject). Файлы GeoIP загружаются из [каталога ресурсов](../../../config/env.md#путь-к-фаилам-ресурсов).
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
local privateIPsObj = geodata.BuildIPMatcher(
|
||||
"10.0.0.0/8", "192.168.0.0/16", "fc00::/7"
|
||||
)
|
||||
```
|
||||
|
||||
## Объекты
|
||||
|
||||
### DomainMatcher
|
||||
|
||||
| Свойство | Описание |
|
||||
| ------------------- | -------------------------------------------------------------------------------------- |
|
||||
| Базовый тип Go | Реализация интерфейса `geodata.DomainMatcher` |
|
||||
| Представление в Lua | `userdata` |
|
||||
| Получение | Возвращаемое значение [`geodata.BuildDomainMatcher(...)`](#geodata-builddomainmatcher) |
|
||||
|
||||
**Общие соглашения**
|
||||
|
||||
Методы сопоставления принимают одну строку домена. `nil`, отсутствие аргумента, неверный тип или число аргументов вызывают исключение Lua.
|
||||
|
||||
Входной домен не приводится к нижнему регистру автоматически; при необходимости это должен делать скрипт.
|
||||
|
||||
#### MatchAny
|
||||
|
||||
```lua
|
||||
local matched = domainMatcherObj:MatchAny(domain)
|
||||
```
|
||||
|
||||
Проверяет, совпадает ли домен хотя бы с одним правилом.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| -------- | -------- | ----------------------------------- |
|
||||
| `domain` | `string` | Обязателен; домен для сопоставления |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| --------- | --------- | ------------------------------------ |
|
||||
| `matched` | `boolean` | `true` при совпадении, иначе `false` |
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
local matched = sitesObj:MatchAny("www.example.com")
|
||||
```
|
||||
|
||||
#### Match
|
||||
|
||||
```lua
|
||||
local indices = domainMatcherObj:Match(domain)
|
||||
```
|
||||
|
||||
Получает номера правил, с которыми совпал домен.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| -------- | -------- | ----------------------------------- |
|
||||
| `domain` | `string` | Обязателен; домен для сопоставления |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| --------- | ---------------------------------------------- | --------------------------------------------------------------------------- |
|
||||
| `indices` | [`[]uint32`](./data-types.md#uint32) или `nil` | Номера совпавших правил; при отсутствии совпадений — `nil` или срез длины 0 |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Номера правил начинаются с **0** и соответствуют порядку правил, переданных при создании. Порядок результатов не гарантируется; возможны повторяющиеся номера. Записи, развёрнутые из GeoSite, сохраняют номер исходного правила.
|
||||
|
||||
Если те же правила сохранены в массиве Lua, исходное правило можно получить через `rules[ruleNumber + 1]`. Доступ к срезам описан в разделе [Типы данных](./data-types.md#slice).
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
local indices = sitesObj:Match("www.example.com")
|
||||
if indices ~= nil then
|
||||
for i = 1, #indices do
|
||||
local ruleNumber = indices[i]
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### IPMatcher
|
||||
|
||||
| Свойство | Описание |
|
||||
| ------------------- | ------------------------------------------------------------------------------ |
|
||||
| Базовый тип Go | Реализация интерфейса `geodata.IPMatcher` |
|
||||
| Представление в Lua | `userdata` |
|
||||
| Получение | Возвращаемое значение [`geodata.BuildIPMatcher(...)`](#geodata-buildipmatcher) |
|
||||
|
||||
**Общие соглашения**
|
||||
|
||||
Для отдельного IP используется [`net.IP`](./data-types.md#net-ip); для сопоставления или фильтрации списков формы ввода описаны в разделе [Ввод списка IP](./data-types.md#ввод-списка-ip). Строки IP-адресов не преобразуются в `net.IP` автоматически.
|
||||
|
||||
Методы сопоставления и фильтрации принимают явно переданный `nil`. Отсутствие аргументов, неверный тип или число аргументов вызывают исключение Lua.
|
||||
|
||||
#### Match
|
||||
|
||||
```lua
|
||||
local matched = ipMatcherObj:Match(ip)
|
||||
```
|
||||
|
||||
Проверяет, совпадает ли отдельный IP с правилами.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| -------- | -------------------------------------------- | ------------------------------- |
|
||||
| `ip` | [`net.IP`](./data-types.md#net-ip) или `nil` | Обязателен; нужно передать явно |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| --------- | --------- | ------------------------------------------------------------------------- |
|
||||
| `matched` | `boolean` | `true`, если допустимый IP совпал; `false` для `nil` или недопустимого IP |
|
||||
|
||||
**Поведение**
|
||||
|
||||
`""` или пустая таблица `{}` трактуются как пустой IP и возвращают `false`. Строки не разбираются как текст IP-адреса.
|
||||
|
||||
#### AnyMatch
|
||||
|
||||
```lua
|
||||
local matched = ipMatcherObj:AnyMatch(ips)
|
||||
```
|
||||
|
||||
Проверяет, совпадает ли с правилами хотя бы один допустимый IP.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| -------- | ------------------------------------------------ | -------------------------------------------------- |
|
||||
| `ips` | [Ввод списка IP](./data-types.md#ввод-списка-ip) | Обязателен; нужно передать явно; допускается `nil` |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| --------- | --------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| `matched` | `boolean` | `true`, если совпал хотя бы один допустимый IP; `false` для `nil`, пустого списка или отсутствия совпадений |
|
||||
|
||||
#### Matches
|
||||
|
||||
```lua
|
||||
local matched = ipMatcherObj:Matches(ips)
|
||||
```
|
||||
|
||||
Проверяет, совпадает ли с правилами весь список IP.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| -------- | ------------------------------------------------ | -------------------------------------------------- |
|
||||
| `ips` | [Ввод списка IP](./data-types.md#ввод-списка-ip) | Обязателен; нужно передать явно; допускается `nil` |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| --------- | --------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| `matched` | `boolean` | `true`, если весь список удовлетворяет условиям; `false` для `nil`, пустого списка или списка с недопустимыми IP |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Сочетание правил может содержать несколько внутренних объектов сопоставления. Один внутренний объект должен сопоставить весь список.
|
||||
|
||||
Например, для `geodata.BuildIPMatcher("192.168.1.0/24", "geoip:us")` список с `192.168.1.1` и `8.8.8.8` даёт `false` у `Matches`: первый IP совпадает с пользовательским CIDR, второй — с `geoip:us`, но эти правила принадлежат разным внутренним объектам, и ни один не сопоставляет весь список.
|
||||
|
||||
Если нужно проверить лишь наличие совпавшего адреса, используйте [`AnyMatch`](#anymatch).
|
||||
|
||||
#### FilterIPs
|
||||
|
||||
```lua
|
||||
local matched, unmatched = ipMatcherObj:FilterIPs(ips)
|
||||
```
|
||||
|
||||
Разделяет допустимые IP на совпавшие и несовпавшие группы.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| -------- | ------------------------------------------------ | -------------------------------------------------- |
|
||||
| `ips` | [Ввод списка IP](./data-types.md#ввод-списка-ip) | Обязателен; нужно передать явно; допускается `nil` |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| ----------- | -------------------------------------- | -------------------------------- |
|
||||
| `matched` | [`[]net.IP`](./data-types.md#net-ip-1) | Совпавшие IP; никогда не `nil` |
|
||||
| `unmatched` | [`[]net.IP`](./data-types.md#net-ip-1) | Несовпавшие IP; никогда не `nil` |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Группа без результатов является пустым срезом. При передаче `nil`, пустого списка или только недопустимых IP обе группы — пустые срезы.
|
||||
|
||||
Недопустимые IP отбрасываются; порядок результатов не обязательно совпадает с порядком ввода.
|
||||
|
||||
#### SetReverse
|
||||
|
||||
```lua
|
||||
ipMatcherObj:SetReverse(reverse)
|
||||
```
|
||||
|
||||
Устанавливает флаг инверсии каждого внутреннего объекта сопоставления.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| --------- | --------- | ------------------------------------------------------- |
|
||||
| `reverse` | `boolean` | Обязателен; `true` включает инверсию, `false` отключает |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
Нет возвращаемых значений.
|
||||
|
||||
**Поведение**
|
||||
|
||||
`nil`, отсутствие аргумента или неверный тип вызывают исключение Lua. Операция заменяет прежний флаг инверсии каждого внутреннего объекта, включая флаги `!` из правил. Инверсия действует только на семейства адресов исходного правила и не сопоставляет недопустимые IP.
|
||||
|
||||
Установленное состояние инверсии сохраняется в текущем объекте сопоставления. Если последующие вызовы Hook повторно используют этот объект, изменённое состояние продолжает действовать. См. [Состояние в экземплярах пула](../guide/lifecycle.md#состояние-в-экземплярах-пула).
|
||||
|
||||
**Пример**
|
||||
|
||||
После инверсии `10.0.0.0/8` сопоставляются допустимые адреса IPv4 вне этого диапазона:
|
||||
|
||||
```lua
|
||||
local ipMatcherObj = geodata.BuildIPMatcher("10.0.0.0/8")
|
||||
ipMatcherObj:SetReverse(true)
|
||||
```
|
||||
|
||||
#### ToggleReverse
|
||||
|
||||
```lua
|
||||
ipMatcherObj:ToggleReverse()
|
||||
```
|
||||
|
||||
Переключает флаг инверсии каждого внутреннего объекта сопоставления.
|
||||
|
||||
**Параметры**
|
||||
|
||||
Дополнительных параметров нет.
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
Нет возвращаемых значений.
|
||||
|
||||
**Поведение**
|
||||
|
||||
Каждый внутренний объект в сочетании правил переключает собственный флаг инверсии. Результат не равнозначен логическому отрицанию всего сочетания.
|
||||
Новое состояние инверсии сохраняется в текущем объекте сопоставления. Если последующие вызовы Hook повторно используют этот объект, изменённое состояние продолжает действовать. См. [Состояние в экземплярах пула](../guide/lifecycle.md#состояние-в-экземплярах-пула).
|
||||
@@ -0,0 +1,69 @@
|
||||
# xray.log
|
||||
|
||||
Записывает сообщения в систему журналирования Xray.
|
||||
|
||||
```lua
|
||||
local log = require("xray.log")
|
||||
```
|
||||
|
||||
## Указатель API
|
||||
|
||||
| Категория | Член API | Описание |
|
||||
| --------- | ---------------------------------- | ------------------------ |
|
||||
| Функция | [`log.Debug(...)`](#log-debug) | Запись сообщения debug |
|
||||
| Функция | [`log.Info(...)`](#log-info) | Запись сообщения info |
|
||||
| Функция | [`log.Warning(...)`](#log-warning) | Запись сообщения warning |
|
||||
| Функция | [`log.Error(...)`](#log-error) | Запись сообщения error |
|
||||
|
||||
## Функции
|
||||
|
||||
### log.Debug
|
||||
|
||||
```lua
|
||||
log.Debug(...)
|
||||
```
|
||||
|
||||
Записывает сообщение уровня `debug`.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| -------- | ------------------ | ------------------------------------------------------------ |
|
||||
| `...` | Любое значение Lua | Необязательны; любое число значений, объединяемых по порядку |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
Нет возвращаемых значений.
|
||||
|
||||
**Преобразование аргументов**
|
||||
|
||||
Допускается вызов без аргументов, а также `nil`, `""`, `{}` и пустые срезы. Аргументы преобразуются в текст и объединяются по порядку без автоматической вставки пробелов или разделителей.
|
||||
|
||||
- Значения [`error`](./data-types.md#error) в первую очередь преобразуются в сообщения об ошибках.
|
||||
- Для остальных значений с функцией `__tostring` используется это преобразование; исключения из него передаются вызывающему коду.
|
||||
- Остальные значения используют строковое представление по умолчанию. `nil` становится `"nil"`, пустая строка не добавляет текст; таблицы и срезы не разворачиваются в списки элементов.
|
||||
|
||||
**Условия вывода**
|
||||
|
||||
Сообщения имеют префикс с именем файла вызывающего скрипта. Вывод зависит от [`log.loglevel`](../../../config/log.md#logobject). Например, при уровне `warning` функции `Debug` и `Info` ничего не выводят и не вызывают преобразование аргументов через `__tostring`.
|
||||
|
||||
Ни одна из четырёх функций не возвращает `err`. Если присвоить результат вызова переменной, она получит `nil`; по этому значению нельзя определить, было ли сообщение успешно записано.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
log.Info("Запрашиваемый домен: ", domain)
|
||||
log.Warning("Ошибка запроса к вышестоящему серверу: ", err)
|
||||
```
|
||||
|
||||
### log.Info
|
||||
|
||||
Как описано выше.
|
||||
|
||||
### log.Warning
|
||||
|
||||
Как описано выше.
|
||||
|
||||
### log.Error
|
||||
|
||||
Как описано выше.
|
||||
@@ -0,0 +1,119 @@
|
||||
# xray.router
|
||||
|
||||
Предоставляет константы и вспомогательные интерфейсы для [скриптов маршрутизации](../guide/routing.md). Параметры запроса и контекст описаны в [Hook маршрутизации](./hook-routing.md).
|
||||
|
||||
```lua
|
||||
local router = require("xray.router")
|
||||
```
|
||||
|
||||
## Указатель API
|
||||
|
||||
| Категория | Член API | Описание |
|
||||
| --------- | ---------------------------------------------------------- | ------------------------------------------------ |
|
||||
| Константа | [`router.NetworkUnknown`](#константы) | Неизвестная сеть |
|
||||
| Константа | [`router.NetworkTCP`](#константы) | TCP |
|
||||
| Константа | [`router.NetworkUDP`](#константы) | UDP |
|
||||
| Константа | [`router.NetworkUNIX`](#константы) | UNIX |
|
||||
| Константа | [`router.LocalOS`](#константы) | Платформа выполнения |
|
||||
| Функция | [`router:PickOutbound(balancerTag)`](#router-pickoutbound) | Выбор исходящего подключения через балансировщик |
|
||||
| Функция | [`router.FindProcess(ctx)`](#router-findprocess) | Поиск процесса локального соединения |
|
||||
|
||||
## Константы
|
||||
|
||||
| Имя | Тип | Значение / Описание |
|
||||
| ----------------------- | -------- | ---------------------------------------------------------------------------- |
|
||||
| `router.NetworkUnknown` | `number` | `0`, неизвестная сеть |
|
||||
| `router.NetworkTCP` | `number` | `2`, TCP |
|
||||
| `router.NetworkUDP` | `number` | `3`, UDP |
|
||||
| `router.NetworkUNIX` | `number` | `4`, UNIX |
|
||||
| `router.LocalOS` | `string` | Текущая платформа выполнения, например `"windows"`, `"linux"` или `"darwin"` |
|
||||
|
||||
Параметр `network` из [Hook маршрутизации](./hook-routing.md#handleroute) можно сравнивать с сетевыми константами:
|
||||
|
||||
```lua
|
||||
if network == router.NetworkUDP then
|
||||
return "direct", "lua-udp"
|
||||
end
|
||||
```
|
||||
|
||||
## Функции
|
||||
|
||||
### router:PickOutbound
|
||||
|
||||
```lua
|
||||
local outboundTag, err = router:PickOutbound(balancerTag)
|
||||
```
|
||||
|
||||
Выбирает исходящее подключение через указанный балансировщик.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| `balancerTag` | `string` | Значение `tag` нужного балансировщика, настроенного в [`routing.balancers`](../../../config/routing.md#balancerobject) |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| ------------- | ------------------------------------------ | ------------------------------------------------------------- |
|
||||
| `outboundTag` | `string` или `nil` | При успехе — непустой `tag` выбранного исходящего подключения |
|
||||
| `err` | [`error`](./data-types.md#error) или `nil` | `nil` означает успех |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Нужно явно передать строку, иначе возникает исключение Lua. Пустая строка `""` выполняет поиск по пустому `tag`.
|
||||
|
||||
Перед использованием результата проверьте `err`. Если балансировщик не существует, возвращается `nil, err`; если существует, но не выбрал исходящее подключение, — `"", err`. Когда срабатывает настроенный `fallbackTag`, возвращаются этот тег исходящего подключения и `nil`.
|
||||
|
||||
**Пример**
|
||||
|
||||
Ниже используется балансировщик с `tag` `"proxy-pool"`, а результат передаётся согласно [соглашению о возвращаемых значениях Hook маршрутизации](./hook-routing.md#возвращаемые-значения):
|
||||
|
||||
```lua
|
||||
local outboundTag, err = router:PickOutbound("proxy-pool")
|
||||
return outboundTag, "lua-balance", err
|
||||
```
|
||||
|
||||
Полный пример приведён в [руководстве по скриптам маршрутизации](../guide/routing.md#связь-с-конфигурациеи-маршрутизации).
|
||||
|
||||
### router.FindProcess
|
||||
|
||||
```lua
|
||||
local pid, name, path, err = router.FindProcess(ctx)
|
||||
```
|
||||
|
||||
Находит процесс на локальной машине, связанный с текущим соединением.
|
||||
|
||||
**Параметры**
|
||||
|
||||
| Параметр | Тип | Описание / Требования |
|
||||
| -------- | ------------------------------------------------------ | -------------------------------------------------------- |
|
||||
| `ctx` | [`routing.Context`](./hook-routing.md#routing-context) | Контекст текущего запроса, переданный Hook маршрутизации |
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
| Значение | Тип | Описание |
|
||||
| -------- | ------------------------------------------ | ------------------------------------------------ |
|
||||
| `pid` | `number` | ID процесса; обычно `0`, если не получен |
|
||||
| `name` | `string` | Имя процесса; `""`, если не получено |
|
||||
| `path` | `string` | Путь к исполняемому файлу; `""`, если не получен |
|
||||
| `err` | [`error`](./data-types.md#error) или `nil` | `nil` означает успех |
|
||||
|
||||
**Поведение**
|
||||
|
||||
Нужно явно передать допустимый контекст маршрутизации, иначе возникает исключение Lua. Если нет IP источника, тип сети не TCP/UDP, поиск не удался или платформа не поддерживается, возвращается ошибка.
|
||||
|
||||
`pid`, `name` и `path` никогда не равны `nil`, но при ошибке могут содержать частичные данные; перед использованием проверьте `err`. Если нет IP источника или тип сети не поддерживается, возвращается `0, "", "", err`; в остальных случаях результат платформенного поиска возвращается без изменений.
|
||||
|
||||
Поиск использует первый IP источника и порт источника. Если есть IP назначения, также передаются первый IP назначения и порт назначения. Точный способ сопоставления определяет платформенная реализация поиска.
|
||||
|
||||
Возможности поиска зависят от платформы и прав доступа. Windows, Linux и macOS имеют встроенные реализации. В Android среда выполнения должна зарегистрировать реализацию поиска; даже при успехе имя или путь могут отсутствовать. iOS и другие неподдерживаемые платформы возвращают ошибку.
|
||||
|
||||
**Пример**
|
||||
|
||||
```lua
|
||||
local pid, name, path, err = router.FindProcess(ctx)
|
||||
if err == nil and name == "curl" then
|
||||
return "direct", "lua-process"
|
||||
end
|
||||
```
|
||||
Reference in New Issue
Block a user