#!/usr/bin/env bash # geolocate_ip # ------------ # Geolocaliza una IP o dominio usando la API pública de ip-api.com. # Muestra país, ciudad, ISP, ASN y detecta VPN/Proxy/Hosting. # # USO (directo): # geolocate_ip # # Depende de: curl, dig (para resolver dominios) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../shell/bash_colors.sh" source "$SCRIPT_DIR/../shell/bash_log.sh" bash_colors bash_log_init # ─── Constantes ─────────────────────────────────────────────────────────────── _GEOIP_API="http://ip-api.com/json" _GEOIP_FIELDS="status,message,country,countryCode,regionName,city,zip,lat,lon,isp,org,as,proxy,hosting,query" # ─── Funciones puras ────────────────────────────────────────────────────────── _geo_is_ip() { [[ "$1" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] } _geo_build_api_url() { local target="$1" echo "${_GEOIP_API}/${target}?fields=${_GEOIP_FIELDS}" } _geo_extract_field() { local json="$1" local key="$2" echo "$json" | grep -o "\"${key}\":[^,}]*" | cut -d: -f2- | tr -d '"' | xargs } # ─── Funciones de efecto ────────────────────────────────────────────────────── _geo_resolve_domain() { local domain="$1" dig +short A "$domain" 2>/dev/null | head -1 || true } _geo_fetch() { local target="$1" local url url="$(_geo_build_api_url "$target")" curl -s --max-time 10 "$url" 2>/dev/null } _geo_display_result() { local json="$1" local status status="$(_geo_extract_field "$json" "status")" if [[ "$status" != "success" ]]; then local msg msg="$(_geo_extract_field "$json" "message")" error "La API devolvió error: ${msg:-respuesta inesperada}" >&2 return 1 fi local ip_queried country country_code region city zip lat lon isp org asn proxy hosting ip_queried="$(_geo_extract_field "$json" "query")" country="$(_geo_extract_field "$json" "country")" country_code="$(_geo_extract_field "$json" "countryCode")" region="$(_geo_extract_field "$json" "regionName")" city="$(_geo_extract_field "$json" "city")" zip="$(_geo_extract_field "$json" "zip")" lat="$(_geo_extract_field "$json" "lat")" lon="$(_geo_extract_field "$json" "lon")" isp="$(_geo_extract_field "$json" "isp")" org="$(_geo_extract_field "$json" "org")" asn="$(_geo_extract_field "$json" "as")" proxy="$(_geo_extract_field "$json" "proxy")" hosting="$(_geo_extract_field "$json" "hosting")" echo "" echo -e "${PURPLE}════════════════════════════════════════════════════════════${NC}" echo -e " ${CYAN}IP consultada:${NC} ${ip_queried}" echo -e " ${CYAN}País:${NC} ${country} (${country_code})" echo -e " ${CYAN}Región:${NC} ${region}" echo -e " ${CYAN}Ciudad:${NC} ${city} ${zip}" echo -e " ${CYAN}Coordenadas:${NC} ${lat}, ${lon}" echo -e " ${CYAN}ISP:${NC} ${isp}" echo -e " ${CYAN}Organización:${NC} ${org}" echo -e " ${CYAN}ASN:${NC} ${asn}" echo "" if [[ "$proxy" == "true" ]]; then echo -e " ${RED}[!] VPN / Proxy detectado${NC}" fi if [[ "$hosting" == "true" ]]; then echo -e " ${YELLOW}[i] Hosting / datacenter detectado${NC}" fi if [[ "$proxy" != "true" && "$hosting" != "true" ]]; then echo -e " ${GREEN}[ok] Sin indicios de VPN, Proxy o Tor${NC}" fi echo -e "${PURPLE}════════════════════════════════════════════════════════════${NC}" } # ─── Punto de entrada ───────────────────────────────────────────────────────── geolocate_ip() { local target="$1" if [[ -z "$target" ]]; then error "geolocate_ip: se requiere una IP o dominio como argumento" >&2 return 1 fi if ! command -v curl &>/dev/null; then error "geolocate_ip: 'curl' no está instalado (sudo apt install curl)" >&2 return 1 fi local query_target="$target" if ! _geo_is_ip "$target"; then info "Resolviendo dominio a IP..." local resolved resolved="$(_geo_resolve_domain "$target")" if [[ -z "$resolved" ]]; then error "geolocate_ip: no se pudo resolver '$target'" >&2 return 1 fi info "Resuelto: ${target} -> ${resolved}" query_target="$resolved" fi info "Consultando geolocalización de ${query_target}..." local json json="$(_geo_fetch "$query_target")" if [[ -z "$json" ]]; then error "geolocate_ip: no se obtuvo respuesta de la API" >&2 return 1 fi _geo_display_result "$json" } # Ejecutar si se llama directamente if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then geolocate_ip "$@" fi