The OpenNET Project / Index page

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



Индекс форумов
Составление сообщения

Исходное сообщение
"Парсер реестра с сайта Роскомнадзора"
Отправлено McLeod095, 06-Июн-14 10:56 
>> Если надо, могу выложить весь скрипт. Он довольно объемный оказался.
>> Логика работы простая
>> проверяем список, если есть изменения то применяем их. Также 4 раза в
>> сутки производится обязательная закачка списка, что бы на той стороне видели
>> что скачивается регулярно.
> Выложи, может кому пригодится.

Код не идеален, но вроде как работает и работает исправно


#!/usr/bin/env perl
#

use warnings;
use strict;
use MIME::Base64;
use SOAP::Lite;
use Fcntl qw(:flock);
use Archive::Extract;
use XML::Simple;
use Data::Dumper;
use utf8;
use Encode;
binmode STDOUT, ":utf8";

use constant {
    NOTICE => 0,
    WARN => 1,
    ERROR => 2,
    DEBUG => 3,
};

# Отключаем буферизацию вывода
$|=1;

# Название компании по которой делаем выгрузку, файлы должны иметь вид компания.req компания.sig
my $company = shift or die("Use script with parameters\n");
my $requestFile = "/root/bin/" . $company . ".req";
my $signatureFile = "/root/bin/" . $company .".sig";
my $registryFile = "/tmp/" . $company . ".registry.zip";
my $registryTime = 0;
my $retries = 240;                                            # Количество секунд ожидания приема файла
my $step = 30;                                                # Опрашивать каждые  step  секунд
my $update = 1;
our $debug = 0;

my $aclDomainFile = "/etc/squid/block_domain.acl";
my $aclUrlFile = "/etc/squid/block_url.acl";
my $hostFile = "/etc/squid/banned_hosts";

my $request;
my $signature;

sub trim {
    my $text = shift;
    $text =~ s/^\s+|\s+$//g;
    return $text;
}

sub getLevel {
    my $level = shift;
    if($level == 0){
        return "NOTICE";
    }
    elsif($level == 1){
        return "WARN";
    }
    elsif($level == 2){
        return "ERROR";
    }
    return "DEBUG";
}

sub _log {
    my $level = shift;
    my $message = shift;
    if($debug == 1 || ($level < DEBUG and $debug == 0)){
        my ($second, $minute, $hour, $mday, $mon, $year, $wday, $yday, undef) = localtime(time);
        $year += 1900;
        $mon += 1;
        printf("ddd-d:d:d : %s : %s", $year, $mon, $mday, $hour, $minute, $second, getLevel($level), $message);
    }
}

# Разархивируем файл
sub unzip {
    my $zip = shift;
    my $archive = Archive::Extract->new( archive => $zip);
    my $archive_ok = $archive->extract( to => '/tmp') or die "Cannot extract files from $zip: $archive->error";
    # Пока путь возвращаем через костыль
    return "/tmp/dump.xml";
}

# Пасрим XML
sub parse_xml {
    my $xml = shift;
    my $simple = XML::Simple->new();
    my $data = $simple->XMLin($xml);
    my $urls;
    my $domains;
    my $blockDomains;
    my $ips;
    my %seenDomains;
    my %seenIps;

    foreach my $number (keys %{$data->{'content'}}){
        my $block = 0;
        if(ref($data->{'content'}{$number}{'url'}) eq "ARRAY"){
            foreach my $url (@{$data->{'content'}{$number}{'url'}}){
                if($url =~ /^https:/i){
                    $block = 1;
                }
                push @$urls, quotemeta(trim($url));
            }
        }
        else{
            if($data->{'content'}{$number}{'url'} =~ /^https:/i){
                $block = 1;
            }
            push @$urls, quotemeta(trim($data->{'content'}{$number}{'url'}));
        }
        if(! $seenDomains{$data->{'content'}{$number}{'domain'}}++){
            if($block){
                push @$blockDomains, $data->{'content'}{$number}{'domain'};
            }
            push @$domains, $data->{'content'}{$number}{'domain'};
        }
        if(ref($data->{'content'}{$number}{'ip'}) eq "ARRAY"){
            foreach my $ip (@{$data->{'content'}{$number}{'ip'}}){
                if(! $seenIps{$ip}++){
                    push @$ips, $ip;
                }
            }
        }
        else{
            if(! $seenIps{$data->{'content'}{$number}{'ip'}}++){
                push @$ips, $data->{'content'}{$number}{'ip'};
            }
        }
    }
    @$urls = sort @$urls;
    @$domains = sort @$domains;
    @$ips = sort @$ips;
    @$blockDomains = sort @$blockDomains;

    return ($urls, $domains, $ips, $blockDomains);
}

sub _ipset {
    my $ips = shift;
    my $ipset = "/usr/sbin/ipset";
    my $ipsetName = "blockip";
    my $ipsetTemp = "blocktmp";

    system "$ipset create $ipsetTemp hash:ip";
    foreach my $ip (@{$ips}){
        system "$ipset add $ipsetTemp $ip";
    }
    system "$ipset swap $ipsetTemp $ipsetName";
    system "$ipset destroy $ipsetTemp";
}

# Логирования, надо отключить после тестов
my $logFile = "/tmp/" . $company . ".log";
open LOGFILE, ">>$logFile" or die "Cannot open log file $logFile: $!";

# Переключаем стандартный вывод в файл логирования
select LOGFILE;

my $currentTime = time;
my ($second, $minute, $hour, undef, undef, undef, undef, undef, undef) = localtime($currentTime);

# Если файл реестра существует запоминаем время последнего редактирования
if(-e $registryFile){
    _log DEBUG, "Registry file $registryFile exists\n";
    $registryTime = (stat($registryFile))[9];
}
else{
    _log DEBUG, "Registry file $registryFile not exists\n";
}

# 4 раза в сутки скачиваем файл реестра обязательно в независимости от последеного обновления файла и реестра
if( ($hour == 0 and ($minute >=0 and $minute <10) and $registryTime < $currentTime - 600) or
    ($hour == 6 and ($minute >=0 and $minute <10) and $registryTime < $currentTime - 600) or
    ($hour == 12 and ($minute >=0 and $minute <10) and $registryTime < $currentTime - 600) or
    ($hour == 18 and ($minute >=0 and $minute <10) and $registryTime < $currentTime - 600)) {
    _log NOTICE, "Time update is now\n";
    $registryTime = 0;
}
    
unless(open REQUEST, $requestFile){
    _log ERROR, "Cannot open request file $requestFile\n";
    exit 1;
}
$request .= $_ while <REQUEST>;
close REQUEST;

unless(open SIGNATURE, $signatureFile){
    _log ERROR, "Cannot open signature file $signatureFile\n";
    exit 1;
}
$signature .= $_ while <SIGNATURE>;
close SIGNATURE;

my $soap = SOAP::Lite->service("http://vigruzki.rkn.gov.ru/services/OperatorRequest/?wsdl");
$SOAP::Constants::PREFIX_ENV = 'SOAP-ENV';

# метод возвращает время в милисекундах, нам и секунд достаточно!! )
my $lastUpdateTime = ($soap->getLastDumpDateEx)[1] * 0.001;
# Убрать после теста
_log NOTICE, "File update time:     $registryTime\n";
_log NOTICE, "Registry update time: $lastUpdateTime\n";

# Если есть срочные обновления в реестре запращиваем файл реестра и в течении времени ожидания приема файла пробуем загрузить файл раз в step секунд
if($lastUpdateTime > $registryTime){
    _log NOTICE, "Trying update registry file\n";
    my @sendRequest = $soap->sendRequest($request, $signature);
    if($sendRequest[0] eq "true"){
        unless(open REGISTRY, ">$registryFile"){
            _log ERROR, "Cannot open file $registryFile\n";
            exit 1;
        }
        flock REGISTRY, LOCK_EX;
        my $code = $sendRequest[2];
        _log NOTICE, "Code for checking\t\t$code\n";
        while ($retries > 0) {
            _log NOTICE, "Trying get result for check code $code. Wait $retries seconds\n";
            $retries -= $step;
            sleep $step;
            my @getResult = $soap->getResult($code);
            if($getResult[0] eq "true"){
                _log DEBUG, "Update request for code $code is answered\n";
                print REGISTRY decode_base64($getResult[1]);
                _log NOTICE, "Registry updated\n";
                my $xml = unzip($registryFile);
                my ($urls, $domains, $ips, $blockDomains) = parse_xml(unzip($registryFile));
                
                _log DEBUG, "Update ipset";
                _ipset $ips;

                unless(open SQUIDACL, ">$aclDomainFile"){
                    _log ERROR, "Cannot open acl file $aclDomainFile\n";
                    exit 1;
                }
                flock SQUIDACL, LOCK_EX;
                binmode SQUIDACL, ":utf8";
                foreach (@{$domains}){
                    print SQUIDACL "$_\n";
                }
                close SQUIDACL;

                unless(open SQUIDACL, ">$aclUrlFile"){
                    _log ERROR, "Cannot open acl file $aclUrlFile\n";
                    exit 1;
                }

                flock SQUIDACL, LOCK_EX;
                binmode SQUIDACL, ":utf8";
                foreach (@{$urls}){
                    print SQUIDACL "$_\n";
                }
                close SQUIDACL;

                unless (open BLOCKHOSTS, ">$hostFile") {
                    _log ERROR, "Cannot open hosts file $hostFile\n";
                    exit 1;
                }

                flock BLOCKHOSTS, LOCK_EX;
                binmode BLOCKHOSTS, ":utf8";
                foreach (@$blockDomains){
                    print BLOCKHOSTS "192.168.202.1\t$_\n";
                }
                close BLOCKHOSTS;
                $update = 0;
                last;
            }
        }
        close REGISTRY;
    }
    else{
        _log ERROR, "Cannot send request:  $sendRequest[1]\n";
    }
}    
select STDOUT;
close LOGFILE;
exit $update;

Запускается он вот такой строчкой в /etc/crontab


*/5 * * * * root if /root/bin/vigruzki.update.pl company; then service squid reload; service dnsmasq reload; fi

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

 

Ваше сообщение
Имя*:
EMail:
Для отправки новых сообщений в текущей нити на email укажите знак ! перед адресом, например, !user@host.ru (!! - не показывать email).
Более тонкая настройка отправки ответов производится в профиле зарегистрированного участника форума.
Заголовок*:
Сообщение*:
  Введите код, изображенный на картинке: КОД
 
При общении не допускается: неуважительное отношение к собеседнику, хамство, унизительное обращение, ненормативная лексика, переход на личности, агрессивное поведение, обесценивание собеседника, провоцирование флейма голословными и заведомо ложными заявлениями. Не отвечайте на сообщения, явно нарушающие правила - удаляются не только сами нарушения, но и все ответы на них. Лог модерирования.



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

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