LinuxParty

Inicio desactivadoInicio desactivadoInicio desactivadoInicio desactivadoInicio desactivado
 

Si llevas años utilizando geoiplookup para identificar el país o la procedencia de una dirección IP, quizá haya llegado el momento de revisar de dónde salen sus datos. En LinuxParty hemos preparado geoipshscript.sh: una alternativa en Bash que consulta un servicio en línea y conserva la presentación tradicional para facilitar su integración en nuestros scripts.

Hay herramientas que terminan formando parte del paisaje de cualquier terminal Linux. geoiplookup es una de ellas: una dirección IP, una orden y una respuesta sencilla que podemos leer directamente o procesar con otras utilidades.

El problema aparece cuando seguimos consultando bases de datos antiguas. El programa puede ejecutarse perfectamente y, aun así, ofrecer información desfasada.

MaxMind retiró sus bases de datos GeoIP Legacy en mayo de 2022 y recomienda migrar a GeoIP2 y libmaxminddb. Por tanto, conviene comprobar qué base de datos utiliza nuestra instalación antes de confiar en sus resultados.

Nuestra alternativa: Bash, curl y jq

Para nuestras consultas habituales hemos desarrollado geoipshscript.sh, un script Bash que obtiene los datos de geolocalización mediante una petición HTTPS a ipwho.is y transforma su respuesta JSON en una salida familiar.

Su funcionamiento es sencillo:

  1. Recibe una dirección IPv4 o IPv6.
  2. Consulta el servicio mediante curl.
  3. Comprueba que la respuesta sea válida y que la consulta haya tenido éxito.
  4. Extrae los campos con jq.
  5. Presenta país, ubicación y sistema autónomo con las etiquetas tradicionales.

Si lo ejecutamos sin argumentos, consulta la IP pública de salida de nuestra conexión.

No necesita mantener una base de datos local: la información procede del proveedor en el momento de la consulta. Esto evita depender del fichero antiguo que tengamos instalado, aunque la exactitud sigue dependiendo de los datos del servicio.

Hemos conservado la presentación de geoiplookup

Una de nuestras prioridades era mantener una salida reconocible. Muchos administradores ya tienen pequeñas automatizaciones que buscan determinadas líneas o extraen sus campos.

Por eso conservamos estas tres etiquetas:

GeoIP Country Edition:
GeoIP City Edition, Rev 1:
GeoIP ASNum Edition:

La estructura de salida es la siguiente:

GeoIP Country Edition: código de país, país
GeoIP City Edition, Rev 1: país, código de región, región, ciudad, código postal, latitud, longitud, 0, 0
GeoIP ASNum Edition: ASnúmero organización

Cuando falta información, el script utiliza N/A. Si no recibe un ASN válido, muestra:

GeoIP ASNum Edition: IP Address not found

El objetivo es preservar los posibles scripts que utilizaban esta forma de presentación y reducir los cambios necesarios para adaptarlos.

Hay un detalle que debemos tener en cuenta: mantenemos las etiquetas y una estructura similar, pero no se trata de una compatibilidad completa con todas las opciones y campos de geoiplookup. Los dos ceros finales de la línea de ciudad son valores de relleno; no representan información obtenida del proveedor. También conviene revisar las automatizaciones que interpreten posiciones concretas, códigos de región o nombres de ubicación.

Qué necesitamos para utilizarlo

El script requiere Bash, curl y jq.

En Debian, Ubuntu y distribuciones derivadas podemos instalar las dependencias con:

sudo apt install curl jq

En Fedora:

sudo dnf install curl jq

Una vez guardado el código en ~/bin/geoipshscript.sh, le damos permisos de ejecución:

chmod +x ~/bin/geoipshscript.sh

Y ya podemos consultar una dirección:

~/bin/geoipshscript.sh 8.8.8.8

También admite IPv6:

~/bin/geoipshscript.sh 2001:4860:4860::8888

Para consultar nuestra propia IP pública:

~/bin/geoipshscript.sh

La ayuda está disponible mediante:

~/bin/geoipshscript.sh --help

Cómo adaptarlo a nuestras automatizaciones

Si antes teníamos una consulta como esta:

geoiplookup "$ip"

Podemos sustituirla por:

"$HOME/bin/geoipshscript.sh" "$ip"

Los filtros basados en las etiquetas conservadas pueden seguir resultando útiles. Por ejemplo, para seleccionar únicamente la línea del país:

"$HOME/bin/geoipshscript.sh" "$ip" |
    awk '/^GeoIP Country Edition:/'

Antes de incorporarlo a una tarea programada, debemos comprobar que los campos que consume nuestro script mantienen el significado esperado y gestionar los posibles errores de consulta.

Controles para evitar respuestas engañosas

El script comprueba que las dependencias estén instaladas, limita los caracteres admitidos en la dirección y establece tiempos máximos de conexión y respuesta.

