ISP`s IT Аутсорсинг
Быстрый переход: Главная блога Главная сайта Форум
Если Вы чего то недопоняли или не нашли - задайте
вопрос на нашем форуме и мы попробуем Вам помочь.
Subnets.ru Регистрация IP и Автономных систем mega-net.ru

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

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

Для реализации этой задачи нам понадобится две вещи:

  1. порт ucspi-tcp
  2. небольшой perl скрипт

Приступим. Начнем с установки порта:

/usr/ports/sysutils/ucspi-tcp

ucspi-tcp is a set of command-line tools for building TCP-based
client/server applications.  They are compliant to UCSPI, the
UNIX Client-Server Program Interface.  UCSPI tools are available
for several different types of networks.
WWW: http://cr.yp.to/ucspi-tcp.html

cd /usr/ports/sysutils/ucspi-tcp
make install clean

После установки нам необходимо создать файл, в котором укажем какие IP-адреса или подсети, которые смогут обращаться к нам, например это будут:

  • 127.0.0.1
  • 10.100.1.0/24

для этого создадим файл /etc/tcp.server со следующим содержанием:

127.0.0.1:allow,RELAYCLIENT=»»
10.100.1.:allow,RELAYCLIENT=»»

Затем сформируем cdb файл:

/usr/local/bin/tcprules /etc/tcp.server.cdb /etc/tcp.server.tmp < /etc/tcp.server

Теперь напишем небольшой скрипт на perl, /usr/local/sbin/scripts/serv_main.pl.
Скрипту будут передаваться команды, вида:

  • cmd=X;
  • cmd=X PARAMS;

Можно передать все команды и одной строкой, разделяя их символом «;»

Для примера покажу обработку 3-х переданных команд:

  • cmd=1;                                      — вывод списка существуюших интерфейсов tun на данном сервере
  • cmd=2 -h 192.168.1.15;    — добавляем этот IP в firewall ipfw
  • cmd=3 ad4;                            — выводим температуру HDD
#!/usr/bin/perl                                                                                                                     

$scr_path="/usr/local/sbin/scripts";
$cr="\r\n";
$addr=$ENV {TCPREMOTEIP};
$date=`date "+[%Y-%m-%d %H:%M:%S]"`;
chomp($date);
#Открываем лог файл для записи
open(LOG,">>/var/log/serv.log");
if (chk($addr)){
        #Проверяем с какого IP к нам подключились и если его нет в списке (см. функцию chk), то запрещаем выполнение команд
        print "Forbidden".$cr;
        print LOG $date." [".$addr."]: Forbidden\n";
}else{
        #Скрипту может передаваться список команд разделенных символом ";"
        $arg=<STDIN>;
        @a=split(';',$arg);
        pop @a;
        print LOG $date." [".$addr."]: ".@a."\n";
        #Разбираем в цикле переданные команды
        foreach $par (@a){
                $e.="[".++$nn."]: ".$par."\n";
                $l.=$par." ";
                #Проверяем синтаксис переданной команды и разбираем параметры
                if ($par=~/cmd=(\d{1,2})\s*([\w.]*)/){
                        $b=$1;
                        if ($b eq "1"){
                                #Переданная команда cmd=1;
                                #Выполняем функцию cmd1
                                cmd1();
                        }elsif ($b eq "2"){
                                #Переданная команда cmd=2 -h 192.168.1.15;
                                if ($par=~/^cmd=2\s\-h\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/){
                                      $ip=$1;
                                      cmd2($ip);
                                }
                        }elsif($b eq "3"){
                                #Переданная команда cmd=3 ad4;
                                if ($par=~/^cmd=3\s(ad\d{1})$/){
                                           hdd_temp($1);
                               }
                        }
                }
        }
}
close LOG;                                                                                                                          

sub chk {
        #Проверяем IP с которого пытаются отдать команду
        my $ip=shift;
        if ($ip eq "127.0.0.1") {return 0;}
        if ($ip eq "10.100.1.2") {return 0;}
        return 1;
}
sub cmd1 {
    #Выводим список существующих на сервере интерфейсов tun
    @a=`netstat -rn | /usr/bin/grep tun`;
    foreach $tun (@a){
        chomp($tun);
                if ($tun=~/(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s+\S+\s+\S+\s+\S+\s+\S+\s+(tun\d+)/){
                        print $1.";".$2."\n";
                }
    }
}
sub cmd2 {
    #Добаляем переданный IP в firewall, в таблицу table(10)
    my $ip=shift;
    `/sbin/ipfw table 10 add $ip/32 0`;
     print "IP $ip added\n";
}
sub hdd_temp {
    #Выводим температуру жесткого диска
    my $hdd=shift;
    $hdd_temp=`/usr/local/sbin/smartctl -a /dev/$hdd | /usr/bin/grep '194 Temper' | /usr/bin/awk '{ print $10 }'`;
    print $hdd_temp;
}

На этих трех простых примерах можно понять что передавать и как обрабатывать полученные команды. Поле для вашего творчества неограниченно. Вы можете отрабатывать команды описанные в самом serv_main.pl или передавать эти параметры другим скриптам на сервере.

Сделаем файл /usr/local/sbin/scripts/serv_main.pl исполняемым:

/bin/chmod a+x /usr/local/sbin/scripts/serv_main.pl

Можете запустить его руками, убедиться, что он запускается и не содержит ошибок, запустим:

/usr/local/sbin/scripts/serv_main.pl

Затем введите команду:

cmd=1;

На экран будет выведен результат отпработки функции cmd1()

Подготовим стартовый скрипт 0_zstart.sh и расположим его в /usr/local/etc/rc.d:

#!/bin/sh

case "$1" in
start)
         ip=10.100.1.15
         port=5555
         path=/usr/local/sbin/scripts
         /usr/local/bin/tcpserver -v -H -R -l 0 -c 10 -x /etc/tcp.server.cdb ${ip} ${port} ${path}/serv_main.pl &
         echo ' Zserver started...'
         ;;
stop)
         /usr/bin/killall -9 tcpserver
         echo ' Zserver stoped...'
         ;;
*)
         echo "Usage: `basename $0` {start|stop}" >&2
         ;;
esac

Этот sh скрипт запускает tcpserver на порту 5555 и IP-адресе 10.100.1.15, принимает наш perl скрипт serv_main.pl в кач-ве параметра и ему (perl скрипту) tcpserver будет передавать полученные команды.

Запустим наше творение:

/usr/local/etc/rc.d/0_zstart.sh start

Проверим его наличие в списке процессов:

/bin/ps -ax | grep tcpserver

1251 con- I      0:00.24 /usr/local/bin/tcpserver -v -H -R -l 0 -c 10 -x /etc/tcp.server.cdb 10.100.1.15 ……..

Ну и убедимся, что порт 5555 прослушивается:

/usr/bin/sockstat | grep 5555
root     tcpserver  1251  3  tcp4   10.100.1.15:5555       *:*

Теперь можно испытать нашу конструкцию, например telnet`ом.

