Skip to content

Instantly share code, notes, and snippets.

@juliancantillo
Created November 4, 2025 02:23
Show Gist options
  • Select an option

  • Save juliancantillo/d25c9b841dba530e4ccdc26a5be4c77b to your computer and use it in GitHub Desktop.

Select an option

Save juliancantillo/d25c9b841dba530e4ccdc26a5be4c77b to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script para geolocalizar direcciones IP y generar tabla LaTeX usando GeoIP2
Uso: python3 geolocalize_ips.py < ips.txt
Requiere: pip install geoip2
Descarga la base de datos GeoLite2-City.mmdb de MaxMind
"""
import sys
import geoip2.database
import math
import os
from typing import List, Dict, Tuple
class GeoLocalizador:
"""Clase para geolocalizar IPs y calcular distancias"""
def __init__(self, db_path=None):
self.ips_data = []
self.distancia_acumulada = 0
self.latitud_anterior = None
self.longitud_anterior = None
# Buscar base de datos GeoIP2
if db_path is None:
# Buscar en ubicaciones comunes
possible_paths = [
'GeoLite2-City.mmdb',
'/usr/share/GeoIP/GeoLite2-City.mmdb',
'/usr/local/share/GeoIP/GeoLite2-City.mmdb',
os.path.expanduser('~/GeoLite2-City.mmdb'),
]
for path in possible_paths:
if os.path.exists(path):
db_path = path
break
if db_path is None:
raise FileNotFoundError(
"No se encontró GeoLite2-City.mmdb. "
"Descárgalo de https://dev.maxmind.com/geoip/geolite2-free-geolocation-data"
)
self.reader = geoip2.database.Reader(db_path)
print(f"[*] Base de datos GeoIP2 cargada: {db_path}", file=sys.stderr)
def __del__(self):
"""Cierra el lector de base de datos al destruir el objeto"""
if hasattr(self, 'reader'):
self.reader.close()
def obtener_ubicacion(self, ip: str) -> Dict:
"""
Obtiene la ubicación geográfica de una IP usando GeoIP2
Args:
ip (str): Dirección IP a geolocalizar
Returns:
dict: Diccionario con información de ubicación
"""
try:
response = self.reader.city(ip)
# Obtener datos de ubicación
ciudad = response.city.name or 'Desconocida'
pais = response.country.name or 'Desconocido'
latitud = response.location.latitude or 0
longitud = response.location.longitude or 0
# GeoIP2 no proporciona ISP en la versión gratuita
# Para obtener ISP necesitas GeoLite2-ASN o GeoIP2-ISP (de pago)
isp = 'N/A'
return {
'ip': ip,
'ciudad': ciudad,
'pais': pais,
'latitud': latitud,
'longitud': longitud,
'isp': isp,
'exito': True
}
except geoip2.errors.AddressNotFoundError:
return {
'ip': ip,
'ciudad': 'No encontrada',
'pais': 'No encontrado',
'latitud': 0,
'longitud': 0,
'isp': 'N/A',
'exito': False
}
except Exception as e:
return {
'ip': ip,
'ciudad': 'Error',
'pais': str(e),
'latitud': 0,
'longitud': 0,
'isp': 'N/A',
'exito': False
}
def calcular_distancia_haversine(self, lat1: float, lon1: float,
lat2: float, lon2: float) -> float:
"""
Calcula la distancia entre dos puntos usando la fórmula de Haversine
Args:
lat1, lon1: Latitud y longitud del punto 1
lat2, lon2: Latitud y longitud del punto 2
Returns:
float: Distancia en kilómetros
"""
R = 6371 # Radio de la Tierra en km
lat1_rad = math.radians(lat1)
lat2_rad = math.radians(lat2)
delta_lat = math.radians(lat2 - lat1)
delta_lon = math.radians(lon2 - lon1)
a = math.sin(delta_lat/2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon/2)**2
c = 2 * math.asin(math.sqrt(a))
distancia = R * c
return distancia
def procesar_ips(self, ips: List[str]) -> List[Dict]:
"""
Procesa una lista de IPs y obtiene su ubicación
Args:
ips (list): Lista de direcciones IP
Returns:
list: Lista de diccionarios con información de geolocalización
"""
self.distancia_acumulada = 0
self.latitud_anterior = None
self.longitud_anterior = None
for i, ip in enumerate(ips, 1):
print(f"[*] Procesando IP {i}/{len(ips)}: {ip}", file=sys.stderr)
ubicacion = self.obtener_ubicacion(ip)
# Calcular distancia acumulada
if ubicacion['exito'] and self.latitud_anterior is not None:
dist = self.calcular_distancia_haversine(
self.latitud_anterior,
self.longitud_anterior,
ubicacion['latitud'],
ubicacion['longitud']
)
self.distancia_acumulada += dist
elif ubicacion['exito']:
self.distancia_acumulada = 0
ubicacion['distancia_acumulada'] = round(self.distancia_acumulada, 2)
ubicacion['salto'] = i
# Actualizar coordenadas anteriores
if ubicacion['exito']:
self.latitud_anterior = ubicacion['latitud']
self.longitud_anterior = ubicacion['longitud']
self.ips_data.append(ubicacion)
return self.ips_data
def generar_tabla_latex(self) -> str:
"""
Genera la tabla LaTeX con los resultados de geolocalización
Returns:
str: Tabla LaTeX formateada
"""
tabla = r"\begin{table}[H]" + "\n"
tabla += r"\centering" + "\n"
tabla += r"\caption{Geolocalizacion de Routers en la Ruta}" + "\n"
tabla += r"\begin{tabular}{|c|c|c|c|c|c|c|}" + "\n"
tabla += r"\hline" + "\n"
tabla += r"\textbf{Salto} & \textbf{IP} & \textbf{Ciudad} & \textbf{Pais} & \textbf{Latitud} & \textbf{Longitud} & \textbf{Dist. Ac. (km)} \\" + "\n"
tabla += r"\hline" + "\n"
for dato in self.ips_data:
salto = dato['salto']
ip = dato['ip']
ciudad = dato['ciudad']
pais = dato['pais']
latitud = round(dato['latitud'], 4)
longitud = round(dato['longitud'], 4)
dist_ac = dato['distancia_acumulada']
# Formatear para LaTeX (escapar caracteres especiales)
ciudad = ciudad.replace('_', r'\_')
pais = pais.replace('_', r'\_')
tabla += f"{salto} & {ip} & {ciudad} & {pais} & {latitud} & {longitud} & {dist_ac} \\\\\n"
tabla += r"\hline" + "\n"
tabla += r"\end{tabular}" + "\n"
tabla += r"\end{table}" + "\n"
return tabla
def main():
"""Función principal"""
print("[*] Geolocalizador de IPs v1.0", file=sys.stderr)
print("[*] Leyendo IPs del stdin...", file=sys.stderr)
# Leer IPs del stdin
ips = []
try:
for linea in sys.stdin:
ip = linea.strip()
if ip and not ip.startswith('#'): # Ignorar líneas vacías y comentarios
ips.append(ip)
except KeyboardInterrupt:
print("\n[!] Interrupción del usuario", file=sys.stderr)
sys.exit(1)
if not ips:
print("[!] No se encontraron IPs válidas", file=sys.stderr)
sys.exit(1)
print(f"[*] Se encontraron {len(ips)} IPs para procesar", file=sys.stderr)
# Procesar IPs
geolocalizador = GeoLocalizador()
geolocalizador.procesar_ips(ips)
# Generar tabla LaTeX
tabla_latex = geolocalizador.generar_tabla_latex()
# Mostrar resultados
print("\n" + "="*80, file=sys.stderr)
print("[✓] Tabla LaTeX generada exitosamente", file=sys.stderr)
print("="*80 + "\n", file=sys.stderr)
# Imprimir tabla en stdout
print(tabla_latex)
# Mostrar resumen
print(f"\n% Resumen: {len(ips)} IPs procesadas", file=sys.stderr)
print(f"% Distancia total acumulada: {geolocalizador.distancia_acumulada:.2f} km", file=sys.stderr)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment