Структура документа:
Описание
Вступление
Теория
Функции для пользовательских
скриптов:
Команды для работы в
partyline
- .uafs
Публичные команды
- !uafs
Константы
Прочие
настройки
Примеры
Wrapper
DESCRIPTION
- Описание
UAFS.tcl - Universal Anti-Flood
Script
Версия: beta 10
Скрипт UAFS.tcl for eggdrop
представляет собой
средство для контроля количества событий в
определенный промежуток времени.
Применительно к eggdrop'y, события, как правило,
представляют собой команды пользователя,
посланные боту, хотя в общем случае это
могут быть и joins/parts/nick changes/all messages.
Вступление:
Рассмотрим пример:есть скрипт
который
выдает новости с neowin.net по запросу
пользователя.Доступ к скрипту имеют все
пользователи данного канала.Легко
представить себе ситуацию когда кучка
хакеров-полуросликов решает завалить бота
запросами которые он и будет обслуживать не
жалея своих сил (встроенный антифлуд не
сработает - маски то разные!). В этом случае
имеются как минимум 2 фактора из-за которых
хотелось бы ввести ограничение на
пользование скриптом по временному
признаку,то есть по частоте:
- При обращении к ресурсу,бот
принимает/посылает определенное
количество информации с сервера/на сервер,что выражается в количестве
потребленного траффика и нагрузке на канал [передачи данных],в
некоторых случаях это может быть критично, если, к примеру, бот сидит
на медленном канале [передачи данных].
- Если бот выдает новости на
канал, то во-первых, он создает флуд
на канале, во-вторых забивает свою очередь сообщений, которая, как
известно, по умолчанию не резиновая ибо бот защищает себя от excess
flood'a (это применимо и к приватным сообщениям/нотисам). В следствии
этого остальные функции бота могут быть недоступны, грубо говоря
получается маленький DoS. Несмотря на то что данный вопрос намного шире
и частично решается подгонкой конфигурации ircd тем или иным образом
под конкретного бота, проблему он показывает ясно.
Для предотвращения этих а также
других
нежелательных ситуаций и необходимо
вводить ограничения,но к сожалению, по
умолчанию данную функциональность eggdrop не
поддерживает, поэтому на свет появился
UAFS.tcl, призванный упростить жизнь другим
разработчикам и избавить от изобретания
колеса.
Ну
и как вся эта хуйня [censored]
работает? Как бля [censored] её юзать нах [censored]?
(вместо введения :)
Поразмышляв некоторое время над
схожим
вопросом,только вместо "работает" было -
"будет работать", я пришел к выводу что
необходимо реализовать внешний интерфейс,
или, если угодно внешнюю функцию, которая и
будет проверять есть флуд,али нет. Но как внешняя
функция узнает, по какому критерию нужно
проверять? Сколько событий и за какой
промежуток времени можно допустить?
Правильно,нужно ей об этом сообщить, то есть
вызвать ее с параметром задающим
легетимное кол-во событий в определенный
отрезок времени. Хорошо, с этим
определились,но вот незадача - пользователи
идентифицируются минимум тремя
параметрами в виде nick!ident@host
а не только nick'om как нам бы хотелось, значит
надо еще и по маске сравнивать? а если
сравнивать по маске,значит уже имеющиеся
данные о масках надо где-то хранить? да и
получать их нужно, лишние строчки кода
писать в нашей локальной функции вызванной
триггером. То есть мы сами получаем,запоминаем
храним, а внешняя функция только проверяет
на временной критерий? Хм...ну ладно,пускай
так будет, но что делать с другой проблемой -
если использовать ограничение более чем в
одном месте (более чем одной локальной процедуре ) да еще и
с разными критериями - как внешняя функция
сможет различить кто желает от нее проверки?
Легче тогда уж хранить все данные в своей
процедуре,в ней же и проверять, а на внешную
хуй [censored] забить, нахуй [censored] она сдалась.
Но получаем изобретение колеса - каждый
будет все реализовывать по-своему и еще раз
по-своему и еще раз по-своему...кто-то скажет
- ну тык,йопт, пусь реализовывает если его
чиста прет и вставляет,на что вполне
резонно можно заметить - а нахуйа [censored]
ему сдался eggdrop & tcl - писал бы своего бота и
свой язык, раз его так чиста прет, в общем не
наш это метод Федя,не наш. Как написанно в
умной книжке Dan'a Appelman'a по VB.Net - повторное
использование кода - мантра программиста,
что и так ясно, если вы канешна настоящий
программист по убеждению - то есть
обладаете достаточным запасом логики и
лени. В общем, такого рода рассуждения
завели меня в небольшой тупик - вроде и надо
людям помоч,а вроде как хуйня [censored] выходит.
К моему удивлению, выход нашелся довольно
быстро - повспоминав Win32 API, я пришел к выводу
что решением может послужить использование
handlers ( по-русски "манипуляторов", всё из
той же умной книжки ) для однозначной
идентификации настроек флуд контроля...допустим,
регистрируются настройки флуда, флагов
игнорирования, строгости проверки, способ
сравнения масок в другой внешней функции,
она отдает нам какой-либо идентификатор
который в дальнейшем и используется, и
пусть сама она при проверке все это дело
извлекает, вычисляет,проверяет, на то она и
отдельная функция. Такая идея мне
понравилась (не знаю как вам), поэтому все
так и реализованно. Предвижу вопрос - ну и
нахуй [censored] нужно было всё это
расписывать да еще и на столько строчек - и,
предвидя, отвечаю - дабы объяснить
кажущуюся излишнюю трудность
использования скрипта, которой очень часто
приходится платить за расширение
функциональности и гибкости конечного
решения.
Теперь,когда ты, уважаемый
читатель,
подкован в теоретическом смысле, перейдем к
практической реализации сией гениальной
задумки. Итого, скрипт реализует несколько
функций (в квадратных скобках
необязательные параметры):
Функции
для
пользовательских скриптов:
- Первая
и самая главная:
Функция registerhandle
производит регистрацию уникального
идентификатора ( ufh ) с настройками флуд контроля.
registerhandle
floodsettings
[hostmask type] [ignore flags] [callback_function] [strict mode]
[comment]
Parameters:
Обязательным
параметром
является только floodsettings
в
формате times:seconds
то есть, сколько раз (times) в течении промежутка времени seconds (в
секундах) может
происходить определенное событие.
Если тип
хостмаски не указан,
ей будет присвоено значение по умолчанию ( masks(host) ).
ignore
flags - флаги
при наличии которых функция isflood
будет игнорировать пользователя и
возвращать 0.Флаги имеют стандартный формат eggdrop'a. Если флаги
пользователя совпадают с ignore
flags функция не заполняет
массив временных меток и не создает запись о пользовательской маске
Callback function, тип маски
хоста, флаги игнорирования как и strict
mode являются необязательными.
Функция обратного вызова представляет собой имя функции, которая будет
вызвана в случае возникновения флуда.
Если
функция обратного вызова не указана, она не
будет вызвана при возникновении флуда. В зависимости от настройки
параметра checkforcallback
функция
может возвращать ошибку если callback
function не существует.
параметр strict
mode
определяет, как функция isflood будет
обрабатывать проверки на флуд,после того как флуд обнаружен.
По
умолчанию выставляется в 1,то есть после того как функция
определила
флуд, требуется
чтобы истек интервал времени заданный в floodsettings.
Например:
floodsettings
= 5:30, пользователь превышает этот лимит, был
kick'нут с канала и зашел обратно и инициировал проверку на флуд
(например использовал команду бота), функция isflood
проверит истекли ли 30 секунд
после того
как данный пользователь был помечен как флудер. Если этот промежуток
времени еще не истек, функция isflood
возвратит 1,то есть флуд обнаружен. На внутреннем уровне это
реализованно
через заполнение массива временных меток ( timestamps ), т.е. по
умолчанию после обнаружения флуда данный массив полностью забивается
временем когда произошел флуд.
Если strictmode
установлен
в 0, массив содержит штампы последовательных
срабатываний и интервал времени считается как разность между
временем последнего события и первого.
comment -
поле комментария - при просмотре статистики из partyline можно видеть
каккие манипуляторы за что отвечают
Если это значение пустое, используется название пространства имен из
которого функция была вызвана .
Возвращаемые значения:
Значения больше 0 - идентификатор ufh, функция зарегистрировала
манипулятор успешно.
Отрицательные значения возвращаются в случае каких-либо ошибок.
Расшифровка кодов ошибок:
-1 - общая ошибка,в текущей версии не используется
-2 - ошибка в функции обратного вызова - не существует (
возвращается если checkforcallback
выставлено в 1 )
-3 - ошибка в формате floodsettings
-4 - ошибка в формате hostmask
type
- такой тип не определен
-5 - ошибка в формате strictmode
примеры
внизу
- unregisterhandle
Функция unregisterhandle
уничтожает заданный манипулятор ( ufh ), удаляя
все временные
метки и маски пользоватей связанные с
этим ufh .
Внимание!
После
удаления идентификатор становится недействительным и его дальнейшее
использование невозможно!
Для
получения нового манипулятора используйте registerhandle
unregisterhandle ufh
Parameters: ufh
- идентификатор настроек полученный из
registerhandle
Возвращаемые
значения:
1 - идентификатор успешно удален.
-11 - ошибка, такой идентификатор не существует.
- isflood
Функция isflood производит
проверку на флуд
isflood
ufh nick uhost [chan]
[ignore flags]
Parameters:
ufh
-
идентификатор
настроек полученный из registerhandle
nick - псевдоним пользователя
uhost - хост пользователя в
формате ident@hostname
chan
- имя канала. Опциональный
параметр, кроме того chan не
обязательно должен быть именем реального канала, т.к. функция никаких
действий по отношению к пользователю и каналу не предпринимает (если не
задан параметр ignore flags).
Данный параметр является своего
рода идентификатором. По умолчанию равен all,
то есть
если проверяются команды/private query/notices и параметр chan
опущен,
события будут регистрироваться на виртуальный канал all и
при
вызове callback function передается
так же all !
ignore flags - флаги при
наличии которых функция будет
игнорировать проверку и возвращать 0.Флаги имеют стандартный формат
eggdrop'a. Если флаги пользователя совпадают с ignore
flags функция
не заполняет массив временных меток и не создает запись о
пользовательской маске.
Обратите внимание,
что флаги переданные при вызове isflood
имеют больший приоритет чем
флаги указанные в registerhandle
!
Возвращаемые значения:
1 если флуд обнаружен
0 если флуд не обнаружен
В случае ошибки возвращаются отрицательные значения
Расшифровка кодов ошибок:
-21 - такой ufh не
существует
-22 - ошибка при создании маски - неверный формат uhost
либо nick
примеры
внизу
- peacetime
Функция peacetime определяет
интервал
времени ( в секундах ) по истечении которого isflood
вызванная с теми же параметрами ( ufh
nick uhost chan ) вернет 0,
т.е. с помощью этой функции можно
определить через какой промежуток времени событие должно произойти
чтобы не быть расцененным как флуд, полезно для уведомления
пользователей о том сколько нужно подождать чтобы снова воспользоваться
ботом.
peacetime ufh
nick uhost [chan]
Parameters: ufh
-
идентификатор
настроек полученный из registerhandle
nick - псевдоним пользователя
uhost - хост пользователя в
формате ident@hostname
chan - имя канала. Опциональный
параметр, кроме того chan не
обязательно должен быть именем реального канала, т.к. функция никаких
действий по отношению к пользователю и каналу не предпринимает (если не
задан параметр ignore flags).
Данный параметр является своего
рода идентификатором. По умолчанию равен all,
то есть
если проверяются команды/private query/notices и параметр chan
опущен,
события будут отнесенны к виртуальному каналу all.
Возвращаемые значения:
Время в секундах
В случае ошибки возвращаются отрицательные значения
Расшифровка кодов ошибок:
-31 - такой ufh не
существует
-32 - ошибка
при создании
маски - неверный формат uhost
либо nick
примеры внизу
- formatmessage
Функция
возвращает описание ошибки по ее числовому коду
formatmessage code
Parameters:
code
- код ошибки возвращенный одной
из предыдущих
функций, если такого кода не определенно, возвращается
"there is no message for
such error code"
- gethandleinfo
Функция возвращает набор данных о манипуляторе ufh которые были
использованны при регистрации
манипулятора
gethandleinfo ufh [type]
Parameters:
ufh -
идентификатор манипулятора
type - тип
получаемых
данных, может быть одним из:
- fset
- значение
параметра floodsettings
- callback
- имя
функции обратного вызова
- hostmask
- тип хостмаски
- ignoreflags
-
значение флагов игнорирования
пользователя
- strictmode
-
значение режима strictmode
- all
- в случае, если
тип данных не указан, не распознан или равен "all", то, используется
тип "all", который возвращает все вышеперечисленные параметры в виде
списка, то есть тип hostmask
можно
получить ипользуя как
lindex [::uafs::gethandleinfo $ufh] 2
так и
::uafs::gethandleinfo $ufh "hostmask"
В случае ошибки возвращаются отрицательные значения
Примечание:
Проверку
возвращаемых значений
рекомендуется делать следующим образом
(если,
конечно, вы вообще делаете
обработку ошибок) :
set hinfo
[::uafs::gethandleinfo $ufh]
if
{!([string
is
integer $hinfo] && $hinfo < 0)} {
#info was recieved successfully
#some actions here
}
else {
putlog "error:
can't get info for handle \"$ufh\""
putlog "error code is \"$hinfo\", message is:[::uafs::formatmessage
$hinfo]"
}
Расшифровка кодов ошибок:
-51 -
такой ufh не
существует
- createmask
Функция создаёт маску из nick и uhost
используя masktype
для определения вида маски.
createmask
nick
uhost masktype
Parameters:
nick
- псевдоним пользователя
uhost - хост
пользователя в формате ident@hostname
masktype
- тип хостмаски
В
случае ошибки возвращаются
отрицательные значения
Расшифровка кодов ошибок:
-41 - такого типа
маски (masktype)
не существует
-42 - неверный формат uhost
-43 - неверный формат nick
Примечание:
Проверку
возвращаемых значений
рекомендуется делать следующим образом
(если,
конечно, вы вообще делаете
обработку ошибок) :
set
ufhmask
[::uafs::createmask $nick $uhost $::uafs::masks(host)]
if
{![string
is
integer
$ufhmask]} {
#mask was
created ok
#some actions here
}
else {
putlog "error:
can't create hostmask"
putlog "error code is \"$ufhmask\", message is:[::uafs::formatmessage
$ufhmask]"
}
- checksoftcounter
Функция возвращает
значение счетчика "мягких" (soft) флудов
Под "мягким" флудом
подразумевается
серия из последовательных
срабатываний функции isflood,
которая при
отсутствии флуда будет обнулена, то есть этакие штрафные очки, которые
при непрерывном флуде увеличиваются, но если следующие событие
флудом не является, будут обнулены. Проще всего это пояснить
на
примере:
Допустим, есть скрипт который банит тех кто много слапает
(slaps), к примеру больше 3х раз в минуту, и, допустим, мы не хотим
банить после первого же слапа, а хотим сначала вывести предупреждение,
потом кик, а затем уже бан. То есть по сути, пользователь должен
нафлудить 3 раза чтобы быть забаненым, нужно считать
количество
флудов относительно данного пользователя, и при этом если слап не был
флудом,(пользоваталь следующий раз слапал через 5 минут), сбрасывать
счетчик. Это и есть "мягкий" флуд, который сбрасывается после серии
событий в 0. Если же не сбрасывается, то это уже "hard" flood то
есть общее
количество раз когда событие было расцененно как флуд.
Внимание!
На результат работы этой функции, так же как и isflood,
может значительно влиять параметр strict mode, учитывайте это
при регистрации
манипулятора!
checksoftcounter ufh
nick
uhost [ chan ]
Parameters:
ufh
-
идентификатор
настроек полученный из registerhandle
nick - псевдоним пользователя
uhost - хост пользователя в
формате ident@hostname
chan - имя канала,
правила те же самые что и для isflood
Возвращаемые
значения:
Количество непрерывных последовательностей флуда на текущий момент. Как
правило следует употреблять после проверки на флуд функцией isflood,
хотя может быть вызвана в любой момент.
Небольшой пример из скрипта wtf.uafs.tcl:
set
counter [::uafs::checksoftcounter $ufh $nick $uhost $chan]
if {$counter<0} {
#some error occured
putlog "error while getting counter value, error
code
\"$counter\", description:[::uafs::formatmessage $counter]"
} elseif {$counter > 0} {
switch -exact -- $counter {
"1" {
#1st time - warning
putserv "NOTICE
$nick : You are flooder $nick, calm down and wait for [duration
[::uafs::peacetime $ufh $nick $uhost $chan]]"
}
"2" {
#2nd time - kicking
#является ли
бот опом или халфопом?
if {[botisop
$chan] || [botishalfop $chan]} {
#раз да,то кикаем.
putserv "kick $chan $nick :Stop flooding
me with
\"$lastbind\""
}
}
default {
#3rd & other
times - banning
set mask
[::uafs::createmask $nick $uhost [::uafs::gethandleinfo $ufh
"hostmask"]]
newchanban $chan
$mask ${botnet-nick} "flooded me with \"$lastbind\"" $bantime
}
}
}
В случае ошибки возвращаются отрицательные значения
Расшифровка кодов ошибок:
-61 - такой манипулятор
не зарегистрирован.
Остальные коды ошибок возвращаются другими функциями, например createmask или isflood
поэтому formatmessage
может возвращать
описание ошибок из других функций.
- checkhardcounter
Функция возвращает
значение счетчика "твердых" (hard) флудов - описание
soft & hard floood
checkhardcounter ufh
nick
uhost [ chan ]
Parameters:
ufh
-
идентификатор
настроек полученный из registerhandle
nick - псевдоним пользователя
uhost - хост пользователя в
формате ident@hostname
chan - имя канала,
правила те же самые что и для isflood
Возвращаемые
значения:
Общее количество срабатываний функции isflood на текущий момент. С течением времени
только
увеличивается.
Как
правило следует употреблять после проверки на флуд функцией isflood,
хотя может быть вызванна в любой момент.
В случае ошибки возвращаются отрицательные значения
Расшифровка кодов ошибок:
-71 - такой манипулятор
не зарегистрирован.
Остальные коды ошибок возвращаются другими функциями, например createmask или isflood, поэтому formatmessage
может возвращать описание ошибок из других функций.
- reset
Функция сбрасывает значения временных меток событий
reset ufh
nick
uhost [ chan ]
Parameters:
ufh
-
идентификатор
настроек полученный из registerhandle
nick - псевдоним пользователя
примечание:
если nick содержит
пустое значение (""), манипулятор обнуляется полностью
uhost - хост пользователя в
формате ident@hostname
chan - имя канала,
правила те же самые что и для isflood
В случае ошибки возвращаются
отрицательные значения
Расшифровка кодов ошибок:
-81 - такой манипулятор
не зарегистрирован.
Остальные коды ошибок возвращаются другими функциями, например createmask или isflood, поэтому formatmessage
может возвращать описание ошибок из других функций.
Команды
для работы в partyline
- uafs
- help
Выводит справку по использованию команд в partyline, а так же
показывает текущие значения debugmode/debuglevel
- stats
channels
Выводит статистику по манипуляторам - показывает какие каналы
использованны.
- stats
handles
Выводит идентификаторы которые сейчас используются и их общее
количество.
- stats
handle <handle>
Выводит свойства и статистику по манипулятору <handle>
- stats
size
Выводит размер (в
байтах) который занимают структуры используемые uafs.
- debug on/off
Включает или выключает режим отладки.
- dlevel <level>
Устанавливает уровень отладки. Чем больше уровень,
тем больше сообщений попадет в лог (partyline)
На текущий момент поддерживаются уровни 1 и 2, но вы можете поставить
любое целое неотрицательное число.
- chandle
Команда chandle
предназначена для смены установок для handle из
partyline.
На текущий момент поддерживаются следующие настройки:
- fset
изменяет настройки флуда, т.е пары значений события:время,
смысл такой же как и в registerhandle
например .uafs
chandle <handle> fset 3:10
Публичные команды
- !uafs
Выводит статистику канала/общую - количество
проверок на флуд, флудов, проигнорированных проверок ( совпадение нс
флагами игнорирования ), количество используемых масок.
По умолчанию доступна n|n
Константы:
- Типы
хостмасок
masks(fullmask)
- полная
маска вида nick!ident@hostname.
masks(nickhost)
- маска вида
nick!*@hostname.
masks(identhost)
- маска
вида *!ident@hostname.
masks(host)
- маска вида
*!*@hostname.
masks(all)
- маска вида
*!*@*.
masks(ident)
- маска вида
*!ident@*.
- Коды ошибок
"-1"
"Register handle: general
errror"
"-2"
"Register handle: callback
function doesn't exist"
"-3"
"Register handle:
floodsettings have wrong format"
"-4"
"Register handle: such
hostmask type is not supported or not defined"
"-5"
"Register handle: strict
mode setting format error"
"-11"
"Unregister handle: such
ufh doesn't exist"
"-21"
"isflood: no such ufh
exists"
"-22"
"isflood: error while
creating usermask,check nick & uhost values"
"-31"
"peacetime: no such ufh
exists"
"-32"
"peacetime: error while
creating usermask,check nick & uhost values"
"-41"
"CreateMask: there is no
such hostmask type"
"-42"
"CreateMask: uhost variable
is not valid"
"-43"
"CreateMask: nick variable
is not valid"
"-51"
"gethandleinfo: no such ufh
exists"
"-61"
"checksoftcounter: no such
ufh exists"
"-71"
"checkhardcounter: no such
ufh exists"
"-81" "reset: no such ufh
exists"
Прочие
настройки:
- checkforcallback
В случае
если
checkforcallback выставлено в 1 и callback
function переданная в registerhandle
не
существует, registerhandle
возвратит ошибку.
По умолчанию стоит в 0, изменяется путем правки скрипта.
- debugmode
Определяет,
будет ли
скрипт работать в режиме отладки или нет, возможные варинаты значений: 1 и 0
- debuglevel
Определяет уровень выдачи отладочной информации - чем больше уровень,
тем больше информации будет выдавать скрипт.
Возможные значения на текущий момент 1 и 2
Примеры:
- Самый простой
#example
tcl for uafs
namespace eval beer {
#registering handle
set beer_ufh [::uafs::registerhandle "3:40"]
#is all okay?
if {$beer_ufh<0} { putlog "unable to register handler";die
"unable
to register handler beer_ufh"}
#putlog $beer_ufh
proc beerproc { nick uhost hand chan rest } {
variable beer_ufh;global lastbind
set bla [::uafs::isflood $beer_ufh $nick $uhost $chan]
if {$bla=="1"} {
set piu [::uafs::peacetime $beer_ufh $nick $uhost $chan]
putserv "NOTICE $nick :You are flooder! next time u may use $lastbind
after [duration $piu]"
} else {
putserv "PRIVMSG $chan :here is your beer $nick"
}
}
}
bind pub - "!beer" ::beer::beerproc
putlog "example tcl for uafs loaded"
- example4.tcl for uafs, updated for uafs beta 6
задача:
Привет! Можешь помочь с одним скриптом,
пожалуйста.
Когда кто-нибудь ввёл воторой раз в течение 5 минут "!кручу", бот
говорил,
чтобы подождал 5 минут, если он начинает флудить: предпреждение, 2
кика,
потом бан на 1
минуту!
uafs.example4.tcl
- wtf.uafs.tcl
version 1.0
works with wtf tool from bsdgames package & shows acronyms
meanings
показывает значения акронимов, например AFAIK IMHO BRB и так далее.
Существует возможность задавать каналы где будет работать при помощи
.chanset #chan +wtf.
wtf.uafs.tcl
- antislap.uafs.tcl version 1.1
Смысл данного скрипта в том, чтобы ограничить использование популярного
action (с применением форели) до, скажем, двух раз в минуту, с
предупредительным киком и баном злоупотребляемых лиц (c) Red Pepper
antislap.uafs.tcl