Files
XTLS_Xray-docs-next/docs/ru/development/lua/guide/routing.md
T

5.8 KiB

Скрипты маршрутизации

Когда скрипт указан через routing.script, выбор исходящего подключения передаётся функции Lua HandleRoute.

Минимальный пример

Следующий фрагмент конфигурации задаёт файл скрипта и настраивает исходящие подключения для прямого соединения и блокировки:

{
  "routing": {
    "script": "routing.lua"
  },
  "outbounds": [
    { "tag": "direct", "protocol": "freedom" },
    { "tag": "block", "protocol": "blackhole" }
  ]
}

Сохраните routing.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 исходящих подключений в конфигурации выше.

Этот фрагмент нужно объединить с полной конфигурацией. Правила поиска файла описаны в разделе Пути к файлам скриптов.

HandleRoute также может получать дополнительные параметры и возвращать имя правила и ошибку. Полное соглашение о вызове и поведение при ошибках описаны в HandleRoute.

Связь с конфигурацией маршрутизации

При включении скрипта маршрутизации rules и domainStrategy не действуют. Если скрипт не выбрал исходящее подключение или возникла ошибка, встроенные правила маршрутизации также не проверяются.

Настройка balancers остаётся доступной. Скрипт выбирает исходящее подключение через router:PickOutbound:

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-адреса назначения запроса. При необходимости он явно разрешает домен и выбирает исходящее подключение по диапазонам частных адресов.

{
  "dns": {
    "tag": "dns-query",
    "servers": ["1.1.1.1"]
  },
  "routing": {
    "script": "routing.lua"
  },
  "outbounds": [
    { "tag": "direct", "protocol": "freedom" },
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        // ...
      }
    }
  ]
}
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; при необходимости измените это поведение согласно своей политике.

Инициализация верхнего уровня и сохранение состояния скриптов маршрутизации описаны в разделе Жизненный цикл пула.