Семь веб-интерфейсов к электронной почте. Выберите лучший! Сергей Супрунов   Alias /mail/ /usr/local/www/ilohamail/ ; Initialize session on request startup session.auto_start = 1     ; Initialize session on request startup session.auto_start = 1     /usr/libexec/sendmail/sendmail -oi -t     $addedentry = $AddressBook->AddEntry($headerinfo->(ISDecode(fromaddress)); $addedentry = $AddressBook->AddEntry(ISDecode($headerinfo->fromaddress); function PageHeader($echo=1, $frame=0) { $header = ""; if ($_SESSION["locale"] == "ru_RU") { $header = "\n"; } else { $header = "\n"; } ; Initialize session on request startup session.auto_start = 0   -----------------------------------------------------------------------------------------------------------------   Полезные советы по FreeBSD Сергей Супрунов   # script /var/log/build.log # make buildworld # exit   # /usr/local/sbin/pkg_cutleaves -x        $ cat /usr/src/sys/`uname -p`/conf/`uname -i`     $ touch arch`date "+%Y-%m-%d"` $ echo a`echo b\`echo c\\\`echo d\\\`c\`b`a # portsnap fetch && portsnap update   -----------------------------------------------------------------------------------------------------------------   Полезные советы по Apache Сергей Супрунов   AllowOverride None AllowOverride All     Alias /proect/ /usr/local/www/htdocs/project/     Checkspelling on   -----------------------------------------------------------------------------------------------------------------   Упаковщики исполняемых файлов в Linux/BSD Крис Касперски   Листинг 1. Дизассемблерный листинг расшифровщика, внедряемого ELFCrypt в файл (как он выглядит в hiew) :entrypoint .080495DC: EB02 jmps .0080495E0 ; переходим на расшифровщик .080495DE: 06 push es ; \ мусор, оставленный... .080495DF: C6 ??? ; / ...транслятором ассемблера .080495E0: 60 pushad ; сохраняем все регистры в стеке .080495E1: 9C pushfd ; сохраняем флаги в стеке .080495E2: BEC0820408 mov esi, 0080482C0 ; начало расшифровываемого фрагмента .080495E7: 8BFE mov edi, esi ; EDI := EDI (расшифровка на месте) .080495E9: B978000000 mov ecx, 000000078 ; количество двойных слов для расшифровки .080495EE: BBBD03CC09 mov ebx, 009CC03BD ; ключ расшифровки .080495F3: AD lodsd ; читаем очередной двойное слово <-----+ .080495F4: 33C3 xor eax,ebx ; расшифровываем через xor | .080495F6: AB stosd ; записываем результат на место | .080495F7: E2FA loop .0080495F3 ; мотаем цикл -------------------------+ .080495F9: 9D popfd ; восстанавливаем флаги из стека .080495FA: 61 popad ; восстанавливаем все регистры .080495FB: BDC0820408 mov ebp, 0080482C0 ; адрес оригинальной точки входа (OEP) .08049600: FFE5 jmp ebp ; передаем управление расшифрован. коду     Листинг 2. Быстрая расшифровка elf-файла в отладчике gdb ; определяем точку входа в файл root@5[elf_crypt]#objdump -f elfcrypt-demo root@5[elf_crypt]# gdb elfcrypt-demo ; ставим точку останова на точку входа (gdb) b *0x80495DC ; пускаем программу (gdb) r ; сработала точка останова ; говорим отображать команды Ассемблера (gdb) display/i $pc ; начинаем трассировать программу (gdb) si ; продолжаем трассировать ; видим цикл ; ставим точку останова за его концом (gdb) b *0x80495F9 ; запускаем программу «вживую» (gdb) c ; точка останова достигнута ; программа расшифрована!   Листинг 3. Нет, это не хитрый антиотладочный код, это просто оригинальная точка входа в программу, еще не расшифрованная расшифровщиком .text:080482C0 _start proc near .text:080482C0 8C EE mov esi, gs .text:080482C2 92 xchg eax, edx .text:080482C3 80 5C 80 28 F9 sbb byte ptr [eax+eax*4+28h], 0F9h .text:080482C8 ED in eax, dx .text:080482C9 57 push edi .text:080482CA 9E sahf .text:080482CB 61 popa .text:080482CC AD lodsd .text:080482CD 87 C8 xchg ecx, eax .text:080482CF 01 D5 add ebp, edx .text:080482D1 B3 4F mov bl, 4Fh .text:080482D3 0D B5 52 9A 61 or eax, 619A52B5h .text:080482D8 2D 80 C8 01 55 sub eax, 5501C880h .text:080482DD CC int 3 ; Trap to Debugger .text:080482DE 33 F6 xor esi, esi .text:080482E0 42 inc edx .text:080482E1 F7 5C 99 E8 neg dword ptr [ecx+ebx*4-18h] .text:080482E1 _start endp     Листинг 4. Дизассемблерный листинг расшифровщика, внедряемого ELFCrypt в файл (как он выглядит в IDA Pro) extern:80495DC 7F 01 00 00 extrn puts@@GLIBC_2_0:near extern:80495E0 FA 00 00 00 extrn __libc_start_main@@GLIBC_2_0:near extern:80495E4 7F 01 00 00 extrn puts:near ; CODE XREF: .plt:_puts^j extern:80495E4 ; DATA XREF: .got:off_80495CC↑o extern:80495E8 FA 00 00 00 extrn __libc_start_main:near extern:80495E8 ; CODE XREF: ___libc_start_main↑j extern:80495E8 ; DATA XREF: .got:off_80495D0↑o extern:80495EC 00 extrn _Jv_RegisterClasses ; weak extern:80495F0 00 extrn __gmon_start__ ; weak extern:80495F0 ; DATA XREF: .got:080495D4↑o     Листинг 5. Протокол отладки, иллюстрирующий ход динамической загрузки ; устанавливаем точку останова на начало стартового кода (gdb) b _start ; запускаем программу на выполнение (gdb) r ; ок, мы в точке входа. Смотрим на extern (gdb) x 0x80495DC ; IDA Pro нас уверяет, что extern содержит адрес 0000017Fh, но в действительности область extern ; на момент запуска файла девственно чиста и забита нулями ; незначащие машинные инструкции пропущены ; но вот стартовый код вызывает библиотечную функцию ___libc_start_main, поскольку компилятор ; еще не знает ее фактического адреса, он вставляет переходник к секции .plt, ; содержащей переходники к секции .got, заполняемой динамическим загрузчиком ; IDA Pro корректно отобразила plt-переходник, вызывающий функцию, указатель на которую ; расположен в двойном слове по адресу 80495D0h ; а вот тут уже начались расхождения... ; IDA Pro уверяет, что здесь расположено смещение функции __libc_start_main, в то время как ; отладчик показывает, что здесь находится специальный код push 08h/jmp 8048290h. ; Посмотрим, что покажет IDA Pro по адресу 8048290h ; парад различий продолжается! IDA Pro вообще не показывает ничего! Отладчик же показывает код, ; засылающий в стек смещение первого (считая от нуля) элемента таблицы .got и передающего управление по адресу, ; записанному во втором элементе таблицы .got. Как следует из спецификации elf-формата, первые три элемента секции ; .got зарезервированы для служебных целей и вторая из них хранит адрес функции _dl_map_object_deps, которая, ; получив в качестве аргумента адрес начала .got, читает его содержимое (а содержатся там ссылки на библиотечные функции) ; и заполняет extern фактическими адресами ; ага! Вот эта функция, расположенная на моей машине по адресу 4000BBD0h, принадлежащему библиотеке libc.so.6 ; (на других машинах этот адрес может быть иным) она-то и выполняет всю работу по инициализации extern, ; в котором находится наш расшифровщик, уже расшифровавший программу, а затем вызывает __libc_start_main, ; так что загрузка динамической библиотеки происходит совершенно прозрачно     Листинг 6. Распаковка программы путем установки точки останова на _dl_map_object_deps ; загружаем программу в отладчик root@5[elf_crypt]# gdb elfcrypt-demo ; ставим brkpnt на _dl_map_object_deps (gdb) hbreak *0x4000BBD0 ; запускаем программу (gdb) r ; первое всплытие установленной точки останова ; сейчас будем проверять - «наше» ли оно или нет ; смотрим стек (gdb) x $esp+8 ; адрес указывает на libc.so.6 это «левое» всплытие, идем дальше (gdb) c ; второе всплытие установленной точки останова ; проверяем - «наше» ли оно или нет ; должен быть ret из call main (gdb) x $esp+8 ; судя по адресу, это возможно так и есть ; должен быть указатель на main (gdb) x $esp+0xC ; судя по адресу это так и есть ; проверяем наше предположение (gdb) disassemble 0x80482e1 ; дизассемблер показывает типичный стартовый код, значит, приложение уже распаковано!     Листинг 7. Скрипт для IDA Pro, расшифровывающий программу auto a,x; for(a=0x80482C0;a<0x8048338;) { x=Dword(a); x = x ^ 0x9CC03BD; PatchDword(a,x); a = a + 4; }     Листинг 11. Встроенный распаковщик UPX не смог распаковать файл с затертой сигнатурой root@5[upx-2.01-i386_linux]# ./upx -d elinks     Листинг 12. Снятие дампа с последующей реконструкцией elf-файла ; запускаем упакованный процесс на выполнение root@5[src]# ./demo ; определяем его pid root@5[src]# ps -a ; дампим процесс в файл root@5[src]# ./pd -o dumped 9771 ; утилита PD окончила процесс дампинга ; запускаем полученный процесс на выполнение root@5[src]# ./dumped     Листинг 13. Дизассемблерный листинг единственного антиотладочного приема в Burneye LOAD:053714A7 mov ebx, 5 ; SIGTRAP LOAD:053714AC mov ecx, offset anti_handler ; обработчик LOAD:053714B1 mov edx, 30h ; signal LOAD:053714B6 mov eax, edx LOAD:053714B8 int 80h ; signal(SIGTRAP, anti_handler); LOAD:053714BA add esi, offset word_5375A00 LOAD:053714C0 mov [ebp-2DCh], esi LOAD:053714C6 int 3 ; Trap to Debugger LOAD:053714C7 cmp anti_debug, 0 ; если ноль, мы под отладчиком LOAD:053714CE jnz short debugger_not_present ... LOAD:05371A0C anti_handler: ; обработчик сигнала SIGTRAP LOAD:05371A0C push ebp ; (получает управление только LOAD:05371A0D mov ebp, esp ; при запуске без отладчика) LOAD:05371A0F inc anti_debug ; увеличиваем секретную переменную LOAD:05371A15 leave LOAD:05371A16 retn ; выходим из обработчика     Листинг 14. Фрагмент burndump, отождествляющий упаковщик по «сигнатуре» codeptr = current->mm->start_code + 1; /* caller == burneye ??? */ if ((codeptr >> 16) == 0x0537) printk("<1> 7350 signature 0x0537 found!\n");     Листинг 15. Фрагмент файла, упакованного протектором Burneye .05371035: FF3508103705 push d,[05371008] .0537103B: 9C pushfd .0537103C: 60 pushad .0537103D: 8B0D00103705 mov ecx,[05371000] .05371043: E93A000000 jmp .005371082 ---v (1)   -----------------------------------------------------------------------------------------------------------------   Как обнаружить malware-программы? Универсальный метод Крис Касперски   Листинг 1. «Макетная» программа va_thread.c, создающая поток тем же самым методом, что и malware // код потока, который ничего не делает, а только мотает цикл thread(){while(1);} main() { void *p; // переменная многоцелевого использования // создаем «честный» поток CreateThread(0,0,(void*)&thread,0x999,0,&p); // создаем «нечестный» поток так, как это делает malware // выделяем блок памяти из кучи, копируем туда // код потока и вызываем CreateThread p = VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(p,thread,0x1000);CreateThread(0,0,p,0x666,0,&p); // ждем нажатия на любую клавишу getchar(); }     cl.exe va_thread.c     THREAD x va_thread proclist.exe > out Листинг 3. Фрагмент кода, ответственный за перечисление всех имеющихся потоков #include #include #include print_thr(THREADENTRY32 thr) { printf("cntUsage : %Xh\n",thr.cntUsage); printf("th32ThreadID : %Xh\n",thr.th32ThreadID); printf("th32OwnerProcessID : %Xh\n",thr.th32OwnerProcessID); printf("tpBasePri : %Xh\n",thr.tpBasePri); printf("tpDeltaPri : %Xh\n",thr.tpDeltaPri); printf("dwFlags : %Xh\n",thr.dwFlags); } main() { HANDLE h; THREADENTRY32 thr; int a; // создаем «слепок» потоков h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); // перебираем все потоки один за другим thr.dwSize = sizeof(THREADENTRY32); a = Thread32First(h, &thr); if (a && print_thr(thr)) while(Thread32Next(h, &thr)) print_thr(thr); } Листинг 4. Фрагмент кода, считывающего значение ESP потока с идентификатором thr.th32ThreadID HANDLE ht; CONTEXT context; context.ContextFlags = CONTEXT_CONTROL; // преобразуем идентификатор потока в дескриптор ht = OpenThread(THREAD_GET_CONTEXT, 0, thr.th32ThreadID); // считываем регистровый контекст GetThreadContext(ht,&context); // закрываем дескриптор CloseHandle(ht); Листинг 5. Фрагмент кода, определяющий положение дна стека и считывающий байт GET_FZ с его конца (в которых хранится стартовый адрес потока) #define GET_FZ 4 // на сколько двойных слов отступать DWORD buf[GET_FZ]; DWORD x; HANDLE hp; MEMORY_BASIC_INFORMATION mbi; // открываем процесс, владеющий данным потоком hp = OpenProcess(PROCESS_VM_READ|PROCESS_QUERY_INFORMATION,0,thr.th32OwnerProcessID); // определяем параметры блока памяти, на который указывает регистр ESP VirtualQueryEx(hp, (void*)context.Esp, &mbi, sizeof(mbi)); // вычисляем положение дна стека x = (DWORD) mbi.BaseAddress + mbi.RegionSize; // читаем GET_FZ слов со дна стека в буфер buf ReadProcessMemory(hp,(char*)x-GET_FZ*sizeof(DWORD),buf,GET_FZ*sizeof(DWORD),&a); // закрываем дескриптор процесса CloseHandle(hp); Листинг 6. Декодирование содержимого буфера buf и определение стартового адреса потока эвристическим методом DWORD st_adr; // определяем стартовый адрес потока st_adr = ((buf[GET_FZ-3])?buf[GET_FZ-3]:buf[GET_FZ-2]); // выводим стартовый адрес на экран или DEADBEEF, если стартовый адрес определить не удалось printf("start address : %08Xh\n",st_adr?st_adr:0xDEADBEEF); // определяем указатель на аргументы потока и выводим его на экран printf("point to args : %08Xh\n",((buf[GET_FZ-3])?buf[GET_FZ-2]:buf[GET_FZ-1])); Листинг 7. Фрагмент кода, определяющий тип блока памяти, к которому принадлежит стартовый адрес потока // определение типа региона памяти, к которому принадлежит стартовый адрес VirtualQueryEx(hp, (void*)st_adr, &mbi, sizeof(mbi)); // декодирование полученного результата и вывод его на экран printf("type : %s\n", (mbi.Type==MEM_IMAGE)?"MEM_IMAGE": (mbi.Type==MEM_MAPPED)?"MEM_MAPPED": (mbi.Type==MEM_PRIVATE)?"MEM_PRIVATE":"UNKNOWN");   -----------------------------------------------------------------------------------------------------------------   Ajax. Новое слово в разговоре клиента и сервера Алексей Мичурин   Test Ajax
Данные для запроса:
x =
Ход выполнения запроса: null
Статус ответа: null
Результат разбора ответа:
время: null
строка запроса: null
x-квадрат: null
    '.$_SERVER['REQUEST_URI']."\n"); $x=intval($_REQUEST['x']); $xx=$x*$x; echo "$x²=$xx\n"; ?> function prepare_http_object() { r = false; if (window.XMLHttpRequest) { // Mozilla, Safari, Opera ... r = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE r = new ActiveXObject("Microsoft.XMLHTTP"); } return r; } function do_http_rq() { r=prepare_http_object(); if (r) { setup_http_object(r); send_http_require(r); } else { alert('Эта страница не может быть корректно отображена вашим браузером'); } } function prepare_http_object() { r = false; if (window.XMLHttpRequest) { // Mozilla, Safari, Opera ... r = new XMLHttpRequest(); if (http_request.overrideMimeType) { http_request.overrideMimeType('text/xml'); } } else if (window.ActiveXObject) { // IE ... obj.onreadystatechange = function_name; obj.onreadystatechange = function() { // делаем что-то } function setup_http_object(r) { r.onreadystatechange = function() {process_response(r);}; } function unclose(r) { r.onreadystatechange = function() {}; } obj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); r.open('GET', 'calc.php?x='+escape(document.frm.x.value), true); /ajax/calc.php?x=4   -----------------------------------------------------------------------------------------------------------------   Устанавливаем DACS Сергей Яремчук   $ cd openssl-0.9.8a/ $./config --prefix=/opt/openssl $ make; make test # make install     $ cd apache-2.0.58 $./configure --enable-ssl --with-ssl=/opt/openssl --prefix=/opt/apache2     # /opt/apache2/bin/apachectl –l     # /opt/openssl/bin/openssl req -config /opt/openssl/openssl.cnf -new -x509 -keyout gw-ca.pem -out gw-ca.pem -days 365     # /opt/bin/openssl rsa -in gw-ca.pem -out gw-ca.key # /opt/ openssl/bin/openssl x509 -in gw-ca.pem -out gw-ca.crt     # cp gw-ca.crt /opt/apache2/conf/server.crt # cp gw-ca.key /opt/apache2/conf/server.key     Include /opt/conf/ssl.conf     SSLCertificateFile /opt/apache2/conf/ssl.crt/server.crt SSLCertificateKeyFile /opt/apache2/conf/ssl.key/server.key     $ cd expat-2.0.0 $ ./configure --prefix=/opt/expat; make # make install     # /sbin/ldconfig     $ cd dacs-1.4.13a $ src/configure --help $ src/configure --with-ssl=/opt/openssl --with-expat=/opt/expat --with-apache=/opt/apache2 --enable-unix-auth --enable-debug --enable-apache-auth --enable-native-auth --prefix=/opt/dacs --enable-ndbm=no --enable-bdb=no $ gmake depend $ gmake smalltag # gmake install # /opt/dacs/bin/version -v # cat httpd.conf | grep LoadModule # /opt/apache2/bin/apachectl start # /opt/dacs/bin/sslclient testserver.net:443 Options Indexes FollowSymLinks Order allow,deny Allow from all # Настраиваем виртуальный сервер и делаем доступными каталоги DACS NameVirtualHost 127.0.0.1:8080 Listen 127.0.0.1:8080 ServerName testdacs.net DocumentRoot "/opt/dacs/www/" ErrorLog "/opt/dacs/logs/error_log" TransferLog "/opt/dacs/logs/access_log" ScriptAlias /cgi-bin/ "/opt/apache2/cgi-bin/dacs/" Alias /css "/opt/dacs/www/css/" Alias /icons/ "/opt/apache2/icons/" Alias /dacs "/opt/dacs/www/" Alias /dtd-xsd "/opt/dacs/www/dtd-xsd/" Alias /examples "/opt/dacs/www/examples/" Alias /handlers "/opt/dacs/www/handlers/" Alias /man "/opt/dacs/www/man/" Alias /misc "/opt/dacs/www/misc/" Alias /mod "/opt/dacs/www/mod/" # install -g apache2 -m 0640 /opt/dacs/federations/site.conf-std /opt/dacs/federations/site.conf ${Conf::FEDERATIONS_ROOT}/${Conf::FEDERATION_DOMAIN}/${Conf::JURISDICTION_NAME} # install -g apache2 -m 0660 /dev/null /opt/dacs/federations/dacs.conf # install -d -g apache2 -m 0770 /opt/dacs/federations/testdacs.net/ # install -d -g apache2 -m 0770 /opt/dacs/federations/testdacs.net/FIRST # install -d -g apache2 -m 0770 /opt/dacs/federations/testdacs.net/FIRST/acls # install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/FIRST/acls/revocations # install -d -g apache2 -m 0770 /opt/dacs/federations/testdacs.net/FIRST/groups /opt/dacs/federations/testdacs.net/FIRST/groups/FIRST /opt/dacs/federations/testdacs.net/FIRST/groups/DACS # install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/FIRST/groups/DACS/jurisdictions.grp FEDERATION_DOMAIN "testdacs.net" FEDERATION_NAME "DACSTEST" LOG_LEVEL "info" JURISDICTION_NAME "FIRST" # ln -s /opt/dacs/federations/dacs.conf /opt/dacs/federations/ testdacs.net/FIRST/dacs.conf # /opt/dacs/bin/conf -u testdacs.net -q # install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/federation_keyfile # /opt/dacs/bin/mkkey -u testdacs.net -q /opt/dacs/federations/testdacs.net/federation_keyfile # cat /opt/dacs/federations/testdacs.net/federation_keyfile # install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/FIRST/jurisdiction_keyfile # /opt/dacs/bin/mkkey -uj FIRST /opt/dacs/federations/testdacs.net/FIRST/jurisdiction_keyfile dacs_admin() # install -g apache2 -m 0660 /dev/null /opt/dacs/federations/FIRST/acls/acl-prenv.0 user("any") # то есть всем AddDACSAuth dacs-acs /opt/dacs/bin/dacs_acs "-t -v" SetDACSAuthMethod dacs-acs external SetDACSAuthConf dacs-acs "/opt/dacs/federations/dacs.conf" AllowOverride AuthConfig Require valid-user Options ExecCGI AuthType DACS AuthDACS dacs-acs # /opt/apache2/bin/apachectl restart JURISDICTION_NAME "FIRST" URL "http://testdacs.net:8080/cgi-bin/dacs/local_unix_authenticate" STYLE "pass" CONTROL "sufficient" # install -g apache2 -m 0660 /dev/null /opt/dacs/federations/testdacs.net/FIRST/passwd # /opt/dacs/bin/dacspasswd -u testdacs.net -q -a sergej # cat /opt/dacs/federations/testdacs.net/FIRST/passwd # /opt/dacs/bin/cookie -u testdacs.net -decrypt < cookie   -----------------------------------------------------------------------------------------------------------------   Развиваем модуль DBI Алексей Мичурин   # для DBI это не работает @ISA=qw(DBI);     my $dbh=DBI->connect(...);     my $sth=$dbh->prepare('select ...');     1: package DBItoo; 2: use strict; 3: use DBI; 4: use vars qw(@ISA); 5: @ISA = qw(DBI); 6: package DBItoo::db; 7: use vars qw(@ISA); 8: @ISA = qw(DBI::db); 9: package DBItoo::st; 10: use vars qw(@ISA); 11: @ISA = qw(DBI::st); 12: 1;     #!/usr/bin/perl -w use strict; use DBItoo; my $dbh=DBItoo->connect('DBI:mysql:test', 'root', ''); my $sth=$dbh->prepare('SELECT id, txt FROM tbl'); $sth->execute(); while (my ($id, $txt)=$sth->fetchrow_array()) { print "$id $txt\n"; } $sth->finish(); $dbh->disconnect();     use DBI; my $dbh=DBI->connect('DBI:mysql:test', 'root', '', {RootClass => 'DBItoo'});     3: use DBI     @DBItoo_cmpct::ISA = qw(DBI); @DBItoo_cmpct::db::ISA = qw(DBI::db); @DBItoo_cmpct::st::ISA = qw(DBI::st); 1;     $dbh=DBI->connect(...);     1: use strict; 2: @DBIru::ISA = qw(DBI); 3: @DBIru::st::ISA = qw(DBI::st); 4: 5: package DBIru::db; 6: @DBIru::db::ISA = qw(DBI::db); 7: sub connected { 8: my ($dbh, $src, $login, $passwd, $attr)=@_; 9: $dbh->do('SET CHARACTER SET koi8r'); 10: } 11: 12: 1;     $dbh->do(q|SET time_zone='+04:00'|); [dbi_options] default-character-set=koi8r $db=DBI->connect('DBI:mysql:test;'. 'mysql_read_default_file=/home/etc/my.cfg;'. 'mysql_read_default_group=dbi_options', 'root', ''); mysql> SET GLOBAL time_zone = '+04:00'; 1: use strict; 2: @DBIping::ISA = qw(DBI); 3: @DBIping::st::ISA = qw(DBI::st); 4: 5: package DBIping::db; 6: @DBIping::db::ISA = qw(DBI::db); 7: sub ping { 8: my ($dbh)=@_; 9: my $r=0; 10: eval { 11: local $SIG{__DIE__} = sub { return (0); }; 12: local $SIG{__WARN__} = sub { return (0); }; 13: $r=$dbh->do('select 1'); 14: }; 15: return ($@)?0:$r; 16: } 17: 1; 1: use strict; 2: @DBIlog::ISA = qw(DBI); 3: @DBIlog::db::ISA = qw(DBI::db); 4: 5: package DBIlog::st; 6: @DBIlog::st::ISA = qw(DBI::st); 7: sub execute { 8: my $st=shift; 9: my @args=@_; 10: my $s=$st->{'Statement'}; 11: $s=~s/\s+/ /g; 12: open FH, '>>statments' or die; 13: print FH "$s\n"; 14: close FH; 15: return $st->SUPER::execute(@args); 16: } 17: 1; 1: use strict; 2: @DBItime::ISA = qw(DBI); 3: @DBItime::db::ISA = qw(DBI::db); 4: 5: package DBItime::st; 6: @DBItime::st::ISA = qw(DBI::st); 7: sub execute { 8: my $st=shift; 9: my $s=$st->SUPER::execute(@_); 10: $st->{execure_at => time()} if ($s); 11: return $s; 12: } 13: 1; 1: use strict; 2: @DBImd5::ISA = qw(DBI); 3: @DBImd5::st::ISA = qw(DBI::st); 4: 5: package DBImd5::db; 6: @DBImd5::db::ISA = qw(DBI::db); 7: sub md5 { 8: my ($db, $table)=@_; 9: my $sql='CHECKSUM TABLE '. 10: $db->quote_identifier($table); 11: my $st=$db->prepare($sql); 12: $st->execute(); 13: my (undef, $md5)=$st->fetchrow_array(); 14: $st->finish(); 15: return $md5; 16: } 17: 1; $dbh->md5(имя_таблицы); 1: use strict; 2: @DBIautodef::ISA = qw(DBI); 3: @DBIautodef::db::ISA = qw(DBI::db); 4: 5: package DBIautodef::st; 6: @DBIautodef::st::ISA = qw(DBI::st); 7: sub fetchrow_array { 8: my $st=shift; 9: return map {defined($_)?$_:'N/A'} ? $st->SUPER::fetchrow_array(); 10: } 11: 1;