resolver todos os endereços IP na saída do comando usando ferramentas de linha de comando padrão

8

Eu tenho vários arquivos de log que contêm vários endereços IP. Eu adoraria poder canalizar os dados através de um programa que corresponda e resolva endereços IP.

IE cat / var / log / somelogfile | hospedeiro

que viraria uma linha como

10:45 acessado por 10.13.13.10

para dentro

10:45 acessado por myhostname.intranet

Meu pensamento é que pode haver uma maneira de fazer isso com uma combinação de sed e host, mas não tenho idéia de como fazê-lo. Sei que poderia escrever um script simples que o faria, mas preferiria usar ferramentas internas, se possível. Alguma sugestão?

Daniel
fonte
2
A razão pela qual isso normalmente não é feito é porque pode ser bastante lento fazer todas essas consultas PTR. Um script multiencadeado (em, por exemplo, Python) que armazena em cache os resultados (possivelmente persistentemente) funcionaria melhor.
Alexios18:

Respostas:

8

Aqui está uma solução rápida e suja para isso em Python. Faz cache (incluindo cache negativo), mas não é necessário realizar threads e não é a coisa mais rápida que você já viu. Se você salvá-lo como algo como rdns, pode chamá-lo assim:

zcat /var/log/some-file.gz | rdns
# ... or ...
rdns /var/log/some-file /var/log/some-other-file # ...

A execução anotará os endereços IP com seus registros PTR no local:

$ echo "74.125.132.147, 64.34.119.12." | rdns
74.125.132.147 (rdns: wb-in-f147.1e100.net), 64.34.119.12 (rdns: stackoverflow.com).

E aqui está a fonte:

#!/usr/bin/env python

import sys, re, socket

cache = dict()

def resolve(x):
    key = x.group(0)
    try:
        return "%s (rdns: %s)" % (key, cache[key])
    except KeyError:
        try:
            cache[key] = socket.gethostbyaddr(key)[0]
        except socket.herror:
            cache[key] = '?'
        return "%s (rdns: %s)" % (key, cache[key])

for f in [open(x) for x in sys.argv[1:]] or [sys.stdin]:
    for line in f:
        sys.stdout.write(re.sub("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", resolve, line))

# End of file.

Observe: isso não é exatamente o que você procura após a carta (usando 'ferramentas padrão'). Mas isso provavelmente ajuda mais do que um hack que resolve todos os endereços IP sempre que são encontrados. Com mais algumas linhas, você pode até fazer cache de resultados persistentemente, o que ajudaria com invocações repetidas.

Alexios
fonte
Obrigado pelo script. Faz exatamente o que eu estava procurando. Eu esperava encontrar uma solução que não exigisse a escrita de um script, mas esta provavelmente é a próxima melhor coisa.
Daniel
3

Eu usaria jdresolve -n -a

Empacotado para debian, etc. também disponível em:

https://github.com/jdrowell/jdresolve

    O jdresolve resolve endereços IP para nomes de host. Qualquer formato de arquivo é
    suportado, incluindo aqueles em que a linha não começa com o IP
    endereço.

Uso-o há mais de uma década para resolver logs do apache, logs do squid e qualquer outra coisa com muitos endereços IP que precisam ser resolvidos. Funciona bem, de forma confiável e rápida, e pode armazenar em cache pesquisas de execuções anteriores.

cas
fonte
2

um script bash no qual você pode inserir seu arquivo de log e canalizar.

#!/bin/bash

while read input; do

    for arg in $( echo $input ); do
            match=$(echo "$arg" | grep -P '([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])' )
            if [ "x${match}" = "x" ]; then
                    printf "%-s" "$arg "
            else
                    dns=$( host $arg | tail -1 | awk '{print $NF}' 2>/dev/null )
                    if [ "${dns}" == "3(NXDOMAIN)" ]; then
                            printf "%-s" "$arg "
                    else
                            if [ "x${dns}" == "x" ]; then
                                    printf "%-s" "$arg "
                            else
                                    printf "%-s" "$dns "
                            fi
                    fi
            fi
    done
done
printf "\n"

saída se parece com:

tk-air:~ tim$ echo "10:45 accessed by 8.8.8.8" | ./get-dns 
10:45 accessed by FWDR-8.FWDR-8.FWDR-8.FWDR-8. 

tk-air:~ tim$ echo "10:45 accessed by 8.8.8.8 26 times" | ./get-dns 
10:45 accessed by FWDR-8.FWDR-8.FWDR-8.FWDR-8. 26 times 
Tim Kennedy
fonte
2

Um rápido perl:

perl -MSocket -pe 's/(\d+\.){3}\d+/"$&\[".gethostbyaddr(inet_aton($&), AF_INET)."]"/ge'
Stéphane Chazelas
fonte
1

Se o formato do log estiver exibindo consistentemente o mesmo que você mostra acima, você poderá fazer isso muito sujo echo 10:45 accessed by 10.13.13.10|awk '{print $4}'|nslookup

Tim
fonte