PDA

Показать полную графическую версию : [решено] Автоматическое изменение маршрутов


El Scorpio
18-10-2011, 03:15
Добрый день, прошу помощи в решении следующей проблемы
На работе есть прокси-сервер и два канала связи:
172.25.46.1 - спутниковый модем с большим лимитом предоплаченного трафика и очень большим пингом (около секунды)
172.25.46.254 - ADSL-модем с быстрым пингом, малым лимитом и периодической нестабильностью соединения.

Также есть ряд сайтов, созданных с применением новейших откатно-распилочных технологий. Эти сайты содержат множество скриптов, которые генерируют множество мелких запросов, каждый из которых за счёт большого пинга выполняется нецензурное количество времени.
Можно было бы просто прописать на прокси маршруты через DSL, но это соединение в нашей сельской местности временами работает ещё медленее (или не работает вовсе). В связи с чем планирую написать скрипт, который будет периодически мониторить DSL и переключать маршруты.

Основной алгоритм такой
1. Пинг маршрутизаторов обоих провайдеров и сравнение результатов
2. Если результат DSL лучше, то добавление маршрутов к сайтам по списку (из файла)
3. Если результат DSL хуже, то удаление маршрутов к сайтам по списку (из файла)

По первому пункту. Команда ping выдаёт следующий результат
11 packets transmitted, 10 received, 9% packet loss, time 10852ms
rtt min/avg/max/mdev = 789.661/1015.057/1258.212/156.293 ms, pipe 2
Указанный результат выводится в файл (на RAM-диск, дабы жёсткий до дыр не протереть :) )
Как выделить из этого процент потерянных пакетов и среднее время передачи?

P.S.
man sed прошу не писать...

PhilB
18-10-2011, 16:42
Как выделить из этого процент потерянных пакетов и среднее время передачи? »
Конечно решение не идеально, но работает.
Процент потерянных пакетов:
cat 1 | sed 's/[^0-9 ]//g;q' | awk '{print $3;}'
Среднее время передачи:
cat 1 | sed 's/[^0-9 ]//g;q' | awk '{print $4;}'
где 1 - имя файла с результатом пинга.

El Scorpio
20-10-2011, 09:06
PhilB, спасибо. Правда, во второй строке была небольшая ошибка, вызванная использованием символа '/' для разделения цифр. Пришлось добавить дополнительную замену

В общем, получилось следующее
#!/bin/bash

