Правила Content Switch¶
Введение¶
Правила Content Switch — это простые логические выражения, например:
$header["User-Agent"] ~= "Chrome"
($method == POST and ($header["token"] == "some_text" or (is_set($content_length) and $content_length >= 13))) or
($method == GET and $path ~= "/temp/")
Правила состоят из:
Констант
Функций
Логических выражений
Скобок
Функции не имеют приоритета и выполняются слева направо (если функция должна быть выполнена).
Если переменная, используемая в функции, не определена в запросе, функция немедленно возвращает false.
Например, правило $header["User-Agent"] ~= "Chrome" вернёт false, если заголовок User-Agent не установлен.
Правила обрабатываются в порядке возрастания ID. Правило срабатывает, если:
Правило возвращает
trueВсе предыдущие правила (с меньшими ID) вернули
false
Константы¶
Константы — это значения, определённые напрямую в правиле. Они могут быть:
Строки
Синтаксис строк похож на Python: они заключаются в двойные или одинарные кавычки.
"some 'text' string"
'some "text" string'
Строки — это массивы байтов и могут содержать любые двоичные данные, включая нулевые байты. Поддерживаются стандартные последовательности экранирования:
\r– возврат каретки (13)\n– символ новой строки (10)\t– табуляция (9)\0– нулевой байт\xFF– шестнадцатеричный код (FF — это байт в шестнадцатеричной системе)\!– заменяет вертикальную черту|(которая не допускается в правилах)\\– одинарная обратная косая черта
Примечание
Завершающий ноль не добавляется в конец строки, если используются двоичные данные.
Числа
Числа записываются напрямую:
1234567890
-123
0xdeadbeef
0xBABADEDA
Булевы значения
true
false
IP-адреса
192.168.1.1
10.13.13.1
Подсети
192.168.0.0/16
10.10.10.10/32
10.0.0.0/8
Подсети проверяются при добавлении правила.
Примечание
В HTTP CS выражение $client_addr == 192.168.1.1 работает как ожидается. В L4 TCP CS то же выражение не поддерживается — необходимо указывать адрес вместе с маской (длиной префикса).
Метод
Это значения, которые принимает переменная $method. Они записываются просто как ключевое слово, без кавычек:
$method == POST or $method == PUT
$method поддерживает стандартные методы HTTP:
GET, POST, DELETE, HEAD, PUT, CONNECT, OPTIONS, TRACE,
COPY, LOCK, MKCOL, MOVE, PROPFIND, PROPPATCH, SEARCH,
UNLOCK, BIND, REBIND, UNBIND, ACL, REPORT, MKACTIVITY,
CHECKOUT, MERGE, MSEARCH, NOTIFY, SUBSCRIBE, UNSUBSCRIBE,
PATCH, PURGE, MKCALENDAR, LINK, UNLINK
Выражения¶
Существует две формы выражений:
Функциональная форма — вызов функции с параметрами в скобках, разделёнными запятыми:
contains(10.13.0.0/24, $client_addr)Форма оператора — операция между двумя значениями, например:
$path== "/some_path/"
Выражения всегда возвращают true или false и не поддерживают вложенность.
Некоторые выражения имеют одинаковое имя, но принимают разные наборы параметров. Таблица ниже показывает необязательные параметры в квадратных скобках ([]).
Функция |
Оператор |
Описание |
|---|---|---|
|
Проверка на равенство / неравенство / регистронезависимое равенство |
|
|
Сравнение чисел |
|
|
|
Проверяет, содержится ли подстрока в строке или IP-адрес в подсети.
|
|
|
Проверяет, соответствует ли
|
|
|
Проверяет, начинается ли строка
|
|
Проверяет, определена ли переменная или элемент массива |
Детали и примеры функций¶
Равенство¶
Проверяет, равны ли два значения (==):
$path == "/some_path/"
Для проверки равенства без учёта регистра используйте =^=.
Для проверки неравенства используйте !=:
$path != "/"
Вы можете сравнивать значения разных типов. Например:
192.168.1.1 == "\x0C\xAB\x00\x00" # returns true
Сравнение¶
Для сравнения используйте стандартные операции: <, >, <=, >=
Например:
$content_length >= 100
Проверка включения¶
Проверяет, содержит ли одна строка другую, или принадлежит ли IP-адрес подсети:
contains(<haystack>, <needle>[, offset, max_length][, ic])
где:
offset— Используется только с$body. Этот параметр задает смещение в байтах от начала данных, с которого должна начаться проверка. Он позволяет пропустить начало содержимого, если оно неактуально. По умолчанию 0.max_length— Используется только с$body. Параметрmax_lengthопределяет максимальное количество байтов для анализа во время проверки. Этот параметр важен, так как он напрямую влияет на использование памяти. Например, еслиmax_lengthустановлен наN, будут проанализированы только первыеNбайт тела.max_lengthособенно полезен, когда$bodyможет содержать большие объемы данных. По умолчанию не ограничено.ic— логическое значение. Если установлено вtrue, включает регистронезависимое сопоставление (например,Helloбудет совпадать сhello). Если установлено вfalse, сопоставление чувствительно к регистру. По умолчаниюfalse.
Примеры
$header["haystack"] ~= "needle"
$client_addr ~= 10.13.0.0/24
contains($header["haystack"], "needle")
contains($body, "value", 100, 50)
contains(10.13.0.0/24, $client_addr)
Проверка префикса¶
Используйте starts_with() или .= (для регистронезависимой проверки — ^=).
Проверяет, начинается ли одна строка с другой. Эта функция позволяет проверить, что в начале данных присутствует определённый префикс.
Примеры
starts_with($body, "error")
$body .= "error"
$body .^= "ololo"
Регулярное выражение¶
Используйте matches() или %= (для регистронезависимой проверки — %^=)
Проверяет, соответствует ли строка или бинарные данные регулярному выражению. Это частичное соответствие — если вы хотите, чтобы вся строка соответствовала, используйте ^ и $.
matches(<data>, <regex>[, <offset>, <max_len>][, <ic>])
offset— Используется только с$body. Смещение в байтах от начала данных перед сопоставлением с регулярным выражением. По умолчанию 0.max_length— Используется только с$body. Параметрmax_lengthопределяет максимальное количество байтов для проверки регулярным выражением. Этот параметр важен, так как он напрямую влияет на использование памяти. Если вы установитеmax_lengthвN, то будут проверены только первыеNбайтов тела. Это особенно полезно, когда$bodyможет содержать большие объемы данных. По умолчанию 128. При использовании этой функции с данными, отличными от$body, ограничений по длине нет.ic— Логическое значение. Если установлено вtrue, включает регистронезависимое сопоставление (например,Helloбудет совпадать сhello). Если установлено вfalse, сопоставление чувствительно к регистру. По умолчаниюfalse.
Пример
matches($body, "some_string") # проверка первых 128 байт
$body %= "some_string"
matches($body, "some_string", 0, 1024) # проверка первых 1024 байт
matches($body, "some_string", 100, 1024) # начиная с 100-го байта
matches($body, "some_string", 0, 1024, true) # без учета регистра
matches($body, "some_string", true) # сокращенная форма: 128 байт, без учета регистра
$body %^= "some_string"
Движок регулярных выражений использует расширенный стандарт POSIX (ERE) в однострочном режиме, то есть:
Escape-последовательности
\d,\w,\sи их отрицания (\D,\W,\S) не поддерживаются. Используйте классы символов:[[:digit:]],[[:alnum:]],[[:space:]]их отрицания:
[[:^digit:]],[[:^alnum:]],[[:^space:]][0-9]для цифр
Точка
.соответствует любому символу кроме символа новой строки (\n). Используйте шаблон(.|[\n]), чтобы включить символы новой строки.Ленивые квантификаторы (
*?,+?,??,{n,m}?) не поддерживаются. Все квантификаторы жадные и будут захватывать максимально возможное количество символов.Анкоры
^и$совпадают с началом и концом всей входной строки, а не отдельных строк.Помните, что специальные символы в строках нужно экранировать дважды. Например, для поиска символа точки, напишите
"\\.".Включите оба символа
^и$в ваш шаблон, чтобы обеспечить полное совпадение строки. По умолчанию проверка ищет только частичное совпадение, а не точное. Например, если строка должна быть числом, используйте выражение^[0-9]+$. Использование[0-9]+вместо этого будет проверять, содержит ли строка число — что эквивалентно^.*[0-9]+.*$.
Важно
Проверки регулярных выражений относительно ресурсоёмки. Используйте их только при необходимости и устанавливайте max_length на минимально необходимое значение.
Проверка существования¶
Особая функция, которая проверяет, определена ли переменная или элемент массива. Применяется к $body, заголовкам, куки и $content_length.
Логические выражения¶
Логические операции:
notили!логическое НЕandили&&логическое Иorлогическое ИЛИ
Оператор NOT может быть размещён перед скобками или функциями:
!is_set($header["foo"])
!($client_addr == 192.168.1.1)
!($header["user-agent"] ~= "Chrome" or $header["user-agent"] ~= "Opera")
Последний пример вернёт true, если клиент не использует ни один из перечисленных браузеров.
Операторы AND и OR располагаются между функциями или группированными выражениями:
!($header["user-agent"] ~= "Chrome") or $client_addr == 192.168.1.1
Правило вернёт true, если браузер не Chrome или если IP-адрес клиента — 192.168.1.1 (независимо от браузера).
Группировка логических выражений¶
Скобки — синтаксические элементы, используемые для группировки логических выражений и контроля порядка их вычисления.
Используйте скобки для группировки логических операций:
($method == POST and ($header["token"] == "some_text" or (is_set($content_length) and $content_length >= 13))) or
($method == GET and $path ~= "/temp/")
Правило срабатывает в любом из следующих случаев:
$method == POSTи$header["token"] == "some_text"$method == POSTи$content_length >= 13$method == GETи$path ~= "/temp/"
Функции не имеют приоритета и выполняются слева направо. Это означает, что проверка $path ~= "/temp/" будет выполнена, только если все предыдущие условия ложны. Например, если $method == GET равен false (например, метод запроса не является GET), проверка подстроки в $path не будет выполнена.
Имейте это в виду при написании правил: сопоставление подстрок является относительно ресурсоёмкой операцией и должно находиться в конце выражения, если это возможно.