Под хабракатом приведены примеры скриптов, упрощающие жизнь :)
В своё время у Акадо наблюдались проблемы с авторизацией pppoe.
И поскольку при загрузке системы часть демонов привязывалась к получаемому ip адресу, то нужно было как-то автоматизировать процесс загрузки системы и исключить ситуацию простоя.
Идея заключалась в том, чтоб после запуска pppd проверять полученный от провайдера адрес.
Сам скрипт представляет из себя следующее:
и добавлен в /etc/rc.d/ppp.
Если не удалось получить требуемый адрес, то отправляем машинку в ребут.
Почему не пытаемся перезапустить сам демон ppp?
К моменту проверки ещё не многое запущено, поэтому исключаем версию о том, что перезагрузка будет долгой — до момента остановки процессов, а усложнять конструкцию очень не хотелось.
Помимо описанной выше ситуации могут случиться проблемы с потерей соединения.
Хочу оговориться, что полёт пакетов происходит след. образом:
Скрипт запускается по крону с периодом в 10 минут и если пинг неудачен до внутренних адресов, то пытаемся переполучить адрес от dhcp, до внешних — рестартим pppd.
Не забываем подставить свои значения проверяемых внутренних ресурсов (см. определение массива @check_ips).
В /var/log/ifaces.log можем отслеживать проблемы.
Само собой, можно было убрать использование модуля Touch и по иному описать часть операций, но мне в момент написания хотелось именно так :)
P.S.: используется FreeBSD, Perl 5.10.
Перл 5.8 будет ругаться на использование threads->list(threads::all).
Часть 1. Проверка получаемого адреса
В своё время у Акадо наблюдались проблемы с авторизацией pppoe.
И поскольку при загрузке системы часть демонов привязывалась к получаемому ip адресу, то нужно было как-то автоматизировать процесс загрузки системы и исключить ситуацию простоя.
Идея заключалась в том, чтоб после запуска pppd проверять полученный от провайдера адрес.
Сам скрипт представляет из себя следующее:
i=0
pppip="<my_ip>"
echo -e "waiting pppoe connection"
until [ "$i" -eq "30" ]
do
iconf=`/sbin/ifconfig tun0 | awk '/inet/ {print $2}'`
if [ "$iconf" = "$pppip" ]
then
echo -e "successful"
i="30"
break
else
i=`expr $i + 1`
echo -n "."
sleep 5
fi
done
if [ "$iconf" != "$pppip" ]
then
echo -e "pppoe not connected!\nSystem will be reboot"
reboot
fiи добавлен в /etc/rc.d/ppp.
Если не удалось получить требуемый адрес, то отправляем машинку в ребут.
Почему не пытаемся перезапустить сам демон ppp?
К моменту проверки ещё не многое запущено, поэтому исключаем версию о том, что перезагрузка будет долгой — до момента остановки процессов, а усложнять конструкцию очень не хотелось.
Часть 2. Проверка соединения
Помимо описанной выше ситуации могут случиться проблемы с потерей соединения.
Хочу оговориться, что полёт пакетов происходит след. образом:
- для работы локальной сети используется адрес, выдаваемый от dhcp сервера провайдера;
- для выхода во вне используется pppoe.
Скрипт запускается по крону с периодом в 10 минут и если пинг неудачен до внутренних адресов, то пытаемся переполучить адрес от dhcp, до внешних — рестартим pppd.
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Touch;
use Net::Ping;
use Net::Ifconfig::Wrapper qw(Ifconfig);
my @check_hosts = qw/ya.ru google.com/;
my @check_ips = qw/172.18.1.1 172.18.1.2/;
my $int_if = 're0';
my $ext_if = 're1';
sub get_ips {
my ($iface) = @_ ;
my @ifaces = ();
my $info = Ifconfig('list', '', '', '');
unless ( defined($info->{$iface}) ) {
die "Couldn't find ip address on $iface\n";
}
for ( sort keys %{$info->{$iface}{'inet'}} ) {
push(@ifaces,$_);
}
if ( scalar(@ifaces) > 0 ) {
return \@ifaces;
}
else {
return undef;
}
}
sub ping_state {
my ($dst_src,$proto,$iface) = @_;
die "Check params in sub ping_state"
unless ( defined($dst_src) && ref($dst_src) eq 'ARRAY' );
$proto = ''
unless ( defined($proto) );
my $p = Net::Ping->new($proto);
my $int_ips = undef;
$int_ips = get_ips($iface)
if ( defined($iface) );
$p->bind($int_ips->[0])
if ( defined($int_ips) );
my $i = 0;
for my $sources ( @{$dst_src} ) {
if ( $p->ping($sources,10) ) {
$i++; last;
}
}
$p->close();
if ($i > 0) { return 1; }
else { return 0; }
}
sub do_log {
my ($message,$log_file) = @_;
$log_file = '/var/log/ifaces.log'
unless ( defined($log_file) );
unless ( -e "$log_file" ) {
touch($log_file) or die("Failed touch $log_file");
}
open(LOG,">> $log_file");
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
print LOG '[' . ($year+1900) .
'-' . ( ( $mon < 10 ) ? ( '0'.$mon ) : $mon ) .
'-' . ( ( $mday < 10 ) ? ( '0'.$mday ) : $mday ) .
' ' . ( ( $hour < 10 ) ? ( '0'.$hour ) : $hour ) .
':' . ( ( $min < 10 ) ? ( '0'.$min ) : $min ) .
':' . ( ( $sec < 10 ) ? ( '0'.$sec ) : $sec ) .
']' . "$message\n";
close LOG;
}
my $thr = threads->create(sub {
unless ( ping_state(\@check_ips,'tcp',$int_if) ) {
do_log("Check connect to LAN resources : failed");
system("dhclient $ext_if");
}
});
unless ( ping_state(\@check_hosts,'icmp') ) {
do_log("Check connect to WAN resources : failed");
opendir(RUN,'/var/run');
for ( grep {/tun\w+\.pid/} readdir(RUN) ) {
open(PID,'/var/run/' . "$_");
local $/ = undef;
my $pid = <PID>;
close(PID);
chop($pid);
kill(9,$pid);
}
closedir(RUN);
system("ppp -ddial akado");
}
foreach my $t ( threads->list(threads::all) ) {
$t->join();
}Не забываем подставить свои значения проверяемых внутренних ресурсов (см. определение массива @check_ips).
В /var/log/ifaces.log можем отслеживать проблемы.
Само собой, можно было убрать использование модуля Touch и по иному описать часть операций, но мне в момент написания хотелось именно так :)
P.S.: используется FreeBSD, Perl 5.10.
Перл 5.8 будет ругаться на использование threads->list(threads::all).