feat(sniffer): IP-ID sequence classifier (random/incremental/zero/constant)
Adds a per-source-IP rolling sample buffer (deque, maxlen=8) for IP-ID values seen on attacker SYNs and a stdlib-only classifier in decnet/sniffer/seq_class.py. Each new SYN appends ip.id and re-classifies the buffer; the result is logged on tcp_syn_fingerprint events alongside sample count. The dedup key now folds in ipid_class so a transition from 'unknown' to a definitive verdict emits exactly one fresh event instead of being suppressed by the old (os|options) key. Profiler rollup carries the latest non-'unknown' label into attacker.tcp_fingerprint. UI surfaces it as a colour-coded tag in the TCP STACK panel: random neutral, incremental amber, zero/constant green (the strong signal).
This commit is contained in:
@@ -22,6 +22,7 @@ interface AttackerBehavior {
|
||||
tos?: number | null;
|
||||
dscp?: number | null;
|
||||
ecn?: number | null;
|
||||
ipid_class?: string | null;
|
||||
} | null;
|
||||
retransmit_count: number;
|
||||
behavior_class: string | null;
|
||||
@@ -145,6 +146,18 @@ const HashRow: React.FC<{ label: string; value?: string | null }> = ({ label, va
|
||||
);
|
||||
};
|
||||
|
||||
// Random ISN/IP-ID is the modern default; non-random patterns are
|
||||
// fingerprinting gold (legacy stacks, custom raw-socket tools).
|
||||
const seqClassColor = (cls: string): string | undefined => {
|
||||
switch (cls) {
|
||||
case 'random': return undefined; // neutral, expected
|
||||
case 'incremental': return '#e5c07b'; // amber — uncommon
|
||||
case 'zero':
|
||||
case 'constant': return '#98c379'; // green — strong signal
|
||||
default: return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const Tag: React.FC<{ children: React.ReactNode; color?: string }> = ({ children, color }) => (
|
||||
<span style={{
|
||||
fontSize: '0.7rem', padding: '2px 8px', letterSpacing: '1px',
|
||||
@@ -755,6 +768,9 @@ const TcpStackBlock: React.FC<{ b: AttackerBehavior }> = ({ b }) => {
|
||||
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
|
||||
{fp.has_sack && <Tag>SACK</Tag>}
|
||||
{fp.has_timestamps && <Tag>TS</Tag>}
|
||||
{fp.ipid_class && fp.ipid_class !== 'unknown' && (
|
||||
<Tag color={seqClassColor(fp.ipid_class)}>IPID:{fp.ipid_class.toUpperCase()}</Tag>
|
||||
)}
|
||||
</div>
|
||||
{fp.options_sig && (
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user