Каждому по потребностям – шейпинг трафика при помощи IPFW

Исходные данные: FreeBSD 7.2, IPFW, MPD4.3. две ADSL линии.
Задача – раздавать интернет пользователям – у каждой группы пользователей свой канал.

Итак, настраиваем mpd. В /usr/local/etc/mpd4 нас интересуют два файла:

snake@snake [mpd4]#ls -al
total 118
drwxr-xr-x   2 root   wheel    512 16 окт 22:57 .
drwxr-xr-x  24 root   wheel   1536 18 окт 20:53 ..
-rw-r--r--   1 snake  snake   2799 19 сен 00:33 mpd.conf
-rw-r--r--   1 snake  snake    638 17 сен 23:14 mpd.links

Содержимое mpd.conf:

startup:
        # configure the console
        set console port 5005
        set console ip 127.0.0.1
        set console user user test
        set console open

default:
        load vtk_unlim
        load vtk_unlim2

vtk_unlim:
        new -i ng0 pppoe_vtk pppoe_vtk #имя соединения в mpd.links
        set iface route default #установить соединение маршрутом по умолчанию
        set iface disable on-demand
        set iface idle 0
        set ipcp yes vjcomp
        set ipcp ranges 0.0.0.0/0 0.0.0.0/0
        set bundle disable multilink
        set auth authname mylogin
        set auth password MyPaSsWoRd
        set link no acfcomp protocomp
        set link disable pap chap#настройки шифрования
        set link accept chap
        set link mtu 1400 #настройка MTU
        set link keep-alive 10 60
        set link max redial 0 #число попыток реконнекта
        set bundle disable noretry #перезванивать при обрыве
        set iface up-script /usr/local/etc/mpd4/up #скрипт, выполняющийся при установке соединения
        open

vtk_unlim2:
        new -i ng1 pppoe_vtk2 pppoe_vtk2
        set iface route default
        set iface disable on-demand
        set iface idle 0
        set ipcp yes vjcomp
        set ipcp ranges 0.0.0.0/0 0.0.0.0/0
        set bundle disable multilink
        set auth authname mylogin2
        set auth password mYpAsSwOrD
        set link no acfcomp protocomp
        set link disable pap chap
        set link accept chap
        set link mtu 1400
        set link keep-alive 10 60
        set link max redial 0
        set bundle disable noretry
        set iface up-script /usr/local/etc/mpd4/up2
        open

Содержимое скриптов запуска:

#!/bin/sh
out_if="-interface ng0"
route delete default
route add default $out_if

Скрипт назначает наш pppoe канал маршрутом по умолчанию как для самого сервера, так и для клиентов

Скрипт up2:

#!/bin/sh
out_if="-interface ng1"
setfib 1 route add -net default $out_if
gw=`ifconfig ng1 | grep "inet" | cut -d " " -f 4`
host=`ifconfig ng1 | grep "inet" | cut -d " " -f 2`
fw="/sbin/ipfw -q"
users2=`cat /usr/local/etc/rc.fire.new | grep "users2=" | cut -d "=" -f 2`
num=`ipfw show | grep "fwd" | cut -d " " -f 1`
/usr/local/etc/rc.d/natd.sh
$fw delete $num
$fw add $num fwd $gw ip from $host to any

Суть этого скрипта в том, что он выдирает из вывода ifconfig текущие шлюз и ip (т.к. на втором соединении ип динамический) и добавляет эти значения в правило ipfw, обеспечивающее прохождение трафика. Подробней про эти правила будет ниже.

Файл mpd.links:

pppoe_vtk:
    set link type pppoe # Тип соединения PPPoE
    set pppoe iface em1 #Интерфейс, на котором создается pppoe соединение
    set pppoe service ""
    set pppoe disable incoming #запрещаем входящие соединения
    set pppoe enable originate

pppoe_vtk2:
    set link type pppoe
    set pppoe iface fxp0
    set pppoe service ""
    set pppoe disable incoming
    set pppoe enable originate

mpd настроен. При запуске он должен автоматически поднять соединения и мы увидим нечто вроде этого:

ng0: flags=88d1 metric 0 mtu 1400
        inet 85.15.66.66 --> 85.15.64.119 netmask 0xffffffff
ng1: flags=88d1 metric 0 mtu 1400
        inet 85.15.81.133 --> 85.15.80.1 netmask 0xffffffff

Не забудьте прописать в /etc/syslog.conf:

!mpd
*.*                                             /var/log/mpd.log

Теперь займемся настройкой нат. Я использовал natd. Про свежевыпущенный ipfw nat скажу ниже

Прописываем в /etc/rc.conf следующее:

snake@snake [mpd4]#cat /etc/rc.conf | grep natd
natd_enable="YES"

далее создаем файлы конфигурации (в моем случае /etc/natd2.conf, /etc/natd3.conf):

