更新README.md

This commit is contained in:
cmliu
2025-05-27 00:55:49 +08:00
parent 95ec5ce831
commit 211492f161
2 changed files with 210 additions and 9 deletions

View File

@@ -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)

View File

@@ -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}`;
}
}