- PVSM.RU - https://www.pvsm.ru -

Программный интернет шлюз для уже не маленькой компании (Shorewall, OpenVPN, OSPF). Часть 1

Представляю две статьи (вторую пока пишу), ориентированных на «продолжающих» системных администраторов, для опытных я вряд ли открою что-то новое.
В этих статьях мы рассмотрим построение интернет шлюза на linux, позволяющего связать несколько офисов компании, и обеспечить ограниченный доступ в сеть, приоритетзацию трафика (QoS) и простую балансировку нагрузки с резервированием канала между двумя провайдерами.
Конкретно в этой части:

  • Простейшая настройка Shorewall
  • Ужасно сложная настройка dnsmasq
  • Не менее сложная настройка OpenVPN
  • И для многих продолжающих админов нетипичная, динамическая маршрутизация, на примере OSPF

А во второй части будут рассмотрены:

  • Более подробная настройка Shorewall
  • Страшный и не понятный QoS
  • Балансировка нагрузки и резервирование


Все описанное ниже справедливо для 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 все вертится вокруг понятия «зона». В зону включаются хосты (путем задания интерфейсов или непосредственно сетей и/или отдельных адресов).

Заглянем в файл zones

#
# 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 — зона для наших туннелей

Пришло время поместить в эти зоны интерфейсы (отдельные хосты мы пока не будем использовать), но перед этим внесем некоторые правки в файл:

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
IF_GRN=eth1
NET_GRN=172.16.0.0/23
IF_TUN=tap+

#LAST LINE -- DO NOT REMOVE

В этом файле можно задать различные переменные, которые будем потом использовать в других файлах, и которые помогают сделать конфиг более переносимым между системами. Сейчас у нас тут прописаны наши физические интерфейсы и локальная подсеть филиала. Обратите внимание, tap+ говорит об использовании маски, под которую попадает любой tapX (кроме просто «tap»).
Ну а теперь файл:

interfaces

#
# 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.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» задает тип блокируемых пакетов (всех) для забаненых адресов, тоже на будущее.
Пришло время для создания политик по умолчанию:

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	ACCEPT
grn	all	ACCEPT
red	all	DROP

tun	grn	ACCEPT
tun	red	REJECT
tun	$FW	ACCEPT

Ключевые слова значат следующие:

  • ACCEPT — принимать (в том числе форвардить) пакеты
  • REJECT — Отбросить пакет, а отправителю сообщить, что писем мы от него не ждем
  • DROP — Отбросить пакет, и загадочно осмотревшись, никому ничего не сказать

В третий столбец можно прописать еще несколько параметров, один из которых info, задаст логирование данной политики (имеет смысл для DROP и REJECT, а то ACCEPT завалит вас логами).

Заданная политика примитивна и не годится для серьезных проектов, соответствует настройке большинства домашних роутеров, но для самого старта она нам подойдет.
Осталось чуть чуть, а именно настроить маскарадинг (чего в эпоху IPv6 делать будет не надо):

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

Очевидно, все что идет в сторону интерфейса $IF_RED1 из сети $NET_GRN нужно замаскировать. Третий столбец ADDRESS используется для SNAT.

Для отслеживания и соответствующего изменения правил файрвола, в ответ на включениеотключение интерфейса, нам поможет небольшой скрипт:

/etc/NetworkManager/dispatcher.d/30-shorewall.sh

#!/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 для неё не является проблемой, а простота и гибкость настроек делает её очень подходящей для нашей ситуации.
Так как файл настроек большой, приведу и его тоже в урезанном виде:

/etc/dnsmasq.conf

# 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

Думаю это часть не составит особого труда вообще никому, но приведем эти шаги:

  1. Из epel установим пакеты: openvpn easy-rsa
  2. Скопируем из /usr/share/easy-rsa папку в /etc/openvpn и переименуем её в easy-rsa
  3. Перейдем в /etc/openvpn/easy-rsa и при необходимости отредактируем файл vars
  4. Выполним: ". ./vars && ./clean-all && ./build-dh && openvpn --genkey --secret ./keys/ta.key &&./build-ca && ./build-key-server server #привет от гентушника (как установить Gentoo одной командой, да и такое возможно)!

Еще нам понабиться файл конфигурации сервера:

/etc/openvpn/inter-lan.conf

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 для клиента:

/etc/openvpn/ccd/inter-lan/DEFAULT

push "comp-lzo no"

Файл клиентского шаблона конфигурации:

/etc/openvpn/easy-rsa/templates/inter-lan.conf

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>

И вспомогательный самописный скриптик:

/etc/openvpn/easy-rsa/build-ovpn.sh

#!/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 для клиента:

/etc/openvpn/ccd/inter-lan/<имя клиента>

# Тут могли быть параметры, если бы они нам были нужны :), поэтому удалим его, пусть использует DEFAULT

После надо скопировать файл из каталога /etc/openvpn/ovpn/<имя клиента>/<имя клиента>.ovpn на клиентский компьютер (шлюз) и поместить его в /etc/openvpn/ с расширением ".conf"
Запускаем openvpn на клиенте и сервере:

systemctl enable openvpn@<имя conf файла без расширения conf>.service && systemctl start openvpn@<имя conf файла без расширения conf>.service

А результат есть только на сервере! Клиент в непонятках. Во всем виноват shorewall, а точнее, наша политика, мы не разрешили соединения из интернета (red зона)!
Внесем разрешающее правило в файл:

/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
#Правило ниже использует макрос из: /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 <имя интерфейса> #Несколько раз выполним для всех, где у нас точно не будет взаимодействия по протоколу ospf, а именно интернет интерфейс и скорее всего смотрящий в локалку
ospfd(config-router)# network 172.16.0.0/12 area 0.0.0.0 #Задаем сеть, для которой будут строится маршруты, также задает интерфейсы, по которым будет происходить взаимодействие. Сеть с маской /12 охватывает все частное пространство, в котором мы для себя нарезали подсети
ospfd(config-router)# write memory #сохранит текущую настройку в файл

Итоговый файл конфигурации:

/etc/quagga/ospfd.conf

!
! 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 eth0
 passive-interface eth1
 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 я изучил еще не достаточно глубоко).

Автор: MagicGTS

Источник [1]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/linux/108340

Ссылки в тексте:

[1] Источник: http://habrahabr.ru/post/274639/