Вячеслав Калошин
IPCHAINS-HOWTO-RUS 1.0


    
    Здесь по идее должны быть замечания о лицензии и о том, что автор не
несет никакой ответственности, но я это опущу за ненадобностью - кому надо
ЭТО, может спокойно прочитать в оригинальном IPCHAINS-HOWTO. Данный документ
представляет собой почти полный перевод оригинального текста и был сделан
для публикации на linux.irk.ru Вячеславом Калошиным (multik@istu.edu)

    
    Что такое ipchains.
    
    Linux ipchains это замена, пришедшая на смену ipfwadm (который,
в свою очередь, был списан с BSD. Для работы с ними вам необходима
версия ядра выше, чем  2.1.102.


    Зачем переходить на ipchains ?
    
    В старых версиях линукса файрволл не работал с фрагментами пакетов,
имел 32х битные счетчики (на intel-процессорах), не давал указывать
типы протоколов, отличные от TCP,UDP и ICMP, не давал делать большие
изменения автоматически, не имел инверсных правил, и был очень тяжелым для
управления.


    Немного информации.
    
    Весь траффик в сети посылается в виде пакетов. В начале каждого пакета
идет информация о том, откуда он идет, тип пакета и другие подобные детали.
Начало пакета называется заголовком (хедером,header), остальная часть пакета
обычно назвается телом (body).
    Некоторые протоколы, как TCP, которые используются для web, mail и прочего,
используют понятие "соединения" - перед тем, как любой пакет с данными будет
послан получателю, проходят некоторые установочные пакеты (со специальными
заголовками)с сообщениями типа "я хочу установить соединение", "хорошо",
"спасибо,устанавливаю". И только потом пойдут нормальные пакеты с информацией.
    Фильтр пакетов - это часть программного обеспечения, которое смотрит на
заголовки пакетов и либо пропускает пакет дальше, либо запрещает его дальнейшее
движение. Есть некоторое различие между понятиями "запрет" (deny) и "отказ" (reject).
"Запрет" - это когда пакет от отправителя отвергается системой так, что
отправитель думает, что пакет не дошел до получателя, а "Отказ" - это когда
отправитель пакета извещается о том, что его пакет был отвергнут получателем.


    Зачем вообще нужен фильтр пакетов ?
    
    Управление
    Когда ваш линукс подлючен к различным сетяи (и к интернету в том числе),
вы должны иметь возможность управлять любыми потоками данных, идущих через
вашу систему. Например, вы должны быть уверены, что любой пакет из внутренней
сети, которые может содержать важную информацию, не уйдет на просторы интернет.
    
    Безопасность
    Когда линукс стоит один на один с хаосом интернета, да еще и служит мостом
в интернет для машин внутренней сети, вы должны быть уверены, кто и куда ходит
через мост. Например, вы желаете ходить по интернет, но не желаете, чтобы ваша
машина была сервером (а вы уверены, что у вас все пользователи имеют пароли и
лишние сервисы закрыты ?). С наличием файрволла эти проблемы решаются легко
и быстро.

    Крутость ;-)
    Иногда какая-нибудь неправильно настроенная машина в локальной сети или
пользователь, которые по незнанию или по злому умыслу начнут посылать во
внешнюю сеть различные пакеты (начиная от нюков и заканчивая пакетами
от троянцев). Так вот, фильтр пакетов позволит избежать таких случаев и
даст вам знать, что случилось, автоматически, а не заставляет вас сидеть
и контролировать трафик вручную.

    Как установить фильтр пакетов ?
    Вы нуждаетесь в ядре, в который вкомпилен фильтр пакетов. Посмотрите на
файл /proc/net/ip_fwchains - если вы его видите, то все в порядке. Если вы его
не видите, то вам необходимо взять ядро 2.1.102 или выше. Если у вас ядро
серии 2.0, то вам необходима специальная заплатка. Отконфигурируйте ядро так,
чтобы у него были включены опции IP firewalling. В /usr/src/linux/.config для
ядер 2.1 и 2.2 должны быть включены следующие опции
 CONFIG_FIREWALL=y
 CONFIG_IP_FIREWALL=y
