В этой статье хочу рассказать, как заставить работать одновременно 2 канала, каждый из которых поднимается через ppp на примере USB модемов.
Огромный нюанс заключается в том, что мы наперёд не знаем IP-адреса шлюзов для ppp-сессий. Но это нам не помешает правильно реализовать задуманное.
Тестовый стенд: FreeBSD 8.2 i386, USB модемы Novatel U720, AnyData ADU-500.
1) Подготовка модемов.
Для того, что бы можно было работать с модемами, достаточно драйвера u3g, который уже присутствует в ядре GENERIC.
Послу подключения модемов, они у вас должны определиться, как показано ниже:
# usbconfig | grep CDMA
ugen0.2: <AnyDATA CDMA Products AnyDATA Corporation> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON
ugen1.2: <Novatel Wireless CDMA Novatel Wireless Inc.> at usbus1, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON
Если у вас не видятся модемы, возможно требуется загрузить дополнительные драйвера, информацию о которых можно найти в статьях через Поиск на сайте по ключевому слову USB.
2) Настройка ppp.
Вот пример конфигурационного файла ppp.conf (напомню, что все строки, кроме itc и mts начинаются с отступов):
itc:
ident user-ppp VERSION (built COMPILATIONDATE)
set log PHase Chat LCP IPCP CCP tun command
set device /dev/cuaU4.0
set phone "#777"
set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" AT OK-AT-OK ATE1Q0s7=60 OK \\dATDT\\T TIMEOUT 40 CONNECT"
set login
set timeout 0
set authname "IT"
set authkey "IT"
add default HISADDR
disable ipv6cp
mts:
set log Phase Chat LCP IPCP CCP tun command
ident user-ppp VERSION (built COMPILATIONDATE)
set device /dev/cuaU0.0
set speed 115200
set ctsrts off
set phone "#777"
set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" AT OK-AT-OK ATE1Q0 OK \\dATD\\T TIMEOUT 40 CONNECT"
set login
set timeout 0
set authname "mobile"
set authkey "internet"
set ifaddr 0.0.0.0/0 0.0.0.0/0 0.0.0.0/0
# add default HISADDR
set ipcpretries 10 5
disable ipv6cp
Теперь перейдём к файлу ppp.linkup. Этот файл используется для возможности выполнять определённые действия при поднятии/опускании ppp-соединения. Формат похож на ppp.conf. Добавим в него такие строки (строки начинающиеся с ! должны иметь отступы):
itc:
!bg /etc/pf-anchor.sh itc INTERFACE HISADDR
mts:
!bg /etc/pf-anchor.sh mts INTERFACE HISADDR
Которые собственно означают, что при поднятии соответствующего соединения запускать указанный скрипт с нужными параметрами.
Точно так же можно создать файл ppp.linkdown.
Примечание.
Обратите внимание на строки set device. У вас они могут отличаться и самое главное выяснить, какому модему отвечает какое устройство. Я нашёл соответствие экспериментальным путём.
Осталось добавить строки в /etc/rc.conf для запуска демона ppp. Они выглядят так:
ppp_enable="YES"
ppp_mode="ddial"
ppp_nat="NO"
ppp_profile="itc mts"
ppp_user="root"
Примечание.
Здесь могут быть нюансы в том плане, что перечислять “профили” нужно именно в таком порядке. В другом порядке поднимался только 1 модем.
3) Настройка PF.
Файл с правилами /etc/pf.rules содержит такие строки (я пока рассматриваю самый простой вариант):
nat-anchor itc
nat-anchor mts
anchor itc
anchor mts
Теперь создадим файл я правилами, которые будут применяться для каждого якоря (/etc/pf-anchor.conf):
nat on $ext_if from 10.1.0.0/24 to any -> ($ext_if)
pass in on $ext_if reply-to ($ext_if $gw) from any to ($ext_if) keep state
Здесь тоже всё просто: правило для NAT’a и правило для пакетов, что бы шли туда, откуда пришли, а не через таблицу маршрутизации.
Ну и завершающий этап – создание скрипта для применения правил (/etc/pf-anchor.sh):
#!/bin/sh
anchor=$1
ext_if=$2
gw=$3
pf_config="/etc/pf-anchor.conf"
pf="/sbin/pfctl"
$pf -a $anchor -Fa
$pf -a $anchor -D ext_if=$ext_if -D gw=$gw -f $pf_config
Не забудьте сделать скрипт исполняемым!
Объяснять здесь нечего, кроме последней строки – тут мы собственно передаём переменные для якоря, которые потом в зависимости от того, какая сессия ppp их вызвала трансформируются в соответствующие правила.
Примечание.
Можно обойтись и без использования якорей. Для этого можно использовать такие правила:
pass in on $int2 reply-to ($int2 $int2:peer) from any to ($int2) keep state
pass in on $int1 reply-to ($int1 $int1:peer) from any to ($int1) keep state
но тогда вы можете столкнутся с тем, что правила применяться раньше, чем поднимутся интерфейсы tun0/tun1.
4) Проверка работы.
После поднятия сессий мы увидим такое:
srv-test# ifconfig tun0
tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
options=80000<LINKSTATE>
inet 195.128.XX.XX --> 195.128.XX.XX netmask 0xffffffff
Opened by PID 456
srv-test# ifconfig tun1
tun1: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
options=80000<LINKSTATE>
inet 77.52.YY.YY --> 80.255.YY.YY netmask 0xffffffff
Opened by PID 465
Смотрим теперь правила:
srv-test# pfctl -a '*' -sr
anchor "itc" all {
pass in on tun0 reply-to (tun0 195.128.XX.XX) inet from any to (tun0) flags S/SA keep state
}
anchor "mts" all {
pass in on tun1 reply-to (tun1 80.255.YY.YY) inet from any to (tun1) flags S/SA keep state
}
Замечу, что если бы мы использовали просто pf -sr, увидели бы следующее:
anchor "itc" all
anchor "mts" all
Тоже самое касается и правил трансляции:
srv-test# pfctl -a 'itc' -sn
nat on tun0 inet from 10.1.0.0/24 to any -> (tun0) round-robin
srv-test# pfctl -a 'mts' -sn
nat on tun1 inet from 10.1.0.0/24 to any -> (tun1) round-robin
5) Нюансы
Для UDP приложению, которое слушает “любой IP” (*:port), нельзя выяснить,
на который именно IP пришел запрос, поэтому нельзя ответить с него.bind (и ntpd и другие) обходят эту проблему, создавая по отдельному сокету
для каждого IP и принимая запросы в разные сокеты.
Что это значит? А то, что, если вы к примеру, повесите на * демон openvpn’a, то ответные пакеты не будут уходить на НЕ default route. Как выходить из такого? Вешать по отдельному демону на каждый такой интерфейс, который НЕ смотрит на default route.
4 коментарі “[pf] Несколько ppp сессий и reply-to из PF”
Ох, как вовремя! На днях предстоит. Спасибо!
freebsd 8.2 , работают два модема U720 и U760 от Интертелеком, сегодня с утра оба получают один и тот же IP адрес на стороне провайдера. Соответственно имеем в ppp.log:
tun1: IPCP: myaddr 93.180.XX.XX hisaddr = 195.128.182.33
tun1: Warning: iface add: ioctl(SIOCAIFADDR, 93.180.XX.XX -> 195.128.182.33): File exists
tun1: Error: ipcp_InterfaceUp: unable to set ip address
как бы так сделать, что бы работало? Спасибо.
Только обращаться в ИнтерТелеком, так как модемы должны получать разные IP. Может слетели настройки? Кстати, они у себя там пару месяцев назад меняли частоты и из-за этого у меня часть модемов не работала. Отвёз им, перепрошили, сейчас вроде бы нормально работают.
Ещё как вариант, попробуй вставить в разные компы и проверить, получат ли в этом случае один и тот же адрес. Или как вариант по отдельности их включить.
Хм, проблема была в попытке ppp добавить в маршруты, повторно один и тот же адрес шлюза провайдера. Решил добавлением в ppp.linkup
route delete 195.128.182.33
криво но работает 🙂