From f9349f9713c6d857c0c0c00e257687b95c6e375e Mon Sep 17 00:00:00 2001 From: cmliu Date: Thu, 6 Nov 2025 23:37:32 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96SOCKS5=E6=8F=A1?= =?UTF-8?q?=E6=89=8B=E9=80=BB=E8=BE=91=EF=BC=8C=E7=A7=BB=E9=99=A4UDP?= =?UTF-8?q?=E5=A4=84=E7=90=86=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _worker.js | 127 +++++------------------------------------------------ 1 file changed, 10 insertions(+), 117 deletions(-) diff --git a/_worker.js b/_worker.js index 26a1307..d0ff03d 100644 --- a/_worker.js +++ b/_worker.js @@ -306,44 +306,25 @@ function handleConnection(ws, request, FIXED_UUID) { let socket, writer, reader, info; let isFirstMsg = true, bytesReceived = 0, stallCount = 0, reconnectCount = 0; let lastData = Date.now(); - let udpStreamWrite = null, isDns = false; const timers = {}; const dataBuffer = []; const earlyDataHeader = request.headers.get("sec-websocket-protocol") || ""; async function 处理魏烈思握手(data) { const bytes = new Uint8Array(data); - const 协议版本 = new Uint8Array([bytes[0], 0]); ws.send(new Uint8Array([bytes[0], 0])); if (Array.from(bytes.slice(1, 17)).map(n => n.toString(16).padStart(2, '0')).join('').replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5') !== FIXED_UUID) throw new Error('Auth failed'); const offset1 = 18 + bytes[17] + 1; - const command = bytes[offset1]; - const port = (bytes[offset1 + 1] << 8) | bytes[offset1 + 2]; - const addrType = bytes[offset1 + 3]; - const offset2 = offset1 + 4; + const port = (bytes[offset1] << 8) | bytes[offset1 + 1]; + const addrType = bytes[offset1 + 2]; + const offset2 = offset1 + 3; const { host, length } = parseAddress(bytes, offset2, addrType === 1 ? 1 : addrType === 2 ? 2 : 4); const payload = bytes.slice(length); if (host.includes(atob('c3BlZWQuY2xvdWRmbGFyZS5jb20='))) throw new Error('Access'); - - // 判断是否为UDP命令(0x02) - const isUDP = command === 2; - if (isUDP) { - if (port === 53) { - isDns = true; - const 魏烈思响应头 = new Uint8Array([协议版本[0], 0]); - const { write } = await handleUDPOutBound(ws, 魏烈思响应头); - udpStreamWrite = write; - udpStreamWrite(payload); - return { socket: null, writer: null, reader: null, info: { host, port, isUDP: true } }; - } else { - throw new Error('UDP proxy only enable for DNS which is port 53'); - } - } - const sock = await createConnection(host, port); await sock.opened; const w = sock.writable.getWriter(); if (payload.length) await w.write(payload); - return { socket: sock, writer: w, reader: sock.readable.getReader(), info: { host, port, isUDP: false } }; + return { socket: sock, writer: w, reader: sock.readable.getReader(), info: { host, port } }; } async function 处理木马握手(data) { @@ -353,44 +334,19 @@ function handleConnection(ws, request, FIXED_UUID) { const socks5Data = bytes.slice(58); if (socks5Data.byteLength < 6) throw new Error("invalid SOCKS5 request data"); - - const command = socks5Data[0]; - // 0x01 TCP (CONNECT) - // 0x02 UDP - const isUDP = command === 2; - - if (command !== 1 && command !== 2) { - throw new Error(`unsupported command ${command}, only TCP (CONNECT) and UDP are allowed`); - } + if (socks5Data[0] !== 1) throw new Error("unsupported command, only TCP (CONNECT) is allowed"); const { host, length } = parseAddress(socks5Data, 2, socks5Data[1]); if (!host) throw new Error(`address is empty, addressType is ${socks5Data[1]}`); if (host.includes(atob('c3BlZWQuY2xvdWRmbGFyZS5jb20='))) throw new Error('Access'); const port = (socks5Data[length] << 8) | socks5Data[length + 1]; - const payload = socks5Data.slice(length + 4); - - // 处理UDP DNS请求 - if (isUDP) { - if (port === 53) { - isDns = true; - // 木马协议不需要响应头,直接传入空数组 - const 木马响应头 = new Uint8Array(0); - const { write } = await handleUDPOutBound(ws, 木马响应头); - udpStreamWrite = write; - if (payload.length) udpStreamWrite(payload); - return { socket: null, writer: null, reader: null, info: { host, port, isUDP: true } }; - } else { - throw new Error('UDP proxy only enable for DNS which is port 53'); - } - } - - // 处理TCP连接 const sock = await createConnection(host, port); await sock.opened; const w = sock.writable.getWriter(); + const payload = socks5Data.slice(length + 4); if (payload.length) await w.write(payload); - return { socket: sock, writer: w, reader: sock.readable.getReader(), info: { host, port, isUDP: false } }; + return { socket: sock, writer: w, reader: sock.readable.getReader(), info: { host, port } }; } async function createConnection(host, port) { @@ -557,18 +513,11 @@ function handleConnection(ws, request, FIXED_UUID) { const bytes = new Uint8Array(firstData); if (bytes.byteLength >= 58 && bytes[56] === 0x0d && bytes[57] === 0x0a) ({ socket, writer, reader, info } = await 处理木马握手(firstData)); else ({ socket, writer, reader, info } = await 处理魏烈思握手(firstData)); - - // 如果是DNS UDP请求,不需要启动定时器和读取循环 - if (!isDns) { - startTimers(); - readLoop(); - } + startTimers(); + readLoop(); } else { lastData = Date.now(); - // 处理UDP DNS数据 - if (isDns && udpStreamWrite) { - await udpStreamWrite(evt.data); - } else if (socket && writer) { + if (socket && writer) { await writer.write(evt.data); } else { dataBuffer.push(evt.data); @@ -613,62 +562,6 @@ function parseAddress(bytes, offset, addrType) { } return { host, length: endOffset }; } - -const WS_READY_STATE_OPEN = 1; -async function handleUDPOutBound(webSocket, 协议响应头) { - let 响应头已发送 = false; - const transformStream = new TransformStream({ - start(controller) { }, - transform(chunk, controller) { - // UDP消息前2字节是UDP数据的长度 - for (let index = 0; index < chunk.byteLength;) { - const lengthBuffer = chunk.slice(index, index + 2); - const udpPacketLength = new DataView(lengthBuffer).getUint16(0); - const udpData = new Uint8Array( - chunk.slice(index + 2, index + 2 + udpPacketLength) - ); - index = index + 2 + udpPacketLength; - controller.enqueue(udpData); - } - }, - flush(controller) { } - }); - - // 处理DNS UDP查询 - 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; - const udpSizeBuffer = new Uint8Array([(udpSize >> 8) & 0xff, udpSize & 0xff]); - - if (webSocket.readyState === WS_READY_STATE_OPEN) { - console.log(`DoH success and dns message length is ${udpSize}`); - if (响应头已发送) { - webSocket.send(await new Blob([udpSizeBuffer, dnsQueryResult]).arrayBuffer()); - } else { - webSocket.send(await new Blob([协议响应头, udpSizeBuffer, dnsQueryResult]).arrayBuffer()); - 响应头已发送 = true; - } - } - } - })).catch((error) => { - console.error('DNS UDP has error:', error); - }); - const writer = transformStream.writable.getWriter(); - return { - write(chunk) { - writer.write(chunk); - } - }; -} - ////////////////////////////////SOCKS5/HTTP函数/////////////////////////////////////////////// async function httpConnect(addressRemote, portRemote) { const { username, password, hostname, port } = parsedSocks5Address;