resuelva todas las direcciones IP en la salida del comando usando herramientas de línea de comando estándar

8

Tengo varios archivos de registro que contienen un montón de direcciones IP. Me encantaría poder canalizar los datos a través de un programa que coincidiría y resolvería las direcciones IP.

IE cat / var / log / somelogfile | anfitrión

que convertiría una línea como

10:45 accedido por 10.13.13.10

dentro

10:45 accedido por myhostname.intranet

Mi pensamiento es que podría haber una manera de hacer esto con una combinación de sed y host, pero no tengo idea de cómo hacerlo. Sé que podría escribir un script simple que lo hiciera, pero preferiría poder usar herramientas integradas si es posible. ¿Alguna sugerencia?

Daniel
fuente
2
La razón por la que esto no se hace normalmente es porque puede ser bastante lento hacer todas esas consultas PTR. Un script de subprocesos múltiples (en, por ejemplo, Python) que almacena en caché los resultados (posiblemente de forma persistente) funcionaría mejor.
Alexios

Respuestas:

8

Aquí hay una solución rápida y sucia para esto en Python. Realiza el almacenamiento en caché (incluido el almacenamiento en caché negativo), pero no el enhebrado y no es lo más rápido que has visto. Si lo guarda como algo así rdns, puede llamarlo así:

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

Al ejecutarlo, se anotarán las direcciones IP con sus registros PTR en el lugar:

$ 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).

Y aquí está la fuente:

#!/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.

Tenga en cuenta: esto no es exactamente lo que busca al pie de la letra (usando 'herramientas estándar'). Pero probablemente lo ayude más que un truco que resuelve cada dirección IP cada vez que se encuentra. Con unas pocas líneas más, incluso puede hacer que guarde en caché sus resultados de forma persistente, lo que ayudaría a repetir las invocaciones.

Alexios
fuente
Gracias por el guion. Hace exactamente lo que estaba buscando. Esperaba encontrar una solución que no requiriera escribir un script, pero esta es probablemente la mejor opción.
Daniel
3

Yo usaría jdresolve -n -a

Empaquetado para debian, etc. también disponible en:

https://github.com/jdrowell/jdresolve

    jdresolve resuelve las direcciones IP a nombres de host. Cualquier formato de archivo es
    compatible, incluidos aquellos en los que la línea no comienza con la IP
    habla a.

Lo he estado usando durante más de una década para resolver registros de apache, registros de calamar y cualquier otra cosa con muchas direcciones IP que deben resolverse. Funciona bien, de manera confiable y rápida, y puede almacenar en caché las búsquedas de ejecuciones anteriores.

cas
fuente
2

un script bash en el que puede capturar su archivo de registro y canalizarlo.

#!/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"

la salida se ve así:

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
fuente
2

Una rápida perl:

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

Si el formato de registro muestra constantemente lo mismo que muestra arriba, puede hacerlo realmente sucio con echo 10:45 accessed by 10.13.13.10|awk '{print $4}'|nslookup

Tim
fuente