Подключаем резервный канал интернет в роутере с прошивкой dd-wrt

от автора

Неприятно, если у провайдера авария и у вас дома пропал доступ в интернет. Вдвойне неприятно, если в этот момент вы находитесь далеко от дома и вам нужно залезть на домашний компьютер или NAS. В моем случае застраховаться от падения канала мне помогла компания МГТС, заменив устаревшую медь на оптику, с которой я получил ещё один канал интеренет, и чтение различных мануалов по dd-wrt. Если с оптикой я помочь не смогу, то готовым решением по dd-wrt я с удовольствием поделюсь.

Решение не универсальное, но, как мне кажется, очень простое и на его основе неискушенные пользователи смогут, если не создать свое, то просто расширить свой кругозор и понимание этой популярной прошивки.


Я использую роутер asus rt-n16 и прошивку от тов. Kong 22000++. Интернет от основного провайдера приходит ко мне по кабелю, все настройки получаются роутером по dhcp. В интерфейса dd-wrt это выглядит как-то так:

Фактически, все по умолчанию. Адрес роутера во внутренней сети сменен на 192.168.199.1.

Переключение каналов интернета будет выполняться скриптом, который мы создадим во внутренней памяти роутера JFFS2, соответственно, нужно эту внутреннюю память включить. Для этого в разделе Administration-Mangement интерфейса dd-wrt включим соответствующую опцию:

После включения JFFS2 память нужно очистить. Для этого выберем «Clean JFFS2» и нажмем применить. Возможно, нужно будет перезагрузить роутер. Наша задача — добиться того, чтобы появилось свободное место в этой памяти.

Теперь зайдем на роутер при помощи telnet. Я использую для этого putty:

putty -telnet 192.168.199.1

Имя пользователя root, даже если для логина в вебинтерфейс dd-wrt вы используете другое имя. Пароль — тот, который вы используете для логина в вебинтерфейс.

Лирическое отступление

Первая команда, которую мы введем и её результат у меня

root@DD-WRT:~# nvram show >/dev/null size: 29978 bytes (2790 left) 

Как видите, свободных байт в nvram немного и именно поэтому мы там не станет хранить наши скрипты. Если эта память исчерпается, то роутер перезагрузиться и восстановит все конфиги dd-wrt по умолчанию. Поэтому же, не стоит, например, загружать сертификаты openvpn в вебинтерфейсе, потому как сохраненные через вебинтерфейс сертификаты будут храниться в переменных nvram. Сертификаты openvpn можно хранить в памяти jffs2 и подключать их в переменной «additional config» настроек openvpn таким образом:

Следующий шаг. Мы подключаем резервный кабель в порт LAN1 роутера. В моем случае резервный кабель идет от оборудования GPON, которое поставил МГТС. Это оборудование раздает интернет в своей локальной сети 192.168.100.0/255.255.255.0. Нам нужно будет «оторвать» необходимый порт нашего роутера от остальных портов и назначить ему адрес из сети оборудования GPON, например, 192.168.100.200.

Теперь информация специфичная для конкретной железки, а именно asus rt-n16. Наберем в терминале следующие команды и посмотрим ответ:

root@DD-WRT:~# nvram show | grep vlan.*port vlan2ports=0 8 vlan0ports=1 2 3 4 5* vlan1ports=4 3 2 1 8* size: 29978 bytes (2790 left) root@DD-WRT:~# nvram show | grep vlan.*hw vlan2hwname=et0 vlan1hwname=et0 vlan0hwname=et0 size: 29978 bytes (2790 left) 

Группы портов объединенны в вэланы. Порт 0 — это WAN порт роутера, порты 1234 — это порты роутера, которые соответствуют (внимание!) портам LAN4,LAN3,LAN2,LAN1 роутера, то есть порт 4 подписан на корпусе роутера LAN1. Порт 8 и порт 8* — это порты процессора, через них мы будем видеть интерфейсы в роутере. Я не хочу вдаваться в подробности, принципиально то, что любой вэлан должен замыкаться на процессор роутера. Давайте «оторвем» 4-ый порт:

root@DD-WRT:~# nvram set vlan0ports="1 2 3 5*" root@DD-WRT:~# nvram set vlan1ports="3 2 1 8*" 

а теперь назначим 4 порт в 3-ий вэлан

root@DD-WRT:~# nvram set vlan3ports="4 8" 