Также необходимо скачать утилиту ipchains , которая и будет управлять
фильтром пакетов в ядре. Все последние дистрибутивы linux, которые основаны
на ядрах 2.1 и 2.2 , уже имеют такую утилиту в наличии.

    Как пакеты проходят через фильтры
    Ядро стартует с 3мя списками правил, эти правила называются правилами
файрволла или просто цепочками (chains). Эти три цепочки называются input
(входная), output (выходная) и forward (пересылка). Когда пакет приходит
(скажем, через сетевую карту), ядро использует входную цепочку для определения
того, может ли пакет двигаться дальше. Если пакет проходит эту проверку, то
он двигается дальше ( это еще называется роутинг). Если он предназначен
другой машине, ядро смотрит на цепочку пересылки (forward). В конце, перед тем,
как пакет уйдет наружу, ядро смотрит на выходную цепочку.
    Цепочка - это список правил. Каждое правило выглядит так "если заголовок
пакета содержит то и то, то делай с пакетом то". Если правило
не подходит к заголовку пакета, ядро смотрит на следующее правило в цепочке.
В конце, если пакет прошел всю цепочку правил, и ни одно правило не сработало,
ядро смотрит на правила цепочки. В защищенных системах пакет обычно отвергается
или запрещается.
                       ACCEPT/
                      REDIRECT                                        ACCEPT
  --> C --> S --> ______ --> D --> ~~~~~~~~ --> local ------> _______ -->
      h  -> a    |input |    e    {Routing } |  __|____ -->->|output |
      e  |  n    |Chain |    m    {Decision} | |forward|   | |Chain  |
      c  |  i    |______|    a     ~~~~~~~~  | |Chain  |   | |_______|
      k  |  t       |        s        |      | |_______|   |     |
      s  |  y       |        q        |      |     |       |     |
      u  |  |       v        e        v      |     |       |     v
      m  |  |     DENY/      r  Local Process|     v       |   DENY/
      |  |  v    REJECT      a        |-------   DENY/     |  REJECT
      |  |DENY               d        |         REJECT     |
      v  |                   e -------+---------------------
     DENY|                            |
         ------------------------------
			
    Пошаговое описание каждой стадии
    
    Проверка контрольной суммы (Checksum) - ядро проверяет пакет на предмет
целостности и коректности заголовков. Если пакет не удовлетворяет этим условиям, он
запрещается.

    Назначение (Sanity) - ядро проверяет, кому предназначен пакет, зачем и
куда. Множество лишних пакетов отсеиваются именно на этой стадии, но приоритет
"входной" (input) цепочки выше. 

    Входная цепочка (input) - это первая цепочка, с помощью которой фильтр
отсеивает пакеты. Если решение этой цепочки не "отвергнуть" (REJECT) или
"запретить" (DENY), то пакет продолжает свое движение дальше.
    Демаскарад (Demasquaerade) - если пакет - это ответ на предыдущий
маскарадный пакет, он демаскарадируется, и сразу пропускатеся на выходную
цепочку. Если вы не использете маскарадинг, вы можете мысленно стереть
это место из рисунка.
    Роутинг (routing) - поле "получатель" пакета анализируется частью кода,
которая ответственна за то, куда пакет пойдет дальше - на локальную обработку
или будет перенаправлен на другую машину (смотрите на цепочку "пересылка"
(forward)) 
    Локальная обработка (local) - задача, запущенная на локальной машине,
может получить пакет только после того, как он пройдет роутинг, и может
посылать пакеты в ответ (которые пройдут через выходную цепочку, затем через
входную цепочку интерфейса "lo", если пакет предназначен для процесса на
этой-же машине, или уйдет через выходную цепочку). 
    Если пакет не создан задачай на локальной машине, проверяется цепочка 
"пересылка" (forward) , в другом случае пакет идет сразу на "выходную"
(output) цепочку.
    Цепочка "пересылка" (forward) - эту цепочку проходят все пакеты, которые
предназначены для транзитного прохода через систему.
    "Выходная" (output) цепочка - через эту цепочку проходят все пакеты,
