LINUX.ORG.RU
ФорумAdmin

Скрипт переключения на резервного провайдера


0

1

На днях сбойнул провайдер в офисе, что навело меня на мысль сделать скрипт для крона, который бы автоматически переключал на резервный канал в случае сбоев с основным. К сожалению, в bash понимаю туго, но накидал тут скрипт из разных примеров. Прошу критики и советов, как правильно реализовать.

Сервер, на котором все это крутится, является интернет шлюзом и раздает интернет в офис через iptables/NAT.

Что собственно хочу сделать. Оба интернет-канала постоянно включены на шлюзе, но резервный должен использоваться только в случае сбоев на основном. Скрипт должен проверять наличие доступа до нескольких хостов, если ничего не получается, врубать резервный канал, меняя настройки iptables. В следующий запуск скрипт пытается включить обратно основной канал и снова проверяет доступность хостов. Если они доступны, включает основной канал, блокирует резервный, иначе - оставляет резервный.

Основные вопросы:

  • как правильно запретить использование поднятого интерфейса (т.е. чтобы резервный канал, будучи активным, не передавал трафик кроме служебного)?
  • можно ли внутри скрипта передавать аргументы другому скрипту и как правильно это делать?
  • много раз видел, как на домашней машине под оффтопиком вылезают сообщения от провайдера о плановых работах. Используется какая-то сетевая служба Windows. Можно ли посылать подобные сообщения с Linux-сервера в локальную сеть, чтобы менеджеры (на WindowsXP) явно видели, что сидят на резервном канале?

Заготовка скрипта:

#!/bin/bash

#Переменные
p=0
#1) контрольные адреса
check="	ya.ru
	google.com"
#2) каналы провайдеров
WAN1=ppp0 #основной
WAN2=ppp1 #резервный
#3) скрипты iptables
sh=/root/scripts/firewall.sh

#Переключение на основной канал
if [ -e /dev/$WAN1 ]
	then route add default gw $WAN1
	else route add default gw $WAN2 && sh $sh $WAN2 && exit 0 #тут пытаюсь передать аргумент вызываемому скрипту
fi

#Проверка доступности хостов
for ips in $check
do
  echo $ips
  i=$(/bin/ping -c 4 $ips | grep "received" | awk '{print $4}')
  let "p = p + i"
done

if [ p == 0 ]
	then route add default gw $WAN2 && sh $sh $WAN2
	else sh $sh $WAN1 && exit 0
fi

exit 0

>как правильно запретить использование поднятого интерфейса (т.е. чтобы резервный канал, будучи активным, не передавал трафик кроме служебного)?

iptables+iproute2. Должно хватить для любых, даже самых извращенных случаев

можно ли внутри скрипта передавать аргументы другому скрипту и как правильно это делать?


Бегом читать Advanced Bash Scripting Guide. Есть перевод на русский - там такие вещи разжевываются просто и понятно. Вкратце - смотри в сторону переменных $1(первый параметр), $2(второй параметр) и т.д. , $*(все параметры).

много раз видел, как на домашней машине под оффтопиком вылезают сообщения от провайдера о плановых работах.


O_O

Используется какая-то сетевая служба Windows.


скорее всего net send.

Можно ли посылать подобные сообщения с Linux-сервера в локальную сеть, чтобы менеджеры (на WindowsXP) явно видели, что сидят на резервном канале?


подними джаббер-сервер и подключи всех манагеров к нему, скриптом рассылай что хочешь

Pinkbyte ★★★★★ ()
Ответ на: комментарий от Pinkbyte

>Бегом читать Advanced Bash Scripting Guide

Про $1 знаю. Вопрос был в том, можно ли из одного скрипта вызвать другой с аргументами. Т.е., если внутри скрипта 1 будет строка 'sh script2 $var1', то будет ли во втором скрипте выполняться $1==$var1?

скорее всего net send

Оно. Уже понял, что через smbclient можно делать, пока разбираюсь, как именно (на свою же домашнюю машину пока не могу послать)

O_O

У самого butthurt, что эти сообщения вылезают на компе за NATом (думал, что прямое обращение к компу невозможно без проброса на рутере)

подними джаббер-сервер

Лишние сущности, да еще и морока с пересаживанием менеджеров. Лучше разберусь с smblient, благо он уже есть на сервере.

MahMahoritos ★★★ ()
Ответ на: комментарий от Pinkbyte

iptables+iproute2

Допустим, делаю так, чтобы заблочить ppp0 и использовать ppp1:

