Введение

Привет всем, кому интересна ОС FreeBSD! После летне-отпускного отсутствия начинаю новый цикл статей. Надеюсь, будет занимательно и полезно.

Для тех, кто тут впервые, поясню, что являюсь разработчиком российского Интернет-шлюза Интернет Контроль Сервер, реализованного на базе FreeBSD. А потому, изнанка этой операционки, ее фишки и тонкости администрирования - то, с чем я сталкиваюсь ежедневно и делюсь с вами.

В предыдущей серии статей мы рассмотрели файрвол PF. Оценили возможности и настроили его для разных ролей. В новом цикле сделаем то же для файрвола IPFW. Как и с PF, начнем с краткого обзора и создания простой конфигурации для защиты веб сервера. В следующий статьях будем погружаться и усложнять конфигурацию постепенно, вводя новые типы правил и добавляя "мяса".

Ipfirewall - open source модуль, портированный на многие ОС. В этом списке FreeBSD, NetBSD, OpenBSD, SunOS, HP/UX и Solaris, Mac OS и даже Windows. Кроме того, часто используется для различных встраиваемых систем. Впервые появился в FreeBSD версии 2.0.

Основные возможности:

  • обработчик правил на уровне ядра, включающий систему учета пакетов

  • механизм логирования

  • механизм форвардинга

  • ipstealth (механизм редактирования TTL полей, защита от traceroute)

  • основанные на ALTQ средства управления QoS

  • механизмы управления пропускной способностью

  • основанная на таблице маршрутов система анти-спуффинга

  • встроенный NAT, PAT и LSNAT

  • поддержка IPv6 (с некоторыми ограничениями)

ipfw - пользовательская утилита для управления ipfirewall. С помощью этой утилиты происходит взаимодействие с модулем ядра. В дальнейшем я буду использовать ipfw и как имя утилиты, и как сокращение названия ipfirewall, для краткости и простоты, ну и просто потому, что так принято на просторах Интернета.

В ipfw конфигурация состоит из пронумерованных правил. Пакет проходит по правилам, начиная с меньшего номера к большему, до первого действия (к примеру allow или deny), после чего обработка прекращается. Чем-то похоже на iptables в Linux.

Управление и полезные настройки

Для включения ipfw в rc.conf необходимо добавить следующие строки:

firewall_enable="YES"
firewall_script="/etc/ipfw_conf.sh"
firewall_logging="YES"

ipfw с пустой конфигурацией по умолчанию блокирует все соединения. Чтобы не потерять доступ к серверу дополнительно нужно добавить в rc.conf

firewall_type="open"

Эта строка укажет ipfw добавить в конфигурацию строку

65535 allow ip from any to any

Полезные команды:

ipfw list # вывод всех правил

ipfw -d list # вывести все правила, включая динамические

ipfw -de list # вывести все правила, включая динамические, в том числе истёкшие

ipfw -t list # вывести все правила, второй колонкой - время последнего совпадения

ipfw -a list # вывести все правила, второй и третьей колонкой будут счетчики входящих и исходящих совпадений

Добавление правил происходит командой

ipfw add <правило>

Добавить простое правило, под номером 100, разрешающее весь трафик на всех интерфейсах

ipfw add 00100 allow ip from any to any

И удаление:

ipfw delete 00100

Структура правил, основные параметры

Общая структура правила не отличается особой сложностью:

 <Номер> <Действие> <Протокол> from <Источник> to <Назначение> \
    [порт] [in | out] [via IF] \
    [keep-state | limit {src-addr | src-port | dst-addr | dst-port}]

Номер - порядковый номер правила, предпочтительно в конфигурации использовать номера не подряд, это позволит без проблем добавлять правила во время работы файрвола. Возможно добавление нескольких правил под одним номером. В этом случае они будут срабатывать в порядке добавления и ipfw delete удалит их все.

Действие назначенное совпавшему пакету. В этой статье мы рассмотрим

allow | accept | pass | permit

Эти действия равнозначны. Пропустить пакет, обработка завершается. Я буду использовать allow, для единообразия.

deny | drop

Так же равнозначны. Отбросить пакет. Буду использовать deny

check-state

