##################################################################################### # Версия 2.4 by Vertigo@RusNet # pingip.tcl - скрипт, позволяющий пинговать IP или хосты. # # Установка: # 1. Скопировать скрипт в папку scripts # 2. Прописать в конфигурационный файл бота строку source scripts/pingip.tcl # 3. Указать верный путь к исполняемому файлу ping на шелле. (Узнать можно, набрав 'whereis ping' в последнем) # 4. Сделать боту .rehash # 5. Включить скрипт на канале командой .chanset #канал +pingip # # ——————————————————————————————————————————————————————————————— # # Использование: # !pingip # где IP/host - IP-адрес или хост, count - число отправляемых пакетов. # Если команду подавать с канала, можно вместо хоста/IP указать ник. # # ——————————————————————————————————————————————————————————————— # # История версий: # 1.0 - Первый публичный релиз. # 1.5 - Устранены некоторые ошибки. Добавлена опция указания пакетов. # 2.0 - Изменен парсер, формат выдачи сообщения. Устранены мелкие ошибки. # 2.2 - Косметические правки. Добавлен фильтр вводимого текста. # 2.3 - Скрипт переписан с нуля. Теперь используется вместо функции exec # функция open. Благодаря этому бот теперь не подвисает в случае # пинга хоста/IP большим числом пакетов или проблем со связью. # 2.4 - Был найден баг, позволяющий выполнять на шелле команды. # ##################################################################################### catch {::pingip::remove} err namespace eval ::pingip { ## # Начало настроек ## ## разрешить работу скрипта в привате у бота [1/0] variable private 1 ## использовать или нет цвета [1/0] variable colors 1 ## в чем выводить результат [0-ms/1-sec/2-auto] variable time 2 ## бинды variable binds {пингип пип pingip pip gbyubg gbg зштпшз зшз} ## префикс команд variable prefix {!} ## права доступа к командам variable accessflags {-|-} ## путь к исполняемому файлу пинга (напр. /sbin/ping) variable pingfile {/sbin/ping} ## сколько посылать пакетов по умолчанию variable defpackets 4 ## максимально допустимое число пакетов variable maxpackets 10 ## защита от флуда (секунды) set ::pingip::check(delay) 20 ## канальный флаг variable chflag [namespace tail [namespace current]] ## # Конец настроек ## setudef flag $chflag variable version "2.4" variable packets 4 proc remove {args} { foreach _ [binds ::pingip::*] { catch {unbind [lindex $_ 0] [lindex $_ 1] [lindex $_ 2] [lindex $_ 4]} } namespace delete ::pingip:: } foreach _ $binds { bind pub $accessflags $prefix$_ [namespace current]::pub if {$private} {bind msg $accessflags $prefix$_ [namespace current]::msg} } proc msg {nick uhost hand text} { main $nick $uhost $hand $nick $text } proc pub {nick uhost hand chan text} { variable chflag if {![channel get $chan $chflag]} {return} main $nick $uhost $hand $chan $text } proc main {nick uhost hand chan text} { variable colors; variable pingfile; variable packets; variable maxpackets; variable defpackets if {[info exists ::pingip::check(lasttime,$uhost)] && [expr $::pingip::check(lasttime,$uhost) + $::pingip::check(delay)] > [clock seconds] && ![matchattr $hand n]} { putquick "NOTICE $nick :Команда $::lastbind станет для Вас доступна через [expr $::pingip::check(delay) - [expr [clock seconds] - $::pingip::check(lasttime,$uhost)]] сек." return } set text [split [string map {\x17 "" \x26 ""} [stripcodes bcurag $text]]] set ::pingip::check(lasttime,$uhost) [clock seconds] if {$text eq ""} { if {$colors} {putquick "PRIVMSG $chan :\00303$nick\00314, используйте: \00304$::lastbind\00305 \ \[count\]\003" return } else { putquick "PRIVMSG $chan :$nick, используйте: $::lastbind \ \[count\]" return } } if {[regexp -- { (\d+)$} $text -> packets]} {regsub -- " $packets" $text "" text} else {set packets $defpackets} set packets [scan $packets %d] if {$packets > $maxpackets} { putquick "NOTICE $nick :Максимально возможное число отправляемых пакетов: \002$maxpackets\002!" return #set packets $maxpackets } set text [string map {\x20 ""} $text] if {[string index $chan 0] eq "#"} { if {[onchan $text $chan]} { set host [lindex [split [getchanhost $text $chan] "@"] 1] } else { set host $text } } else { set host $text } if {[regexp -all -- {[\[\]\{\}\$\^\&\*\(\)\@\#\~\`\"\+\?\\\;\'\\>\<\||а-яА-ЯёЁ]} $host]} { putquick "NOTICE $nick :\002\00304Ошибка\003\002. В вашем запросе обнаружены недопустимые символы." return } putquick "NOTICE $nick :Ваш запрос принят. Пожалуйста подождите..." variable pingfile if {![file executable $pingfile] && ![file readable $pingfile]} { putquick "NOTICE $nick :\002\00304Ошибка при выполнении\003\002. Проверьте путь к исполняемому файлу пинга или права доступа к нему." return } set extra [list $nick $chan $host $packets] if {[catch {set fid [open "|$pingfile -c $packets $host" w+] fconfigure $fid -translation {auto crlf} -buffering full -buffersize 8092 fileevent $fid readable [list [namespace current]::fdone $extra $fid] # catch {fconfigure $fid -blocking 0} } err]} { putquick "NOTICE $nick :\002\00304Ошибка при выполнении\003\002. Инфо: $err" return } } proc fdone {extra fid} { variable time; variable colors; variable data foreach {nick chan host packets} $extra {break} catch {read $fid} data catch {close $fid} err if {![info exists data] || $data eq ""} {set data $err} if {[string length $data] < 10} { putquick "NOTICE $nick :\002\00304Ошибка при получении данных\003\002." return } set dataend [join [lrange [split $data \n] end-3 end]] set resolv_ "" if {[regexp -nocase -- {.*\((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\)\:} $data -> resolv_]} { set resolv " \00312\(\00303$resolv_\00312\)"} else { set resolv "" } if {$resolv_ eq $host} {set resolv ""} if {[regexp -nocase -- {, (\d+).*received, (.*?)% packet loss.*dev =(.*?) ms} $dataend -> packets_received percent_loss average_time]} { set average_time [lindex [split $average_time "/"] 1] if {$time eq 2} { if {$average_time >= "1000"} {set average_time "[format "%.4f" [expr $average_time / 1000.0]]\00314 сек" } elseif {$average_time < "1000"} { set average_time "[format "%.2f" $average_time]\00314 мс" } } elseif {$time eq 1} { set average_time "[format "%.4f" [expr $average_time / 1000.0]]\00314 сек"} else { set average_time "[format "%.2f" $average_time]\00314 мс" } if {$colors} { putquick "PRIVMSG $chan :\00314Среднее время ответа от\00303 $host$resolv\00314:\00304 $average_time.\00314 Дополнительно:\00303 $packets\00314 [lindex {. {пакет отправлен} {пакета отправлено} {пакетов отправлено}} [numgrp $packets]],\00303 $packets_received\00314 [lindex {. {пакет принят} {пакета принято} {пакетов принято}} [numgrp $packets_received]].\00304 $percent_loss% \00314потерь.\003" } else { putquick "PRIVMSG $chan :Среднее время ответа от $host[stripcodes c $resolv]: [stripcodes c $average_time]. Дополнительно: $packets [lindex {. {пакет отправлен} {пакета отправлено} {пакетов отправлено}} [numgrp $packets]], $packets_received [lindex {. {пакет принят} {пакета принято} {пакетов принято}} [numgrp $packets_received]]. $percent_loss% потерь." } } elseif { [regexp -nocase -- {, (\d+).*received, (.*?)% packet loss.*} $data -> packets_received percent_loss]} { if {$colors} { putquick "PRIVMSG $chan :\00314От\00303 $host$resolv\00314 ответа не получено.\00314 Дополнительно:\00303 $packets\00314 [lindex {. {пакет отправлен} {пакета отправлено} {пакетов отправлено}} [numgrp $packets]],\00303 $packets_received\00314 [lindex {. {пакет принят} {пакета принято} {пакетов принято}} [numgrp $packets_received]].\00304 $percent_loss% \00314потерь.\003" } else { putquick "PRIVMSG $chan :От $host[stripcodes c $resolv] ответа не получено. Дополнительно: $packets [lindex {. {пакет отправлен} {пакета отправлено} {пакетов отправлено}} [numgrp $packets]], $packets_received [lindex {. {пакет принят} {пакета принято} {пакетов принято}} [numgrp $packets_received]]. $percent_loss% потерь." } } elseif {[regexp -nocase -- {ping: cannot resolve.*: (.+?)} $data -> msg]} { putquick "PRIVMSG $chan :$nick, при обработке запроса \(\002$host\002\) произошла ошибка: \"Cannot resolve $host: $msg\"" } else { putquick "NOTICE $nick :\002\00304Ошибка при парсинге данных\003\002." } } proc numgrp {seconds} { switch -glob -- "$seconds" { *11 {return 3} *12 {return 3} *13 {return 3} *14 {return 3} *1 {return 1} *2 {return 2} *3 {return 2} *4 {return 2} default {return 3} } } return "\002pingip.tcl\002 v$version by \002Vertigo\002@RusNet loaded." }