shell-script-pt
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [shell-script-pt] Parser em log pflogfile


From: Marcelo Primo
Subject: Re: [shell-script-pt] Parser em log pflogfile
Date: Fri, 12 Mar 2021 11:00:09 -0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.1

Salve Arkanon, bom dia!

kkk... Sempre deixamos algo para trás.... kkk...

Esse script será executado em bash, então a opção -P não seria um problema.
Estou olhando as opções enviadas (aprendendo bastante com as novas abordagens), testando e ajustando alguma coisa ou outra (em outras palavras, fazendo experiências :D ).

Agradeço pelo tempo dispensado em elaborar algumas opções.

P.S: Ainda estou aberto a novas sugestões :-P


Atenciosamente,
Marcelo

Em 12/03/2021 10:19, Arkanon escreveu:
Óbvio que eu esqueci uma coisa, Marcelo :-/

Muitos de nós estamos cientes do risco de usar o comando grep com o parâmetro -P, que trata as expressões regulares como PCRE (Perl Compatible Regular _expression_). É um dos detalhes que o Mestre Julio não cansa de alertar no curso de Programação Shell Linux. Justamente por isso esse patch na minha resposta: não que ele vá pensar que não presto atenção nas aulas :-p

O -P está presente no GNU grep, mas possivel(talvez provavel)mente não em outras implementações. Os Unix like não Linux são bons candidatos a não poderem executar a solução 10 (por default).
Um ambiente onde acabei de confirmar esse risco é o terminal do MacOS (kernel Darwin baseado em BSD). Ele vem por padrão com o BSD grep, que possui os parâmetros -F (fixed strings), -G (basic regexp, default) e -E (extended regexp), mas não o -P (perl regexp).

Então, se além de eficiência procuramos portabilidade nos scripts, está aí outra importantíssima variável. Além claro (apesar de não nesses exemplos em particular), da sintaxe que for exclusiva do Bash, os tais "bashismos". Eles podem vir a ser complicadores se o script precisar ser executado por outro shell.
O ash, por exemplo, é o shell default no Alpine Linux, uma distro estupidamente leve e muito usada em containers mas, por ser completa, com o potencial de ser adotada também em desktops, continuando mais leve que a esmagadora maioria das outras. Várias características matadoras do bash não são implementadas no ash.
Já o MacOS vem com o ksh. (begin piada; Eu, pessoalmente, nunca usei esse shell, mas a minha filha de número 23 usa, e ela diz que esse shell é bom, muito bom; end piada). Na época que eu usei Mac, quase 10 anos atrás, fiz questão de socar meus arquivos de inicialização do bash no terminal do Mac. Tive minha cota de sofrimento por essa pretensão, hehe.
Claro, talvez seja possível instalar o gnu grep e o bash; mas talvez não seja, sabe-se lá por qual motivo aleatório.

Era isso.

Em sex., 12 de mar. de 2021 às 09:20, Arkanon <arkanon@lsd.org.br> escreveu:
Aí, Marcelo.

Veja só, quando substituí o zgrep pelo gzip nas soluções iniciais, acabei esquecendo do grep. Culpo a idade e a amostra, a qual deixei sem exemplos diferentes de "pass in" :-p
Aproveitei para alterar o tr em s1{2..3}, fazendo-o deletar as ocorrências de .: ao invés de substituí-las por espaço e fiz o awk devolver o resultado com espaço ao invés de ;, só pra ficar tudo no mesmo estilo, mas ainda há a diferença dos espaços iniciais, o que faz com que as soluções com e sem awk não sejam realmente equivalentes mas, como foquei na velocidade do primeiro resultado legível, optei por deixar assim.
A adição do grep aumentou levemente o tempo final das soluções, mas o reposicionamento do /dev/null para fora do for de N laços o diminuiu (percebe-se em s10, que já tinha o grep), o que mostra que "jogar fora" também tem seu custo, hehe.

s11(){ gzip -dc $F | grep "pass in" | sed -E 's/.*\.([0-9]+):.*/\1/' | sort | uniq -c | sort -rn | head -n20; }
s12(){ gzip -dc $F | grep "pass in" | grep -Eo '(\.[0-9]+\:)' | sort | uniq -c | sort -rn | head -n20 | tr -d .:; }
s13(){ gzip -dc $F | grep "pass in" | cut -d " " -f12 | cut -d. -f5 | sort | uniq -c | sort -rn | head -n20 | tr -d .:; }
s14(){ gzip -dc $F | grep "pass in" | awk '{print $12}' | cut -d. -f5 | sort | uniq -c | sort -rn | head -n20 | tr -d .:; }