snake@snake [mpd4]#cat /etc/natd2.conf
# порт, на котором висит natd
port 8448
# интерфейс
interface ng0
# стараться не изменять порты
same_ports yes
# перенаправлять только трафик с адресом источника 10.0.0.0/8, 172.16.0.0/12 и 192.168.0.0/16.
unregistered_only yes
dynamic yes

# проброс портов для отдельных машин наружу
redirect_port tcp 10.12.51.24:51024 51024
redirect_port udp 10.12.51.24:51024 51024
redirect_port tcp 10.12.51.24:51025 51025
redirect_port udp 10.12.51.24:51025 51025
snake@snake [mpd4]#cat /etc/natd3.conf
port 8558
interface ng1
same_ports yes
unregistered_only yes
dynamic yes
redirect_port tcp 10.12.51.118:31027 31027
redirect_port udp 10.12.51.118:31027 31027

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

snake@snake [mpd4]#cat /usr/local/etc/rc.d/natd.sh
#!/bin/sh
/sbin/natd -f /etc/natd2.conf
/sbin/natd -f /etc/natd3.conf

Запускаем, смотрим: в sockstat должно быть что-то такое:

snake@snake [mpd4]#sockstat -l4 | grep natd
root     natd       1033  4  div4   *:8558                *:*
root     natd       1031  4  div4   *:8448                *:*

Теперь приступим к самой ответственной части – а именно настройке фаервола 🙂
Тут я приведу конфиг полностью, с пояснениями и комментариями
Про ядерный nat ipfw можно почтитать тут

#Создаем каналы-пайпы. Труба одна для каждой группы пользователей
$fw pipe 100 config bw $downi queue 50
$fw pipe 200 config bw $upi   queue 50
$fw pipe 300 config bw $downi queue 50
$fw pipe 400 config bw $up2 queue 50
$fw pipe 500 config bw $downvtk queue 50
$fw pipe 600 config bw $upvtk queue 50
#-----------------------------------

#Очереди трафика (подробнее смотрим man ipfw) 
#именно они обеспечивают справедливое распределение канала между пользователями
#inet --> LAN
$fw queue 101 config weight $tcp2w queue 50 pipe 100 gred 0.002/10/35/0.1 mask dst-ip 0xffffffff
$fw queue 102 config weight $tcp1w queue 50 pipe 100 gred 0.002/10/35/0.1 mask dst-ip 0xffffffff

#LAN --> inet
$fw queue 201 config weight $tcp2w queue 50 pipe 200 gred 0.002/10/35/0.1 mask src-ip 0xffffffff
$fw queue 202 config weight $tcp1w queue 50 pipe 200 gred 0.002/10/35/0.1 mask src-ip 0xffffffff

#inet --> LAN
$fw queue 301 config weight $tcp1w queue 50 pipe 300 gred 0.002/10/35/0.1 mask dst-ip 0xffffffff

#LAN --> inet
$fw queue 401 config weight $tcp1w queue 50 pipe 400 gred 0.002/10/35/0.1 mask src-ip 0xffffffff

#VTK --> LAN
$fw queue 501 config weight $tcp2w queue 50 pipe 500 gred 0.002/10/35/0.1 mask dst-ip 0xffffffff

#LAN --> VTK
$fw queue 601 config weight $tcp2w queue 50 pipe 600 gred 0.002/10/35/0.1 mask src-ip 0xffffffff
#-----------------------------------
#Настройки ядерного NAT. У меня нормально так и не заработал, но может у вас получится ;) 
$fw nat 300 config log if $wan same_ports deny_in
#-----------------------------------
#Selfcare & service
##loopback
# разрешаем ходить локалхост трафику, но только в пределах интерфейса loopback
$fwa 01000 allow ip from any to any via lo0
$fwa 01010 deny ip from any to 127.0.0.0/8
$fwa 01020 deny ip from 127.0.0.0/8 to any
#-----------------------------------
##Deny networks
# Запрещаем частные подсети на внешних интерфейсах
$fwa 1200 deny log ip from 10.0.0.0/8 to me in via $inet
$fwa 1210 deny log ip from any to 10.0.0.0/8 out via $inet
$fwa 1220 deny log ip from 172.16.0.0/12 to any in via $inet
$fwa 1230 deny log ip from any to 172.16.0.0/12 out via $inet
$fwa 1240 deny log ip from 192.168.0.0/16 to any in via $inet
$fwa 1250 deny log ip from any to 192.168.0.0/16 out via $inet

$fwa 1205 deny log ip from 10.0.0.0/8 to any in via $inet2
$fwa 1215 deny log ip from any to 10.0.0.0/8 out via $inet2
$fwa 1225 deny log ip from 172.16.0.0/12 to any in via $inet2
$fwa 1235 deny log ip from any to 172.16.0.0/12 out via $inet2
$fwa 1245 deny log ip from 192.168.0.0/16 to any in via $inet2
$fwa 1255 deny log ip from any to 192.168.0.0/16 out via $inet2

