Сценарии

Общие сведения о Сценариях

Сценарии – это Lua-файлы, являющиеся дополнением к основным параметрам конфигурации Виртуальных Серверов.

Сценарии предназначены для:

  • выбора Сервера Балансировки: распределения клиентских запросов по нескольким Серверам Балансировки на основе данных в запросе;

  • изменения содержимого запросов (HTTPS/HTTPS);

  • ответа на запрос (HTTP/HTTPS);

  • прерывания нежелательного соединения.

В Сценариях можно определять условия выполнения того или иного действия логическими выражениями:

  • if;

  • elseif;

  • else;

  • end.

Условиями для логических выражений могут быть любые данные, полученные из запроса, а также комбинация эти данных, например:

  • выражение для сравнения имени хоста из запроса с именем abc.ru для выполнения какого-либо действия:

if client.http_req.host == "abc.ru” then
  • выражение для сравнения имени хоста из запроса с именем abc.ru и принадлежностью к определенному IP-адресу:

if (client.http_req.host == "abc.ru” and client.remote_p.ip == "192.0.2.1")

Для работы с полученными данными можно использовать возможности языка программирования Lua. Примеры выражений для обработки запроса вида qwe.123.ru/abczxc:

  • выражение сравнения. Результатом будет true:

if client.http_req.path == "/abcZxc"
  • выражение содержания определенного значения. Результатом будет true:

if (client.http_req.path:find(”zx"))
  • выражение для получения определенной части строки. Результатом будет qwe:

(client.http_req.host:match(”(.*).123.ru")

Обработка правил Сценария осуществляется через глобальную переменную client, которая содержит в себе ряд полей. Описание полей приведено в таблице (см. Описание полей структуры client).

Обработка правил Сценария останавливается после выражения: client.action = “xxx”.
Таблица 1. Описание полей структуры client
Поле Тип поля Описание

client.remote_p

Структура

Содержит поля удаленной точки подключения, где:

  • remote_p.ip (строка) – возвращает IP-адрес соединения;

  • remote_p.port (целое) – возвращает порт соединения;

  • remote_p:is_network(VAR) (метод) – осуществляет проверку, является ли IP-адрес частью сети, задаваемой в переменной VAR вида {IP}/{PREFIX}:

if client.remote_p:is_network("127.0.0.1/24") then
...
end

client.local_p

Структура

Содержит поля локальной точки подключения, аналогично remote_p

client.http_req

Структура или nil

В текущей версии Termidesk Connect значение nil для балансировки уровня L7 вернуться не может.

Содержит поля HTTP-запроса или возвращает значение nil (HTTP-запросотсутствует). Описание полей приведено в таблице (см. Описание полей структуры http_req).

client.http_resp

Структура

Содержит поля для работы с HTTP-ответом (используется в Сценариях модификации ответов).

Пример:

  • client.http_resp.header – работа с заголовком в HTTP-ответе;

  • client.http_resp.status – возвращает код HTTP-ответа

client.bs

Строка

Определяет имя Сервера Балансировки.

Пример:

client.bs = "lb1"

client.respond.status

Целое

Возвращает код ответа

client.action

Строка

Определяет действие:

  • client.action = "bs" – возвращает Сервер Балансировки, определенный в client.bs;

  • client.action = "respond" – возвращает ответ клиенту, не передавая запрос на Реальный Сервер. Содержимое ответа описывается в client.respond.status;

  • client.action = "drop" – сбрасывает соединение;

  • client.action = "pass" – используется в скриптах для модификации ответов;

  • client.action = "auth" – останавливает обработку для аутентификации пользователя

client:bs_state

Строка

Возвращает статус Сервера Балансировки: client:bs_state("ws1")

client.rs

Строка

Возвращает данные Реального Сервера.

Пример:

  • client.rs.ip - возвращает IP-адрес Реального Сервера;

  • client.rs.port - возвращает порт Реального Сервера

Таблица 2. Описание полей структуры http_req
Поле Тип поля Описание

http_req.version

Целое

Возвращает версию протокола HTTP: целое число, в котором младший десяток соответствует значению после точки, старший десяток - перед точкой.

Поддерживаются версии: 1.0, 1.1.

Пример:

для HTTP/1.0 будет возвращен ответ: 10

http_req.method

Строка

Возвращает метод запроса (GET, POST, HEAD, DELETE, PATCH, PUT, OPTIONS, CONNECT, TRACE и др.).

В примере ниже: GET

http_req.path

Строка

Возвращает путь запроса.

В примере ниже: termideskconnect

http_req.query

Строка

Возвращает запрос.

В примере ниже: test=query

http_req.path_and_query

Строка

Возвращает полный путь запроса.

В примере ниже: termideskconnect?test=query

http_req.host

Строка

Возвращает значение заголовка Host.

В примере ниже: connect.termidesk.ru

http_req.headers

Таблица (словарь)

Возвращает все заголовки со значениями.

В примере ниже:

Host: connect.termidesk.ru
User-Agent: Mozilla Firefox/3.0.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cookie: sessionid=100TC

http_req.body

Строка

Возвращает тело HTTP-запроса

Примеры из таблицы отражены в этом ответе на запрос к узлу termideskconnect по протоколу HTTP:

GET /termideskconnect?test=query HTTP/1.0
Host: connect.termidesk.ru
User-Agent: Mozilla Firefox/3.0.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cookie: sessionid=100TC

Добавление Сценария

Добавление Сценария выполняется одним из способов:

  • из интерфейса командной строки Termidesk Connect;

  • из веб-интерфейса Termidesk Connect (см. подраздел Веб. Сценарии).

Пример команды с указанием порядка исполнения и имени файла Сценария:

set vs HTTP <имя> luarules 5 script test.lua

Файлы должны располагаться:

  • Сценарии балансировки в каталоге /var/lib/tdc/lbscripts/content-switching/;

  • Сценарии генерации ответов в каталоге /var/lib/tdc/lbscripts/error-reply/;

  • Сценарии модификации ответов в каталоге /var/lib/tdc/lbscripts/response-modifying/.

Порядковый номер определяет очередность выполнения файла Сценария: например, Сценарий с порядковым номером 10 будет исполнен раньше, чем Сценарий с порядковым номером 15.

При этом правила в файлах Сценариев также обрабатываются по порядку:

  • сначала правила из файла Сценария с наименьшим порядковым номером;

  • затем правила из файла Сценария со следующим порядковым номером, если не было совпадений.

Правила Сценария могут располагаться как в одном файле, так и в нескольких.

Примеры Сценариев для изменения содержимого запросов

Пример 1. Если имя хоста содержит текст «abc» и запрос пришел из сети 192.0.2.0/24, то добавить заголовок «XFF: <IP-адрес_пользователя_при_подключении>», и перенаправить запрос на Сервер Балансировки «lb1».

Код:

if (client.http_req.host:find("abc") and client.remote_p:is_network("192.0.2.0/24")) then
        client.http_req.header:field_set("XFF", client.remote_p.ip)
        client.bs = "lb1"
        client.action = "bs"
end

Результат:

WEB -- 03<p>Method GET</p><p>URL on server: /</p><p>REQ
Headers: </p>Host: abc.domain.ru
User-Agent: curl/7.81.0
Accept: */*
XFF: 192.0.2.5

Пример 2. Если имя хоста начинается с «abc», то добавить заголовок «XFF: <IP-адрес_пользователя_при_подключении>» и «Remote-port: <порт-источник_на_клиенте>», и перенаправить запрос на Сервер Балансировки «lb1».

Код:

function startswith(text, prefix)
  return text:find(prefix, 1, true) == 1
end

if startswith(client.http_req.host, "abc") then
  client.http_req.header:field_set("Remote-port", client.remote_p.port)
  client.http_req.header:field_set("XFF", client.remote_p.ip)
  client.bs = "lb1"
  client.action = "bs"
end

Пример 3. Если путь запроса содержит «app», то при наличии заголовка X-Forwarded-For добавить IP-адрес клиента в конец запроса. Если заголовка не было в запросе, то добавить новый. Перенаправить запрос на Сервер Балансировки «lb1».

Код:

if client.http_req.path:find("abc") then
        if client.http_req.header:field_count("X-Forwarded-For") > 0 then
                xff, xffip = client.http_req.header:field_get("X-Forwarded-For")
                client.http_req.header:field_set("X-Forwarded-For", xffip ..", "..client.remote_p.ip)
        else
                client.http_req.header:field_set("X-Forwarded-For", client.remote_p.ip)
        end
client.bs = "lb1"
client.action = "bs"

end

Пример 4. Подменить домен «ru» на домен «local» (например, если запрос идет к app.domain.ru, то в сторону Реального Сервера должен прийти app.domain.local). В начале пути запроса добавить «/external» и перенаправить запрос на Сервер Балансировки «lb1».

Код:

client.http_req.host =  client.http_req.host:match("(.*).ru") .. ".local"
client.http_req.path = "/external" .. client.http_req.path
client.bs = "lb1"
client.action = "bs"

Примеры Сценариев для ответа на запрос

Пример 1. Если метод не GET или не HEAD, то сбросить соединение.

Код:

if (client.http_req.method ~= "GET" and client.http_req.method ~= "HEAD") then
    client.action = "drop"
end

Пример 2. Перенаправить соединение с HTTP на HTTPS.

Код:

client.respond.status = 302
client.respond.header["Location"] = "https://" .. client.http_req.host .. client.http_req.path
client.respond.header["Connection"] = "close"
client.action = "respond"

Пример 3. Если запрос из сети 192.0.2.0/24, то ответить HTML-страницей и параметрами запроса.

Код:

if client.remote_p:is_network("192.0.2.0/24") then
    client.respond.header["Connection"] = "close"
    client.respond.header["Content-type"] = 'text/html
    client.respond.body = [[<html>
    <body>
    <meta charset="UTF-8">
    <h1>Lets goodbye!</h1>
    <p>Доступ запрещен</p>
    </body>
    </html>]] .. "IP: " .. client.remote_p.ip .. "\n TRY: " .. client.http_req.host .. client.http_req.path .. "\n" ..      " Vserver: " .. client.local_p.ip .. ":" .. client.local_p.port
client.action = 'respond'

Примеры Сценариев для выбора Сервера Балансировки

Пример 1. Передача любого запроса на Сервер Балансировки «lb1».

Код:

client.bs = "lb1"
client.action = "bs"

Пример 2. Если имя хоста в запросе точно соответствует «abc.domain.ru», то направить запрос на Сервер Балансировки «lb1». В противном случае вернуть код ответа 403 (по умолчанию вернется ошибка 503).

Код:

if client.http_req.host == "abc.domain.ru" then
        client.bs = "lb1"
        client.action = "bs"
else
        client.respond.status = 403
        client.action = "respond"
end

Пример 3. Если имя хоста содержит текст «abc» и запрос пришел из сети 192.0.2.0/24, то вернуть Сервер Балансировки «lb1». В противном случае вернуть код ответа 403 (по умолчанию вернется ошибка 503).

Код:

if (client.http_req.host:find("abc") and client.remote_p:is_network("192.0.2.0/24"))
then
        client.bs = "lb1"
        client.action = "bs"
else
        client.respond.status = 403
        client.action = "respond"
end

Пример 4. Если путь содержит:

  • «red», то вернуть Сервер Балансировки «lb1»;

  • «green», то вернуть Сервер Балансировки «lb2».

Если не сработало ни одно из условий выше, то вернуть Сервер Балансировки «lb-default».

Код:

if client.http_req.path:find("red") then
        client.bs = "lb1"
        client.action = "bs"
elseif client.http_req.path:find("green") then
        client.bs = "lb2"
        client.action = "bs"
else
        client.bs = "lb-default"
        client.action = "bs"
end