mirror of
https://github.com/lush2020/edgetunnel.git
synced 2026-03-21 17:12:33 +08:00
更新README.md
This commit is contained in:
@@ -273,4 +273,4 @@
|
||||
- [SHIJS1999/cloudflare-worker-vless-ip](https://github.com/SHIJS1999/cloudflare-worker-vless-ip)
|
||||
- [Stanley-baby](https://github.com/Stanley-baby)
|
||||
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR/tree/master/Clash/config)
|
||||
- [股神](https://t.me/CF_NAT/38885)
|
||||
- [股神](https://t.me/CF_NAT/38889)
|
||||
217
明文源码.js
217
明文源码.js
@@ -376,12 +376,12 @@ async function handleTCPOutBound(remoteSocket, addressType, addressRemote, portR
|
||||
}
|
||||
|
||||
async function connectAndWrite(address, port, socks = false, http = false) {
|
||||
log(`connected to ${address}:${port}`);
|
||||
log(`connected to ${address}:${port}`);
|
||||
//if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(address)) address = `${atob('d3d3Lg==')}${address}${atob('LmlwLjA5MDIyNy54eXo=')}`;
|
||||
// 先确定连接方式,再创建连接
|
||||
const tcpSocket = socks
|
||||
? (http ? await httpConnect(address, port, log) : await socks5Connect(addressType, address, port, log))
|
||||
: connect({ hostname: address, port: port });
|
||||
// 先确定连接方式,再创建连接
|
||||
const tcpSocket = socks
|
||||
? (http ? await httpConnect(address, port, log) : await socks5Connect(addressType, address, port, log))
|
||||
: connect({ hostname: address, port: port });
|
||||
|
||||
remoteSocket.value = tcpSocket;
|
||||
//log(`connected to ${address}:${port}`);
|
||||
@@ -392,6 +392,18 @@ async function handleTCPOutBound(remoteSocket, addressType, addressRemote, portR
|
||||
return tcpSocket;
|
||||
}
|
||||
|
||||
async function nat64() {
|
||||
const nat64Proxyip = `[${await resolveToIPv6(addressRemote)}]`;
|
||||
log(`NAT64 代理连接到 ${nat64Proxyip}:443`);
|
||||
tcpSocket = await connectAndWrite(nat64Proxyip, '443');
|
||||
tcpSocket.closed.catch(error => {
|
||||
console.log('retry tcpSocket closed error', error);
|
||||
}).finally(() => {
|
||||
safeCloseWebSocket(webSocket);
|
||||
})
|
||||
remoteSocketToWS(tcpSocket, webSocket, 维列斯ResponseHeader, null, log);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重试函数:当 Cloudflare 的 TCP Socket 没有传入数据时,我们尝试重定向 IP
|
||||
* 这可能是因为某些网络问题导致的连接失败
|
||||
@@ -414,14 +426,15 @@ async function handleTCPOutBound(remoteSocket, addressType, addressRemote, portR
|
||||
if (proxyIP.includes('.tp')) portRemote = proxyIP.split('.tp')[1].split('.')[0] || portRemote;
|
||||
tcpSocket = await connectAndWrite(proxyIP.toLowerCase() || addressRemote, portRemote);
|
||||
}
|
||||
// 无论重试是否成功,都要关闭 WebSocket(可能是为了重新建立连接)
|
||||
/* 无论重试是否成功,都要关闭 WebSocket(可能是为了重新建立连接)
|
||||
tcpSocket.closed.catch(error => {
|
||||
console.log('retry tcpSocket closed error', error);
|
||||
}).finally(() => {
|
||||
safeCloseWebSocket(webSocket);
|
||||
})
|
||||
*/
|
||||
// 建立从远程 Socket 到 WebSocket 的数据流
|
||||
remoteSocketToWS(tcpSocket, webSocket, 维列斯ResponseHeader, null, log);
|
||||
remoteSocketToWS(tcpSocket, webSocket, 维列斯ResponseHeader, nat64, log);
|
||||
}
|
||||
|
||||
let useSocks = false;
|
||||
@@ -2339,4 +2352,192 @@ async function KV(request, env, txt = 'ADD.txt') {
|
||||
headers: { "Content-Type": "text/plain;charset=utf-8" }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveToIPv6(target) {
|
||||
// 检查是否为IPv4
|
||||
function isIPv4(str) {
|
||||
const parts = str.split('.');
|
||||
return parts.length === 4 && parts.every(part => {
|
||||
const num = parseInt(part, 10);
|
||||
return num >= 0 && num <= 255 && part === num.toString();
|
||||
});
|
||||
}
|
||||
|
||||
// 检查是否为IPv6
|
||||
function isIPv6(str) {
|
||||
return str.includes(':') && /^[0-9a-fA-F:]+$/.test(str);
|
||||
}
|
||||
|
||||
// 获取域名的IPv4地址
|
||||
async function fetchIPv4(domain) {
|
||||
const url = `https://cloudflare-dns.com/dns-query?name=${domain}&type=A`;
|
||||
const response = await fetch(url, {
|
||||
headers: { 'Accept': 'application/dns-json' }
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('DNS查询失败');
|
||||
|
||||
const data = await response.json();
|
||||
const ipv4s = (data.Answer || [])
|
||||
.filter(record => record.type === 1)
|
||||
.map(record => record.data);
|
||||
|
||||
if (ipv4s.length === 0) throw new Error('未找到IPv4地址');
|
||||
return ipv4s[Math.floor(Math.random() * ipv4s.length)];
|
||||
}
|
||||
|
||||
// 查询NAT64 IPv6地址
|
||||
async function queryNAT64(domain) {
|
||||
const socket = connect(atob('ZG90Lm5hdDY0LmRrOjg1Mw=='), {
|
||||
secureTransport: 'on',
|
||||
allowHalfOpen: false
|
||||
});
|
||||
|
||||
const writer = socket.writable.getWriter();
|
||||
const reader = socket.readable.getReader();
|
||||
|
||||
try {
|
||||
// 发送DNS查询
|
||||
const query = buildDNSQuery(domain);
|
||||
const queryWithLength = new Uint8Array(query.length + 2);
|
||||
queryWithLength[0] = query.length >> 8;
|
||||
queryWithLength[1] = query.length & 0xFF;
|
||||
queryWithLength.set(query, 2);
|
||||
await writer.write(queryWithLength);
|
||||
|
||||
// 读取响应
|
||||
const response = await readDNSResponse(reader);
|
||||
const ipv6s = parseIPv6(response);
|
||||
|
||||
return ipv6s.length > 0 ? ipv6s[0] : '未找到IPv6地址';
|
||||
} finally {
|
||||
await writer.close();
|
||||
await reader.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// 构建DNS查询包
|
||||
function buildDNSQuery(domain) {
|
||||
const buffer = new ArrayBuffer(512);
|
||||
const view = new DataView(buffer);
|
||||
let offset = 0;
|
||||
|
||||
// DNS头部
|
||||
view.setUint16(offset, Math.floor(Math.random() * 65536)); offset += 2; // ID
|
||||
view.setUint16(offset, 0x0100); offset += 2; // 标志
|
||||
view.setUint16(offset, 1); offset += 2; // 问题数
|
||||
view.setUint16(offset, 0); offset += 6; // 答案数/权威数/附加数
|
||||
|
||||
// 域名编码
|
||||
for (const label of domain.split('.')) {
|
||||
view.setUint8(offset++, label.length);
|
||||
for (let i = 0; i < label.length; i++) {
|
||||
view.setUint8(offset++, label.charCodeAt(i));
|
||||
}
|
||||
}
|
||||
view.setUint8(offset++, 0); // 结束标记
|
||||
|
||||
// 查询类型和类
|
||||
view.setUint16(offset, 28); offset += 2; // AAAA记录
|
||||
view.setUint16(offset, 1); offset += 2; // IN类
|
||||
|
||||
return new Uint8Array(buffer, 0, offset);
|
||||
}
|
||||
|
||||
// 读取DNS响应
|
||||
async function readDNSResponse(reader) {
|
||||
const chunks = [];
|
||||
let totalLength = 0;
|
||||
let expectedLength = null;
|
||||
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
chunks.push(value);
|
||||
totalLength += value.length;
|
||||
|
||||
if (expectedLength === null && totalLength >= 2) {
|
||||
expectedLength = (chunks[0][0] << 8) | chunks[0][1];
|
||||
}
|
||||
|
||||
if (expectedLength !== null && totalLength >= expectedLength + 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 合并数据并跳过长度前缀
|
||||
const fullResponse = new Uint8Array(totalLength);
|
||||
let offset = 0;
|
||||
for (const chunk of chunks) {
|
||||
fullResponse.set(chunk, offset);
|
||||
offset += chunk.length;
|
||||
}
|
||||
|
||||
return fullResponse.slice(2);
|
||||
}
|
||||
|
||||
// 解析IPv6地址
|
||||
function parseIPv6(response) {
|
||||
const view = new DataView(response.buffer);
|
||||
let offset = 12; // 跳过DNS头部
|
||||
|
||||
// 跳过问题部分
|
||||
while (view.getUint8(offset) !== 0) {
|
||||
offset += view.getUint8(offset) + 1;
|
||||
}
|
||||
offset += 5;
|
||||
|
||||
const answers = [];
|
||||
const answerCount = view.getUint16(6); // 答案数量
|
||||
|
||||
for (let i = 0; i < answerCount; i++) {
|
||||
// 跳过名称
|
||||
if ((view.getUint8(offset) & 0xC0) === 0xC0) {
|
||||
offset += 2;
|
||||
} else {
|
||||
while (view.getUint8(offset) !== 0) {
|
||||
offset += view.getUint8(offset) + 1;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
const type = view.getUint16(offset); offset += 2;
|
||||
offset += 6; // 跳过类和TTL
|
||||
const dataLength = view.getUint16(offset); offset += 2;
|
||||
|
||||
if (type === 28 && dataLength === 16) { // AAAA记录
|
||||
const parts = [];
|
||||
for (let j = 0; j < 8; j++) {
|
||||
parts.push(view.getUint16(offset + j * 2).toString(16));
|
||||
}
|
||||
answers.push(parts.join(':'));
|
||||
}
|
||||
offset += dataLength;
|
||||
}
|
||||
|
||||
return answers;
|
||||
}
|
||||
|
||||
try {
|
||||
// 判断输入类型并处理
|
||||
if (isIPv6(target)) {
|
||||
return target; // IPv6直接返回
|
||||
}
|
||||
|
||||
let domain;
|
||||
if (isIPv4(target)) {
|
||||
domain = target + atob('LmlwLjA5MDIyNy54eXo='); // IPv4转换为NAT64域名
|
||||
} else {
|
||||
// 域名先解析IPv4再转NAT64
|
||||
const ipv4 = await fetchIPv4(target);
|
||||
domain = ipv4 + atob('LmlwLjA5MDIyNy54eXo=');
|
||||
}
|
||||
|
||||
return await queryNAT64(domain);
|
||||
} catch (error) {
|
||||
console.error('解析错误:', error);
|
||||
return `解析失败: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user