В этих статьях мы рассмотрим построение интернет шлюза на linux, позволяющего связать несколько офисов компании, и обеспечить ограниченный доступ в сеть, приоритетзацию трафика (QoS) и простую балансировку нагрузки с резервированием канала между двумя провайдерами.
Конкретно в этой части:
- Простейшая настройка Shorewall
- Ужасно сложная настройка dnsmasq
- Не менее сложная настройка OpenVPN
- И для многих продолжающих админов нетипичная, динамическая маршрутизация, на примере OSPF
А во второй части будут рассмотрены:
- Более подробная настройка Shorewall
- Страшный и не понятный QoS
- Балансировка нагрузки и резервирование
В третьей части:
- QoS во всю ширь в Shorewall
- Более подробная настройка Shorewall
- Раскидывание трафика по каналам в соответствии с протоколами
- Костыли, без них, никуда
Все описанное ниже справедливо для CentOS 7.1 (и выше, 6 серия тоже подойдет, но с небольшими особенностями)
Исходим из того, что у нас:
- Локалка первого филиала: 172.16.0.0/23
- Подсеть OpenVPN первого филиала: 172.16.3.0/25
- Второй филиал соответственно: 172.16.8.0/23 и 172.16.11.0/25
Вообще мой ip план подразумевал резервацию /21 сети для каждого филиала из диапазона 172.16.0.0/12. Каждый диапазон /21 нарезается на подсети для различных нужд (подробнее в следующей статье).
Простейшая настройка Shorewall
Для тех кто не слышал раньше, Shorewall это надстройка над утилитой iptables для конфигурирования NetFilter в ядре Linux. Сама по себе iptables не слишком сложная, но когда конфигурация шлюза становится большой и от этого сложной, разобраться в таком объеме команд iptables становиться не просто.
На помощь в таких ситуациях приходят различные самопальные скрипты или, уже давно не самопальные, системы аналогичные Shorewall.
В Shorewall все вертится вокруг понятия «зона». В зону включаются хосты (путем задания интерфейсов или непосредственно сетей и/или отдельных адресов).
#
# Shorewall -- /etc/shorewall/zones
#
# For information about this file, type "man shorewall-zones"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-zones.html
#
###############################################################################
#ZONE TYPE OPTIONS IN OUT
# OPTIONS OPTIONS
fw firewall
red ipv4
grn ipv4
tun ipv4
Тут я определил три зоны (для протокола ipv4), помимо специальной зоны «fw», которая олицетворяет сам шлюз.
- red — зона интернета
- grn — зона локальной сети
- tun — зона для наших туннелей
Пришло время поместить в эти зоны интерфейсы (отдельные хосты мы пока не будем использовать), но перед этим внесем некоторые правки в файл:
#
# 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
IF_GRN=eth1
NET_GRN=172.16.0.0/23
IF_TUN=tap+
#LAST LINE -- DO NOT REMOVE
В этом файле можно задать различные переменные, которые будем потом использовать в других файлах, и которые помогают сделать конфиг более переносимым между системами. Сейчас у нас тут прописаны наши физические интерфейсы и локальная подсеть филиала. Обратите внимание, tap+ говорит об использовании маски, под которую попадает любой tapX (кроме просто «tap»).
Ну а теперь файл:
#
# Shorewall -- /etc/shorewall/interfaces
#
# For information about entries in this file, type "man shorewall-interfaces"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-interfaces.html
#
###############################################################################
?FORMAT 2
###############################################################################
#ZONE INTERFACE OPTIONS
red $IF_RED1 dhcp,routeback,optional
grn $IF_GRN dhcp,routeback,optional
tun $IF_TUN dhcp,routeback,optional
Тут тоже ничего особенно сложного, опции говорят нам, что:
- dhcp — на интерфейсе может работать DHCP протокол (как клиент так и сервер)
- routeback — пригодится в будущем, заставляет возвращать ответы через тот же интерфейс, откуда пришли запросы
- optional — говорит, что не надо паниковать, если интерфейс не активен (если Shorewall не находит обязательный интерфейс, то он не стартует целиком)
Внесем несколько изменений в файл «shorewall.conf», он довольно большой, приведу его усеченный вид (только измененные значения):
###############################################################################
#
# Shorewall Version 5 -- /etc/shorewall/shorewall.conf
#
# For information about the settings in this file, type "man shorewall.conf"
#
# Manpage also online at http://www.shorewall.net/manpages/shorewall.conf.html
###############################################################################
# S T A R T U P E N A B L E D
###############################################################################
STARTUP_ENABLED=Yes
###############################################################################
# F I R E W A L L O P T I O N S
###############################################################################
BLACKLIST="ALL"
CLAMPMSS=Yes
IP_FORWARDING=Yes
################################################################################
# P A C K E T M A R K L A Y O U T
################################################################################
TC_BITS=14
PROVIDER_BITS=8
PROVIDER_OFFSET=16
MASK_BITS=16
ZONE_BITS=0
Все параметры достаточно понятны, но секция «PACKET MARK LAYOUT» будет рассмотренная в следующих частях, «BLACKLIST» задает тип блокируемых пакетов (всех) для забаненых адресов, тоже на будущее.
Пришло время для создания политик по умолчанию:
#
# 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 ACCEPT
grn all ACCEPT
red all DROP
tun grn ACCEPT
tun red REJECT
tun $FW ACCEPT
Ключевые слова значат следующие:
- ACCEPT — принимать (в том числе форвардить) пакеты
- REJECT — Отбросить пакет, а отправителю сообщить, что писем мы от него не ждем
- DROP — Отбросить пакет, и загадочно осмотревшись, никому ничего не сказать
В третий столбец можно прописать еще несколько параметров, один из которых info, задаст логирование данной политики (имеет смысл для DROP и REJECT, а то ACCEPT завалит вас логами).
Заданная политика примитивна и не годится для серьезных проектов, соответствует настройке большинства домашних роутеров, но для самого старта она нам подойдет.
Осталось чуть чуть, а именно настроить маскарадинг (чего в эпоху IPv6 делать будет не надо):
#
# 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
Очевидно, все что идет в сторону интерфейса $IF_RED1 из сети $NET_GRN нужно замаскировать. Третий столбец ADDRESS используется для SNAT.
Для отслеживания и соответствующего изменения правил файрвола, в ответ на включение\отключение интерфейса, нам поможет небольшой скрипт:
#!/bin/bash
IF=$1 # имя сетевого интерфейса, с которым связано событие
STATUS=$2 # новое состояние сетевого интерфейса
case $STATUS in
up)
# команды выполняемые после установления соединения
shorewall enable $IF
shorewall6 enable $IF
;;
down)
# команды выполняемые после разрыва соединения
shorewall disable $IF
shorewall6 disable $IF
;;
esac
Дав команду «systemctl enable shorewall.service && systemctl restart shorewall.service», мы применим настройки нашего файрвола, и у нас ничего (ну почти), не заработает, нам не хватает самой малости: нет кэширующего DNS И DHCP серверов (не будем же мы сами все клиентские машины настраивать).
Простейшая настройка dnsmasq
Эта служба очень неплохо справляется со своей задачей, и сеть /23 для неё не является проблемой, а простота и гибкость настроек делает её очень подходящей для нашей ситуации.
Так как файл настроек большой, приведу и его тоже в урезанном виде:
# Configuration file for dnsmasq.
#
# Format is one option per line, legal options are the same
# as the long options legal on the command line. See
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
# If you want dnsmasq to listen for DHCP and DNS requests only on
# specified interfaces (and the loopback) give the name of the
# interface (eg eth0) here.
# Repeat the line for more than one interface.
interface=eth1
# Set the domain for dnsmasq. this is optional, but if it is set, it
# does the following things.
# 1) Allows DHCP hosts to have fully qualified domain names, as long
# as the domain part matches this setting.
# 2) Sets the "domain" DHCP option thereby potentially setting the
# domain of all systems configured by DHCP
# 3) Provides the domain part for "expand-hosts"
domain=domain.local
# This is an example of a DHCP range where the netmask is given. This
# is needed for networks we reach the dnsmasq DHCP server via a relay
# agent. If you don't know what a DHCP relay agent is, you probably
# don't need to worry about this.
dhcp-range=172.16.0.50,172.16.0.150,255.255.254.0,12h
# Set the DHCP server to authoritative mode. In this mode it will barge in
# and take over the lease for any client which broadcasts on the network,
# whether it has a record of the lease or not. This avoids long timeouts
# when a machine wakes up on a new network. DO NOT enable this if there's
# the slightest chance that you might end up accidentally configuring a DHCP
# server for your campus/company accidentally. The ISC server uses
# the same option, and this URL provides more information:
# http://www.isc.org/files/auth.html
dhcp-authoritative
Думаю пояснять тут ничего особо не надо, задали интерфейс, на котором обслуживать DNS и DHCP запросы, задали диапазон раздаваемых адресов, задали некоторые передаваемые в DHCP параметры и задали авторитарный режим работы.
Теперь после «systemctl enable dnsmasq.service && systemctl restart dnsmasq.service» у нас заработает доступ в интернет с внутренних клиентов (как только аренду DHCP получат).
Настройка OpenVPN
Думаю это часть не составит особого труда вообще никому, но приведем эти шаги:
- Из epel установим пакеты: openvpn easy-rsa
- Скопируем из /usr/share/easy-rsa папку в /etc/openvpn и переименуем её в easy-rsa
- Перейдем в /etc/openvpn/easy-rsa и при необходимости отредактируем файл vars
- Выполним: ". ./vars && ./clean-all && ./build-dh && openvpn --genkey --secret ./keys/ta.key &&./build-ca && ./build-key-server server #привет от гентушника (как установить Gentoo одной командой, да и такое возможно)!
Еще нам понабиться файл конфигурации сервера:
port 1194
proto udp
topology subnet
dev tap0
ca ./easy-rsa/keys/ca.crt
cert ./easy-rsa/keys/server.crt
key ./easy-rsa/keys/server.key
dh ./easy-rsa/keys/dh1024.pem
client-config-dir ./ccd/inter-lan/
client-to-client
keepalive 10 120
tls-server
tls-auth ./easy-rsa/keys/ta.key 0
cipher AES-256-OFB
comp-lzo no
auth SHA256
status /var/run/openvpn/inter-lan.status
sndbuf 393216
rcvbuf 393216
push "sndbuf 393216"
push "rcvbuf 393216"
mode server
push "topology subnet"
ifconfig 172.16.3.1 255.255.255.128
ifconfig-pool 172.16.3.2 172.16.3.126 255.255.255.128
ifconfig-pool-persist /var/run/openvpn/inter-lan.db 3600
verb 1
Файл умолчательных параметров передаваемых OpenVPN для клиента:
push "comp-lzo no"
Файл клиентского шаблона конфигурации:
client
port 1194
dev tap4
proto udp
remote <тут адрес вашего сервера> 1194
tls-client
ns-cert-type server
cipher AES-256-OFB
auth SHA256
verb 1
comp-lzo no
<ca>
-----CERTIFICATE-CA-----
</ca>
<cert>
-----CERTIFICATE-----
</cert>
<key>
-----KEY-----
</key>
key-direction 1
<tls-auth>
-----TLS-----
</tls-auth>
И вспомогательный самописный скриптик:
#!/bin/bash
# $2 - дает команду сгенерировать новые ключи для клиента
[ "$2" == "-r" ] && ./build-key $1
CWD=$(pwd)
RUN=$(dirname $0)
cd "$RUN"
mkdir -p ../ovpn/$1
for i in $(ls -1 ./templates/); do
TEMPLATE=$(basename $i .conf)
sed -e '/-----CERTIFICATE-CA-----/{r /etc/openvpn/easy-rsa/keys/ca.crt' -e 'd}' ./templates/${TEMPLATE}.conf | sed -e '/-----CERTIFICATE-----/{r /etc/openvpn/easy-rsa/keys/'"$1.crt"'' -e 'd}' | sed -e '/-----KEY-----/{r /etc/openvpn/easy-rsa/keys/'"$1.key"'' -e 'd}' | sed -e '/-----TLS-----/{r /etc/openvpn/easy-rsa/keys/ta.key' -e 'd}' > ../ovpn/$1/${TEMPLATE}-$1.ovpn
done
cd "$CWD"
Я использую интерфейс типа tap, потому, что tun маршрутизируется ядром OpenVPN, и конфигурируется это все директивой iroute. И печаль такова, если за одним сервером, будет еще один, к которому нам нужен маршрут, этот маршрут нам надо в явном виде прописывать в ccd, той самой директивой iroute, что помимо обычных маршрутов создаст лишние трудности (о каких трудностях я говорю, написано в разделе OSPF).
Теперь сгенерим конфигурацию для клиента:
./build-ovpn.sh <имя клиента> -r
Создадим файл ccd для клиента:
# Тут могли быть параметры, если бы они нам были нужны :), поэтому удалим его, пусть использует DEFAULT
После надо скопировать файл из каталога /etc/openvpn/ovpn/<имя клиента>/<имя клиента>.ovpn на клиентский компьютер (шлюз) и поместить его в /etc/openvpn/ с расширением ".conf"
Запускаем openvpn на клиенте и сервере:
systemctl enable openvpn@<имя conf файла без расширения conf>.service && systemctl start openvpn@<имя conf файла без расширения conf>.service
А результат есть только на сервере! Клиент в непонятках. Во всем виноват shorewall, а точнее, наша политика, мы не разрешили соединения из интернета (red зона)!
Внесем разрешающее правило в файл:
#
# 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
#Правило ниже использует макрос из: /usr/share/shorewall/macro.OpenVPN
#Макросов там достаточно, свои можно помещать в /etc/shorewall, а также переопределять там дефолтовые
OpenVPN(ACCEPT) red $FW
#Тоже самое, но без макроса было бы так:
#ACCEPT red $FW udp 1194
Выполняем «shorewall restart» и видим, что клиент успешно подключился.
Попробуем попинговать ip клиента, выданный OpenVPN, все Ok. Теперь сеть за клиентом (172.16.8.0/23), и опять облом, ip в туннеле пингуется, а сеть нет, так как нет маршрутов, их нам и предоставит OSPF.
Настройка протокола динамической маршрутизации OSPF в quagga
Тут на хабре есть серия больших статей посвященных динамической маршрутизации, тому как оно работает, и т.д., тут же я дам некоторую практическую выжимку из них и саму настройку.
К использованию OSPF я пришел после того, как компания в которой я работаю, обзавелась почти десятком филиальчиков и представительств, и туннели между ними были построены не только звездой, но и были еще прямые между отдельными филиалами (чтобы наиболее активно взаимодействующие ходили по прямой, а не в центральный узел). Когда я малость припух от числа маршрутов и мест их настройки, соорудил велосипед (скрипт, который перестраивал статические конфиги маршрутов по прописанной карте), велосипед был красивый, колеса шестиугольные, педалей десять, и для езды ты его катишь, сам идя рядом… Ну его в болото, подумал я, и по быстрому выяснил про OSPF и начал внедрение.
Нам понадобится пакет quagga, после установки, скопируем файл начальной конфигурации и запустим службу:
cp /usr/share/doc/quagga-0.99.22.4/ospfd.conf.sample /etc/quagga/ospfd.conf && chown quagga. /etc/quagga/ospfd.conf
systemctl enable ospfd.service && systemctl start ospfd.service
Теперь нам понабиться настроить ip адрес на loopback интерфейсе, который помимо прочего (смысл вы найдете в других статьях), будет выполнять роль router-id.
В файл /etc/sysconfig/network-scripts/ifcfg-lo добавим строки:
IPADDR2=172.16.248.1
NETMASK2=255.255.255.255
И повторно подымим интерфейс: ifup lo
Теперь подключимся к службе ospfd и проведем её настройку:
telnet localhost ospfd
#пароль по умолчанию zebra
ospfd# enable #Включит режим привилегированных команд
ospfd# configure terminal #переход в режим конфигурирования
ospfd(config)# password <пароль> #задаст пароль на консоль управления
ospfd(config)# hostname <имя хоста> #задаст имя шлюза, хотя это не обязательно
ospfd(config)# log syslog #пусть логи идут в системный журнал
ospfd(config)# interface <в нашем случае tap0> #настроим интерфейс
ospfd(config-if)# ip ospf network point-to-multipoint #Задает для tap интерфейса его тип (важно для правильного построения топологии, по умолчанию определяет не верно для наших конфигураций)
ospfd(config-if)# exit #выходим из текущего режима
ospfd(config)# router ospf #переход в настройку ospf
ospfd(config-router)# router-id 172.16.248.1 #задаем наш идентификатор
ospfd(config-router)# passive-interface default #Отключим OSPF на всех интерфейсах
ospfd(config-router)# no passive-interface <имя интерфейса> #Несколько раз выполним для всех, где у нас будет взаимодействии по протоколу ospf (в нашем случае это только tap0)
ospfd(config-router)# network 172.16.0.0/12 area 0.0.0.0 #Задаем сеть, для которой будут строится маршруты, также задает интерфейсы, по которым будет происходить взаимодействие. Сеть с маской /12 охватывает все частное пространство, в котором мы для себя нарезали подсети
ospfd(config-router)# write memory #сохранит текущую настройку в файл
Итоговый файл конфигурации:
!
! Zebra configuration saved from vty
! 2016/01/05 14:20:08
!
hostname ospfd
password zebra
log stdout
log syslog
!
!
!
interface eth0
!
interface eth1
!
interface lo
!
interface tap0
ip ospf network point-to-multipoint
ip ospf cost 3
!
router ospf
ospf router-id 172.16.248.1
passive-interface default
no passive-interface tap0
network 172.16.0.0/12 area 0.0.0.0
!
line vty
!
Можно заметить, что файл отражает команды конфигурации что мы вводили в консоль. Разве, что можно заметить «ip ospf cost 3», которым я указал стоимость интерфейса (опять на будущие, когда будут разные маршруты до одной точки).
Скопировав этот файл на другой шлюз (который связан с этим по OpenVPN) и внеся туда соответствующие правки, мы получим рабочую конфигурацию между двумя шлюзами (службу ospfd на втором шлюзе тоже надо запустить).
Теперь команда «ip route list» должна показать нам нечто подобное:
default via 192.168.10.1 dev eth0 proto static metric 100
172.16.0.0/23 dev eth1 proto kernel scope link src 172.16.0.1 metric 100
172.16.3.0/25 dev tap0 proto kernel scope link src 172.16.3.1
172.16.3.1 dev tap0 proto zebra
172.16.8.0/23 via 172.16.3.2 dev tap0 proto zebra metric 13
172.16.11.1 via 172.16.3.2 dev tap0 proto zebra metric 3
172.16.12.129 via 172.16.3.2 dev tap0 proto zebra metric 3
172.16.248.2 via 172.16.3.2 dev tap0 proto zebra metric 13
192.168.10.0/24 dev eth0 proto kernel scope link src 192.168.10.37 metric 100
192.168.10.1 dev eth0 scope link src 192.168.10.37
Маршруты с «proto zebra» как раз добавлены с помощью OSPF.
Я рекомендую всем, используйте динамическую маршрутизацию, даже если у вас всего два филиала. Когда их станет больше, вам не составит труда добавить еще один узел в сеть.
И конечно, предложенная конфигурация OSPF довольна примитивна, более сложные варианты с примерами ждите в следующей статье (или читайте статьи более компетентных товарищей, по сути, OSPF я изучил еще не достаточно глубоко).
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (8)
Hatifnatt
09.01.2016 14:42+1Если у вас много интерфейсов, а OSPF нужен, допустим, только на одном, то неудобно писать много раз:
Можно сделать иначе:ospfd(config-router)# passive-interface <имя интерфейса>
passive-interface default no passive-interface <имя интерфейса>
А вот что мне интересно, есть ли у вас шлюзы где есть хотя бы пара интерфейсов за которыми находятся другие шлюзы и как в таком случае у вас работает OSPF, а вернее сказать как у вас в таком случае маршрутизируется мультикаст.MagicGTS
09.01.2016 14:55Спасибо за подсказку (как я и писал, OSPF пока довольно поверхностно изучил).
Пока у меня OSPF работает только для VPN и из VPN есть цепочки.
В «лаборатории» строил и длинные цепи (условно конечно, из трех узлов), кольца и альтернативные маршруты. Все «магическим» образом работало. Надо по подробнее это посмотреть (подумаю как это понанояднее проверить).MagicGTS
09.01.2016 20:54Еще раз перечитав вопрос, понял, что спрашивали про мультикаст именно OSPF протокола (для обмена данными между роутерами), и о том, как трафик обмена данными доходит до других шлюзов. Так ответ тут простой, мультикаст идет в приделах ровно одного интерфейса (его широковещательного домена). Обмен данными OSPF идет только между непосредственными соседями, дальше идет пересылка (опять в приделах одного интерфейса соседа). Обычный мультикаст в моей сети никуда не пересылается.
evg_krsk
09.01.2016 20:46Насколько помню, все IGP переносят юникастовые префиксы.
За маршрутизацию мультикаста обычно отвечают другие протоколы, например PIM (Protocol Independent Multicast). В пределах одного сегмента, конечно, всё работает и так.
kvaps
Спасибо за статью, весьма познавательно.
Скажите а вы пробовали Firewalld? — почему выбор пал именно на Shorewall? Интересно услышать о плюсах и минусах онного по сравнению с Shorewall.
MagicGTS
Пока вы защищаете рабочую станцию или ну очень не сложный шлюз, все ок. И местами даже удобно, но приходит время Rich Rules или, не дай бог, Custom Rules, и начинапшь задумываться: зачем я изучаю синтаксис iptables обернутый во что-то липкое, стоя на голове и смотря в зеркало?
Моё мнение такое: пока он недостаточно развит, что-бы быть удобным в сложных проектах.