Importação de IPs do Whatsapp como Objeto do Zentyal

Publicado por Willian Itiho Amano (última atualização em 19/01/2015)

[ Hits: 5.178 ]

Download importa.pl




Sabe-se que o Whatsapp é um grande consumidor de tempo dos funcionários e de banda para empresas que disponibilizam wifi devido aos envios de imagens e vídeos. Com a incumbência de bloquear o Whatsapp fui procurar os IPs utilizados pelo serviço. Esta lista está disponível no endereço: https://www.whatsapp.com/cidr.txt

Veja que é uma lista muito grande para cadastrar manualmente no Firewall. No caso utilizo o Firewall Zentyal 4.0. Pesquisando na internet achei o seguinte script ( http://www.institutmarianao.cat/wordpress/?p=226 ) que importa os dados para dentro do Zentyal.

Crie um arquivo objects.csv com os IPs com o seguinte formato ( disponível em: http://pastebin.com/7JgbbQgA )

WhatsApp,IP1,ipaddr,5.153.52.248,29,
WhatsApp,IP2,ipaddr,31.13.65.14,32,

Após isso crie um arquivo chamado importa.pl com o conteúdo do script no mesmo diretório do csv e dê permissão de execução. Aí é só executar, acessar o Zentyal e criar uma regra bloqueando este objeto.

  



Esconder código-fonte

#!/usr/bin/perl

use strict;
use warnings;

use EBox;
use EBox::Global;
use EBox::Objects;
use Scalar::Util;

EBox::init();

open (my $OBJECTS, 'objects.csv');
# File objects.csv format "objecte name", "member name", "member type", "member ip", "member mac o ip"
# types : ipaddr | iprange

my $module = EBox::Global->getInstance(0)->modInstance(qw(objects));
if (not $module) {
EBox::error(qw(objects) . "has impot data but it is not installed, not importing");
return;
}

my @members;
my $object = '';

while (my $line = <$OBJECTS>) {
chomp ($line);
my $member;

my ($objectname, $membername, $membertype, $memberip, $memberipormask, $membermac) = split(',', $line);

$membername =~ s/^\s+|\s+$//g;
$membertype =~ s/^\s+|\s+$//g;
$memberip =~ s/^\s+|\s+$//g;
$memberipormask =~ s/^\s+|\s+$//g;

if ($membertype eq 'ipaddr') {
if ($membermac) {
$membermac =~ s/^\s+|\s+$//g;
$member = { 'name' => $membername,
'address_selected' => $membertype,
'ipaddr_ip' => $memberip,
'ipaddr_mask' => $memberipormask,
'macaddr' => $membermac };
} else {
$member = { 'name' => $membername,
'address_selected' => $membertype,
'ipaddr_ip' => $memberip,
'ipaddr_mask' => $memberipormask };
}
} else {
$member = { 'name' => $membername,
'address_selected' => $membertype,
'iprange_begin' => $memberip,
'iprange_end' => $memberipormask };
}

if ($object ne $objectname) {
# canvi objecte
if (@members) {
# Some member exist. Not first loop
print "Adding $object...\n";
$module->addObject('name' => $object, 'members' => \@members);
@members = ();
}
$object = $objectname;
}
push(@members, $member);
}

print "Adding $object...\n";
$module->addObject('name' => $object, 'members' => \@members);

close ($OBJECTS);

1;

Scripts recomendados

Instalação automatizada do Squid 2.5 STABLE14

CRIAR CBQ

Obter Nome e IP do Host

Smb Network

Slowloris.pl (não foi feito por mim é apenas um compartilhamento.)


  

Comentários
[1] Comentário enviado por removido em 23/01/2015 - 23:17h

Seguem algumas observações.

Na primeira linha, o shebang poderia ser trocado para:

[code]#!/usr/bin/env perl[/code]

Porque em muitos sistemas o local onde o interpretador perl está instalado não é o "padrão".

O uso do 'open' com apenas dois argumentos é uma má prática de programação, o recomendado é utilizar três argumentos:

[code]open my $objfh, q(<), q(objects.csv);[/code]

Você não faz nenhum validação caso o arquivo não exista ou caso não possa ser aberto pelo usuário que executou o script. Também não vejo muita necessidade neste script, mas caso queira modificar, pode-se utilizar o pragma autodie (perldoc autodie) ou simplesmente adicionar ao final da instrução do 'open':

[code]or die $!;[/code]


Na linha 20, você utilizou o comando 'return' sem estar em uma subrotina, isto não caso erros de compilação, mas caso aquele 'if' seja executado, você receberá uma mensagem do tipo:

[code]Can't return outside a subroutine at importa.pl line 20.[/code]

Creio que você na verdade pretendia interromper a execução do script, para estes casos você usa ou 'exit' ou 'die' (que aceita mensagens como argumento). Ainda neste trecho, você testa com o operador de baixa precedência 'not' a variável '$module', creio que o mais adequado seria testar se '$module' está definido ao invés de testar sua "validez" (string vazia, variável não definida e 0 são inválidos):

[code]if ( ! defined $module ) {
...
die ...
}
[/code]

Na linha 24, você inicializa uma variável com o valor vazio, isto é desnecessário e também não é recomendado.

Na linha 30, assim como em vários outros lugares, você usar parênteses para builtins, é consenso atualmente de não mais usá-los quando não são realmente necessários. O uso de parênteses para não builtins continua opcional.

Para parser de arquivos delimitados por caractere é recomendável o uso do módulo Text::CSV (_XS ou não), neste caso, onde o CSV é realmente muito simples, não vejo necessidade.

Com as variáveis que são criadas a partir do 'split', você faz várias substituições de espaços nas extremidades das string mesmo sem necessidade. Perceba que o mesmo código é reescrito em vários lugares para fazer exatamente a mesma coisa, nestes casos, pode-se usar:

[code]foreach (
$objectname, $membername, $membertype,
$memberip, $memberipormask, $membermac
)
{
s/^\s+//;
s/\s+$//;
}
[/code]

Que é bem mais performático e simples de manter, contudo ainda precisa reescrever o nome das variáveis e por isto ou escolheria outro tipo de estrutura de dados ou faria isto com 'map' em cima do 'split'.

Na linha 42, você testa se a variável '$membermac' possui conteúdo válido, se ela possuir um ou mais caracteres de espaço já seria válido, passaria no teste e seu conteúdo desapareceria no tratamentos posteriores.

Para todos os '$member' há duas chaves que são comuns: name e address_selected, você poderia pré declará-las antes das estruturas de decisão e assim não ter que reescrever a cada 'if' que for feito:

[code]my $member = {
name => $membername,
address_selected => $membertype,
};
[/code]

Com o uso do fat comma (=>) não é necessário o uso de apóstrofos se as suas chaves são nomes de variáveis válidos, como é o caso aqui, o fat comma já faz esse trabalho.

Quando existe '$membermac', só há uma diferença: a presença do 'macaddr', então, o código poderia ser encurtado para:

[code]if ( $membertype eq q(ipaddr) ) {
$member->{ipaddr_ip} = $memberip;
$member->{ipaddr_mask} = $memberipormask;
$member->{macaddr} = $membermac if defined $membermac;
}
[/code]

Que poderia ser mais curto mas complicaria mais também. Por conta dessas estruturas de dados penso que já criar o hash "principal" no 'split' da linha tornaria as coisas ainda mais fáceis.

Há mais detalhes para serem explorados mas o comentário ficou longo e cansativo.

Como última dica, dê uma olhada no perltidy (Perl::Tidy), com ele, eu, por exemplo, vou escrevendo tudo num única linha, mando executar em cima do código e o resultado é um código indentado como os snippets que postei.

[2] Comentário enviado por leandz em 17/04/2015 - 16:06h


boa tarde!

tentei fazer esse mesmo processo no meu Zentyal 3.4 e não obtive sucesso...


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts