(entries)
| 8345 | } |
| 8346 | |
| 8347 | // ---- DTP Watch (passive VLAN-hopping / switch-spoofing scanner) ------------- |
| 8348 | const _DTP_VERDICT_STYLE = { |
| 8349 | clean: ['bg-green-950/40 border-green-900 text-green-400', '✓ No DTP trunk negotiation — ports are not forming trunks here'], |
| 8350 | 'dtp-enabled': ['bg-amber-950/50 border-amber-800 text-amber-300', '⚠ DTP is enabled on this segment — disable with `switchport nonegotiate`'], |
| 8351 | 'trunk-negotiation': ['bg-amber-950/50 border-amber-800 text-amber-300', '⚠ DTP is negotiating trunks — a rogue host could VLAN-hop'], |
| 8352 | 'vlan-hop': ['bg-red-950/60 border-red-800 text-red-300', '🛑 VLAN HOP — trunk-forming DTP from a new speaker (switch spoofing)'], |
| 8353 | unknown: ['bg-slate-800 border-slate-700 text-slate-400', '— Could not determine'], |
| 8354 | }; |
| 8355 | function _dtpFillIfaces() { |
| 8356 | const sel = document.getElementById('dtp-iface'); |
| 8357 | if (!sel || sel.dataset.filled === '1') return Promise.resolve(); |
| 8358 | return fetchAPI('/api/net/interfaces').then(x => { |
| 8359 | (x.interfaces || []).forEach(i => { |
| 8360 | const o = document.createElement('option'); |
| 8361 | o.value = i.name; |
| 8362 | const tag = i.type === 'wifi' ? ' (WiFi)' : i.type === 'ethernet' ? ' (LAN)' : (i.type ? ' (' + i.type + ')' : ''); |
| 8363 | o.textContent = i.name + tag; |
| 8364 | sel.appendChild(o); |
| 8365 | }); |
| 8366 | sel.dataset.filled = '1'; |
| 8367 | }).catch(() => {}); |
| 8368 | } |
| 8369 | async function runDtpWatch() { |
no test coverage detected