iptables -A INPUT -i ppp0 -j DROP
iptables -A OUTPUT -i ppp0 -j DROP
route del default
route add default dev ppp1

Приведет ли оно к блокировке этого интерфейса или вызовет глюки в сети? Собственно и спрашиваю, как именно правильно заблочить интерфейс, чтобы по нему трафик без надобности не гулял.

MahMahoritos ★★★ ()

много раз видел, как на домашней машине под оффтопиком вылезают сообщения от провайдера о плановых работах. Используется какая-то сетевая служба Windows. Можно ли посылать подобные сообщения с Linux-сервера в локальную сеть, чтобы менеджеры (на WindowsXP) явно видели, что сидят на резервном канале?

Очевидно net send. Оно доступно через smbclient для отправки. И сервер самбы может ринимать такие, оно довольно просто настраивается, принимет текст и делает с ним что хочешь, например вывешивает юзеру через zenity/kdialog прямо как в венде. Я так на последнем рабочем месте рассылки принимал. Линуксовая тачка состояла в домене, сам вводил :)

erfea ★★★★★ ()
Ответ на: комментарий от MahMahoritos

>как именно правильно заблочить интерфейс, чтобы по нему трафик без надобности не гулял.

если радикально - ifconfig iface down. Но тогда ты хрен определишь - поднялось ли там что или нет. Достаточно убрать маршруты(так ты уберешь исходящие и часть транзитного трафика через этот интерфейс) и, если уж мучает паранойя, забань входящий трафик через iptables. Только related,established пакеты оставь - мало ли что...

Pinkbyte ★★★★★ ()
Ответ на: комментарий от MahMahoritos

Про $1 знаю. Вопрос был в том, можно ли из одного скрипта вызвать другой с аргументами. Т.е., если внутри скрипта 1 будет строка 'sh script2 $var1', то будет ли во втором скрипте выполняться $1==$var1?

Что значит «выполняться» в данном случае? Мыслите в терминах подстановок. Строка

sh script2 $var1
в скрипте при исполнении преобразуется к виду
sh script2 VAR1_CONTENTS
ну и соответственно VAR1_CONTENTS будет содержаться во втором скрипте в $1. До самой переменной $var1 вы из внутреннего скрипта не доберётесь, если её не export-ите, но тогда и никакой передачи через аргумент не потребуется.

undertaker ★★ ()

#!/bin/sh

T1=`ping -c 2 -S (поставить ip адрес основного канала подробней man ping) 80.75.128.101 | grep transmitted | awk '{print $4}'`
echo $T1
if [ $T1 = 2 ]; then
{
echo «Основной »
route -nq change default 89.XX.XX.XX
}
fi
if [ $T1 = 0 ];then
{
echo «rezerv»
route -nq change default 82.XX.XX.XX
}
fi
exit
Данный скрипт не дергает канал туда сюда если стоим на резерве.
Проверяет от основного канала и ip адреса этого интерфейса.
Ну и впринципе потом меняем маршруты ну и все что нам нужно.

pvvking ★★ ()

Некоторые соображения в тему...

  • Что понимать под «сбоем интернет канала»? Варианты:
    • Исчезновение линка на сетёвке / отвал ppp-соединения / полное отсутствие входящего трафика. Тут более-менее всё понятно. Детектим одну из подобных ситуаций и «переключаем» маршруты куда надо.
    • Линк (ppp) есть, но интернета нет. Тут сложнее, так как часто интернет отваливается не целиком, а кусками. В таких случаях запросто могут работать яндекс и локальные сервера гугла, а весь остальной «забугор» - фиг. ИМХО единственный нормальный способ бороться с таким - в контрольный список для пинговалки добавлять основные сервера, доступ к которым нужен для работы: почтовый, vpn, сайт компании и так далее.
  • Лучше пинговать по IP-адресам, так как иначе детектор будет срабатывать при глюках DNS-сервера. Чтобы не «хардкодить» IP'шники в скрипт, можно сделать что-то вроде простого кеша, то есть если DNS-работает, то запрашивать IP с него, если нет - читать из кеша.
  • Если основной канал идёт через PPP и надо использовать резервный только в случае отвала всего канала (первый случай в списке выше), то можно обойтись без скриптов. Достаточно держать два маршрута по умолчанию, причём у маршрута на основной канал метрику сделать меньше, чем у маршрута на резервный. Тогда при отвале основного ppp ядро будет автоматически отправлять трафик по резервному маршруту.

Вот как-то так...

