---
name: whois_lookup
kind: function
lang: py
domain: cybersecurity
version: "1.0.0"
purity: impure
signature: "def whois_lookup(dominio: str, timeout_s: float = 15.0) -> dict"
description: "Recoleccion OSINT pasiva de datos de registro de dominio via RDAP (reemplazo moderno de WHOIS sobre HTTP/JSON). Consulta https://rdap.org/domain/<dominio> con http_get_json y normaliza registrar, fechas de creacion/expiracion/ultimo cambio, nameservers, estados y entidades. Devuelve {found: False} si el dominio no existe (404)."
tags: [osint-passive, whois, rdap, recon, cybersecurity]
params:
  - name: dominio
    desc: "Dominio a consultar, ej. organic-machine.com. Vacio lanza RuntimeError."
  - name: timeout_s
    desc: "Segundos maximo de espera de la peticion HTTP a rdap.org (default 15.0)."
output: "dict normalizado con found (bool), registrar, creation_date, expiration_date, last_changed, nameservers (lista), status (lista), entities (lista de {handle, roles}) y raw (RDAP completo). Si el dominio no existe (HTTP 404) devuelve {found: False}."
uses_functions: ["http_get_json_py_infra"]
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: true
tests: ["test_normaliza_respuesta_rdap", "test_dominio_no_encontrado_404", "test_otro_error_http_se_propaga", "test_sin_registrar_ni_fechas", "test_dominio_vacio_lanza_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("organic-machine.com")
if info["found"]:
    print(info["registrar"])         # 'Example Registrar Inc.'
    print(info["creation_date"])     # '2020-01-15T10:00:00Z'
    print(info["expiration_date"])   # '2027-01-15T10:00:00Z'
    print(info["nameservers"])       # ['ns1.example.net', 'ns2.example.net']
    print(info["status"])            # ['client transfer prohibited']
else:
    print("dominio no registrado")
```

## Cuando usarla

Usala para obtener metadatos de registro de un dominio sin depender del CLI
`whois` (no instalado): edad del dominio, fecha de expiracion (dominios a
punto de caducar), registrar y nameservers autoritativos. Util en perfilado
pasivo, deteccion de dominios recien creados (typosquatting/phishing) y
validacion de propiedad.

## Gotchas

- RDAP no esta uniformemente desplegado en todos los TLD: algunos devuelven
  campos vacios o ni siquiera responden. Por eso los campos opcionales pueden
  quedar `None` y `nameservers`/`status`/`entities` listas vacias.
- rdap.org actua como bootstrap y redirige al servidor RDAP autoritativo del
  TLD; depende de su disponibilidad.
- El registrante (`entities` con rol distinto de `registrar`) suele estar
  redactado por privacy/GDPR: casi siempre solo veras `handle` y `roles`, sin
  datos personales.
- Un dominio no registrado devuelve `{"found": False}` (HTTP 404); cualquier
  otro error HTTP (rate limit 429, 5xx) se propaga como `RuntimeError`.
- Las fechas se devuelven tal cual las da RDAP (ISO 8601 UTC), sin parsear a
  objetos `datetime`.