Для этого запустим команду telnet с хоста, IP которого разрешен для выполнения команд, в моем примере это хост 10.100.1.2.

telnet 10.100.1.15 5555

Trying 10.100.1.15…
Connected to 10.100.1.15.
Escape character is ‘^]’.

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

cmd=1;

Ну и увидим результат её отработки:

192.168.2.12;tun37
192.168.2.17;tun25
192.168.2.18;tun44
192.168.2.20;tun76
………………………….
192.168.2.228;tun126

После полной отработки команды произойдет отключение от сервера:

Connection closed by foreign host.

Вот и все.  Теперь команды можно отдавать, например:

  • из консоли telnet`ом
  • из другого perl скрипта используя IO::Socket
  • из web-интерфейса — php скрипта используя Sockets Support

Этот клиент-сервер ограничен только вашей фантазией.

З.Ы. При копировании статьи ссылка на источник ОБЯЗАТЕЛЬНА !

Авторы:  Панфилов Алексей (lehis (at) subnets.ru) и Николаев Дмитрий (virus (at) subnets.ru)

Похожие статьи:

    Не найдено

Прочитано: 20 602 раз(а)
Ничего не понялТак себе...Не плохоДовольно интересноОтлично ! То что нужно ! (голосов: 1, среднее: 5,00 из 5)
Загрузка...
Отправить на почту Отправить на почту

комментариев 7

  1. freefd сказал:

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

    P.S.
    use strict; use warnings;
    my $variable
    $ENV{‘SOME_ENV’}
    open FH, «>>», $file || die $!;

    надеюсь, намёк ясен 🙂

  2. admin сказал:

    ессно не секрет, что много можно решить многими способами, тут описан один из них и я не считаю «велосипедом» что-то созданное своими руками. Каждый выбирает свой путь — удобный ему.

    P.S. Мне намек не очень понятен.

  3. freefd сказал:

    Коду требуется срочный рефакторинг, начинать с use strict; use warnings;.
    Тоже самое можно аккуратно решить посредством telnet/ssh + aliases, бо классы и модули для работы скриптов с этими протоколами существуют уже давно. Вы написали вольную интерпретацию telnet, зачем — не понятно.

  4. lehisnoe сказал:

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

    P.S. Про код — известная песТня, но руки не доходят привести к нормальному виду 🙁

  5. freefd сказал:

    То есть фразу «посредством telnet/ssh + aliases, бо классы и модули для работы скриптов с этими протоколами существуют уже давно» не услышали. Ну да ладно. Мониторить температуру, опять же, проще и легче через snmp.

    Иначе встаёт вопрос: почему каждый до сих пор не написал себе свою операционную систему, и зачем вообще люди стремятся к унификации?..

  6. lehisnoe сказал:

    Почему же не слышали? Слышали и юзаем до сих пор.
    Слышали также и про agentx, но с ним пока еще даже не начинали разбираться.

    Кстати, мы тут не претендуем на истину в последней инстанции, просто делимся своим практическим опытом, отдавая себе отчет в том, что, наверняка, что-то можно сделать более оптимально и грамотнее…

  7. freefd сказал:

    🙂

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

Вам следует авторизоваться для размещения комментария.