p1nokk1o, p!nokk!o, pinokkio

ManageEngine ServiceDesk Update - проблемы

У знакомых на работе установлен ManageEngine ServiceDesk - удобная штука для тех. поддержки.
После обновления - ServiceDesk перестал видеть часть прикрепленных к задачам файлов - причем исключительно тех, чьи имена содержали кириллицу. Попросили помочь с бедой.

Как оказалось, ServiceDesk после обновления, у части файлов, находящихся в папке-хранилище "fileAttachments", в их именах вместо кириллических символов подставил символ "?". А вот на странице задачи выводил правильные имена прикрепленных к ней файлов. Рожилось подозрение, что некорректные имена файлов это имена в кодировке "CP1251" положенные на файловую систему с кодировкой "UTF-8". Создав файл с именем в кодировке "CP1251" я получил файл с именем состоящим из "?" вместо кириллических символов, что подтвердило мои предположения. Таким образом встала наобходимость переименовать файлы с некорректными именами в нормальные.

Два часа ковыряния в mysql - и вуаля! наконец-то была найдена таблица хранящая в себе прикрепленные файлы - "sdeskattachment". Для отображения использовалось поле "attachmentname", а для загрузки файла поле - "attachmentpath", содержащее в себе путь относительно папки "ServiceDesk/bin".

Еще полчаса и родился php-скрипт успешно справившийся со своей задачей. Предлагаю его вашему вниманию - возможно кому-то это поможет.


 //Путь к сокету т.к ServiceDesk стартует mysql Из своей подпапки, а не системно установленный Mysql
 $socket = "/opt/ServiceDesk/mysql/tmp/mysql.sock";
 //Путь к папке servicedesk/bin - с "/" в конце!
 $baseDir = "/opt/ServiceDesk/bin/";
 //имя пользователя Mysql
 $username = "root";
 //пароль пользователя mysql
 $passwd = "";

 echo "Connecting...";
 $dbh = @mysql_connect(":".$socket,$username,$passwd);
 if ( !$dbh )
 {
  echo "fail!\n";
  echo "FATAL: Unable to connect to database\n";
  die();
 }
 echo "ok\n";
 echo "Executing query...";
 //Устанавливаем кодировку mysql - UTF-8
 mysql_query("SET CHARACTER SET UTF8");
 mysql_query("SET NAMES UTF8");
 //Получаем список файлов прикрепленных к задачам
 $result  = mysql_query( "SELECT attachmentname, attachmentpath from servicedesk.sdeskattachment" );
 if ( is_resource( $result ) )
 {
  echo "Ok\n";
  echo "Fetching results...";
  $list = array();
  while ( $tmpRow = @mysql_fetch_array( $result, MYSQL_ASSOC ) )
  {
    $list[] = $tmpRow;
  }
  @mysql_free_result( $result );
  echo count( $list )." record(s) fetched\n";
  echo "Disconnected\n";
  mysql_close( $dbh );

  //Идем по списку файлов
  echo "Searching attachment's broken filenames...\n";
  for ( $i = 0; $i < count( $list ); $i++ )
  {
   $filename = $list[$i]["attachmentname"];//Имя в кодировке UTF-8 из БД
   $ru_filename = iconv("UTF-8", "CP1251", $filename); //Переконвертируем имя в кодировку CP1251
   //Заменяем все кириллические символы на "?"
   $exist = false;
   for ( $z = 0; $z < strlen( $ru_filename ); $z++ )
   {
    for ( $j=192; $j<=255; $j++ )
    {
     //А..Я а..я
     if ( chr($j) == substr( $ru_filename, $z, 1 ) )
     {
      $ru_filename = str_replace(chr($j), chr(63), $ru_filename);
      $exist = true;
     }
     //№
     if ( chr(185) == substr( $ru_filename, $z, 1 ) )
     {
      $ru_filename = str_replace(chr(185), chr(63), $ru_filename);
      $exist = true;
     }
    }
   }
   //Конвертируем обратно в UTF-8
   $ru_filename = iconv("CP1251", "UTF-8", $ru_filename);
   //В имени файла были кириллические символы?
   if ( $exist )
   {
    //В некоторых полных путях к файлу встречаются экранированные символы "/", заменяем их одинарный "/"
    $full_filename = str_replace("//","/", $list[$i]["attachmentpath"] );
    //Получаем путь к файлу
    $tmp = explode("/", $full_filename );
    $path = "";
    for ( $j=0;$j<count($tmp)-1;$j++)
    {
     if ( $path != "" )  { $path .="/"; }
     $path .= $tmp[$j];
    }
    //Файл с исковерканным именем - существует?
    if ( file_exists( $baseDir.$path."/".$ru_filename ) )
    {
     //переименовываем файл в нормальный вид
     echo "Rename ".$baseDir.$path."/".$ru_filename." --> ".$baseDir.$path."/".$filename."\n";
     rename( $baseDir.$path."/".$ru_filename, $baseDir.$path."/".$filename );
    }
   }
  }
 }
 else
 {
  echo "fail!\nFATAL: Unable to execute query!\n";
 }
?>
p1nokk1o, p!nokk!o, pinokkio

Установка Postfix на Ubuntu 10.10 Server ч2.

