Files
ip-address/DNS Resolver Pro
2026-01-12 15:29:41 +03:00

346 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DNS Resolver Pro</title>
<link rel="icon" href="https://rockblack.pro/images/favicon.ico" type="image/x-icon">
<style>
body {
font-family: 'Helvetica Neue', 'Segoe UI', Arial, sans-serif;
margin: 0 auto;
padding: 30px;
max-width: 800px;
background: #0f0f0f;
color: #fff;
line-height: 1.6;
}
body.light-mode {
background: #f8f9fa;
color: #333;
}
h2 {
text-align: center;
font-size: 2.2em;
margin-bottom: 30px;
color: #4CAF50;
}
.input-group {
margin: 20px 0;
}
textarea {
width: 100%;
height: 150px;
padding: 15px;
border-radius: 8px;
border: 2px solid #2d2d2d;
background: #1a1a1a;
color: #fff;
font-family: 'Courier New', monospace;
}
body.light-mode textarea {
background: #fff;
border-color: #ddd;
color: #333;
}
.controls {
display: flex;
gap: 15px;
flex-wrap: wrap;
margin: 25px 0;
justify-content: center;
}
select, button {
padding: 12px 20px;
border-radius: 8px;
border: none;
font-weight: 600;
cursor: pointer;
}
select {
background: #1a1a1a;
color: #fff;
border: 2px solid #4CAF50;
}
body.light-mode select {
background: #fff;
border-color: #2196F3;
color: #333;
}
button {
background: linear-gradient(135deg, #4CAF50, #45a049);
color: white;
}
.theme-toggle {
background: linear-gradient(135deg, #673AB7, #512DA8);
}
pre {
background: #1a1a1a;
padding: 20px;
border-radius: 8px;
white-space: pre-wrap;
border: 2px solid #2d2d2d;
font-family: 'Courier New', monospace;
}
body.light-mode pre {
background: #fff;
border-color: #ddd;
}
.progress-container {
width: 100%;
height: 20px;
background-color: #1a1a1a;
border-radius: 10px;
margin: 20px 0;
overflow: hidden;
display: none;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #4CAF50, #45a049);
width: 0%;
transition: width 0.3s ease;
text-align: center;
color: white;
font-size: 12px;
line-height: 20px;
}
body.light-mode .progress-container {
background-color: #eee;
}
body.light-mode .progress-bar {
background: linear-gradient(90deg, #2196F3, #1976D2);
}
</style>
</head>
<body>
<h2>🔍 DNS Resolver Pro</h2>
<div class="input-group">
<textarea id="domains" placeholder="Введите домены каждый с новой строки"></textarea>
</div>
<div class="progress-container">
<div class="progress-bar" id="progressBar">0%</div>
</div>
<div class="controls">
<select id="format">
<option value="standard">IPv4</option>
<option value="keenetic">Keenetic</option>
<option value="keenetic_clear">Keenetic route</option>
<option value="keenetic_ip_min">Keenetic route Min</option>
</select>
<button onclick="resolveDomains()">🚀 Найти IP</button>
<button onclick="saveToTxt()">💾 Сохранить в TXT</button>
<button class="theme-toggle" onclick="toggleTheme()">🌓 Сменить тему</button>
</div>
<pre id="result">Результаты появятся здесь...</pre>
<script>
function normalizeDomain(input) {
// Обработка URL (https://example.com)
if (input.includes('://')) {
try {
const url = new URL(input);
return url.hostname;
} catch (e) {
return input;
}
}
// Обработка формата: 0: "example.com"
const matchIndex = input.match(/^\s*\d+\s*:\s*"([^"]+)"\s*$/);
if (matchIndex && matchIndex[1]) {
return matchIndex[1];
}
// Обработка формата: "example.com",
const matchQuotes = input.match(/^\s*"([^"]+)"\s*,?\s*$/);
if (matchQuotes && matchQuotes[1]) {
return matchQuotes[1];
}
return input.trim();
}
async function fetchDNSFromResolver(resolverName, url) {
try {
const options = (resolverName === 'Cloudflare')
? { headers: { "accept": "application/dns-json" } }
: {};
const response = await fetch(url, options);
const data = await response.json();
return { resolver: resolverName, data };
} catch (error) {
return { resolver: resolverName, error: error.message };
}
}
async function resolveDomainWithResolvers(domain) {
const resolvers = [
{ name: "Google", url: `https://dns.google/resolve?name=${domain}&type=A` },
{ name: "Cloudflare", url: `https://cloudflare-dns.com/dns-query?name=${domain}&type=A` }
];
const promises = resolvers.map(r => fetchDNSFromResolver(r.name, r.url));
return await Promise.all(promises);
}
async function resolveDomains() {
const domainsText = document.getElementById("domains").value;
const rawLines = domainsText.split('\n').filter(line => line.trim() !== "");
const domains = rawLines.map(normalizeDomain).filter(domain => domain !== "");
const format = document.getElementById("format").value;
const progressContainer = document.querySelector('.progress-container');
const progressBar = document.getElementById('progressBar');
progressContainer.style.display = 'block';
progressBar.style.width = '0%';
progressBar.textContent = '0%';
let output = "";
if (domains.length === 0) {
document.getElementById("result").textContent = "Пожалуйста, введите хотя бы один домен.";
progressContainer.style.display = 'none';
return;
}
const totalDomains = domains.length;
let processed = 0;
const updateProgress = () => {
const percent = Math.round((processed / totalDomains) * 100);
progressBar.style.width = `${percent}%`;
progressBar.textContent = `${percent}%`;
if (percent === 100) {
setTimeout(() => {
progressContainer.style.display = 'none';
}, 500);
}
};
if (format === "keenetic_clear") {
const uniqueIPs = new Set();
for (let domain of domains) {
try {
const results = await resolveDomainWithResolvers(domain);
results.forEach(result => {
if (result.data?.Answer) {
result.data.Answer
.filter(ans => ans.type === 1)
.forEach(ans => uniqueIPs.add(ans.data));
}
});
} catch (error) {}
processed++;
updateProgress();
}
output = Array.from(uniqueIPs)
.map(ip => `route add ${ip} mask 255.255.255.255 0.0.0.0`)
.join('\n');
} else if (format === "keenetic_ip_min") {
const uniqueIPs = new Set();
for (let domain of domains) {
try {
const results = await resolveDomainWithResolvers(domain);
results.forEach(result => {
if (result.data?.Answer) {
result.data.Answer
.filter(ans => ans.type === 1)
.forEach(ans => uniqueIPs.add(ans.data));
}
});
} catch (error) {}
processed++;
updateProgress();
}
// Группировка IP в подсети /24
const cidrMap = new Map();
uniqueIPs.forEach(ip => {
if (ip === "0.0.0.0" || ip === "255.255.255.255") return;
const octets = ip.split('.').map(Number);
const network = `${octets[0]}.${octets[1]}.${octets[2]}.0/24`;
cidrMap.set(network, true);
});
// Сортировка подсетей
const sortedCidrs = Array.from(cidrMap.keys()).sort((a, b) => {
const aParts = a.split('.').map(Number);
const bParts = b.split('.').map(Number);
for (let i = 0; i < 3; i++) {
if (aParts[i] !== bParts[i]) {
return aParts[i] - bParts[i];
}
}
return 0;
});
output = sortedCidrs
.map(cidr => `route add ${cidr.split('/')[0]} mask 255.255.255.0 0.0.0.0`)
.join('\n');
} else {
for (let domain of domains) {
output += `Домен: ${domain}\n`;
try {
const results = await resolveDomainWithResolvers(domain);
results.forEach(result => {
output += ` [${result.resolver}]\n`;
if (result.error) {
output += ` Ошибка: ${result.error}\n`;
} else if (result.data?.Answer) {
const aRecords = result.data.Answer.filter(ans => ans.type === 1);
if (aRecords.length > 0) {
aRecords.forEach(ans => {
const ip = ans.data;
if (format === "keenetic") {
output += ` route add ${ip} mask 255.255.255.255 0.0.0.0\n`;
} else {
output += ` ${ip}\n`;
}
});
} else {
output += ` Нет A записей.\n`;
}
} else {
output += ` Нет ответа.\n`;
}
});
} catch (error) {
output += ` Ошибка: ${error.message}\n`;
}
processed++;
updateProgress();
output += "\n";
}
}
document.getElementById("result").textContent = output.trim() || "Не удалось получить IP-адреса.";
updateProgress();
}
function toggleTheme() {
document.body.classList.toggle('light-mode');
}
function saveToTxt() {
const content = document.getElementById("result").textContent;
if (!content || content.trim() === "Результаты появятся здесь...") {
alert("Нет данных для сохранения.");
return;
}
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "dns_result.txt";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
</body>
</html>