Иногда требуется выполнять команды на удаленных серверах, запускать какие либо скрипты, выводить отработку команд в web-интерфейс.
Например для обновлений правил firewall или вывода результата отработки какой либо команды в web-интерфейс, обновления содержимого файлов на сервере, мониторинг температуры и т.д. и т.п. список можно продолжать бесконечно.
Для реализации этой задачи нам понадобится две вещи:
- порт ucspi-tcp
- небольшой 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)
Похожие статьи:
- Не найдено
freefd сказал:
Ключевая фраза: не надо создавать новых сущностей, если задачу можно решить уже существующими.
Велосипед, как часть теории — интересно, применять на практике я бы не стал.
P.S.
use strict; use warnings;
my $variable
$ENV{‘SOME_ENV’}
open FH, «>>», $file || die $!;
…
надеюсь, намёк ясен 🙂
09.03.2009, 17:03admin сказал:
ессно не секрет, что много можно решить многими способами, тут описан один из них и я не считаю «велосипедом» что-то созданное своими руками. Каждый выбирает свой путь — удобный ему.
P.S. Мне намек не очень понятен.
09.03.2009, 17:21freefd сказал:
Коду требуется срочный рефакторинг, начинать с use strict; use warnings;.
09.03.2009, 17:27Тоже самое можно аккуратно решить посредством telnet/ssh + aliases, бо классы и модули для работы скриптов с этими протоколами существуют уже давно. Вы написали вольную интерпретацию telnet, зачем — не понятно.
lehisnoe сказал:
Именно вольная интерпретация телнет и нужна для, например, исполнения команд от рута на удаленных серверах, отданных через вэб-ифейс (зачем это нужно и аспекты безопасности сознательно не упоминаю).
P.S. Про код — известная песТня, но руки не доходят привести к нормальному виду 🙁
10.03.2009, 11:20freefd сказал:
То есть фразу «посредством telnet/ssh + aliases, бо классы и модули для работы скриптов с этими протоколами существуют уже давно» не услышали. Ну да ладно. Мониторить температуру, опять же, проще и легче через snmp.
Иначе встаёт вопрос: почему каждый до сих пор не написал себе свою операционную систему, и зачем вообще люди стремятся к унификации?..
10.03.2009, 11:27lehisnoe сказал:
Почему же не слышали? Слышали и юзаем до сих пор.
Слышали также и про agentx, но с ним пока еще даже не начинали разбираться.
Кстати, мы тут не претендуем на истину в последней инстанции, просто делимся своим практическим опытом, отдавая себе отчет в том, что, наверняка, что-то можно сделать более оптимально и грамотнее…
10.03.2009, 11:50freefd сказал:
🙂
10.03.2009, 12:10