++ ВведениеНа сервере FreeBSD 10.1 установлены два интернет канала. Первый вполне нормальный Ethernet, выделенный ip адрес.
Второй - LTE модем, адрес соответственно динамический.
Весь трафик squid должен уходить на второй канал.
Для этого используется опция tcp_outgoing в squid.conf
В правилах ipfw добавлены два правила для обеспечения forward на новый шлюз
ipfw add 10 fwd <адрес шлюза на втором канале> all from <динамический адрес второго канала> to not 192.168.1.0/24 out
ipfw add 11 pass all from any to <динамический адрес второго канала> via <интерфейс LTE модема> in
Механизм ясен. Осталось сделать следующее:
1. При изменении динамического адреса надо подставлять новые значения в ipfw и в squid
2. Сделать это при старте сервера
По тексту интерфейс ue0 - интерфейс LTE модема.
++ Получение нового динамического адреса
После инициализации модема и запуска dhclient мы получим динамический IP адрес. dhclient формирует leases в своем файле.
Пример файла:
lease {
interface "ue0";
fixed-address 100.67.50.124;
option subnet-mask 255.255.255.248;
option routers 100.67.50.121;
option domain-name-servers 83.149.32.225,83.149.32.224;
option dhcp-lease-time 518400;
option dhcp-message-type 5;
option dhcp-server-identifier 100.67.50.121;
option dhcp-renewal-time 259200;
option dhcp-rebinding-time 453600;
renew 1 2015/6/15 08:59:05;
rebind 3 2015/6/17 14:59:05;
expire 4 2015/6/18 08:59:05;
}
lease {
interface "ue0";
fixed-address 100.67.3.43;
option subnet-mask 255.255.255.248;
option routers 100.67.3.41;
option domain-name-servers 83.149.32.225,83.149.32.224;
option dhcp-lease-time 518400;
option dhcp-message-type 5;
option dhcp-server-identifier 100.67.3.41;
option dhcp-renewal-time 259200;
option dhcp-rebinding-time 453600;
renew 6 2015/6/13 16:12:27;
rebind 1 2015/6/15 22:12:27;
expire 2 2015/6/16 16:12:27;
}
Lease в текущий момент будет последним. Нас интересует две строки. fixed-address - это сам динамический адрес. option routers - это адрес шлюза на этом интерфейсе.
Я получаю эти поля через awk, только потому, что lease несколько и нам нужен последний. Через awk это удобно сделать.
Скрипт для получения ip
megafon_get_ip.awk:
BEGIN {nline=1
}
{
tag1[nline]=$1
tag2[nline]=$2
nline=nline+1
}
END {
for (u=1;u<nline;u++)
{
if (tag1=="fixed-address")
{
# Делаем замену последнего символа, что бы не мешал.
gsub(";","",tag2);
ip = tag2;
}
}
print ip;
}
Скрипт для получения routers
megafon_get_router.awk:
BEGIN {nline=1
}
{
tag2[nline]=$2
tag3[nline]=$3
nline=nline+1
}
END {
for (u=1;u<nline;u++)
{
if (tag2=="routers")
{
# Делаем замену последнего символа, что бы не мешал.
gsub(";","",tag3);
router = tag3;
}
}
print router;
}
++ Обновление таблиц ipfw
Считывание нового динамического адреса и адреса шлюза в ipfw сделано через cat
Выдержка из rc.firewall:
...
eth_megafon="ue0"
ip_megafon=`cat /etc/megafon_ip`
router_megafon=`cat /etc/megafon_router`
${fwcmd} add 10 fwd $router_megafon all from $ip_megafon to not 192.168.0.0/16 out
${fwcmd} add 11 pass all from any to $ip_megafon via $eth_megafon in
...
Как видно, текущие адреса хранятся в /etc/megafon_ip и /etc/megafon_router
++ Обновление squid.conf
К сожалению, опция tcp_outgoing_address требует указания адреса. То есть фокус как в rc.firewall не пройдет.
Значит надо будет делать замену.
Создаем файл squid.conf.etalon:
...
tcp_outgoing_address #ip_megafon#
...
И остается применить
sed 's/#ip_megafon#/'< новый динамический адрес >'/g' /usr/local/etc/squid/squid.conf.etalon > /usr/local/etc/squid/squid.conf
++ Основной скрипт
Итак, получать новые адреса научились. Обновлять в ipfw, менять squid.conf тоже.
Полученные новые адреса пишем во временные файлы, потом сравниваем новый динамический адрес с прежним.
Прежний (текущий) адрес храним в файл /etc/megafon. Если адреса не совпадают, обновляем файл с адресом и запускаем механизм обновления
megafon_get_ip:
#Получаем новый ip
awk -f /usr/local/scripts/megafon_get_ip.awk /var/db/dhclient.leases.ue0 > /tmp/megafon_ip
#Получаем новый router. Хотя можно и позже, но для удобства понимания можно и тут
awk -f /usr/local/scripts/megafon_get_router.awk /var/db/dhclient.leases.ue0 > /tmp/megafon_router
#Сравниваем его с существующим
ip_new=`cat /tmp/megafon_ip`
ip_now=`cat /etc/megafon_ip`
if [ $ip_new != $ip_now ]; then
# Обновляем файлы. Нужно обновлять и таблицы ipfw
cp /tmp/megafon_ip /etc/megafon_ip
cp /tmp/megafon_router /etc/megafon_router
#Обновляем ipfw. Эта конструкция не отрубает соединение при обновлении правил ipfw
sh /etc/rc.firewall > /dev/null 2>&1
#Формируем новый конфиг squid. К сожалению, tcp_outgoing не умеет брать адрес из файла.
sed 's/#ip_megafon#/'$ip_new'/g' /usr/local/etc/squid/squid.conf.etalon > /usr/local/etc/squid/squid.conf
#Рестарт squid.
/usr/local/sbin/squid -k reconfigure
fi
++ Запуск основного скрипта при старте сервера
Для получения динамического адреса самым простым виделось поставить в rc.conf строку ifconfig_ue0="DHCP"
Но модем от Мегафона, его надо инициализировать перед запросом адреса. Заодно обеспечим вызов основного скрипта.
Создал /usr/local/etc/rc.d/megafon
megafon:
#!/bin/sh
#
# PROVIDE: megafon
# REQUIRE: dhclient
# KEYWORD: shutdown
. /etc/rc.subr
name=megafon
load_rc_config ${name}
command=/usr/local/etc/megafon
command_args=""
run_rc_command "$1"
В rc.conf добавляем:
...
megafon="YES"
...
Сам стартовый скрипт
/usr/local/etc/megafon:
#Инициализация модема
echo 'AT^NDISDUP=1,1,"internet"' > /dev/cuaU1
#Стартуем клиента
/sbin/dhclient -b ue0
#Через 10 секунд надо вызвать обновление таблиц и всего остального. Приводит к 10 секундной задержки старта сервера.
sleep 10
#Вызов основного скрипта
/usr/local/scripts/megafon_get_ip
++ Периодическое обновление
Механизма вызова сторонних скриптов при обновлении динамического адреса не нашел. Если поставить основной скрипт в cron с периодом запуска 1 минута, то при обновлении адреса время потери составит связи не больше 1 минуты.
URL:
Обсуждается: http://www.opennet.me/tips/info/2909.shtml