Инструкция по установке Postfix на Ubuntu 10.10 Server (основана на Postfix Ubuntu 8.04 Tutorial by Falko Timme) ч2.



  1. Настройки Courier
    Укажем Courier, чтобы он проводил аутентификацию используя нашу базу данных MySQL. Редактируем /etc/courier/authdaemonrc и изменяем значение authmodulelist
    #> sudo vi /etc/courier/authdaemonrc
    authmodulelist="authmysql"

    Сделаем резервную копию файла /etc/courier/authmysqlrc и очистим его содержимое:
    #> sudo cp /etc/courier/authmysqlrc /etc/courier/authmysqlrc_orig; sudo cat /dev/null > /etc/courier/authmysqlrc

    Добавим в него новые строки
    #> sudo vi /etc/courier/authmysqlrc
    MYSQL_SERVER 127.0.0.1
    MYSQL_USERNAME тут_имя_пользователя_из_пункта_3
    MYSQL_PASSWORD тут_пароль_этого_пользователя
    MYSQL_PORT 3306
    MYSQL_DATABASE mail
    MYSQL_USER_TABLE users
    MYSQL_CRYPT_PWFIELD password
    MYSQL_UID_FIELD 5000
    MYSQL_GID_FIELD 5000
    MYSQL_LOGIN_FIELD email
    MYSQL_HOME_FIELD "/home/vmail"
    MYSQL_MAILDIR_FIELD CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/')
    MYSQL_NAME_FIELD CONCAT(lastname,' ',firstname)
    MYSQL_QUOTA_FIELD quota

    Редактируем файл /etc/courier/imapd-ssl
    #> sudo vi /etc/courier/imapd-ssl
    SSLPORT=993
    SSLADDRESS=ip_адрес_вашего_почтового_сервера

    Редактируем файл /etc/courier/pop3d-ssl
    #> sudo vi /etc/courier/pop3d-ssl
    SSLPORT=995
    SSLADDRESS=ip_адрес_вашего_почтового_сервера

    ВНИМАНИЕ! Убедитесь что порты 25, 110, 143, 993, 995 открыты в Вашем фаерволле.
    Перезапустим Courier:
    #> sudo /etc/init.d/courier-authdaemon restart;sudo /etc/init.d/courier-imap restart;sudo /etc/init.d/courier-imap-ssl restart;sudo /etc/init.d/courier-pop restart;sudo /etc/init.d/courier-pop-ssl restart

    Убедимся что наш POP3-сервер корректно работает
    #> telnet localhost pop3
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    +OK Hello there.
    quit
    +OK Better luck next time.
    Connection closed by foreign host.

    Поправим файл /etc/aliases так чтобы вся поста приходящая на root перенаправлялась на postmaster@ваш_домен
    #> sudo vi /etc/aliases
    postmaster: root
    root: postmaster@ваш_домен

    После изменения /etc/aliases, вы должны запустить команду newaliases и перезапустить Postfix
    #> sudo newaliases;sudo /etc/init.d/postfix restart


  2. 7) Установка анти-спам и анти-вирусного ПО
    #> sudo  apt-get install amavisd-new spamassassin clamav clamav-daemon zoo unzip bzip2 unzoo libnet-ph-perl libnet-snpp-perl libnet-telnet-perl nomarch lzop pax


    Настроим amavisd-new. Конфигурационные файлы находятся в директории /etc/amavis/conf.d .
    Ознакомитесь с ними. Большинство из настроек в этих файлах отлично выставлены, но все же мы изменим три файла:
    Во первых включим ClamAV и SpamAssassin in /etc/amavis/conf.d/15-content_filter_mode раскомментировав @bypass_virus_checks_maps и @bypass_spam_checks_maps lines:
    #> sudo vi /etc/amavis/conf.d/15-content_filter_mode

    Последним отредактируем /etc/amavis/conf.d/50-user добавив посередке параметр $pax='pax';
    #> sudo vi /etc/amavis/50-user

    use strict;
    #
    # Place your configuration directives here. They will override those in
    # earlier files.
    #
    # See /usr/share/doc/amavisd-new/ for documentation and examples of
    # the directives you can use in this file
    #
    $pax = ‘pax’;

    #------------ Do not modify anything below this line -------------
    1; # ensure a defined return


    После этого добавим пользователя clamav в группу amavis и презапустим amavisd-new и ClamAV:
    #> sudo adduser clamav amavis; sudo /etc/init.d/amavis restart; sudo /etc/init.d/clamav-daemon restart; sudo /etc/init.d/clamav-freshclam restart


    Добавим следующие строки в /etc/postfix/master.cf:
    #> sudo vi etcpostfix/master.cf
    amavis unix - - - - 2 smtp
    -o smtp_data_done_timeout=1200
    -o smtp_send_xforward_command=yes

    127.0.0.1:10025 inet n - - - - smtpd
    -o content_filter=
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o smtpd_restriction_classes=
    -o smtpd_client_restrictions=
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o mynetworks=127.0.0.0/8
    -o strict_rfc821_envelopes=yes
    -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
    -o smtpd_bind_address=127.0.0.1

    Перезапустим Postfix
    #> sudo /etc/init.d/postfix restart

    Убедимся, что Postfix (master) прослушивает 25 (smtp) и 10025 порт, а amavisd-new расположен на 10024:
    #> sudo netstat –tapln
    tcp 0 0 127.0.0.1:10024 0.0.0.0:* LISTEN 1834/amavisd
    tcp 0 0 127.0.0.1:10025 0.0.0.0:* LISTEN 1528/master
    tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN 1528/master


  3. Установка Razor, Pyzor, DCC и настройка SpamAssassin
    Razor, Pyzor и DCC это спам фильтры, которые используются совместно для фильтрации в сети. Установим Razor и Pyzor
    #> sudo apt-get install razor pyzor

    DCC не содержится в репозитории Ubuntu, поэтому мы его установим с сайта автора.
    Убедитесь, что у вас установлен пакет “wget”.
    #> cd /tmp
    #> sudo wget –c http://www.dcc-servers.net/dcc/source/dcc.tar.Z;sudo tar –zxvf ./dcc.tar.Z

    Перейдите в папку с распакованным архивом вида “ dcc-x.x.xxx” (например “dcc-1.3.141”)
    #> cd dcc-1.3.141
    #> sudo ./configure;sudo make;sudo make install


    Скажем SpamAssassin использовать эти три программы. Отредактируем /etc/spamassassin/local.cf добавив несколько строчек в него:
    #> sudo vi /etc/spamassassin/local.cf
    #dcc
    use_dcc 1
    dcc_path /usr/local/bin/dccproc
    #pyzor
    use_pyzor 1
    pyzor_path /usr/bin/pyzor
    #razor
    use_razor2 1
    razor_config /etc/razor/razor-agent.conf
    #bayes
    use_bayes 1
    use_bayes_rules 1
    bayes_auto_learn 1


    Мы должны включить плагин DCC в SpamAssassin. Откроем /etc/spamassassin/v310.pre и раскомментируем такую строчку loadplugin Mail::SpamAssassin::Plugin::DCC :
    #> sudo vi /etc/spamassassin/v310.pre
    # DCC - perform DCC message checks.
    # DCC is disabled here because it is not open source. See the DCC
    # license for more details.
    #
    loadplugin Mail::SpamAssassin::Plugin::DCC

    Можно проверить настройки SpamAssassin выполнив:
    #> sudo spamassassin --lint

    Вывод не должен содержать никаких ошибок.
    Перезапускаем amavisd-new:
    #> sudo /etc/init.d/amavis restart

    Обновим набор правил для SpamAssassin следующим образом:
    #> sudo sa-update –no-gpg

    Добавим в cron задание, чтобы набор правил обновлялся регулярно. Запустим
    crontab –e чтобы открыть редактор cron и добавим в него следующее задание:
    #> sudo crontab -e
    23 4 */2 * * /usr/bin/sa-update –no-gpg &> /dev/null

    Это позволит обновлять набор правил каждый 2 день в 4 часа 23 минуты.

  4. Предупреждение при превышении квоты
    Создадим Perl-скрипт отсылающий на почтовый ящик администратора сообщения о том, что квота какого-либо почтового ящика вашего домена превышена.
    #> sudo /usr/local/sbin/quota_notify
    #!/usr/bin/perl -w

    # Author <jps@tntmax.com>
    #
    # This script assumes that virtual_mailbox_base in defined
    # in postfix's main.cf file. This directory is assumed to contain
    # directories which themselves contain your virtual user's maildirs.
    # For example:
    #
    # -----------/
    # |
    # |
    # home/vmail/domains/
    # | |
    # | |
    # example.com/ foo.com/
    # |
    # |
    # -----------------
    # | | |
    # | | |
    # user1/ user2/ user3/
    # |
    # |
    # maildirsize
    #

    use strict;

    my $POSTFIX_CF = "/etc/postfix/main.cf";
    my $MAILPROG = "/usr/sbin/sendmail -t";
    #Укажите процент заполнения почтового ящика при котором сработает предупреждение
    my $WARNPERCENT = 80;
    #Укажите email администратора вашего домена
    my @POSTMASTERS = ('postmaster@myhost.ru');
    #Название ваше компании
    my $CONAME = 'MyHost Company';
    #С какого адреса будут приходить письма администратору(поле From)
    my $COADDR = 'postmaster@myhost.ru;
    #С какого адреса будут приходить письма пользователю превысевшему квоту(поле From)
    my $SUADDR = 'postmaster@myhost.ru';
    #Отправлять ли письма администратору с отчетом о заполненности ящиков пользователей
    my $MAIL_REPORT = 1;
    #Отправлять ли пользователям письма-предупреждения о превышении квоты
    my $MAIL_WARNING = 1;

    #get virtual mailbox base from postfix config
    open(PCF, "< $POSTFIX_CF") or die $!;
    my $mboxBase;
    while () {
    next unless /virtual_mailbox_base\s*=\s*(.*)\s*/;
    $mboxBase = $1;
    }
    close(PCF);

    #assume one level of subdirectories for domain names
    my @domains;
    opendir(DIR, $mboxBase) or die $!;
    while (defined(my $name = readdir(DIR))) {
    next if $name =~ /^\.\.?$/; #skip '.' and '..'
    next unless (-d "$mboxBase/$name");
    push(@domains, $name);
    }
    closedir(DIR);
    #iterate through domains for username/maildirsize files
    my @users;
    chdir($mboxBase);
    foreach my $domain (@domains) {
    opendir(DIR, $domain) or die $!;
    while (defined(my $name = readdir(DIR))) {
    next if $name =~ /^\.\.?$/; #skip '.' and '..'
    next unless (-d "$domain/$name");
    push(@users, {"$name\@$domain" => "$mboxBase/$domain/$name"});
    }
    }
    closedir(DIR);

    #get user quotas and percent used
    my (%lusers, $report);
    foreach my $href (@users) {
    foreach my $user (keys %$href) {
    my $quotafile = "$href->{$user}/maildirsize";
    next unless (-f $quotafile);
    open(QF, "< $quotafile") or die $!;
    my ($firstln, $quota, $used);
    while () {
    my $line = $_;
    if (! $firstln) {
    $firstln = 1;
    die "Error: corrupt quotafile $quotafile"
    unless ($line =~ /^(\d+)S/);
    $quota = $1;
    last if (! $quota);
    next;
    }
    die "Error: corrupt quotafile $quotafile"
    unless ($line =~ /\s*(-?\d+)/);
    $used += $1;
    }
    close(QF);
    next if (! $used);
    my $percent = int($used / $quota * 100);
    $lusers{$user} = $percent unless not $percent;
    }
    }

    #send a report to the postmasters
    if ($MAIL_REPORT) {
    open(MAIL, "| $MAILPROG");
    select(MAIL);
    map {print "To: $_\n"} @POSTMASTERS;
    print "From: $COADDR\n";
    print "Subject: Daily Quota Report.\n";
    print "DAILY QUOTA REPORT:\n\n";
    print "----------------------------------------------\n";
    print "| % USAGE | ACCOUNT NAME |\n";
    print "----------------------------------------------\n";
    foreach my $luser ( sort { $lusers{$b} <=> $lusers{$a} } keys %lusers ) {
    printf("| %3d | %32s |\n", $lusers{$luser}, $luser);
    print "---------------------------------------------\n";
    }
    print "\n--\n";
    print "$CONAME\n";
    close(MAIL);
    }

    #email a warning to people over quota
    if ($MAIL_WARNING) {
    foreach my $luser (keys (%lusers)) {
    next unless $lusers{$luser} >= $WARNPERCENT; # skip those under quota
    open(MAIL, "| $MAILPROG");
    select(MAIL);
    print "To: $luser\n";
    map {print "BCC: $_\n"} @POSTMASTERS;
    print "From: $SUADDR\n";
    print "Subject: WARNING: Your mailbox is $lusers{$luser}% full.\n";
    print "Reply-to: $SUADDR\n";
    print "Your mailbox: $luser is $lusers{$luser}% full.\n\n";
    print "Once your e-mail box has exceeded your monthly storage quota\n";
    print "your monthly billing will be automatically adjusted.\n";
    print "Please consider deleting e-mail and emptying your trash folder to clear some space.\n\n";
    print "Contact <$SUADDR> for further assistance.\n\n";
    print "Thank You.\n\n";
    print "--\n";
    print "$CONAME\n";
    close(MAIL);
    }
    }

    Сделаем файл исполняемым
    #> sudo chmod +x /usr/local/sbin/quota_notify

    Запустим crontab -e чтоб задать задание cron на выполнения скрипта
    #> sudo crontab -e

    0 0 * * * /usr/local/sbin/quota_notify &> /dev/null

  5. Проверка функционирования Postfix
    Чтобы посмотреть слушает ли Postfix порты SMTP-AUTH и TLS, выполним

    #> sudo telnet localhost 25

    После установления подключения с вашим почтовым сервером Postfix введем следующее:
    ehlo localhost

    и увидим следующие строки если все нормально
    250-STARTTLS
    250-AUTH LOGIN PLAIN

    Введем quit для того чтобы вернутся в оболочку Linux.


  6. Создание почтовых ящиков
    Для начала установим программу для отправки почты из консоли. Данная программа необходима для того, чтобы отослать письмо на созданный почтовый ящик так как только в этом случае почтовый ящик корректно создаться в папке “/home/vmail” и будет функционировать.
    #>sudo apt-get install bsd-mailx

    Создадим 4 shell-скрипта. Первый будет отвечать за создание почтового домена.
    #>sudo vi /root/mail_domain_add.sh
    #!/bin/bash
    mysql=/usr/bin/mysql

    AskQuestion() {
    DefaultAns=$2
    Answer="$DefaultAns"
    if [ -z "$Answer" ]
    then
    echo -n "${1}: "
    else
    echo -n "${1} (${2}): "
    fi
    read Answer
    if [ -z "$Answer" ]
    then
    Answer="$DefaultAns"
    fi
    }
    echo "New Mail Domain Create Utility v1.0"
    echo "====================================="
    domain=""
    while [ -z "$domain" ]
    do
    AskQuestion "Enter mail domain (e.g domain.ltd)"
    domain=$Answer
    done

    mysql_user=""
    while [ -z "$mysql_user" ]
    do
    AskQuestion "Enter mysql user"
    mysql_user=$Answer
    done

    mysql_pswd=""
    while [ -z "$mysql_pswd" ]
    do
    AskQuestion "Enter mysql password"
    mysql_pswd=$Answer
    done

    echo -n "Creating mail domain..."
    echo "INSERT INTO mail.domains (domain) VALUES ('$domain');" >/tmp/sql.tmp
    $mysql -u $mysql_user --password=$mysql_pswd -D mail
    echo "done"
    rm -f /tmp/sql.tmp


    Второй - за создание почтовых ящиков.
    #>sudo vi /root/mail_user_add.sh
    #!/bin/bash
    mailx=/usr/bin/mailx
    mysql=/usr/bin/mysql
    welcome=/root/ welcome.msg

    # Prompt for response, store result in Answer

    AskQuestion() {
    DefaultAns=$2
    Answer="$DefaultAns"
    if [ -z "$Answer" ]
    then
    echo -n "${1}: "
    else
    echo -n "${1} (${2}): "
    fi
    read Answer
    if [ -z "$Answer" ]
    then
    Answer="$DefaultAns"
    fi
    }
    echo "New User Mailbox Create Utility v1.0"
    echo "====================================="
    mbox=""
    while [ -z "$mbox" ]
    do
    AskQuestion "Enter mailbox (e.g user@domain.ltd)"
    mbox=$Answer
    done

    pswd1=""
    pswd2=""

    while [ -z $pswd1 ]
    do
    while [ -z "$pswd1" ]
    do
    AskQuestion "Enter mailbox password"
    pswd1=$Answer
    done

    while [ -z "$pswd2" ]
    do
    AskQuestion "Confirm mailbox password"
    pswd2=$Answer
    done
    if [ "$pswd1" != "$pswd2" ]
    then
    echo "ERROR: mailbox password not confirmed"
    pswd1=""
    pswd2=""
    fi
    done


    quota=10485760
    min=0
    AskQuestion "Enter mailbox quota size (e.g 10485760)"
    if [ "$Answer" -gt "$min" ]
    then
    quota=$Answer
    fi

    firstname=""
    while [ -z "$firstname" ]
    do
    AskQuestion "Enter firstname (e.g Peter)"
    firstname=$Answer
    done

    secondname=""
    AskQuestion "Enter secondname (e.g G.)"
    secondname=$Answer

    lastname=""
    while [ -z "$lastname" ]
    do
    AskQuestion "Enter lastname (e.g Anvil)"
    lastname=$Answer
    done

    mysql_user=""
    while [ -z "$mysql_user" ]
    do
    AskQuestion "Enter mysql user"
    mysql_user=$Answer
    done

    mysql_pswd=""
    while [ -z "$mysql_pswd" ]
    do
    AskQuestion "Enter mysql password"
    mysql_pswd=$Answer
    done

    echo -n "Creating mailbox..."
    echo "INSERT INTO mail.users (email, password, quota, firstname, secondname, lastname, enabled) VALUES ('$mbox',ENCRYPT('$pswd1'), $quota, '$firstname', '$secondname', '$lastname', 'Y');" >/tmp/sql.tmp
    $mysql -u $mysql_user --password=$mysql_pswd -D mail
    echo "done"
    rm -f /tmp/sql.tmp
    echo "Activating mailbox..."
    $mailx -s "Congratulations" $mbox <$welcome
    echo "done"


    Третий – за смену пароля на указанный почтовый ящик.
    #>sudo vi /root/mail_user_chngpswd.sh
    #!/bin/bash
    mysql=/usr/bin/mysql

    AskQuestion() {
    DefaultAns=$2
    Answer="$DefaultAns"
    if [ -z "$Answer" ]
    then
    echo -n "${1}: "
    else
    echo -n "${1} (${2}): "
    fi
    read Answer
    if [ -z "$Answer" ]
    then
    Answer="$DefaultAns"
    fi
    }
    echo "User Mailbox Password Change Utility v1.0"
    echo "====================================="
    mbox=""
    while [ -z "$mbox" ]
    do
    AskQuestion "Enter mailbox (e.g user@domain.ltd)"
    mbox=$Answer
    done

    pswd1=""
    pswd2=""

    while [ -z $pswd1 ]
    do
    while [ -z "$pswd1" ]
    do
    AskQuestion "Enter mailbox new password"
    pswd1=$Answer
    done

    while [ -z "$pswd2" ]
    do
    AskQuestion "Confirm mailbox new password"
    pswd2=$Answer
    done
    if [ "$pswd1" != "$pswd2" ]
    then
    echo "ERROR: mailbox new password not confirmed"
    pswd1=""
    pswd2=""
    fi
    done

    mysql_user=""
    while [ -z "$mysql_user" ]
    do
    AskQuestion "Enter mysql user"
    mysql_user=$Answer
    done
    mysql_pswd=""
    while [ -z "$mysql_pswd" ]
    do
    AskQuestion "Enter mysql password"
    mysql_pswd=$Answer
    done
    echo -n "Changing password..."
    echo "UPDATE mail.users set password=ENCRYPT('$pswd1') where email='$mbox'">/tmp/sql.tmp
    $mysql -u $mysql_user --password=$mysql_pswd -D mail
    echo "done"
    rm -f /tmp/sql.tmp


    Четвертый – за добавление правил перенаправлений писем с одного почтового ящика на другой.
    #>sudo vi /root/mail_forward_add.sh
    #!/bin/bash
    mysql=/usr/bin/mysql

    AskQuestion() {
    DefaultAns=$2
    Answer="$DefaultAns"
    if [ -z "$Answer" ]
    then
    echo -n "${1}: "
    else
    echo -n "${1} (${2}): "
    fi
    read Answer
    if [ -z "$Answer" ]
    then
    Answer="$DefaultAns"
    fi
    }
    echo "Mail Forwarding Utility v1.0"
    echo "====================================="
    src=""
    dst=""
    while [ "$src" == "$dst" ]
    do
    while [ -z "$src" ]
    do
    AskQuestion "Enter source mailbox (e.g user1@domain.ltd)"
    src=$Answer
    done

    while [ -z "$dst" ]
    do
    AskQuestion "Enter destination mailbox (e.g user2@domain.ltd or user2@domain.ltd, user3@domain.ltd ... etc)"
    dst=$Answer
    done
    if [ "$src" == "$dst" ].
    then
    echo "ERROR: Invalid fowarding rule! Source mailbox must not be equal to destination mailbox"
    src="";
    dst=""
    fi
    done

    mysql_user=""
    while [ -z "$mysql_user" ]
    do
    AskQuestion "Enter mysql user"
    mysql_user=$Answer
    done

    mysql_pswd=""
    while [ -z "$mysql_pswd" ]
    do
    AskQuestion "Enter mysql password"
    mysql_pswd=$Answer
    done

    echo -n "Creating forwarding rule..."
    echo "INSERT INTO mail.forwardings (source, destination) VALUES ('$src', '$dst');" >/tmp/sql.tmp
    $mysql -u $mysql_user --password=$mysql_pswd -D mail
    echo "done"
    rm -f /tmp/sql.tmp

    Создадим также файл с текстом письма которое будет отсылаться свежесозданным пользователям.
    #>sudo vi /root/welcome.msg
    Здравствуйте.
    Приветствую Вас в нашей почтовой системе.
    Теперь вы можете отправлять и получать письма с Вашего почтового ящика.
    Напоминаю Вам, что правилами предприятия
    - запрещена массовая и вирусная рассылка
    - запрещена отправка .exe, .dll файлов (если все же их нужно отправить,.
    упакуйте такие файлы в архив и отправьте уже его)
    - запрещен вынос мозга админу "умными" вопросами
    - разрешена и приветствуется поставка пива админу в неограниченных количествах

    С Уважением, Ваш Любимый Админ

    Сделаем файлы исполняемым
    #> sudo chmod +x /root/ mail_domain_add.sh; sudo +x /root/ mail_user_add.sh;sudo +x /root/mail_user_chngpswd.sh;sudo +x /root/mail_forward_add.sh

    Добавим наш почтовый домен в базу
    #> sudo /root/ mail_domain_add.sh
    New Mail Domain Create Utility v1.0
    =====================================
    Enter mail domain (e.g domain.ltd): тут_введите_ваш_почтовый_домен (например myhost.ru)
    Enter mysql user: тут_введите_имя_пользователя_из_пункта_3
    Enter mysql password: тут_введите_пароль_этого_пользователя
    Creating mail domain...
    done

    Если Вы увидите фразу “… Duplicate entry …” это означает что домен с таким именем в базе уже есть.
    Создадим первый почтовый ящик:
    #> sudo /root/ mail_user_add.sh
    New User Mailbox Create Utility v1.0
    ==============================
    Enter mailbox (e.g user@domain.ltd) тут_введите_ваш_почтовый_ящик (например admin@myhost.ru)
    Enter mailbox password: тут_введите_пароль_на_ваш_почтовый_ящик
    Confirm mailbox password: тут_введите_пароль_на_ваш_почтовый_ящик_еще_раз
    Enter mailbox quota size (e.g 10485760): тут_укажите_размер_почтового_ящика_в_байтах
    Enter firstname (e.g Peter): тут_укажите_ваше_имя
    Enter secondname (e.g G.): тут_укажите_отчество
    Enter lastname (e.g Anvil): тут_укажите_фамилию
    Enter mysql user: тут_введите_имя_пользователя_из_пункта_3
    Enter mysql password: тут_введите_пароль_этого_пользователя
    Creating mailbox...
    done
    Activating mailbox...
    done

    Если Вы увидите фразу “… Duplicate entry …” это означает что почтовый ящик с таким именем в базе уже есть.
    Перенаправим все письма с ящиков postmaster@ваш_домен и webmaster@ваш_домен на только что созданный почтовый ящик.
    #> sudo sudo /root/ mail_ forward _add.sh
    Mail Forwarding Utility v1.0
    =======================
    Enter source mailbox (e.g user1@domain.ltd): postmaster@ваш_домен (например postmaster@myhost.ru)
    Enter destination mailbox (e.g user2@domain.ltd or user2@domain.ltd, user3@domain.ltd ... etc): тут_введите_ваш_почтовый_ящик (например admin@myhost.ru, для перенаправления на несколько почтовых ящиков введите эти ящики через запятую)
    Enter mysql user: тут_введите_имя_пользователя_из_пункта_3
    Enter mysql password: тут_введите_пароль_этого_пользователя
    Creating forwarding rule...
    done


    Если Вы увидите фразу “… Duplicate entry …” это означает что правило для указанного почтового ящика в базе уже есть.
    При попытке перенаправить письмо с одного ящика на самого себя вы увидите сообщение
    “Invalid fowarding rule! Source mailbox must not be equal to destination mailbox”

    Если все прошло успешно – проверьте существование в папке “/home/vmail” подпапки c именем вашего почтового домена, а в ней подпапки с именем пользователя чей почтовый ящик мы только что создали. Например для ящика почтового домена”myhost.ru” и ящика admin@myhost.ru в папке “/home/vmail” должна появится подпапка “myhost.ru”, а в ней подпапка “admin”. Если этого не произошло – смотрите лог - /var/log/mail.log на наличие ошибок и исправьте их.

    Настроим почтовый клиент – The Bat! для получения и отправки почты.
    Все на примере для почтового домена “myhost.ru”

    Название почтового ящика: admin@myhost.ru
    Ваше полное имя: Админов Админ Админович
    Адрес e-mail: admin@myhost.ru
    Для доступа к серверу использовать протокол: IMAP4
    Сервер для получения почты: mx.myhost.ru
    Адрес сервера SMTP: mx.myhost.ru
    Пользователь: admin@myhost.ru
    Пароль: ***

    После появления почтового ящика в дереве ящиков The Bat! – нажимаем правой кнопкой на ящике и выбираем “Свойства”. В свойствах выбираем “Транспорт”. В появившемся окне для раздела “Отправка почты” указываем соединение “Безопасное на спецпорт TLS” – указываем порт – 995. Для раздела “Получение почты” указываем соединение “Безопасное на спецпорт TLS” – указываем порт – 993. Сохраняем. Перезапускаем The Bat!. Если все работает корректно то при попытке получить почту The Bat! Выдаст окно-предупреждение о том что SSL-сертификат является самоподписанным. Добавьте сертификат к доверенным и можно работать!

