(scans)
| 5233 | </tr>`; |
| 5234 | }).join(''); |
| 5235 | const p = d.poison || {}; |
| 5236 | let poisonBanner = ''; |
| 5237 | if (p.verdict === 'hijacked') { |
| 5238 | poisonBanner = '<div class="mb-2 px-3 py-2 rounded bg-red-950/60 border border-red-800 text-red-300 text-sm">🛑 <strong>DNS poisoning / hijack detected</strong></div>'; |
| 5239 | } else if (p.verdict === 'suspicious') { |
| 5240 | poisonBanner = '<div class="mb-2 px-3 py-2 rounded bg-amber-950/50 border border-amber-800 text-amber-300 text-sm">⚠ <strong>Possible DNS tampering</strong> — review the signals below</div>'; |
| 5241 | } else if (p.verdict === 'clean') { |
| 5242 | poisonBanner = '<div class="mb-2 px-3 py-2 rounded bg-green-950/40 border border-green-900 text-green-400 text-sm">✓ No DNS poisoning signals</div>'; |
| 5243 | } |
| 5244 | const reasonsList = (p.reasons && p.reasons.length) |
| 5245 | ? '<ul class="text-xs text-gray-400 mb-2 list-disc pl-5">' + p.reasons.map(x => '<li>' + escapeHtml(x) + '</li>').join('') + '</ul>' |
| 5246 | : ''; |
| 5247 | const dohInfo = (p.doh && p.doh.checked) |
| 5248 | ? ' · DoH cross-check ' + (p.doh.mismatch ? '<span class="text-red-400">mismatch</span>' : '<span class="text-green-400">match</span>') |
| 5249 | : ''; |
| 5250 | const banner = d.consistent |
| 5251 | ? '<span class="text-green-400">✓ resolvers agree (shared answer)</span>' |
| 5252 | : '<span class="text-amber-300">⚠ resolvers returned disjoint answers — normal for CDN/anycast, but a hijack/split-DNS smell if unexpected</span>'; |
| 5253 | out.innerHTML = poisonBanner + reasonsList + `<p class="text-xs mb-2">${banner} · DNSSEC ${d.dnssec_ok ? '<span class="text-green-400">validated</span>' : '<span class="text-gray-500">not validated</span>'} |
| 5254 | · DoH ${d.doh_reachable ? '✓' : '✗'} · DoT ${d.dot_reachable ? '✓' : '✗'}${dohInfo}</p> |
| 5255 | <table class="min-w-full text-sm text-gray-300 whitespace-nowrap"> |
| 5256 | <thead><tr class="text-left text-xs uppercase text-gray-500"> |
| 5257 | <th class="px-3 py-1.5">Resolver</th><th class="px-3 py-1.5"></th><th class="px-3 py-1.5">Answers</th> |
| 5258 | <th class="px-3 py-1.5 text-right">Latency</th><th class="px-3 py-1.5 text-center">DNSSEC</th> |
| 5259 | </tr></thead><tbody>${rows}</tbody></table>`; |
| 5260 | } catch (e) { |
| 5261 | out.innerHTML = '<p class="text-sm text-red-400">Failed: ' + escapeHtml(e.message) + '</p>'; |
| 5262 | } finally { |
| 5263 | _ndBusy(btn, false); |
| 5264 | } |
| 5265 | } |
| 5266 | |
| 5267 | async function runPmtu() { |
| 5268 | const input = document.getElementById('pmtu-target'); |
| 5269 | const out = document.getElementById('pmtu-results'); |
| 5270 | const target = (input.value || '').trim(); |
| 5271 | if (!target) { input.focus(); return; } |
| 5272 | const btn = event && event.target ? event.target : null; |
| 5273 | _ndBusy(btn, true, 'Discovering…'); |
| 5274 | out.classList.remove('hidden'); |
| 5275 | out.innerHTML = '<p class="text-sm text-gray-400">Tracing path MTU to ' + escapeHtml(target) + '…</p>'; |
| 5276 | try { |
| 5277 | const d = await postAPI('/api/net/pmtu', { target: target }); |
| 5278 | if (!d.success) { |
| 5279 | out.innerHTML = d.missing_tool ? _ndMissingTool(d, 'runPmtu') |
| 5280 | : '<p class="text-sm text-red-400">Error: ' + escapeHtml(d.error || 'failed') + '</p>'; |
| 5281 | return; |
| 5282 | } |
| 5283 | const pmtu = d.pmtu != null ? d.pmtu + ' bytes' : 'unknown'; |
| 5284 | const verdict = d.pmtu == null |
| 5285 | ? '<span class="text-amber-300">⚠ could not measure</span>' |
| 5286 | : d.reduced |
| 5287 | ? '<span class="text-amber-300">⚠ below 1500 — MTU black-hole / tunnel overhead likely</span>' |
| 5288 | : '<span class="text-green-400">✓ full 1500-byte path</span>'; |
| 5289 | out.innerHTML = `<p class="mb-1">Path MTU: <strong>${escapeHtml(pmtu)}</strong> — ${verdict}</p> |
| 5290 | <p class="text-xs text-gray-400">${escapeHtml(d.note || '')}</p>`; |
| 5291 | } catch (e) { |
| 5292 | out.innerHTML = '<p class="text-sm text-red-400">Failed: ' + escapeHtml(e.message) + '</p>'; |
no test coverage detected