s15(){ gzip -dc $F | grep "pass in" | sed -r 's/^[^>]+> ([0-9]{1,3}\.){4}([0-9]+):.*/\2/' | sort | uniq -c | sort -rn | head -n20; }
s16(){ awk '$0~"pass in" && $0!~"icmp" { split($12,out,"."); print substr(out[5], 1, length(out[5])-1) }' <(gzip -dc $F) | sort | uniq -c | sort -rn | awk 'NR <= 20 {print $1" "$2}'; }
s17(){ awk '{ split($12,out,"."); print substr(out[5], 1, length(out[5])-1) }' <(gzip -dc $F | grep "pass in") | sort | uniq -c | sort -rn | awk 'NR <= 20 {print $1" "$2}'; }

s10(){ gzip -dc $F | grep -oP "pass in.+>.+\.\K[0-9]+(?=:)" | sort | uniq -c | sort -rn | head -n20; }

F=pflogtext.0.gz
N=1000
for s in s{11..17} s10; { echo -e "\n# $s: "; $s; }; echo # apenas mostra o resultado cada solução
for s in s{11..17} s10; { echo -n "# $s: "; time for ((n=0; n<N; n++)); { $s; } &> /dev/null; } # testa efetivamente
# s11: 0m3,570s
# s12: 0m3,438s
# s13: 0m3,552s
# s14: 0m3,902s
# s15: 0m3,610s
# s16: 0m4,171s
# s17: 0m4,406s
# s10: 0m2,974s

Tomara que não tenha sobrado outra gafe :-p

Att,

Em qui., 11 de mar. de 2021 às 19:59, Arkanon <arkanon@lsd.org.br> escreveu:
Blz, Marcelo!

Comparei o tempo de execução das soluções apresentadas, incluindo uma minha na qual evitei o sed e o awk. Na falta do arquivo gigante que você tem, executei N vezes cada solução sobre a amostra.

s01(){ zgrep "pass in" $F | sed -E 's/.*\.([0-9]+):.*/\1/' | sort | uniq -c | sort -rn | head -n20; }
s02(){ zgrep "pass in" $F | grep -Eo '(\.[0-9]+\:)' | sort | uniq -c | sort -rn | head -n20 | tr '[.:]' ' '; }
s03(){ zgrep "pass in" $F | cut -d " " -f12 | cut -d "." -f5 | sort | uniq -c | sort -rn | head -n20 | tr '[.:]' ' '; }
s04(){ zgrep "pass in" $F | awk '{print $12}' | cut -d "." -f5 | sort | uniq -c | sort -rn | head -n20 | tr '[.:]' ' '; }

s05(){ zgrep "pass in" $F | sed -r 's/^[^>]+> ([0-9]{1,3}\.){4}([0-9]+):.*/\2/' | sort | uniq -c | sort -rn | head -n20; }
s06(){ awk '$0~"pass in" && $0!~"icmp" { split($12,out,"."); print substr(out[5], 1, length(out[5])-1) }' <(gzip -dc $F) | sort | uniq -c | sort -rn | awk 'NR <= 20 {print $1";"$2}'; }
s07(){ awk '{ split($12,out,"."); print substr(out[5], 1, length(out[5])-1) }' <(zgrep "pass in" $F) | sort | uniq -c | sort -rn | awk 'NR <= 20 {print $1";"$2}'; }

s08(){ zcat $F | grep -oP "pass in.+>.+\.\K[0-9]+(?=:)" | sort | uniq -c | sort -rn | head -n20; }
s09(){ zgrep -oP "pass in.+>.+\.\K[0-9]+(?=:)" $F | sort | uniq -c | sort -rn | head -n20; }
s10(){ gzip -dc $F | grep -oP "pass in.+>.+\.\K[0-9]+(?=:)" | sort | uniq -c | sort -rn | head -n20; }

F=pflogtext.0.gz
N=1000
for s in s{01..10}; { echo -n "# $s: "; time for ((n=0; n<N; n++)); { $s &> /dev/null; }; }
# s01: 0m8,082s
# s02: 0m8,191s
# s03: 0m8,339s
# s04: 0m8,470s
# s05: 0m8,048s
# s06: 0m4,286s
# s07: 0m9,036s
# s08: 0m4,854s
# s09: 0m12,296s
# s10: 0m3,083s

Nessa comparação, inicialmente a s06 foi a mais eficiente, seguida da s08 (onde evitei o sed e o awk).
Resolvi testá-la com o zgrep (criando a s09) e ele acabou com tudo... :-O
Aí reparei que a s06 usa gzip ao invés do zcat/zgrep e resolvi aplicar a ideia na s08, que virou a s10. Veja a diferença!

Então, como o gzip puro parece mais eficiente que o zcat, refiz tudo com ele (menos a s08 e a s09, que perderam a razão de existir, já que seriam iguais à s10):

s11(){ gzip -dc $F | sed -E 's/.*\.([0-9]+):.*/\1/' | sort | uniq -c | sort -rn | head -n20; }
s12(){ gzip -dc $F | grep -Eo '(\.[0-9]+\:)' | sort | uniq -c | sort -rn | head -n20 | tr '[.:]' ' '; }
s13(){ gzip -dc $F | cut -d " " -f12 | cut -d "." -f5 | sort | uniq -c | sort -rn | head -n20 | tr '[.:]' ' '; }
s14(){ gzip -dc $F | awk '{print $12}' | cut -d "." -f5 | sort | uniq -c | sort -rn | head -n20 | tr '[.:]' ' '; }

s15(){ gzip -dc $F | sed -r 's/^[^>]+> ([0-9]{1,3}\.){4}([0-9]+):.*/\2/' | sort | uniq -c | sort -rn | head -n20; }
s16(){ awk '$0~"pass in" && $0!~"icmp" { split($12,out,"."); print substr(out[5], 1, length(out[5])-1) }' <(gzip -dc $F) | sort | uniq -c | sort -rn | awk 'NR <= 20 {print $1";"$2}'; }
s17(){ awk '{ split($12,out,"."); print substr(out[5], 1, length(out[5])-1) }' <(gzip -dc $F) | sort | uniq -c | sort -rn | awk 'NR <= 20 {print $1";"$2}'; }

s10(){ gzip -dc $F | grep -oP "pass in.+>.+\.\K[0-9]+(?=:)" | sort | uniq -c | sort -rn | head -n20; }

F=pflogtext.0.gz
N=1000
for s in s{11..17} s10; { echo -n "# $s: "; time for ((n=0; n<N; n++)); { $s &> /dev/null; }; }
# s11: 0m3,452s
# s12: 0m3,252s
# s13: 0m3,414s
# s14: 0m3,699s
# s15: 0m3,418s
# s16: 0m4,221s
# s17: 0m4,155s
# s10: 0m3,015s

Com o gzip, a s06 (agora s16) passou de primeiro para último lugar, fazendo com que a s10, que evitou o sed e o awk, apresentasse o melhor desempenho.

É bem possível que com outras amostra, principalmente arquivos maiores, o comportamento se altere. Se você puder, refaça essa comparação com o seu arquivo completo. Basta alterar o valor da variável F. Não esqueça de começar com um valor mais baixo para N ;-)

Att,

Em qui., 11 de mar. de 2021 às 14:53, Marcelo Primo <marcelooprimo@yahoo.com.br> escreveu:

Salve Arkanon, tudo na paz?


Na verdade o trecho original do script tem essa referência ao protocolo icmp, mas nos arquivos de origem que analisei, não há qualquer referência à esse protocolo. Creio que quando o autor fez o script, das duas uma, ou existia alguma referência ao protocolo icmp ou ele tenha colocado esse grep a mais como uma forma de prevenção caso aparecesse qualquer coisa de icmp na lista.

Sobre as linhas que mandei, elas são a saída do arquivo sem qualquer alteração (exceto os IPs de destino). Uma amostra mais significativa seria as mesmas linhas enviadas, mas com portas e IPs de destino diferentes.

Obrigado pela disposição em ajudar.

Atenciosamente,
Marcelo

Em 11/03/2021 12:19, Arkanon escreveu:
Olá, Marcelo.

Você pode disponibilizar uma amostra mais significativa do arquivo? O comando original seleciona entradas com a string "pass in" e remove as com protocolo icmp e a amostra que você passou tem apenas exemplos positivos (com "pass in" e sem icmp).

Att,

