Skip to content

Commit 9c7b600

Browse files
authored
Merge pull request cmliu#1392 from cmliu/alpha2.1
Alpha2.1
2 parents 7139e5a + e0d8e7a commit 9c7b600

2 files changed

Lines changed: 124 additions & 19 deletions

File tree

CHANGELOG

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## [2.1.20260722191426] - 2026-07-22 19:14:26
2+
3+
### Change
4+
5+
- 适配 `http://cp.cloudflare.com/generate_204` 真连接测试地址。
6+
17
## [2.1.20260711190235] - 2026-07-11 19:02:35
28

39
### ADD

_worker.js

Lines changed: 118 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const Version = '2026-07-11 19:02:35';
1+
const Version = '2026-07-22 19:14:26';
22
let config_JSON, 缓存SOCKS5白名单 = null, 调试日志打印 = false;
33
let SOCKS5白名单 = ['*tapecontent.net', '*cloudatacdn.com', '*loadshare.org', '*cdn-centaurus.com', 'scholar.google.com'];
44
const Pages静态页面 = 'https://edt-pages.github.io';
@@ -538,7 +538,14 @@ async function 处理XHTTP请求(request, yourUUID, 反代上下文 = {}) {
538538
}
539539
if (isSpeedTestSite(首包.hostname)) {
540540
try { reader.releaseLock() } catch (e) { }
541-
return new Response('Forbidden', { status: 403 });
541+
return new Response(构造本地204响应(首包.respHeader), {
542+
status: 200,
543+
headers: {
544+
'Content-Type': 'application/octet-stream',
545+
'X-Accel-Buffering': 'no',
546+
'Cache-Control': 'no-store'
547+
}
548+
});
542549
}
543550
if (首包.isUDP && 首包.协议 !== 'trojan' && 首包.port !== 53) {
544551
try { reader.releaseLock() } catch (e) { }
@@ -1052,7 +1059,10 @@ async function 处理gRPC请求(request, yourUUID, 反代上下文 = {}) {
10521059
if (解析结果?.hasError) throw new Error(解析结果.message || 'Invalid trojan request');
10531060
const { port, hostname, rawClientData, isUDP } = 解析结果;
10541061
log(`[gRPC] 木马首包: ${hostname}:${port} | UDP: ${isUDP ? '是' : '否'}`);
1055-
if (isSpeedTestSite(hostname)) throw new Error('Speedtest site is blocked');
1062+
if (isSpeedTestSite(hostname)) {
1063+
grpcBridge.send(构造本地204响应());
1064+
return;
1065+
}
10561066
if (isUDP) {
10571067
isDnsQuery = true;
10581068
木马UDP上下文.目标主机 = hostname;
@@ -1068,12 +1078,15 @@ async function 处理gRPC请求(request, yourUUID, 反代上下文 = {}) {
10681078
if (解析结果?.hasError) throw new Error(解析结果.message || 'Invalid 魏烈思 request');
10691079
const { port, hostname, version, isUDP, rawClientData } = 解析结果;
10701080
log(`[gRPC] 魏烈思首包: ${hostname}:${port} | UDP: ${isUDP ? '是' : '否'}`);
1071-
if (isSpeedTestSite(hostname)) throw new Error('Speedtest site is blocked');
1081+
const respHeader = new Uint8Array([version, 0]);
1082+
if (isSpeedTestSite(hostname)) {
1083+
grpcBridge.send(构造本地204响应(respHeader));
1084+
return;
1085+
}
10721086
if (isUDP) {
10731087
if (port !== 53) throw new Error('UDP is not supported');
10741088
isDnsQuery = true;
10751089
}
1076-
const respHeader = new Uint8Array([version, 0]);
10771090
grpcBridge.send(respHeader);
10781091
const rawData = rawClientData;
10791092
if (isDnsQuery) {
@@ -1170,6 +1183,52 @@ async function 处理WS请求(request, yourUUID, url, 反代上下文 = {}) {
11701183
let WS显式队列字节 = 0, WS显式队列条目 = 0;
11711184
let 判断协议类型 = null, 当前写入Socket = null, 远端写入器 = null;
11721185
let ss上下文 = null, ss初始化任务 = null;
1186+
let WS本地测速模式 = false, WS本地测速回包Socket = null;
1187+
let WS本地测速请求缓存 = new Uint8Array(0);
1188+
let WS本地测速首包响应头 = null;
1189+
const WS本地测速请求上限 = 64 * 1024;
1190+
1191+
const 发送WS本地测速响应 = async () => {
1192+
if (!WS本地测速回包Socket) return;
1193+
const respHeader = WS本地测速首包响应头;
1194+
WS本地测速首包响应头 = null;
1195+
await WebSocket发送并等待(WS本地测速回包Socket, 构造WS本地204响应(respHeader));
1196+
};
1197+
1198+
const 查找HTTP请求头结尾 = (data) => {
1199+
for (let i = 0; i <= data.byteLength - 4; i++) {
1200+
if (data[i] === 0x0d && data[i + 1] === 0x0a && data[i + 2] === 0x0d && data[i + 3] === 0x0a) return i + 4;
1201+
}
1202+
return -1;
1203+
};
1204+
1205+
const 处理WS本地测速数据 = async (data) => {
1206+
const chunk = 数据转Uint8Array(data);
1207+
if (!chunk.byteLength) return;
1208+
if (WS本地测速请求缓存.byteLength + chunk.byteLength > WS本地测速请求上限) throw new Error('WS local speed-test request is too large');
1209+
WS本地测速请求缓存 = 拼接字节数据(WS本地测速请求缓存, chunk);
1210+
1211+
while (WS本地测速请求缓存.byteLength) {
1212+
const headerEnd = 查找HTTP请求头结尾(WS本地测速请求缓存);
1213+
if (headerEnd === -1) return;
1214+
const headerText = VLESS文本解码器.decode(WS本地测速请求缓存.subarray(0, headerEnd));
1215+
const contentLengthMatch = headerText.match(/(?:^|\r\n)content-length\s*:\s*(\d+)/i);
1216+
const contentLength = contentLengthMatch ? Number(contentLengthMatch[1]) : 0;
1217+
const requestLength = headerEnd + contentLength;
1218+
if (!Number.isSafeInteger(contentLength) || requestLength > WS本地测速请求上限) throw new Error('WS local speed-test request body is too large');
1219+
if (WS本地测速请求缓存.byteLength < requestLength) return;
1220+
WS本地测速请求缓存 = WS本地测速请求缓存.slice(requestLength);
1221+
await 发送WS本地测速响应();
1222+
}
1223+
};
1224+
1225+
const 启用WS本地测速模式 = async (回包Socket, respHeader = null, 首请求数据 = null) => {
1226+
WS本地测速模式 = true;
1227+
WS本地测速回包Socket = 回包Socket;
1228+
WS本地测速请求缓存 = new Uint8Array(0);
1229+
WS本地测速首包响应头 = respHeader;
1230+
if (有效数据长度(首请求数据) > 0) await 处理WS本地测速数据(首请求数据);
1231+
};
11731232

11741233
const 释放远端写入器 = () => {
11751234
if (远端写入器) {
@@ -1395,6 +1454,10 @@ async function 处理WS请求(request, yourUUID, url, 反代上下文 = {}) {
13951454
throw err;
13961455
}
13971456
for (const 明文块 of 明文块数组) {
1457+
if (WS本地测速模式) {
1458+
await 处理WS本地测速数据(明文块);
1459+
continue;
1460+
}
13981461
let 已写入 = false;
13991462
try {
14001463
已写入 = await 写入远端(明文块, false);
@@ -1437,7 +1500,10 @@ async function 处理WS请求(request, yourUUID, url, 反代上下文 = {}) {
14371500
const port = (明文数据[cursor] << 8) | 明文数据[cursor + 1];
14381501
cursor += 2;
14391502
const rawClientData = 明文数据.subarray(cursor);
1440-
if (isSpeedTestSite(hostname)) throw new Error('Speedtest site is blocked');
1503+
if (isSpeedTestSite(hostname)) {
1504+
await 启用WS本地测速模式(上下文.回包Socket, null, rawClientData);
1505+
return;
1506+
}
14411507
上下文.首包已建立 = true;
14421508
上下文.目标主机 = hostname;
14431509
上下文.目标端口 = port;
@@ -1455,6 +1521,10 @@ async function 处理WS请求(request, yourUUID, url, 反代上下文 = {}) {
14551521
await 处理SS数据(chunk);
14561522
return;
14571523
}
1524+
if (WS本地测速模式) {
1525+
await 处理WS本地测速数据(chunk);
1526+
return;
1527+
}
14581528
if (await 写入远端(chunk)) return;
14591529

14601530
if (判断协议类型 === null) {
@@ -1477,7 +1547,10 @@ async function 处理WS请求(request, yourUUID, url, 反代上下文 = {}) {
14771547
const 解析结果 = 解析木马请求(chunk, yourUUID);
14781548
if (解析结果?.hasError) throw new Error(解析结果.message || 'Invalid trojan request');
14791549
const { port, hostname, rawClientData, isUDP } = 解析结果;
1480-
if (isSpeedTestSite(hostname)) throw new Error('Speedtest site is blocked');
1550+
if (isSpeedTestSite(hostname)) {
1551+
await 启用WS本地测速模式(serverSock, null, rawClientData);
1552+
return;
1553+
}
14811554
if (isUDP) {
14821555
isDnsQuery = true;
14831556
木马UDP上下文.目标主机 = hostname;
@@ -1494,12 +1567,15 @@ async function 处理WS请求(request, yourUUID, url, 反代上下文 = {}) {
14941567
const 解析结果 = 解析魏烈思请求(bytes, yourUUID);
14951568
if (解析结果?.hasError) throw new Error(解析结果.message || 'Invalid 魏烈思 request');
14961569
const { port, hostname, version, isUDP, rawClientData } = 解析结果;
1497-
if (isSpeedTestSite(hostname)) throw new Error('Speedtest site is blocked');
1570+
const respHeader = new Uint8Array([version, 0]);
1571+
if (isSpeedTestSite(hostname)) {
1572+
await 启用WS本地测速模式(serverSock, respHeader, rawClientData);
1573+
return;
1574+
}
14981575
if (isUDP) {
14991576
if (port === 53) isDnsQuery = true;
15001577
else throw new Error('UDP is not supported');
15011578
}
1502-
const respHeader = new Uint8Array([version, 0]);
15031579
const rawData = rawClientData;
15041580
if (isDnsQuery) {
15051581
if (判断是否是木马) return 转发木马UDP数据(rawData, serverSock, 木马UDP上下文, request);
@@ -2608,17 +2684,40 @@ async function connectStreams(remoteSocket, webSocket, headerData, retryFunc) {
26082684
}
26092685

26102686
function isSpeedTestSite(hostname) {
2611-
const speedTestDomains = [atob('c3BlZWQuY2xvdWRmbGFyZS5jb20=')];
2612-
if (speedTestDomains.includes(hostname)) {
2613-
return true;
2614-
}
2687+
const speedTestDomains = ['speed.cloudflare.com', 'cp.cloudflare.com'];
2688+
hostname = hostname.toLowerCase();
2689+
return speedTestDomains.some(domain => hostname === domain || hostname.endsWith('.' + domain));
2690+
}
26152691

2616-
for (const domain of speedTestDomains) {
2617-
if (hostname.endsWith('.' + domain) || hostname === domain) {
2618-
return true;
2619-
}
2620-
}
2621-
return false;
2692+
function 构造本地204响应(respHeader = null) {
2693+
const 本地204响应 = new TextEncoder().encode(
2694+
'HTTP/1.1 204 No Content\r\n' +
2695+
'Content-Length: 0\r\n' +
2696+
'Connection: close\r\n' +
2697+
'\r\n'
2698+
);
2699+
if (有效数据长度(respHeader) === 0) return 本地204响应;
2700+
const 协议响应头 = 数据转Uint8Array(respHeader);
2701+
const response = new Uint8Array(协议响应头.byteLength + 本地204响应.byteLength);
2702+
response.set(协议响应头, 0);
2703+
response.set(本地204响应, 协议响应头.byteLength);
2704+
log(`[TCP转发] 构造本地204响应: ${response.byteLength}B`);
2705+
return response;
2706+
}
2707+
2708+
function 构造WS本地204响应(respHeader = null) {
2709+
const WS本地204响应 = new TextEncoder().encode(
2710+
'HTTP/1.1 204 No Content\r\n' +
2711+
'Content-Length: 0\r\n' +
2712+
'Connection: keep-alive\r\n' +
2713+
'\r\n'
2714+
);
2715+
if (有效数据长度(respHeader) === 0) return WS本地204响应;
2716+
const 协议响应头 = 数据转Uint8Array(respHeader);
2717+
const response = new Uint8Array(协议响应头.byteLength + WS本地204响应.byteLength);
2718+
response.set(协议响应头, 0);
2719+
response.set(WS本地204响应, 协议响应头.byteLength);
2720+
return response;
26222721
}
26232722

26242723
///////////////////////////////////////////////////////SOCKS5/HTTP函数///////////////////////////////////////////////

0 commit comments

Comments
 (0)