Удалить DNS Resolver Pro
This commit is contained in:
345
DNS Resolver Pro
345
DNS Resolver Pro
@@ -1,345 +0,0 @@
|
|||||||
<!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>
|
|
||||||
Reference in New Issue
Block a user