Added some detail taken from RIPE
This commit is contained in:
174
app.py
174
app.py
@@ -5,56 +5,79 @@ from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
app = Flask(__name__)
|
||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
|
||||
|
||||
RIPESTAT_BASE = "https://stat.ripe.net/data"
|
||||
|
||||
HTML_TEMPLATE = """<!doctype html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SolidData – IP & RIPE Lookup</title>
|
||||
<title>myip – IP & RIPE Lookup</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/static/favicon.png">
|
||||
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
|
||||
<link rel="stylesheet" href="/static/myip.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="card">
|
||||
{% if show_logo %}
|
||||
<a href="https://soliddata.cloud" class="logo-link" target="_blank" rel="noopener">
|
||||
<a href="https://www.netech-solution.it" class="logo-link" target="_blank" rel="noopener">
|
||||
<img src="/static/logo.png" class="logo" alt="Logo">
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<div class="badge">
|
||||
<span class="badge-dot"></span>
|
||||
<span>IP & RIPE Lookup</span>
|
||||
</div>
|
||||
|
||||
<h1 class="title">Il tuo IP pubblico è:</h1>
|
||||
|
||||
<div class="ip-wrapper">
|
||||
<span id="ip-value" class="ip">{{ ip }}</span>
|
||||
</div>
|
||||
|
||||
<button id="copy-btn" class="copy-btn copy-btn-below" type="button">
|
||||
<span class="copy-icon">📋</span>
|
||||
<span class="copy-label">Copia IP</span>
|
||||
</button>
|
||||
<div class="ip-wrapper">
|
||||
<span id="ip-value" class="ip">{{ ip }}</span>
|
||||
</div>
|
||||
|
||||
<button id="copy-btn" class="copy-btn copy-btn-below" type="button">
|
||||
<span class="copy-icon">📋</span>
|
||||
<span class="copy-label">Copia IP</span>
|
||||
</button>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
{% if ripe %}
|
||||
<div class="ripe-title">Informazioni RIPE</div>
|
||||
|
||||
{% if ripe.holder %}
|
||||
<div class="ripe-item"><strong>Provider:</strong> {{ ripe.holder }}</div>
|
||||
{% endif %}
|
||||
{% if ripe.prefix %}
|
||||
<div class="ripe-item"><strong>Prefisso:</strong> {{ ripe.prefix }}</div>
|
||||
<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 %}
|
||||
<div class="ripe-item"><strong>Routing Status:</strong> {{ ripe.routing_status }}</div>
|
||||
{% endif %}
|
||||
{% if ripe.reverse_dns %}
|
||||
<div class="ripe-item"><strong>Reverse DNS:</strong> {{ ripe.reverse_dns }}</div>
|
||||
{% endif %}
|
||||
{% if ripe.geoloc %}
|
||||
<div class="ripe-item">
|
||||
<strong>GeoLocation:</strong>
|
||||
{% if ripe.geoloc.code %}
|
||||
<img src="https://flagsapi.com/{{ ripe.geoloc.code }}/flat/24.png" class="flag-icon" alt="{{ ripe.geoloc.code }}">
|
||||
{% endif %}
|
||||
{{ ripe.geoloc.country }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if ripe.abuse %}
|
||||
<div class="ripe-item"><strong>Abuse Contact:</strong> {{ ripe.abuse }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="ripe-muted">Dati ottenuti tramite RIPEstat Data API.</div>
|
||||
{% else %}
|
||||
<div class="ripe-title">Informazioni RIPE</div>
|
||||
@@ -77,15 +100,18 @@ HTML_TEMPLATE = """<!doctype html>
|
||||
var ip = ipSpan.textContent.trim();
|
||||
if (!ip) return;
|
||||
|
||||
navigator.clipboard.writeText(ip).then(function () {
|
||||
var original = btn.querySelector(".copy-label").textContent;
|
||||
btn.classList.add("copy-btn-success");
|
||||
btn.querySelector(".copy-label").textContent = "Copiato!";
|
||||
setTimeout(function () {
|
||||
btn.classList.remove("copy-btn-success");
|
||||
btn.querySelector(".copy-label").textContent = original;
|
||||
}, 1500);
|
||||
}).catch(console.error);
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(ip).then(function () {
|
||||
var labelEl = btn.querySelector(".copy-label");
|
||||
var original = labelEl.textContent;
|
||||
btn.classList.add("copy-btn-success");
|
||||
labelEl.textContent = "Copiato!";
|
||||
setTimeout(function () {
|
||||
btn.classList.remove("copy-btn-success");
|
||||
labelEl.textContent = original;
|
||||
}, 1500);
|
||||
}).catch(console.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -93,50 +119,112 @@ HTML_TEMPLATE = """<!doctype html>
|
||||
</html>
|
||||
"""
|
||||
|
||||
RIPESTAT_BASE = "https://stat.ripe.net/data"
|
||||
|
||||
def get_client_ip():
|
||||
"""Determina l'IP reale del client dietro proxy / load balancer."""
|
||||
xff = request.headers.get("X-Forwarded-For", "")
|
||||
if xff:
|
||||
parts = [p.strip() for p in xff.split(",") if p.strip()]
|
||||
if parts:
|
||||
return parts[0]
|
||||
|
||||
xri = request.headers.get("X-Real-IP")
|
||||
if xri:
|
||||
return xri.strip()
|
||||
|
||||
return request.remote_addr or "Sconosciuto"
|
||||
|
||||
|
||||
def fetch_ripe_info(ip: str):
|
||||
"""Recupera informazioni RIPEstat estese per l'IP."""
|
||||
info = {
|
||||
"prefix": None,
|
||||
"asns": [],
|
||||
"holder": None,
|
||||
"routing_status": None,
|
||||
"reverse_dns": None,
|
||||
"geoloc": None,
|
||||
"abuse": None,
|
||||
}
|
||||
|
||||
try:
|
||||
ni_resp = requests.get(f"{RIPESTAT_BASE}/network-info/data.json", params={"resource": ip}, timeout=2)
|
||||
ni_resp.raise_for_status()
|
||||
ni_data = ni_resp.json().get("data", {})
|
||||
# 1. Network info (prefisso + ASN)
|
||||
ni = requests.get(
|
||||
f"{RIPESTAT_BASE}/network-info/data.json",
|
||||
params={"resource": ip},
|
||||
timeout=2,
|
||||
).json().get("data", {})
|
||||
|
||||
prefix = ni_data.get("prefix")
|
||||
asns = ni_data.get("asns") or []
|
||||
holder = None
|
||||
info["prefix"] = ni.get("prefix")
|
||||
asns = ni.get("asns") or []
|
||||
info["asns"] = [f"AS{a}" for a in asns]
|
||||
|
||||
# 2. AS overview (holder/provider)
|
||||
if asns:
|
||||
first_asn = asns[0]
|
||||
ao_resp = requests.get(f"{RIPESTAT_BASE}/as-overview/data.json", params={"resource": first_asn}, timeout=2)
|
||||
ao_resp.raise_for_status()
|
||||
holder = ao_resp.json().get("data", {}).get("holder")
|
||||
ao = requests.get(
|
||||
f"{RIPESTAT_BASE}/as-overview/data.json",
|
||||
params={"resource": asns[0]},
|
||||
timeout=2,
|
||||
).json().get("data", {})
|
||||
info["holder"] = ao.get("holder")
|
||||
|
||||
class R: pass
|
||||
r = R()
|
||||
r.prefix = prefix
|
||||
r.asns = [f"AS{x}" for x in asns] if asns else []
|
||||
r.holder = holder
|
||||
# 3. Routing status / visibility
|
||||
rs = requests.get(
|
||||
f"{RIPESTAT_BASE}/routing-status/data.json",
|
||||
params={"resource": ip},
|
||||
timeout=2,
|
||||
).json().get("data", {})
|
||||
info["routing_status"] = rs.get("status")
|
||||
|
||||
# 4. Reverse DNS
|
||||
rd = requests.get(
|
||||
f"{RIPESTAT_BASE}/reverse-dns/data.json",
|
||||
params={"resource": ip},
|
||||
timeout=2,
|
||||
).json().get("data", {}).get("result", [])
|
||||
info["reverse_dns"] = rd[0].get("name") if rd else None
|
||||
|
||||
# 5. GeoLocation
|
||||
gl = requests.get(
|
||||
f"{RIPESTAT_BASE}/geoloc/data.json",
|
||||
params={"resource": ip},
|
||||
timeout=2,
|
||||
).json().get("data", {})
|
||||
country = None
|
||||
if gl.get("locations"):
|
||||
country = gl["locations"][0].get("country", {})
|
||||
if country:
|
||||
info["geoloc"] = {
|
||||
"country": country.get("name"),
|
||||
"code": country.get("code"),
|
||||
}
|
||||
|
||||
# 6. Abuse Contact
|
||||
ac = requests.get(
|
||||
f"{RIPESTAT_BASE}/abuse-contact-finder/data.json",
|
||||
params={"resource": ip},
|
||||
timeout=2,
|
||||
).json().get("data", {})
|
||||
emails = ac.get("emails") or []
|
||||
info["abuse"] = emails[0] if emails else None
|
||||
|
||||
except Exception:
|
||||
# In caso di errore lasciamo info parziali / vuote
|
||||
pass
|
||||
|
||||
return info
|
||||
|
||||
return r if any([r.prefix, r.asns, r.holder]) else None
|
||||
except:
|
||||
return None
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
ip = get_client_ip()
|
||||
ripe = fetch_ripe_info(ip) if ip != "Sconosciuto" else None
|
||||
return render_template_string(HTML_TEMPLATE, ip=ip, ripe=ripe, show_logo=True)
|
||||
ripe_info = fetch_ripe_info(ip) if ip != "Sconosciuto" else None
|
||||
return render_template_string(
|
||||
HTML_TEMPLATE,
|
||||
ip=ip,
|
||||
ripe=ripe_info,
|
||||
show_logo=True,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
||||
|
||||
Reference in New Issue
Block a user