p1nokk1o, p!nokk!o, pinokkio

Установка Postfix на Ubuntu 10.10 Server ч1.

Инструкция по установке Postfix на Ubuntu 10.10 Server (основана на Postfix Ubuntu 8.04 Tutorial by Falko Timme) ч1.



#> sudo cp /etc/courier/authmysqlrc /etc/courier/authmysqlrc_orig; sudo cat /dev/null > /etc/courier/authmysqlrc
  1. Останавливаем и отключаем app-armor
    #> sudo /etc/init.d/apparmor stop;sudo update-rc.d -f apparmor remove

  2. Устанавливаем PostFix, Courier, Saslauthd, MySQL
    #> sudo apt-get install apt-get install postfix postfix-mysql postfix-doc 
       mysql-client mysql-server courier-authdaemon courier-authlib-mysql
       courier-pop courier-pop-ssl courier-imap courier-imap-ssl postfix-tls 
       libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql openssl

    В процессе установки вас попросят ввести пароль для пользователя “root” (администратора MySQL-сервера).
    Также спросят создать ли автоматически все необходимые папки для пакета «courier-webadmin» - «НЕТ»
    Также спросят тип почтового сервера – «Интернет-сайт»
    Укажите dns-имя вашего сервера (обычно это имя вашего сервера с приставкой “mx”)

  3. Создаем базу и пользователя MySQL необходимых для postfix
    #> mysql –u root –p         
    Enter password: ****
    mysql> create database mail;                
    

    После создания базы, создадим пользователя под которым postfix будет ходить в базу.
    mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 
           'тут_укажите_имя_пользователя'@'localhost' 
           IDENTIFIED BY 'тут_укажите_пароль_пользователя';
    mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 
           'тут_повторите_имя_пользователя'@127.0.0.1 
           IDENTIFIED BY 'тут_повторите_еще_раз_пароль';
    mysql>flush privileges;
    

    Теперь наполним базу таблицами в которых будет хранится информация о пользователях, почтовых ящиках, квотах.
    mysql> USE mail;
    
    mysql> CREATE TABLE domains (id int not null auto_increment, 
           domain varchar(50) NOT NULL, UNIQUE(domain), PRIMARY KEY (id) ) 
           TYPE=MyISAM;
    
    mysql> CREATE TABLE forwardings (id int not null auto_increment,
           source varchar(80) NOT NULL, destination TEXT NOT NULL, UNIQUE(source), 
           PRIMARY KEY (id) ) TYPE=MyISAM;
    
    mysql> CREATE TABLE users (id int not null auto_increment, 
            firstname char(60) not null, 
           secondname char(60) not null, lastname char(60) not null, 
           email varchar(80) NOT NULL, password varchar(20) NOT NULL, 
           quota INT(10) DEFAULT '10485760', 
           enabled enum('Y', 'N') not null default 'Y',
           UNIQUE(email), PRIMARY KEY (id)) TYPE=MyISAM;
    

    Первая таблица “domains” хранит в себе имена обслуживаемых почтовых доменов – например “myhost.ru”
    Вторая таблица “forwardings” хранит в себе почтовые адреса служащие для перенаправления почты. Это очень удобно когда у вас есть «виртуальные» почтовые ящики – почту с которых вы хотите перенаправлять на свой реальный почтовый ящик. Или же для рассылки уведомлений сразу всем сотрудникам.
    Например: source=community@myhost.ru, destination=ivanov@myhost.ru,petrov@myhost.ru
    Третья таблица “users” хранит в себе имена почтовых ящиков (email), пароль (password) (зашифрован встроенной в mysql функцией ENCRYPT), ФИО владельца (lastname, firstname, secondname), квота – ограничение на размер почтового ящика (quota), включен или нет прием писем на почтовый ящик (enabled).

  4. Настраиваем Postfix
    Так как вся информация о почтовых ящиках хранится в СУБД MySQL необходимо указать postfix как попасть в базу данных. Перво-наперво убедимся что сервер СУБД MySQL в целях безопасности принимает соединения только с локального IP-адреса почтового сервера – 127.0.0.1. Для этого открываем файл /etc/mysq/my.cnf ищем строчку начинающуюся на “bind-address =”. Если после знака “=” стоит “127.0.0.1” отлично. Если нет – правим на “127.0.0.1” (даже если там стоит “localhost” т.к PostFix не умеет из chroot лазить к localhost зато прекрасно умеет это делать с Ip-адресами).

    Если вы внесли изменения в “/etc/mysql/my.cnf” – перезапустите MySQL.
    #> /etc/init.d/mysql restart

    Проверьте после этого что mysql слушает именно «127.0.0.1»
    sudo  netstat -tpln | grep mysql
    tcp        0      0 127.0.0.1:3306          0.0.0.0:*     LISTEN      18692/mysqld
    


    Создаем файлы необходимые PostFix для соединения с СУБД MySQL.
    #> sudo vi /etc/postfix/mysql-virtual_domains.cf

    Вводим нижеследующие строки:
    user = тут_имя_пользователя_из_пункта_3
    password = тут_пароль_этого_пользователя
    dbname = mail 
    query = SELECT domain AS virtual FROM domains WHERE domain='%s'
    hosts = 127.0.0.1
    

    Следующий файл
    #> sudo vi /etc/postfix/mysql-virtual_ forwardings.cf

    Вводим нижеследующие строки:
    user = тут_имя_пользователя_из_пункта_3
    password = тут_пароль_этого_пользователя
    dbname = mail 
    query = SELECT destination FROM forwardings WHERE source='%s'
    hosts = 127.0.0.1
    

    Следующий файл
    #> sudo /etc/postfix/mysql-virtual_mailboxes.cf

    Вводим нижеследующие строки:
    user = тут_имя_пользователя_из_пункта_3
    password = тут_пароль_этого_пользователя
    dbname = mail 
    query = SELECT email FROM users WHERE email='%s' and enabled = 'Y'
    hosts = 127.0.0.1
    

    Следующий файл
    #> sudo /etc/postfix/mysql-virtual_ mailbox_limit_maps.cf

    Вводим нижеследующие строки:
    user = тут_имя_пользователя_из_пункта_3
    password = тут_пароль_этого_пользователя
    dbname = mail 
    query = SELECT quota FROM users WHERE email='%s' and enabled = 'Y'
    hosts = 127.0.0.1
    

    Изменяем права доступа и группу для этих файлов
    #> sudo chmod o= /etc/postfix/mysql-virtual_*.cf
    #> sudo chgrp postfix /etc/postfix/mysql-virtual_*.cf
    

    Создаем нового пользователя и группу с названием vmail (uid=5000) с домашней директорией /home/vmail ,где будут находиться почтовые ящики:
    #> sudo groupadd -g 5000 vmail
    #> sudo sudo useradd -g vmail -u 5000 vmail -d /home/vmail -m
    

    Создаем файлы с помощью которых мы будем отбиваться от спамеров на первом уровне (далее с этим будет бороться антиспам ПО)
    #> sudo vi /etc/postfix/check.client-pcre

    Вводим нижеследующие строки:
    /[ax]dsl.*\..*\..*/i REJECT Your message looks like SPAM
    /\.dsl.*\..*\..*/i   REJECT Your message looks like SPAM
    /cable.*\..*\..*/i   REJECT Your message looks like SPAM
    /client.*\..*\..*/i  REJECT Your message looks like SPAM
    /dhcp.*\..*\..*/i    REJECT Your message looks like SPAM
    /dial.*\..*\..*/i    REJECT Your message looks like SPAM
    /dialup.*\..*\..*/i  REJECT Your message looks like SPAM
    /dslam.*\..*\..*/i   REJECT Your message looks like SPAM
    /host.*\..*\..*/i    REJECT Your message looks like SPAM
    /node.*\..*\..*/i    REJECT Your message looks like SPAM
    /pool.*\..*\..*/i    REJECT Your message looks like SPAM
    /ppp.*\..*\..*/i     REJECT Your message looks like SPAM
    /user.*\..*\..*/i    REJECT Your message looks like SPAM
    /(modem|dia(l|lup)|dialin|dsl|p[cp]p|cable|catv|poo(l|les)|dhcp|client|customer|user|[0-9]{6,})(-|\.|[0-9])/ REJECT Your message looks like SPAM
    /([0-9]{,4}\-[0-9]{,4}\-[0-9]{,4}\-[0-9]{,4})/  REJECT Your message looks like SPAM 
    /([0-9]{,4}\.[0-9]{,4}\.[0-9]{,4}\.[0-9]{,4}.{4,})/     REJECT Your message looks like SPAM
    


    Следующий файл:
    #> sudo vi /etc/postfix/check.dul-pcre

    Вводим нижеследующие строки:
    /[0-9]*-[0-9]*-[0-9]*-[0-9]*-tami\.tami\.pl/i 553 SPAM_POOL
    /pool-[0-9]*-[0-9]*-[0-9]*-[0-9]*\..*/i 553 SPAM_POOL
    /.*-[0-9]*-[0-9]*-[0-9]*-[0-9]*\.gtel.net.mx/i 553 SPAM_POOL
    /dial.*\..*\..*/i 553 SPAM_DIAL
    /ppp.*\..*\..*/i 553 SPAM_PPP
    /dslam.*\..*\..*/i 553 SPAM_DSLAM
    /dhcp.*\..*\..*/i 553 SPAM_DHCP
    /[\.-]dsl.*\..*\..*/i 553 SPAM_DSL
    /[ax]dsl.*\..*\..*/i 553 SPAM_XDSL
    /.*([0-9]*\.){4}cableonline\.com\.mx/i 553 SPAM_IP-cableonline-com-mx
    /.*\.([0-9]*\.){4}ip\.holtonks\.net/i 553 SPAM_ip-holtonks-net
    /([0-9]*-){3}[0-9]*\.fibertel\.com\.ar/i 553 SPAM_IP-fibertel-com-ar
    /.*[0-9]*-[0-9]*\.fibertel\.com\.ar/i 553 SPAM_IP-fibertel-com-ar
    /[0-9]*\.user\.veloxzone\.com\.br/i 553 SPAM_user-veloxzone-com-br
    /[0-9]*\.customer\.alfanett\.no/i 553 SPAM_customer-alfanett-no
    /.*([0-9]*-){3}[0-9]*\.telecom\.net\.ar/i 553 SPAM_host-telecom-net-ar
    /.*(-[0-9]*){2}\.telpol\.net\.pl/i 553 SPAM_host-telpol-net-pl
    /(.*\.){2}maxonline\.com\.sg/i 553 SPAM_host-maxonline-com-sg
    /(.*-){2}.*\.fairgamemail\.us/i 553 SPAM_host-fairgamemail-us
    /[0-9]*[0-9]*-\.wispnet\.net/i 553 SPAM_host-wispnet-net
    /.*-.*(\..*){2}\.ne\.jp/i 553 SPAM_host-ne-jp
    /[0-9]*\..*\.ne\.jp/i 553 SPAM_h09t-ne-jp
    /(.*\.){3}ad\.jp/i 553 SPAM_host-ad-jp
    /(.*\.){4}revip\.asianet\.co\.th/i 553 SPAM_revip-asianet-co-th
    /[0-9]*\..*\.virtua\.com\.br/i 553 SPAM_host-virtua-com-br
    /([0-9]*-){3}[0-9]*\.exatt\.net/i 553 SPAM_host-exatt-net
    /([0-9]*\.){4}ip\.alltel\.net/i 553 SPAM_host-ip-alltel-net
    /[0-9]{6,}\.chello\.../i 553 SPAM_host-chello
    /.*[0-9]*\..*\.chello\.../i 553 SPAM_host-chello-xx
    /.*\..*\.t-dialin\.net/i 553 SPAM_t-dialin-net
    /.*\..*\.t-ipconnect\.de/i 553 SPAM_t-ipconnect-de
    /([0-9]*-){2,3}[0-9]*\..*\.cgocable\.net/i 553 SPAM_host-cgocable-net
    /.*\..*\.shawcable\.net/i 553 SPAM_host-shawcable-net
    /p[0-9]*\.mp[0-9]*\.aaanet\.ru/i 553 SPAM_aaa_modem_pool
    /([0-9]*-){2}[0-9]*\.ip\.adsl\.hu/i 553 SPAM_ip-adsl-hu
    /([0-9]{1,3}\.){2}broadband4\.iol\.cz/i 553 SPAM_broadband-iol-cz
    /.*\.wanadoo.co.uk/ 553 SPAM_host-wanadoo-co
    /.*-[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\..*/i 553 SPAM_host-ip
    /.*[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\..*/i 553 SPAM_host-ip
    /.*\.bdsl\.sk/i 553 SPAM_bdsl-sk
    /dxb-.*[0-9]*\.alshamil\.net\.ae/i 553 SPAM_dxb-net-ae
    /i.*\.versanet\.de/i 553 SPAM_ip-add-rr-ess_networks
    /nn.*\.excitenetwork\.com/i 553 SPAM_ip-add-rr-ess_networks
    /.*\.sbcis\.sbc\.com/i 553 SPAM_ip-add-rr-ess_networks
    /ms-smtp-[0-9]*\.socal\.rr\.com/i 553 SPAM_ip-add-rr-ess_networks
    /hu-out-[0-9]*\.google\.com/i 553 SPAM_hu-out
    /ip-.*\.powernet\.bg/i 553 SPAM_ip-add-rr-ess_networks
    /.*\.claranet\.co\.uk/i 553 SPAM_ip-add-rr-ess_networks
    /.*\.turktelekom\.com\.tr/i 553 SPAM_ip-add-rr-ess_networks
    /imf.*\.mail\.bellsouth\.net/i 553 SPAM_ip-add-rr-ess_networks
    /nat-altair.*\.netbynet\.ru/i 553 SPAM_ip-add-rr-ess_networks
    /server.*\.publicompserver\.de/i 553 SPAM_ip-add-rr-ess_networks
    /.*dynamic\..*\.retail\.telecomitalia\.it/i 553 SPAM_ip-add_networks
    

    Следующий файл:
    #> sudo vi /etc/postfix/check.header

    Вводим нижеследующие строки:
    ^Content-(Type|Disposition):.*name[[:space:]]*=.*\.exe/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.acm/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.ax/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.bat/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.bin/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.bpl/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.cat/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.chm/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.cmd/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.com/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.cpl/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.dat/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.dll/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.dpl/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.drv/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.exe/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.hlp/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.inf/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.ini/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.msc/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.nls/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.ocx/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.onb/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.pif/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.rom/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.scr/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.sys/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.tlb/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.vba/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.vbs/ REJECT
    /^Content-(Type|Disposition):.*name[[:space:]]*=.*\.vxd/ REJECT
    /^Bel-Tracking: .*/    REJECT
    /^Hel-Tracking: .*/    REJECT
    /^Kel-Tracking: .*/    REJECT
    /^BIC-Tracking: .*/    REJECT
    /^Lid-Tracking: .*/    REJECT
    /^X-Mailer: Avalanche/ REJECT
    

    Следующий файл:
    #> sudo vi /etc/postfix/check.mime-header

    Вводим нижеследующие строки:
    /^Disposition-Notification-To:/ IGNORE
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)com)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)exe)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)acm)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)ax )(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)bat)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)bin)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)bpl)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)cat)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)chm)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)cmd)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)com)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)cpl)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)dat)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)dll)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)dpl)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)drv)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)exe)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)hlp)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)inf)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)ini)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)msc)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)nls)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)ocx)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)onb)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)pif)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)rom)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)scr)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)sys)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)tlb)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)vba)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)vbs)(\?=)?"?\s*$/ REJECT
    /^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+(\.|2E)vxd)(\?=)?"?\s*$/ REJECT
    

    Ставим программу которая по сути будет «уничтожать» почту отправленную на несуществующий у вас почтовый ящик
    #> sudo apt-get install procmail

    Правим конфигурационный файл postfix
    #> sudo vi /etc/postfix/main.cf

    Исправляем найденные строки на указанные значения или добавляем строки если таких в файле нет:
    #Папка где находится postfix
    base = /etc/postfix
    
    #Приветствие которое выдается в момент подключения
    #Вводим в легкое заблуждение тех кто попытается выяснить версию почтово-серверного ПО чтобы применить уязвимости
    smtpd_banner = $myhostname ESMTP $mail_name (Windows2008R2)
    biff = no
    append_dot_mydomain = no
    readme_directory = /usr/share/doc/postfix
    
    # TLS parameters
    smtpd_tls_cert_file = $base/smtpd.cert
    smtpd_tls_key_file = $base/smtpd.key
    smtpd_use_tls = yes
    smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
    smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
    
    #Доменное имя почтового сервера (данный компьютер)
    #НЕ ЗАБУДЬТЕ ИСПРАВИТЬ НА СВОЕ!
    myhostname = mx.myhost.ru
    
    #Имя домена (по сути то что будет подставлятся после @ в email-адресе)
    mydomain = myhost.ru
    myorigin = $mydomain
    mydestination = $myhostname, localhost, localhost.$mydomain
    
    alias_maps = hash:/etc/aliases
    alias_database = hash:/etc/aliases
    relayhost =.
    
    #Список IP-адресов (через пробел) или масок подсетей с которых можно #получать/отправлять почту
    #Здесь вы можете прописать «белые» IP-адреса  домашних компьютеров
    #сотрудников и они смогут получать и отправлять корпоративную почту
    #прямо из дома
    mynetworks = 192.168.0.0/16 127.0.0.0/8
    relay_domains = $mydestination, $mynetworks
    local_recipient_maps = $virtual_mailbox_maps
    
    #Указываем с помощью какой программу уничтожать почту пришедшую
    #на несуществующий ящик
    mailbox_command = procmail -a "$EXTENSION"
    
    mailbox_size_limit = 0
    virtual_mailbox_limit = 0
    message_size_limit = 0
    recipient_delimiter = +
    inet_interfaces = all
    html_directory = /usr/share/doc/postfix/html
    virtual_alias_domains =.
    
    #Указываем файлы настроек для работы с MySQL из БД которой и будут #браться пользователи
    virtual_alias_maps = proxy:mysql:$base/mysql-virtual_forwardings.cf, mysql:$base/mysql-virtual_email2email.cf
    virtual_mailbox_domains = proxy:mysql:$base/mysql-virtual_domains.cf
    virtual_mailbox_maps = proxy:mysql:$base/mysql-virtual_mailboxes.cf
    
    #Указываем папку где будут храниться письма
    virtual_mailbox_base = /home/vmail/
    
    #Указываем что владелец – поьзователь “vmail” (uid=5000)
    virtual_uid_maps = static:5000
    virtual_gid_maps = static:5000
    
    # Включаем поддержку sasl аутентификации
    smtpd_sasl_auth_enable = yes
    
    # Включает функциональную совместимость с SMTP клиентами, которые
    # используют устаревшую версию команды AUTH (RFC 2554),
    # например, outlook express 4 и MicroSoft Exchange version 5.0.
    broken_sasl_auth_clients = yes
    smtpd_sasl_authenticated_header = yes
    # Дополнительные ограничения доступа  smtp сервера в контексте
    # smtp запроса клиента
    #Вот тут и пригодятся написанные нами ранее файлы для защиты от #спамеров
    smtpd_recipient_restrictions = reject_non_fqdn_recipient,
    reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unknown_recipient_domain, permit_mynetworks, permit_sasl_authenticated,  check_client_access regexp:$base/check.client-pcre, regexp:$base/check.dul-pcre, reject_unauth_destination, reject_non_fqdn_hostname, reject_invalid_hostname, reject_unverified_sender, permit
    
    #Дополнительные ограничения, применяемые сервером Postfix
    # в контексте SMTP команды HELO
    smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, regexp:$base/check.dul-pcre, reject_invalid_helo_hostname
    
    # Дополнительные ограничения, применяемые сервером Postfix
    # в контексте команды MAIL FROM
    smtpd_sender_restrictions = permit_mynetworks, reject_authenticated_sender_login_mismatch, reject_non_fqdn_sender, reject_unlisted_sender
    
    # Дополнительные ограничения, применяемые сервером Postfix
    # в контексте команды RCPT TO
    smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_unauth_pipelining,  reject_non_fqdn_recipient
    
    # Отклонять команду ETRN
    smtpd_etrn_restrictions = reject
    # Заставляем отклонять почту с неизвестным адресом отправителя.
    # Позволяет бороться с червями и некоторыми вирусами.
    smtpd_reject_unlisted_sender = yes
    
    # Отключает SMTP команду VRFY. В результате чего, невозможно определить
    # существование определенного ящика. Данная техника (применение команды
    # VRFY) используется спамерами для сбора имен почтовых ящиков.
    disable_vrfy_command = yes
    
    # Требуем чтобы адреса, передаваемые в SMTP командах MAIL FROM и RCPT TO
    # заключались в <>, а также не содержали стилей или фраз RFC 822.
    strict_rfc821_envelopes = yes
    
    # Скрываем отображение имени таблицы получателей в ответе "User unknown"
    # yes: User unknown in virtual mailbox table
    # no: User unknown
    show_user_unknown_table_name = no
    
    # Числовой код ответа SMTP сервера Postfix в случае, когда адрес
    # получателя отвергнут ограничением reject_unverified_sender.
    unverified_sender_reject_code = 550
    
    # Требуем, чтобы удаленный SMTP клиент представлял себя
    # в начале SMTP сессии с помощью команды HELO или EHLO.
    smtpd_helo_required = yes
    
    # Всегда отправлять EHLO вначале SMTP сессии
    smtp_always_send_ehlo = yes
    
    # Максимальное количество ошибок, которое может сделать удаленный SMTP #клиент.При превышение данного числа Postfix разорвет соединение.
    smtpd_hard_error_limit = 3
    
    # Отвергаем методы, позволяющие анонимную аутентификациюsmtpd_sasl_security_options = noanonymous
    
    #Таймауты
    smtpd_timeout = 30s
    smtp_helo_timeout = 15s
    smtp_mail_timeout = 15s
    smtp_rcpt_timeout = 15s
    
    #transport_maps = proxy:mysql:$base/mysql-virtual_transports.cfvirtual_create_maildirsize = yes
    virtual_mailbox_extended = yes
    virtual_mailbox_limit_maps = proxy:mysql:$base/mysql-virtual_mailbox_limit_maps.cf
    virtual_mailbox_limit_override = yes
    virtual_maildir_limit_message = "The user you are trying to reach is over quota."virtual_overquota_bounce = yes
    proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $mynetworks $virtual_mailbox_limit_maps #$transport_maps
    
    #Перенаправление на почтовый антивирус который мы поставим позднее
    content_filter = amavis:[127.0.0.1]:10024
    receive_override_options = no_address_mappings
    


    Создадим самоподписанный сертификат SSL необходимый для TLS:
    #> cd /etc/postfix/
    #>sudo openssl req -new -outform PEM -out smtpd.cert -newkey rsa:2048 -nodes -keyout smtpd.key -keyform PEM -days 365 -x509
    Country Name (2 letter code) [AU]: RU
    State or Province Name (full name) [Some-State]: англ. Буквами ваша область (например Novosibirskaya Oblast)
    Locality Name (eg, city) []: англ. Буквами ваш город (например Novosibirsk)
    Organization Name (eg, company) [Internet Widgits Pty Ltd]: англ. Буквами название вашей компании (например OOO Roga and Kopyta)
    Organizational Unit Name (eg, section) []: англ.буквами название отдела (обычно IT)
    Common Name (eg, YOUR name) []: доменное имя вашего почтового сервера (например mx.myhost.ru)
    Email Address []: например  postmaster@myhost.ru
    

    Изменяем права доступа на smtpd.key:
    #> sudo chmod o= /etc/postfix/smtpd.key

    Удалим существующие файлы /etc/courier/imapd.pem и /etc/courier/pop3d.pem и сгенерируем их заново. Для этого вначале отредактируем конфигурационные файлы /etc/courier/imapd.cnf и /etc/courier/pop3d.cnf
    #> sudo vi /etc/courier/imapd.cnf
    RANDFILE = /usr/lib/courier/imapd.rand
    [ req ]
    default_bits = 1024
    encrypt_key = yes
    distinguished_name = req_dn
    x509_extensions = cert_type
    prompt = no
    [ req_dn ]
    C=RU
    ST=тут_укажите_англ.буквами_вшау_область (например Novosibirskaya Oblast)
    L=тут_укажите_англ.буквами_ваш_город (например Novosibirsk)
    O=Courier Mail Server
    OU=Automatically-generated IMAP SSL key
    CN=тут_укажите_доменное_имя_вашего_почтового_сервера (например mx.myhost.ru)emailAddress=тут_укажите_email_владельца_домена (например: postmaster@myhost.ru)
    [ cert_type ]
    nsCertType = server
    

    Отредактируем файл /etc/courier/pop3d.cnf
    #> sudo vi /etc/courier/pop3d.cnf
    RANDFILE = /usr/lib/courier/pop3d.rand
    [ req ]
    default_bits = 1024
    encrypt_key = yes
    distinguished_name = req_dn
    x509_extensions = cert_type
    prompt = no
    [ req_dn ]
    C=RU
    ST=тут_укажите_англ.буквами_вшау_область (например Novosibirskaya Oblast)
    L=тут_укажите_англ.буквами_ваш_город (например Novosibirsk)
    O=Courier Mail Server
    OU=Automatically-generated IMAP SSL key
    CN=тут_укажите_доменное_имя_вашего_почтового_сервера (например mx.myhost.ru)emailAddress=тут_укажите_email_владельца_домена (например: postmaster@myhost.ru)
    [ cert_type ]
    nsCertType = server
    

    Сгенерируем заново файлы /etc/courier/imapd.pem и /etc/courier/pop3d.pem
    #> sudo rm -f /etc/courier/imapd.pem; sudo rm –f /etc/courier/pop3d.pem;sudo /usr/lib/courier/mkimapdcert;sudo /usr/lib/courier/mkpop3dcert

  5. продолжение во второй части.
