Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> FreeBSD —> WWW —> блокировка spam на www

скрипт блокировки спамеров на www средствами ipfw table и nginx

Автор: ProFTP.


email: q7u5@ukr.net



задача: закрыть спам на сайтах.

есть черный список (black list) ip на сайте http://www.stopforumspam.com/ (есть и другие списки), список часто обновляется. В blacklist входя прокси-сервера, взломанные машины через которые боты пытаються спамить на все www сразу...

проще всего добаавить в ipfw таблицу, после блокировки максимум 1 спам сообщение за несколько суток или за неделю.

ipfw table:
add deny ip from table(1) to any

ee /root/spamstop.pl
#!/usr/bin/perl

# use File::Pid;
# my $pidfile = File::Pid->new( { file => '/var/run/x0.pid', } );
# my $pid = $pidfile->running;
# die "Service already running: $pid\n" if $pid;
# $pidfile->write;
## можно раскомментировать, это для того чтобы скрипт
## одновременно повторно не запустился

use LWP::Simple;

my $spam = get("http://www.stopforumspam.com/downloads/bannedips.csv");

# system("ipfw table 1 flush > /dev/null &") if (defined $spam);


open( IP, "ipfw table 1 list |" );
$/ = '';    # Включить режим чтения абзацев
my $use_ip = <IP>;
close IP;

# IP которые уже присутствуют в таблице не удаляются
# а добавляются новые тех которых нету
my %seen;
@seen{ return_ip($spam) } = ();
delete @seen{ return_ip($use_ip) };

#print keys %seen;

foreach (keys %seen) {
 print $_;
	system("exec ipfw table 1 add ".$_ );
# system("exec ipfw table 1 add $_ > /dev/null &");

}

sub return_ip {
   # print $_[0];
   my $hash;
    $hash->{$1}++
      while $_[0] =~ /(\d+\.\d+\.\d+\.\d+)/smg xor 
         grep { $_ > 255 } split /\./,
        $1;
    return keys %$hash;

}

# $pidfile->remove;
## можно раскомментировать, это для того чтобы скрипт
## одновременно повторно не запустился

exit;

crontab:
8 0  *   *   *  root  /root/spamstop.pl

или запускать скрипт, через каждых 3 часа:
0 */3 * * * root  /root/spamstop.pl

можно при старте системы добавить этот скрипт в /usr/local/etc/rc.d/

скрипт выполняется не быстро, 4-10 минут, грузит процессор, можно попробовать вариант быстрого добавления в ipfw таблицу ЧСВ python биндинг для ipfw бацаю


ipfw -a list | grep table
00150   1317     65171 deny ip from table(1) to any

========
========
========

вариант помягче:
http://forum.lissyara.su/viewtopic.php?f=14&t=16531#p159781

теперь в фаерволле у меня правило:

    00530 fwd 127.0.0.1,8013 tcp from table(1) to me dst-port 80

а 127.0.0.1:8013 слушает nginx
(основной вебсервер апач на 80 порту, а nginx только для быстрого отлупа "форум-спамера")

вот конфиг nginx

    #user  nobody;
    worker_processes  1;
    #error_log  logs/error.log;
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;
    #pid        logs/nginx.pid;
    events {
        worker_connections  10;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
#log_format  main  '$remote_addr - $remote_user [$time_local] $request '
#                  '"$status" $body_bytes_sent "$http_referer" '
#                  '"$http_user_agent" "$http_x_forwarded_for"';
        #access_log  logs/access.log  main;
        sendfile        on;
        #tcp_nopush     on;
        #keepalive_timeout  0;
        keepalive_timeout  1;
        #gzip  on;
        server {
            listen       127.0.0.1:8013;
            server_name  localhost;
            #charset koi8-r;
            #access_log  logs/host.access.log  main;
            error_page  400 401 403 404 500 502 503 504 =200  /index.html;
            location / {
                root   /usr/local/www/nginx;
                index  index.html index.htm;
            }
        }
    }

а в index.html что-то типа этого

    <html>
    <head>
    <title>Welcome to zztop!</title>
    </head>
    <body bgcolor="white" text="black">
    <center><h1>You are seing this page, because you are in blacklist.
     </h1></center>
    <center><h2>Visit http://www.stopforumspam.com/ to check you IP,
          or contact me: email@was.here</h2></center>
    <center><h3>Best regards, St. Me.</h3></center>
    </body>
    </html>

Результат:
- nginx как "легкий" веб-сервер отлично и быстро отдает статику типа маленького html файлика, в котором написано что пользователь в стоп-листе
- если пользователь оказывается в стоп-листе, то он не тупо отфаерволивается, а редиректится на nginx, где его посылают, но красиво :)
- в апач запросы спамера не попадут вообще, т.е. он их не будет обрабатывать, и 1) нагружаться; 2) позволять роботам постить спам


######!!!!!!!!!!!!!!!!#########

UPD 2010.1.20


ссылка перестала работать http://www.stopforumspam.com/downloads/bannedips.csv

адсресс ссылки поменялся на http://www.stopforumspam.com/downloads/bannedips.zip, они список поставли в zip, не знаю зачем, но скрипт надо не много переделать:

#!/usr/bin/perl

# use File::Pid;
# my $pidfile = File::Pid->new( { file => '/var/run/x0.pid', } );
# my $pid = $pidfile->running;
# die "Service already running: $pid\n" if $pid;
# $pidfile->write;
## можно раскомментировать, это для того чтобы скрипт
## одновременно повторно не запустился

#my $spam = get("http://www.stopforumspam.com/downloads/bannedips.zip");

# system("ipfw table 1 flush > /dev/null &") if (defined $spam);

system("wget http://www.stopforumspam.com/downloads/bannedips.zip");

# use Archive::Zip;
# my $zip = Archive::Zip->new("bannedips.zip"); # Создаём объект
# $zip->extractTree(); # Разархивируем ZIP архив

system("/usr/local/bin/unzip bannedips.zip");

open( IPB, "bannedips.csv" );
$/ = '';    # Включить режим чтения абзацев
my $spam = <IPB>;
close IPB;

system("rm bannedips.csv");
system("rm bannedips.zip");

open( IP, "ipfw table 1 list |" );
$/ = '';    # Включить режим чтения абзацев
my $use_ip = <IP>;
close IP;

#####################
# IP которые уже присутствуют в таблице не удаляются
# а добавляются новые тех которых нету
my %seen;
@seen{ return_ip($spam) } = ();
delete @seen{ return_ip($use_ip) };


foreach ( keys %seen ) {
    print $_;
    system( "exec ipfw table 1 add " . $_ );
}

sub return_ip {

    my $hash;
    $hash->{$1}++
      while $_[0] =~ /(\d+\.\d+\.\d+\.\d+)/smg xor 
          grep { $_ > 255 } split /\./,
        $1;
    return keys %$hash;

}

# $pidfile->remove;
## можно раскомментировать, это для того чтобы скрипт
## одновременно повторно не запустился

exit;

/etc/crontab:
(переменное окружение)
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin

зеркало



размещено: 2009-03-29,
последнее обновление: 2010-05-15,
автор: ProFTP


Alexander Sheiko, 2009-03-31 в 22:49:44

На мой взгляд - это бредовый список. Хотя бы потому, что там есть адреса вида "10.10.152.36,10.2.25.40,10.208.10.25,10.5.4.101" и занесены отдельные хосты, которых довольно мало (как для всего инета).

Куда логичнее было бы взять сишный http://samm.kiev.ua/bruteblock/index.html.ru и натравить его на ошибки авторизации в логе апача.

gralex, 2009-04-01 в 8:53:38

2Alexander Sheiko, а bruteblock поддерживает список исключений? Чтобы "по-пьяне" не заблочить свой IP))))

Ведь поставил не 10 минут, а 10 часов))))

Alexander Sheiko, 2009-04-01 в 15:26:03

gralex - выше запрещающего правила ipfw пропишите:

allow ip from <my_ip> to me via <server_if> in

gralex, 2009-04-02 в 7:30:05

2Alexander Sheiko, ну это само собой понятно, прописано причем давно. Решил уточнить, вдруг чего не доглядел.

gralex, 2009-04-02 в 10:13:36

Мне вот интересно по каким образом отлавливать вот такие сообщения в логах:

Apr  2 12:57:39 server sshd[986]: Connection from 200.164.68.202 port 36245
Apr  2 12:57:44 server sshd[986]: User root not allowed because not listed in AllowUsers
Apr  2 12:57:45 server sshd[1048]: Connection from 200.164.68.202 port 36973
Apr  2 12:57:47 server sshd[1048]: User root not allowed because not listed in AllowUsers
Apr  2 12:57:48 server sshd[1064]: Connection from 200.164.68.202 port 37345
Apr  2 12:57:49 server sshd[1082]: Connection from 200.164.68.202 port 27668
Apr  2 12:57:50 server sshd[1064]: User root not allowed because not listed in AllowUsers
Apr  2 12:57:50 server sshd[1115]: Connection from 200.164.68.202 port 37746
Apr  2 12:57:52 server sshd[1082]: User root not allowed because not listed in AllowUsers



Блочить по строке: Connection from 200.164.68.202 port 20898
не корректно, т.к. там могут быть и легальные коннекты.

С другой стороны нелегальные коннекты идут с частотой 1 коннект в 1-2 секунды. Тогда получается, ловим подобные сообщения и повышает количество повторов до 10-20 в минуту (для примера).

Других вариантов нет?

Гость, 2009-04-03 в 12:29:38

ну этот список помогает, спама нету совсем, достаточно даже один раз по крону запустить!

написано что в списке прокси и взломанные машины... те кто гадостями занимаються...

но можно добавить в скрипт другой список или использовать несколько!

Денис, 2009-10-13 в 16:23:34

gralex, sshguard тебе поможет.

Гость, 2009-12-14 в 2:57:52

обновил статью, теперь скрипт смотрит существующие записи в таблицу, и повторно не добавляет айпи которые уже существуют в таблице, ... можно было бы с начало это сделать

ProFTP, 2010-10-23 в 0:35:50

добавь файл размером 10-20Мб в директиву Deny и посмотришь как оно будет работать...

Chrono, 2011-07-17 в 2:37:27

Смешной вариант использования nginx, учитывая что он применяется для нагруженных сайтов вместо Apache, который и машину нерационально грузит, и статику медленно отдает и дыр хватает... В остальном способ блока спамеров хорош.



 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.0457 секунд
Из них PHP: 34%; SQL: 66%; Число SQL-запросов: 77 шт.
Исходный размер: 33757; Сжатая: 8252