(testType, data)
| 10421 | } |
| 10422 | async function fhrpTrustBaseline() { |
| 10423 | try { |
| 10424 | await postAPI('/api/net/fhrp-baseline', { action: 'reset' }); |
| 10425 | addConsoleMessage('FHRP baseline reset — re-learning current groups, speakers & priorities', 'info'); |
| 10426 | await runFhrpWatch(); |
| 10427 | } catch (e) { |
| 10428 | addConsoleMessage('Failed to reset FHRP baseline: ' + e.message, 'error'); |
| 10429 | } |
| 10430 | } |
| 10431 | |
| 10432 | // ---- BGP Path Watch (passive) ---------------------------------------------- |
| 10433 | const _BGP_VERDICT_STYLE = { |
| 10434 | clean: ['bg-green-950/40 border-green-900 text-green-400', '✓ No BGP anomalies detected'], |
| 10435 | weak_session: ['bg-amber-950/50 border-amber-800 text-amber-300', '⚠ BGP session without TCP-MD5/TCP-AO'], |
| 10436 | anomaly: ['bg-amber-950/50 border-amber-800 text-amber-300', '⚠ BGP anomaly — rogue peer / session reset / bogon / leak'], |
| 10437 | injection: ['bg-red-950/60 border-red-800 text-red-300', '🛑 BGP prefix / origin hijack detected'], |
| 10438 | storm: ['bg-red-950/60 border-red-800 text-red-300', '🛑 BGP route-churn / leak storm detected'], |
| 10439 | unknown: ['bg-slate-800 border-slate-700 text-slate-400', '— Could not determine'], |
| 10440 | }; |
| 10441 | function _bgpFillIfaces() { |
| 10442 | const sel = document.getElementById('bgp-iface'); |
| 10443 | if (!sel || sel.dataset.filled === '1') return Promise.resolve(); |
| 10444 | return fetchAPI('/api/net/interfaces').then(x => { |
| 10445 | (x.interfaces || []).forEach(i => { |
| 10446 | const o = document.createElement('option'); |
| 10447 | o.value = i.name; |
| 10448 | const tag = i.type === 'wifi' ? ' (WiFi)' : i.type === 'ethernet' ? ' (LAN)' : (i.type ? ' (' + i.type + ')' : ''); |
| 10449 | o.textContent = i.name + tag; |
| 10450 | sel.appendChild(o); |
| 10451 | }); |
| 10452 | sel.dataset.filled = '1'; |
| 10453 | }).catch(() => {}); |
| 10454 | } |
| 10455 | async function runBgpWatch() { |
| 10456 | const out = document.getElementById('bgp-results'); |
| 10457 | if (!out) return; |
| 10458 | const btn = (typeof event !== 'undefined' && event && event.target) ? event.target : null; |
| 10459 | const ifaceSel = document.getElementById('bgp-iface'); |
| 10460 | const iface = ifaceSel && ifaceSel.value ? ifaceSel.value : ''; |
| 10461 | const secsEl = document.getElementById('bgp-secs'); |
| 10462 | const secs = secsEl && secsEl.value ? secsEl.value : '15'; |
| 10463 | _ndBusy(btn, true, 'Listening…'); |
| 10464 | out.classList.remove('hidden'); |
| 10465 | out.innerHTML = '<p class="text-sm text-gray-400">Passively capturing BGP (TCP/179) on the segment…</p>'; |
| 10466 | try { |
| 10467 | _bgpFillIfaces(); |
| 10468 | const qs = '?seconds=' + encodeURIComponent(secs) + (iface ? '&interface=' + encodeURIComponent(iface) : ''); |
| 10469 | const d = await fetchAPI('/api/net/bgp-watch' + qs); |
| 10470 | if (!d || d.success === false) { |
no test coverage detected