Динамический шейпер траффика (dummynet + PF + mrtg)

Опубликовано:

Необходимо было настроит динамический шейпер для локальной сети. Выбор стал между ipfw+dummynet и pf+altq. В результате шейпер решили настроить на dummynet, а правила NAT и фильтрации на PF, так как PF+ALTQ не дает возможности создания очереди на виртуальных интерфейсах (bridge, ng*, tun* ).
Визуальную статистику по пользователям, будем смотреть с помощью mrtg. Вышло даже неплохо.
Установленная ОС:

[root@pdcserv ~]# uname -rv
FreeBSD 8.1-RELEASE #0

Первым делом пересоберем ядро с поддержкой дамминета и PF:

#PF
device pf
device pflog
device pfsync
options ALTQ
options ALTQ_CBQ
options ALTQ_RED
options ALTQ_RIO
options ALTQ_HFSC
options ALTQ_PRIQ
options ALTQ_NOPCC#IPFW
options IPFIREWALL
options DUMMYNET
options HZ=1000

Далее необходимо немного тюнинговать ядро:

[root@pdcserv /etc]# cat /etc/sysctl.conf
net.inet.ip.forwarding=1 #включаем форвардинг пакетов
net.inet.ip.fastforwarding=1 #эта опция действительно ускоряет форвардинг
net.inet.tcp.blackhole=2 #ядро убивает tcp пакеты, приходящие в систему на непрослушиваемые порты
net.inet.udp.blackhole=0 #как и выше, только не убивает ибо traceroute пакеты не покажут этот хоп
net.inet.icmp.drop_redirect=1 #не обращаем внимания на icmp redirect
net.inet.icmp.log_redirect=0 #и не логируем их
net.inet.ip.redirect=0 #не реагируем на icmp redirect
net.inet.ip.sourceroute=0 #отключение маршрутизации от источника
net.inet.ip.accept_sourceroute=0 #старый и бесполезный механизм
net.inet.icmp.bmcastecho=0 #защита от SMURF атак
net.inet.icmp.maskrepl=0 #не отдавать по icmp паску своей подсети
net.link.ether.inet.max_age=30 #переспрашиваем каждые 30 секунд mac адреса в своём arp пространстве
net.inet.tcp.drop_synfin=1 #небольшая защита
net.inet.tcp.syncookies=1 #от доса
kern.ipc.somaxconn=32768 #увеличиваем размер очереди для сокетов
kern.maxfiles=204800 #увеличиваем число открытых файловых дескрипторов
kern.maxfilesperproc=200000 #кол-во ф.д. на каждоый процесс  
kern.ipc.nmbclusters=524288 #увеличиваем число сетевых буферов
kern.ipc.maxsockbuf=2097152 #
kern.random.sys.harvest.ethernet=0 #не использовать трафик и прерывания    
kern.random.sys.harvest.interrupt=0 #как источник энтропии для random'a  
net.inet.ip.dummynet.io_fast=1 #заставляет dummynet работать побыстрее  
net.inet.ip.dummynet.hash_size=65535 #  
net.inet.ip.dummynet.pipe_slot_limit=2048 #
kern.ipc.shmmax=67108864 #макс. размер сегмента памяти
net.inet.ip.intr_queue_maxlen=8192 #размер очереди ip-пакетов
#net.inet.ip.fw.one_pass=0 # 0=пакеты, прошедшие пайпы не вылетают из фаервола, а дальше идут по нему
net.inet.ip.fw.verbose=1
net.inet.ip.fw.verbose_limit=5
net.inet.ip.dummynet.hash_size=1024
net.inet.ip.fw.dyn_buckets=1024

Перейдем к настройке IPFW (dummynet);

[root@pdcserv /etc]#cat /etc/ipfw.conf
#!/bin/sh

cmd="ipfw -q"
lan=rl0 # LAN
wan=ae0 # WAN
drate=2Mbit/s # download
urate=2Mbit/s # upload
n=10 #Количество пользователей (1:253)

$cmd flush # Очищаем правила
$cmd pipe flush # Очищаем пайпы
$cmd table all flush # Очищаем все таблицы

