()
| 7686 | if (d.reasons && d.reasons.length) { |
| 7687 | html += '<ul class="text-xs text-gray-400 mt-2 list-disc pl-5">' + |
| 7688 | d.reasons.map(r => '<li>' + escapeHtml(r) + '</li>').join('') + '</ul>'; |
| 7689 | } |
| 7690 | out.innerHTML = html; |
| 7691 | } catch (e) { |
| 7692 | out.innerHTML = '<p class="text-sm text-red-400">Failed: ' + escapeHtml(e.message) + '</p>'; |
| 7693 | } finally { |
| 7694 | _ndBusy(btn, false); |
| 7695 | } |
| 7696 | } |
| 7697 | async function ospfTrustBaseline() { |
| 7698 | try { |
| 7699 | await postAPI('/api/net/ospf-baseline', { action: 'reset' }); |
| 7700 | addConsoleMessage('OSPF baseline reset — re-learning current routers & originators', 'info'); |
| 7701 | await runOspfWatch(); |
| 7702 | } catch (e) { |
| 7703 | addConsoleMessage('Failed to reset OSPF baseline: ' + e.message, 'error'); |
| 7704 | } |
| 7705 | } |
| 7706 | |
| 7707 | // ---- STP/BPDU Watch (passive spanning-tree security scanner) ---------------- |
| 7708 | const _STP_VERDICT_STYLE = { |
| 7709 | clean: ['bg-green-950/40 border-green-900 text-green-400', '✓ Spanning-tree root(s) and bridges match the baseline'], |
| 7710 | 'topology-change': ['bg-amber-950/50 border-amber-800 text-amber-300', '⚠ Topology-change churn — MAC tables being flushed (instability / TCN flood)'], |
| 7711 | 'bpdu-flood': ['bg-red-950/60 border-red-800 text-red-300', '🛑 BPDU flood — spanning-tree reconvergence storm (DoS)'], |
| 7712 | 'rogue-bridge': ['bg-red-950/60 border-red-800 text-red-300', '🛑 New STP bridge on the segment — unexpected switch / spoofed bridge'], |
| 7713 | 'root-hijack': ['bg-red-950/60 border-red-800 text-red-300', '🛑 ROOT HIJACK — a superior BPDU is taking over the root bridge (L2 MITM)'], |
| 7714 | unknown: ['bg-slate-800 border-slate-700 text-slate-400', '— Could not determine'], |
| 7715 | }; |
| 7716 | function _stpFillIfaces() { |
| 7717 | const sel = document.getElementById('stp-iface'); |
nothing calls this directly
no test coverage detected