которые отправляются этой машиной.


    Использование ipchains
    
    Сначала проверьте, какая версия ipchains стоит у вас на машине.
# ipchains --version
ipchains 1.3.5, 26-June-1998

    Этот документ ссылается именно на эту версию программы.

    ipchains имеет man-документацию, но если вам необходимо больше узнать
о путях прохождения пакетов, вы можете проверить руководство по
программированию интерфейсов (man 4 ipfw), или файл net/ipv4/ipfw.c в исходных
текстах ядра линукса, они достаточно компетентны в данном вопросе ;-).

    Есть несколько различных вещей, которые можно делать с цепочками. Первое - 
это оперирование целыми цепочками. Ядро стартует с 3мя встроенными цепочками -
"входная", "выходная", "пересылка" (input, output, forward) - их вы не можете
удалить. Нижу указано, что можно делать.

    Создание новой цепочки (-N)
    Удаление пустой цепочки (-X)
    Смена правил для встроенных цепочек (-P)
    Список всех правил в цепочке (-L)
    Очистка цепочки от правил (-F)
    Сброс счетчиков пакетов и байт во всех правилах цепочки) (-Z)

    Есть несколько путей для манипулирования правилами внутри цепочки
    
    Добавить новое правило к цепочке (-А)
    Вставить новое правило в указанную позицию в цепочке (-I)
    Заменить правило в указанной позиции цепочки (-R)
    Удалить правило в указанной позиции (-D)
    Удалить первое правило, которое срабатывает в цепочке (-D)
    
    Если еще несколько операций для маскарадинга
    
    Показать текущие соединения через маскарад (-M -L)
    Установить тайм-ауты для маскарада (-M -S)
    
    В конце, есть команды, которые дают вам проверить, что случиться с данным
пакетом, если он пойдет через указанную цепочку.


    Операции с одним правилом.
    
    Это основные операции в ipchains - манипуляция правилами. Обычно, вы можете
попробовать команды добавить (-А) и удалить (-D) правило. Аналогично
и с командами вставить (-I) и заменить (-R) - синтаксис их практически одинаков.
    Каждое правило указывает список условий, которые пакет должет иметь, и что
с ним делать при совпадении условий. Для примера, давайте запретим все ICMP
пакеты, которые идут с адреса 127.0.0.1. В нашем случае протокол должен быть
ICMP, и адрес источника 127.0.0.1 - для таких условий "запретить".
    Адрес 127.0.0.1 - это интерфейс-заглушка, который есть, даже есть вы не
имеете реальных сетевых соединений. Вы можете использовать программу ping для
генерации этих пакетов (он просто посылает пакеты с типом ICMP 8 (echo request),
на которые обычно все дружественные системы обычно отвечают пакетами с типом
ICMP 0 (echo reply)). Это нам и потребуется для тестирования.

# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.2 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.2/0.2/0.2 ms
# ipchains -A input -s 127.0.0.1 -p icmp -j DENY
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
#

    Вы видите, что первый ping прошел успешно (ключ "-с 1" говорит ping'у, что
надо послать всего один пакет)

    Потом мы добавили (-А) во "входную" цепочку правило, которое указывет, что
пакеты 127.0.0.1 (-s 127.0.0.1) с протоколом ICMP (-p ICMP) должны запрещаться
(-j DENY).

    Затем мы проверили наше правило, используя второй ping. Он маленько
подождал, пока не сдался, ожидая пакет с ответом, который никогда не придет.

    Мы можем удалить правило двумя путями. Так как мы знаем, что у нас только
одно правило, мы можем использовать удаление правила по номеру, вот так :
# ipchains -D input 1
    Это удаляет правило номер 1 из входной цепочки.
    Второй путь - это зеркальное отображение команды "добавить", но с заменой
-A на -D. Этот путь полезен, когда вы имеете полную правил цепочку, и вы не
имеете желания считать, какое это же правило по номеру. В этом случае можно
сделать так.
# ipchains -D input -s 127.0.0.1 -p icmp -j DENY
    Синтакис после команды (-D) должен совпадать с систаксисом команды -A