p1nokk1o, p!nokk!o, pinokkio

Windows7 + Ubuntu 10.10 на одном винчестере. Танцы с бубнами.

Так случилось, что на моем компьютере целый табор разномастных винтов. От разных производителей, разной емкости, да еще и под двумя ОС - Windows7 и Ubuntu 10.10
Надоело мне переключаться между винтами при смене ОС, захотелось все иметь на одном винчестере.
Так бы было все ничего - взять да и поставить обе ОС с нуля на один винт (первой винду конечно, ибо при установке эта зараза начисто переписывает загрузчик, а уж следом Ubuntu чтобы прописался ее загрузчик и появилась возможность загрузки обеих ОС). Но не так все просто. Захотелось оставить настроенную винду да и Ubuntu со всеми ее красявостями. А это уже пахло созданием образов винтов. Итак купил я новый винтик на 2Тб...

По старой памяти решил сделать образы с помощью старичка Norton Ghost, да вот незадача, как оказалось он не умеет работать с не-виндовыми разделами точнее говоря не умеет образы этих разделов компрессировать. Попытка тупо перенести разделы с помощью Acronis Disk тоже не увенчалась успехом ибо он вообще отказывался работать с не-виндовыми разделами.

Почитав кучу статей остановился я на утилите входящей в поставку Ubuntu - dd.
Для начала сделал образы раздела с настроенной Windows7.
Делается это довольно просто.