Deleted ()
Ответ на: комментарий от MahMahoritos

Вижу что топик старый, но все ж спрошу: автору удалось толково реализовать задумку? Подобная задача встала и передо мной.

Stranger03 ()
Ответ на: комментарий от Stranger03

Вроде бы получилось. У меня 3 сервера, на 2х из них инет доставляется провайдером через DHCP напрямую. На 3ем же разделены внутренняя сеть прова (DHCP) и интернет (через VPN). Первые два сервера нормально живут со скриптами уже два месяца, за это время проблем не было, даже когда в одном из них оказалась глючащая сетевуха (нужно было периодически перезапускать соединение). С третьим же сервером пока не все гладко.

Сначала кратко суть скриптов. В случае DHCP все просто: проверяем внешние ресурсы на доступность пингом, если пинги проходят, завершаем скрипт, если же нет - перезапускаем соединение, пишем логи.

В случае VPN скрипт работает схоже. Проверяется доступность внешних ресурсов, если они недоступны, проверяем доступность ресурсов провайдера (я решил взять DNS-серверы), если последние доступны, перезапускаем только VPN, иначе - перезапускаем все интерфейсы. Проблема оказалась в том, что однажды скрипт обнаружил отсутствие Интернет и постоянно перезапускал VPN, что не решало проблему. Так что этот скрипт еще надо будет доработать. Возможно, сделать общий перезапуск всех интерфейсов обязательным при любой неполадке.

MahMahoritos ★★★ ()
Ответ на: комментарий от Stranger03

Собственно скрипты:
Скрипт для DHCP:

#!/bin/bash

#Объявление переменных
#Список адресов для проверки сети
list=ip.list
#Внутренние переменные для работы скрипта
declare -i a=0
declare -i p=0
#Переменные времени для логов и дампов
sysdat=$(date +%Y.%m.%d)
datum=$(date +%Y%m%d)
clock=$(date +%H:%M)
#Внешний сетевой интерфейс (его перезапускаем при проблемах)
inter=wan
#Расположение системного лога
syslog=/var/log/messages

#Переменные для определения запуска
LCK_FILE=`basename $0`.lck

#Определение рабочей директории и переход в нее
rootdir=$(cd $(dirname $0) && pwd);
cd $rootdir

#Проверка работы существующего скрипта
if [ -f "${LCK_FILE}" ]; then
	# The file exists so read the PID
	# to see if it is still running
	MYPID=`head -n 1 "${LCK_FILE}"`
	TEST_RUNNING=`ps -p ${MYPID} | grep ${MYPID}`
	if [ -z "${TEST_RUNNING}" ]; then
		# The process is not running
		# Echo current PID into lock file
		echo $$ > "${LCK_FILE}"
	else
		exit 0
	fi
else
	echo $$ > "${LCK_FILE}"
fi

#Проверка сети
for ip in $(cat $list); do
	p=$(/bin/ping -q -c 2 -t 200 $ip | grep "received" | awk '{print $4}')
	let a=$a+$p
	if [[ "$a" != 0 ]]
		then
			rm -f "${LCK_FILE}"
			exit 0
	fi
done

mkdir -p dumps/
touch dumps/dmesg-$datum.dump && touch dumps/messages-$datum.dump
echo "Дамп ядра от $clock $sysdat" >> dumps/dmesg-$datum.dump
dmesg | tail -n 100 >> dumps/dmesg-$datum.dump
echo "Срез системного лога от $clock $sysdat" >> dumps/messages-$datum.dump
tail -n 100 $syslog >> dumps/messages-$datum.dump
/etc/init.d/net.$inter restart
echo "$(date) - Restarting WAN due to connection problems" >> check.log

rm -f "${LCK_FILE}"
exit 0

Скрипт для VPN

#!/bin/bash

#Объявление переменных
#Список адресов для проверки сети
#Внешние
listext=ip_ext.list
#Внутренние
listint=ip_int.list
#Внутренние переменные для работы скрипта
declare -i a=0
declare -i p=0
#Переменные времени для логов и дампов
sysdat=$(date +%Y.%m.%d)
datum=$(date +%Y%m%d)
clock=$(date +%H:%M)
#Внешний сетевой интерфейс (его перезапускаем при проблемах)
#Основной
interint=eth0
#VPN
interext=ppp0
#Туннель OpenVPN
intervpn=tun0
#Расположение системного лога
syslog=/var/log/messages

#Переменные для определения запуска
LCK_FILE=`basename $0`.lck