Además, verifica que el proveedor devuelva un objeto JSON y confirme el éxito de la consulta. Los errores se escriben en la salida de error y el programa termina con un código distinto de cero.

También limpia caracteres de control y comas dentro de los campos de texto para mantener una línea por registro y unos separadores estables.

Qué cambia al utilizar un servicio en línea

Frente a una consulta sobre una base de datos local, esta alternativa necesita conexión a Internet y envía la dirección consultada al proveedor.

Está sujeta a la disponibilidad, las condiciones de uso y los límites de consultas de ipwho.is. Antes de utilizarla para procesar grandes registros o realizar consultas masivas, conviene revisar la documentación del servicio.

La ubicación obtenida debe interpretarse como una estimación: no identifica el domicilio de una persona ni garantiza que el equipo esté físicamente en la ciudad indicada.

Para consultas puntuales desde la terminal y automatizaciones sencillas que acepten esa dependencia de red, geoipshscript.sh es una alternativa práctica al viejo geoiplookup: renovamos la fuente de información y conservamos su presentación clásica para facilitar la transición.

#!/usr/bin/env bash
# Script: geoipshscript.sh
set -euo pipefail

# Uso:
#   ./geoipshscript.sh 8.8.8.8
#   ./geoipshscript.sh
#
# Sin argumento consulta la IP púlica de salida.
# La IP consultada se envía ipwho.is mediante HTTPS.

error() {
    printf 'Error: %s\n' "$*" >&2
    exit 1
}

ayuda() {
    printf 'Uso: %s [IPv4|IPv6]\n' "${0##*/}"
    printf 'Sin argumento consulta tu IP púlica.\n'
}

if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
    ayuda
    exit 0
fi

(( $# <= 1 )) || {
    ayuda >&2
    exit 1
}

for programa in curl jq; do
    command -v "$programa" >/dev/null 2>&1 ||
        error "falta $programa. Instálalo para continuar."
done

ip="${1:-}"

# Evitar que el argumento introduzca rutas o parámetros en la URL.
# La validación definitiva de la dirección corresponde al proveedor.
if [[ -n "$ip" && ! "$ip" =~ ^[0-9A-Fa-f:.]+$ ]]; then
    error "indica una dirección IPv4 o IPv6 válida."
fi

if ! respuesta="$(
    curl \
        --silent \
        --show-error \
        --fail \
        --proto '=https' \
        --connect-timeout 5 \
        --max-time 20 \
        --get \
        --data-urlencode 'lang=en' \
        "https://ipwho.is/${ip}"
)"; then
    error "No se ha podido consultar el servicio. Comprueba la conexión o el límite de consultas."
fi

if ! jq -e 'type == "object"' >/dev/null 2>&1 <<< "$respuesta"; then
    error "El proveedor no ha devuelto un objeto JSON válido."
fi

if ! jq -e '.success == true' >/dev/null <<< "$respuesta"; then
    mensaje="$(
        jq -r '
            (.message // "Consulta rechazada o IP sin datos")
            | tostring
            | gsub("[[:cntrl:]]"; " ")
        ' <<< "$respuesta"
    )"
    error "$mensaje"
fi

jq -r '
    # Mantener una línea por registro y separadores estables.
    def campo:
        if . == null or . == "" then
            "N/A"
        else
            tostring
            | gsub("[[:cntrl:]]"; " ")
            | gsub(","; " ")
        end;

    def coordenada:
        if type == "number" then tostring else "N/A" end;

    (.connection | if type == "object" then . else {} end) as $conexion
    |
    "GeoIP Country Edition: \(.country_code | campo), \(.country | campo)",

    (
        "GeoIP City Edition, Rev 1: " +
        ([
            (.country_code | campo),
            (.region_code | campo),
            (.region | campo),
            (.city | campo),
            (.postal | campo),
            (.latitude | coordenada),
            (.longitude | coordenada),
            "0",
            "0"
        ] | join(", "))
    ),

    (
        "GeoIP ASNum Edition: " +
        (
            if $conexion.asn == null
               or $conexion.asn == ""
               or $conexion.asn == 0
            then
                "IP Address not found"
            else
                "AS" +
                ($conexion.asn | campo | sub("^AS"; "")) +
                " " +
                (
                    (
                        $conexion.org
                        | if . == null or . == ""
                          then $conexion.isp
                          else .
                          end
                    ) | campo
                )
            end
        )
    )
' <<< "$respuesta"

Escribir un comentario

Código de seguridad
Refescar



Redes:



   

 

Encuestas

¿Cuál es tu OS de Escritorio en Casa? - 2026

Suscribete / Newsletter

Suscribete a nuestras Newsletter y periódicamente recibirás un resumen de las noticias publicadas.

Donar a LinuxParty

 

Dona a LInuxParty

Donar 10

Donar 20

 

 

Tutorial de Linux

Formulario de acceso