The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Perl" / Оглавление документа

pop before smtp для popa3d(другие демоны pop-аутентификации можно дописать, о чем здесь ниже)

Когда конфигурируют sendmail, в файле /etc/mail/access содержатся правила для доставки почты, смысл которых заключается в том, что можно отправлять почту только с определенных айпиадресов, прописанных в файле /etc/mail/access. Что не очень удобно, если обладатель почтового ящика довольно часто перемещается по миру и из-за этих правил не может отправлять почту через свой адрес. Для преодоления данной трудности существуют два патча: SMTP AUTH и pop before smtp. Ни одну из них поставить не удалось, и пришлось поступить следующим образом: идем на сайт pop before smtp for Postfix, скачиваем тамошний модуль, распаковываем его и находим в распакованном файл popa3d-0.4.patch(там и для других демонов батчи есть, см. README). Согласно написанному правим сишные исходники демона popa3d, компилируем демон, получаем бинарник и перезаписываем его в /usr/sbin/popa3d. В результате в логах при pop3-аутентификации добавляется ip-адрес снявшего почту. Итого имеем имя и адрес снимающего почту. Дальше нужно написать некую программу, которая умеет смотреть, что добавляется в лог-файл, извлекать оттуда имя и ip-адрес и запысывать ip в /etc/mail/access:

#!/usr/bin/perl -wT

use strict;
use File::Tail;
use Fcntl ':flock';
use Date::Parse;

my $l = '/var/log/messages'; #путь до логфайла
my $file="/etc/mail/access"; #путь до файла с relay'ями на ip
my (@q, $fi, $ip);
my $relay = 60;#время открытого релея после popa3d-аутентификации для ip, снявшего почту

&tail(); 

while (1){
    m&^(.*\d+:\d+:\d+).*\[(.*?)\]$& if $_=$fi->read; #get ip and name
    my $time = str2time($1) + $relay or next; $ip=$2; #таймер
    next if $time < time;  
    open A, ">>$file" or die "can't open: $!";    flock A, 2;
    print "\tВремя для $ip пошло(всего $relay секунд), relay открыт\n";
    print A "$2\t\tRELAY\n"; 
    close A; &makemap(); #закрываем и делаем ребилд для /etc/mail/access.db
    push @q, $time; 
    while(1){
     do{ my @file;
       open B, "<$file" or die "can't open: $!";  flock B, 1;
       do{ push @file, $_ unless m%^$ip%} while (<B>); #не нужны ip, у которых кончилось время
       close B;
       print "\tВремя для $ip закончилось, relay закрыт\n"; 
       open C, ">$file" or die "can't open: $!"; 
       flock C, 1;
       print C join "" => grep{!m&^$ip(\t)\1+RELAY$&} @file;
       close C; &proverka();
       &makemap(); #закрываем и делаем ребилд для /etc/mail/access.db
       last
     } if $q[0] < time; sleep 1
    } $#q=-1;
}

sub makemap{qx[makemap hash /etc/mail/access</etc/mail/access]}

sub tail{ 
  return $fi = File::Tail->new(
    name => $l,
    maxinterval => 1,
    adjustafter => 1000000000,
    interval => 4,
    tail => 0)
}

sub proverka{
    open D, "<$file" or die "can't open: $!"; flock D, 1;
    my @debug=<D>; close D;
    open E, ">$file" or die "can't open: $!"; flock E, 1;
    print E join "" => grep{!m/Authentication passed/} @debug;
    close E;
}
Вобщем берется модуль File::Tail со спана и натравливается на логфайл. Соответственно по нему читаются маны и т.д. В чем прелесть, можно написать shell-script(взял из init-redhat-alex из pop before smtp для почтовика Postfix) и сделать приведенный скрипт демоном, который по добавлению в логфайл открывает на 30 секунд RELAY для того, кто перед этим снял почту, используя стандартные методы аутентификацииPOP3. можно релей открывать на 15 секунд... но, вобщем, вроде-бы защиту от спамеров оно гарантирует. Ниже методы проверки адреса на relay. Ну а на сервере, через который происходит отправка почты, выглядит это примерно так(результат отправки почты при помощи написанных на perl pop и smtp клиентов, см. ниже):
[root@tv pop-before-smtp-1.28]# /root/pop-before-smtp-1.28/contrib/init-redhat-alex start
Запуск pop-before-smtp:                                  [ OK ]
[root@tv pop-before-smtp-1.28]# 
	Время для 194.218.214.122 пошло(всего 60 секунд), relay открыт
	Время для 194.218.214.122 закончилось, relay закрыт.

Можно сделать так, чтобы эти сообщения писались в то-же /var/log/message. Программа очень нехитрая, написана на несложном языке, соответственно модификации для остальных видов демонов приветствуются.

Соответственно можно подправить sendmail.cf на предмет подсказки пользователю, что он должен сделать, чтобы отправить почту:

# check client name: first: did it resolve?
R$*		$: < $&{client_resolve} >
R<TEMP>		$#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
R<FORGED>	$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
R<FAIL>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed, please, get your mail for check relay" $&{client_name}
R$*             $: <?> $&{client_name}

Теперь пытаемся отправить почту из Нью-Йорка например через www.online.ru и получаем ответ(исходник smtp.pl см. ниже):
[root@www devel]# ./smtp.pl
SMTP RCPT command failed:
5.7.1 <user@last.my.server.ru>... Relaying denied. IP name lookup 
failed, please, get your mail for check relay[194.218.214.122]

 at ./smtp.pl line 18
[root@www devel]#

Логин телнетом на 25-й порт sendmail'а для открытого релея(при закрытом ругнется и напишет relaing denyed и разорвет соединение):

[root@tv /root]# telnet tv 25
Trying 212.142.230.135...
Connected to tv.server.ru (212.142.230.135).
Escape character is '^]'.
220 tv.server.ru ESMTP Sendmail 8.11.2/8.11.2; Sun, 24 Mar 2002 02:10:00 +0300
mail from:<test@tv.server.ru>
250 2.1.0 <test@tv.server.ru>... Sender ok
rcpt to:<user@last.my.server.ru>
250 2.1.5 <user@last.my.server.ru>... Recipient ok
data
354 Enter mail, end with "." on a line by itself
dfg
.
250 2.0.0 g2NNANt15274 Message accepted for delivery
Pop-3 клиент на perl:
#!/usr/bin/perl

use Net::POP3;

$p=Net::POP3->new("tv.server.ru")
  or die "cant open connection to server: $!\n";
$p->login("test","rusalka") or die "Cant  authentificate: $!\n";
$m=$p->list or die "cant get list of undeleted mesg: $!\n";
foreach $list(keys %$m){
$msg=$p -> get($list);
print "@$msg\n";
}
И smtp клиент:
#!/usr/bin/perl

$to = 'user@last.my.server.ru';
$from = 'test@tv.server.ru';

use MIME::Lite;

$msg = MIME::Lite->new(
        To       =>$to,
        From     =>$from,
        Subject  =>'Helloooooo, nurse!',
        Type    =>'multipart/mixed'
                        );
$msg->attach(Type     =>'text',
             Data     => qq{test}
            );
MIME::Lite->send('smtp', "tv.server.ru", Timeout=>60);
$msg->send;
Вобщем все, но лучше бы протестировать открывающий релей скрипт, потому, что мог допустить какую-то ошибку.



Закладки на сайте
Проследить за страницей
Created 1996-2019 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру

Hosting by Ihor