Загружаемся с CD содержащую ОС Ubuntu 10.10 (можно и выше). Выбираем язык и жмем "Попробовать Ubuntu".
После того как ОС загрузилась нажимаем Ctrl+Alt+T (или выбираем через пункты меню) и получаем окно Терминала.
Далее мы будем работать в нем.
Просмотрим какие разделы у нас содержат Windows7 и ее 100Мб раздел
sudo fdisk -l

У меня это оказались /dev/sda1 (100Мб) и /dev/sda2 (Windows7)

Для хранения образов лично я использовал USB flash-hdd на 500 Гб, он у меня опознался как  /dev/sdb1 - лично Вы можете хранить образы например на другом винчестере - тогда смотрите какое имя устройства он будет иметь у вас.
Монтируем диск на котором будем хранить образы:
sudo mount /dev/sdb1 /media

Для тех кому сложно все делать руками - эти операции можно сделать через Disk Utility в пункте меню "System\Adminstration" :)

Создаем образ раздела /dev/sda1 (100Мб):
sudo dd if=/dev/sda1 bs=8096 | gzip -9cf > /media/windows7-swap-100Mb-sda1.dd-image.gz

Здесь мы указали что делаем образ раздела /dev/sda1 (if=/dev/sda1) в выходной файл windows7-swap-100Mb-sda1.dd-image.gz.


По умолчанию dd не выводит никакой информации о прогрессе. Однако мы можем узнать об этом с помощью маленькой хитрости.
Откроем еще одну консоль терминала (Ctrl+Alt+T) и узнаем pid процесса dd
sudo ps aux | grep dd
Во одной из строк полученного списка мы увидим "dd if=/dev/sda1 ..." это и ест наш процесс, а его pid будет во втром столбце в этой же строке - допустим это будет 4691.
В этой же консоли вводим
sudo watch -n 15 "kill -USR1 4691"
Переключаемся в первую консоль терминала (где у нас вовсю пыхтит dd) и видим как с переодичностью 15 сек он сообщает нам о том сколько мегабайт он обработал.

По тому же сценарию повторим созданием образа раздела с windows7, а затем и разделов с других винчестеров содержащих Ubuntu. Только не забывайте менять имя выходного файла в зависимости от ОС и раздела :)

