Настройка VPN-сервера с ведением статистики, шейпингом и фильтрацией во FreeBSD

Для начала: данная статья не претендует на роль полноценного руководства или панацеи на все случаи жизни, посему все вопросы и пожелания по исправлению и дополнению статьи шлем на <shulik at ua.fm>.

Итак - приступим. В работе нам понадобится: FreeBSD 6.0-RELEASE (можно и другую :) ), mpd, freeradius, netams, mysql, поддержка в ядре или в виде модулей IPFW, IPDIVERT, PF, NETGRAPH. Рекомендуется включить поддержку этих компонентов в ядро. Поэтому открываем конфигурационный файл вашего ядра и добавляем, если не хватает, туда следующее:

options NETGRAPH # собственно поддержка netgraph

options NETGRAPH_PPP # поддержка PPP в netgraph

options NETGRAPH_PPTPGRE # поддержка gre-туннелирования

options IPFIREWALL # включаем поддержку ipfw

options IPFIREWALL_DEFAULT_TO_ACCEPT # политика по умолчанию - ACCEPT

options IPDIVERT # включаем divert-сокеты (понадобится для статистики)

Что касается pf - то я оставил его в виде модуля. Если хотите включить в ядро - /sys/conf/NOTES вам поможет.

Теперь установим такие пакеты, как freeradius, mpd, mysql и netams. Коротко:

cd /usr/ports/net-mgmt/netams

make clean

make

make install

make clean

При сборке freeradius обязательно указываем поддержку mysql.

cd /usr/ports/databases/mysql50-server

make clean

make

make install

make clean

cd /usr/ports/net/freeradius

make clean

make

make install

make clean

cd /usr/ports/net/mpd

make clean

make

make install

make clean

Теперь необходимо отконфигурировать установленный софт. MySQL конфигурим по вкусу - задавая пароли рута и прослушку портов или ее отсутствие. Затем нужно настроить freeradius. Для начала идем в /usr/local/etc/raddb/ и переименовываем все файлики из ‘*.samples’ в ‘*’. Открываем radiusd.conf. В нем правим следующие настройки:

log_stripped_names=yes # Логируем атрибут User-Name если он найден в запросе

log_auth=yes # Логируем запросы аутентификации

log_auth_badpass=yes # Если пароль неверен - пишем его в Лог

log_auth_goodpass=no # верные пароли незачем писать в лог

Проверяем чтобы была раскоментарена строчка:

$INCLUDE ${confdir}/sql.conf

В секции authorize комментарим

files

и удаляем комментарий с

sql

В секции accounting также снимаем комментарий с

sql

Далее смотрим в sql.conf и правим:

driver="rlm_sql_mysql"

server="localhost"

login="login_k_mysql"

password="pass_k_mysql"

Осталось поправить clients.conf, задав для клиента 127.0.0.1 secret:

secret=MyOwnSecret

Кроме того нужно создать в mysql базу radius’a следующего содержания: таблица со словарями:

CREATE TABLE `dictionary` (

`id` int(10) NOT NULL AUTO_INCREMENT,

`Type` varchar(30) DEFAULT NULL,

`Attribute` varchar(64) DEFAULT NULL,

`Value` varchar(64) DEFAULT NULL,

`Format` varchar(20) DEFAULT NULL,

`Vendor` varchar(32) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

таблица с клиентами самого радиуса (вместо нее пользуем файлы)

CREATE TABLE `nas` (

`id` int(10) NOT NULL AUTO_INCREMENT,

`nasname` varchar(128) DEFAULT NULL,

`shortname` varchar(32) DEFAULT NULL,

`ipaddr` varchar(15) DEFAULT NULL,

`type` varchar(30) DEFAULT NULL,

`ports` int(5) DEFAULT NULL,

`secret` varchar(60) DEFAULT NULL,

`community` varchar(50) DEFAULT NULL,

`snmp` varchar(10) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

таблица для клиентских сессий:

CREATE TABLE `radacct` (

`RadAcctId` bigint(21) NOT NULL AUTO_INCREMENT,

`AcctSessionId` varchar(32) NOT NULL DEFAULT '',

`AcctUniqueId` varchar(32) NOT NULL DEFAULT '',

`UserName` varchar(64) NOT NULL DEFAULT '',

`Realm` varchar(64) DEFAULT '',

`NASIPAddress` varchar(15) NOT NULL DEFAULT '',

`NASPortId` int(12) DEFAULT NULL,

`NASPortType` varchar(32) DEFAULT NULL,

`AcctStartTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',

`AcctStopTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',

`AcctSessionTime` int(12) DEFAULT NULL,

`AcctAuthentic` varchar(32) DEFAULT NULL,

`ConnectInfo_start` varchar(32) DEFAULT NULL,

`ConnectInfo_stop` varchar(32) DEFAULT NULL,

`AcctInputOctets` int(12) DEFAULT NULL,

`AcctOutputOctets` int(12) DEFAULT NULL,

`CalledStationId` varchar(10) NOT NULL DEFAULT '',

`CallingStationId` varchar(10) NOT NULL DEFAULT '',

`AcctTerminateCause` varchar(32) NOT NULL DEFAULT '',

`ServiceType` varchar(32) DEFAULT NULL,

`FramedProtocol` varchar(32) DEFAULT NULL,

`FramedIPAddress` varchar(15) NOT NULL DEFAULT '',

`AcctStartDelay` int(12) DEFAULT NULL,

`AcctStopDelay` int(12) DEFAULT NULL,

PRIMARY KEY (`RadAcctId`),

KEY `UserName` (`UserName`),

KEY `FramedIPAddress` (`FramedIPAddress`),

KEY `AcctSessionId` (`AcctSessionId`),

KEY `AcctUniqueId` (`AcctUniqueId`),

KEY `AcctStartTime` (`AcctStartTime`),

KEY `AcctStopTime` (`AcctStopTime`),

KEY `NASIPAddress` (`NASIPAddress`)

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

таблица для проверяемых параметров:

CREATE TABLE `radcheck` (

`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,

`UserName` varchar(64) NOT NULL DEFAULT '',

`Attribute` varchar(32) NOT NULL DEFAULT '',

`op` char(2) NOT NULL DEFAULT '',

`Value` varchar(253) NOT NULL DEFAULT '',

PRIMARY KEY (`id`),

KEY `UserName` (`UserName`(32))

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

таблица для проверяемых параметров групп:

CREATE TABLE `radgroupcheck` (

`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,

`GroupName` varchar(64) NOT NULL DEFAULT '',

`Attribute` varchar(32) NOT NULL DEFAULT '',

`op` char(2) NOT NULL DEFAULT '',

`Value` varchar(253) NOT NULL DEFAULT '',

PRIMARY KEY (`id`),

KEY `GroupName` (`GroupName`(32))

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

таблица для возвращаемых параметров групп:

CREATE TABLE `radgroupreply` (

`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,

`GroupName` varchar(64) NOT NULL DEFAULT '',

`Attribute` varchar(32) NOT NULL DEFAULT '',

`op` char(2) NOT NULL DEFAULT '',

`Value` varchar(253) NOT NULL DEFAULT '',

`prio` int(10) UNSIGNED NOT NULL DEFAULT '0',

PRIMARY KEY (`id`),

KEY `GroupName` (`GroupName`(32))

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

таблица для возвращаемых параметров:

CREATE TABLE `radreply` (

`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,

`UserName` varchar(64) NOT NULL DEFAULT '',

`Attribute` varchar(32) NOT NULL DEFAULT '',

`op` char(2) NOT NULL DEFAULT '',

`Value` varchar(253) NOT NULL DEFAULT '',

PRIMARY KEY (`id`),

KEY `UserName` (`UserName`(32))

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

таблица соответствия пользователей и групп:

CREATE TABLE `usergroup` (

`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,

`UserName` varchar(64) NOT NULL DEFAULT '',

`GroupName` varchar(64) NOT NULL DEFAULT '',

PRIMARY KEY (`id`),

KEY `UserName` (`UserName`(32))

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

И сразу же заведем тестового пользователя:

INSERT INTO `radcheck` VALUES (1,'user_test','Password','==','qwerty');

INSERT INTO `radreply` VALUES (1,'user_test','Framed-IP-Address',':=','192.168.1.3');

INSERT INTO `radreply` VALUES (1,'user_test','Framed-IP-Netmask',':=','255.255.255.255');

INSERT INTO `radreply` VALUES (1,'user_test','Framed-Protocol',':=','PPP');

По сути ААА готова к использованию. Добавляем в /etc/rc.conf строки:

radiusd_enable="YES"

mysql_enable="YES"

и стартуем скриптами из /usr/local/etc/rc.d/

Проверим радиус на работоспособность:

radtest user_test qwerty 127.0.0.1 0 MyOwnSecret

В результате должны получить что-то вида:

Sending Access-Request of id 189 to 127.0.0.1:1812

User-Name = "user_test"

User-Password = "qwerty"

NAS-IP-Address = localhost

NAS-Port = 0

rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=189, length=38

Framed-IP-Address = 192.168.1.3

Framed-IP-Netmask = 255.255.255.255

Framed-Protocol = PPP

Это говорит о том, что радиус работает верно. Если нет - смотрим что он кричит в /var/log/radiusd.log

Пришло время настроить mpd. Смело идем в /usr/local/etc/mpd/ и убираем из имен конфигов samples. Открываем mpd.conf и пишем туда:

default:

load pptp0

pptp0:

new -i ng0 pptp0 pptp0

load pptp_all

pptp_all:

set ipcp ranges 192.168.1.1/32 10.0.0.0/24

set iface disable on-demand

set bundle disable multilink

set link yes acfcomp protocomp

set link no pap chap

set link enable chap

set link keep-alive 60 180

set ipcp yes vjcomp

set ipcp dns 192.168.1.1 # или любой другой доступный DNS

# set bundle enable compression # обязательно проверяем, чтобы это было выключено.

# иначе будем долго искать, почему пинги идут, но ничего не грузится

set pptp enable incoming

set pptp disable originate

# если нужно - задаем ip для открытия 1723 порта. по умолчанию - все

# set pptp self 172.16.101.2

set radius timeout 10

set radius config /usr/local/etc/mpd/radius.conf

set radius retries 3

set bundle enable radius-acct

set bundle enable radius-auth

set ipcp yes radius-ip

Нужно заметить, что для примера создан всего лишь один pptp линк. В реале их нужно создать столько, сколько вам необходимо одновременных pptp-туннелей. Создаем mpd.links:

pptp0:

set link type pptp

И radius.conf:

acct 127.0.0.1 MyOwnSecret

auth 127.0.0.1 MyOwnSecret

Добавляем в rc.conf строку:

mpd_enable="YES"

и запускаем mpd.

Теперь нужно его проверить. Чтобы проще было вести отладку - добавим в /etc/syslog.conf:

!mpd

*.* /var/log/mpd.log

И передергиваем syslog. Идем за клиентскую машинку и проверяем подключение по впн.

Если все прошло удачно - идем дальше, иначе ищем ошибку.

Далее нужно клиентов из внутренней сети с внутренними ip-адресами выпустить в инет. Для этого у нас есть несколько путей: воспользоваться связками ipfw+natd или ipfw+ng_nat, но мы пойдем по пути использования pf.

В /etc/rc.conf добавляем:

pf_enable="YES"

pf_rules="/etc/pf.rules"

pf_flags=""

pflog_enable="YES"

pflog_logfile="/var/log/pflog"

pflog_flags=""

Файлик pf.rules:

ext_ip="19х.1хх.хх.хх" # внешний ip-адрес сервера

int_if="rl1" # интерфейс смотрящий в локалку

int_net_vpn="xx.yy.zz.ff" # внутренняя VPN-сеть

local_net="..." # внутрення локалка

int_ip="..." # внутренний ип в локалке

nat on rl0 from $int_net_vpn to any -> $ext_ip # собсно NAT

pass quick on lo0 all # разрешаем все на lo0

pass quick from $ext_ip to any # Разрешаем траф

pass quick from any to $ext_ip # на внешнем ip

pass quick from $int_net_vpn to any # разрешаем любой траф

pass quick from any to $int_net_vpn # по впн-сети

# блокируем платные сервисы из локалки

block in quick on $int_if proto { tcp udp } from $local_net to $int_ip port { 25 110 143 3128 3306 }

pass in quick on $int_if from $local_net to $int_ip

block in all # все осальное блокируем по умолчанию

Все. Теперь трафик должен ходить в инет. Осталось организовать логирование трафика через netams. Приведу лишь коротки отрывки конфигов - так как на сайте netams.com есть хорошая документация на русском языке с примерами настройки netams. В rc.conf привычно добавляем:

firewall_enable="YES"

firewall_script="/etc/ipfw.sh"

ipfw.sh:

#!/bin/sh

fwcmd="/sbin/ipfw"

${fwcmd} -f flush

${fwcmd} -f flush pipe

${fwcmd} -f flush queue

${fwcmd} pipe 1 config bw 512Kbit/s queue 50 # для обжимки трафа пользуемся pipe'ами

${fwcmd} pipe 2 config bw 512Kbit/s queue 50

${fwcmd} add pipe 1 ip from <vpn_net> to any in # вгоняем траф в пайпы

${fwcmd} add pipe 2 ip from any to <vpn_net> out

${fwcmd} add tee 100 ip from <vpn_net> to any in # копируем траф в divert-socket для netams.

${fwcmd} add tee 100 ip from any to <vpn_net> out

В netams для нас важны разделы:

service data-source 1

type ip-traffic

source tee 100

service storage 1

type mysql

user mysql_login # с правами создания БД, хотя бы на момент первого запуска

password mysql_pass

host localhost

service monitor 1

monitor to storage 1

monitor unit VPN

unit net name VPN ip <vpn-net> acct-policy ip

http://bozza.ru/?p=articles&c=11&text=58
Обновлено: 12.03.2015