(или -I и -R), которой и было заданно это правило. Если есть несколько
одинаковых правил в разных цепочках, только первое правило будет удаленно.


    Спецификация для фильтров.
    
    Мы будем использовать -p для указания протокола и -s для указания
адреса источника, но есть и другие опции, которые указывают другие
характеристики пакетов. Они будут описаны дальше.


    Указание ip-адресов источников и получателей.
    
    ip-адреса источников (-s) и получателей (-d) могут быть указаны 4мя путями.
Обычно их указывают полными именами, например "localhost" или "linux.irk.ru".
Второй путь - указание полного ip-адреса, например 127.0.0.1. Третий и
четвертые пути дают возможность указывать группы ip адресов, например
"62.76.19.0/24" или "62.76.19.0/255.255.255.0". Оба эти варианта
указывают адреса с 62.76.19.0 включительно до 62.76.19.255. Цифры после "/" 
указывают, какая чать ip адреса будет значимой. По умолчанию принимается
"/32" или "/255.255.255.255" (попадают все ip адреса).
Для указания любого ip адреса возможно применение "/0", например
# ipchains -A input -s 0/0 -j DENY
Это вызовет такой-же эффект, как и без указания -s вообще.


    Указание инверсии
    
    Многие флаги, включая -s и -d могут иметь третий аргумент в виде "!", для
вычисления адресов, которые НЕ попадают в указанные. Например под
"-s ! localhost" попадают все пакеты, которые не идут с localhost.


    Указание протокола
    
    Протокол может быть указан с помощью флага -p. Протокол может быть номером
(если вы знаете значение номеров протоколов для ip) или одним из следующих
значений : TCP, UDP или ICMP. Регистр не имеет значения, tcp то же самое, что
и TCP. Протоколы также могут быть инвертированы с помощью "!", напрмер
"-р ! ТСР" указывает на те протоколы, которые не TCP.


    Указание TCP и UDP портов
    
    Когда указаны протоколы TCP или UDP, возможен третий аргумент, который
указывает TCP&UDP порты или их диапазон (включая конечные порты). Диапазон
указывается с помощью символа ":", например "6000:6100" указывает на 11 портов,
от 6000 до 6010 включительно. Если нижняя граница не указана, за нее принимается
0. Если верхняя граница не указана, она принимается равной 65535. Например, 
для указания TCP соединений, идущих с портов ниже 1024, синтаксис будет
следующим "-p TCP -s 0.0.0.0/0 :1024". Также порты могут быть указаны по имени,
например www (для перевода в численное значение смотрите файл /etc/services)

    Номера портов также можно инвертировать с помощью "!". Например, для
указания любого TCP пакета, кроме WWW пакетов, вы должны указать
"-p TCP -d 0.0.0.0/0 ! www"
Важно понять, что
"-p TCP -d ! 192.168.1.1 www"
ОЧЕНЬ СИЛЬНО ОТЛИЧАЕТСЯ от
"-p TCP -d 192.168.1.1 ! www"
    Первое правило указывает на любые TCP пакеты на WWW порт на любую машину,
но не на 192.168.1.1. Второе правило указывает любое TCP соединение на
192.168.1.1 на любой порт, кроме WWW.
Объеденив эти правила, получим
 -p TCP -d ! 192.168.1.1 ! www
то есть на любую машину, кроме 192.168.1.1 и на любой порт, кроме WWW


    Указание типов и кодов ICMP
    
    ICMP также допускает использование дополнительных аргументов, но ICMP не
имеет портов (ICMP использует тип и код для передачи данных).
    Вы можете указывать имена ICMP пакетов (ipchains -h icmp для списка
имен) после ключа -s, или числовое значение типа и кода ICMP, где тип
следует после ключа -s, а код следует после ключа -d.
    ICMP имена на такие длинные, достаточно указать несколько символов,
по которым их можно однозначно отличить от других.
    Ниже приведена маленькая таблица ICMP типов

       Номер    Имя                      Нужен для
       
        0       echo-reply               ping
	3       destination-unreachable  любого TCP/UDP траффика.
	5       redirect                 роутинга,если не запущен демон роутинга
	8       echo-request             ping
	11      time-exceeded