eb8dbf66a1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
69 lines
3.1 KiB
Markdown
69 lines
3.1 KiB
Markdown
---
|
|
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`.
|