Проверяет пакет по таблице динамических правил (соединений), никаких дополнительных опций не предполагает.

Протокол - tcp, udp, icmp, или любой другой протокол, описанный в /etc/protocols

Источник и Назначение - ip адреса, без комментариев. Кючевое слово all означает любой адрес. Ключевое слово me означает локальный адрес хоста.

Порт - номер порта для tcp и udp. Можно использовать имена сервисов, описанные в /etc/services

in|out - означают совпадение с входящими или исходящими пакетами.

via IF - совпадение с трафиком только одного интерфейса IF.

keep-state - ключевое слово, указывающее о необходимости создания динамического правила, которое разрешит обмен пакетами между источником и назначением.

limit - разрешать только N соединений, соответствующих правилу. Создаёт динамические правила подобно keep-state. Нельзя в одном правиле использовать limit и keep-state.

Простейшая конфигурация

Возьмем простейший веб-сервер в вакууме. Нам нужно открыть порты 22, 80, 443 для доступа извне. Исходящие соединения разрешим все.

Для сохранения конфигурации и загрузки правил мы будем использовать shell скрипт, указанный в rc.conf опцией firewall_script.

Фактически, этот shell скрипт содержит набор команд ipfw. Что позволяет использовать в написании конфигурации все преимущества shell. Особенно пригодятся переменные. К примеру:

# cat /etc/ipfw-conf.sh
#
ipfw -q -f flush       # очистка всех правил -q подавляет вывод информации
# значения по умолчанию
eif="em0"              # выходной интерфейс
edns="8.8.8.8"         # IP адрес DNS
cmd="ipfw -q add "     # команда 
ks="keep-state"        # опция, которая добавляет сохранение состояний
# разрешаем всё на локальной петле
$cmd 00010 allow all from any to any via lo0
# если состояние сохрано, пропускаем
$cmd 00020 check-state 
# запрещаем неизвестные фрагментированные пакеты
$cmd 00030 deny all from any to any frag 
# запрешаем все tcp ack, не проходящие по динамическим правилам
# то есть если не было SYN, ACK не будет принят.
$cmd 00040 deny tcp from any to any established in via $eif

#разрешаем входящие на порты веб-сервера
$cmd 000100 allow tcp from any to me 80 in via $eif $ks
$cmd 000110 allow tcp from any to me 443 in via $eif $ks
#разрешаем входящие на порт ssh
$cmd 000120 allow tcp from any to me 22 in via $eif $ks
#разрешаем исходящие соединения
$cmd 000900 allow all from me to any out via $eif $ks
#остальное логгируем и запрещаем
$cmd 001000 deny log all from any to any

При запуске файрвола будет выполнен этот скрипт, и соответствующие правила будут загружены.

Заключение

Мы разобрались с тем, что такое ipfw и запустили его. Рассмотрели простейшие правила фильтрации и научились с ними работать. А так же создали простую, но вполне рабочую конфигурацию файрвола, способную защитить наш сервер от угроз извне.

В следующей статье мы рассмотрим дополнительные опции фильтрации, усовершенствуем конфигурацию для защиты нашего веб-сервера. А пока у вас есть отличная возможность потестировать Интернет Контроль Сервер, тем более что полнофункциональная демо-версия доступна в течение 35 дней, а версия до 9 пользователей вообще бесплатная.

