Представляю вторую статью из серии, ориентированных на «продолжающих» системных администраторов, для опытных я вряд ли открою что-то новое.
В этих статьях мы рассмотрим построение интернет шлюза на linux, позволяющего связать несколько офисов компании, и обеспечить ограниченный доступ в сеть, приоритетзацию трафика (QoS) и простую балансировку нагрузки с резервированием канала между двумя провайдерами.
Конкретно в этой части:
А в предыдущей части были рассмотрены:
В третьей части:
Все описанное ниже справедливо для CentOS 7.1 (и выше, 6 серия тоже подойдет, но с небольшими особенностями)
В прошлый раз мы настроили довольно доверчивый и примитивный режим работы, сейчас мы включим немного здравой паранойи.
Это сделать не сложно, давайте внесем правки в файл:
Новая конфигурация стала проще, но радоваться рано, файл rules значительно распухнет:
И воспользуемся директивой INCLUDE для разнесения правил по нескольким файлам:
Теперь весь трафик под нашим контролем, пускаем только те протоколы, что хотим. Обратите внимание на правила для SSH, мы ограничили частоту соединений до 3-х в минуту, с каждого ip источника. Но надо быть очень осторожным с этим параметром, неверно указав ключ s: или d:, можно сделать ваш сервис легко поддающимся DDoS атаке. А для Web трафика (да и вообще любого), надо учитывать, что много потенциальных клиентов может сидеть за NAT, и тогда один IP, источник соединений, может генерировать значительное число подключений.
Обратите внимание на то, как мы обошлись с SIP и FTP протоколом. Мы просто их прописали, а Shorewall, используя макросы, спрятал от нас все тонкости работы с модулями nf_nat_* и nf_conntrack_* (без соответствующих модулей, для каждого протокола, который кроме командного соединения (или вообще все порты динамические, типа RPC), создает ещё и вторичные на неизвестных заранее портах, Shorewall, как и iptables, не сможет динамически открыть порты для этих соединений). В примерах для SIP я использовал почти ручную настройку, указав протокол, порт и используемый helper.
С helpers Shorewall работает автоматически (если это не отключить), как только встречается протокол, или явно заданное использование столбца helper, Shorewall подгружает соответствующий модуль. Посмотреть известные shorewall модули и их настройки можно в файле: /usr/share/shorewall/helpers. Если есть необходимость их изменить, скопируйте файл в /etc/shorewall, тогда эта копия переопределит стандартный файл.
Если нам нужно пробросить порты к внутренним серверам, сделать это не сложно:
Кроме всего, Shorewall поддерживает ipsets (проверим, что пакет установлен: yum install ipset), которые просто являются именованными списками адресов. Полезно, когда нужно выполнить настройку некого правила для группы хостов, которые невозможно объединить в подсеть.
В конфигах их использовать не сложно, достаточно везде, где используются адреса или подсети, прописать +<имя ipsets>.
Если мы хотим, что-бы Shorewall сохранял и восстанавливал нам ipsets при своих перезапусках, то нужно установить SAVE_IPSETS=Yes в файле shorewall.conf
Вот как может выглядеть конфигурация с использованием и без ipsets:
Для начала объявим наш ipsets:
Вот и все, можем посмотреть, что у нас записалось: ipset -L
Скажу сразу, и балансировка и резервирование, только лишь настраиваются с помощью Shorewall, сам он не предоставляет никакого функционала по обнаружению пропажи канала или равномерному распределения реальной нагрузки.
Вся настройка сводится к редактированию одного файла:
Если кто помнит, в прошлой статье была секция из «Shorewall.conf». Она нужна как раз для настройки маркировки пакетов и работе с провайдерами. Там мы задали, какие биты из метки пакета, задают идентификатор провайдера, какие просто метки (я такие пока нигде не использую, но Shorewall сам их задействует, для своих нужд), а какие для отслеживания соединений.
Тут мы описали двух провайдеров, задали как маркировать пакеты для них, на каком интерфейсе каждый сидит и какой у кого шлюз.
Вот столбец OPTIONS, надо пояснить немного. Тут ключ fallbaсk заставляет сгенерировать дополнительные правила маршрутизации, на случай если балансировочные не смогут обработать пакет (интерфейс прилег к примеру), а циферка задает вес интерфейса. Параметр track, говорит о необходимости отслеживать, в какого провайдера пошло соединение, и посылать следующий пакет, от этого соединения, в того же провайдера (если в shorewall.conf установлена TRACK_PROVIDERS=Yes, то эта опция прописывается автоматически всем провайдерам).Чем вес больше, тем чаще в интерфейс будут поступать новые соединения (используется в итоге относительный вес, у кого в пропорции вес выше, туда и трафик чаще, задавать большое значение веса не рекомендуется). Балансировка происходит по принципу roundrobin уже самим ядром и базируется на факте установления соединения по маршруту клиент-сервер (в качестве клиента ваш маршрутизатор, а сервер соответственно, удаленный сервер). При этом маршруты кэшируются на некоторое время, и получается такой эффект: кто-то в локалке, полез к примеру на некий сайт (у которого один IP), трафик пошел через провайдера 1, затем кто-то еще полез туда же, и трафик побежит опять через провайдера 1 (если кэш не успел сбросится). Еще может получится, что у вас не симметричные провайдеры, как в примере, и так повезет, каждое четвертое соединение, попадающие на первого провайдера, окажется и самым «тяжелым», а мы хотели этого избежать… Тут уже простых решений нет, и эта статья вам никак не поможет.
Но, не все так плохо, и даже так оно работает достойно (к слову сказать, так оно работает у большинства решений, для «честной» балансировки используются весьма не простые решения, которые часто без поддержки на стороне провайдеров (обоих) не работают).
Дополненный файл переменных:
Можно заметить, что у второго провайдера шлюз указан как ключевое слово «detect», которое работает на соединениях с динамической адресацией. Для некоторый случаев (к примеру PPtP), сам Shorewall не может корректно определить шлюз, для чего используется файл с вспомогательным скриптом:
И важно, нужно все это правильно замаскировать:
Параметр detect, в столбце ADDRESS, заставляет определить исходящий адрес на интерфейсе для SNAT (при нескольких провайдерах становится необходимым).
И дополнит все это скрипт для NetworkManager (более простая версия была в прошлой статье, и она не учитывала, что после поднятия интерфейса, Shorewall не всегда корректно строит политику маршрутизации, поэтому мы для таких интерфейсов просто его перезапускаем).
Дав команду, после shorewall restart:
Можно увидеть построенную схему маршрутизации:
Но, можно ли направить какой либо трафик по конкретному провайдеру? Ответ Да!
Тут мы пометили весь трафик от 172.16.0.4 в любую сеть, кроме 172.16.0.0/12, меткой второго провайдера. Условия могут быть и хитрее, надо только учитывать, для трафика сгенерированного на нашем шлюзе, из правила нужно убрать ":P".
Сразу надо пояснить вот что: по настоящему регулировать скорость мы можем только при отправке. Входящий трафик, уже дошел до нашего интерфейса минуя все узкие места, и толкаясь в очередях, за право оказаться у нас на пороге.
Но отчаиваться рано, и есть механизмы, не столь изящные и надежные, как хотелось бы, но решающие эту проблему. В сетях на базе протоколов семейства IP, это решается таким образом:
Источник плавно наращивает скорость отправки, пока ответы о доставке (пакеты ACK в протоколе TCP) вообще приходят или приходят с нормальной задержкой. Если есть потери или растет задержка ACK, скорость снижается. Потом, спустя некоторый промежуток времени, скорость пытаются вновь поднять. И так происходит до окончания передачи.
А как же UDP? А с ним все просто, нет контроля доставки, нет головной боли. Отправил и ОК (это пусть получатель мучается).
Конечно, в чистом виде UDP обычно не используют в сложных задачах по передаче данных. Этот протокол обычно используют как основу, при реализации своего варианта контроля доставки (можно сказать, своих реализаций TCP, в случаях, когда стандартный не устраивает). Поэтому во многих протоколах работающих поверх UDP, контроль доставки тоже есть. Что не отменяет возможности слать непрерывный поток UDP во всю мощь, забивая канал связи цели (тот самый вариант DDoS).
Как же мы можем организовать приоритезацию трафика и выделения полосы пропускания входящего трафика? Ответ есть выше: создать задержку в получении на своей стороне (как следствие, задержку в генерации ACK) или если задержка неприлично высока, пакет отбросить.
В Linux это реализуется созданием псевдо-интерфейса IFB, который как бы встает между физическим интерфейсом и самим шлюзом, пропуская через себя входящий трафик. Трафик входит в физический интерфейс (мы его уже приняли на нем), и тут же отправляется в IFB, который уже регулирует, с какой скоростью, и в каком порядке пропустить этот трафик (или вообще отбросить).
В настройке нам поможет Shorewall (хотя можно и в /etc/modprobe.d прописать):
Тут тривиально, создали три псевдо-интерфейса IFB и их подняли.
Далее опишем интерфейсы, на которых мы будем регулировать трафик:
Тут мы в явном виде, задаем номера используемых интерфейсов (если не задать, Shorewall пронумерует их в порядке объявления файле), ассоциировали IFB с реальными интерфейсами, задали максимальную исходящую скорость (помним, только её мы и регулируем, и интерфейс ifb по сути это входящая линия) и задали дисциплины классификации и что трафик мы будем именно классифицировать.
Важно! Скорость нужно установить чуть-чуть ниже скорости, которую дает провайдер. Если скорость, которой мы оперируем будет выше чем дает нам провайдер, то и ограничение полосы пропускания случится на его стороне, а значит и все наши потуги на классификацию и т.п. (не совсем полностью, но значительной степени) окажутся тщетны. На каналах с переменной пропускной способностью QoS сделать очень не просто, так как из всех рабочих инструментов у вас будет только переупорядочивание пакетов, в надежде, что ценный трафик пролезет через канал (страдальцы на радиоканалах грустно вздыхают).
Опишем те самые классы:
Пока не будем делать ничего сложного (и оттого интересного и полезного), пока привяжем к каждому интерфейсу (включая IFB) по два класса.
В первом столбце мы ассоциируем интерфейс с классами. <номер интерфейса>:<номер родительского класса>:<номер описываемого класса>.
На интерфейсе всегда есть класс 1, который мы по сути, описали в tcdevices.
Далее, пакеты мы не маркировали, и потому столбец использовать не будем, дальше идет самое интересное, минимально гарантированная полоса пропускания, и максимально возможная (не больше чем таковая у класса родителя), для данного класса. Приоритет задаст порядок разрешения спорной ситуации (у кого меньше, тот и пойдет первым, если вышел за приделы гарантированной полосы, и она уже кем-то другим занята полностью). В заключении идут опции, default говорит о том, что если фильтрами ничего не найдено (пакеты не отнесены к классам), то присвоить им класс по умолчанию).
Дальше, так исторически сложилось, что правила классификации реальных интерфейсов, находятся в файле:
А для виртуальных IFB в:
В примере выше, я поместил входящий трафик от HTTP(S) сервера в класс с номером 3 на физическом интерфейсе, и на виртуальный, ассоциированный с ним, и исходящий я сделал аналогично, но «развернув порты». Очень внимательно отнеситесь к тому, что соединения часто двунаправленны, и расписывать их классификацию надо отдельно для каждого направления, не зависимо от того, кто инициировал, клиент или сервер.
Именно тут, и начинает трещать крыша. Для понимания поможет картинка (прошу ногами особо не бить, в Visio работать толком не умею).
Резать трафик в итоге можно на разных участках, не применяя IFB, если у вас один провайдер, а сам шлюз, трафик не принимает (не является его получателем). Если провайдеров больше, а шлюз сам активно принимает трафик (он к примеру обслуживает VPN), тогда без IFB выкручиваться не легко.
P.S.
В следующей статье я планирую подробнее остановится на QoS, особенно в свете распространения VoIP технологий. Тема большая, и нужно все хорошенько спланировать. Если вас интересует некий аспект более подробно, пишите запрос в комментарии, я учту пожелания в следующей статье.
В этих статьях мы рассмотрим построение интернет шлюза на linux, позволяющего связать несколько офисов компании, и обеспечить ограниченный доступ в сеть, приоритетзацию трафика (QoS) и простую балансировку нагрузки с резервированием канала между двумя провайдерами.
Конкретно в этой части:
- Более подробная настройка Shorewall
- Страшный и не понятный QoS
- Балансировка нагрузки и резервирование
А в предыдущей части были рассмотрены:
- Простейшая настройка Shorewall
- Ужасно сложная настройка dnsmasq
- Не менее сложная настройка OpenVPN
- И для многих продолжающих админов нетипичная, динамическая маршрутизация, на примере OSPF
В третьей части:
- QoS во всю ширь в Shorewall
- Более подробная настройка Shorewall
- Раскидывание трафика по каналам в соответствии с протоколами
- Костыли, без них, никуда
Все описанное ниже справедливо для CentOS 7.1 (и выше, 6 серия тоже подойдет, но с небольшими особенностями)
Углубленная настройка Shorewall
В прошлый раз мы настроили довольно доверчивый и примитивный режим работы, сейчас мы включим немного здравой паранойи.
Это сделать не сложно, давайте внесем правки в файл:
policy
#
# Shorewall -- /etc/shorewall/policy
#
# For information about entries in this file, type "man shorewall-policy"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-policy.html
#
###############################################################################
#SOURCE DEST POLICY LOG LIMIT: CONNLIMIT:
# LEVEL BURST MASK
$FW all REJECT
grn all REJECT
tun all REJECT
red all DROP
Новая конфигурация стала проще, но радоваться рано, файл rules значительно распухнет:
/etc/shorewall/rules
#
# Shorewall -- /etc/shorewall/rules
#
# For information on the settings in this file, type "man shorewall-rules"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-rules.html
#
######################################################################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
# PORT(S) PORT(S) DEST LIMIT GROUP
?SECTION ALL
?SECTION ESTABLISHED
?SECTION RELATED
?SECTION INVALID
?SECTION UNTRACKED
?SECTION NEW
INCLUDE rules.fw
INCLUDE rules.grn
INCLUDE rules.red
INCLUDE rules.red-dnat
INCLUDE rules.tun
И воспользуемся директивой INCLUDE для разнесения правил по нескольким файлам:
rules.fw
#
# Shorewall -- /etc/shorewall/rules.fw
#
# For information on the settings in this file, type "man shorewall-rules"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-rules.html
#
######################################################################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
# PORT(S) PORT(S) DEST LIMIT GROUP
DNS(ACCEPT) $FW red
Web(ACCEPT) $FW red
FTP(ACCEPT) $FW red
OpenVPN(ACCEPT) $FW red
Ping(ACCEPT) $FW all
OSPF(ACCEPT) $FW tun
SSH(ACCEPT) $FW all
rules.grn
#
# Shorewall -- /etc/shorewall/rules.grn
#
# For information on the settings in this file, type "man shorewall-rules"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-rules.html
#
######################################################################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
# PORT(S) PORT(S) DEST LIMIT GROUP
DNS(ACCEPT) grn $FW
Web(ACCEPT) grn red
FTP(ACCEPT) grn red
Ping(ACCEPT) grn all
SSH(ACCEPT) grn all - - - - s:3/min
#Сделаем, в ручную, правило для SIP (макросы для него уже есть)
ACCEPT grn red udp 5060 - - - - - - - - sip
rules.red
#
# Shorewall -- /etc/shorewall/rules.red
#
# For information on the settings in this file, type "man shorewall-rules"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-rules.html
#
######################################################################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
# PORT(S) PORT(S) DEST LIMIT GROUP
OpenVPN(ACCEPT) red $FW
SSH(ACCEPT) red $FW - - - - s:3/min
SIP(ACCEPT) red grn
rules.tun
#
# Shorewall -- /etc/shorewall/rules.tun
#
# For information on the settings in this file, type "man shorewall-rules"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-rules.html
#
######################################################################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
# PORT(S) PORT(S) DEST LIMIT GROUP
Ping(ACCEPT) tun $FW
OSPF(ACCEPT) tun $FW
SSH(ACCEPT) tun $FW - - - - s:3/min
SSH(ACCEPT) tun grn - - - - s:3/min
Теперь весь трафик под нашим контролем, пускаем только те протоколы, что хотим. Обратите внимание на правила для SSH, мы ограничили частоту соединений до 3-х в минуту, с каждого ip источника. Но надо быть очень осторожным с этим параметром, неверно указав ключ s: или d:, можно сделать ваш сервис легко поддающимся DDoS атаке. А для Web трафика (да и вообще любого), надо учитывать, что много потенциальных клиентов может сидеть за NAT, и тогда один IP, источник соединений, может генерировать значительное число подключений.
Обратите внимание на то, как мы обошлись с SIP и FTP протоколом. Мы просто их прописали, а Shorewall, используя макросы, спрятал от нас все тонкости работы с модулями nf_nat_* и nf_conntrack_* (без соответствующих модулей, для каждого протокола, который кроме командного соединения (или вообще все порты динамические, типа RPC), создает ещё и вторичные на неизвестных заранее портах, Shorewall, как и iptables, не сможет динамически открыть порты для этих соединений). В примерах для SIP я использовал почти ручную настройку, указав протокол, порт и используемый helper.
С helpers Shorewall работает автоматически (если это не отключить), как только встречается протокол, или явно заданное использование столбца helper, Shorewall подгружает соответствующий модуль. Посмотреть известные shorewall модули и их настройки можно в файле: /usr/share/shorewall/helpers. Если есть необходимость их изменить, скопируйте файл в /etc/shorewall, тогда эта копия переопределит стандартный файл.
Если нам нужно пробросить порты к внутренним серверам, сделать это не сложно:
rules.red-dnat
#
# Shorewall -- /etc/shorewall/rules.red-dnat
#
# For information on the settings in this file, type "man shorewall-rules"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-rules.html
#
######################################################################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
# PORT(S) PORT(S) DEST LIMIT GROUP
Web(DNAT) red grn:172.16.0.2
#Вариант, если у нас несколько внешних адресов, а мы хотим DNAT только с одного из них:
#Web(DNAT) red grn:172.16.0.2 - - - 192.168.10.37
#Варианты, все руками:
#DNAT red grn:172.16.0.2 tcp 80,443
#DNAT red grn:172.16.0.2 tcp 80,443 - 192.168.10.37
#Вариант с нестандартными портами:
#DNAT red grn:172.16.0.2:80 tcp 8080
Кроме всего, Shorewall поддерживает ipsets (проверим, что пакет установлен: yum install ipset), которые просто являются именованными списками адресов. Полезно, когда нужно выполнить настройку некого правила для группы хостов, которые невозможно объединить в подсеть.
В конфигах их использовать не сложно, достаточно везде, где используются адреса или подсети, прописать +<имя ipsets>.
Если мы хотим, что-бы Shorewall сохранял и восстанавливал нам ipsets при своих перезапусках, то нужно установить SAVE_IPSETS=Yes в файле shorewall.conf
Вот как может выглядеть конфигурация с использованием и без ipsets:
rules
#
# Shorewall -- /etc/shorewall/rules
#
# For information on the settings in this file, type "man shorewall-rules"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-rules.html
#
######################################################################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
# PORT(S) PORT(S) DEST LIMIT GROUP
#Без ipsets
OpenVPN(ACCEPT) red:192.168.10.4,192.168.23.2 $FW
#С ipsets
OpenVPN(ACCEPT) red:+ovpn_allow $FW
Для начала объявим наш ipsets:
#Используем тип iphash (кроме него есть еще куча типов, рекомендую читать man ipset для прояснения всех аспектов)
ipset -N ovpn_allow iphash
#Добавим в него наши адреса
ipset -A ovpn_allow 192.168.10.4
ipset -A ovpn_allow 192.168.23.2
Вот и все, можем посмотреть, что у нас записалось: ipset -L
Name: ovpn_allow
Type: hash:ip
Revision: 1
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16560
References: 0
Members:
192.168.23.2
192.168.10.4
Простая балансировка нагрузки и резервирование в Shorewall
Скажу сразу, и балансировка и резервирование, только лишь настраиваются с помощью Shorewall, сам он не предоставляет никакого функционала по обнаружению пропажи канала или равномерному распределения реальной нагрузки.
Вся настройка сводится к редактированию одного файла:
providers
#
# Shorewall -- /etc/shorewall/providers
#
# For information about entries in this file, type "man shorewall-providers"
#
# For additional information, see http://shorewall.net/MultiISP.html
#
############################################################################################
#NAME NUMBER MARK DUPLICATE INTERFACE GATEWAY OPTIONS COPY
pr1 1 0x10000 - $IF_RED1 $GW_RED1 track,fallback=1
pr2 2 0x20000 - $IF_RED2 $GW_RED2 track,fallback=4
Если кто помнит, в прошлой статье была секция из «Shorewall.conf». Она нужна как раз для настройки маркировки пакетов и работе с провайдерами. Там мы задали, какие биты из метки пакета, задают идентификатор провайдера, какие просто метки (я такие пока нигде не использую, но Shorewall сам их задействует, для своих нужд), а какие для отслеживания соединений.
Тут мы описали двух провайдеров, задали как маркировать пакеты для них, на каком интерфейсе каждый сидит и какой у кого шлюз.
Вот столбец OPTIONS, надо пояснить немного. Тут ключ fallbaсk заставляет сгенерировать дополнительные правила маршрутизации, на случай если балансировочные не смогут обработать пакет (интерфейс прилег к примеру), а циферка задает вес интерфейса. Параметр track, говорит о необходимости отслеживать, в какого провайдера пошло соединение, и посылать следующий пакет, от этого соединения, в того же провайдера (если в shorewall.conf установлена TRACK_PROVIDERS=Yes, то эта опция прописывается автоматически всем провайдерам).Чем вес больше, тем чаще в интерфейс будут поступать новые соединения (используется в итоге относительный вес, у кого в пропорции вес выше, туда и трафик чаще, задавать большое значение веса не рекомендуется). Балансировка происходит по принципу roundrobin уже самим ядром и базируется на факте установления соединения по маршруту клиент-сервер (в качестве клиента ваш маршрутизатор, а сервер соответственно, удаленный сервер). При этом маршруты кэшируются на некоторое время, и получается такой эффект: кто-то в локалке, полез к примеру на некий сайт (у которого один IP), трафик пошел через провайдера 1, затем кто-то еще полез туда же, и трафик побежит опять через провайдера 1 (если кэш не успел сбросится). Еще может получится, что у вас не симметричные провайдеры, как в примере, и так повезет, каждое четвертое соединение, попадающие на первого провайдера, окажется и самым «тяжелым», а мы хотели этого избежать… Тут уже простых решений нет, и эта статья вам никак не поможет.
Но, не все так плохо, и даже так оно работает достойно (к слову сказать, так оно работает у большинства решений, для «честной» балансировки используются весьма не простые решения, которые часто без поддержки на стороне провайдеров (обоих) не работают).
Дополненный файл переменных:
params
#
# Shorewall -- /etc/shorewall/params
#
# Assign any variables that you need here.
#
# It is suggested that variable names begin with an upper case letter
# to distinguish them from variables used internally within the
# Shorewall programs
#
# Example:
#
# NET_IF=eth0
# NET_BCAST=130.252.100.255
# NET_OPTIONS=routefilter,norfc1918
#
# Example (/etc/shorewall/interfaces record):
#
# net $NET_IF $NET_BCAST $NET_OPTIONS
#
# The result will be the same as if the record had been written
#
# net eth0 130.252.100.255 routefilter,norfc1918
#
###############################################################################
IF_RED1=eth0
GW_RED1=192.168.10.1
IF_RED2=eth2
GW_RED2=detect
IF_GRN=eth1
NET_GRN=172.16.0.0/23
IF_TUN=tap+
#LAST LINE -- DO NOT REMOVE
Можно заметить, что у второго провайдера шлюз указан как ключевое слово «detect», которое работает на соединениях с динамической адресацией. Для некоторый случаев (к примеру PPtP), сам Shorewall не может корректно определить шлюз, для чего используется файл с вспомогательным скриптом:
findgw
#
# Shorewall version 4 - Findgw File
#
# /etc/shorewall/findgw
#
# The code in this file is executed when Shorewall is trying to detect the
# gateway through an interface in /etc/shorewall/providers that has GATEWAY
# specified as 'detect'.
#
# The function should echo the IP address of the gateway if it knows what
# it is; the name of the interface is in $1.
#
# See http://shorewall.net/shorewall_extension_scripts.htm for additional
# information.
#
###############################################################################
LANG='C' nmcli --terse --fields IP6.GATEWAY device show ${1} | cut -f2- -d':' #IPv6
LANG='C' nmcli --terse --fields IP4.GATEWAY device show ${1} | cut -f2- -d':' #IPv4
И важно, нужно все это правильно замаскировать:
masq
#
# Shorewall -- /etc/shorewall/masq
#
# For information about entries in this file, type "man shorewall-masq"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-masq.html
#
###################################################################################################################################
#INTERFACE:DEST SOURCE ADDRESS PROTO PORT(S) IPSEC MARK USER/ SWITCH ORIGINAL PROBABILITY
# GROUP DEST
$IF_RED1 $NET_GRN detect
$IF_RED2 $NET_GRN detect
Параметр detect, в столбце ADDRESS, заставляет определить исходящий адрес на интерфейсе для SNAT (при нескольких провайдерах становится необходимым).
И дополнит все это скрипт для NetworkManager (более простая версия была в прошлой статье, и она не учитывала, что после поднятия интерфейса, Shorewall не всегда корректно строит политику маршрутизации, поэтому мы для таких интерфейсов просто его перезапускаем).
/etc/NetworkManager/dispatcher.d/30-shorewall.sh
#!/bin/bash
IF=$1 # имя сетевого интерфейса, с которым связано событие
STATUS=$2 # новое состояние сетевого интерфейса
function check_prov() {
PARAM=$(grep -v '^#' /etc/shorewall/params | grep $1 | cut -d '=' -f 1)
if [ -z "$PARAM" ]; then
grep -v '^#' /etc/shorewall/providers | grep -q $1
[[ $? == 0 ]] && shorewall restart
else
grep -v '^#' /etc/shorewall/providers | grep -q $PARAM
[[ $? == 0 ]] && shorewall restart
fi
}
case $STATUS in
up)
# команды выполняемые после установления соединения
shorewall enable $IF
shorewall6 enable $IF
check_prov $IF
;;
down)
# команды выполняемые после разрыва соединения
shorewall disable $IF
shorewall6 disable $IF
check_prov $IF
;;
esac
Дав команду, после shorewall restart:
shorewall show routing
Можно увидеть построенную схему маршрутизации:
Пример маршрутизации
Shorewall 5.0.2.1 Routing at cent1.domain.local - Пт янв 8 23:41:30 MSK 2016
Routing Rules
0: from all lookup local
999: from all lookup main
10000: from all fwmark 0x10000/0xff0000 lookup pr1
10001: from all fwmark 0x20000/0xff0000 lookup pr2
20000: from 192.168.10.37 lookup pr1
20000: from 192.168.10.36 lookup pr2
32765: from all lookup balance
32767: from all lookup default
Table balance:
Table default:
default nexthop via 192.168.10.1 dev eth0 weight 1 nexthop via 192.168.10.1 dev eth2 weight 1
Table local:
local 192.168.10.37 dev eth0 proto kernel scope host src 192.168.10.37
local 192.168.10.36 dev eth2 proto kernel scope host src 192.168.10.36
local 172.16.3.1 dev tap0 proto kernel scope host src 172.16.3.1
local 172.16.3.129 dev tap1 proto kernel scope host src 172.16.3.129
local 172.16.248.1 dev lo proto kernel scope host src 172.16.248.1
local 172.16.0.1 dev eth1 proto kernel scope host src 172.16.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 192.168.10.255 dev eth2 proto kernel scope link src 192.168.10.36
broadcast 192.168.10.255 dev eth0 proto kernel scope link src 192.168.10.37
broadcast 192.168.10.0 dev eth2 proto kernel scope link src 192.168.10.36
broadcast 192.168.10.0 dev eth0 proto kernel scope link src 192.168.10.37
broadcast 172.16.3.255 dev tap1 proto kernel scope link src 172.16.3.129
broadcast 172.16.3.128 dev tap1 proto kernel scope link src 172.16.3.129
broadcast 172.16.3.127 dev tap0 proto kernel scope link src 172.16.3.1
broadcast 172.16.3.0 dev tap0 proto kernel scope link src 172.16.3.1
broadcast 172.16.248.1 dev lo proto kernel scope link src 172.16.248.1
broadcast 172.16.1.255 dev eth1 proto kernel scope link src 172.16.0.1
broadcast 172.16.0.0 dev eth1 proto kernel scope link src 172.16.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
Table main:
192.168.10.1 dev eth2 scope link src 192.168.10.36
172.16.3.1 dev tap0 proto zebra
172.16.3.129 dev tap1 proto zebra
172.16.248.2 via 172.16.3.2 dev tap0 proto zebra metric 13
172.16.12.129 via 172.16.3.2 dev tap0 proto zebra metric 3
172.16.11.1 via 172.16.3.2 dev tap0 proto zebra metric 3
172.16.3.128/25 dev tap1 proto kernel scope link src 172.16.3.129
172.16.3.0/25 dev tap0 proto kernel scope link src 172.16.3.1
192.168.10.0/24 dev eth2 proto kernel scope link src 192.168.10.36 metric 101
192.168.10.0/24 dev eth0 proto kernel scope link src 192.168.10.37 metric 100
172.16.8.0/23 via 172.16.3.2 dev tap0 proto zebra metric 13
172.16.0.0/23 dev eth1 proto kernel scope link src 172.16.0.1 metric 100
Table pr1:
192.168.10.1 dev eth0 scope link src 192.168.10.37
default via 192.168.10.1 dev eth0 src 192.168.10.37
Table pr2:
192.168.10.1 dev eth2 scope link src 192.168.10.36
default via 192.168.10.1 dev eth2 src 192.168.10.36
Но, можно ли направить какой либо трафик по конкретному провайдеру? Ответ Да!
mangle
#
# Shorewall -- /etc/shorewall/mangle
#
# For information about entries in this file, type "man shorewall-mangle"
#
# See http://shorewall.net/traffic_shaping.htm for additional information.
# For usage in selecting among multiple ISPs, see
# http://shorewall.net/MultiISP.html
#
# See http://shorewall.net/PacketMarking.html for a detailed description of
# the Netfilter/Shorewall packet marking mechanism.
#
####################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE USER TEST LENGTH TOS CONNBYTES HELPER PROBABILITY DSCP
# PORT(S) PORT(S)
MARK(0x20000):P 172.16.0.4 0.0.0.0/0!172.16.0.0/12
Тут мы пометили весь трафик от 172.16.0.4 в любую сеть, кроме 172.16.0.0/12, меткой второго провайдера. Условия могут быть и хитрее, надо только учитывать, для трафика сгенерированного на нашем шлюзе, из правила нужно убрать ":P".
Страшный и ужасный QoS
Сразу надо пояснить вот что: по настоящему регулировать скорость мы можем только при отправке. Входящий трафик, уже дошел до нашего интерфейса минуя все узкие места, и толкаясь в очередях, за право оказаться у нас на пороге.
Но отчаиваться рано, и есть механизмы, не столь изящные и надежные, как хотелось бы, но решающие эту проблему. В сетях на базе протоколов семейства IP, это решается таким образом:
Источник плавно наращивает скорость отправки, пока ответы о доставке (пакеты ACK в протоколе TCP) вообще приходят или приходят с нормальной задержкой. Если есть потери или растет задержка ACK, скорость снижается. Потом, спустя некоторый промежуток времени, скорость пытаются вновь поднять. И так происходит до окончания передачи.
А как же UDP? А с ним все просто, нет контроля доставки, нет головной боли. Отправил и ОК (это пусть получатель мучается).
Конечно, в чистом виде UDP обычно не используют в сложных задачах по передаче данных. Этот протокол обычно используют как основу, при реализации своего варианта контроля доставки (можно сказать, своих реализаций TCP, в случаях, когда стандартный не устраивает). Поэтому во многих протоколах работающих поверх UDP, контроль доставки тоже есть. Что не отменяет возможности слать непрерывный поток UDP во всю мощь, забивая канал связи цели (тот самый вариант DDoS).
Как же мы можем организовать приоритезацию трафика и выделения полосы пропускания входящего трафика? Ответ есть выше: создать задержку в получении на своей стороне (как следствие, задержку в генерации ACK) или если задержка неприлично высока, пакет отбросить.
В Linux это реализуется созданием псевдо-интерфейса IFB, который как бы встает между физическим интерфейсом и самим шлюзом, пропуская через себя входящий трафик. Трафик входит в физический интерфейс (мы его уже приняли на нем), и тут же отправляется в IFB, который уже регулирует, с какой скоростью, и в каком порядке пропустить этот трафик (или вообще отбросить).
В настройке нам поможет Shorewall (хотя можно и в /etc/modprobe.d прописать):
/etc/shorewall/init
#
# Shorewall -- /etc/shorewall/init
#
# Add commands below that you want to be executed at the beginning of
# a "shorewall start", "shorewall-reload" or "shorewall restart" command.
#
# For additional information, see
# http://shorewall.net/shorewall_extension_scripts.htm
#
###############################################################################
modprobe ifb numifbs=3
ip link set ifb0 up
ip link set ifb1 up
ip link set ifb2 up
Тут тривиально, создали три псевдо-интерфейса IFB и их подняли.
Далее опишем интерфейсы, на которых мы будем регулировать трафик:
tcdevices
#
# Shorewall -- /etc/shorewall/tcdevices
#
# For information about entries in this file, type "man shorewall-tcdevices"
#
# See http://shorewall.net/traffic_shaping.htm for additional information.
#
###############################################################################
#NUMBER: IN-BANDWITH OUT-BANDWIDTH OPTIONS REDIRECTED
#INTERFACE INTERFACES
1:$NET_GRN - 1000mbit hfsc,classify
2:ifb1 - 1000mbit hfsc,classify $NET_GRN
3:$NET_RED1 - 10mbit hfsc,classify
4:ifb0 - 10mbit hfsc,classify $NET_RED1
5:$NET_RED2 - 10mbit hfsc,classify
6:ifb2 - 10mbit hfsc,classify $NET_RED2
Тут мы в явном виде, задаем номера используемых интерфейсов (если не задать, Shorewall пронумерует их в порядке объявления файле), ассоциировали IFB с реальными интерфейсами, задали максимальную исходящую скорость (помним, только её мы и регулируем, и интерфейс ifb по сути это входящая линия) и задали дисциплины классификации и что трафик мы будем именно классифицировать.
Важно! Скорость нужно установить чуть-чуть ниже скорости, которую дает провайдер. Если скорость, которой мы оперируем будет выше чем дает нам провайдер, то и ограничение полосы пропускания случится на его стороне, а значит и все наши потуги на классификацию и т.п. (не совсем полностью, но значительной степени) окажутся тщетны. На каналах с переменной пропускной способностью QoS сделать очень не просто, так как из всех рабочих инструментов у вас будет только переупорядочивание пакетов, в надежде, что ценный трафик пролезет через канал (страдальцы на радиоканалах грустно вздыхают).
Опишем те самые классы:
tcclasses
#
# Shorewall -- /etc/shorewall/tcclasses
#
# For information about entries in this file, type "man shorewall-tcclasses"
#
# See http://shorewall.net/traffic_shaping.htm for additional information.
#
###############################################################################
#INTERFACE:CLASS MARK RATE: CEIL PRIORITY OPTIONS
# DMAX:UMAX
1:1:2 - 1mbit 3mbit 2 default
1:1:3 - 256kbit full 1
2:1:2 - 1mbit 3mbit 2 default
2:1:3 - 256kbit full 1
3:1:2 - 1mbit 3mbit 2 default
3:1:3 - 256kbit full 1
4:1:2 - 1mbit 3mbit 2 default
4:1:3 - 256kbit full 1
5:1:2 - 1mbit 3mbit 2 default
5:1:3 - 256kbit full 1
6:1:2 - 1mbit 3mbit 2 default
6:1:3 - 256kbit full 1
Пока не будем делать ничего сложного (и оттого интересного и полезного), пока привяжем к каждому интерфейсу (включая IFB) по два класса.
В первом столбце мы ассоциируем интерфейс с классами. <номер интерфейса>:<номер родительского класса>:<номер описываемого класса>.
На интерфейсе всегда есть класс 1, который мы по сути, описали в tcdevices.
Далее, пакеты мы не маркировали, и потому столбец использовать не будем, дальше идет самое интересное, минимально гарантированная полоса пропускания, и максимально возможная (не больше чем таковая у класса родителя), для данного класса. Приоритет задаст порядок разрешения спорной ситуации (у кого меньше, тот и пойдет первым, если вышел за приделы гарантированной полосы, и она уже кем-то другим занята полностью). В заключении идут опции, default говорит о том, что если фильтрами ничего не найдено (пакеты не отнесены к классам), то присвоить им класс по умолчанию).
Дальше, так исторически сложилось, что правила классификации реальных интерфейсов, находятся в файле:
mangle
#
# Shorewall -- /etc/shorewall/mangle
#
# For information about entries in this file, type "man shorewall-mangle"
#
# See http://shorewall.net/traffic_shaping.htm for additional information.
# For usage in selecting among multiple ISPs, see
# http://shorewall.net/MultiISP.html
#
# See http://shorewall.net/PacketMarking.html for a detailed description of
# the Netfilter/Shorewall packet marking mechanism.
#
####################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE USER TEST LENGTH TOS CONNBYTES HELPER PROBABILITY DSCP
# PORT(S) PORT(S)
CLASSIFY(1:3) 0.0.0.0/0 0.0.0.0/0 tcp - 80,443
CLASSIFY(3:3) 0.0.0.0/0 0.0.0.0/0 tcp 80,443
А для виртуальных IFB в:
tcfilters
#
# Shorewall -- /etc/shorewall/tcfilters
#
# For information about entries in this file, type "man shorewall-tcfilters"
#
# See http://shorewall.net/traffic_shaping.htm for additional information.
#
########################################################################################################
#INTERFACE: SOURCE DEST PROTO DEST SOURCE TOS LENGTH PRIORITY
#CLASS PORT(S) PORT(S)
2:3 0.0.0.0/0 0.0.0.0/0 tcp - 80,443
4:3 0.0.0.0/0 0.0.0.0/0 tcp 80,443
В примере выше, я поместил входящий трафик от HTTP(S) сервера в класс с номером 3 на физическом интерфейсе, и на виртуальный, ассоциированный с ним, и исходящий я сделал аналогично, но «развернув порты». Очень внимательно отнеситесь к тому, что соединения часто двунаправленны, и расписывать их классификацию надо отдельно для каждого направления, не зависимо от того, кто инициировал, клиент или сервер.
Именно тут, и начинает трещать крыша. Для понимания поможет картинка (прошу ногами особо не бить, в Visio работать толком не умею).
Резать трафик в итоге можно на разных участках, не применяя IFB, если у вас один провайдер, а сам шлюз, трафик не принимает (не является его получателем). Если провайдеров больше, а шлюз сам активно принимает трафик (он к примеру обслуживает VPN), тогда без IFB выкручиваться не легко.
P.S.
В следующей статье я планирую подробнее остановится на QoS, особенно в свете распространения VoIP технологий. Тема большая, и нужно все хорошенько спланировать. Если вас интересует некий аспект более подробно, пишите запрос в комментарии, я учту пожелания в следующей статье.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
mikes
Маловато про сами правила.
Есть неявные места при варианте «все запрещено кроме разрешенного» при работе с разными сервисами, к примеру пропуск NFS, FTP с их динамическими портами. Это отсылает нас либо к настройке сервисов, либо к настройке соответствующих helper в shorewall.
Отдельно было бы неплохо упомянуть о работе с ipset в разрезе shorewall ибо рано или поздно люди к ним прийдут.
Ну и предупредить, что shorewall без helper'ов не разбирает содержимое пакетов как это делают многие из аппаратных firewall.
MagicGTS
Спасибо за замечание, внес эти правки в статью.
Тема с настройкой правил вообще большая, поэтому все равно все тонкости не раскрою, тут уже кроме как самим изучать Shorewall (и обязательно и iptables) вариантов нет.