Дополнительные соответствия
Кроме описанных в предыдущих статьях условий соответствия, поддерживаемых современной версией iptables, существует ряд дополнительных условий соответствия, которые могут не поддерживаться версиями iptables, установленными из бинарных файлов. Чтобы сделать доступным то или иное условие, скомпилируйте iptables самостоятельно из исходных текстов, которые можно загрузить с сайта www.iptables.org . В некоторых случаях может также потребоваться загрузка исходного кода дополнительных модулей, которые можно найти на сайте www.netfilter.org .
Соответствие condition
Этот модуль позволяет проверять соответствие пакетов условиям, записанным в переменные, которые хранятся в файлах /proc. Для работы с функциями этого модуля в строке спецификации правил должна присутствовать команда -m condition.
К поддерживаемым этим модулем условиям предъявляется ряд требований:
-
условия должны храниться в файлах каталога /proc/net/ipt_condition/;
-
переменные условий могут принимать только логические значения FALSE (0) и TRUE (1);
-
каждая переменная может влиять на состояние одного или нескольких условий;
-
файл условий создается автоматически при первом упоминании нового условия;
-
файл условий автоматически удаляется после удаления последней ссылки на соответствующее условие.
Модуль использует единственную опцию
--condition [!] conditionfile
которая позволяет проверить соответствие условий для пакета переменной в файле conditionfile. Например, для запрета доступа к web-серверу на время его обслуживания можно воспользоваться командой
iptables -A FORWARD -p tcp -d 192.168.1.10 --dport http -m condition --condition webdown -j REJECT --reject-with tcp-reset
указав значение TRUE в файле условия с помощью команды
echo 1 > /proc/net/ipt_condition/webdown
Пока в файле /proc/net/ipt_condition/webdown будет записано значение 1, доступ к web-серверу будет заблокирован.
Соответствие fuzzy
Модуль fuzzy позволяет проверять соответствие пакетов динамическим профилям, реализованным с помощью простого контроллера FLC (Fuzzy Logic Controller).
Это соответствие проверяется на основе метода TSK FLC (Takagi-Sugeno-Kang Fuzzy Logic Controller), определяющего результат проверки в зависимости от скорости доставки пакетов с учетом значений нижнего и верхнего порога скорости; указанных правилом:
-
пока скорость доставки пакетов не достигает нижнего порога, условие никогда не будет выполняться;
-
при скорости в диапазоне между нижним и верхним порогами частота выполнения условий будет расти пропорционально скорости доставки пакетов;
-
после превышения верхнего порога скорости частота выполнения условий достигнет максимального значения - 99%.
При использовании модуля в строке спецификации должна явно присутствовать команда его загрузки
-m fuzzy
Модуль поддерживает 2 параметра, определяющих верхний и нижний пределы скорости
--lower-limit n
нижний предел по достижении которого условие начинает выполняться с вероятностью, пропорциональной скорости получения пакетов;
--upper-limit n
верхний предел, после превышения условие выполняется с вероятностью 99%.
С учетом условий работы современных сетей и достаточно высокой загрузки межсетевого экрана приведенное ниже правило должно хорошо работать в условиях атак на службы (Denials Of Service).
iptables -A INPUT -m fuzzy --lower-limit 100 --upper-limit 1000 -j REJECT
Правило будет работать следующим образом
-
при скорости менее 100 пак/с условие не будет выполняться и пакеты будут беспрепятственно приниматься хостом;
-
при скоростях от 100 до 1000 пак/с вероятность принятия пакетов будет снижаться от 100% (при скорости 100 пак/с) до 1% (при скорости 1000 пак/с).
-
при скоростях более 1000 хост будет принимать только 1% адресованных ему пакетов.
Соответствие iplimit
Модуль iplimit позволяет ограничить число одновременных соединений TCP для одного хоста или сети. Для работы с модулем спецификация правила должна содержать команду -m iplimit. Модуль поддерживает 2 опции:
[!] --iplimit-above n
задает порог числа одновременных соединений TCP. Опция может использоваться со знаком инверсии.
--iplimit-mask n
указывает маску для группы хостов (подсети).
Например, если вы хотите каждому клиенту ограничить до 4 число одновременных соединений HTTP с данным хостом, можно использовать правило:
iptables -A INPUT -p tcp --syn --dport http -m iplimit --iplimit-above 4 -j REJECT
Если после ввода правила воспользоваться командой iptables -L, на экран будет выведено:
Chain INPUT (policy ACCEPT)
target prot opt source destination
REJECT tcp -- anywhere anywhere tcp dpt:http flags:SYN,RST,ACK/SYN #conn/32 > 4 reject-with icmp-port-unreachable
Обратите внимание, что ни в команде спецификации правила, ни в выводе результатов не присутствует адрес отправителя. Это правило действует для ограничения числа соединений любого хоста. Можно также ограничить число соединений для всех хостов сети, заданной значением маски. Например, команда:
iptables -A INPUT -p tcp --syn --dport http -m iplimit --iplimit-mask 8 --iplimit-above 4 -j REJECT
будет позволять не более 4 соединений с портом HTTP для всех хостов любой сети класса A. Результат использования этой команды показан ниже:
Chain INPUT (policy ACCEPT)
target prot opt source destination
REJECT tcp -- anywhere anywhere tcp dpt:http flags:SYN,RST,ACK/SYN #conn/8 > 4 reject-with icmp-port-unreachable
Соответствие ipv4options
Модуль ipv4options позволяет проверять соответствие пакетов заданному набору опций IP. Для работы с модулем в спецификации правила должна присутствовать команда загрузки модуля -m ipv4options. Модуль поддерживает несколько опций:
--ssrr
проверяет соответствие флага strict source routing;
--lsrr
проверяет соответствие флага loose source routing;
--no-srr
проверяет отсутствие флагов source routing;
[!] --rr
проверяет наличие или отсутствие флага record route;
[!] --ts
проверяет наличие или отсутствие флага timestamp;
[!] --ra
проверяет значение опции router-alert;
[!] --any-opt
проверяет наличие или отсутствие в заголовке IP хотя бы одной опции.
Например, для отбрасывания всех пакетов с установленными опциями record-route и timestamp можно использовать команды:
iptables -A INPUT -m ipv4options --rr -j DROP
iptables -A INPUT -m ipv4options --ts -j DROP
Если после этих команд посмотреть список правил с помощью команды -L, вы увидите:
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all -- anywhere anywhere IPV4OPTS RR
DROP all -- anywhere anywhere IPV4OPTS TS
Соответствие nth
Модуль nth позволяет создавать правила, которым будет соответствовать каждый N-й пакет, удовлетворяющий остальным условиям данного правила. Для работы с этим модулем в правилах должна присутствовать команда -m nth. Модуль поддерживает 4 опции:
--every N
указывает, что условий будет соответствовать каждый N-й пакет;
[--counter] num
задает номер используемого правилом счетчика. Модуль поддерживает до 16 счетчиков с номерами от 0 до 15. По умолчанию используется счетчик 0.
[--start] num
указывает начало отсчета для счетчика пакетов. Этот параметр может принимать значения от 0 до N-1;
[--packet] num
задает номер пакета, для которого выполняются условия. Параметр может принимать значения от 0 до N-1.
Например, для отбрасывания каждого второго запроса packets вы можете воспользоваться командой:
iptables -A INPUT -p icmp --icmp-type echo-request -m nth --every 2 -j DROP
Этот модуль может быть очень эффективен для распределения нагрузки между несколькими входящими или исходящими каналами, а также для распределения нагрузки на серверы. Например, для распределения трафика между 3 адресами 10.0.0.5, 10.0.0.6 и 10.0.0.7 можно воспользоваться правилами:
iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 --every 3 --packet 0 -j SNAT --to-source 10.0.0.5
iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 --every 3 --packet 1 -j SNAT --to-source 10.0.0.6
iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 --every 3 --packet 2 -j SNAT --to-source 10.0.0.7
Если вы после этого воспользуетесь командой iptables -L, на экран будут выведено
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT all -- anywhere anywhere every 3th packet #0 to:10.0.0.5
SNAT all -- anywhere anywhere every 3th packet #1 to:10.0.0.6
SNAT all -- anywhere anywhere every 3th packet #2 to:10.0.0.7
Соответствие psd
Модуль psd обеспечивает поддержку функций обнаружения сканирования портов. Для использования модуля в строке спецификации правила должна присутствовать команда -m psd. Модуль поддерживает опции:
[--psd-weight-threshold threshold]
пороговый уровень “веса” при сканировании портов.
[--psd-delay-threshold delay]
пороговый уровень задержки при обнаружении попыток сканирования.
[--psd-lo-ports-weight lo]
“вес” для привилегированных портов.
[--psd-hi-ports-weight hi]
“вес” для портов со старшими номерами.
Если вы создадите правило:
iptables -A INPUT -m psd -j DROP
а потом воспользуетесь командой iptables –list, вы увидите в цепочке INPUT условия детектирования попыток сканирования портов:
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all -- anywhere anywhere psd weight-threshold: 21 delay-threshold: 300 lo-ports-weight: 3 hi-ports-weight: 1
Соответствие quota
Этот модуль позволяет задавать количественные ограничения (квоты), по достижении которых условие перестает выполняться. Для использования модуля в строке спецификации правила должна присутствовать команда -m quota. Модуль поддерживает единственную опцию:
--quota quota
которая задает количественное значение, по достижении которого условие перестает выполняться.
Команды
iptables -A INPUT -p tcp --dport 80 -m quota --quota 52428800 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j DROP
позволяют ограничить входящий трафик HTTP значением 50 Мбайт. Если вы после этих команд воспользуетесь командой просмотра правил, то увидите цепочки
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:http quota: 52428800 bytes
DROP tcp -- anywhere anywhere tcp dpt:http
Таким образом, весь входящий трафик HTTP будет отбрасываться после приема первых 50 Мбайт.
Соответствие random
Этот модуль позволяет устанавливать для пакетов соответствие на основе случайных (вероятностных) значений. Для работы с модулем спецификация правила должна содержать команду -m random. Модуль использует единственную опцию:
[--average percent]
определяющую процент пакетов, которые будут соответствовать данному правилу. Целочисленное значение опции может лежать в диапазоне от 1 до 99. По умолчанию уровень соответствия составляет 50%.
Например, для случайного отбрасывания половины пакетов ping можно воспользоваться правилом:
iptables -A INPUT -p icmp --icmp-type echo-request -m random --average 50 -j DROP
Если после этого вы воспользуетесь командой iptables –list, можно будет увидеть, что 50% случайно выбранных пакетов icmp echo-request будут отброшены
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP icmp -- anywhere anywhere icmp echo-request random 50%
Соответствие realm
Этот модуль позволяет проверять в пакетах значение маршрутного ключа realm. Для работы с модулем спецификация правила должна содержать команду -m realm. Модуль использует единственную опцию:
--realm [!] value[/mask]
-> Match realm
Например, для записи в журнал информации обо всех исходящих пакетах со значением realm = 10 вы можете использовать правило:
iptables -A OUTPUT -m realm --realm 10 -j LOG
Если вы после этого воспользуетесь командой iptables –list, то увидите в цепочке правило
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
LOG all -- anywhere anywhere REALM match 0xa LOG level warning
Для использования модуля при компиляции ядра должна быть включена опция. Если для опции ядра было выбрано значение M, потребуется также загрузка модуля ядра ipt_realm.
Соответствие record_rpc
Модуль record_rpc позволяет проверить был ли порт запрошен ранее отправителем пакета с помощью portmapper или это новый запрос GET к portmapper. Использование модуля может обеспечить эффективную фильтрацию RPC. Не забывайте указывать в строке спецификации правила команду загрузки модуля -m record_rpc.
Для записи информации о соединениях RPC достаточно использовать команду:
iptables -A INPUT -m record_rpc -j ACCEPT
Если вы после этого посмотрите список правил с помощью команды iptables --list
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere
то увидите, что сам модуль record_rpc не выполняет по отношению к пакету никаких действий. Отсутствие вывода от данного модуля объясняется тем, что функция print() просто ничего не делает:
/* Prints out the union ipt_matchinfo. */
static void
print(const struct ipt_ip *ip,
const struct ipt_entry_match *match,
int numeric)
{
}
Соответствие string
Этот модуль позволяет находить текстовые строки в любом месте пакетов(контекстный поиск). Для работы с модулем в строке спецификации правила следует указывать команду -m string. Модуль использует единственную опцию:
--string [!] string
для проверки наличия в пакете заданного фрагмента текста.
Например, для обнаружения пакетов, содержащих текст cmd.exe с целью их передачи в очередь системы IDS вы можете воспользоваться командой:
iptables -A INPUT -m string --string 'cmd.exe' -j QUEUE
При использовании этого модуля следует соблюдать осторожность. Многим начинающим администраторам может показаться целесообразным использование этого модуля для блокирования известных червей и вирусов по их сигнатурам, задавая в качестве действия правила операцию DROP. Однако в этом случае пакеты не будут передаваться системе IDS.
Другой ошибкой при использовании этого модуля является попытка предотвратить использование некоторых функций HTTP (например, POST или GET) путем отбрасывания пакетов, содержащих соответствующую строку. Отметим, что с этой работой гораздо лучше справляются фильтрующие прокси-серверы. Кроме того, при использовании такого подхода будут заблокированы все пакеты HTTP, которые содержат документы с данным словом.
Этот модуль предназначен только для передачи пакетов программам пользовательского пространства для дальнейшего анализа этих пакетов. Отбрасывание пакетов с помощью данного модуля будет просто приводить к обходу систем IDS.
Соответствие time
Модуль time позволяет проверить для пакетов время прибытия или отправки. Для использования модуля в строке спецификации правила должна присутствовать команда -m time. Модуль поддерживает несколько опций:
--timestart value
проверяет, что значение временной метки не меньше указанного времени (HH:MM)
--timestop value
проверяет, что временная метка не превышает указанного значения (HH:MM)
--days listofdays
проверяет для временной метки соответствие заданному дню недели
-
- Mon
-
- Tue
-
- Wed
-
- Thu
-
- Fri
-
- Sat
-
- Sun
При указании дня недели следует соблюдать регистр символов.
Приведенная ниже команда обеспечит восприятие всех входящих пакетов по рабочим дням с 8:00 до 18:00:
iptables -A INPUT -m time --timestart 8:00 --timestop 18:00 --days Mon,Tue,Wed,Thu,Fri -j ACCEPT
Если вы воспользуетесь командой iptables --list, то сможете увидеть включенное в цепочку правило фильтрации
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere TIME from 8:0 to 18:0 on Mon,Tue,Wed,Thu,Fri
Соответствие u32
Разработанный Доном Коэном (Don Cohen) модуль u32 позволяет взять из пакета любые байты, выполнить по отношению к ним те или иные действия, и проверить результат. Например, вы можете взять из заголовка пакета IP поле Fragmentation, отбросить в нем все флаги, за исключением More Fragments и посмотреть значение этого флага.
Модуль позволяет выполнить множество операций и хорошо документирован, поэтому вы сможете самостоятельно создавать правила на основе этого модуля, прочитав последующие параграфы и предварительно поэкспериментировав. Для работы с модулем вы должны хорошо знать структуру пакетов и особенно их заголовков. Краткие сведения о заголовках пакетов вы сможете найти в документе TCP/IP and tcpdump Packet Reference Guide. Будет полезно также прочесть спецификации протоколов стека TCP/IP, тексты которых вы найдете на сайте http://rfc-editor.org.
Нумерация байтов в описании этого модуля всегда начинается с 0 (первый байт заголовка пакета). Например, в заголовках IP байт 0 содержит 4-битовое поле Version (номер версии) и 4-битовое поле IP Header Length (размер заголовка IP), а байт 1 содержит поле TOS.
При работе с функциями модуля не забывайте в спецификации правила указывать команду загрузки модуля -m u32.
Проверка значений 2-байтовых полей
Простейшим вариантом использования модуля u32 является выборка из пакета 4-байтового блока, начиная с позиции Start, применение к нему маски Mask и сравнение результата с диапазонов Range. Ниже приведен пример такого использования:
iptables -m u32 --u32 "Start=Range"
В качестве значения поля Start следует указывать номер последнего интересующего вас байта минус 3 (например, если вас интересуют байты 4 и 5 в заголовке IP, следует использовать в качестве параметра Start значение 5 - 3 = 2). Битовая маска позволяет отбросить все биты, которые вас не интересуют. Значения маски лежат в диапазоне от 0 0xFFFFFFFF. Для того, чтобы получить интересующие нас байты 4 и 5, нужно отбросить байты 2 и 3. В этом случае маска должна иметь значение 0x0000FFFF (можно использовать сокращенную запись без нулей слева – 0xFFFF).
Таким образом, для того, чтобы проверить принадлежность значения IP ID (байты 4 и 5) к диапазону 2 - 256, мы должны использовать правило:
iptables -m u32 --u32 "2&0xFFFF=0x2:0x0100"
Переведем это правило на человеческий язык: "Загрузить модуль u32 и выполнить по отношению к пакету проверку u32 – выбрать из пакета 4 байта, начиная со второго, применить к ним маску 0x0000FFFF (для отбрасывания байтов 2 и 3) и проверить, что значение IP ID лежит в диапазоне от 2 до 256."
В iptables отсутствует специальная операция проверки поля IP ID и описанное правило эквивалентно условию ip[2:2] >= 2 & ip[2:2] <= 256 для фильтров tcpdump/bpf.
В приведенном примере не было указано действие для пакетов, соответствующих правилу. В зависимости от ваших задач вы можете выбрать что-то типа :
-j LOG --log-prefix "ID-in-2-256 "
или
-j DROP
При необходимости вы можете включить в спецификацию правила и другие условия.
Вы можете использовать это правило, например, для проверки размера пакетов. Чтобы отобрать пакеты, размер которых не менее 256 байтов, можно использовать правило:
iptables -m u32 --u32 "0&0xFFFF=0x100:0xFFFF"
Эту операцию можно также выполнить с помощью правила iptables:
iptables -m length --length 256:65535
или фильтра bpf:
"len >= 256"
Проверка значений 1-байтовых полей
Проверка однобайтовых значений отличается от операций для 4-байтовых слов лишь использованием маски 0x000000FF (или короткого варианта 0xFF) для выделения 1 байта из 4 прочитанных модулем u32. Например, для отбора пакетов, в которых значение поля TTL не превышает 3:
iptables -m u32 --u32 "5&0xFF=0:3"
которое эквивалентно правилу
iptables -m ttl --ttl-lt 4
или bpf-фильтру
"ip[8] <= 3"
Просмотр 4 байтов сразу
Для проверки значения IP-адреса получателя нам потребуются биты 16-19 из заголовка пакета. Поскольку мы должны проверить все 4 бита, маска в этом случае становится ненужной. Например, для обнаружения в поле адреса получателя значения 224.0.0.1 можно использовать правило
iptables -m u32 --u32 "16=0xE0000001"
эквивалентное правилу
iptables -d 224.0.0.1/32
Если мы хотим проверить только три первых байта адреса (принадлежность к сети класса C), снова потребуется маска (0xFFFFFF00), которая позволит избавиться от ненужного байта. Для проверки принадлежности адреса получателя к сети 192.168.15.0/24 (0xC0A80F00) можно использовать правило
iptables -m u32 --u32 "12&0xFFFFFF00=0xC0A80F00"
эквивалентное правилу
iptables -s 192.168.15.0/24
Проверка каждого байта в заголовке
Если вы хотите посмотреть значение поля TOS (байт 1 в заголовке IP), в соответствии с приведенными в параграфе (стр. 7) в качестве стартовой позиции нужно указать значение -2 (1-3). Вместо этого можно начать выборку с байта 0, выделить его с помощью маски и переместить в последнюю позицию для упрощения проверки. Это не единственный способ решения задачи, но он служит достаточно хорошей иллюстрацией метода.
Для выделения поля TOS сначала сделаем выборку байтов 0 – 3 с помощью модуля u32, задав смещение 0. После этого выделим нужный байт (второй байт выбранного блока) с помощью маски 0x00FF0000. Далее для упрощения проверки значения поля TOS следует сдвинуть этот байт на 16 битовых позиций вправо. Для решения этой задачи модуль u32 поддерживает специальную операцию сдвига вправо, задаваемую символом >>, вслед за которым указывается величина сдвига (в нашем случае 16). В результате правило проверки наличия в поле TOS значения 0x08 (максимальная пропускная способность) будет иметь вид:
iptables -m u32 --u32 "0&0x00FF0000>>16=0x08"
Это правило эквивалентно строке:
iptables -m ttl --tos 8
Проверка отдельных битов
Если вам потребуется проверить значения некоторых битовых флагов (например, поля More Fragments) в iptables может не оказаться готовых правил для такой проверки. В частности, условию -f будут соответствовать все фрагменты, начиная со второго, а вам для работы может потребоваться идентификация всех фрагментов, кроме последнего. Рассмотрим, как можно решить задачу на примере уже упомянутого поля фрагментации. Интересующий нас бит находится в шестом байте, поэтому мы можем сделать выборку с байта 3 и отбросить с помощью маски (0x000000FF) байты 3-5. Но для решения нашей задачи не требуется весь байт полностью, поэтому мы можем воспользоваться маской 0x00000020 (0010 0000), которая позволит нам выделить только интересующий нас бит. После этого можно пойти двумя путями: сдвинуть бит в крайнюю правую позицию для сравнения с 1 или оставить все как есть, сравнивая с соответствующим значениям (32). В первом случае правило будет иметь вид
iptables -m u32 --u32 "3&0x20>>5=1"
а во втором
iptables -m u32 --u32 "3&0x20=0x20"
Оба варианта будут возвращать значение true при установленном флаге More Fragments.
Объединение проверок
Если вы хотите объединить в одном правиле несколько проверок, используйте знак
&&
Работа с заголовками пакетов
В трех следующих параграфах рассматриваются примеры реализации правил с использованием модуля u32 для анализа заголовков TCP, UDP и ICMP.
TCP
Рассмотрим задачу анализа поля порядкового номера TCP (байты 4 - 7 заголовка TCP). Предположим для простоты, что размер заголовка IP составляет 20 байтов. Первым считываемым байтом будет четвертый октет заголовка TCP, следующего непосредственно после заголовка IP. Для нашего примера будем проверять соответствие порядкового номера значению 41 (0x29) с помощью правила
iptables -m u32 --u32 "24=0x29"
Однако это правило не будет работать для пакетов, в которых размер заголовка IP не равен 20 байтам, поэтому постараемся его усовершенствовать.
Для начала убедимся, что пакет относится к протоколу TCP. Информация о протоколе содержится в байте 9 заголовка IP, поэтому разумно будет взять из заголовка IP 4 байта, начиная с байта 6, отбросить байты 6-8 и убедиться, что оставшийся байт содержит идентификатор протокола ЕСЗ (6). Усовершенствованное правило проверяет принадлежность пакета к протоколу TCP и значение порядкового номера (41)
iptables -m u32 --u32 "6&0xFF=0x6 && 24=0x29"
Вернемся к проблеме размера заголовка IP, который может меняться в зависимости от наличия опций. Для решения этой задачи нужно выполнить ряд действий:
-
Определим размер заголовка из первого байта заголовка IP (младший полубайт, указывающий размер заголовка в 4-байтовых словах). Для выделения байта, содержащего размер нужно прочесть первые 4 байта заголовка и сдвинуть полученное значение на 3 байта вправо
"0>>24"
-
Далее нужно выделить четыре младших бита и умножить полученное значение на 4 (размер слова). Умножение эквивалентно сдвигу влево на 2 бита, а для выделения результата следует взять 6-битовую маску 0x3C (<< 0x0F). В результате получается
"0>>22&0x3C"
Для заголовка IP без опций это выражение дает в результате значение 20, в остальных случаях – размер заголовка с учетом опций.
-
Добавим смещение поля порядкового номера в заголовке TCP (4) и передадим его в качестве стартовой позиции правилу u32. Для передачи значения используется знак @, который трактует содержащееся слева от него значение как смещение для отсчета стартовой позиции u32.
Результирующее правило будет иметь вид
iptables -m u32 --u32 "6&0xFF=0x6 && 0>>22&0x3C@4=0x29"
Таким образом мы получаем для проверки значение порядкового номера TCP для всех пакетов (независимо от размера заголовка IP).
Однако мы еще не приняли во внимание возможность фрагментации пакетов. Протокол IP устроен так, что заголовки IP не могут быть разделены на фрагменты, однако заголовки и данные TCP могут быть фрагментированы. Поэтому при просмотре второго и последующих фрагментов даже последний вариант правила будет давать некорректные результаты и нам придется научиться принимать во внимание фрагменты.
Для обеспечения корректной работы правила нужно научиться отличать первый фрагмент и нефрагментированные пакеты. Для решения этой задачи нужно проверить значение байтов 6 и 7 заголовка IP (смещение фрагмента и флаги), отбросив значение поля флагов. Это можно сделать с помощью операции
"4&0x1FFF=0"
Окончательное правило (идентификация протокола TCP и первого фрагмента или отсутствия фрагментации, проверка значения порядкового номера) приобретает форму
iptables -m u32 --u32 "6&0xFF=0x6 && 4&0x1FFF=0 && 0>>22&0x3C@4=0x29"
Это правило будет корректно работать во всех случаях, поскольку любая реализация IP должна обрабатывать пакеты размером, по крайней мере 68 байтов, а заголовок IP не может превышать в размере 60 байтов. Поэтому даже при столь жесткой фрагментации первые 8 байтов заголовка TCP окажутся в первом фрагменте.
Отметим также, что модуль u32 возвращает значение false (несоответствие правилу), для тех случаев, когда указанные правилом значения выходят за размеры пакета.
ICMP
В качестве примера рассмотрим правило для обнаружения пакетов ICMP Host Unreachable (ICMP, тип 3, код 1). Как и в предыдущем примере нам нужно проверить в заголовке IP поле протокола (1 для ICMP) и после этого просматривать полные пакеты и первые фрагменты:
"6&0xFF=1 && 4&0x1FFF=0"
Для проверки типа и кода ICMP нам опять потребуется пропустить заголовок IP
"0>>22&0x3C@..."
Для выборки двух первых байтов, начнем чтение с байта 0 и сдвинем вправо первые 16 битов. В результате получится правило
iptables -m u32 --u32 "6&0xFF=1 && 4&0x1FFF=0 && 0>>22&0x3C@0>>16=0x0301"
UDP
Попытаемся заглянуть внутрь пакетов и выделить все пакеты UDP с запросами DNS. В этом случае следует не только проверить порт получателя (53), но и определить значение старшего бита в байте 2 поля данных пакета (DNS query).
Начнем с проверки принадлежности пакета протоколу UDP:
"6&0xFF=17"
Как обычно, выделим первый фрагмент или нефрагментированный пакет:
"4&0x1FFF=0"
Для проверки порта получателя нам потребуются байты 2 и 3 из заголовка UDP, который следует вслед за заголовком IP (который мы просто пропускаем):
"0>>22&0x3C@0&0xFFFF=53"
Если пакет соответствует всем рассмотренным выше условиям, мы проверяем в нем содержимое поля данных (не забудьте пропустить заголовок IP переменной длины и 8-байтовый заголовок UDP):
"0>>22&0x3C@8 ..."
для того, чтобы идентифицировать запрос DNS. Для того, чтобы отличить запрос от отклика, нам потребуется старший бит байта 2, используем смещение 8 для выборки первых 4 байтов данных и сдвинем результат на 15 битов вправо для выделения бита Query с помощью маски 0x01:
"0>>22&0x3C@8>>15&0x01=1"
Полное правило будет иметь вид:
iptables -m u32 --u32 "6&0xFF=17 && 4&0x1FFF=0 && 0>>22&0x3C@0&0xFFFF=53 && 0>>22&0x3C@8>>15&0x01=1"
Эквивалентное правило можно записать и в более простой форме с использованием других проверок iptables. Выберем для этого нефрагментированные пакеты или первые фрагменты UDP, адресованные в порт 53 и применим к ним последнее условие u32:
iptables -p udp --dport 53 ! -f -m u32 --u32 "0>>22&0x3C@8>>15&0x01=1"
Примеры правил
Сначала повторим описанные в предыдущих параграфах проверки, а потом добавим несколько новых правил.
"2&0xFFFF=0x2:0x0100"
проверяет, что значение поля IP ID лежит в диапазоне от 2 до 256.
"0&0xFFFF=0x100:0xFFFF"
проверяет, что размер пакета не менее 256 байтов.
"5&0xFF=0:3"
проверяет, что пакет имеет значение TTL не более 3.
"16=0xE0000001"
проверяет что IP-адрес получателя равен 224.0.0.1.
"12&0xFFFFFF00=0xC0A80F00"
проверяет, что пакет получен из сети класса C 192.168.15.X.
0&0x00FF0000>>16=0x08
проверяет, что поле TOS имеет значение 8 (максимальная пропускная способность).
"3&0x20>>5=1"
проверяет наличие флага More Fragments.
"6&0xFF=0x6"
проверяет принадлежность пакета к протоколу TCP.
"4&0x1FFF=0"
проверяет что пакет не фрагментирован или является первым фрагментов (смещение фрагмента = 0).
"0>>22&0x3C@4=0x29"
проверяет, что порядковый номер TCP равен 41 (для этого теста также требуется проверить два предыдущих условия).
"0>>22&0x3C@0>>16=0x0301"
проверяет принадлежность пакета ICMP (type=3, code=1); для этого требуется проверка принадлежности к протоколу UDP и отсутствие фрагментации или первый фрагмент).
"0>>22&0x3C@0&0xFFFF=53"
проверяет, что пакет UDP адресован в порт 53 (требуется также проверка на отсутствие фрагментации или первый фрагмент).
"0>>22&0x3C@8>>15&0x01=1"
проверяет наличие бита DNS Query в пакетах UDP (сначала проверяется принадлежность к протоколу UDP, отсутствие фрагментации/первый фрагмент и адресация в порт 53).
Несколько новых проверок:
"6&0xFF=1"
проверяет принадлежность к протоколу ICMP.
"6&0xFF=17"
проверяет принадлежность к протоколу UDP.
"4&0x3FFF=0"
проверяет нулевое смещение фрагмента и отсутствие флага MF (наличие дополнительных фрагментов). Выполнение условия говорит о том, что пакет не является фрагментом.
"4&0x3FFF=1:0x3FFF"
проверяет нулевое смещение фрагмента и присутствие флага MF (наличие дополнительных фрагментов). Выполнение условия говорит о том, что пакет является фрагментом.
0>>22&0x3C@12>>26&0x3C@-3&0xFF=0:255
проверяет принадлежность поля данных к протоколу TCP, обеспечивая изящный способ обнаружения пакетов TCP SYN.
|