# Адрес маршрутизатора второго канала связи
gateway=192.168.1.254
# Адрес маршрутизатора второго провайдера
provider=*.*.*.*
# Адрес сервера в сети интернет, по которому проводится проверка
testserver=8.8.8.8
# Максимально допустимое время прохождения сигнала по второму каналу (в микросекундах)
maxpingtime=500000
# Максимально допустимый процент потери пакетов
maxpinglost=50
# Количество пакетов, используемых для проверки прохождения сигнала
countping=10
# Имя временного файла, в который выводятся результаты проверки (создаётся на RAM-диске)
testpingfile=/tmp/ramdrive/testping
# Имя временного файла, наличие которого означает изменение маршрутов (создаётся на RAM-диске)
usingroutesfile=/tmp/ramdrive/chroutelock
# Имя файла протокола переключения маршрутов
logfile=/var/log/chroute.log
# Флаг хорошей связи (пустое значение означает ложность)
goodlink=
# Файл списка сайтов, работа с которыми будет выполняться по дополнительному каналу (автоматически создаётся при необходимости)
newfilehostlist=/etc/chroute/hosts.lst
[ -a $newfilehostlist ] || touch $newfilehostlist
# Копия файла списка сайтов на RAM-диске (автоматически создаётся при необходимости)
oldfilehostlist=/tmp/ramdrive/chroutehosts.lst
[ -a $oldfilehostlist ] || touch $oldfilehostlist
# Список новых сайтов
newhostlist=$(cat $newfilehostlist | grep -v \#)
# Список действующих сайтов
hostlist=$(cat $oldfilehostlist | grep -v \#)
echo $newhostlist
echo $hostlist

## Функция проверки качества линии связи
testroute()
{
route add -host $testserver gw $gateway metric 1
ping $testserver -c $countping | tee $testpingfile 2>&1
route del -host $testserver
testpinglost=$(grep "packets transmitted" $testpingfile | sed 's/[^0-9 ]//g;q' | awk '{print $3;}')
testpingtime=$(grep "rtt min/avg/max/mdev" $testpingfile | sed 's%\/%\ %g' | sed 's/[^0-9 ]//g;q' | awk '{print $2;}' )
if [[ $testpinglost -gt $maxpinglost ]]
then
echo "Обнаружено $testpinglost потерянных пакетов, связь по данному каналу неустойчива"
elif [[ $testpingtime -gt $maxpingtime ]]
then
echo "Время прохождения пакетов по данному каналу $testpingtime превышает разрешённое $maxpingtime"
else
goodlink=true
echo "Канал связи работает"
fi
}

## Функция добавления маршрутов по списку $hostlist
addroutes()
{
for hostname in $hostlist
do
echo "Добавляется маршрут к $hostname"
route add -host $hostname gw $gateway metric 1
done
touch $usingroutesfile
}

## Функция удаления маршрутов по списку $hostlist
delroutes()
{
for hostname in $hostlist
do
echo "Удаляется маршрут к $hostname"
route delete -host $hostname
done
rm $usingroutesfile
}

## Функция обновления маршрутов
syncroutes()
{
# Если связь была хорошая, то удалить старые маршруты
[ -a $usingroutesfile ] && delroutes
# Обновить список маршрутов (во временном файле и в памяти)
if [ -a $newfilehostlist ]
then
cp $newfilehostlist $oldfilehostlist
else
rm $oldfilehostlist
fi
hostlist=$newhostlist
# Если связь хорошая, то добавить новые маршруты
[ $goodlink ] && addroutes
}

## Основной код программы

# добавляется маршрут до узла провайдера (при необходимости)
[[ $( route -n | grep $provider | wc -l ) > 0 ]] || route add -host $provider gw $gateway metric 1

testroute
if [[ "$hostlist" != "$newhostlist" ]]
then
echo $(date +%F\ %T)": Изменён файл списка сайтов, производится обновление маршрутов" | tee -a $logfile
syncroutes
elif [[ $goodlink && ! -a $usingroutesfile ]]
then
echo $(date +%F\ %T)": Связь по дополнительному каналу работает, производится добавление маршрутов" | tee -a $logfile
addroutes
elif [[ ! $goodlink && -a $usingroutesfile ]]
then
echo $(date +%F\ %T)": Проблемы связи по дополнительному каналу, производится удаление маршрутов" | tee -a $logfile
delroutes
fi

exit


Если кто найдёт и поможет исправить ошибку, буду очень признателен.
Желающим использовать этот скрипт в работе, использование и дальнейшую модификацию разрешаю

El Scorpio
25-10-2011, 07:56
Упс, нашёл баг в функции delroutes , из-за которого не удаляются маршруты к некоторым сайтам

Я исходил из того, что команда route del -host $hostname определяет IP хоста по его имени, а затем удаляет из таблицы маршрутизации строку с соответствующим IP и маской 255.255.255.255.
Однако всё словно происходит с точностью до наоборот: команда определяет имена хостов для всех строк таблицы маршрутизации, а затем ищет среди них нужную. При этом, если для какого-то адреса поиск в "обратной зоне DNS" возвращает другое (!!!) имя сайта (например www.XXXX.ru вместо XXXX.ru), то вместо удаления выводится сообщение об отсутствии указанного маршрута.

Значит нужно удалять маршрут по IP-адресу сайта, а для этого его нужно сначала определить. Например, вот так:
ip=$(ping $hostname -c 1 | head -n 1 | sed ... )
# в результате получается
# PING имя.сайта (ip.адрес.сайта) 56(84) bytes of data.

Какие параметры для команды sed указать, чтобы получить значение между первыми скобками?

PhilB
25-10-2011, 20:35
Вроде так
sed '/[^(]*(\([^ ]*\)).*/s//\1/g'

El Scorpio
03-11-2011, 03:38
Итак, предлагаю вашему вниманию исправленную и доработанную версию скрипта, который автоматически переключает маршруты к определённым сайтам. Распространение приветсвуется


#!/bin/bash

# Адрес маршрутизатора второго канала связи
gateway=192.168.1.254
# Адрес маршрутизатора второго провайдера
provider=x.x.x.x
# Адрес сервера в сети интернет, по которому проводится проверка
testserver=8.8.8.8
# Максимально допустимое время прохождения сигнала по второму каналу (в микросекундах)
maxpingtime=1000000
# Максимально допустимый процент потери пакетов
maxpinglost=50
# Количество пакетов, используемых для проверки прохождения сигнала
countping=10
# Имя временного файла, в который выводятся результаты проверки (создаётся на RAM-диске)
testpingfile=/tmp/ramdrive/testping
# Имя временного файла, наличие которого означает изменение маршрутов (создаётся на RAM-диске)
usingroutesfile=/tmp/ramdrive/chroutelock
# Имя файла протокола переключения маршрутов
logfile=/var/log/chroute.log
# Флаг хорошей связи (пустое значение означает ложность)
goodlink=
# Файл списка сайтов, работа с которыми будет выполняться по дополнительному каналу newfilehostlist=/etc/chroute/hosts.lst
# если файл отсутствует, то создаётся автоматически
[ -a $newfilehostlist ] || touch $newfilehostlist
# Копия файла списка сайтов на RAM-диске
oldfilehostlist=/tmp/ramdrive/chroutehosts.lst
# если файл отсутствует, то создаётся автоматически
[ -a $oldfilehostlist ] || touch $oldfilehostlist
# Список новых сайтов. Записи добавляются построчно. Лишние можно закомментировать "решёткой"
newhostlist=$(cat $newfilehostlist | grep -v \#)
# Список действующих сайтов
hostlist=$(cat $oldfilehostlist | grep -v \#)

echo $newhostlist
echo $hostlist

## Функция проверки качества линии связи
testroute()
{
# добавление временного маршрута к тестовому серверу и проверка прохождения сигнала
route add -host $testserver gw $gateway metric 1
ping $testserver -c $countping | tee $testpingfile 2>&1
route del -host $testserver
# выделение значений из результатов пинга
testpinglost=$(grep "packets transmitted" $testpingfile | sed 's/[^0-9 ]//g;q' | awk '{print $3;}')
testpingtime=$(grep "rtt min/avg/max/mdev" $testpingfile | sed 's%\/%\ %g' | sed 's/[^0-9 ]//g;q' | awk '{print $2;}' )
# если процент потерянных пакетов превышает максимальный
if [[ $testpinglost -gt $maxpinglost ]]
then
echo "Обнаружено $testpinglost потерянных пакетов, связь по данному каналу неустойчива"
# если среднее время прохождения сигнала превышает максимальное
elif [[ $testpingtime -gt $maxpingtime ]]
then
echo "Время прохождения пакетов по данному каналу $testpingtime превышает разрешённое $maxpingtime"
else
goodlink=true
echo "Канал связи работает"
fi
}

## Функция добавления маршрутов по списку $hostlist
addroutes()
{
for hostname in $hostlist
do
echo "Добавляется маршрут к $hostname"
route add -host $hostname gw $gateway metric 1
done
touch $usingroutesfile
}

## Функция удаления маршрутов по списку $hostlist
delroutes()
{
for hostname in $hostlist
do
echo "Удаляется маршрут к $hostname"
# При выполнении "route delete -host" производится поиск имени хоста среди списка имён.
# Список имён формируется в процессе обратной расшифровки адресов в имена.
# Если в результате обратной расшифровки возвращается имя, отличное от исходного,
# то команда удаления найти маршрут по исходному имени не может
# Посему приходится сначала определять IP-адрес по имени сайта, а потом удалять маршрут по этому IP-адресу
ip=$(ping $hostname -c 1 | head -n 1 | sed '/[^(]*(\([^ ]*\)).*/s//\1/g')
echo "Для сайта $hostname IP-адрес равен $ip"
route del -host $ip
done
rm $usingroutesfile
}

## Функция обновления маршрутов
syncroutes()
{
# Если связь была хорошая, то удалить старые маршруты
[ -a $usingroutesfile ] && delroutes
# Обновить список маршрутов (во временном файле и в памяти)
if [ -a $newfilehostlist ]
then
cp $newfilehostlist $oldfilehostlist
else
rm $oldfilehostlist
fi
hostlist=$newhostlist
# Если связь хорошая, то добавить новые маршруты
[ $goodlink ] && addroutes
}

## Основной код программы

# добавляется маршрут до узла провайдера (если отсутствует)
[[ $( route -n | grep $provider | wc -l ) > 0 ]] || route add -host $provider gw $gateway metric 1

testroute
if [[ "$hostlist" != "$newhostlist" ]]
then
echo $(date +%F\ %T)": Изменён файл списка сайтов, производится обновление маршрутов" >> $logfile
syncroutes
# Если связь хорошая и нет файла-флага добавленных маршрутов
elif [[ $goodlink && ( ! -a $usingroutesfile ) ]]
then
echo $(date +%F\ %T)": Связь по дополнительному каналу работает, производится добавление маршрутов" >> $logfile
addroutes
# Если связь плохая и есть флаг-файл добавленных маршрутов
elif [[ ! $goodlink && ( -a $usingroutesfile ) ]]
then
echo $(date +%F\ %T)": Проблемы связи по дополнительному каналу, производится удаление маршрутов" >> $logfile
delroutes
fi
# Комбинации состояний "связь хорошая, маршруты уже добавлены" и "связь плохая, маршруты уже удалены" действий не требуют

exit




Монтирование RAM-диска производится через файл /etc/fstab
tmpfs /tmp/ramdrive tmpfs nosuid,nodev,noatime,nodiratime 0 0




© OSzone.net 2001-2012