# download (wan->lan)
$cmd pipe 100 config bw $drate queue 100 noerror
$cmd queue 111 config pipe 100 weight 50 queue 100 mask dst-ip 0xffffffff noerror

# upload (lan->wan)
$cmd pipe 200 config bw $urate  queue 100 noerror
$cmd queue 211 config pipe 200 weight 50 queue 100 mask src-ip 0xffffffff noerror

#Создаем очереди по таблицам
$cmd add queue tablearg ip from table(10) to any out recv $lan xmit $wan
$cmd add queue tablearg ip from any to table(11) out recv $wan xmit $lan

#Генерация правил подсчета трафика по пользователях
i=2
k=`expr $i + $n`
while [ "$i" -lt "$k" ]
do
$cmd add count all from any to 10.10.10.$i/32
$cmd add count all from 10.10.10.$i/32 to any
i=`expr $i + 1`
done

# IPFIREWALL_DEFAULT_TO_ACCEPT
$cmd add allow all from any to any

### Заполняем таблицы: ip номер_пайпы ###
# user_1
#$cmd table 10 add 10.10.10.2/32 211
#$cmd table 11 add 10.10.10.2/32 111

# user_2
#$cmd table 10 add 10.10.10.3/32 211
#$cmd table 11 add 10.10.10.3/32 111

# user_3
#$cmd table 10 add 10.10.10.4/32 211
#$cmd table 11 add 10.10.10.4/32 111
#user_all
$cmd table 10 add 10.10.10.0/24 211
$cmd table 11 add 10.10.10.0/24 111

На PF настраиваем только NAT:

[root@pdcserv /etc]#cat /etc/pf.conf
####МАКРОСЫ####
# WAN ISP
ext_if="ae0"

# LAN
int_if="rl0"

LAN="10.10.10.0/24"
#### NAT ####
# Разрешаем ходить в интернет через NAT
nat on $ext_if inet from $LAN to !$LAN -> ($ext_if)

Для автозапуска добавим строчки в /etc/rc.conf:

[root@pdcserv /etc]#cat >>  /etc/rc.conf
#pf  
pf_enable="YES"
pf_rules="/etc/pf.conf"
pf_flags=""
pflog_logfile="/var/log/pf.log"
pflog_flags=""#ipfw
firewall_enable="YES"
firewall_script="/etc/ipfw.conf"

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

#Общий блок
HtmlDir: /usr/local/www/mrtg
ImageDir: /usr/local/www/mrtg/img
LogDir: /usr/local/www/mrtg
Language: russian
Options[^]: growright, unknaszero, nobanner, transparent, noinfo, nopercent, integer
Background[_]: #B0C4DE
XSize[_]: 400
YSize[_]: 100# ipfw user_2
Target[user_2]: `ipfw show 300 | awk '{ print $3 }' && ipfw show 400 | awk '{ print $3 }'`
Title[user_2]: user_2
Pagetop[user_2]: <H1>user 192.168.100.2</H1>
Options[user_2]: bits
MaxBytes[user_2]:1250000

Вывод сгенерированных правил для 2-х пользователей:

[root@pdcserv ~]# ipfw show 
00100   0     0 queue tablearg ip from table(10) to any out recv rl0 xmit ae0
00200   0     0 queue tablearg ip from any to table(11) out recv ae0 xmit rl0
00300   0     0 count ip from any to 10.10.10.2
00400   0     0 count ip from 10.10.10.2 to any
00500   0     0 count ip from any to 10.10.10.3
00600   0     0 count ip from 10.10.10.3 to any
00700 129 48429 allow ip from any to any
65535   0     0 deny ip from any to any
[root@pdcserv ~]#

Просмотр текущих динамических очередей:

[root@pdcserv ~]# ipfw queue show
q00211 100 sl. 0 flows (1024 buckets) sched 200 weight 50 lmax 0 pri 0 droptail
mask:  0x00 0xffffffff/0x0000 -> 0x00000000/0x0000
BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp
q00111 100 sl. 0 flows (1024 buckets) sched 100 weight 50 lmax 0 pri 0 droptail
mask:  0x00 0x00000000/0x0000 -> 0xffffffff/0x0000
BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp
[root@pdcserv ~]#

Понравилась статья, расскажи о ней друзьям, нажми кнопку!