Комментарии (15)


  1. resetsa
    21.10.2021 11:24

    А вот это зачем?

    # запрешаем все tcp, не проходящие по динамическим правилам
    $cmd 00040 deny tcp from any to any established in via $eif


    1. M14xa Автор
      21.10.2021 12:59

      Ну в основном для того, чтобы продемонстрировать само правило. Но используется в основном для того, чтобы отсеять все ACK, которым не предшествовал SYN с одной из сторон. Просто защита от мусора. Сейчас добавлю в статью разъяснения.


  1. lepota
    21.10.2021 12:49

    Зачем в конфигурации два правила за номером 100? Почему ssh соединения разрешены на 20 порт вместо 22, как указано в тексте?


    1. M14xa Автор
      21.10.2021 12:49

      Спасибо, поправил. Обычные опечатки.


  1. NekoYos
    21.10.2021 12:49

    ipfw мощная штука, на фряхе многие до сих пор строят програмные маршрутизаторы, включая интернет провайдеров.

    Пример в статье очень банально простой, для совсем новичков. Но я с ним не согласен, я бы сразу всем объяснял что нужно правила оптимизаировать, заставлять пакеты проходить минимальный набор правил, только те правила котоые ему нужны, а не все скопом - афектит перформанс на сильно нагруженных системах. Для этого есть такие вещи как tablearg skipto, на основе которого разделяешь пакеты по in/out на каждом интерфейсе отдельно. Получаешь отдельные наборы правил на вход/выход пакетов каждого интерфейса отдельно, как на вендоровских железках. Если интересно, приведу пример с одного из своих маршрутизаторов :)

    Ну и нужно не забывать о netgraph в freebsd, который, похоже, все так же остается самой сильной сетевой подсистемой которую люди изобрели. На нем можно сделать что угодно ;)


    1. M14xa Автор
      21.10.2021 12:52

      Приветствую! Эта статья - вводная, посмотрите на цикл по PF, там такая же структура. Дальше будем постепенно погружаться, усложнять конфигурации и до skipto дойдём :) Конфигурация тоже демонстрационная. Основная цель - показать, как вообще сторится конфигурация, что именно нужно в какой последовательности писать.


      1. simpleadmin
        21.10.2021 16:06

        Конфигурация тоже демонстрационная. Основная цель - показать, как вообще сторится конфигурация, что именно нужно в какой последовательности писать.

        Читатели хабра не умеют читать маны? Статей по ipfw нет на опеннет и лиссяре? Что нового здесь? Какие bestpractice описаны?

        Ну дали б просто ссылку на статью Кеды 15-и летней давности и сразу под ней свою рекламу...


    1. simpleadmin
      21.10.2021 15:58

      ipfw мощная штука, на фряхе многие до сих пор строят програмные маршрутизаторы, включая интернет провайдеров.

      Ну это только динозавры, которых не смущают десятки копирований пакета. Для остальных Луиджи (собственно автор ipfw) десять лет назад сделал netmap.


  1. post_ed
    21.10.2021 12:53

    Как вы работаете с доменными именами? Как известно pf, ipfw работают только с ip-адресами.


    1. M14xa Автор
      21.10.2021 12:54

      С PF всё не так просто, есть возможность заполнить таблицу доменными именами и она будет разрешаться в IP при загрузке. Инфа есть в предыдущем цикле статей.
      С IPFW - так и есть, в ИКС имеется отдельная внутренняя служба, отвечающая за разрешение доменных имён в IP адреса.


    1. NekoYos
      21.10.2021 13:13

      Так это и есть фильтры трафика на 2-4 уровнях osi, а значит доменных имен нет. Это не L7 фильтры. Если сильно хочется, можно например закостылить что-то в стиле сценария который резолвит ip'ы по доменным именам, и динамически добавляет в нужные таблицы


  1. NekoYos
    21.10.2021 13:04

    Три правила

    $cmd 000100 allow tcp from any to me 80 in via $eif $ks
    $cmd 000110 allow tcp from any to me 443 in via $eif $ks
    $cmd 000120 allow tcp from any to me 22 in via $eif $ks

    По хорошему заменяется одним

    $cmd 000100 allow tcp from any to me 22, 80, 443 in via $eif $ks


    1. M14xa Автор
      21.10.2021 13:08

      Можно, что ж нет. Но это вводная статья, где всё максимально упрощено. Кроме того, такие правила гораздо сложнее редактировать во время работы файрволла. Например, удалить 80 порт.


      1. NekoYos
        21.10.2021 13:28

        Имхо. Я бы даже в вводной статье делал минимизации конструкций, чтоб новички изначально учились делать правильно. Так сказать воспитание с детства :)

        Насчет сложности редактирования не согласен. Да, не так просто просто как сделать один delete, например, но все же считаю правильным стараться минимизировать количество правил.

        Для удаления, например, 80-го придется сделать две команды:

        ipfw delete 100
        ipfw add 100 allow tcp from any to me 22, 443 in via em0 keep-state


  1. caes
    22.10.2021 13:16

    Лучший файр в мире. Простой и мощный.