()
| 10204 | addConsoleMessage('IS-IS baseline reset — re-learning current routers & prefixes', 'info'); |
| 10205 | await runIsisWatch(); |
| 10206 | } catch (e) { |
| 10207 | addConsoleMessage('Failed to reset IS-IS baseline: ' + e.message, 'error'); |
| 10208 | } |
| 10209 | } |
| 10210 | |
| 10211 | // ---- EIGRP Watch (passive Cisco IGP routing-security scanner) --------------- |
| 10212 | const _EIGRP_VERDICT_STYLE = { |
| 10213 | clean: ['bg-green-950/40 border-green-900 text-green-400', '✓ No EIGRP anomalies detected'], |
| 10214 | 'weak-auth': ['bg-amber-950/50 border-amber-800 text-amber-300', '⚠ EIGRP without HMAC authentication — exposed to route injection'], |
| 10215 | anomaly: ['bg-amber-950/50 border-amber-800 text-amber-300', '⚠ EIGRP anomaly — K-value / AS mismatch'], |
| 10216 | storm: ['bg-red-950/60 border-red-800 text-red-300', '🛑 EIGRP flooding storm detected'], |
| 10217 | 'rogue-router': ['bg-red-950/60 border-red-800 text-red-300', '🛑 Rogue EIGRP speaker — adjacency spoofing'], |
| 10218 | injection: ['bg-red-950/60 border-red-800 text-red-300', '🛑 EIGRP route/next-hop injection detected'], |
| 10219 | unknown: ['bg-slate-800 border-slate-700 text-slate-400', '— Could not determine'], |
| 10220 | }; |
| 10221 | function _eigrpFillIfaces() { |
| 10222 | const sel = document.getElementById('eigrp-iface'); |
| 10223 | if (!sel || sel.dataset.filled === '1') return Promise.resolve(); |
| 10224 | return fetchAPI('/api/net/interfaces').then(x => { |
| 10225 | (x.interfaces || []).forEach(i => { |
| 10226 | const o = document.createElement('option'); |
| 10227 | o.value = i.name; |
| 10228 | const tag = i.type === 'wifi' ? ' (WiFi)' : i.type === 'ethernet' ? ' (LAN)' : (i.type ? ' (' + i.type + ')' : ''); |
| 10229 | o.textContent = i.name + tag; |
| 10230 | sel.appendChild(o); |
| 10231 | }); |
| 10232 | sel.dataset.filled = '1'; |
| 10233 | }).catch(() => {}); |
| 10234 | } |
| 10235 | async function runEigrpWatch() { |
| 10236 | const out = document.getElementById('eigrp-results'); |
| 10237 | if (!out) return; |
| 10238 | const btn = (typeof event !== 'undefined' && event && event.target) ? event.target : null; |
| 10239 | const ifaceSel = document.getElementById('eigrp-iface'); |
| 10240 | const iface = ifaceSel && ifaceSel.value ? ifaceSel.value : ''; |
| 10241 | const secsEl = document.getElementById('eigrp-secs'); |
| 10242 | const secs = secsEl && secsEl.value ? secsEl.value : '15'; |
| 10243 | _ndBusy(btn, true, 'Listening…'); |
| 10244 | out.classList.remove('hidden'); |
| 10245 | out.innerHTML = '<p class="text-sm text-gray-400">Passively capturing EIGRP on the segment…</p>'; |
| 10246 | try { |
| 10247 | _eigrpFillIfaces(); |
| 10248 | const qs = '?seconds=' + encodeURIComponent(secs) + (iface ? '&interface=' + encodeURIComponent(iface) : ''); |
| 10249 | const d = await fetchAPI('/api/net/eigrp-watch' + qs); |
| 10250 | if (!d || d.success === false) { |
| 10251 | const msg = (d && d.error) || 'failed'; |
| 10252 | let extra = ''; |
| 10253 | if (d && d.missing_tool) extra = ' <button onclick="installNetTool(\'tcpdump\', this, runEigrpWatch)" class="ml-2 underline text-cyan-400">Install tcpdump</button>'; |
| 10254 | out.innerHTML = '<p class="text-sm text-red-400">Error: ' + escapeHtml(msg) + extra + '</p>'; |
| 10255 | return; |
| 10256 | } |
nothing calls this directly
no test coverage detected