Теперь займемся восстановлением созданных образов на новом винчестере. Подключаем новый винчестер (у меня это WD 2Тб).
Грузимся с CD с ОС Ubuntu 10.10, выбираем язык и жмем "Попробовать Ubuntu" как и в прошлый раз.
Загрузившись выбираем в пункте меню "System\Administration" утилиту Gparted. С ее помощью мы создадим разделы на новом винчестере.

Выбираем "New Partition" и указываем ее размер в Мб. Первым я создал 100Мб первичный раздел от Windows7. Далее еще два первичных раздела - один размером 100Гб под ОС Windows7 (хотя образ у меня был от винчестера размером 80Гб) и второй под дистрибутивы программ для Windows размером 350Гб. Заодно всем указал тип файловой системы - NTFS.

При создании разделов помните что они не должны быть меньше чем те разделы с которых вы создали образы. Т.е если вы создали образ с раздела объемом 80Гб, то новый раздел куда вы будете восстанавливать образ должен быть не меньше 80 Гб.

Таким образом у меня получилось уже 3 первичных раздела. Так как таких разделов можно создать всего 4 (а мне нужно еще как минимум 2 раздела под ОС Ubuntu - swap и / ) пришлось создать на всю оставшуюся область extended раздел, а уже его разбить еще на два раздела под swap и корень Ubuntu.

Теперь восстанавливаем разделы (примонтировав вначале винчестер на который мы сохранили образы).
Первым у меня будет раздел 100Мб от Windows7 (/dev/sda1), вторым корень Windows7 (/dev/sda2) затем раздел под дистрибутивы (/dev/sda3), и уже потом swap Ubuntu (/dev/sda5) и корень Ubuntu (/dev/sda6)
sudo gunzip -c /media/windows7-swap-100Mb-sda1.dd-image.gz | dd of=/dev/sda1 bs=8096

По аналогии (меняя только названия файлов-образов и имена разделов) восстанавливаем из образов оставшиеся разделы.

После того как мы все восстановили и перезагрузились - что же мы увидели?
в лучшем случае у нас сразу пошла грузиться ОС Windows7 (а где же загрузчик Ubuntu?) - в худшем нам вывалится сообщение от загрузчика Windows7 о том что он не может загрузиться так как не нашел какое-то там устройство с длиннющим кодом.
Что же делать?
Без паники.
Снова грузимся с компашки с ОС Ubuntu. Выбираем язык и жмем "Попробовать Ubuntu".
Открываем консоль терминала (Ctrl+Alt+T)
Смотрим название раздела с ОС Ubuntu.
sudo fdisk -l

Если вспомним как мы разбивали разделы с помощью Gparted то у меня это раздел /dev/sda6
Монтируем его в /media
sudo mount /dev/sda6 /media
Монтируем системные папки /dev, /sys, /proc в раздел (как бы подменяем их временно)
sudo mount --bind /dev /media/dev
sudo mount --bind /proc /media/proc
sudo mount --bind /sys  /media/sys

переходим в chroot
sudo chroot /media

Устанавливаем GRUB командой
grub-install /dev/sda

Если все прошло хорошо выходим из chroot
exit

и отмонтируем разделы
sudo umount /media/dev
sudo umount /media/proc
sudo umount /media/sys


Перезагружаемся. После перезагрузки - мы сразу попадем в Ubuntu загруженной уже с винчестера (теперь мы не видим Windows7 что за черт). Вызываем консоль терминала (Ctrl+Alt+T) и обновляем загрузчик grub.
sudo update-grub


Теперь после перезагрузки мы увидим обе системы - но Windows7 попрежнему не грузится если ее выбрать из списка ОС. Осталось всего ничего.
Грузимся с установочной DVD Windows7. Выбираем язык. Выбираем тип устанавливаемой ОС (x86, x64).
Появится экран с большой кнопкой "Установить" - посмотрите вниз. В левом углу есть надпись "Восстановление системы". Это то, что нам нужно. После ее нажатия Windows сама определит раздел на который она установлена и поправит свой загрузчик так чтобы он указывал на него. При этом не затронет загрузчик Ubuntu.

Вот и все. Теперь можно работать в любой из этих ОС с одного винчестера.

P.S Важное дополнение: после восстановления образа Ubuntu на раздел большего размера чем раздел в образе для того чтобы использовался ВЕСь объем раздела необходимо использовать утилиту resize2fs
p1nokk1o, p!nokk!o, pinokkio

Подсчет трафика офиса своими руками. Часть I.

Возникла интересная задача. По месту работы контора разделена на несколько малых офисов. Каждый из которых состоит из внутренней "серой" сети сидящей за 1 "белым" IP-адресом. Все "белые" адреса закреплены у провайдера за главным офисом. Периодически тот или иной офис накачивает трафику так, что не балуй - а провайдер выставляет счет естественно на главную контору и дает в расшифровке потребление трафика по каждому "белому" IP-адресу малых офисов. Возникла идея - подсчитывать потребление трафика для каждого IP-адреса "серых" подсетей малых офисов - отправлять все это на шлюз главного офиса и на нем же выводить статистику потребления, а также выдавать инструкции шлюзам малых офисов о блокировании доступа в интернет для тех IP-адресов внутренных "серых" сетей кто исчерпал свою квоту.

Пересмотрел кучу разных самопальных систем подсчета трафика. У всех есть разные недостатки не позволяющие применить их для моей задачи. Решил написать свое. Итак часть первая. :)

Все шлюзы у меня работают на FreeBSD. На каждом из них выполняем все нижеперечисленное. Для подсчета трафика используем ng_ipacct из портов

admin@gateway>> cd /usr/ports/net_mgmt/ng_ipacct/
admin@gateway>> make install clean

После установки не забываем делать "rehash".

Добавляем в "/etc/rc.conf" строчку:
ng_ipacct_enable="YES"

Копируем "ng_ipacct.conf.sample" в "ng_ipacct.conf"
cp /usr/local/etc/ng_ipacct.conf.sample /usr/local/etc/ng_ipacct.conf

Правим "ng_ipacct.conf"
Разкомментариваем строчку 
ng_ipacct_enable="YES"

Разкомментариваем строчку и прописываем свои интерфейс ( в моем случае это rl0 (внешний) и rl1 (внутренний) )
ng_ipacct_interfaces="rl0 rl1"

Правим строчку
ng_ipacct_modules_list="ng_netgraph ng_tee ng_ether ng_ipacct"
убираем ng_netgraph

Копируем строчки начинающиеся на "ng_ipacct_xl0_" в самый низ "ng_ipacct.conf".
Заменяем в них "xl0" на "rl0".
Копируем еще раз.
Заменяем в них "xl0" на "rl1".

В скопированных строчках комментируем строчки заканчивающиеся на
"..checkpoint_script" и "..afterstart_script"

Также убедитесь что в скопированных строчках - строки заканчивающиеся на
".._start=" и ".._stop=" содержат "default_ether", а не "bpf_ether"

Теперь у нас будет собираться статистика по внутреннему и внешнему интерфейсу. Если внешний вам не нужен - уберите его.

Создаем папку в которой у нас будут храниться логи "ng_ipacct" о том кто куда ходил и сколько скачал. А также наши скрипты. У меня все это храниться в "/usr/local/etc/traffic/"

mkdir /usr/local/etc/traffic
mkdir /usr/local/etc/traffic/bin
mkdir /usr/local/etc/traffic/log

Создаем скрипты. Сохраняем их в "/usr/local/etc/traffic/bin/".

Первый скрипт снимает данные с интерфейсов и сохраняет их в лог-файл вида IP-YYYY-MM-DD.iface.log

Например в моем случае это будет "10-15-86-234-2009-03-10.rl0.log" и "10-15-86-234-2009-03-10.rl1.log

ipacct.sh:

#!/bin/sh
# Written by p1nokk1o@livejournal.com
# Log File name format
# YYYY-MM-DD

IPACCTCTL="/usr/local/sbin/ipacctctl"
INTERFACES="rl1 rl0"
DIR=/usr/local/etc/traffic/log
MYIP="10-15-86-234"
NAME=`date -v-9M "+%Y-%m-%d"`
for IFACE in $INTERFACES; do
$IPACCTCTL ${IFACE}_ip_acct:$IFACE checkpoint
$IPACCTCTL ${IFACE}_ip_acct:$IFACE show >> $DIR/$MYIP-$NAME.$IFACE
$IPACCTCTL ${IFACE}_ip_acct:$IFACE clear
done

/usr/bin/tail -1 $DIR/$MYIP-$NAME.$IFACE | /usr/bin/fgrep exceed

Второй скрипт будет архивировать данные за прошедший день для уменьшения занимаемого ими места и переносить их в подпапку "archive". А также автоматически удалять файлы созданные более чем за 180 дней назад.

compress.sh:
#!/bin/sh
# Written by p1nokk1o@livejournal.com 
# compress traffic log file of previous day

# Log File name format
# YYYY-MM-DD
DIR=/usr/local/etc/traffic/log
MYIP="10-15-86-234"
NAME=`date -v-1d "+%Y-%m-%d"`
INTERFACES="rl0 rl1"
EXPIRE=180

files=`ls $DIR`
for IFACE in $INTERFACES; do
 for file in $files; do
   if test $file = $MYIP-$NAME.$IFACE
    then
     nice /usr/bin/gzip $DIR/$file && mv $DIR/$file.gz $DIR/archive/$file.gz
     break
   fi
 done
done
# delete expire logs (older than $expire days)
find $DIR/archive -mtime +$EXPIRE -mindepth 1 -delete

Не забываем сделать оба скрипта - исполняемыми - "chmod +x".

Также напишем маленький скрипт вся задача которого архивировать лог-файлы и закачивать их на ftp-сервер головного офиса.

upload.sh:
#!/bin/sh
# Written by p1nokk1o@livejournal.com
# compress traffic log file and upload to ftp-server

# Log File name format
# YYYY-MM-DD
DIR=/usr/local/etc/traffic/log
NAME=`date -v-9M "+%Y-%m-%d"`
MYIP="10-15-86-234"
FTPUSER="пользователь_ftp_сервера"
FTPPSWD="пароль_пользователя_ftp_сервера"
FTPHOST="IP-адрес или хост ftp-Сервера"
INTERFACES="rl0 rl1"

files=`ls $DIR`
for IFACE in $INTERFACES; do
 for file in $files; do
   if test $file = $MYIP-$NAME.$IFACE
    then
     nice /bin/cp $DIR/$file /tmp/$file >/dev/null
     nice /usr/bin/gzip -q /tmp/$file >/dev/null
     nice /usr/bin/ftp -u -e ftp://$FTPUSER:$FTPPSWD@$FTPHOST/incoming/traffic/$file.gz /tmp/$file.gz
     nice rm /tmp/$file.gz
     break
   fi
 done
done

Не забываем сделать скрипт исполняемым - "chmod +x".

На шлюзе головного офиса создадим еще один скрипт - его задача разархивировать закачанные из малых офисов на ftp log-файлы и перенести их в общее место хранения - "/usr/local/etc/traffic/log/".

movelog.sh
#!/bin/sh
# Written by p1nokk1o@livejournal.com
# decompress traffic log file transferred via ftp
# and move it to storage folder

# Log File name format
# YYYY-MM-DD
STRDIR=/usr/local/etc/traffic/log
FTPDIR=/usr/local/ftp/incoming/traffic
NAME=`date -v-9M "+%Y-%m-%d"`

#Decompress files
files=`ls $FTPDIR | grep $NAME`
for file in $files; do
 nice /usr/bin/gzip -d -q $FTPDIR/$file
done

#Remove existing decompressed files in storage folder and move transferred files
files=`ls $FTPDIR | grep $NAME`
for file in $files; do
 if [ -f $STRDIR/$file ]
  then
  nice rm -f $STRDIR/$file
 fi
 mv $FTPDIR/$file $STRDIR/$file
done

Проверяем:
admin@gateway:/usr/local/etc/rc.d/>> ng_ipacct.sh start
admin@gateway:/usr/local/etc/traffic/bin/>> compress.sh

Если после запуска "compress.sh" видим примерно следующее:
ipacctctl: ip_account_ctl: NgSendMsg: No such file or directory
ipacctctl: Cann't get version number from node

Внимательно проверяем "ng_ipacct.conf" - строчки:
#Тут укажите ваши интерфейсы и убедитесь что строчка не закомментарена
ng_ipacct_interfaces="rl0 rl1"

#Убедитесь что указаны нижеперечисленные модули для загрузки и строчка не закомментарена
ng_ipacct_modules_list="ng_tee ng_ether ng_ipacct"

