Improved version
This commit is contained in:
206
app.py
206
app.py
@@ -53,12 +53,6 @@ HTML_TEMPLATE = """<!doctype html>
|
|||||||
{% if ripe.holder %}
|
{% if ripe.holder %}
|
||||||
<div class="ripe-item"><strong>Provider:</strong> {{ ripe.holder }}</div>
|
<div class="ripe-item"><strong>Provider:</strong> {{ ripe.holder }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if ripe.prefix %}
|
|
||||||
<div class="ripe-item"><strong>Prefisso annunciato:</strong> {{ ripe.prefix }}</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if ripe.asns %}
|
|
||||||
<div class="ripe-item"><strong>ASN:</strong> {{ ripe.asns | join(', ') }}</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if ripe.routing_status %}
|
{% if ripe.routing_status %}
|
||||||
<div class="ripe-item"><strong>Routing Status:</strong> {{ ripe.routing_status }}</div>
|
<div class="ripe-item"><strong>Routing Status:</strong> {{ ripe.routing_status }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -78,6 +72,26 @@ HTML_TEMPLATE = """<!doctype html>
|
|||||||
<div class="ripe-item"><strong>Abuse Contact:</strong> {{ ripe.abuse }}</div>
|
<div class="ripe-item"><strong>Abuse Contact:</strong> {{ ripe.abuse }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if ripe.netname %}
|
||||||
|
<div class="ripe-item"><strong>Netname:</strong> {{ ripe.netname }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if ripe.org_name %}
|
||||||
|
<div class="ripe-item"><strong>Organisation:</strong> {{ ripe.org_name }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if ripe.rir %}
|
||||||
|
<div class="ripe-item"><strong>RIR:</strong> {{ ripe.rir }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if ripe.block %}
|
||||||
|
<div class="ripe-item"><strong>IP Block:</strong> {{ ripe.block }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if ripe.rir %}
|
||||||
|
<div class="ripe-item"><strong>RIR:</strong> {{ ripe.rir }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="ripe-muted">Dati ottenuti tramite RIPEstat Data API.</div>
|
<div class="ripe-muted">Dati ottenuti tramite RIPEstat Data API.</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="ripe-title">Informazioni RIPE</div>
|
<div class="ripe-title">Informazioni RIPE</div>
|
||||||
@@ -160,9 +174,9 @@ def get_client_ip():
|
|||||||
return request.remote_addr or "Sconosciuto"
|
return request.remote_addr or "Sconosciuto"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_ripe_info(ip: str):
|
def fetch_ripe_info(ip: str):
|
||||||
"""Recupera informazioni RIPEstat estese per l'IP."""
|
"""Recupera informazioni RIPEstat estese per l'IP, compatibili col template."""
|
||||||
|
|
||||||
info = {
|
info = {
|
||||||
"prefix": None,
|
"prefix": None,
|
||||||
"asns": [],
|
"asns": [],
|
||||||
@@ -171,76 +185,173 @@ def fetch_ripe_info(ip: str):
|
|||||||
"reverse_dns": None,
|
"reverse_dns": None,
|
||||||
"geoloc": None,
|
"geoloc": None,
|
||||||
"abuse": None,
|
"abuse": None,
|
||||||
|
# campi extra che stai già usando in pagina
|
||||||
|
"block": None,
|
||||||
|
"rir": None,
|
||||||
|
"country": None, # non usato ora in UI
|
||||||
|
"country_whois": None, # usato in "Country (WHOIS)"
|
||||||
|
"netname": None, # usato in "Netname"
|
||||||
|
"org_name": None,
|
||||||
|
"raw": {}, # solo per debug
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 1. Network info (prefisso + ASN)
|
# 0) PREFIX-OVERVIEW: blocco IP + RIR + stato announced/routed
|
||||||
ni = requests.get(
|
po_resp = requests.get(
|
||||||
|
f"{RIPESTAT_BASE}/prefix-overview/data.json",
|
||||||
|
params={"resource": ip},
|
||||||
|
timeout=2,
|
||||||
|
)
|
||||||
|
po = po_resp.json().get("data", {})
|
||||||
|
info["raw"]["prefix_overview"] = po
|
||||||
|
|
||||||
|
if po:
|
||||||
|
# es: 77.43.64.0/18
|
||||||
|
info["block"] = po.get("resource")
|
||||||
|
# es: block.desc = "RIPE NCC (Status: ALLOCATED)"
|
||||||
|
block = po.get("block") or {}
|
||||||
|
desc = block.get("desc")
|
||||||
|
if desc:
|
||||||
|
# prendiamo la parte prima della parentesi
|
||||||
|
info["rir"] = desc.split("(")[0].strip()
|
||||||
|
|
||||||
|
# announced / routed (bool)
|
||||||
|
info["routing_status"] = None
|
||||||
|
if po.get("announced") is not None:
|
||||||
|
info["routing_status"] = "Announced" if po.get("announced") else "Not announced"
|
||||||
|
|
||||||
|
# prefix principale
|
||||||
|
if not info["prefix"]:
|
||||||
|
info["prefix"] = po.get("resource")
|
||||||
|
|
||||||
|
# 1) NETWORK-INFO: prefisso + ASNs
|
||||||
|
ni_resp = requests.get(
|
||||||
f"{RIPESTAT_BASE}/network-info/data.json",
|
f"{RIPESTAT_BASE}/network-info/data.json",
|
||||||
params={"resource": ip},
|
params={"resource": ip},
|
||||||
timeout=2,
|
timeout=2,
|
||||||
).json().get("data", {})
|
)
|
||||||
|
ni = ni_resp.json().get("data", {})
|
||||||
|
info["raw"]["network_info"] = ni
|
||||||
|
|
||||||
|
if ni:
|
||||||
|
if not info["prefix"]:
|
||||||
info["prefix"] = ni.get("prefix")
|
info["prefix"] = ni.get("prefix")
|
||||||
asns = ni.get("asns") or []
|
asns = ni.get("asns") or []
|
||||||
info["asns"] = [f"AS{a}" for a in asns]
|
info["asns"] = [f"AS{a}" for a in asns]
|
||||||
|
|
||||||
# 2. AS overview (holder/provider)
|
# 2) AS-OVERVIEW: holder/provider (es: "AS-IRIDEOS - Retelit Digital Services S.p.A.")
|
||||||
if asns:
|
if ni and ni.get("asns"):
|
||||||
ao = requests.get(
|
ao_resp = requests.get(
|
||||||
f"{RIPESTAT_BASE}/as-overview/data.json",
|
f"{RIPESTAT_BASE}/as-overview/data.json",
|
||||||
params={"resource": asns[0]},
|
params={"resource": ni["asns"][0]},
|
||||||
timeout=2,
|
timeout=2,
|
||||||
).json().get("data", {})
|
)
|
||||||
info["holder"] = ao.get("holder")
|
ao = ao_resp.json().get("data", {})
|
||||||
|
info["raw"]["as_overview"] = ao
|
||||||
|
if ao:
|
||||||
|
info["holder"] = ao.get("holder") or info["holder"]
|
||||||
|
|
||||||
# 3. Routing status / visibility
|
# 3) ROUTING-STATUS: origin AS + visibilità
|
||||||
rs = requests.get(
|
rs_resp = requests.get(
|
||||||
f"{RIPESTAT_BASE}/routing-status/data.json",
|
f"{RIPESTAT_BASE}/routing-status/data.json",
|
||||||
params={"resource": ip},
|
params={"resource": info["prefix"] or ip},
|
||||||
timeout=2,
|
timeout=2,
|
||||||
).json().get("data", {})
|
)
|
||||||
info["routing_status"] = rs.get("status")
|
rs = rs_resp.json().get("data", {})
|
||||||
|
info["raw"]["routing_status"] = rs
|
||||||
|
|
||||||
# 4. Reverse DNS
|
if rs:
|
||||||
rd = requests.get(
|
origins = rs.get("origins") or []
|
||||||
|
origin_as = None
|
||||||
|
if origins:
|
||||||
|
origin_as = origins[0].get("origin")
|
||||||
|
v4 = (rs.get("visibility") or {}).get("v4") or {}
|
||||||
|
peers = v4.get("ris_peers_seeing")
|
||||||
|
total = v4.get("total_ris_peers")
|
||||||
|
|
||||||
|
if origin_as and peers is not None and total is not None:
|
||||||
|
info["routing_status"] = f"Origin AS{origin_as}, visibility {peers}/{total} peers"
|
||||||
|
elif origin_as:
|
||||||
|
info["routing_status"] = f"Origin AS{origin_as}"
|
||||||
|
|
||||||
|
# 4) REVERSE-DNS
|
||||||
|
rd_resp = requests.get(
|
||||||
f"{RIPESTAT_BASE}/reverse-dns/data.json",
|
f"{RIPESTAT_BASE}/reverse-dns/data.json",
|
||||||
params={"resource": ip},
|
params={"resource": ip},
|
||||||
timeout=2,
|
timeout=2,
|
||||||
).json().get("data", {}).get("result", [])
|
)
|
||||||
info["reverse_dns"] = rd[0].get("name") if rd else None
|
rd = rd_resp.json().get("data", {}).get("result", [])
|
||||||
|
info["raw"]["reverse_dns"] = rd
|
||||||
|
if rd:
|
||||||
|
info["reverse_dns"] = rd[0].get("name")
|
||||||
|
|
||||||
# 5. GeoLocation
|
# 5) GEOLOC (usa located_resources → locations)
|
||||||
gl = requests.get(
|
gl_resp = requests.get(
|
||||||
f"{RIPESTAT_BASE}/geoloc/data.json",
|
f"{RIPESTAT_BASE}/geoloc/data.json",
|
||||||
params={"resource": ip},
|
params={"resource": ip},
|
||||||
timeout=2,
|
timeout=2,
|
||||||
).json().get("data", {})
|
)
|
||||||
country = None
|
gl = gl_resp.json().get("data", {})
|
||||||
if gl.get("locations"):
|
info["raw"]["geoloc"] = gl
|
||||||
country = gl["locations"][0].get("country", {})
|
|
||||||
if country:
|
located_resources = gl.get("located_resources") or []
|
||||||
|
if located_resources:
|
||||||
|
first_res = located_resources[0]
|
||||||
|
locs = first_res.get("locations") or []
|
||||||
|
if locs:
|
||||||
|
loc0 = locs[0]
|
||||||
|
city = loc0.get("city")
|
||||||
|
country_code = loc0.get("country")
|
||||||
|
# flagsapi vuole il codice (es: IT)
|
||||||
|
label = country_code
|
||||||
|
if city and country_code:
|
||||||
|
label = f"{city}, {country_code}"
|
||||||
|
|
||||||
info["geoloc"] = {
|
info["geoloc"] = {
|
||||||
"country": country.get("name"),
|
"country": label,
|
||||||
"code": country.get("code"),
|
"code": country_code,
|
||||||
}
|
}
|
||||||
|
|
||||||
# 6. Abuse Contact
|
# 6) ABUSE CONTACT (abuse_contacts, non emails)
|
||||||
ac = requests.get(
|
ac_resp = requests.get(
|
||||||
f"{RIPESTAT_BASE}/abuse-contact-finder/data.json",
|
f"{RIPESTAT_BASE}/abuse-contact-finder/data.json",
|
||||||
params={"resource": ip},
|
params={"resource": ip},
|
||||||
timeout=2,
|
timeout=2,
|
||||||
).json().get("data", {})
|
)
|
||||||
emails = ac.get("emails") or []
|
ac = ac_resp.json().get("data", {})
|
||||||
info["abuse"] = emails[0] if emails else None
|
info["raw"]["abuse"] = ac
|
||||||
|
|
||||||
|
abuse_contacts = ac.get("abuse_contacts") or []
|
||||||
|
if abuse_contacts:
|
||||||
|
info["abuse"] = abuse_contacts[0]
|
||||||
|
|
||||||
|
# 7) WHOIS: netname, country (WHOIS), org / descr
|
||||||
|
whois_resp = requests.get(
|
||||||
|
f"{RIPESTAT_BASE}/whois/data.json",
|
||||||
|
params={"resource": ip},
|
||||||
|
timeout=3,
|
||||||
|
)
|
||||||
|
whois = whois_resp.json().get("data", {})
|
||||||
|
info["raw"]["whois"] = whois
|
||||||
|
|
||||||
|
records = whois.get("records") or []
|
||||||
|
for block in records:
|
||||||
|
for entry in block:
|
||||||
|
k = entry.get("key", "").lower()
|
||||||
|
v = entry.get("value", "")
|
||||||
|
|
||||||
|
if k == "netname" and not info["netname"]:
|
||||||
|
info["netname"] = v
|
||||||
|
elif k == "country" and not info["country_whois"]:
|
||||||
|
info["country_whois"] = v
|
||||||
|
elif k in ("org-name", "organisation", "descr") and not info["org_name"]:
|
||||||
|
info["org_name"] = v
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
# In caso di errore lasciamo info parziali / vuote
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
ip = get_client_ip()
|
ip = get_client_ip()
|
||||||
@@ -261,5 +372,16 @@ def debug():
|
|||||||
all_headers=dict(request.headers),
|
all_headers=dict(request.headers),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.route("/ripe-debug")
|
||||||
|
def ripe_debug():
|
||||||
|
from flask import jsonify
|
||||||
|
ip = get_client_ip()
|
||||||
|
ripe_info = fetch_ripe_info(ip) if ip != "Sconosciuto" else None
|
||||||
|
return jsonify({
|
||||||
|
"ip": ip,
|
||||||
|
"ripe": ripe_info,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0", port=8000)
|
app.run(host="0.0.0.0", port=8000)
|
||||||
|
|||||||
Reference in New Issue
Block a user