Skip to content

Commit

Permalink
增加 DNS 泄露( DNS Leaks )检测
Browse files Browse the repository at this point in the history
  • Loading branch information
jason5ng32 committed Nov 26, 2023
1 parent 67a3c9f commit 2ef715c
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 14 deletions.
42 changes: 37 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
<a class="nav-link" href="#scrollspyHeading1">IP 信息</a>
<a class="nav-link" href="#scrollspyHeading2">可用性测试</a>
<a class="nav-link" href="#scrollspyHeading3">WebRTC 测试</a>
<a class="nav-link" href="#scrollspyHeading4">DNS 泄露测试</a>
</div>
</div>
</nav>
Expand Down Expand Up @@ -146,11 +147,12 @@ <h2 id="scrollspyHeading1" class="col-6">🛜 IP 数据</h2>
<div class="form-check form-switch col-6 jn-radio">
<input class="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckDefault"
@change="toggleMaps" :checked="isMapShown">
<label class="form-check-label" for="flexSwitchCheckDefault">{{ isMapShown ? '&nbsp;显示地图' : '&nbsp;隐藏地图' }}</label>
<label class="form-check-label" for="flexSwitchCheckDefault">{{ isMapShown ? '&nbsp;显示地图' : '&nbsp;隐藏地图'
}}</label>
</div>
</div>
<div class="text-secondary">
<p>将会从 4 个来源检查 IP 数据,如果当前 IP 栈只有 1 个,则没有数据的来源会显示为空。</p>
<p>将会从 6 个来源检查 IP 数据,如果当前 IP 栈只有 1 个,则没有数据的来源会显示为空。</p>
</div>
<div class="jn-card-deck">
<div class="row">
Expand Down Expand Up @@ -215,7 +217,7 @@ <h2 id="scrollspyHeading2">🚦 可用性测试</h2>
<h5 class="card-title"><i class="bi" :class="'bi-'+test.icon"></i> {{ test.name }}</h5>

<p class="card-text"
:class="{'text-info': test.status === '检查中...', 'text-success': test.status.includes('可用'), 'text-danger': test.status === '不可用' || test.status === '超时或不可用'}"
:class="{'text-info': test.status === '待检测', 'text-success': test.status.includes('可用'), 'text-danger': test.status === '不可用' || test.status === '超时或不可用'}"
v-html="test.status">
</p>
</div>
Expand All @@ -225,7 +227,7 @@ <h5 class="card-title"><i class="bi" :class="'bi-'+test.icon"></i> {{ test.name
</div>

<!-- WebRTC 测试 -->
<div class="availability-test-section mb-4">
<div class="webrtc-test-section mb-4">
<div class="jn-title">
<h2 id="scrollspyHeading3">🚥 WebRTC 测试</h2>
<button @click="checkAllWebRTC" class="btn btn-light"><i class="bi bi-arrow-clockwise"></i></button>
Expand All @@ -240,14 +242,44 @@ <h2 id="scrollspyHeading3">🚥 WebRTC 测试</h2>
<h5 class="card-title"><i class="bi bi-sign-merge-left-fill"></i> {{ stun.name }}</h5>
<p class="card-text text-secondary" style="font-size: 10pt;">{{ stun.url }}</p>
<p class="card-text"
:class="{'text-info': stun.ip === '检查中...', 'text-success': stun.ip.includes('.'|':'), 'text-danger': stun.ip === '测试出错'}"
:class="{'text-info': stun.ip === '待检测或连接错误', 'text-success': stun.ip.includes('.'|':'), 'text-danger': stun.ip === '测试出错'}"
v-html="stun.ip"></p>
</p>
</div>
</div>
</div>
</div>
</div>

<!-- DNS Leak 测试 -->
<div class="dnsleak-test-section mb-4">
<div class="jn-title">
<h2 id="scrollspyHeading4">🚥 DNS 泄露测试</h2>
<button @click="checkAllDNSLeakTest" class="btn btn-light"><i class="bi bi-arrow-clockwise"></i></button>
</div>
<div class="text-secondary">
<p>DNS 泄露(DNS Leaks)的意思是,当你<strong>挂上 VPN/代理后</strong>,你解析域名时,依然通过当地的运营商进行解析,这时就有 DNS
泄露的风险。泄露测试的方法是通过访问新生成的域名,检测你是通过哪个地区的
DNS 进行解析,如果返回的地区数据与你当地的运营商地区相同,则有泄露风险,你可能需要修改你的 VPN/代理设置。</p>
</div>
<div class="row">
<div v-for="leak in leakTest" :key="leak.id" class="col-6 col-md-3 mb-4">
<div class="card jn-card">
<div class="card-body">
<h5 class="card-title"><i class="bi bi-server"></i> {{ leak.name }}</h5>
<p class="card-text text-secondary" style="font-size: 10pt;">DNS 出口:{{ leak.ip }}</p>
<p class="card-text" :class="[
'text-success',
{'text-info': leak.geo === '待检测', 'text-danger': leak.geo.includes('China') || leak.geo.includes('china')}
]">出口地区:{{ leak.geo }}</p>
</p>
</div>
</div>
</div>
</div>
</div>


</div>
</div>

Expand Down
136 changes: 127 additions & 9 deletions res/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ new Vue({
},
{
id: 'nextcloud',
name: 'NxtCld(v6)',
name: 'NxtCld',
url: 'stun:stun.nextcloud.com:443',
ip: '待检测或无 IPv6 地址'
ip: '待检测或连接错误'
},
{
id: 'peerjs',
Expand Down Expand Up @@ -196,11 +196,37 @@ new Vue({
},
{
id: 'stunprotocol',
name: 'StnPtc(v6)',
name: 'StnPtc',
url: 'stun:stunserver.stunprotocol.org',
ip: '待检测或无 IPv6 地址'
ip: '待检测或连接错误'
}
],
leakTest: [
{
"id": "ipapi1",
"name": "检测 1",
"geo": "待检测",
"ip": "待检测"
},
{
"id": "ipapi2",
"name": "检测 2",
"geo": "待检测",
"ip": "待检测"
},
{
"id": "sfshark1",
"name": "检测 3",
"geo": "待检测",
"ip": "待检测"
},
{
"id": "sfshark2",
"name": "检测 4",
"geo": "待检测",
"ip": "待检测"
},
],
alertMessage: '',
alertStyle: '',
alertTitle: '',
Expand All @@ -216,7 +242,7 @@ new Vue({
getIPFromUpai() {
const unixTime = Date.now();
const url = `https://pubstatic.b0.upaiyun.com/?_upnode&t=${unixTime}`;

fetch(url)
.then(response => {
if (!response.ok) {
Expand Down Expand Up @@ -562,14 +588,103 @@ new Vue({
}
},



checkAllWebRTC() {
this.stunServers.forEach(stun => {
this.checkSTUNServer(stun);
});
},

generate32DigitString() {
const unixTime = Date.now().toString(); // 13 位 Unix 时间戳
const fixedString = "jason5ng32"; // 固定字符串
const randomString = Math.random().toString(36).substring(2, 11); // 随机 9 位字符串

return unixTime + fixedString + randomString; // 拼接字符串
},

generate14DigitString() {
const fixedString = "jn32"; // 固定字符串
const randomString = Math.random().toString(36).substring(2, 11); // 随机 9 位字符串

return fixedString + randomString; // 拼接字符串
},

fetchLeakTestIpApiCom(index) {
const urlString = this.generate32DigitString();
const url = `https://${urlString}.edns.ip-api.com/json`;

fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if (data.dns && 'geo' in data.dns && 'ip' in data.dns) {
const geoSplit = data.dns.geo.split(' - ');
this.leakTest[index].geo = geoSplit[0];
this.leakTest[index].ip = data.dns.ip;
} else {
console.error('Unexpected data structure:', data);
}
})
.catch(error => {
console.error('Error fetching leak test data:', error);
this.leakTest[index].geo = '检查出错';
this.leakTest[index].ip = '检查出错';
});
},

fetchLeakTestSfSharkCom(index, key) {
const urlString = this.generate14DigitString();
const url = `https://${urlString}.ipv4.surfsharkdns.com`;

fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
// 获取 data 对象中的指定键
const getKey = Object.keys(data)[key];
const keyEntry = data[getKey];

if (keyEntry && keyEntry.Country && keyEntry.IP) {
this.leakTest[index].geo = keyEntry.Country;
this.leakTest[index].ip = keyEntry.IP;
} else {
console.error('Unexpected data structure:', data);
}
})
.catch(error => {
console.error('Error fetching leak test data:', error);
this.leakTest[index].geo = '检查出错';
this.leakTest[index].ip = '检查出错';
});
},


checkAllDNSLeakTest() {
setTimeout(() => {
this.fetchLeakTestIpApiCom(0);
}, 100);

setTimeout(() => {
this.fetchLeakTestIpApiCom(1);
}, 1000);

setTimeout(() => {
this.fetchLeakTestSfSharkCom(2, 1);
}, 100);

setTimeout(() => {
this.fetchLeakTestSfSharkCom(3, 2);
}, 1000);
}

},

created() {
Expand All @@ -586,10 +701,13 @@ new Vue({
mounted() {
setTimeout(() => {
this.checkAllConnectivity();
}, 2500);
}, 2500);
setTimeout(() => {
this.checkAllWebRTC();
}, 4000);
}, 4000);
setTimeout(() => {
this.checkAllDNSLeakTest();
}, 2500);
this.getIPFromCloudflare_V4();
this.getIPFromCloudflare_V6();
this.getIPFromIpify_V4();
Expand Down

0 comments on commit 2ef715c

Please sign in to comment.