Также убедитесь что - строки заканчивающиеся на
"..ваш_интерфейс_start=" и "..ваш_интерфейс_stop=" содержат "default_ether", а не "bpf_ether"

Убедитесь что ядро собрано с опцией "options NETGRAPH" - если это не так пересоберите ядро с данной опцией.

Если все нормально - то в папке "/usr/local/etc/traffic/log" появятся НЕпустые файлы, примерно вот такого содержания:
172.16.0.2      1520    88.212.196.77   80      6       3       144     -1
172.16.0.3      1250    195.93.186.193  80      6       2       682     -1
172.16.0.254    3008    94.100.177.6    110     6       8       372     -1

Пропишем частоту вызова скриптов в crontab.
vi /etc/crontab

Каждые 10 минут скидываем статистику в log-файлы
*/10    *       *       *       *       root    /usr/local/etc/traffic/bin/ipacct.sh

Каждые 12 минут (дадим 2 минуты предыдущему скрипту на сброс статистики в log-файлы) закачиваем архивированные log-файлы на ftp-cервер головного офиса
*/12    *       *       *       *       root    /usr/local/etc/traffic/bin/upload.sh

В 00:10 каждого дня архивируем логи за прошедший день
10      0       *       *       *       root    /usr/local/etc/traffic/bin/compress.sh

На шлюзе головного офиса пропишем в crontab вызов "movelog.sh"
*/15      0       *       *       *       root    /usr/local/etc/traffic/bin/movelog.sh

Самое главное, для того чтобы не путать пользователей разных офисов при подсчете статистики - задайте подсетям офисов разные диапазоны ip-адресов.

Например:
для головного офиса - 172.16.0.0/24
для офиса №1 - 172.16.1.0/24
для офиса №2 - 172.16.2.0/24
и тд.

На этом первую часть и закончим. Во второй части создадим БД на основе mySQL в которой будем хранить статистику. Напишем perl- и php-скрипты для парсинга log-файлов и сохранения полученных данных в БД.
p1nokk1o, p!nokk!o, pinokkio

Система "Город". Накипевшее...

Случилось.. нет не чудо.. мудо? да так более правильно... в силу обстоятельств пришлось ставить на кассах, по месту работы, систему "Город" от ЦФТ. В связи с чем хотелось бы поделиться впечатлениями и предостережениями.

Первое. У вас мало проблем? Сидите плюете в потолок от безделья? Тогда процесс установки, настройки и дальнейшего сопровождения системы "Город" - вам в руки. Поимеете "счастья" по самое нехочу. Начнем с процесса установки. Сам процесс подписывания документов и получения сертификатов - отдельная эпопея. Как минимум в 3 томах. Ладно. Приехали ко мне наконец-то аппаратики для записи магнитных карт. Вызвали ребят которые будут собственно устанавливать сами аппаратики и их настраивать. День на третий наконец-то удалось состыковаться и все-таки привезти аппараты на кассы. Сами ребята-железячники оказались на редкость приятными и обязательными людьми - все последующие проблемы по их части решались довольно оперативно. А вот программная часть системы "Город" и люди ее обслуживающие... Тут Вас постигнет первое разочарование - контора хоть и называется одним именем - "Центр Финансовых Технологий" на самом деле - куча мелких отделов которые напрочь отказываются взаимодействовать сами с собой внутри собственной конторы. Т.е - если вы позвоните железячникам - опишите проблему - а они решат что это проблема программная - вас пошлют... правильно - в отдел занимающийся программной частью системы "Город"... думаете все? фигушки! если там в свою очередь решат что на самом деле проблема все же таки по "железной" части - вас пошлют... да-да назад в отдел железячников... на каком витке перепинываний туда-сюда вам надоест - зависит от крепости ваших нервов. Сами же внутри себя созваниваться и решать Вашу проблему они не будут.

Второе. Приготовьтесь к тому, что настраивать программную часть системы "Город" Вам придется самому по файлам с инструкциями от ЦФТ. О том чтобы сотрудники ЦФТ приехали к вам и все настроили в одном как говориться флаконе - можете смело забыть. Вот так вот они ведут "бизнес" - "боряться" за клиента... Далее - приготовьте компьютер с "белым" IP-адресом и (!) ОС WIndows!. В этом месте администраторы я думаю уже хихикают. "Дырявая" винда глядящая напрямую в интернет. Издержки системы "Город"... Дело в том что им нужен Ваш IP-адрес для того, чтобы прописать у себя в firewall доступ с него на свои терминальные сервера и (!) для прямого коннекта с вашим компьютером для обратной связи и так для каждого компьютера где будет стоять аппарат и программная часть от "Города". Т.е если у вас стоит шлюзом Unix-like ОС вам придется настраивать port-redirect.

Третье. Требуйте сразу чтобы у вас для печати на вашем принтере из программы системы "Город" был установлен драйвер прямой печати на локальный принтер. А не через spool. Иначе готовьтесь к тому, что переодически у вас будет отваливаться принтер и квитанции на него выдаваться не будут. Решается это только прописыванием dll (присылаемой ЦФТ отдельно после долгих мучительных поисков проблемы) в реестре локального компьютера после чего подключенная через RDP программа-клиент от ЦФТ начнет выдавать на печать минуя spool.

Четвертое. Подключайте аппарат для записи магнитных карт только на встроенный COM-порт материнской платы. Если вы подключите его через переходник USB-to-COM готовьтесь к тому что переодически система "Город" будет выдавать Вам сообщение "1000, не найден COMxxx (-1)". На все Ваши звонки в СТП системы "Город" Вас будут настойчиво убеждать что дурак собственно именно Вы ,а не у них глючная программа и что у других точно также как у Вас все подключено и все прекрасно работает.

Пятое. Готовьтесь сразу к отратительному качеству обслуживания СТП системы "Город". Чтобы потом не расстраиваться лишний раз. Вас будут пинать от отдела к отделу. Перекидывать на других сотрудников которые не в курсе Вашей проблемы и Вам придется заново каждый раз объяснять им одно и тоже.  Готовьтесь к тому что с 13 до 14 СТП будет не доступен - ибо все кто в курсе ваших проблем - ушли на обед.

Это только самые яркие впечатления от работы с системой "Город". Напоследок еще один совет - даже не предлагайте им "возьмите по человеку от отдела отвечающего за ПО и отдела отвечающего за железо, приедьте ко мне - проведите тут какое-то время и разберитесь наконец почему Ваша система неработает". Если "железячники" еще и могут согласиться, то ответ отдела отвечающего за ПО Вас "приятно" удивит - "МЫ НЕ ВЫЕЗЖАЕМ".

Вот так. И похрен им на то, что часть их з/п формируется в том числе и из ваших процентных отчислений за принятые по их системе платежи. "Их величества не выезжают"...

Вы все еще желаете поставить систему "Город"? Купите вашему админу - валидола...
p1nokk1o, p!nokk!o, pinokkio

FreeBSD+Firebird. Танцы с бубном.

Недавно встала передо мной задача установки СУБД Firebird на FreeBSD 6.2
Думалось мне, что дело это тривиальное - порты они и в Африке порты. Однако пару выкрутасов все же пришлось сделать.
Делюсь, так как информации по данной теме в рунете на удивление мало учитывая довольно большую популярность данной СУБД на просторах необъятной Родины.

Перво-наперво. Создаем пользователя и группу "firebird" - без домашнего каталога и шелла. Из-под него в дальнейшем и будет запускаться Firebird.

Далее - в портах на время установки сделайте данного пользователя владельцем каталогов
"/usr/ports/databases/firebird20-client" и
"/usr/ports/databases/firebird20-server".

Дело в том, что по ходу установки инсталлятор вывалиться с сообщением о том, что дальнейшую установку нужно продолжить из-под пользователя не имеющего рутовских прав. Тут-то вы через "sudo" или "su" зайдете под созданным ранее пользователем "firebird" и из-под него продолжите установку. Спустя какое-то время инсталлятор снова вывалиться, но уже с требованием рутовских прав.

Установив Firebird убедитесь что у вас разрешен к запуску inetd (многие администраторы отрубают его как небезапасный) - либо установите xinetd. Через них Firebird будет запускаться как сервис. Перезапустите inetd (killall -1 inetd) или xinetd. И проверьте что порт 3050 у вас слушается.

Верните права руту на каталоги
"/usr/ports/databases/firebird20-client" и
"/usr/ports/databases/firebird20-server"

Напоследок предложу вам UDF-ку для Firebird со множеством "вкусных" функций - rfunc





p1nokk1o, p!nokk!o, pinokkio

PHP. Создание простейшего шаблонизатора

Любой веб-программист рано или поздно сталкивается с проблемой шаблонов. Столкнулся с этим и я когда заказчик пожелал, чтобы на его сайте изменялся дизайн в зависимости от времени года - летний, осенний, зимний, весенний. Дизайн был простенький, как и программная часть движка - поэтому такие "монстры"-шаблонизаторы как Smarty тут вряд ли имели смысл. Пришлось взяться за написание простенького шаблонизатора.
За основу возьмем идею того же Smarty - заключенные в наши теги куски кода мы преобразуем в php-код и полученный файл через include подключаем к основному файлу.

Пример:


<!-- for ( %i = 0; %i < count( %genresList ); %i++ ) -->
  <!-- if ( %genresList[%i]->flm_cnt > 0 ) -->
           <tr height="10"><td colspan="5"></td></tr>
           <tr>
            <td width="5"></td>
            <td width="13"><img src="/images/arrow.gif" width="7" height="7" alt="" border="0"></td>
            <td><a class="mlink" href="/search/genre/<!-- print %name_en -->/"><!-- print %genresList[%i]->name --></a></td>
            <td width="30"><span class="smallredtext"><!-- print %newflm_cnt -->&nbsp;</span></td>
            <td width="30"><span class="smallgraytext">[<!-- print %flm_cnt -->]&nbsp;</span></td>
           </tr>
   <!-- /endif -->
<!-- /endfor -->

Все переменные заменяем с $ на % - весь код заключаем в теги <!-- -->, echo меняем на print, для if и for обязательно должны быть закрывающие - /enif и /endfor - вот вроде и все - вроде как собственный мини-язык :)

Класс для парсинга шаблонов (php5):



<?php
 /**
  * templates.cls.php
  * Содержит классы для работы с шаблонами
  * @package zEngine
  * @author p1nokk1o
  * @version 1.1, 22.01.2009
  * @since engine v.1.0
  * @copyright (c) 2008+ by p1nokk1o@livejournal.com
 */

 /**
  * TTemplatesClass
  * Класс для работы с шаблонами
 */
 class TTemplatesClass
 {
  private $classname;
  private $filename;
  private $content;
  private $assigns;

  /**
   * public __construct
   * Конструктор класса
  */  
  public function __construct()
  {
   $this->filename  = "";
   $this->content   = "";
  }
  /**
   * public setTemplate
   * Функция установки файла для парсинга
   * @param string $filename Файл-шаблон
   * @return boolean
  */  
  public function setTemplate( $filename )
  {
   $result = false;
   if ( file_exists ( $filename ) )
   {
    $this->filename = $filename;
    $tmp = @file( $filename );
    if ( is_array( $tmp ) && count( $tmp ) > 0 )
    {
     $this->content = implode("", $tmp);
     $this->parse();
     $result = true;
    }
   }
   return $result;
  }

  /**
   * public assign
   * Функция назначения ключу значения
   * @return boolean
  */  
  public function assign( $key, $value )
  {
   $this->assigns[$key] = $value;
   return true;
  }

  /**
   * private parse
   * Парсинг
   * @return boolean
  */  
  private function parse()
  {
   $result = false;
   if ( $this->content != "" )
   {

    preg_match_all( "/<!--(.*)-->/i", $this->content, $tmpArray );
    for ( $i = 0; $i < count( $tmpArray[1] ); $i++ )
    {
     $line = strtolower(trim( $tmpArray[1][$i] ));
     //<!-- print %title -->
     if ( substr($line,0,6) == "print ")
     {
      $tmp = $tmpArray[0][$i];
      $tmp = str_replace("<!--","<?php ",$tmp);
      $tmp = str_replace("-->","; ?>",$tmp);
      $tmp = str_replace("%","$",$tmp);
      $tmp = str_replace("print ","echo ",$tmp);
      $this->content = str_replace($tmpArray[0][$i],$tmp,$this->content);
     }
     //<!-- if , for -->
     if ( substr($line,0,3) == "if " || substr($line,0,4) == "for ")
     {
      $tmp = $tmpArray[0][$i];
      $tmp = str_replace("<!--","<?php ",$tmp);
      $tmp = str_replace("-->"," { ?>",$tmp);
      $tmp = str_replace("%","$",$tmp);
      $this->content = str_replace($tmpArray[0][$i],$tmp,$this->content);
     }
     //<!-- /endif, /endfor --> тупо меняем на }
     if ( substr($line,0,6) == "/endif" || substr($line,0,7) == "/endfor" )
     {
      $tmp = $tmpArray[0][$i];
      $tmp = str_replace("<!--","<?php ",$tmp);      
      $tmp = str_replace("-->","} ?>",$tmp);
      $tmp = str_replace("/endif","",$tmp);
      $tmp = str_replace("/endfor","",$tmp);
      $this->content = str_replace($tmpArray[0][$i],$tmp,$this->content);
     }
  
    }
    $result = true;
   }
   return $result;
  }

  /**
   * public output
   * Функция вывода страницы
   * @return boolean
  */  
  public function output( )
  {
   $result = false;
   if ( is_array( $this->assigns ) && count( $this->assigns ) > 0 )
   {
    $keys = array_keys( $this->assigns );
    for ( $i = 0; $i < count( $keys ); $i++ )
    {
     $$keys[$i]= $this->assigns[$keys[$i]];
    }
   }
   //В папке cache в корне сайта создаем временный айл который потом инклудим
   $fp = @fopen("cache/".session_id().".tmp","w");
   if ( $fp )
   {
    @fputs( $fp, $this->content );
    @fclose($fp);
    @include("cache/".session_id().".tmp");
    @unlink("cache/".session_id().".tmp");
    $result = true;
   }
   return $result;
  }


  /**
   * public __destruct
   * Деструктор класса
  */  
  public function __destruct() 
  { 
  }
 }