Em qui., 11 de mar. de 2021 às 11:13, Marcelo Primo por (shell-script-pt) <shell-script-pt@nongnu.org> escreveu:
Salve, Blau!

Na minha primeira tentativa em melhorar o código fiz uns testes na saída
do comando com e sem o grep -v "icmp" e notei que não precisava, por
isso que nos meus comandos não tem esse trecho.

Atenciosamente,
Marcelo


Em 11/03/2021 10:52, Blau Araujo escreveu:
> Então...
>
> Nesse caso, eu acho mais interessante usar o zgrep na frente, passando
> a saída por pipe mesmo.
>
> Uma dúvida: e aquele outro filtro, o 'icmp'? Não precisa dele?
>
> Abraços!
>
> Blau Araujo
> -----------------------------
> https://debxp.org
> https://ask.debxp.org
> https://blauaraujo.com
>
> Em 11/03/2021 10:48, Marcelo Primo escreveu:
>> Salve Blau!
>>
>> Explicação claríssima, muito obrigado.
>>
>> Fiz uma alteração na sua sugestão e obtive um resultado similar ao
>> modelo (awk + cut), justamente trocando o gzip pelo zgrep (que, bem
>> observado por você, é onde está o gargalo).
>>
>> Vamos a linha:
>>
>> awk '{ split($12,out,"."); print substr(out[5], 1, length(out[5])-1)
>> }' <(zgrep "pass in" pflogtext.0.gz) | sort | uniq -c | sort -rn |
>> awk 'NR <= 20 {print $1";"$2}' = 2,6s
>>
>>
>> Obrigado pela ajuda.
>> Atenciosamente,
>>
>> Marcelo
>>
>> Em 11/03/2021 10:18, Blau Araujo escreveu:
>>> Salve, Marcelo!
>>>
>>>
>>> Como você não respondeu na lista (acontece... hehehe), aqui vai a
>>> explicação pra que todo mundo possa entender e opinar:
>>>
>>> Primeira parte...
>>>
>>> awk '$0~"pass in" && $0!~"icmp" { ... }' <(gzip -dc SEU_ARQUIVO)
>>>
>>> Aqui estou mandando para o AWK as linhas expandidas pelo gzip
>>> atarvés de uma substituição de processo, que resulta na abertura de
>>> um descritor de arquivos para leitura cujo "conteúdo" é a saída dos
>>> comandos entre os parêntesis:
>>>
>>> <(gzip -dc SEU_ARQUIVO)
>>>
>>> **Este deve ser o gargalo, e talvez o seu "gzcat/zcat |" antes do
>>> awk seja mais interessante.**
>>>
>>> Já a parte abaixo, é uma regra que manda o AWK processar apenas as
>>> linhas que contenham "pass in" e, ao mesmo tempo, não contenham "icmp":
>>>
>>> $0~"pass in" && $0!~"icmp" { ... }
>>>
>>> No programa (a parte entre chaves), eu uso a função 'split' pra
>>> dividir o campo $12 usando seus pontos como separador e atribuindo o
>>> resultado a um vetor de nome "out":
>>>
>>> split($12,out,".");
>>>
>>> Finalmente, eu uso a função 'substr' pra remover o ":" do final do
>>> quinto elemento do vetor obtido anteriormente, e é isso que eu mando
>>> pra saída com o 'print':
>>>
>>> print substr(out[5], 1, length(out[5])-1)
>>>
>>> O restante é o que vc faz pra agrupar e ordenar os resultados, só
>>> que, no final, eu tiro o 'head' e o 'sed' pra fazer todo o
>>> processamento final com o AWK novamente:
>>>
>>> awk 'NR <= 20 {print $1";"$2}'
>>>
>>> Aqui, 'NR <= 20' é uma regra que vai limitar a saída aos 20
>>> primeiros registros, enquanto que, no programa, eu imprimo '$1' e
>>> '$2' já concatenados com o caractere ';'...
>>>
>>>
>>>
>>> Abraços!
>>>
>>> Blau Araujo
>>> -----------------------------
>>> https://debxp.org
>>> https://ask.debxp.org
>>> https://blauaraujo.com
>>>
>>> Em 11/03/2021 09:35, Blau Araujo escreveu:
>>>> Salve!
>>>>
>>>> Eu fiquei curioso pra saber o tempo que isso levaria (ou se
>>>> funcionaria):
>>>>
>>>> ```
>>>>
>>>> awk '$0~"pass in" && $0!~"icmp" { split($12,out,"."); print
>>>> substr(out[5], 1, length(out[5])-1) }' <(gzip -dc SEU_ARQUIVO) |
>>>> sort | uniq -c | sort -rn | awk 'NR <= 20 {print $1";"$2}'
>>>>
>>>> ```
>>>>
>>>> Abraços!
>>>>
>>>> Blau Araujo
>>>> -----------------------------
>>>> https://debxp.org
>>>> https://ask.debxp.org
>>>> https://blauaraujo.com
>>>>
>>>> Em 10/03/2021 19:22, Marcelo Primo por (shell-script-pt) escreveu:
>>>>> Mar 09 00:00:03.146758 rule 12/(match) pass in on em0:
>>>>> 198.199.88.65.61953 > *192.168.1.143.9004**:* S
>>>>> 3776023135:3776023135(0) win 1024
>>>>> Mar 09 00:00:03.151840 rule 12/(match) pass in on em0:
>>>>> 198.199.88.65.61953 > *192.168.1.176.9004:* S
>>>>> 4103556202:4103556202(0) win 1024
>>>>> Mar 09 00:00:03.168233 rule 12/(match) pass in on em0:
>>>>> 203.212.200.241.58481 > *192.168.1.210.23:* S
>>>>> 1794254071:1794254071(0) win 5808 <mss 1452,sackOK,timestamp
>>>>> 63610891 0,nop,wscale 2> (DF)
>>>>> Mar 09 00:00:03.190210 rule 12/(match) pass in on em0:
>>>>> 178.175.97.53.46828 > *192.168.1.210.23:* S 700145820:700145820(0)
>>>>> win 5808 <mss 1452,sackOK,timestamp 159224881 0,nop,wscale 1> (DF)
>>>>> [tos 0x4]
>>>>> Mar 09 00:00:03.213339 rule 12/(match) pass in on em0:
>>>>> 131.159.24.205.51075 > *192.168.1.212.80:* S
>>>>> 2924909527:2924909527(0) win 65535 <sackOK,timestamp 4294967295
>>>>> 16843009,wscale
>>>>> 1,nop,opt-34:,opt-64:,opt-30:00810c0c0c0c0c0c0c0c,eol>
>>>>> Mar 09 00:00:03.263630 rule 12/(match) pass in on em0:
>>>>> 138.197.180.77.61953 > *192.168.1.194.10000:* S
>>>>> 3809871894:3809871894(0) win 1024
>>>>> Mar 09 00:00:03.394312 rule 12/(match) pass in on em0:
>>>>> 178.175.97.53.53172 > *192.168.1.210.23:* S
>>>>> 2983985618:2983985618(0) win 33941 [tos 0x4]
>>>>> Mar 09 00:00:03.500488 rule 12/(match) pass in on em0:
>>>>> 171.67.71.100.35957 > *192.168.1.249.8848:* S
>>>>> 1091778644:1091778644(0) win 65535
>>>>> Mar 09 00:00:03.637855 rule 12/(match) pass in on em0:
>>>>> 203.212.200.241.58457 > *192.168.1.210.23:* S
>>>>> 1746544785:1746544785(0) win 5808 <mss 1452,sackOK,timestamp
>>>>> 63610938 0,nop,wscale 2> (DF)
>>>>
>>>> _______________________________________________
>>>> Lista brasileira de usuários de shell script
>>>> Endereço de e-mail da lista: shell-script-pt@nongnu.org
>>>> Para se inscrever ou desinscrever acesse:
>>>> https://lists.nongnu.org/mailman/listinfo/shell-script-pt
>>>> Para ver os arquivos da lista (mensagens anteriores) e pesquisar
>>>> nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/
>>>>
>>>> NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por
>>>> favor utilize somente esta.
>>>
>>> _______________________________________________
>>> Lista brasileira de usuários de shell script
>>> Endereço de e-mail da lista: shell-script-pt@nongnu.org
>>> Para se inscrever ou desinscrever acesse:
>>> https://lists.nongnu.org/mailman/listinfo/shell-script-pt
>>> Para ver os arquivos da lista (mensagens anteriores) e pesquisar
>>> nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/
>>>
>>> NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor
>>> utilize somente esta.

_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------

reply via email to

[Prev in Thread] Current Thread [Next in Thread]