#!/usr/local/bin/perl
use XML::DOM;
my $parser= XML::DOM::Parser->new();
my $doc = $parser->parsefile ("dump.xml"); # Дамп реестра
my $root = $doc->getDocumentElement();
@nodes =$doc->getElementsByTagName("domain");
open(f2 ,"+>result.txt") or die "ERROR: $!\n";
foreach my $nod (@nodes) {
my $gtr = $nod->getFirstChild()->getData();
print f2 "$gtr\n";
};Вывод в файл result.txt
и гиде айпи? )
> и гиде айпи? )Поменяй
@nodes =$doc->getElementsByTagName("domain");на
@nodes =$doc->getElementsByTagName("ip");будет тебе АЙПИ :)
>[оверквотинг удален]
> my $parser= XML::DOM::Parser->new();
> my $doc = $parser->parsefile ("dump.xml"); # Дамп реестра
> my $root = $doc->getDocumentElement();
> @nodes =$doc->getElementsByTagName("domain");
> open(f2 ,"+>result.txt") or die "ERROR: $!\n";
> foreach my $nod (@nodes) {
> my $gtr = $nod->getFirstChild()->getData();
> print f2 "$gtr\n";
> };
> Вывод в файл result.txtя сделал так
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);
}Пришлось поставить поддержку кодировки cp1251 для Simple::XML
Возвращаем url в виде пригодном для записи в файл который кормится squid у
domains аналогично только для блокировки по доменам
ips список ip адресов, у меня применяется для iptables+ipset
ну и blockDomains тоже список доменов которые вписываются в файл вида /etc/hosts и кормится dnsmasq, пришлось так извратиться что бы не заниматься подделыванием сертификатов на сквиде.
> Пришлось поставить поддержку кодировки cp1251 для Simple::XML
> Возвращаем url в виде пригодном для записи в файл который кормится squid
> у
> domains аналогично только для блокировки по доменам
> ips список ip адресов, у меня применяется для iptables+ipset
> ну и blockDomains тоже список доменов которые вписываются в файл вида /etc/hosts
> и кормится dnsmasq, пришлось так извратиться что бы не заниматься подделыванием
> сертификатов на сквиде.Ну у нас это бинд кушает, потому и отбираю по "domain", ip блокировать я считаю бессмысленным.
>> Пришлось поставить поддержку кодировки cp1251 для Simple::XML
>> Возвращаем url в виде пригодном для записи в файл который кормится squid
>> у
>> domains аналогично только для блокировки по доменам
>> ips список ip адресов, у меня применяется для iptables+ipset
>> ну и blockDomains тоже список доменов которые вписываются в файл вида /etc/hosts
>> и кормится dnsmasq, пришлось так извратиться что бы не заниматься подделыванием
>> сертификатов на сквиде.
> Ну у нас это бинд кушает, потому и отбираю по "domain", ip
> блокировать я считаю бессмысленным.Ну ипы блочатся только для хостов которые используют ssl, хотя может и для всех, давно делал не помню. Ну и по ip это уже так, для верности. Потому что готовилось все для прихода инспектора и здесь лучше перебдеть чем недобдеть.
>> Пришлось поставить поддержку кодировки cp1251 для Simple::XML
>> Возвращаем url в виде пригодном для записи в файл который кормится squid
>> у
>> domains аналогично только для блокировки по доменам
>> ips список ip адресов, у меня применяется для iptables+ipset
>> ну и blockDomains тоже список доменов которые вписываются в файл вида /etc/hosts
>> и кормится dnsmasq, пришлось так извратиться что бы не заниматься подделыванием
>> сертификатов на сквиде.
> Ну у нас это бинд кушает, потому и отбираю по "domain", ip
> блокировать я считаю бессмысленным.Если надо, могу выложить весь скрипт. Он довольно объемный оказался.
Логика работы простая
проверяем список, если есть изменения то применяем их. Также 4 раза в сутки производится обязательная закачка списка, что бы на той стороне видели что скачивается регулярно.
> Если надо, могу выложить весь скрипт. Он довольно объемный оказался.
> Логика работы простая
> проверяем список, если есть изменения то применяем их. Также 4 раза в
> сутки производится обязательная закачка списка, что бы на той стороне видели
> что скачивается регулярно.Выложи, может кому пригодится.
>> Если надо, могу выложить весь скрипт. Он довольно объемный оказался.
>> Логика работы простая
>> проверяем список, если есть изменения то применяем их. Также 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Пришлось писать для разных файлов тк разные юр лица и для каждого менять в скрипте даже значение переменной не сильно хотелось.
>>> Если надо, могу выложить весь скрипт. Он довольно объемный оказался.Добрый день, натолкнулся на ваше решение, интересует момент со сквидом.
Не возникло ли проблем с блокировкой сквидом распарсеных урлов?
Часть из имеющихся в реестре ну никак не поддаются блокировке.
такая беда например происходит с практически всеми урлами суицид-форума.
заранее спасибо.
>>>> Если надо, могу выложить весь скрипт. Он довольно объемный оказался.
> Добрый день, натолкнулся на ваше решение, интересует момент со сквидом.
> Не возникло ли проблем с блокировкой сквидом распарсеных урлов?
> Часть из имеющихся в реестре ну никак не поддаются блокировке.
> такая беда например происходит с практически всеми урлами суицид-форума.
> заранее спасибо.да нет там никаких проблем. могу помочь.
> да нет там никаких проблем. могу помочь.благодарствую, поборол.
оказалось лучшие для сквида перекодировать урл обартно в utf8.
>[оверквотинг удален]
> close LOGFILE;
> exit $update;
>
Здравствуйте. Я в перле почти ничего не понимаю, поэтому прошу помощи.
Судя по скрипту Ip адреса парсятся все что есть в дампе, а как
можно переделать скрипт чтобы парсились только те IP, где в теге <content> стоит тип блокировки blockType="ip" Заранее спасибо.
Потестил, тут, на досуге. Разными парсерами.
XML::DOM#!/usr/bin/perlXML::LibXMLuse strict;
use warnings;
use XML::DOM;my $parser = XML::DOM::Parser->new();
my $dom = $parser->parsefile ("dump.xml") or die;open(FH, ">", "result.txt") or die;
my @nodes = $dom->getElementsByTagName("domain");
foreach my $node (@nodes) {
print FH $node->getFirstChild()->getData(), "\n";
}close FH;
#!/usr/bin/perlXML::Twiguse strict;
use warnings;
use XML::LibXML;my $parser = XML::LibXML->new();
my $dom = $parser->parse_file("dump.xml") or die;open(FH, ">", "result2.txt") or die;
my @nodes = $dom->getElementsByTagName("domain");
foreach my $node (@nodes) {
print FH $node->firstChild()->data, "\n";
}close FH;
#!/usr/bin/perlXML::Simpleuse strict;
use warnings;
use XML::Twig;my $parser = XML::Twig->new();
my $dom = $parser->parsefile('dump.xml') or die;open(FH, ">", "result3.txt") or die;
my @nodes = $dom->root->children('content');
foreach my $node (@nodes) {
print FH $node->first_child('domain')->text, "\n";
}close FH;
#!/usr/bin/perlОт Twig ожидал большего. Зря.)) Хотя.., это же как из пушки по воробьям палить.use strict;
use warnings;
use XML::Simple;my $parser = XML::Simple->new();
my $dom = $parser->XMLin('dump.xml') or die;open(FH, ">", "result4.txt") or die;
foreach my $node (values %{$dom->{'content'}}) {
print FH $node->{'domain'}, "\n";
}close FH;
А самый быстрый, можно сказать реактивный, оказался LibXML
>[оверквотинг удален]
> use XML::Simple;
> my $parser = XML::Simple->new();
> my $dom = $parser->XMLin('dump.xml') or die;
> open(FH, ">", "result4.txt") or die;
> foreach my $node (values %{$dom->{'content'}}) {
> print FH $node->{'domain'}, "\n";
> }
> close FH;От Twig ожидал большего. Зря.)) Хотя.., это же как из пушки
> по воробьям палить.
> А самый быстрый, можно сказать реактивный, оказался LibXMLСпасибо! Дельный коммент. Мне что то и в голову не приходило пробовать разные варианты. Плюсую.