?>


Пример использования:




<?php
  session_start();
  include("templates.cls.php");
  $TEMPLATES = new TTemplatesClass();
  $TEMPLATES->setTemplate( "templates/index.html");
  $TEMPLATES->assign( "title", htmlspecialchars($OPTIONS->siteOptions->title) );
  $TEMPLATES->assign( "charset", htmlspecialchars($OPTIONS->siteOptions->charset) );
  $TEMPLATES->assign( "description", htmlspecialchars($OPTIONS->siteOptions->description) );
  $TEMPLATES->assign( "keywords", htmlspecialchars($OPTIONS->siteOptions->keywords) );
  $TEMPLATES->assign( "robots", htmlspecialchars($OPTIONS->siteOptions->robots) );
  $TEMPLATES->assign( "language", htmlspecialchars($OPTIONS->siteOptions->content_language) );
  $TEMPLATES->assign( "revisit", htmlspecialchars($OPTIONS->siteOptions->revisit) );
  $TEMPLATES->assign( "webmasteremail", htmlspecialchars($OPTIONS->siteOptions->webmasterEmail) );
  $TEMPLATES->output();
?>

p1nokk1o, p!nokk!o, pinokkio

Попингуйка.

- Слушай, попингуй, а?
- От попингуя слышу!

народный фольклор


Недавно при администрировании одного из серверов под FreeBSD возникла интересная проблема - время от времени пинг между этим сервером и сервером БД дико подскакивал на несколько минут затем приходил в норму. С учетом того, что оба сервера находились во внутренней сети одного провайдера пинги обычно не превышали 1-2мс. Проверки обоих серверов показали их непричастность. Значит в некий момент времени кто-то из других пользователей провайдера производил некие действия приводящие к этому или же какое-то оборудование провайдера давало сбой. Для выяснения причины нужно было отловить такой момент повышения пинга и проанализировать загрузку оборудования или же его сбой. Руками отловить такие моменты было нереально. Пришлось сесть и написать на Perl-е скрипт пингующий сервер БД и в случае превышения некоего порога извещающего бы меня об этом по почте. Вспомнив старый прикол - назвал скриптик "Попингуйка" :)
Вот делюсь - может кому поможет.





#!/usr/bin/perl
###################################
# LOW PING & HOST DOWN REMINDER #
# Written by p1nokk1o #
# http://p1nokk1o.livejournal.com #
###################################

#IP-адрес сервера который мы пингуем
$ipaddr = "10.180.10.200";
#Период в секундах в течении которого мы один раз отсылаем письмо (например раз в час)
#чтобы не завалить самого себя письмами с интервалом в 1 сек :)
#Меньше чем раз в 10 минут - ставить не рекомендую :)
$sent_period = 600;
#Кол-во неудачных попыток после которых будет отправлено письмо
#Т.е может быть ситуация Host is down а через 10 сек он поднялся
#Чтобы уж зазря не паниковать - ставим некое кол-во срабатываний
#Например если Host is down повторяется 100 раз - значит легло хорошо :)
$max_down_count = 10;
#Тоже самое для проверки пинга
$max_ping_count = 10;
#Максимальный допустимый пинг ms
$max_ping = 10;
#Полный путь до sendmail
$sendmail = "/usr/sbin/sendmail";
#Кому отправлять почту
$mailto = "root\@localhost";
#От кого отправлять почту
$mailfrom = "root\@localhost";
#Временный счетчик сообщений "Host is down"
$tmp_down_count = 0;
#Временный счетчик превышения пинга
$tmp_ping_count = 0;
#Дата и время когда мы последний раз отправляли письмо
#Изначально нуль :)
$sent_at = 0;
#Массив куда мы запоминаем последние хреновые пинги :)
@ping_stat;

#Подпрограмма получения текущей даты и времени
sub get_datetime
{
my @monthsnames = ("jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec");
my ($gsec,$gmin,$ghour,$gmday,$gmon,$gyear,$gwday,$gyday,$gisdst) = localtime(time);
$gyear += 1900;
if ( length($gmday) < 2 ) { $gmday = "0".$gmday; }
if ( length($ghour) < 2 ) { $ghour = "0".$ghour; }
if ( length($gmin) < 2 ) { $gmin = "0".$gmin; }
if ( length($gsec) < 2 ) { $gsec = "0".$gsec; }
return $gmday." ".@monthsnames[$gmon]." ".$gyear." ".$ghour.":".$gmin.":".$gsec;
}

#Подпрограмма отправки мыла
sub send_email( )
{
open (MAIL, "|".$sendmail." -t");# or die "sendmail not ready";
print MAIL "From: <".$mailfrom.">\n";
print MAIL "To: <".$mailto.">\n";
print MAIL "Reply-To: <".$mailto.">\n";
print MAIL "Subject: ".$_[0]."\n\n";
print MAIL $_[1];
close (MAIL);# or warn "sendmail didn`t close nicely";
return;
}

################ ГЛАВНОЕ ТЕЛО ПРОГРАММЫ ######################
open(PING,"ping ".$ipaddr." 2>&1 |");
while ( )
{
$line = $_;
#Проверяем - если нет связи до сервера...
if ($line=~/Host is down$/)
{
#...и с того времени когда мы последний раз отправляли об этом письмо
#прошло указанное нами время
if ( (time - $sent_at) > $sent_period )
{
#Увеличиваем счетчик найденных сообщений "Host is down"
$tmp_down_count++;
#Если счетчик превысил макс. кол-во - значит сервер лег надежно :)
#С прискорбием сообщаем себе об этом :)
if ( $tmp_down_count >= $max_down_count )
{
#Шлем письмо
&send_email("Host ".$ipaddr." is down", "Attention!\n\n".&get_datetime()." host ".$ipaddr." is not response after ".$down_count." times.");
#Запоминаем время когда мы отослали себе письмо
$sent_at = time;
$tmp_down_count = 0;
}
}
}
else
{
#Т.к сервер откликается на пинги - обнуляем счетчик сообщений Host is down
$tmp_down_count = 0;
#Проверяем пинг до сервера
if ($line=~/(\d+) bytes from (\d+\.\d+\.\d+\.\d+)\: icmp_seq=(\d+) ttl=(\d+) time=(\S+)/)
{
#Строка вида - 64 bytes from x.x.x.x: icmp_seq=0 ttl=22 time=1.242 ms
#парситься в 5 переменных где
#$1 - кол-во байт отправлено (64)
#$2 - ip (x.x.x.x)
#$3 - icmp_seq (0)
#$4 - ttl (22)
#$5 - время отклика (то что нас и интересует) (1.242)
#Если время отклика больше дозволенного...
if ( $5 > $max_ping )
{
#...и с того времени когда мы последний раз отправляли об этом письмо
#прошло указанное нами время
if ( (time - $sent_at) > $sent_period )
{
#Увеличиваем счетчик
$tmp_ping_count++;
#Помещаем в массив статистики пинга новую запись
push @ping_stat, &get_datetime()."> ".$line;
#Если счетчик превысил макс. кол-во - значит пинг действительно хреновый :)
#С прискорбием сообщаем себе об этом :)
if ( $tmp_ping_count >= $max_ping_count )
{
#Шлем письмо
my $body = "";
foreach my $tmp_line(@ping_stat)
{
$body.= $tmp_line;
}
&send_email("Too bad latency to ".$ipaddr, "Ping statistics:\n\n".$body);
#Запоминаем время когда мы отослали себе письмо
$sent_at = time;
$tmp_ping_count = 0;
$#ping_stat =0;
}
}
}
else
{
#Т.к время пинга нормальное обнуляем счетчик
$tmp_ping_count = 0;
#И задно массив
$#ping_stat =0;
}
}
}
}
close(PING);
exit(0);
p1nokk1o, p!nokk!o, pinokkio

PHP. Создание виртуальных URL

В свое время как и многие начинающие php-программисты написал кучу своих "движков" большинство из которых навигацию по сайту представляли в виде blablabla.php?aa=...&bbb=...&ccc=. До поры, до времени это устраивало и меня (в силу нехватки знаний и умений на что-то большее) и заказчиков. Пока наконец не попался заказчик подкованнее всех остальных в сфере веб-индексирования. Прозвучало вполне закономерное требование - "сайт должен индексироваться с Человеко-Понятными-Урлами". Согласно ТЗ страниц и подстраниц в сайте было довольно не мало - плюс перспектива создания новых да еще со своими URL-ами - тупым созданием папок/подпапок со своим скриптом внутри тут явно не обойдешься. Встал вопрос о виртуальных URL... Деньги были хорошими, сроки не сильно сжатые - пришлось разбираться как же сие чудо делается.

Для начала выяснил, что все сие чудо делается с помощью нескольких директив файла .htaccess с прикрученным к Apache - mod_rewrite. Радостно потирая руки пошел звонить хостеру в надежде, что данный модуль у него точно не стоит. Хостер вежливо возмутился за кого я его держу - все порядочные хостеры такую вещь давным-давно прикрутили. Пришлось извиниться и снова садиться за работу.

На мое удивление работа с .htaccess + mod_rewrite оказалась не такой уж и сложной. Вот весь его код для моих нужд:

Options -Indexes -Multiviews FollowSymLinks
Order allow,deny
Allow from all
//Запрещаем попытки индексирования .ini, .cfg файлов т.к они у меня лежат в корне сайта и хранят настройки доступа к СУБД mySQL
IndexIgnore *.ini *.cfg
//Включаем mod_rewrite
RewriteEngine   on
//На нижеследующие папки от корня сайт mod_rewrite не действует т.е отправляет запрос пользователя как есть прямо в папку
//Админка
RewriteCond    %{REQUEST_URI}        !^/admin
//Стили
RewriteCond    %{REQUEST_URI}        !^/styles
//JavaScripts
RewriteCond    %{REQUEST_URI}        !^/scripts
//Картинки
RewriteCond    %{REQUEST_URI}        !^/images
//Файла (архивы там и прочее)
RewriteCond    %{REQUEST_URI}        !^/files
//Все остальное куда бы пользователь не полез - перенаправляется на наш файл redirect.php
RewriteRule     ^(.*)$            redirect.php [PT]
//Запрещаем доступ к файлам .ini и .cfg
<Files ~ "\.ini$">
 Order allow,deny
 Deny from all
 Satisfy All
</Files>
<Files ~ "\.cfg$">
 Order allow,deny
 Deny from all
 Satisfy All
</Files>


Заточить его под свои нужды думаю легко сможет любой.
Ах, да.. Как поймать URL по которому пошел пользователь непосредственно в php-скрипте? Довольно просто:
<?php
  $fullURL = parse_url($_SERVER["REQUEST_URI"]);
?>


Дальше уже все просто - по URL получаете либо текст странички которая с ним связана - либо ничего, тогда это  404 Page Not Found
:)