From a834984489afb34754d9eb73bd5da9ef1f42c90a Mon Sep 17 00:00:00 2001 From: cmliu Date: Mon, 4 Aug 2025 01:59:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0UDP=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96DNS=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _worker.js | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/_worker.js b/_worker.js index 314d732..df61aaf 100644 --- a/_worker.js +++ b/_worker.js @@ -294,14 +294,16 @@ async function 维列斯OverWSHandler(request) { value: null, }; // 标记是否为 DNS 查询 + let udpStreamWrite = null; let isDns = false; // WebSocket 数据流向远程服务器的管道 readableWebSocketStream.pipeTo(new WritableStream({ async write(chunk, controller) { - if (isDns) { + if (isDns && udpStreamWrite) { // 如果是 DNS 查询,调用 DNS 处理函数 - return await handleDNSQuery(chunk, webSocket, null, log); + //return await handleDNSQuery(chunk, webSocket, null, log); + return udpStreamWrite(chunk); } if (remoteSocketWapper.value) { // 如果已有远程 Socket,直接写入数据 @@ -346,7 +348,11 @@ async function 维列斯OverWSHandler(request) { if (isDns) { // 如果是 DNS 查询,调用 DNS 处理函数 - return handleDNSQuery(rawClientData, webSocket, 维列斯ResponseHeader, log); + //return handleDNSQuery(rawClientData, webSocket, 维列斯ResponseHeader, log); + const { write } = await handleUDPOutBound(webSocket, 维列斯ResponseHeader, log); + udpStreamWrite = write; + udpStreamWrite(rawClientData); + return; } // 处理 TCP 出站连接 if (!banHosts.includes(addressRemote)) { @@ -875,6 +881,78 @@ function stringify(arr, offset = 0) { return uuid; } +/** + * + * @param {import("@cloudflare/workers-types").WebSocket} webSocket + * @param {ArrayBuffer} 维列斯ResponseHeader + * @param {(string)=> void} log + */ +async function handleUDPOutBound(webSocket, 维列斯ResponseHeader, log) { + + let is维列斯HeaderSent = false; + const transformStream = new TransformStream({ + start(controller) { + + }, + transform(chunk, controller) { + // udp message 2 byte is the the length of udp data + // TODO: this should have bug, beacsue maybe udp chunk can be in two websocket message + for (let index = 0; index < chunk.byteLength;) { + const lengthBuffer = chunk.slice(index, index + 2); + const udpPakcetLength = new DataView(lengthBuffer).getUint16(0); + const udpData = new Uint8Array( + chunk.slice(index + 2, index + 2 + udpPakcetLength) + ); + index = index + 2 + udpPakcetLength; + controller.enqueue(udpData); + } + }, + flush(controller) { + } + }); + + // only handle dns udp for now + transformStream.readable.pipeTo(new WritableStream({ + async write(chunk) { + const resp = await fetch('https://1.1.1.1/dns-query', + { + method: 'POST', + headers: { + 'content-type': 'application/dns-message', + }, + body: chunk, + }) + const dnsQueryResult = await resp.arrayBuffer(); + const udpSize = dnsQueryResult.byteLength; + // console.log([...new Uint8Array(dnsQueryResult)].map((x) => x.toString(16))); + const udpSizeBuffer = new Uint8Array([(udpSize >> 8) & 0xff, udpSize & 0xff]); + if (webSocket.readyState === WS_READY_STATE_OPEN) { + log(`doh success and dns message length is ${udpSize}`); + if (is维列斯HeaderSent) { + webSocket.send(await new Blob([udpSizeBuffer, dnsQueryResult]).arrayBuffer()); + } else { + webSocket.send(await new Blob([维列斯ResponseHeader, udpSizeBuffer, dnsQueryResult]).arrayBuffer()); + is维列斯HeaderSent = true; + } + } + } + })).catch((error) => { + log('dns udp has error' + error) + }); + + const writer = transformStream.writable.getWriter(); + + return { + /** + * + * @param {Uint8Array} chunk + */ + write(chunk) { + writer.write(chunk); + } + }; +} + /** * 处理 DNS 查询的函数 * @param {ArrayBuffer} udpChunk - 客户端发送的 DNS 查询数据 @@ -2409,7 +2487,7 @@ async function resolveToIPv6(target) { // 获取域名的IPv4地址 async function fetchIPv4(domain) { - const url = `https://cloudflare-dns.com/dns-query?name=${domain}&type=A`; + const url = `https://1.1.1.1/dns-query?name=${domain}&type=A`; const response = await fetch(url, { headers: { 'Accept': 'application/dns-json' } }); @@ -2599,7 +2677,7 @@ async function bestIP(request, env, txt = 'ADD.txt') { 'Accept': 'application/dns-json' } }); - + if (response.ok) { const data = await response.json(); if (data.Status === 0 && data.Answer && data.Answer.length > 0) {