feat(web/attackers): surface ASN + AS name on cards and detail
Attacker list cards gain an AS<number> chip with the AS description on hover. Attacker detail page adds an AS row beside ORIGIN — same shape as the existing country/source pair so operators can read "this attacker is in DE on AS24940 Hetzner" at a glance instead of having to grep the IP into a separate tool. Both fields collapse to "unknown" when the IP isn't BGP-announced (CGNAT, dark space, RFC1918), matching the existing pattern for country resolution.
This commit is contained in:
@@ -61,6 +61,9 @@ interface AttackerData {
|
|||||||
commands: { service: string; decky: string; command: string; timestamp: string }[];
|
commands: { service: string; decky: string; command: string; timestamp: string }[];
|
||||||
country_code: string | null;
|
country_code: string | null;
|
||||||
country_source: string | null;
|
country_source: string | null;
|
||||||
|
asn: number | null;
|
||||||
|
as_name: string | null;
|
||||||
|
asn_source: string | null;
|
||||||
ptr_record: string | null;
|
ptr_record: string | null;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
behavior: AttackerBehavior | null;
|
behavior: AttackerBehavior | null;
|
||||||
@@ -1262,6 +1265,26 @@ const AttackerDetail: React.FC = () => {
|
|||||||
<span className="dim">unknown</span>
|
<span className="dim">unknown</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="dim">AS: </span>
|
||||||
|
{attacker.asn != null ? (
|
||||||
|
<span className="matrix-text">
|
||||||
|
AS{attacker.asn}
|
||||||
|
{attacker.as_name && (
|
||||||
|
<span className="dim" style={{ marginLeft: 6, fontSize: '0.75rem' }}>
|
||||||
|
{attacker.as_name}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{attacker.asn_source && (
|
||||||
|
<span className="dim" style={{ marginLeft: 6, fontSize: '0.75rem' }}>
|
||||||
|
({attacker.asn_source})
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="dim">unknown</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className="dim">REVERSE DNS: </span>
|
<span className="dim">REVERSE DNS: </span>
|
||||||
{attacker.ptr_record ? (
|
{attacker.ptr_record ? (
|
||||||
|
|||||||
@@ -92,6 +92,16 @@
|
|||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
.attackers-root .ak-card .ak-asn {
|
||||||
|
font-size: 0.62rem;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
padding: 1px 6px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
color: var(--matrix);
|
||||||
|
opacity: 0.75;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
.attackers-root .ak-stats {
|
.attackers-root .ak-stats {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ interface AttackerEntry {
|
|||||||
commands: any[];
|
commands: any[];
|
||||||
country_code: string | null;
|
country_code: string | null;
|
||||||
country_source: string | null;
|
country_source: string | null;
|
||||||
|
asn: number | null;
|
||||||
|
as_name: string | null;
|
||||||
|
asn_source: string | null;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +212,14 @@ const Attackers: React.FC = () => {
|
|||||||
<div className="ak-meta">
|
<div className="ak-meta">
|
||||||
<span>First: {new Date(a.first_seen).toLocaleDateString()}</span>
|
<span>First: {new Date(a.first_seen).toLocaleDateString()}</span>
|
||||||
<span>Last: {timeAgo(a.last_seen)}</span>
|
<span>Last: {timeAgo(a.last_seen)}</span>
|
||||||
|
{a.asn != null && (
|
||||||
|
<span
|
||||||
|
className="ak-asn"
|
||||||
|
title={a.as_name ? `${a.as_name}${a.asn_source ? ` (${a.asn_source})` : ''}` : undefined}
|
||||||
|
>
|
||||||
|
AS{a.asn}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
{a.is_traversal && <span className="chip violet" style={{ fontSize: '0.6rem' }}>TRAVERSAL</span>}
|
{a.is_traversal && <span className="chip violet" style={{ fontSize: '0.6rem' }}>TRAVERSAL</span>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user