#Определение рабочей директории и переход в нее
rootdir=$(cd $(dirname $0) && pwd);
cd $rootdir

#Проверка работы существующего скрипта
if [ -f "${LCK_FILE}" ]; then
	# The file exists so read the PID
	# to see if it is still running
	MYPID=`head -n 1 "${LCK_FILE}"`
	TEST_RUNNING=`ps -p ${MYPID} | grep ${MYPID}`
	if [ -z "${TEST_RUNNING}" ]; then
		# The process is not running
		# Echo current PID into lock file
		echo $$ > "${LCK_FILE}"
	else
		exit 0
	fi
else
	echo $$ > "${LCK_FILE}"
fi

#Проверка сети по внешним серверам
for ip in $(cat $listext); do
	p=$(/bin/ping -q -c 2 -t 200 $ip | grep "received" | awk '{print $4}')
	let a=$a+$p
	if [[ "$a" != 0 ]]
		then
			rm -f "${LCK_FILE}"
			exit 0
	fi
done

#Проверка сети по внутренним серверам
for ip in $(cat $listint); do
	p=$(/bin/ping -q -c 2 -t 200 $ip | grep "received" | awk '{print $4}')
	let a=$a+$p
	if [[ "$a" != 0 ]]
		then					
			mkdir -p dumps/
			touch dumps/dmesg-$datum.dump && touch dumps/messages-$datum.dump
			echo "Дамп ядра от $clock $sysdat" >> dumps/dmesg-$datum.dump
			dmesg | tail -n 100 >> dumps/dmesg-$datum.dump
			echo "Срез системного лога от $clock $sysdat" >> dumps/messages-$datum.dump
			tail -n 100 $syslog >> dumps/messages-$datum.dump
			/etc/init.d/net.$interext restart
			echo "$(date) - Restarting VPN due to connection problems" >> check.log
			rm -f "${LCK_FILE}"
			exit 0
	fi
done

#Полный перезапуск внешних интерфейсов
mkdir -p dumps/
touch dumps/dmesg-$datum.dump && touch dumps/messages-$datum.dump
echo "Дамп ядра от $clock $sysdat" >> dumps/dmesg-$datum.dump
dmesg | tail -n 100 >> dumps/dmesg-$datum.dump
echo "Срез системного лога от $clock $sysdat" >> dumps/messages-$datum.dump
tail -n 100 $syslog >> dumps/messages-$datum.dump
/etc/init.d/net.$interext stop
/etc/init.d/net.$intervpn stop
/etc/init.d/net.$interint restart
sleep 10
/etc/init.d/net.$interext start
/etc/init.d/net.$intervpn start
echo "$(date) - Restarting all network due to connection problems" >> check.log

rm -f "${LCK_FILE}"
exit 0

MahMahoritos ★★★ ()
Ответ на: комментарий от MahMahoritos

Ок. Вижу скрипты эволюционировали по сравнению с первым постом. Они работают в паре или по отдельности? Буду разбираться вечерком, а то уже голова не варит. У меня два ppp соединения, основной adsl модем в бридже, резервный 3g модем. Спасибо за ответ.

Stranger03 ()

в общем случае описанное тобой не такая простая задач как кажется.

и да, metric over 1 в путях как бы намекает.xD

mumpster ★★★★★ ()
Ответ на: комментарий от Stranger03

Я уж забыл содержание этой темы... Выложенные мной скрипты не для резервного канала, а для простой проверки соединения и перезапуска при неполадке. Собственно переключение на резервный канал пока не реализовано

MahMahoritos ★★★ ()
Ответ на: комментарий от MahMahoritos

Печаль... А скрипт в первом посте не работает? Если одновременно держать 2 ppp соединения, скриптом проверять шлюз основного канала, при недоступности default route бросать на резервный и в firewall.sh писать ррр1?

Stranger03 ()
Ответ на: комментарий от Stranger03

Как-то сумбурно я написал предыдущий пост, с самого утра юзеры замучили. Вот набросал простой скрипт перехода только на резервный канал, обратное переключение ручками. Гляньте плиз:


#!/bin/bash

#Переменные
p=0

# контрольные адреса
check="8.8.8.8"



#Проверка доступности хостов
for ips in $check
do
  echo $ips
  i=$(/bin/ping -c 4 $ips | grep "received" | awk '{print $4}')
  let "p = p + i"
done

if [ p == 0 ]
	then poff dsl-provider && pon 3g
fi
В таком случае нет необходимости править firewall, так как внешний интерфейс будет ppp0.

Stranger03 ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.