--- name: whois_lookup kind: function lang: py domain: cybersecurity version: "2.0.0" purity: impure signature: "def whois_lookup(target: str, timeout_s: int = 30) -> dict" description: "Lookup WHOIS de un dominio o IP via el CLI `whois` del sistema (apt). Ejecuta `whois ` como subproceso, captura el stdout completo en raw y parsea best-effort (case-insensitive, tolerante a ausencias) registrar, registrant_country, creation_date, expiry_date, updated_date y name_servers. Devuelve siempre un dict {status: ok|error}; nunca lanza excepciones. OSINT pasivo: util para perfilado de dominios, deteccion de typosquatting/phishing y validacion de propiedad." tags: [recon, whois, osint-passive, cybersecurity] params: - name: target desc: "Dominio (ej. google.com) o direccion IP a consultar. Vacio devuelve status error." - name: timeout_s desc: "Segundos maximo de espera del subproceso whois (default 30)." output: "dict. En exito: {status: 'ok', target, raw (stdout completo del whois, SIEMPRE presente), registrar, registrant_country, creation_date, expiry_date, updated_date, name_servers (lista de strings en minusculas)}. Campos no encontrados quedan None; name_servers vacio = []. Para IPs varios campos de dominio quedan None. En fallo: {status: 'error', error: str, target}." uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_py_core" imports: [] tested: true tests: ["test_parsea_campos_comunes", "test_campos_ausentes_quedan_none", "test_raw_siempre_presente", "test_target_vacio_devuelve_error"] test_file_path: "python/functions/cybersecurity/whois_lookup_test.py" file_path: "python/functions/cybersecurity/whois_lookup.py" --- ## Ejemplo ```python import sys, os sys.path.insert(0, os.path.join("python", "functions")) from cybersecurity import whois_lookup info = whois_lookup("google.com") if info["status"] == "ok": print(info["registrar"]) # 'MarkMonitor Inc.' print(info["registrant_country"]) # 'US' print(info["creation_date"]) # '1997-09-15T04:00:00Z' print(info["expiry_date"]) # '2028-09-14T04:00:00Z' print(info["name_servers"]) # ['ns1.google.com', 'ns2.google.com', ...] # info["raw"] tiene el texto whois completo para guardar en OSINT else: print("fallo:", info["error"]) ``` ## Cuando usarla Usala cuando necesites los datos de registro crudos de un dominio o IP via el CLI `whois` clasico: registrar, pais del registrante, edad del dominio (fecha de creacion), fecha de expiracion (dominios a punto de caducar) y nameservers. Ideal en perfilado pasivo OSINT, deteccion de dominios recien creados (typosquatting / phishing) y para conservar el texto WHOIS completo (`raw`) como evidencia. Para datos estructurados JSON modernos, prefiere `rdap_lookup_py_cybersecurity`; ambas se complementan. ## Gotchas - IMPURA: hace red. El servidor WHOIS del TLD/registrar puede tardar o fallar; por eso hay `timeout_s` (default 30) y los timeouts devuelven `{"status": "error", ...}` sin lanzar. - El formato WHOIS **no esta estandarizado**: varia por TLD y por registrar. El parseo es best-effort con multiples labels alternativos (`Creation Date` / `created` / `Registered on`, etc.). Cualquier campo puede quedar `None` aunque el dato exista bajo un label que no contemplamos — el texto completo siempre esta en `raw`. - Para **IPs**, muchos campos de dominio (registrar, creation_date, name_servers) no existen y quedan `None` / `[]`; lo relevante esta en `raw` (rango, org, abuse contact). - Muchos registros estan redactados por privacy/GDPR: el registrante personal raramente aparece; suele verse solo el registrar. - `whois` a menudo escribe en stdout incluso con codigo de retorno != 0 (avisos, rate-limit parciales). Solo se considera error duro cuando el stdout esta totalmente vacio. - Requiere el binario `whois` instalado (`apt install whois`). Si falta, devuelve status error claro en vez de lanzar. ## Capability growth log - v2.0.0 (2026-06-14) — reescrita sobre el CLI `whois` (antes RDAP via HTTP). Nueva firma `(target: str, timeout_s: int = 30)`, acepta dominios e IPs, estilo dict `{status: ok|error}` sin excepciones (alineado con el grupo recon). La variante RDAP/JSON ahora vive en `rdap_lookup_py_cybersecurity`.