для того, чтобы новый вэлан был виден, нужно ввести команду

root@DD-WRT:~# nvram set vlan3hwname=et0 

сохраним изменения

root@DD-WRT:~# nvram commit 

По аналогии, можно сделать для других роутеров с прошивкой dd-wrt.

Теперь нелирическое отступление. В вебинтерфейсе ddwrt есть настройки вэланов. Но если попробовать с ними поиграть, то мало того, что ничего не получится, но может случиться, что дальше поможет только сброс роутера.

А теперь лирическое отступление

Наверное каждый, кто читал про установку dd-wrt на роутер, сталкивался с магическим ритуалом «30 30 30». Это полный сброс роутера. Его настоятельно рекомендуют делать, иначе потом возможны проблемы. Теперь я вам объясню почему. Сброс настроек в вебинтерфейсе затрагивает не все переменные nvram, в частности, те изменения вэланов, которые мы наделали могут остаться. Поэтому ритуал действительно нужен. Но его можно заменить другой командой из терминала (при условии, что вы еще можете зайти на роутер):

root@DD-WRT:~# erase nvram root@DD-WRT:~# reboot 

Если вы «поиграли» с вэланами и все перестало работать, то вышеприведенные полный сброс «30 30 30» может помочь.

Адрес нашему новому интерфейсу, который связан с 4-ым портом, мы будем назначать из скрипта при старте. Поэтому, давайте начнём этот скрипт писать. Но прежде, где он будет храниться. Как учит нас Боконон dd-wrt wiki, всякий скрипт в папке /jffs/etc/config/ с расширением .startup выполняется при запуске системы до того, как файрвол будет сконфигурирован. Назовём наш скрипт vlan3.startup и напишем следующие строки:

#!/bin/sh WAN2_IFNAME=vlan3 WAN2_IPADDR=192.168.100.200 WAN2_GATEWAY=192.168.100.1 WAN2_NETMASK=255.255.255.0 if [ "$(nvram get wan2_ipaddr)" != "$WAN2_IPADDR" ]; then    nvram set wan2_ifname=$WAN2_IFNAME    nvram set wan2_ipaddr=$WAN2_IPADDR    nvram set wan2_gateway=$WAN2_GATEWAY    nvram set wan2_netmask=$WAN2_NETMASK    nvram commit fi ifconfig $(nvram get wan2_ifname) up $(nvram get wan2_ipaddr) netmask $(nvram get wan2_netmask) 

В этих строках всё просто. Мы завели в nvram 4-ре новые переменные и занесли в них название интерфейса, адрес, маску и шлюз для нашего резервного порта интернет. Каждый раз при старте мы проверяем, что адрес именно тот, который задан в переменной скрипта, это на случай, если потребуется поменять настройки резервного интернета. Далее кофигурируем порт заданными значениями. С текущими переменными это выглядело бы так:
ifconfig vlan3 up 192.168.100.200 netmask 255.255.255.0

Добавим к нашему скрипту бесконечный цикл, в котором и будем переключать интернет канал на резервный и обратно:

INTERVAL=30  while sleep $INTERVAL do         WAN1ALIVE=0         WAN2USING=0         WAN1GW=`nvram get wan_gateway`          echo "check"          if [ "$WAN1GW" != "0.0.0.0" ]; then                 if [ "1" = `ping -c 1 $WAN1GW 2>/dev/null | awk    '/packets received/ {print $4}'` ]; then                         WAN1ALIVE=1                         echo "wan1alive"                 fi         fi          TARGET=`ip -4 route list 0/0  | awk -v gate="via "$WAN2_GATEWAY '$0 ~ gate {print $3}'`         if [ ! -z "$TARGET" ]; then                 WAN2USING=1                 echo "wan2using"         fi          if [ "$WAN1ALIVE" = "1" ] && [ "$WAN2USING" = "1" ]; then                 /jffs/etc/config/wan1.up                 echo "Changed active WAN port to 1!"         fi          if [ "$WAN1ALIVE" = "0" ] && [ "$WAN2USING" = "0" ]; then                 if [ "1" = `ping -c 1 $WAN2_GATEWAY 2>/dev/null | awk '/packets received/ {print $4}'` ]; then                         /jffs/etc/config/wan2.up                         echo "Changed active WAN port to 2!"                 fi         fi  done; 

Словами этот длинный кусок кода можно описать так. Каждые n-цать секунд мы проверяем:

  1. Текущий адрес шлюза основного канала. Он хранится в переменной wan_gateway в nvram и назначается автоматически, когда основной шлюз получает параметры по dhcp от основного провайдера. Если этот адрес не равен «0.0.0.0», а «0.0.0.0» он равен тогда, когда адрес не может быть получен, то есть провайдер лежит, мы его пингуем и в случае ответа устанавливаем флаг WAN1ALIVE в единицу, то есть основной канал предполагается рабочим.
  2. Присутствует ли адрес резервного шлюза в таблице роутинга. Если присутствует, то устанавливаем флаг WAN2USING=1, то есть в данный момент используется резервный интернет канал.
  3. Если основной канал работает и используется резервный канал, то переключаемся на основной канал интернет.
  4. Если основной канал не работает и не используется резервный канал, то тестируем доступность шлюза резервного канала и переключаемся на рабочий резерв.

Скрипт включения основного канала wan1.up:

#!/bin/sh # WAN1 DEV=vlan2 GATEWAY=`nvram get wan_gateway` DNS1=8.8.8.8 DNS2=8.8.4.4  nvram set wan_dns="$DNS1 $DNS2" while ip route del default; do :; done ip route add default via $GATEWAY dev $DEV echo "nameserver $DNS1" >/tmp/resolv.dnsmasq echo "nameserver $DNS2" >>/tmp/resolv.dnsmasq pr="$(ps|awk '/dnsmasq/ {print $1}')" kill -9 $pr dnsmasq --conf-file=/tmp/dnsmasq.conf 

Здесь все просто. Удалили все шлюзы по умолчанию. Да-да, их может быть несколько: если после перезагрузки роутера был недоступен основной канал, то включается резервный интернет и мы имеем один шлюз по умолчанию. Если затем начинает работать основной канал, dd-wrt добавляет ещё один шлюз по умолчанию. Тут уж ничего не поделать. Не хотелось долго думать и появился «грязный хак»: while ip route del default; do :; done, а именно удалять все шлюзы по умолчанию, пока не случится ошибка из-за того, что шлюзов больше нет. Некрасиво, придумайте, как лучше.

После того, как удалили все шлюзы по умолчанию, добавим новый шлюз, который записан в переменную wan_gateway nvram (его туда записала логика dd-wrt при получения параметров от основного провайдера). Заменим dns на dns гугл, убьем процесс dnsmasq и запустим этот процесс вновь.

Скрипт для включения резервного канала wan2.up устроен таким-же образом, но адрес шлюза берётся из пременной wan2_gateway nvram и используется интерфейс связанный с 4-ым портом роутера.

#!/bin/sh # WAN2 DEV=vlan3 GATEWAY=`nvram get wan2_gateway` DNS1=8.8.8.8 DNS2=8.8.4.4  nvram set wan_dns="$DNS1 $DNS2" while ip route del default; do :; done ip route add default via $GATEWAY dev $DEV echo "nameserver $DNS1" >/tmp/resolv.dnsmasq echo "nameserver $DNS2" >>/tmp/resolv.dnsmasq pr="$(ps|awk '/dnsmasq/ {print $1}')" kill -9 $pr dnsmasq --conf-file=/tmp/dnsmasq.conf 

Остался маленький скриптик vlan3.wanup, который выполняется после поднятия WAN, сразу после того, как включится файрволл:

#!/bin/sh iptables -t nat -A POSTROUTING -o $(nvram get wan2_ifname) -j SNAT --to $(nvram get wan2_ipaddr) 

Назначение скриптика — добавить правило для ната через резервный интерфейс.

Теперь можно перезагрузить роутер и тестировать. Все скрипты были взяты из моего роутера который живёт своей жизнь и тестирует полученную конфигурацию продолжительное время.

Обобщенный скрипт

Вставляем в окно telnet\ssh следующую простыню и нажимаем «Enter»:

nvram set vlan0ports="1 2 3 5*" nvram set vlan1ports="3 2 1 8*" nvram set vlan3ports="4 8" nvram set vlan3hwname=et0 nvram commit mkdir -p /jffs/etc/config cat << 'EOF' > /jffs/etc/config/vlan3.startup #!/bin/sh WAN2_IFNAME=vlan3 WAN2_IPADDR=192.168.100.200 WAN2_GATEWAY=192.168.100.1 WAN2_NETMASK=255.255.255.0 if [ "$(nvram get wan2_ipaddr)" != "$WAN2_IPADDR" ]; then    nvram set wan2_ifname=$WAN2_IFNAME    nvram set wan2_ipaddr=$WAN2_IPADDR    nvram set wan2_gateway=$WAN2_GATEWAY    nvram set wan2_netmask=$WAN2_NETMASK    nvram commit fi ifconfig $(nvram get wan2_ifname) up $(nvram get wan2_ipaddr) netmask $(nvram get wan2_netmask)  INTERVAL=30  while sleep $INTERVAL do         WAN1ALIVE=0         WAN2USING=0         WAN1GW=`nvram get wan_gateway`          echo "check"          if [ "$WAN1GW" != "0.0.0.0" ]; then                 if [ "1" = `ping -c 1 $WAN1GW 2>/dev/null | awk    '/packets received/ {print $4}'` ]; then                         WAN1ALIVE=1                         echo "wan1alive"                 fi         fi          TARGET=`ip -4 route list 0/0  | awk -v gate="via "$WAN2_GATEWAY '$0 ~ gate {print $3}'`         if [ ! -z "$TARGET" ]; then                 WAN2USING=1                 echo "wan2using"         fi          if [ "$WAN1ALIVE" = "1" ] && [ "$WAN2USING" = "1" ]; then                 /jffs/etc/config/wan1.up                 echo "Changed active WAN port to 1!"         fi          if [ "$WAN1ALIVE" = "0" ] && [ "$WAN2USING" = "0" ]; then                 if [ "1" = `ping -c 1 $WAN2_GATEWAY 2>/dev/null | awk '/packets received/ {print $4}'` ]; then                         /jffs/etc/config/wan2.up                         echo "Changed active WAN port to 2!"                 fi         fi  done; EOF chmod +x /jffs/etc/config/vlan3.startup cat << 'EOF' > /jffs/etc/config/vlan3.wanup #!/bin/sh iptables -t nat -A POSTROUTING -o $(nvram get wan2_ifname) -j SNAT --to $(nvram get wan2_ipaddr) EOF chmod +x /jffs/etc/config/vlan3.wanup cat << 'EOF' > /jffs/etc/config/wan1.up #!/bin/sh # WAN1 DEV=vlan2 GATEWAY=`nvram get wan_gateway` DNS1=8.8.8.8 DNS2=8.8.4.4  nvram set wan_dns="$DNS1 $DNS2" #`ip -4 route list 0/0  | awk '/default via/ {print "ip route delete default"}'` | sh # ip route delete default while ip route del default; do :; done ip route add default via $GATEWAY dev $DEV echo "nameserver $DNS1" >/tmp/resolv.dnsmasq echo "nameserver $DNS2" >>/tmp/resolv.dnsmasq pr="$(ps|awk '/dnsmasq/ {print $1}')" kill -9 $pr dnsmasq --conf-file=/tmp/dnsmasq.conf EOF chmod +x vi /jffs/etc/config/wan1.up cat << 'EOF' > /jffs/etc/config/wan2.up #!/bin/sh # WAN2 DEV=vlan3 GATEWAY=`nvram get wan2_gateway` DNS1=8.8.8.8 DNS2=8.8.4.4  nvram set wan_dns="$DNS1 $DNS2" #`ip -4 route list 0/0  | awk '/default via/ {print "ip route delete default"}'`|sh # ip route delete default while ip route del default; do :; done ip route add default via $GATEWAY dev $DEV echo "nameserver $DNS1" >/tmp/resolv.dnsmasq echo "nameserver $DNS2" >>/tmp/resolv.dnsmasq pr="$(ps|awk '/dnsmasq/ {print $1}')" kill -9 $pr dnsmasq --conf-file=/tmp/dnsmasq.conf EOF chmod +x /jffs/etc/config/wan2.up 

Безусловно, можно и нужно многое поправить\добавить, но моя цель, а именно быстро прикрутить дома резервный канал — выполнена. Главная неприятность — это файрволл и проброс портов при работе с резервным каналом, мне они были не нужны, поэтому я не настраивал. Для тех, кому надо — дополняйте скрипт vlan3.wanup. Желаю удачи в ваших продолжениях!

Идеи статьи были почерпнуты из dd-wrt wiki.

ссылка на оригинал статьи http://habrahabr.ru/post/263163/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *