Профессия – убивать спам. Все, что вы хотели узнать о тонкостях настройки Spamassassin Сергей Супрунов root# perl -MCPAN -e shell cpan> o conf prerequisites_policy ask cpan> install Mail::SpamAssassin cpan> quit # cd /usr/ports/mail/p5-Mail-SpamAssassin # make # make install spamd_enable="YES" ok_locales ru en # ./sa-stats.pl -s 20051013 # ./check_whitelist St = (Th / Ch - Sc) * f + Sc = (22.2 / 2 - 1.8) * 1 + 1.8 = 11.1 use_auto_whitelist 0 auto_whitelist_factor 0.5 # cd /usr/ports/mail/spamass-milter-0.3.0 # make install spamass_milter_enable="YES" MAIL_FILTER(`spamassassin’, `S=local:/var/run/spamass-milter.sock, F=, T=C:15m;S:4m;R:4m;E:10m’)dnl define(`confINPUT_MAIL_FILTERS’, `spamassassin’)dnl # cd /etc/mail # make # make install # /usr/local/etc/rc.d/sa-spamd.sh start # /usr/local/etc/rc.d/spamass-milter.sh start # make restart # Отправляем все сообщения (до 256000 байт) на обработку :0fw: spamassassin.lock * < 256000 | spamassassin # Все сообщения с X-Spam-Status = Yes помещаем в карантин :0: * ^X-Spam-Status: Yes carantine # sa-learn --spam ~serg/sa/spams # sa-learn --ham ~serg/sa/hams # sa-learn --dump :0 * ^To:.*spam@example.com { * < 256000 :0c: spamassassin.spamlock | sa-learn --spam :0: spamassassin.filelock spam } # createuser --no-adduser --no-createdb -U pgsql sauser # createdb --owner sauser -U pgsql sabase # createlang -U pgsql plpgsql sabase # psql -d sabase -U sauser -e < bayes_pg.sql CREATE TABLE bayes_expire ( id integer NOT NULL default '0', runtime integer NOT NULL default '0' ) WITHOUT OIDS; CREATE TABLE CREATE INDEX bayes_expire_idx1 ON bayes_expire (id); .. .. много команд .. .. CREATE FUNCTION bayes_store_module Mail::SpamAssassin::BayesStore::PgSQL bayes_sql_dsn DBI:Pg:dbname=sabase;host=localhost bayes_sql_username sauser bayes_sql_password '' # sa-learn --backup > sabase.back # sa-learn --restore sabase.back # psql -d sabase -U sauser -e < userpref_pg.sql # psql -d sabase -U sauser -e < awl_pg.sq user_scores_dsn DBI:Pg:dbname=sabase;host=localhost user_scores_sql_username sauser user_scores_sql_password '' user_awl_dsn DBI:Pg:dbname=sabase;host=localhost user_awl_sql_username sauser user_awl_sql_password '' # perl Makefile.PL PREFIX=$HOME && make && make install "|IFS=' ' && exec /usr/bin/procmail -f- || exit 75 #user" ----------------------------------------------------------------------------------------------------------------- Как посчитать трафик в Linux Александр Кузнецов # tar -xvzf ipcad-3.6.6.tar.gz # cd ipcad-3.6.6 # ./configure # make # /bin/su - # make install # /usr/local/etc/ipcad.conf # GLOBAL OPTIONS # Опция capture-ports включает/отключает дополнительные поля в статистике, такие как: TCP- и UDP-порты, а также # типы ICMP-пакетов. Однако включение данной опции увеличивает потребление памяти, снижает скорость подсчёта # трафика и в ряде случаев искажает вывод через RSH, поэтому она в данном примере отключена capture-ports disable; # Размер буферов, используемых для передачи статистики ядром, по умолчанию равен 64 Кб, чего вполне достаточно buffers = 64k # INTERFACE OPTIONS # Интерфейсы, на которых считается проходящий трафик. # Рассматривается случай шлюза с двумя сетевыми интерфейсами: внутренним (локальная сеть) и внешним (Интернет) interface eth0; # Считать трафик на Ethernet-интерфейсе... interface eth1; # ...и ещё на одном # Разделять статистику по каждому IP-адресу для подсети 192.168.0.0/24. «aggregate 192.168.0.0/24» указывает # ipcad-диапазон адресов сети. «strip 32» означает, что в статистику необходимо заносить все 32 бита # адреса, принадлежащего данному адресному диапазону aggregate 192.168.0.0/24 strip 32; # RSH SERVER OPTIONS # Настройки rsh-сервера, с помощью которого будет просматриваться статистика. rsh enable at 127.0.0.1; # Правила, указанные ниже, описывают политики доступа к статистике ipcad. Root может полностью управлять # (делать backup, просматривать и изменять таблицы подсчёта). Все остальные могут лишь просматривать статистику rsh root@127.0.0.1 admin; rsh root@127.0.0.1 backup; rsh root@127.0.0.1; rsh 127.0.0.1 view-only; # «Время жизни» и тайм-аут IP-пакета rsh ttl = 3; rsh timeout = 30; # Опцией dumpfile задаётся путь к файлу, в который по умолчанию будут складываться данные статистики dumpfile = /var/log/ipcad/ipcad-curr.dump; # OTHER OPTIONS pidfile = /var/run/ipcad.pid; # Опция memory_limit задаёт количество памяти для хранения содержимого одного потока данных. # Синтаксис следующий: memory_limit = <количество>[{k|m|e}] ; # где k - Кб; m - Мб; e – количество строк таблицы данных memory_limit = 10m; /usr/local/bin/ipcad -rds rsh host comand rsh localhost help rsh localhost show ip accounting traff.acc #!/bin/bash # name of script: traff.acc HOST=localhost rsh $HOST dump rsh $HOST show ip accounting | grep -E '192\.168\.0\.'$1'([^0-9]|$)' echo echo "Summary traffic of 192.168.0.$1 (kbytes):" rsh $HOST show ip accounting | grep -E '192\.168\.0\.'$1'([^0-9]|$)' | awk '{s+=$4} END {print(s/1024)}' ./traff.acc ip /etc/cron.d/ipcad * * * * * root rsh localhost dump >/dev/null 59 23 * * * root date "+\%Y\%m" > /var/log/ipcad/ipcad.date 0 0 1 * * root (rsh localhost dump /var/log/ipcad/ipcad-$(cat /var/log/ipcad/ipcad.date).dump && rsh localhost clear ip accounting) >/dev/null 2>&1 traff.acc.2 #!/bin/bash HOST=localhost USERS=/etc/hosts case $1 in M|m) echo "Summary LAN traffic of month $2 (Mbytes):" rsh $HOST dump awk '{s+=$4} END {print(s/1048576)}' < /var/log/ipcad/ipcad-$2.dump exit 0;; U|u) grep -E '192\.168\.0\.'$3'([^0-9]|$)' $USERS | awk '{print($2)}' USER=`grep -E '192\.168\.0\.'$3'([^0-9]|$)' $USERS | awk '{print($2)}'` rsh $HOST dump cat /var/log/ipcad/ipcad-$2.dump | grep -E '192\.168\.0\.'$3'([^0-9]|$)' echo echo "Summary traffic of $USER in $2 month (kbytes):" cat /var/log/ipcad/ipcad-$2.dump | grep -E '192\.168\.0\.'$3'([^0-9]|$)' | awk '{s+=$4} END {print(s/1024)}' exit 0;; *) echo "Usage: " echo "1) if only month stat:" echo " ./traff.acc.2 m " echo " - number of month" echo "2) if user’s stat for month" echo " ./traff.acc.2 u " echo " - stat for that month" echo " - last octet of user’s IP address" echo "note: for current month in flag just type 'curr'" exit 0;; esac ./traff.acc.2 m ./traff.acc.2 u ----------------------------------------------------------------------------------------------------------------- Создаем загружаемый Flash-диск с FreeBSD и DOS Часть II Рашид Ачилов # tunefs -p /dev/ad0s2a # tunefs -a enable /dev/ad0s1a # /dev/ad2s1: 8 partitions: # size offset fstype [fsize bsize bps/cpg] a: 409600 4194304 4.2BSD b: 4194304 0 swap c: * * unused 0 0 # «raw» part, # don’t edit d: 10485760 4603904 4.2BSD e: 20971520 15089664 4.2BSD f: * 36061184 4.2BSD # disklabel -e -n ad0s1 # disklabel -R -n ad0s1 ad0s1.disklabel # disklabel -R ad0s1 ad0s1.disklabel # fdisk /dev/ad0 > ad0.fdisk # disklabel ad0s1 > ad0s1.disklabel # /dev/ad2s1: 8 partitions: # size offset fstype [fsize bsize bps/cpg] a: 200M 0 4.2BSD b: 2G * swap c: * * unused 0 0 # «raw» part, # don’t edit d: 5G * 4.2BSD e: 10G * 4.2BSD f: * * 4.2BSD # mount /dev/ad0s1a /mnt/s1a # mount /dev/ad4s1a /mnt/s1e # cd /mnt/s1e && dump -0af - /mnt/s1a | restore -xf - # disklabel ad0s1 # disklabel -w ad0s1 # setfacl -m u::rwx /tmp ----------------------------------------------------------------------------------------------------------------- Как управлять индексированием своего сайта Сергей Яремчук User-agent: googlebot User-agent: fast Allow: /info/ User-agent: googlebot aspider Disallow: /images/ Disallow: /cgi-bin/ /1251/ Disallow: /changelog.html User-agent: * Disallow: Disallow: *.gif$ Disallow: /*? Disallow: *.gif$ ----------------------------------------------------------------------------------------------------------------- В чем сильные и слабые стороны HTTP digest-авторизации Алексей Мичурин LoadModule digest_module libexec/apache/mod_digest.so AddModule mod_digest.c htdigest [ -c ] passwdfile realm username htdigest -c passwd Realm-A a AuthType Digest AuthName Realm-A AuthDigestFile /home/www/test/passwd Require valid-user htdigest -c passwd Realm-A a имя_группы: пользователь ещё_пользователь ... Require group имя_группы ещё_имя_группы ... Require user имя_пользователя ещё и_ещё ... Order Deny,Allow Deny from all Allow from 192.168.1.104 Satisfy All BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On SetEnv AuthDigestEnableQueryStringHack On ----------------------------------------------------------------------------------------------------------------- Антиотладка: старые приемы на новый лад Крис Касперски Листинг 1. Простейший антиотладочный прием, распознающий трассировку под некоторыми отладчиками pushf ; сохраняем флаги в стеке, включая и TF pop eax ; выталкиваем сохраненные флаги в eax and eax, 100h ; выделяем флаг трассировки jnz under_debugger ; если TF взведен, нас трассируют Листинг 2. Универсальный антиотладочный прием, распознающий трассировку под большинством отладчиков ; устанавливаем новый обработчик структурных исключений xor eax,eax ; обнуляем регистр eax push offset SEH_handler ; кладем в стек указатель на новый обработчик push dword ptr fs:[eax] ; кладем в стек указатель на старый обработчик mov fs:[eax],esp ; регистрируем новый SEH-обработчик ; взводим флаг трассировки pushf ; заталкиваем в стек регистр флагов pop eax ; выталкиваем его содержимое в регистр eax or ah, 1 ; взводим флаг TF push eax ; кладем eax в стек popf ; выталкиваем его содержимое в регистр флагов ; теперь флаг трассировки взведен! ; после выполнения этой команды генерируется исключение, и если отладчик не установлен, ; его перехватывает SEH-обработчик, который корректирует EIP, и эта команда не выполняется ; под отладчиком происходит переход на ветку under_debugger jmp under_debugger // ... ; основной код программы // ; SEH-обработчик может быть расположен в любом месте (лучше расположить его подальше ; от защитного кода, чтобы он не так бросался в глаза) SEH_handler: mov esi, [esp+0ch] ; указатель на контекст регистров assume esi: PTR CONTEXT mov [esi].regEip, offset continue ; откуда продолжать выполнение ; в отсутствии отладчика xor eax, eax ret ; выход из SEH-обработчика continue: ; // отсюда будет продолжено управление, ; если отладчик не установлен Листинг 3. Пример простейшей самотрассирующейся программы под ms-dos ; // устанавливаем новый обработчик трассировочного прерывания int 01h mov ax,2501h ; функция 25h (установить прерывание), прерывание – 01h lea dx,newint01h ; указатель на обработчик прерывания int 21h ; сервисная функция MS-DOS ; // взводим флаг трассировки pushf ; сохраняем регистр флагов в стеке pop ax ; выталкиваем его в регистр ax or ah,1 ; взводим бит TF push ax ; сохраняем измененный регистр ax в стеке popf ; выталкиваем модифицированное значение в регистр флагов // теперь после выполнения каждой команды процессор будет генерировать int 01, // передавая управление его обработчику // подготавливаем параметры для расшифровки lea si, crypted_begin mov cx, (offset crypted_end - crypted_begin) / 2 repeat: ; // основной цикл расшифровки lodsw ; читаем очередное слово по si в ax, увеличивая si на 2 mov [si-2],bx ; записываем в ячейку [esi-2] содержимое bx loop repeat ; крутим цикл, пока cx не равен нулю ; кажется, что это дурной цикл, работящий как memset ; т.е. заполняющий область памяти содержимым bx ; которое даже не было инициализировано! ; однако все не так, и на каждом ходу генерируется ; трассировочное прерывание, передающее управление ; обработчику int 01h, который неявно модифицирует bx ; // сбрасываем флаг трассировки pushf ; сохраняем регистр флагов в стеке pop dx ; выталкиваем его в регистр dx (ax используется обработчиком int 01h) and dh,0FEh ; сбрасываем бит TF push dx ; сохраняем измененный регистр dx в стеке popf ; выталкиваем модифицированное значение в регистр флагов ; // еще одна ловушка для хакера jmp_to_dbg: jmps under_debugger // ... ; «полезная нагрузка» (основной код программы) // new_int_01h: xor ax, 9fadh ; зашифровываем содержимое регистра ax mov bx, ax ; помещаем его в регистр bx mov word ptr cs:[jmp_to_dbg],9090h ; «убиваем» условный переход, ведущий к подложной ветке ; (под отладчиком обработчик int 01h не получит ; управления и переход не будет убит) iret ; выходим из обработчика прерывания crypted_begin: // ... ; зашифрованный код/данные // crypted_end: Листинг 4. Просмотр списка установленных (псевдо)устройств утилитой objdir $objdir \Devic Листинг 5. Открытие псевдоустройства PhysicalMemory // разные переменные NTSTATUS ntS; HANDLE Section; OBJECT_ATTRIBUTES ObAttributes; INIT_UNICODE(ObString,L"\\Device\\PhysicalMemory"); // инициализация атрибутов InitializeObjectAttributes(&ObAttributes, &ObString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); // открываем секцию PhysicalMemory ntS = NtOpenSection(&Section, SECTION_MAP_READ|SECTION_MAP_WRITE, &ObAttributes); Листинг 6. Проецирование физической памяти на виртуальное адресное пространство // переменные-аргументы HANDLE Section = xxx; // входной параметр дескриптор секции PVOID vAddress = xxx; // входной параметр виртуальный адрес, куда проецировать DWORD Size = xxx; // количество байт для проецирования от начала секции // прочие переменные, инициализированные программой PHYSICAL_ADDRESS pAddress; NTSTATUS ntS; DWORD MappedSize; PVOID MappedAddress=NULL; // Внимание! Функции __GetPhysicalAddress не сущестует в природе! Она дана условно. // Ниже по тексту будет объяснено почему pAddress = __GetPhysicalAddress((PVOID) vAddress); // проецируем секцию PhysicalMemory на виртуальное адресное пространство ntS = NtMapViewOfSection(Section, (HANDLE) -1, &MappedAddress, 0L, Size, &pAddress, &MappedSize, 1, 0, PAGE_READONLY); Листинг 7. Простейший (но ненадежный) алгоритм трансляции адресов PHYSICAL_MEMORY MyGetPhysicalAddress(void *BaseAddress) { if (BaseAddress < 0x80000000 || BaseAddress >= 0xA0000000) { return(BaseAddress & 0xFFFF000); } return(BaseAddress & 0x1FFFF000); } ----------------------------------------------------------------------------------------------------------------- Как программы на Си взаимодействуют с сервером БД PostgreSQL Владимир Мешков struct sockaddr { sa_family_t sa_family; char sa_data[14]; } Листинг 1. Серверный процесс #include #include int main() { int sock, newsock; struct sockaddr saddr; char c; static char rc = 1; /* Создаем сокет домена AF_UNIX */ sock = socket(AF_UNIX, SOCK_STREAM, 0); /* Заполняем адресную структуру saddr */ memset((void *)&saddr, 0, sizeof(saddr)); saddr.sa_family = AF_UNIX; /* тип домена */ /* путь к файлу */ memcpy(saddr.sa_data, "/tmp/.sock.new", 14); bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr)); listen(sock, 1); for(;;) { newsock = accept(sock, NULL, NULL); if(fork() == 0) { while(recv(newsock, &c, 1, 0) > 0) { send(newsock, &i, 1, 0); i++; } close(newsock); exit(0); } close(newsock); } return 0; } Листинг 2. Клиентский процесс int main() { int sock; struct sockaddr saddr; char c, rc; sock = socket(AF_UNIX, SOCK_STREAM, 0); memset((void *)&saddr, 0, sizeof(saddr)); saddr.sa_family = AF_UNIX; memcpy(saddr.sa_data, "/tmp/.sock.new", 14); connect(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr)); for(;;) { c = getchar(); send(sock, &c, 1, 0); if(recv(sock, &rc, 1, 0) > 0) printf("From server: %d\n", rc); else { close(sock); exit(0); } } return 0; } PGconn *PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd); PGresult *PQexec(PGconn *conn, const char *query); ExecStatusType PQresultStatus(const PGresult *res); char* PQgetvalue(const PGresult *res, int tup_num, int field_num); int PQntuples(const PGresult *res); int PQnfields(const PGresult *res); void PQclear(PQresult *res); void PQfinish(PGconn *conn) createuser -a -d my_user -E -P createdb -O my_user my_database # ./insert_data -d [имя базы данных] -t [имя таблицы] -p [имя каталога] unsigned char *dbname = NULL; /* имя базы данных */ unsigned char *table = NULL; /* имя таблицы */ unsigned char *pathname = NULL; /* каталог, из которого считываются данные */ if(argc != 7) usage(); void usage() { fprintf(stderr, "Usage: insert_data -d [имя базы данных] -t [имя таблицы] -p [исходный каталог]\n"); exit(0); } while((int c = getopt(argc, argv, "d:t:p:")) != EOF) { switch(c) { case 'd': /* имя базы данных */ dbname = (unsigned char *)optarg; break; case 't': /* имя таблицы */ table = (unsigned char *)optarg; break; case 'p': /* имя каталога */ pathname = (unsigned char *)optarg; break; /* ошибка в параметрах */ case '?': default: usage(); } } unsigned char user[80]; /* имя пользователя */ unsigned char pwd[80]; /* пароль доступа к базе данных */ memset(user, 0, sizeof(user)); printf("Login: "); scanf("%s", user); memset(pwd, 0, 80); printf("Password: "); #include int tcgetattr(int ttyfd, struct termios *told); int tcsetattr(int ttyfd, int actions, const struct termios *tnew); int ttyfd = open("/dev/tty", O_RDWR); tcgetattr(ttyfd, &t); /* сохраняем настройки терминала */ t.c_lflag &= ~ECHO; /* сбрасываем флаг ECHO */ tcsetattr(ttyfd, TCSANOW, &t); /* устанавливаем новое состояние терминала */ scanf("%s", pwd); t.c_lflag |= ECHO; /* устанавливаем флаг ECHO */ tcsetattr(ttyfd, TCSANOW, &t); close(ttyfd); PGconn *conn = PQsetdbLogin(NULL, NULL, NULL, NULL, dbname, user, pwd); PQsetdbLogin("192.168.1.1", "5432", NULL, NULL, dbname, user, pwd), if(PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed.\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); exit(1); } int list_dir(PGconn *conn, unsigned char *table, unsigned char *pathname) { struct dirent *d; struct stat s; DIR *dp; PGresult *res; /* результат обращения к базе данных */ unsigned char full_path[256]; /* абсолютное путевое имя файла */ unsigned char query[QUERY_LEN]; /* строка запроса к базе данных */ unsigned char escape_string[80]; /* данные, передаваемые базе */ /* Открываем каталог */ if((dp = opendir(pathname)) == NULL) { perror("opendir"); return -1; } /* Пропускаем родительский и текущий каталоги */ d = readdir(dp); // "." d = readdir(dp); // ".." /* Цикл чтения записей каталог */ while(d = readdir(dp)) { /* Формируем абсолютное путевое имя файла и получаем информацию о нем */ memset(full_path, 0, 256); sprintf(full_path, "%s/%s", pathname, d->d_name); stat(full_path, &s); /* Если это каталог – выполняем рекурсивный вызов функции */ if(S_ISDIR(s.st_mode)) list_dir(conn, table, full_path); /* Добавляем в базу информацию о файле, при этом преобразуем путевое имя файла при помощи */ /* функции PQescapeString */ memset(escape_string, 0, 80); PQescapeString(escape_string, full_path, 80); /* Формируем запрос и отправляем его базе данных */ memset(query, 0, QUERY_LEN); sprintf(query, "INSERT INTO %s values('%s','%u')", table, full_path, s.st_size); res = PQexec(conn, query); /* Проверяем статус запроса. Он должен быть равен PGRES_COMMAND_OK, т.к. данных от базы мы не получаем */ if(PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "INSERT query failed.\n"); break; } } closedir(dp); PQclear(res); return 0; } PQfinish(conn); #include int ftw(const char *path, int(* func)(), int depth); int func(const char *name, const struct stat *sptr, int type) { /* Тело функции */ } ftw(pathname, list_dir1, 1); int list_dir1(const char *name, const struct stat *s, int type) { PGresult *res; /* строка запроса к базе данных */ unsigned char query[QUERY_LEN]; unsigned char escape_string[80]; /* Возвращаемся, если вызов stat завершился неудачно */ if(type == FTW_NS) return 0; /* Если объект является регулярным файлом, добавляем информацию о нем в базу */ if((type == FTW_F) && S_ISREG(s->st_mode)) { memset(escape_string, 0, sizeof(escape_string)); PQescapeString(escape_string, name, sizeof(escape_string)); memset(query, 0, QUERY_LEN); sprintf(query, "INSERT INTO %s values('%s','%u')", table, name, s->st_size); res = PQexec(conn, query); /* Проверяем статус запроса */ if(PQresultStatus(res) !=PGRES_COMMAND_OK) { fprintf(stderr, "INSERT query failed.\n"); return -1; } PQclear(res); } return 0; } # gcc -o insert_data insert_data.c -lpq conn = PQsetdbLogin(NULL, NULL, NULL, NULL, dbname, user, pwd); if(PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed.\n"); fprintf(stderr, "%s", PQerrorMessage(conn)); exit(1); } memset(query, 0, QUERY_LEN); sprintf(query, "SELECT * FROM %s", table); res = PQexec(conn, query); if(PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "SELECT query failed.\n"); goto out; } for(i = 0; i < PQntuples(res); i++) { for(n = 0; n < PQnfields(res); n++) printf("%-20s", PQgetvalue(res, i, n)); printf("\n"); } ----------------------------------------------------------------------------------------------------------------- Управляем серверами в реальном времени с помощью WSH-сценариев Андрей Бирюков Листинг 1. Поиск сообщений в журнале событий Option Explicit Dim objWMI, objItem ' Objects // Объявляем переменные Dim strComputer Dim intRecordNum, intRec, colLoggedEvents Dim strAdmin, strAdmin2, i, intrecordNum2, iteration ' WMI Core Section // Сервер, на котором выполняется сценарий strComputer="127.0.0.1" Set objWMI = GetObject("winmgmts:" _ & "{impersonationLevel=impersonate}!\\" _ & strComputer & "\root\cimv2") iteration=2 // счетчик итераций // искомые строки – отключение питания strAdmin = "UPS On Battery" // искомые строки – восстановление питания strAdmin2 = "Utility Power Restored" Do While 1=1 // цикл бесконечный // запрос по журналу событий. Раздел Applications Set colLoggedEvents = objWMI.ExecQuery ("Select * from Win32_NTLogEvent Where Logfile = 'Application'" ) // счетчики записей intRecordNum=0 // счетчик найденных записей intRec=0 // счетчик всех записей intRecordNum2=0 For Each objItem in colLoggedEvents // ищем первое вхождение записи // на отключение If intRecordNum=0 Then If InStr(1,objItem.message,strAdmin,1) Then intRecordNum = intRec+1 End If // ищем первое вхождение записи // на восстановление If intRecordNum2=0 Then If InStr(1,objItem.message,strAdmin2,1) Then intRecordNum2 = intRec +1 End If intRec=intrec+1 // если все нашли, выходим из цикла If intRecordNum>0 AND intrecordNum2>0 Then Exit For Next / если не нашли записей об отключении, // то и записи о восстановлении не нужны If intrecordNum=0 Then intRecordNum2=0 If iteration=0 Then shutdown // а здесь будет находиться ссылка на процедуру // отключения питания на других серверах End If If intrecordNum0 Then iteration=iteration-1 End If loop WScript.Sleep 10000 // Задержка перед следующей итерацией Листинг 2. Процедура отключения питания Sub Shutdown On Error Resume Next // если ошибка, переходим к следующему Dim arrComputers, objLocator Dim login, password, domain // Перечисляем имена серверов, которые должны быть выключены arrComputers = Array("Computer1","Computer2","Computer3") login="operator" // учетная запись с правом на shutdown password="password" // пароль domain="TEST" // домен For Each strComputer In arrComputers Set objLocator = CreateObject("WbemScripting.SWbemLocator") Set objWMIService = objLocator.ConnectServer(strComputer, "root\cimv2", login, password, domain) Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem") For Each objOperatingSystem in colOperatingSystems // непосредственно shutdown ObjOperatingSystem.Shutdown(1) Next // после отключения уведомим администратора sendmail(strComputer) Next WScript.Quit // сценарий завершает свою работу End Sub Листинг 3. Отправка письма с помощью Outlook Dim OutlookObject, OutMail Set OutlookObject = CreateObject("Outlook.Application") Set OutMail = OutlookObject.CreateItem(0) OutMail.to = "test@test.ru" OutMail.Subject = "Тема сообщения" OutMail.Body = "Тело сообщения" OutMail.Send Листинг 4. Отправка письма // Получаем в качестве параметра имя сервера Sub sendmail(server) // Инициализируем переменные Dim iMsg Dim iConf Dim Flds Dim str Const cdoSendUsingPickup = 1 Set iMsg = CreateObject("CDO.Message") Set iConf = CreateObject("CDO.Configuration") // Подготавливаем поля для отправки по SMTP Set Flds = iConf.Fields With Flds .Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = cdoSendUsingPickup .Item("http://schemas.microsoft.com/cdo/configuration/smtpserverpickupdirectory") = "c:\inetpub\mailroot\pickup" .Update End With // Непосредственно текст сообщения str= "Уважаемый администратор. Сервер " & server & " был отключен "& Now &" в связи с потерей электропитания. " // заполоняем все поля сообщения With iMsg Set .Configuration = iConf .To = "admin@server.com" // Поле «Кому» .From = "ups@example.com" // Поле «От кого» // Тема письма .Subject = "Отключение питания на сервере " & server .HTMLBody = str .Send End With // Очищаем переменные Set iMsg = Nothing Set iConf = Nothing Set Flds = Nothing End Sub Листинг 5. Добавление вызова процедуры Wakeup в сценарий Листинга 1 …………….. // Ищем первое вхождение записи на восстановление If intRecordNum2=0 Then If InStr(1,objItem.message,strAdmin2,1) Then intRecordNum2 = intRec +1 WakeUp End If ………….. Листинг 6. Процедура WakeUp Sub WakeUp On Error Resume Next // если ошибка, переходим к следующему Dim arrComputers Dim WshShell, str // Перечисляем имена серверов, которые должны быть выключены arrComputers = Array("Computer1","Computer2","Computer3") Set WshShell = CreateObject("WScript.Shell") For Each strComputer In arrComputers str="ping "& strComputer //запускаем в режиме hide Return = WshShell.Run(str, 0) Next End Sub ----------------------------------------------------------------------------------------------------------------- Настраиваем автоответчик на базе Linux Павел Закляков # rpm -qa|grep mgetty # rpm -e mgetty mgetty-sendfax mgetty-viewfax mgetty-voice # wget ftp://alpha.greenie.net/pub/mgetty/source/1.1/mgetty1.1.33-Apr10.tar.gz # tar -zxvf mgetty1.1.33-Apr10.tar.gz -C /progi # cd /progi/mgetty-1.1.33 # cp policy.h-dist policy.h # chown fax /usr/local/lib/mgetty+sendfax/faxq-helper # cat /etc/passwd|grep fax # adduser fax # ls -l /dev/ttyS0 # make install # cd /progi/mgetty-1.1.33/voice # make # make -n install # make install # cp /progi/mgetty-1.1.33/voice/voice.conf-dist/usr/local/etc/mgetty+sendfax/voice.conf voice_log_level 6 phone_owner root phone_group phone phone_mode 0660 message_flag_file .flag receive_dir incoming message_dir messages message_list Index backup_message standard.rmd answer_mode voice answer_mode voice:fax answer_mode voice:fax:data port_speed 38400 # diff -urN старый_файл новый_файл S0:345:respawn:/usr/local/sbin/vgetty -n 4 ttyS0 # cat message.wav | wavtopvf | pvfspeed -s 9600 | pvftormd ZyXEL_Omni56K 4 > standard.rmd # cat v-1329-1127227035.rmd | rmdtopvf | pvftowav > file.wav # vm devicetest -l ttyS0 phone_group apache phone_mode 0660 # chgrp apache incoming # chmod g+w incoming # su --login apache #!/bin/bash message_dir="/var/spool/voice/incoming" echo "Content-type:text/html; charset=koi8-r" echo echo "" for f in `ls $message_dir` do echo "$f
" done echo "" chmod +x spisok.sh #!/bin/bash message_dir="/var/spool/voice/incoming" echo "Content-type:text/html; charset=koi8-r" echo echo "" echo "Последнее сообщение: `date -R -r $message_dir/../.flag`
" echo "У вас сообщения:
" for f in `ls $message_dir` do d=`date -R -r $message_dir/$f` echo "$f     " echo "$d
" done echo "" #!/bin/bash echo "Content-type:audio/wav" echo cat /var/spool/voice/incoming/$QUERY_STRING|/usr/local/bin/rmdtopvf|/usr/local/bin/pvftowav echo "$f     " echo "$f    " #!/bin/bash rm /var/spool/voice/incoming/$QUERY_STRING echo "Сообщение $QUERY_STRING удалено.
" echo "delete    " #!/bin/bash message_dir="/var/spool/voice/incoming" echo "Content-type:text/html; charset=koi8-r" echo echo "" if [ "$QUERY_STRING» != "" ] then rm $message_dir/$QUERY_STRING echo "Сообщение $QUERY_STRING удалено.
" fi echo "Последнее сообщение: `date -R -r $message_dir/../.flag`
" echo "У вас сообщения:
" for f in `ls $message_dir` do d=`date -R -r $message_dir/$f` fn=`echo $f|cut -d"." -f1` echo "$fn.wav    " echo "delete    " echo " $d
" done echo "" ----------------------------------------------------------------------------------------------------------------- Цифровое небо, или Организуем прием спутникового вещания Антон Борисов # wget linuxtv-dvb-1.1.1.tar.bz2 # tar xjvf linuxtv-dvb-1.1.1.tar.bz2 # cd linuxtv-dvb-1.1.1 # make && make install # ./MAKEDEV-DVB.sh # /sbin/depmod -a # wget linuxtv-dvb-apps-1.1.0.tar.bz2 # tar xjvf linuxtv-dvb-apps-1.1.0.tar.bz2 # cd linuxtv-dvb-apps-1.1.0 # make # /sbin/insmod dvb-core dvb_shutdown_timeout=0 # /sbin/insmod stv0299 # /sbin/insmod skystar2 # dmesg Частота (freq.): 12073 Поляризация (там же): L (левая, она же горизонтальная) Символьный поток (SR): 27500 Аудиоканал (Audio): 4100 Идентификатор (SID): 2 Dinamit FM:12073:h:0:27500:0:4100:1:2 TV1:12173:h:0:2532:401:301:1:1 TNV:12214:h:0:4340:401:320:1:1 # cp channels.conf ~/.mplayer/ # cd linuxtv-dvb-apps-1.1.0/util/szap # ./szap "Dinamit FM" -c ~/.mplayer/channels.conf # cd MPlayer-1.0pre7try2 # ./configure --prefix=/usr/local/mplayer --with-dvbincdir=../dvb/linuxtv-dvb-apps-1.1.0/include/ # make # make install # mplayer dvb://0@"Monte Carlo" -tsprobe 12000