helio.loureiro.eng.br
  • Home
  • Unix
  • Linux
  • Blog
  • Python
  • Programação
  • Tudo
  • Suécia
  1. You are here:  
  2. Home
  3. Programação
  4. Perl

Os artigos mais lidos de 2024

  • linux-br.org num ritmo mais lento
  • Criando um serviço de relay de DNS-over-HTTPS
  • Minha palestra sobre a história do Unix na IX BSD Day
  • Pedal forte de 2023 em dados do Google
  • Linux vs GNU/Linux

Acessos de robôs nos logs web

Details
Written by: Helio Loureiro
Category: Perl
Published: August 14, 2025
Hits: 397

Esses dias eu vi um post no Mastodon sobre bloquear robôs que acessam o servidor web.

Perguntei pro autor do post como foi que ele conseguiu isso, mas fui solenemente ignorado. Coisas da Internet.

Então resolvi dar uma olhada nos logs do servidor, esse que hospeda esse mesmo site. E fiz um programa em perl pra isso. Pra matar as saudades. E tirar a ferrugem.

E esse foi o programa:

  
#! /usr/bin/env perl
use IO::Zlib;

my $LOGDIR = "/var/log/apache2";

opendir(DIR, $LOGDIR) or die "Impossible to read from directory: $!\n";

%ip_addrs;
%bot_agent;

@gzip_files;

foreach my $filename (readdir DIR) {
        next if $filename !~ /access/;
        # skip gz right now
        if ($filename =~ /\.gz/) {
                push(@gzip_files, ($LOGDIR."/".$filename));
                next;
        }

        print($LOGDIR."/".$filename."\n");
        open(FD, $LOGDIR."/".$filename) or die "Impossible to read file: $!\n";
        foreach my $line () {
                next if $line !~ /bot/;
                parse_log_line($line);
        }
}


print("result:\n");


for my $filename (@gzip_files) {
        print("$filename\n");
        my $fh = new IO::Zlib;
        $fh->open($filename, "rb") or die "impossible to read gzip file: $!\n";
        while ( my $line = <$fh>) {
                next if $line !~ /bot/;
                parse_log_line($line);
        }
}

foreach $bot (sort {$bot_agent{$b}<=>$bot_agent{$a} } keys %bot_agent) {
    print("$bot => $bot_agent{$bot}\n");
}

sub parse_log_line() {
        my $line = $_[0];
        our %ip_addrs;
        our %bot_agent;

        @params = split(/ /, $line);
        my $ip = $params[0];
        $ip_addrs{$ip}++;
        $line =~ s/.*]//;
        $line =~ s/\"$//;
        $line =~s/.*\"//;
        chomp($line);
        if ($line =~ m/bot/) {
                $bot_agent{$line}++;
        }
}    
  

E o resultado em formato de tabela:

User-Agent do robô Quantidade de acessos
Mozilla/5.0 (compatible; MJ12bot/v1.4.8; http://mj12bot.com/) 30130
Mozilla/5.0 (compatible; SemrushBot/7~bl; +http://www.semrush.com/bot.html) 22203
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; This email address is being protected from spambots. You need JavaScript enabled to view it.) 16981
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) Chrome/116.0.1938.76 Safari/537.36 15979
Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/) 12112
Mozilla/5.0 (Linux; Android 7.0;) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Safari/537.36 (compatible; PetalBot;+https://webmaster.petalsearch.com/site/petalbot) 10744
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Amazonbot/0.1; +https://developer.amazon.com/support/amazonbot) Chrome/119.0.6045.214 Safari/537.36 9704
Mozilla/5.0 (compatible; DotBot/1.2; +https://opensiteexplorer.org/dotbot; This email address is being protected from spambots. You need JavaScript enabled to view it.) 7434
Mozilla/5.0 (compatible; AwarioBot/1.0; +https://awario.com/bots.html) 5042
Mozilla/5.0 (compatible; DataForSeoBot/1.0; +https://dataforseo.com/dataforseo-bot) 3104
Linguee Bot (http://www.linguee.com/bot; This email address is being protected from spambots. You need JavaScript enabled to view it.) 1957
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15 (Applebot/0.1; +http://www.apple.com/go/applebot) 1450
Mozilla/5.0 (compatible; archive.org_bot +http://archive.org/details/archive.org_bot) Zeno/5741de8 warc/v0.8.85 751
Mozilla/5.0 (compatible; SemrushBot-BA; +http://www.semrush.com/bot.html) 651
Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots) 567
Mozilla/5.0 (compatible; MJ12bot/v2.0.2; http://mj12bot.com/) 538
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.183 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) 531
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) 411
Blogtrottr/2.1 (+https://blogtrottr.com/robot) 340
Googlebot-Image/1.0 315
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) Chrome/100.0.4896.127 Safari/537.36 300
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot) 261
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36; compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot 240
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.7151.119 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) 207
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) Chrome/136.0.0.0 Safari/537.36 191
ZoominfoBot (zoominfobot at zoominfo dot com) 164
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot 150
Mozilla/5.0 (compatible; SeznamBot/4.0; +https://o-seznam.cz/napoveda/vyhledavani/en/seznambot-crawler/) 124
Mozilla/5.0 (compatible; MojeekBot/0.11; +https://www.mojeek.com/bot.html) 107
Mozilla/5.0 (compatible; archive.org_bot +http://archive.org/details/archive.org_bot) Zeno/a7797cb warc/v0.8.78 89
DuckDuckBot/1.1; (+http://duckduckgo.com/duckduckbot.html) 82
Mozilla/5.0 (compatible;PetalBot;+https://webmaster.petalsearch.com/site/petalbot) 80
Mozilla/5.0 (compatible; YandexImages/3.0; +http://yandex.com/bots) 70
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot) 62
Mozilla/5.0 (compatible; YaK/1.0; http://linkfluence.com/; This email address is being protected from spambots. You need JavaScript enabled to view it.) 61
Mozilla/5.0 (compatible; coccocbot-image/1.0; +http://help.coccoc.com/searchengine) 56
Mozilla/5.0 (compatible; wpbot/1.3; +https://forms.gle/ajBaxygz9jSR8p8G9) 41
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Chrome/137.0.7151.119 Safari/537.36 37
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.168 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) 29
Twitterbot/1.0 29
AdsBot-Google (+http://www.google.com/adsbot.html) 22
Mozilla/5.0 (compatible; intelx.io_bot +https://intelx.io) 21
BufferLinkPreviewBot/1.0 (+https://scraper.buffer.com/about/bots/link-preview-bot) 19
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) 14
Mozilla/5.0 (compatible; Thinkbot/0.5.8; +In_the_test_phase,_if_the_Thinkbot_brings_you_trouble,_please_block_its_IP_address._Thank_you.) 13
Mozilla/5.0 (compatible; MJ12bot/v2.0.4; http://mj12bot.com/) 13
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.183 Mobile Safari/537.36 (compatible; AdsBot-Google-Mobile; +http://www.google.com/mobile/adsbot.html) 9
Mozilla/4.0 (compatible; fluid/0.0; +http://www.leak.info/bot.html) 8
Mozilla/5.0 (Windows NT 10.0; Win64; x64; trendictionbot0.5.0; trendiction search; http://www.trendiction.de/bot; please let us know of any problems; web at trendiction.com) Gecko/20100101 Firefox/125.0 7
Googlebot/2.1 (+http://www.google.com/bot.html) 5
Mozilla/5.0 (compatible; SurdotlyBot/1.0; +http://sur.ly/bot.html) 5
Mozilla/5.0 (compatible; Website-info.net-Robot; https://website-info.net/robot) 4
Mozilla/5.0 (compatible; coccocbot-web/1.0; +http://help.coccoc.com/searchengine) 4
Pandalytics/2.0 (https://domainsbot.com/pandalytics/) 4
Mozilla/5.0 (compatible; IbouBot/1.0; This email address is being protected from spambots. You need JavaScript enabled to view it.; +https://ibou.io/iboubot.html) 4
DomainStatsBot/1.0 (https://domainstats.com/pages/our-bot) 4
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) 3
Mozilla/5.0 (compatible; SeekportBot; +https://bot.seekport.com) 3
serpstatbot/2.1 (advanced backlink tracking bot; https://serpstatbot.com/; This email address is being protected from spambots. You need JavaScript enabled to view it.) 3
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.4 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.4 facebookexternalhit/1.1 Facebot Twitterbot/1.0 3
yacybot (-global; amd64 Linux 5.15.161; java 11.0.26-internal; America/en) http://yacy.net/bot.html 2
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Chrome/120.0.6099.199 Safari/537.36 2
Mozilla/5.0 (compatible; Qwantbot/1.0_4396629; +https://help.qwant.com/bot/) 2
DomCopBot (https://www.domcop.com/bot) 2
Mozilla/5.0 (compatible; YandexFavicons/1.0; +http://yandex.com/bots) 2
yacybot (/global; amd64 Linux 5.15.0-140-generic; java 11.0.27; America/en) http://yacy.net/bot.html 2
Synapse (bot; +https://github.com/matrix-org/synapse) 2
Mozilla/5.0 (compatible; archive.org_bot; Wayback Machine Live Record; +http://archive.org/details/archive.org_bot) 1
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) 1
Mozilla/5.0 (compatible; Qwantbot/1.0; +https://help.qwant.com/bot/) 1
Facebot 1
Mozilla/5.0 (compatible; GetHPinfo.com-Bot/0.1; +http://www.gethpinfo.com/bot/ 1
Slack-ImgProxy (+https://api.slack.com/robots) 1
Googlebot-Video/1.0 1
yacybot (/global; amd64 Linux 6.12.38+deb13-amd64; java 21.0.8; Europe/fr) http://yacy.net/bot.html 1
Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25 (compatible; SMTBot/1.0; +http://www.similartech.com/smtbot) 1
Mastodon/4.5.0-alpha.1+chuckya (http.rb/5.3.1; +https://lab.wheelsbot.dev/) 1

O resultado é texto. Eu só formatei pra ficar mais fácil de visualizar aqui (usando "sd" pra isso). E está hardcoded pra buscar os logs do apache2 em sistemas debian alike.

Dos resultados, confesso que fiquei surpreso. Realmente bastante tráfego vindo de robôs. E vários que eu nunca ouvi falar.

Sobre bloquear ou não, eu por enquanto não mexi em nada e os robôs continuam acessando tudo. Mesmo porque eu não fiz nada qualitativo, pra saber se estão recebendo 200 (ok) ou alguma outra coisa como 404 (not found - não encontrad).

Mas caso eu decida pelo bloqueio, achei um projeto bem interessante no GitHub que já faz a curadoria de robôs "bons" e "ruins".

https://github.com/mitchellkrogza/apache-ultimate-bad-bot-blocker

Substituindo o perlcc

Details
Written by: Helio Loureiro
Category: Perl
Published: December 12, 2012
Hits: 9679

Se assim como eu, você precisa invariavelmente entregar programas binários e sem o código fonte, então também está sentindo falta do perlcc, que compilava o programa em perl em um belo binário.

Devido à vários bugs, incompatibilidades e falta de manutenção, o perlcc foi removido já no perl 5.8.

Eu testei várias outras soluções, mas ultimamente estava entregando binário utilizando o freeze do python, que eu achava mais simples.

Hoje, buscando uma outra coisa perl, topei com um PAR packer.  Tanto a sintaxe quanto a funcionalidade é idêntica ao perlcc.

PAR packer

Eu testei aqui, e funcionou muito bem.

helio@shibboleet:tmp$ pp -B -o accumulatorEventSender accumulatorEventSender.pl
helio@shibboleet:tmp$ ls
accumulatorEventSender  accumulatorEventSender.pl
helio@shibboleet:tmp$ file accumulatorEventSender
accumulatorEventSender: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), 
dynamically linked (uses shared libs), for GNU/Linux 2.6.15,
BuildID[sha1]=0x75828a5e4b38f0a935c9461e07d6ac23d3282d73, stripped

O aplicativo se encontra no pacote libpar-packer-perl no Ubuntu (e possivelmente no Debian).

mycrontab

Details
Written by: Helio Loureiro
Category: Perl
Published: June 25, 2011
Hits: 11964

No sistema de agendamento de tarefas, o cron, existe a possibilidade de controle de acesso pelos arquivos /etc/cron.allow e  /etc/cron.deny.  Existindo somente o /etc/cron.allow no sistema, o usuário deverá ter seu login incluso nesse arquivo para fazer uso do cron.  Do contrário será brindando com uma mensagem semelhante a essa:

You (helio) are not allowed to use this program (crontab)
See crontab(1) for more information

Nos ambientes de telecomunicações, onde muitos dos sistemas operacionais em uso são Solaris, ex-Sun e agora da Oracle, esses vêm com essa forma de controle do cron habilitada por padrão.

Isso aumenta a segurança do sistema, mas também torna alguns trabalhos simples mais difíceis, principalmente quando é necessário ter agendamento de trabalho.  Claro que isso poderia ser resolvido com ajuda de um bom administrador de sistemas, o sysadmin, e conhecimento em Unix, mas isso parece estar se tornando cada vez mais raro nesses dias.

Então criei o mycrond, um daemon escrito em perl, para rodar periodicamente como o crond do sistema.  A sintaxe não é perfeita e tem alguns furos, como não aceitar "*/5" para tarefas a cada 5 intervalos, mas utiliza uma sintaxe que somente Solaris aceita como, por exemplo para tarefas agendadas para cada 5 minutos, utilizar "0,5,10,15,20,25,30,35,40,45,50,55".  O restante é parecido com o uso normal da crontab.

Não é 100% perfeito, pois acabei deixando a análise de sintaxe incompleta para todos os valores de data, mas funciona perfeitamente como daemon, não morrendo ao sair do sistema, e é capaz de analisar e rodar formas mais simples da crontab.

O conteúdo do programa é o seguinte:


#! /usr/bin/perl
# $Id: mycrond 29 2011-06-22 20:42:35Z helio $
# Date: Wed Jun 22 12:37:00 BRT 2011
# Author: Helio Loureiro
# Description: an user level alternative to system crond.
#


my $ROOTDIR = "/home/helio/AUDIT";

exit(0); # Edit $ROOTDIR settings and comment this exit.

my $CRONFILE = $ROOTDIR."/etc/crontab";
my $PIDFILE = $ROOTDIR."/var/run/mycrond.pid";

$SIG{CHLD} = 'IGNORE'; #avoid zombies, or they can eat your brain

### Starting in daemon mode
&Daemonize();


sub CheckDir() {
	my $dir = $_[0];
	if ( ! -d "$dir" ) {
		system("mkdir -p $dir");
	}
}

sub ParseCronLine() {
	my $cron = $_[0];
	chomp($cron);

my @params = split(/ /, $cron); my $r_minute = $params[0]; my $r_hour = $params[1]; my $r_day = $params[2]; my $r_month = $params[3]; my $r_dow = $params[4]; my $command = $params[5]; for (my $x = 6; $x < @params; $x++) { $command .= " ".$params[$x]; } my ($second, $minute, $hour, $dayOfMonth, $month, $year, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime(); $year += 1900; $month++; ### Day of week requires some more work if ($r_dow != '*') { if ($r_dow != $dayOfWeek) { return 0; } } if ($r_month != '*') { $run_status = 0; @months = split(/,/, $r_month); foreach $m (@months) { if ($m == $month) { $run_status++ ; } } return if (! $run_status); } if ($r_day != '*') { $run_status = 0; @days = split(/,/, $r_day); foreach $d (@days) { if ($d == $dayOfMonth) { $run_status++ ; } } return if (! $run_status); } if ($r_minute != '*') { $run_status = 0; @minutes = split(/,/, $r_minute); foreach $m (@minutes) { if ($m == $minute) { $run_status++ ; } } return if (! $run_status); } if ($r_hour != '*') { $run_status = 0; @hours = split(/,/, $r_hour); foreach $h (@hours) { if ($h == $hour) { $run_status++ ; } } return if (! $run_status); } # If it is ok, then run your command if (defined($DEBUG)){ print "Running: $command\n"; } exec "$command" or exit(1); exit(0); } sub Run() { ### Saving process PID my $pid = getppid(); $pid++; &CheckDir($ROOTDIR."/var/run"); open(PID, ">$PIDFILE") or die "Impossible to create $PIDFILE: $!\n"; print PID $pid."\n"; close(PID); open(FD, $CRONFILE) or die "Impossible to read crontab: $!\n"; my @cronlines = ; close(FD); my @PIDS; while (1) { foreach my $line (@cronlines) { next if ($line =~ m/^#/); my $runpid = fork(); if ($runpid == 0) { &ParseCronLine($line); exit(0); } if ($runpid > 0) { push(@PIDS, $runpid); } } sleep(60); } } sub Daemonize() { # Change to / chdir("/"); my $pid = fork(); #first fork if ($pid > 0) { #Parent exists exit(0); } if ($pid == 0) { # Son forks again my $pid2 = fork(); if ($pid2 > 0) { exit(0); } if ($pid2 == 0) { &Run(); } } }

Conversão de caracteres em Perl

Details
Written by: Helio Loureiro
Category: Perl
Published: August 24, 2008
Hits: 9978

Faz tempo que não me deparo com esse tipo de problema, mas acabei vendo novamente depois que um colega de trabalho pediu ajuda nisso.

A primeira vez que trabalhei com conversão de caracteres foi em português mesmo, de ISO-8859-1 para UTF-8. Não guardei lembranças boas. Dessa vez o desafio era para converter supostos caracteres no mesmo formato para UTF-8, mas não da nossa língua pátria.

Para quem nunca viu isso, o código em Perl que faz a conversão está no pacote Encode , disponível no CPAN, da seguinte forma:


use Encode; 
... 
... 
foreach $line () { 
    next if ($line =~ m/^$/); 
    chomp($line); 
    $i = Encode::decode("iso-8859-1", $line); 
    $line = Encode::encode("utf8", $i); 
    print $line."\n"; 
} 
...

Dessa vez tive um problema com a palavra "ΑστέριαΑστέρια". Juro que não sei o que significa, mas a droga da palavra, escrita em grego (CP1253) estava junto ao restante do texto codificado em ISO-8859-1.

Apanhei pra achar o formato certo... ainda falta fazer um conversor inteligente o suficiente para usar o formato certo antes de processar, mas já é alguma coisa...

Estatísticas

  • Users 2
  • Articles 468
  • Articles View Hits 3353290

Imagem aleatória