#-----------------------------------
#Allowing connetctions
#-----------------------------------
##Intranet connections
# Разрешаем соединение с сервером из локалки
$fwa 02100 allow ip from $hostel to $iplan $usr_ports in via $lan
$fwa 02110 allow ip from me to $hostel out via $lan
$fwa 02115 allow ip from me to $hostel out via $vlan
#-----------------------------------
##DNS (разрешаем связь с DNS серверами прова 
#и доступ к DNS-серверу на машине из локальной сети
$fwa 02310 allow udp from me to $vtk_dns out
$fwa 02320 allow udp from $vtk_dns to me in
$fwa 02330 allow udp from $hostel to $iplan 53 in via $lan
$fwa 02340 allow udp from $iplan 53 to $hostel out via $lan
$fwa 02350 deny udp from $hostel to $vtk_dns in via $lan
$fwa 02360 deny udp from $hostel to $vtk_dns in via $vlan
$fwa 02370 deny udp from $vtk_dns to $hostel out via $lan
$fwa 02380 deny udp from $vtk_dns to $hostel out via $vlan
#-----------------------------------
# Ради чего все затевалось - разрешаем пользователям из локалки доступ вовне
$fwa 03141 allow ip from "table(1)"  to not me in via $lan
$fwa 03142 allow ip from "table(1)" to not me in via $vlan
$fwa 03143 allow ip from not me to "table(1)" out via $lan
$fwa 03144 allow ip from not me to "table(1)" out via $vlan
#-----------------------------------

#NAT & queues
##Outcoming queues (исходящие очереди)
#Настройка очередей. Трафик сервера идет отдельной очередью
$fwa 05010 queue 201 ip from me to any out via $inet
$fwa 05020 queue 202 ip from $users to any out via $inet
$fwa 05030 queue 401 ip from $users2 to any out via $inet2
$fwa 05040 queue 601 ip from any to $vtk out via $wan
#-----------------------------------
##NAT
#Заворачиваем трафик от разных групп на разные natd
$fwa 07200 divert 8448 ip from $users to any out via $inet
$fwa 07250 divert 8448 ip from any to me in via $inet
$fwa 07100 divert 8558 ip from $users2 to any out via $inet2
#Говорим фаерволу, что трафик второй группы 
#нужно пускать через другой шлюз. 
#Именно это правило мы меняем, когда mpd делает реконнект
#Переменные $gw и $host определяются при каждом перезапуске
#скрипта с правилами
$fwa 07130 fwd $gw ip from $host to any
$fwa 07150 divert 8558 ip from any to me in via $inet2
# тот самый ядерный nat. оставил для примера :)
$fwa 07400 nat 300 ip from any to any via $wan
#----------------------------------
##Incoming queues (входящие очереди)
$fwa 08010 queue 101 ip from any to me in via $inet
$fwa 08020 queue 102 ip from any to $users in via $inet
$fwa 08030 queue 301 ip from any to $users2 in via $inet2
$fwa 08040 queue 501 ip from $vtk to any in via $wan
#-----------------------------------
#Allowing connections
##Outcoming allowers (разрешающие правила для соединений)
$fwa 09000 allow ip from $users to $vtk out via $wan
$fwa 09010 allow ip from me to $vtk out via $wan
$fwa 09023 allow ip from me 12553 to any out via $inet
$fwa 09034 allow ip from me 12554 to any out via $inet
$fwa 09040 allow ip from $users to any out via $inet
$fwa 09050 allow ip from $users2 to any out via $inet2
$fwa 09060 allow ip from me to any out via $inet
$fwa 09070 allow ip from me to any out via $inet2
#----------------------------------
##Incoming allowers
$fwa 09100 allow ip from $vtk to $users in via $wan
$fwa 09110 allow ip from $vtk to me in via $wan
$fwa 09120 allow ip from any to $users in via $inet
$fwa 09130 allow ip from any to $users2 in via $inet2
$fwa 09143 allow ip from any to me 12553 in via $inet
$fwa 09154 allow ip from any to me 12554 in via $inet
$fwa 09160 allow ip from any to me in via $inet
#$fwa 09700 allow ip from any to me in via $inet2
#----------------------------------
##ICMP
$fwa 50200 allow icmp from me to any
$fwa 50250 allow icmp from any to me
##Allow all outcoming
$fwa 60000 allow ip from me to any

На этом в общем-то все 🙂 выставляем на клиентских машинах шлюзом по умолчанию наш сервер и радуемся – инет должен работать

2 Comments

    1. Во-первых, мне больше нравится. Во-вторых, ближайший гуру настраивал именно на нем 🙂

Leave a Reply