当前位置: 首页 > news >正文

台州超值营销型网站建设地址免费商用cms

台州超值营销型网站建设地址,免费商用cms,网络管理系统的主要功能,建设工程合同司法解释前言 本实验将会为大家解析cloud flare的反向解析代理服务如何搭建#xff0c;works如何创建等等。本文中教学创建的实例已在文章编写结束后释放#xff0c;该项技术不可用于违法用途#xff01;违者自行承担后果#xff01;#xff01; 原理拓扑图 一、知识链条 1、Clou…    前言 本实验将会为大家解析cloud flare的反向解析代理服务如何搭建works如何创建等等。本文中教学创建的实例已在文章编写结束后释放该项技术不可用于违法用途违者自行承担后果 原理拓扑图 一、知识链条 1、Cloud flare简介 Cloudflare 是一家全球性的云服务提供商成立于2009年。它提供了一系列网络基础设施和安全性服务帮助网站加速、保护、以及优化其在线内容。 Cloudflare 提供的主要服务包括 1. CDN内容分发网络通过将内容分发到全球性的数据中心加速网站加载速度提高用户体验。 2. DDoS 攻击防护保护网站免受分布式拒绝服务DDoS攻击确保服务的可用性和稳定性。 3. WAF网络应用防火墙监控和过滤网站流量阻止恶意攻击、SQL 注入和跨站脚本等网络攻击。 4. DNS域名解析服务提供快速、可靠的域名解析服务帮助网站管理和优化其网络流量。 5. SSL/TLS 加密提供免费的 SSL/TLS 加密证书加密网站与访问者之间的通信保护数据安全和隐私。 6. Workers允许开发者在 Cloudflare 的边缘网络上运行自定义的代码以实现更高级的功能和定制化的处理。 Cloudflare 的服务被广泛应用于各种规模的网站和在线应用程序中包括企业网站、电子商务平台、博客、游戏、移动应用等。其目标是通过提供简单易用、高性能和高安全性的服务帮助客户在互联网上取得成功。同时Cloud flare持有全球顶级DNS1.1.1.1可见其实力不凡。 2、VLess协议 vless 协议是一个相对于 V2Ray 的一种新的协议它是 V2Ray 的一个轻量级替代品。vless 的设计目标是减少传输数据的开销提高性能并且简化配置。 vless 协议的原理基本上与 V2Ray 中的 vmess 协议类似都是在传输层上实现的一个加密隧道用于在客户端和服务器之间传输数据。但是 vless 相对于 vmess 有一些不同之处 1. **减少传输数据的开销**vless 协议在传输数据时采用了更加精简的数据格式以减少传输数据的开销提高传输效率。     2. **简化配置**相对于 vmessvless 的配置更加简单主要是因为它省略了一些在某些情况下不必要的选项和字段。 3. **增强安全性**vless 在安全性方面与 vmess 相当都是采用了 TLS 加密和传输保障了数据的安全性和隐私。 4. **性能提升**由于 vless 减少了数据传输的开销并且在设计上更加精简因此在一些场景下可能会提供更好的性能表现。 总的来说vless 协议是为了简化配置、提高性能、减少传输开销而设计的一种协议它保留了 vmess 协议的安全性和灵活性同时简化了配置和提高了性能。 3、Cloud flare-works实例 Cloudflare的Works是Cloudflare推出的一系列整合服务旨在为企业提供更全面的网络安全和性能优化解决方案。Works整合了Cloudflare的不同产品包括 1. **Access** 提供零信任访问控制确保用户可以安全地访问企业网络和应用程序无论他们身在何处。 2. **Gateway** 提供安全的互联网访问包括网络内容过滤、恶意软件防护、广告拦截和隐私保护。 3. **Spectrum** 扩展Cloudflare的边缘网络保护到任何TCP/UDP流量使得所有的网络流量都能受到Cloudflare的保护。 4. **Workers** 允许开发者在Cloudflare的边缘网络上运行轻量级的JavaScript代码从而实现定制化的网络功能和逻辑。 5. **Orbit** 提供实时的API和事件监控使得开发者可以实时地查看和分析其应用程序的性能和行为。 通过将这些服务整合在一起Cloudflare Works可以为企业提供更强大、更全面的网络安全和性能优化解决方案帮助他们保护应用程序、数据和用户并提高网络性能和可用性。 4、UUID UUIDUniversally Unique Identifier是一种标识符用于在计算系统中唯一地标识信息或实体。它是由一个128位的数字组成通常以32个十六进制数字的形式表示中间用连字符分隔。UUID的生成算法保证了在理论上具有非常低的重复概率。 UUID广泛应用于各种场景例如 1. 数据库系统UUID可以用作数据库表格的主键确保每个记录在整个数据库中具有唯一标识。 2. 分布式系统在分布式系统中UUID可以用于唯一标识各个节点、任务或事件以确保全局唯一性。 3. 软件开发开发人员可以使用UUID作为临时文件名、会话标识符或唯一的标识符来跟踪和管理数据。 4. 网络通信UUID可以用于标识网络协议中的消息、数据包或会话以确保唯一性和识别性。 总之UUID是一种在计算系统中用于唯一标识信息或实体的标识符具有广泛的应用领域。 接下来我们开始创建workers实例 二、创建workers 1、访问cloud flare 先进入官网Cloud flare 请记住访问cloud flare时会有人机验证照常过就行如果无法通过请开启霍格沃兹力量或者切换IP即可。 这里已经进入首页可以在右上角调整语言设置 首先你要有非CN的账号推荐使用Google我这里使用Google/US账户进行注册登录 进入cloud flare首页在左侧找到workers和pages进入。 2、创建workers 进入创建应用程序开始创建一个workers实例。 给你的workers创建一个名称我这里就使用ceshi然后点击部署。 部署完成后点击编辑代码。 将默认原来的代码全部清除 3、实例代码部署 edgetunnel/src/worker-vless.js at main · leilei223/edgetunnel · GitHub 实例代码1、本章节使用 清除后导入workers代码 // !--GAMFC--version base on commit 43fad05dcdae3b723c53c226f8181fc5bd47223e, time is 2023-06-22 15:20:02 UTC!--GAMFC-END--. // ts-ignore import { connect } from cloudflare:sockets;// How to generate your own UUID: // [Windows] Press Win R, input cmd and run: Powershell -NoExit -Command [guid]::NewGuid() let userID UUID;let proxyIP CDN-IP;if (!isValidUUID(userID)) {throw new Error(uuid is not valid); }export default {/*** param {import(cloudflare/workers-types).Request} request* param {{UUID: string, PROXYIP: string}} env* param {import(cloudflare/workers-types).ExecutionContext} ctx* returns {PromiseResponse}*/async fetch(request, env, ctx) {try {userID env.UUID || userID;proxyIP env.PROXYIP || proxyIP;const upgradeHeader request.headers.get(Upgrade);if (!upgradeHeader || upgradeHeader ! websocket) {const url new URL(request.url);switch (url.pathname) {case /:return new Response(JSON.stringify(request.cf), { status: 200 });case /${userID}: {const vlessConfig getVLESSConfig(userID, request.headers.get(Host));return new Response(${vlessConfig}, {status: 200,headers: {Content-Type: text/plain;charsetutf-8,}});}default:return new Response(Not found, { status: 404 });}} else {return await vlessOverWSHandler(request);}} catch (err) {/** type {Error} */ let e err;return new Response(e.toString());}}, };/*** * param {import(cloudflare/workers-types).Request} request*/ async function vlessOverWSHandler(request) {/** type {import(cloudflare/workers-types).WebSocket[]} */// ts-ignoreconst webSocketPair new WebSocketPair();const [client, webSocket] Object.values(webSocketPair);webSocket.accept();let address ;let portWithRandomLog ;const log (/** type {string} */ info, /** type {string | undefined} */ event) {console.log([${address}:${portWithRandomLog}] ${info}, event || );};const earlyDataHeader request.headers.get(sec-websocket-protocol) || ;const readableWebSocketStream makeReadableWebSocketStream(webSocket, earlyDataHeader, log);/** type {{ value: import(cloudflare/workers-types).Socket | null}}*/let remoteSocketWapper {value: null,};let udpStreamWrite null;let isDns false;// ws -- remotereadableWebSocketStream.pipeTo(new WritableStream({async write(chunk, controller) {if (isDns udpStreamWrite) {return udpStreamWrite(chunk);}if (remoteSocketWapper.value) {const writer remoteSocketWapper.value.writable.getWriter()await writer.write(chunk);writer.releaseLock();return;}const {hasError,message,portRemote 443,addressRemote ,rawDataIndex,vlessVersion new Uint8Array([0, 0]),isUDP,} processVlessHeader(chunk, userID);address addressRemote;portWithRandomLog ${portRemote}--${Math.random()} ${isUDP ? udp : tcp } ;if (hasError) {// controller.error(message);throw new Error(message); // cf seems has bug, controller.error will not end stream// webSocket.close(1000, message);return;}// if UDP but port not DNS port, close itif (isUDP) {if (portRemote 53) {isDns true;} else {// controller.error(UDP proxy only enable for DNS which is port 53);throw new Error(UDP proxy only enable for DNS which is port 53); // cf seems has bug, controller.error will not end streamreturn;}}// [version, 附加信息长度 N]const vlessResponseHeader new Uint8Array([vlessVersion[0], 0]);const rawClientData chunk.slice(rawDataIndex);// TODO: support udp here when cf runtime has udp supportif (isDns) {const { write } await handleUDPOutBound(webSocket, vlessResponseHeader, log);udpStreamWrite write;udpStreamWrite(rawClientData);return;}handleTCPOutBound(remoteSocketWapper, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log);},close() {log(readableWebSocketStream is close);},abort(reason) {log(readableWebSocketStream is abort, JSON.stringify(reason));},})).catch((err) {log(readableWebSocketStream pipeTo error, err);});return new Response(null, {status: 101,// ts-ignorewebSocket: client,}); }/*** Handles outbound TCP connections.** param {any} remoteSocket * param {string} addressRemote The remote address to connect to.* param {number} portRemote The remote port to connect to.* param {Uint8Array} rawClientData The raw client data to write.* param {import(cloudflare/workers-types).WebSocket} webSocket The WebSocket to pass the remote socket to.* param {Uint8Array} vlessResponseHeader The VLESS response header.* param {function} log The logging function.* returns {Promisevoid} The remote socket.*/ async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log,) {async function connectAndWrite(address, port) {/** type {import(cloudflare/workers-types).Socket} */const tcpSocket connect({hostname: address,port: port,});remoteSocket.value tcpSocket;log(connected to ${address}:${port});const writer tcpSocket.writable.getWriter();await writer.write(rawClientData); // first write, nomal is tls client hellowriter.releaseLock();return tcpSocket;}// if the cf connect tcp socket have no incoming data, we retry to redirect ipasync function retry() {const tcpSocket await connectAndWrite(proxyIP || addressRemote, portRemote)// no matter retry success or not, close websockettcpSocket.closed.catch(error {console.log(retry tcpSocket closed error, error);}).finally(() {safeCloseWebSocket(webSocket);})remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, null, log);}const tcpSocket await connectAndWrite(addressRemote, portRemote);// when remoteSocket is ready, pass to websocket// remote-- wsremoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, retry, log); }/*** * param {import(cloudflare/workers-types).WebSocket} webSocketServer* param {string} earlyDataHeader for ws 0rtt* param {(info: string) void} log for ws 0rtt*/ function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) {let readableStreamCancel false;const stream new ReadableStream({start(controller) {webSocketServer.addEventListener(message, (event) {if (readableStreamCancel) {return;}const message event.data;controller.enqueue(message);});// The event means that the client closed the client - server stream.// However, the server - client stream is still open until you call close() on the server side.// The WebSocket protocol says that a separate close message must be sent in each direction to fully close the socket.webSocketServer.addEventListener(close, () {// client send close, need close server// if stream is cancel, skip controller.closesafeCloseWebSocket(webSocketServer);if (readableStreamCancel) {return;}controller.close();});webSocketServer.addEventListener(error, (err) {log(webSocketServer has error);controller.error(err);});// for ws 0rttconst { earlyData, error } base64ToArrayBuffer(earlyDataHeader);if (error) {controller.error(error);} else if (earlyData) {controller.enqueue(earlyData);}},pull(controller) {// if ws can stop read if stream is full, we can implement backpressure// https://streams.spec.whatwg.org/#example-rs-push-backpressure},cancel(reason) {// 1. pipe WritableStream has error, this cancel will called, so ws handle server close into here// 2. if readableStream is cancel, all controller.close/enqueue need skip,// 3. but from testing controller.error still work even if readableStream is cancelif (readableStreamCancel) {return;}log(ReadableStream was canceled, due to ${reason})readableStreamCancel true;safeCloseWebSocket(webSocketServer);}});return stream;}// https://xtls.github.io/development/protocols/vless.html // https://github.com/zizifn/excalidraw-backup/blob/main/v2ray-protocol.excalidraw/*** * param { ArrayBuffer} vlessBuffer * param {string} userID * returns */ function processVlessHeader( vlessBuffer,userID) {if (vlessBuffer.byteLength 24) {return {hasError: true,message: invalid data,};}const version new Uint8Array(vlessBuffer.slice(0, 1));let isValidUser false;let isUDP false;if (stringify(new Uint8Array(vlessBuffer.slice(1, 17))) userID) {isValidUser true;}if (!isValidUser) {return {hasError: true,message: invalid user,};}const optLength new Uint8Array(vlessBuffer.slice(17, 18))[0];//skip opt for nowconst command new Uint8Array(vlessBuffer.slice(18 optLength, 18 optLength 1))[0];// 0x01 TCP// 0x02 UDP// 0x03 MUXif (command 1) {} else if (command 2) {isUDP true;} else {return {hasError: true,message: command ${command} is not support, command 01-tcp,02-udp,03-mux,};}const portIndex 18 optLength 1;const portBuffer vlessBuffer.slice(portIndex, portIndex 2);// port is big-Endian in raw data etc 80 0x005dconst portRemote new DataView(portBuffer).getUint16(0);let addressIndex portIndex 2;const addressBuffer new Uint8Array(vlessBuffer.slice(addressIndex, addressIndex 1));// 1-- ipv4 addressLength 4// 2-- domain name addressLengthaddressBuffer[1]// 3-- ipv6 addressLength 16const addressType addressBuffer[0];let addressLength 0;let addressValueIndex addressIndex 1;let addressValue ;switch (addressType) {case 1:addressLength 4;addressValue new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex addressLength)).join(.);break;case 2:addressLength new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex 1))[0];addressValueIndex 1;addressValue new TextDecoder().decode(vlessBuffer.slice(addressValueIndex, addressValueIndex addressLength));break;case 3:addressLength 16;const dataView new DataView(vlessBuffer.slice(addressValueIndex, addressValueIndex addressLength));// 2001:0db8:85a3:0000:0000:8a2e:0370:7334const ipv6 [];for (let i 0; i 8; i) {ipv6.push(dataView.getUint16(i * 2).toString(16));}addressValue ipv6.join(:);// seems no need add [] for ipv6break;default:return {hasError: true,message: invild addressType is ${addressType},};}if (!addressValue) {return {hasError: true,message: addressValue is empty, addressType is ${addressType},};}return {hasError: false,addressRemote: addressValue,addressType,portRemote,rawDataIndex: addressValueIndex addressLength,vlessVersion: version,isUDP,}; }/*** * param {import(cloudflare/workers-types).Socket} remoteSocket * param {import(cloudflare/workers-types).WebSocket} webSocket * param {ArrayBuffer} vlessResponseHeader * param {(() Promisevoid) | null} retry* param {*} log */ async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) {// remote-- wslet remoteChunkCount 0;let chunks [];/** type {ArrayBuffer | null} */let vlessHeader vlessResponseHeader;let hasIncomingData false; // check if remoteSocket has incoming dataawait remoteSocket.readable.pipeTo(new WritableStream({start() {},/*** * param {Uint8Array} chunk * param {*} controller */async write(chunk, controller) {hasIncomingData true;// remoteChunkCount;if (webSocket.readyState ! WS_READY_STATE_OPEN) {controller.error(webSocket.readyState is not open, maybe close);}if (vlessHeader) {webSocket.send(await new Blob([vlessHeader, chunk]).arrayBuffer());vlessHeader null;} else {// seems no need rate limit this, CF seems fix this??..// if (remoteChunkCount 20000) {// // cf one package is 4096 byte(4kb), 4096 * 20000 80M// await delay(1);// }webSocket.send(chunk);}},close() {log(remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData});// safeCloseWebSocket(webSocket); // no need server close websocket frist for some case will casue HTTP ERR_CONTENT_LENGTH_MISMATCH issue, client will send close event anyway.},abort(reason) {console.error(remoteConnection!.readable abort, reason);},})).catch((error) {console.error(remoteSocketToWS has exception ,error.stack || error);safeCloseWebSocket(webSocket);});// seems is cf connect socket have error,// 1. Socket.closed will have error// 2. Socket.readable will be close without any data comingif (hasIncomingData false retry) {log(retry)retry();} }/*** * param {string} base64Str * returns */ function base64ToArrayBuffer(base64Str) {if (!base64Str) {return { error: null };}try {// go use modified Base64 for URL rfc4648 which js atob not supportbase64Str base64Str.replace(/-/g, ).replace(/_/g, /);const decode atob(base64Str);const arryBuffer Uint8Array.from(decode, (c) c.charCodeAt(0));return { earlyData: arryBuffer.buffer, error: null };} catch (error) {return { error };} }/*** This is not real UUID validation* param {string} uuid */ function isValidUUID(uuid) {const uuidRegex /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;return uuidRegex.test(uuid); }const WS_READY_STATE_OPEN 1; const WS_READY_STATE_CLOSING 2; /*** Normally, WebSocket will not has exceptions when close.* param {import(cloudflare/workers-types).WebSocket} socket*/ function safeCloseWebSocket(socket) {try {if (socket.readyState WS_READY_STATE_OPEN || socket.readyState WS_READY_STATE_CLOSING) {socket.close();}} catch (error) {console.error(safeCloseWebSocket error, error);} }const byteToHex []; for (let i 0; i 256; i) {byteToHex.push((i 256).toString(16).slice(1)); } function unsafeStringify(arr, offset 0) {return (byteToHex[arr[offset 0]] byteToHex[arr[offset 1]] byteToHex[arr[offset 2]] byteToHex[arr[offset 3]] - byteToHex[arr[offset 4]] byteToHex[arr[offset 5]] - byteToHex[arr[offset 6]] byteToHex[arr[offset 7]] - byteToHex[arr[offset 8]] byteToHex[arr[offset 9]] - byteToHex[arr[offset 10]] byteToHex[arr[offset 11]] byteToHex[arr[offset 12]] byteToHex[arr[offset 13]] byteToHex[arr[offset 14]] byteToHex[arr[offset 15]]).toLowerCase(); } function stringify(arr, offset 0) {const uuid unsafeStringify(arr, offset);if (!isValidUUID(uuid)) {throw TypeError(Stringified UUID is invalid);}return uuid; }/*** * param {import(cloudflare/workers-types).WebSocket} webSocket * param {ArrayBuffer} vlessResponseHeader * param {(string) void} log */ async function handleUDPOutBound(webSocket, vlessResponseHeader, log) {let isVlessHeaderSent 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 messagefor (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 nowtransformStream.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 (isVlessHeaderSent) {webSocket.send(await new Blob([udpSizeBuffer, dnsQueryResult]).arrayBuffer());} else {webSocket.send(await new Blob([vlessResponseHeader, udpSizeBuffer, dnsQueryResult]).arrayBuffer());isVlessHeaderSent true;}}}})).catch((error) {log(dns udp has error error)});const writer transformStream.writable.getWriter();return {/*** * param {Uint8Array} chunk */write(chunk) {writer.write(chunk);}}; }/*** * param {string} userID * param {string | null} hostName* returns {string}*/ function getVLESSConfig(userID, hostName) {const vlessMain vless://${userID}${hostName}:443?encryptionnonesecuritytlssni${hostName}fprandomizedtypewshost${hostName}path%2F%3Fed%3D2048#${hostName}return ################################################################ v2ray --------------------------------------------------------------- ${vlessMain} --------------------------------------------------------------- ################################################################ clash-meta --------------------------------------------------------------- - type: vlessname: ${hostName}server: ${hostName}port: 443uuid: ${userID}network: wstls: trueudp: falsesni: ${hostName}client-fingerprint: chromews-opts:path: /?ed2048headers:host: ${hostName} --------------------------------------------------------------- ################################################################ ; } 代码文件workers.js同时存于GitHub 实例代码2、进阶玩家使用 提供给有技术能力的极客玩家和开发者们自行开发支持伪装域名等等借鉴E家之长零度解说。 // ts-ignore import { connect } from cloudflare:sockets; ts-ignore import { connect } from cloudflaresockets; // How to generate your own UUID: // [Windows] Press Win R, input cmd and run: Powershell -NoExit -Command [guid]::NewGuid() let userID d342d11e-d424-4583-b36e-524ab1f0afa4; 如何生成自己的 UUID // [Windows] 按“Win R”输入 cmd 并运行 Powershell -NoExit -Command “[guid]NewGuid” let userID d342d11e-d424-4583-b36e-524ab1f0afa4; const proxyIPs [cdn.xn--b6gac.eu.org, cdn-all.xn--b6gac.eu.org, workers.cloudflare.cyou]; const proxyIPs [cdn.xn--b6gac.eu.org cdn-all.xn--b6gac.eu.org workers.cloudflare.cyou]; // if you want to use ipv6 or single proxyIP, please add comment at this line and remove comment at the next line let proxyIP proxyIPs[Math.floor(Math.random() * proxyIPs.length)]; // use single proxyIP instead of random // let proxyIP cdn.xn--b6gac.eu.org; // ipv6 proxyIP example remove comment to use // let proxyIP [2a01:4f8:c2c:123f:64:5:6810:c55a] 如果要使用 ipv6 或单个 proxyIP请在此行添加注释并在下一行删除注释 let proxyIP proxyIPs[Math.floorMath.random * proxyIPs.length];use single proxyIP instead of random // let proxyIP cdn.xn--b6gac.eu.org;ipv6 proxyIP 示例删除要使用的注释 // let proxyIP “[2a014f8c2c123f6456810c55a]” let dohURL https://sky.rethinkdns.com/1:-Pf_____9_8A_AMAIgE8kMABVDDmKOHTAKg; // https://cloudflare-dns.com/dns-query or https://dns.google/dns-query 让 dohURL https://sky.rethinkdns.com/1:-Pf_____9_8A_AMAIgE8kMABVDDmKOHTAKg;https://cloudflare-dns.com/dns-query 或 https://dns.google/dns-query if (!isValidUUID(userID)) {throw new Error(uuid is invalid); } if isValidUUIDuserID { throw new Erroruuid is invalid; export default {/*** param {import(cloudflare/workers-types).Request} request* param {{UUID: string, PROXYIP: string, DNS_RESOLVER_URL: string, NODE_ID: int, API_HOST: string, API_TOKEN: string}} env* param {import(cloudflare/workers-types).ExecutionContext} ctx* returns {PromiseResponse}*/async fetch(request, env, ctx) {// uuid_validator(request);try {userID env.UUID || userID;proxyIP env.PROXYIP || proxyIP;dohURL env.DNS_RESOLVER_URL || dohURL;let userID_Path userID;if (userID.includes(,)) {userID_Path userID.split(,)[0];}const upgradeHeader request.headers.get(Upgrade);if (!upgradeHeader || upgradeHeader ! websocket) {const url new URL(request.url);switch (url.pathname) {case /cf: {return new Response(JSON.stringify(request.cf, null, 4), {status: 200,headers: {Content-Type: application/json;charsetutf-8,},});}case /${userID_Path}: {const vlessConfig getVLESSConfig(userID, request.headers.get(Host));return new Response(${vlessConfig}, {status: 200,headers: {Content-Type: text/html; charsetutf-8,}});};case /sub/${userID_Path}: {const url new URL(request.url);const searchParams url.searchParams;const vlessSubConfig createVLESSSub(userID, request.headers.get(Host));// Construct and return response objectreturn new Response(btoa(vlessSubConfig), {status: 200,headers: {Content-Type: text/plain;charsetutf-8,}});};case /bestip/${userID_Path}: {const headers request.headers;const url https://sub.xf.free.hr/auto?host${request.headers.get(Host)}uuid${userID}path/;const bestSubConfig await fetch(url, { headers: headers });return bestSubConfig;};default:// return new Response(Not found, { status: 404 });// For any other path, reverse proxy to ramdom website and return the original response, caching it in the processconst randomHostname cn_hostnames[Math.floor(Math.random() * cn_hostnames.length)];const newHeaders new Headers(request.headers);newHeaders.set(cf-connecting-ip, 1.2.3.4);newHeaders.set(x-forwarded-for, 1.2.3.4);newHeaders.set(x-real-ip, 1.2.3.4);newHeaders.set(referer, https://www.google.com/search?qedtunnel);// Use fetch to proxy the request to 15 different domainsconst proxyUrl https:// randomHostname url.pathname url.search;let modifiedRequest new Request(proxyUrl, {method: request.method,headers: newHeaders,body: request.body,redirect: manual,});const proxyResponse await fetch(modifiedRequest, { redirect: manual });// Check for 302 or 301 redirect status and return an error responseif ([301, 302].includes(proxyResponse.status)) {return new Response(Redirects to ${randomHostname} are not allowed., {status: 403,statusText: Forbidden,});}// Return the response from the proxy serverreturn proxyResponse;}} else {return await vlessOverWSHandler(request);}} catch (err) {/** type {Error} */ let e err;return new Response(e.toString());}}, }; 导出默认值 { /** * param {import“cloudflare/workers-types”。request} request * param {{UUID string PROXYIP string DNS_RESOLVER_URL string NODE_ID int API_HOST string API_TOKEN string}} env * param {import“cloudflare/workers-types”。ExecutionContext} ctx * returns {PromiseResponse} */ async fetchrequest env ctx { // uuid_validatorrequest; try { userID env.UUID ||用户 ID;proxyIP 环境。代理IP ||代理IP;dohURL 环境。DNS_RESOLVER_URL ||dohURL;let userID_Path userID;if userID.includes { userID_Path userID.split[0]; } const upgradeHeader request.headers.get升级;if upgradeHeader || upgradeHeader websocket { const url new URLrequest.url; switch url.pathname { case /cf { return new ResponseJSON.stringifyrequest.cf null 4 { status 200 headers { “Content-Type” “application/json;charsetutf-8“ } };} case /${userID_Path} { const vlessConfig getVLESSConfiguserID request.headers.getHost; return new Response${vlessConfig} { status 200 headers { “Content-Type” “text/html;charsetutf-8“ } };};case /sub/${userID_Path} { const url new URLrequest.url; const searchParams url.searchParams; const vlessSubConfig createVLESSSubuserID request.headers.getHost; // 构造并返回响应对象 return new ResponsebtoavlessSubConfig { status 200 headers { “Content-Type” “text/plain;charsetutf-8“ } };};case /bestip/${userID_Path} { const headers request.headers; const url https://sub.xf.free.hr/auto?host${request.headers.get主机}uuid${userID}path/;const bestSubConfig await fetchurl { headers headers };返回 bestSubConfig;};default // 返回 new ResponseNot found { status 404 };对于任何其他路径反向代理到“ramdom website”并返回原始响应将其缓存在进程中 const randomHostname cn_hostnames[Math.floorMath.random * cn_hostnames.length];const newHeaders 新标头request.headers;newHeaders.setcf-connecting-ip 1.2.3.4;newHeaders.setx-转发-for 1.2.3.4;newHeaders.setx-real-ip 1.2.3.4;newHeaders.setreferer https://www.google.com/search?qedtunnel;使用 fetch 将请求代理到 15 个不同的域 const proxyUrl https:// randomHostname url.pathname url.search;let modifiedRequest new RequestproxyUrl { method request.method headers newHeaders body request.body redirect manual };const proxyResponse await fetchmodifiedRequest { redirect manual };检查 302 或 301 重定向状态并返回错误响应 if [301 302].includesproxyResponse.status { return new ResponseRedirects to ${randomHostname} are not allowed. { status 403 statusText Forbidden }; } // 从代理服务器返回响应 return proxyResponse;} } else { return await vlessOverWSHandlerrequest;catch err { /** type {Error} */ let e err; return new Responsee.toString;} }, }; export async function uuid_validator(request) {const hostname request.headers.get(Host);const currentDate new Date(); export async function uuid_validatorrequest { const hostname request.headers.getHost; const currentDate new Date;const subdomain hostname.split(.)[0];const year currentDate.getFullYear();const month String(currentDate.getMonth() 1).padStart(2, 0);const day String(currentDate.getDate()).padStart(2, 0); 常量子域 hostname.split.[0];常量年份 currentDate.getFullYear;常量月 StringcurrentDate.getMonth 1.padStart2 0;const day StringcurrentDate.getDate.padStart2 0;const formattedDate ${year}-${month}-${day}; const formattedDate ${year}-${month}-${day};// const daliy_sub formattedDate subdomainconst hashHex await hashHex_f(subdomain);// subdomain string contains timestamps utc and uuid string TODO.console.log(hashHex, subdomain, formattedDate); } const daliy_sub formattedDate 子域 const hashHex await hashHex_f子域;子域字符串包含时间戳 UTC 和 UUID 字符串 TODO。console.loghashHex subdomain formattedDate;} export async function hashHex_f(string) {const encoder new TextEncoder();const data encoder.encode(string);const hashBuffer await crypto.subtle.digest(SHA-256, data);const hashArray Array.from(new Uint8Array(hashBuffer));const hashHex hashArray.map(byte byte.toString(16).padStart(2, 0)).join();return hashHex; } export async function hashHex_fstring { const encoder new TextEncoder; const data encoder.encodestring; const hashBuffer await crypto.subtle.digestSHA-256 data; const hashArray Array.fromnew Uint8ArrayhashBuffer; const hashHex hashArray.mapbyte byte.toString16.padStart2 0.join; return hashHex; } /*** Handles VLESS over WebSocket requests by creating a WebSocket pair, accepting the WebSocket connection, and processing the VLESS header.* param {import(cloudflare/workers-types).Request} request The incoming request object.* returns {PromiseResponse} A Promise that resolves to a WebSocket response object.*/ async function vlessOverWSHandler(request) {const webSocketPair new WebSocketPair();const [client, webSocket] Object.values(webSocketPair);webSocket.accept(); /** * 通过创建 WebSocket 对、接受 WebSocket 连接并处理 VLESS 标头来处理 VLESS over WebSocket 请求。* param {import“cloudflare/workers-types”。Request} request 传入的请求对象。* returns {Promise} 解Response析为 WebSocket 响应对象的 Promise。 */ 异步函数 vlessOverWSHandlerrequest { const webSocketPair new WebSocketPair; const [client webSocket] Object.valueswebSocketPair; webSocket.accept;let address ;let portWithRandomLog ;let currentDate new Date();const log (/** type {string} */ info, /** type {string | undefined} */ event) {console.log([${currentDate} ${address}:${portWithRandomLog}] ${info}, event || );};const earlyDataHeader request.headers.get(sec-websocket-protocol) || ; let address ;easy portWithRandomLog ;let currentDate 新日期;const log /** type {string} */ info /** type {string | undefined} */ event { console.log[${currentDate} ${address}${portWithRandomLog}] ${info} event ||);};const earlyDataHeader request.headers.getsec-websocket-protocol ||;const readableWebSocketStream makeReadableWebSocketStream(webSocket, earlyDataHeader, log); const readableWebSocketStream makeReadableWebSocketStreamwebSocket earlyDataHeader log;/** type {{ value: import(cloudflare/workers-types).Socket | null}}*/let remoteSocketWapper {value: null,};let udpStreamWrite null;let isDns false; /** type {{ value import“cloudflare/workers-types”。插座 |null}}*/ let remoteSocketWapper { value null };让 udpStreamWrite null;let isDns false;// ws -- remotereadableWebSocketStream.pipeTo(new WritableStream({async write(chunk, controller) {if (isDns udpStreamWrite) {return udpStreamWrite(chunk);}if (remoteSocketWapper.value) {const writer remoteSocketWapper.value.writable.getWriter()await writer.write(chunk);writer.releaseLock();return;} ws -- remote readableWebSocketStream.pipeTonew WritableStream{ async writechunk controller { if isDns ; udpStreamWrite { return udpStreamWritechunk; } if remoteSocketWapper.value { const writer remoteSocketWapper.value.writable.getWriter await writer.writechunk; writer.releaseLock; return; }const {hasError,message,portRemote 443,addressRemote ,rawDataIndex,vlessVersion new Uint8Array([0, 0]),isUDP,} processVlessHeader(chunk, userID);address addressRemote;portWithRandomLog ${portRemote} ${isUDP ? udp : tcp} ;if (hasError) {// controller.error(message);throw new Error(message); // cf seems has bug, controller.error will not end stream} const { hasError message portRemote 443 addressRemote rawDataIndex vlessVersion new Uint8Array[0 0] isUDP } processVlessHeaderchunk userID;地址 addressRemote;portWithRandomLog ${portRemote} ${isUDP udp tcp} ;if hasError { // controller.errormessage; throw new Errormessage; // cf 似乎有 bugcontroller.error 不会结束流 }// If UDP and not DNS port, close itif (isUDP portRemote ! 53) {throw new Error(UDP proxy only enabled for DNS which is port 53);// cf seems has bug, controller.error will not end stream} 如果 UDP 而不是 DNS 端口请关闭它 if isUDP portRemote 53 { throw new ErrorUDP proxy only enabled for DNS which is port 53; // cf 似乎有 bugcontroller.error 不会结束流 }if (isUDP portRemote 53) {isDns true;} if isUDP portRemote 53 { isDns true;// [version, 附加信息长度 N]const vlessResponseHeader new Uint8Array([vlessVersion[0], 0]);const rawClientData chunk.slice(rawDataIndex); [“version” “附加信息长度 N”] const vlessResponseHeader new Uint8Array[vlessVersion[0] 0];const rawClientData chunk.slicerawDataIndex;// TODO: support udp here when cf runtime has udp supportif (isDns) {const { write } await handleUDPOutBound(webSocket, vlessResponseHeader, log);udpStreamWrite write;udpStreamWrite(rawClientData);return;}handleTCPOutBound(remoteSocketWapper, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log);},close() {log(readableWebSocketStream is close);},abort(reason) {log(readableWebSocketStream is abort, JSON.stringify(reason));},})).catch((err) {log(readableWebSocketStream pipeTo error, err);}); TODO当 cf 运行时支持 udp 时这里支持 udp if isDns { const { write } await handleUDPOutBoundwebSocket vlessResponseHeader log; udpStreamWrite write; udpStreamWriterawClientData; return; } handleTCPOutBoundremoteSocketWapper addressRemote portRemote rawClientData webSocket vlessResponseHeader log;} close { logreadableWebSocketStream is close; } abortreason { logreadableWebSocketStream is abort JSON.stringifyreason; } }.catcherr { logreadableWebSocketStream pipeTo error err;return new Response(null, {status: 101,webSocket: client,}); } return new Responsenull { status 101 webSocket client };} /*** Handles outbound TCP connections.** param {any} remoteSocket * param {string} addressRemote The remote address to connect to.* param {number} portRemote The remote port to connect to.* param {Uint8Array} rawClientData The raw client data to write.* param {import(cloudflare/workers-types).WebSocket} webSocket The WebSocket to pass the remote socket to.* param {Uint8Array} vlessResponseHeader The VLESS response header.* param {function} log The logging function.* returns {Promisevoid} The remote socket.*/ async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log,) { /** * 处理出站 TCP 连接。* * param {any} remoteSocket * param {string} addressRemote 要连接到的远程地址。* param {number} portRemote 要连接到的远程端口。* param {Uint8Array} rawClientData 要写入的原始客户端数据。* param {import“cloudflare/workers-types”。WebSocket} webSocket 要将远程套接字传递到的 WebSocket。* param {Uint8Array} vlessResponseHeader VLESS 响应标头。* param {function} log 日志记录函数。* returns {Promisevoid} 远程套接字。 */ 异步函数 handleTCPOutBoundremoteSocket addressRemote portRemote rawClientData webSocket vlessResponseHeader log {/*** Connects to a given address and port and writes data to the socket.* param {string} address The address to connect to.* param {number} port The port to connect to.* returns {Promiseimport(cloudflare/workers-types).Socket} A Promise that resolves to the connected socket.*/async function connectAndWrite(address, port) {/** type {import(cloudflare/workers-types).Socket} */const tcpSocket connect({hostname: address,port: port,});remoteSocket.value tcpSocket;log(connected to ${address}:${port});const writer tcpSocket.writable.getWriter();await writer.write(rawClientData); // first write, nomal is tls client hellowriter.releaseLock();return tcpSocket;} /** * 连接到给定的地址和端口并将数据写入套接字。* param {string} address 要连接到的地址。* param {number} port 要连接到的端口。* returns {Promiseimport“cloudflare/workers-types”。Socket} 解析为连接的套接字的 Promise。*/ 异步函数 connectAndWriteaddress port { /** type {import“cloudflare/workers-types”。套接字} */ const tcpSocket connect{ hostname address port port };remoteSocket.value tcpSocket;log连接到${address}${port};常量写入器 tcpSocket.writable.getWriter;等待 writer.writerawClientData;首先写入nomal 是 tls 客户端 hello writer.releaseLock;返回 tcpSocket;}/*** Retries connecting to the remote address and port if the Cloudflare socket has no incoming data.* returns {Promisevoid} A Promise that resolves when the retry is complete.*/async function retry() {const tcpSocket await connectAndWrite(proxyIP || addressRemote, portRemote)tcpSocket.closed.catch(error {console.log(retry tcpSocket closed error, error);}).finally(() {safeCloseWebSocket(webSocket);})remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, null, log);} /** * 如果 Cloudflare 套接字没有传入数据则重试连接到远程地址和端口。* returns {Promisevoid} 重试完成后解析的 Promise。 */ 异步函数 retry { const tcpSocket await connectAndWriteproxyIP || addressRemote portRemote tcpSocket.closed.catcherror { console.logretry tcpSocket closed error error;finally { safeCloseWebSocketwebSocket; remoteSocketToWStcpSocket webSocket vlessResponseHeader null log;}const tcpSocket await connectAndWrite(addressRemote, portRemote); const tcpSocket await connectAndWriteaddressRemote portRemote;// when remoteSocket is ready, pass to websocket// remote-- wsremoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, retry, log); } 当 remoteSocket 准备就绪时传递到 websocket // remote-- ws remoteSocketToWStcpSocket webSocket vlessResponseHeader retry log;} /*** Creates a readable stream from a WebSocket server, allowing for data to be read from the WebSocket.* param {import(cloudflare/workers-types).WebSocket} webSocketServer The WebSocket server to create the readable stream from.* param {string} earlyDataHeader The header containing early data for WebSocket 0-RTT.* param {(info: string) void} log The logging function.* returns {ReadableStream} A readable stream that can be used to read data from the WebSocket.*/ function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) {let readableStreamCancel false;const stream new ReadableStream({start(controller) {webSocketServer.addEventListener(message, (event) {const message event.data;controller.enqueue(message);}); /** * 从 WebSocket 服务器创建可读流允许从 WebSocket 读取数据。* param {import“cloudflare/workers-types”。WebSocket} webSocketServer 要从中创建可读流的 WebSocket 服务器。* param {string} earlyDataHeader 包含 WebSocket 0-RTT 早期数据的标头。* param {info string void} log 日志函数。* returns {ReadableStream} 可用于从 WebSocket 读取数据的可读流。*/ function makeReadableWebSocketStreamwebSocketServer earlyDataHeader log { let readableStreamCancel false; const stream new ReadableStream{ startcontroller { webSocketServer.addEventListenermessage event { const message event.data; controller.enqueuemessage;webSocketServer.addEventListener(close, () {safeCloseWebSocket(webSocketServer);controller.close();}); webSocketServer.addEventListenerclose { safeCloseWebSocketwebSocketServer;webSocketServer.addEventListener(error, (err) {log(webSocketServer has error);controller.error(err);});const { earlyData, error } base64ToArrayBuffer(earlyDataHeader);if (error) {controller.error(error);} else if (earlyData) {controller.enqueue(earlyData);}}, webSocketServer.addEventListenererror err { logwebSocketServer has error; controller.errorerr;const { earlyData error } base64ToArrayBufferearlyDataHeader;if error { controller.errorerror; } else if earlyData { controller.enqueueearlyData; } }pull(controller) {// if ws can stop read if stream is full, we can implement backpressure// https://streams.spec.whatwg.org/#example-rs-push-backpressure}, pullcontroller { // 如果 ws 可以在流已满时停止读取我们可以实现背压 // https://streams.spec.whatwg.org/#example-rs-push-backpressure }cancel(reason) {log(ReadableStream was canceled, due to ${reason})readableStreamCancel true;safeCloseWebSocket(webSocketServer);}}); cancelreason { log由于 ${reason}ReadableStream 已取消 true; safeCloseWebSocketwebSocketServer;return stream; } 回流;} // https://xtls.github.io/development/protocols/vless.html // https://github.com/zizifn/excalidraw-backup/blob/main/v2ray-protocol.excalidraw https://xtls.github.io/development/protocols/vless.html // https://github.com/zizifn/excalidraw-backup/blob/main/v2ray-protocol.excalidraw /*** Processes the VLESS header buffer and returns an object with the relevant information.* param {ArrayBuffer} vlessBuffer The VLESS header buffer to process.* param {string} userID The user ID to validate against the UUID in the VLESS header.* returns {{* hasError: boolean,* message?: string,* addressRemote?: string,* addressType?: number,* portRemote?: number,* rawDataIndex?: number,* vlessVersion?: Uint8Array,* isUDP?: boolean* }} An object with the relevant information extracted from the VLESS header buffer.*/ function processVlessHeader(vlessBuffer, userID) {if (vlessBuffer.byteLength 24) {return {hasError: true,message: invalid data,};} /** * 处理 VLESS 标头缓冲区并返回包含相关信息的对象。* param {ArrayBuffer} vlessBuffer 要处理的 VLESS 标头缓冲区。* param {string} userID 要根据 VLESS 标头中的 UUID 进行验证的用户 ID。* returns {{ * hasError boolean * message string * addressRemote string * addressType number * portRemote number * rawDataIndex number * vlessVersion Uint8Array * isUDP boolean * }} 包含从 VLESS 标头缓冲区提取的相关信息的对象。*/ 函数 processVlessHeadervlessBuffer userID { if vlessBuffer.byteLength 24 { return { hasError true message invalid data }; }const version new Uint8Array(vlessBuffer.slice(0, 1));let isValidUser false;let isUDP false;const slicedBuffer new Uint8Array(vlessBuffer.slice(1, 17));const slicedBufferString stringify(slicedBuffer);// check if userID is valid uuid or uuids split by , and contains userID in it otherwise return error message to consoleconst uuids userID.includes(,) ? userID.split(,) : [userID];// uuid_validator(hostName, slicedBufferString); const version new Uint8ArrayvlessBuffer.slice0 1;let isValidUser false;let isUDP false;const slicedBuffer new Uint8ArrayvlessBuffer.slice1 17;const slicedBufferString stringifyslicedBuffer;检查 userID 是否有效 uuid 或 uuids 拆分为 并且其中包含 userID否则返回错误消息到控制台 const uuids userID.includes userID.split“” [用户ID];uuid_validator主机名slicedBufferString;// isValidUser uuids.some(userUuid slicedBufferString userUuid.trim());isValidUser uuids.some(userUuid slicedBufferString userUuid.trim()) || uuids.length 1 slicedBufferString uuids[0].trim(); isValidUser uuids.someuserUuid slicedBufferString userUuid.trim;isValidUser uuids.someuserUuid slicedBufferString userUuid.trim ||uuids.length 1 slicedBufferString uuids[0].trim;console.log(userID: ${slicedBufferString}); console.log用户 ID ${slicedBufferString};if (!isValidUser) {return {hasError: true,message: invalid user,};} if isValidUser { return { hasError true message invalid user };const optLength new Uint8Array(vlessBuffer.slice(17, 18))[0];//skip opt for now const optLength new Uint8ArrayvlessBuffer.slice17 18[0];立即跳过选择const command new Uint8Array(vlessBuffer.slice(18 optLength, 18 optLength 1))[0]; const 命令 new Uint8Array vlessBuffer.slice18 optLength 18 optLength 1 [0];// 0x01 TCP// 0x02 UDP// 0x03 MUXif (command 1) {isUDP false;} else if (command 2) {isUDP true;} else {return {hasError: true,message: command ${command} is not support, command 01-tcp,02-udp,03-mux,};}const portIndex 18 optLength 1;const portBuffer vlessBuffer.slice(portIndex, portIndex 2);// port is big-Endian in raw data etc 80 0x005dconst portRemote new DataView(portBuffer).getUint16(0); 0x01 TCP // 0x02 UDP // 0x03 MUX if command 1 { isUDP false; } else if command 2 { isUDP true; } else { return { hasError true message command ${command} is not support command 01-tcp02-udp03-mux }; } const portIndex 18 optLength 1;const portBuffer vlessBuffer.sliceportIndex portIndex 2;port 在原始数据中是 big-Endian 等 80 0x005d const portRemote new DataViewportBuffer.getUint160;let addressIndex portIndex 2;const addressBuffer new Uint8Array(vlessBuffer.slice(addressIndex, addressIndex 1)); let addressIndex 端口索引 2;const addressBuffer new Uint8Array vlessBuffer.sliceaddressIndex addressIndex 1 ;// 1-- ipv4 addressLength 4// 2-- domain name addressLengthaddressBuffer[1]// 3-- ipv6 addressLength 16const addressType addressBuffer[0];let addressLength 0;let addressValueIndex addressIndex 1;let addressValue ;switch (addressType) {case 1:addressLength 4;addressValue new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex addressLength)).join(.);break;case 2:addressLength new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex 1))[0];addressValueIndex 1;addressValue new TextDecoder().decode(vlessBuffer.slice(addressValueIndex, addressValueIndex addressLength));break;case 3:addressLength 16;const dataView new DataView(vlessBuffer.slice(addressValueIndex, addressValueIndex addressLength));// 2001:0db8:85a3:0000:0000:8a2e:0370:7334const ipv6 [];for (let i 0; i 8; i) {ipv6.push(dataView.getUint16(i * 2).toString(16));}addressValue ipv6.join(:);// seems no need add [] for ipv6break;default:return {hasError: true,message: invild addressType is ${addressType},};}if (!addressValue) {return {hasError: true,message: addressValue is empty, addressType is ${addressType},};} 1-- ipv4 addressLength 4 // 2-- 域名 addressLengthaddressBuffer[1] // 3-- ipv6 addressLength 16 const addressType addressBuffer[0];let addressLength 0;让 addressValueIndex addressIndex 1;let addressValue ;switch addressType { case 1 addressLength 4; addressValue new Uint8Array vlessBuffer.sliceaddressValueIndex addressValueIndex addressLength .join.; break; case 2 addressLength new Uint8Array vlessBuffer.sliceaddressValueIndex addressValueIndex 1 [0]; addressValueIndex 1; addressValue new TextDecoder.decode vlessBuffer.sliceaddressValueIndex addressValueIndex addressLength ; break; case 3 addressLength 16; const dataView new DataView vlessBuffer.sliceaddressValueIndex addressValueIndex addressLength ;20010db885a3000000008a2e03707334 const IPv6 [];for let i 0; i 8; i { ipv6.pushdataView.getUint16i * 2.toString16; } addressValue ipv6.join;似乎不需要为 IPv6 中断添加 [];默认值 return { hasError true message invild addressType is ${addressType} };} if addressValue { return { hasError true message addressValue is empty addressType is ${addressType} }; }return {hasError: false,addressRemote: addressValue,addressType,portRemote,rawDataIndex: addressValueIndex addressLength,vlessVersion: version,isUDP,}; } return { hasError false addressRemote addressValue addressType portRemote rawDataIndex addressValueIndex addressLength vlessVersion version isUDP };}/*** Converts a remote socket to a WebSocket connection.* param {import(cloudflare/workers-types).Socket} remoteSocket The remote socket to convert.* param {import(cloudflare/workers-types).WebSocket} webSocket The WebSocket to connect to.* param {ArrayBuffer | null} vlessResponseHeader The VLESS response header.* param {(() Promisevoid) | null} retry The function to retry the connection if it fails.* param {(info: string) void} log The logging function.* returns {Promisevoid} A Promise that resolves when the conversion is complete.*/ async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) {// remote-- wslet remoteChunkCount 0;let chunks [];/** type {ArrayBuffer | null} */let vlessHeader vlessResponseHeader;let hasIncomingData false; // check if remoteSocket has incoming dataawait remoteSocket.readable.pipeTo(new WritableStream({start() {},/*** * param {Uint8Array} chunk * param {*} controller */async write(chunk, controller) {hasIncomingData true;remoteChunkCount;if (webSocket.readyState ! WS_READY_STATE_OPEN) {controller.error(webSocket.readyState is not open, maybe close);}if (vlessHeader) {webSocket.send(await new Blob([vlessHeader, chunk]).arrayBuffer());vlessHeader null;} else {// console.log(remoteSocketToWS send chunk ${chunk.byteLength});// seems no need rate limit this, CF seems fix this??..// if (remoteChunkCount 20000) {// // cf one package is 4096 byte(4kb), 4096 * 20000 80M// await delay(1);// }webSocket.send(chunk);}},close() {log(remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData});// safeCloseWebSocket(webSocket); // no need server close websocket frist for some case will casue HTTP ERR_CONTENT_LENGTH_MISMATCH issue, client will send close event anyway.},abort(reason) {console.error(remoteConnection!.readable abort, reason);},})).catch((error) {console.error(remoteSocketToWS has exception ,error.stack || error);safeCloseWebSocket(webSocket);});/** * 将远程套接字转换为 WebSocket 连接。* param {import“cloudflare/workers-types”。Socket} remoteSocket 要转换的远程套接字。* param {import“cloudflare/workers-types”。WebSocket} webSocket 要连接到的 WebSocket。* param {ArrayBuffer | null} vlessResponseHeader VLESS 响应标头。* param { Promisevoid | null} retry 如果连接失败则重试连接的函数。 * param {info string void} log 日志记录函数。 * returns {Promisevoid} 转换完成后解析的 Promise。 */ 异步函数 remoteSocketToWSremoteSocket webSocket vlessResponseHeader retry log { // remote-- ws let remoteChunkCount 0; let chunks []; /** type {ArrayBuffer | null} */ let vlessHeader vlessResponseHeader; let hasIncomingData false; // 检查 remoteSocket 是否有传入数据 await remoteSocket.readable .pipeTo new WritableStream{ start { } /** * * param {Uint8Array} chunk * param {*} controller */ async writechunk controller { hasIncomingData true; remoteChunkCount; if webSocket.readyState WS_READY_STATE_OPEN { controller.error webSocket.readyState is not open may close ; } if vlessHeader { webSocket.sendawait new Blob[vlessHeader chunk].arrayBuffer; vlessHeader null; } else { // 控制台。logremoteSocketToWS 发送块 ${chunk.byteLength};似乎不需要速率限制这个CF似乎解决了这个问题??..if remoteChunkCount 20000 { // // cf 一个包是 4096 byte4kb 4096 * 20000 80M // await delay1; // } webSocket.sendchunk;} } close { logremoteConnection.readable 接近hasIncomingData 为 ${hasIncomingData};safeCloseWebSocketwebSocket;在某些情况下不需要服务器关闭 websocket 首先会导致 HTTP ERR_CONTENT_LENGTH_MISMATCH问题客户端无论如何都会发送关闭事件。} abortreason { console.errorremoteConnection.可读中止原因;} } .catcherror { console.error remoteSocketToWS has exception error.堆栈 ||错误;safeCloseWebSocketwebSocket;});// seems is cf connect socket have error,// 1. Socket.closed will have error// 2. Socket.readable will be close without any data comingif (hasIncomingData false retry) {log(retry)retry();} } 似乎是 cf 连接套接字有错误 // 1.Socket.closed 将出现错误 // 2.Socket.readable 将关闭没有任何数据传入如果 hasIncomingData false ; retry { logretry retry; /*** Decodes a base64 string into an ArrayBuffer.* param {string} base64Str The base64 string to decode.* returns {{earlyData: ArrayBuffer|null, error: Error|null}} An object containing the decoded ArrayBuffer or null if there was an error, and any error that occurred during decoding or null if there was no error.*/ function base64ToArrayBuffer(base64Str) {if (!base64Str) {return { earlyData: null, error: null };}try {// go use modified Base64 for URL rfc4648 which js atob not supportbase64Str base64Str.replace(/-/g, ).replace(/_/g, /);const decode atob(base64Str);const arryBuffer Uint8Array.from(decode, (c) c.charCodeAt(0));return { earlyData: arryBuffer.buffer, error: null };} catch (error) {return { earlyData: null, error };} } /** * 将 base64 字符串解码为 ArrayBuffer。* param {string} base64Str 要解码的 base64 字符串。* returns {{earlyData ArrayBuffer|null error Error|null}} 包含解码的 ArrayBuffer 或 null如果有错误的对象以及解码期间发生的任何错误如果没有错误则包含 null。*/ function base64ToArrayBufferbase64Str { if base64Str { return { earlyData null error null }; } try { // go use modified Base64 for URL rfc4648 which js atob not support base64Str base64Str.replace/-/g .replace/_/g /; const decode atobbase64Str; const arryBuffer Uint8Array.fromdecode c c.charCodeAt0; return { earlyData arryBuffer.buffer error null }; } catch error { return { earlyData null error }; } } /*** Checks if a given string is a valid UUID.* Note: This is not a real UUID validation.* param {string} uuid The string to validate as a UUID.* returns {boolean} True if the string is a valid UUID, false otherwise.*/ function isValidUUID(uuid) {const uuidRegex /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;return uuidRegex.test(uuid); } /** * 检查给定字符串是否为有效的 UUID。* 注意这不是真正的 UUID 验证。* param {string} uuid 要验证为 UUID 的字符串。* returns {boolean} 如果字符串是有效的 UUID则为 true否则为 false。*/ function isValidUUIDuuid { const uuidRegex /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; return uuidRegex.testuuid; } const WS_READY_STATE_OPEN 1; const WS_READY_STATE_CLOSING 2; /*** Closes a WebSocket connection safely without throwing exceptions.* param {import(cloudflare/workers-types).WebSocket} socket The WebSocket connection to close.*/ function safeCloseWebSocket(socket) {try {if (socket.readyState WS_READY_STATE_OPEN || socket.readyState WS_READY_STATE_CLOSING) {socket.close();}} catch (error) {console.error(safeCloseWebSocket error, error);} } 常量 WS_READY_STATE_OPEN 1;常量 WS_READY_STATE_CLOSING 2;/** * 安全地关闭 WebSocket 连接而不会引发异常。* param {import“cloudflare/workers-types”。WebSocket} socket 要关闭的 WebSocket 连接。*/ function safeCloseWebSocketsocket { try { if socket.readyState WS_READY_STATE_OPEN || socket.readyState WS_READY_STATE_CLOSING { socket.close; } } catch error { console.errorsafeCloseWebSocket error error; const byteToHex []; 常量字节ToHex []; for (let i 0; i 256; i) {byteToHex.push((i 256).toString(16).slice(1)); } for let i 0; i 256; i { byteToHex.pushi 256.toString16.slice1; function unsafeStringify(arr, offset 0) {return (byteToHex[arr[offset 0]] byteToHex[arr[offset 1]] byteToHex[arr[offset 2]] byteToHex[arr[offset 3]] - byteToHex[arr[offset 4]] byteToHex[arr[offset 5]] - byteToHex[arr[offset 6]] byteToHex[arr[offset 7]] - byteToHex[arr[offset 8]] byteToHex[arr[offset 9]] - byteToHex[arr[offset 10]] byteToHex[arr[offset 11]] byteToHex[arr[offset 12]] byteToHex[arr[offset 13]] byteToHex[arr[offset 14]] byteToHex[arr[offset 15]]).toLowerCase(); } 函数 unsafeStringifyarr offset 0 { returnbyteToHex[arr[offset 0]] byteToHex[arr[offset 1]] byteToHex[arr[offset 2]] byteToHex[arr[offset 3]] “-” byteToHex[arr[offset 4]] byteToHex[arr[offset 5]] “-” byteToHex[arr[offset 6]] byteToHex[arr[offset 7]] “-” byteToHex[arr[offset 8]] byteToHex[arr[offset 9]] “-” byteToHex[arr[offset 10]] byteToHex[arr[offset 11]] byteToHex[arr[offset 12]] byteToHex[arr[offset 13]] byteToHex[arr[offset 14]] byteToHex[arr[offset 15]].toLowerCase;} function stringify(arr, offset 0) {const uuid unsafeStringify(arr, offset);if (!isValidUUID(uuid)) {throw TypeError(Stringified UUID is invalid);}return uuid; } function stringifyarr offset 0 { const uuid unsafeStringifyarr offset; if isValidUUIDuuid { throw TypeError“Stringified UUID is invalid”; } return uuid; }/*** Handles outbound UDP traffic by transforming the data into DNS queries and sending them over a WebSocket connection.* param {import(cloudflare/workers-types).WebSocket} webSocket The WebSocket connection to send the DNS queries over.* param {ArrayBuffer} vlessResponseHeader The VLESS response header.* param {(string) void} log The logging function.* returns {{write: (chunk: Uint8Array) void}} An object with a write method that accepts a Uint8Array chunk to write to the transform stream.*/ async function handleUDPOutBound(webSocket, vlessResponseHeader, log) { /** * 通过将数据转换为 DNS 查询并通过 WebSocket 连接发送来处理出站 UDP 流量。* param {import“cloudflare/workers-types”。WebSocket} webSocket 用于发送 DNS 查询的 WebSocket 连接。* param {ArrayBuffer} vlessResponseHeader VLESS 响应标头。* param {string void} log 日志函数。* returns {{write chunk Uint8Array void}} 一个对象其写入方法接受 Uint8Array 块以写入转换流。*/ 异步函数 handleUDPOutBoundwebSocket vlessResponseHeader log {let isVlessHeaderSent false;const transformStream new TransformStream({start(controller) { let isVlessHeaderSent false;const transformStream new TransformStream{ startcontroller {},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 messagefor (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) {}}); } transformchunk controller { // udp message 2 byte 是 udp 数据的长度 // TODO 这应该有 bug beacsue 也许 udp 块可以在两个 websocket 消息中 for let index 0; index chunk.byteLength;{ const lengthBuffer chunk.sliceindex index 2; const udpPakcetLength new DataViewlengthBuffer.getUint160; const udpData new Uint8Array chunk.sliceindex 2 index 2 udpPakcetLength ; index index 2 udpPakcetLength; controller.enqueueudpData; }} flushcontroller { } };// only handle dns udp for nowtransformStream.readable.pipeTo(new WritableStream({async write(chunk) {const resp await fetch(dohURL, // dns server url{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 (isVlessHeaderSent) {webSocket.send(await new Blob([udpSizeBuffer, dnsQueryResult]).arrayBuffer());} else {webSocket.send(await new Blob([vlessResponseHeader, udpSizeBuffer, dnsQueryResult]).arrayBuffer());isVlessHeaderSent true;}}}})).catch((error) {log(dns udp has error error)}); 现在只处理 dns udp transformStream.readable.pipeTonew WritableStream{ async writechunk { const resp await fetchdohURL // dns server url { method POST headers { content-type application/dns-message } body chunk } const dnsQueryResult await resp.arrayBuffer; const udpSize dnsQueryResult.byteLength; // console.log[...new Uint8ArraydnsQueryResult].mapx x.toString16;const udpSizeBuffer new Uint8Array[udpSize 8 0xff udpSize 0xff];if webSocket.readyState WS_READY_STATE_OPEN { logdoh 成功且 dns 消息长度为 ${udpSize}; if isVlessHeaderSent { webSocket.sendawait new Blob[udpSizeBuffer dnsQueryResult].arrayBuffer; } else { webSocket.sendawait new Blob[vlessResponseHeader udpSizeBuffer dnsQueryResult].arrayBuffer; isVlessHeaderSent true;}.catcherror { logdns udp has error error };const writer transformStream.writable.getWriter(); 常量写入器 transformStream.writable.getWriter;return {/*** * param {Uint8Array} chunk */write(chunk) {writer.write(chunk);}}; } return { /** * * param {Uint8Array} 块 */ writechunk { writer.writechunk;} /**** param {string} userID - single or comma separated userIDs* param {string | null} hostName* returns {string}*/ function getVLESSConfig(userIDs, hostName) {const commonUrlPart :443?encryptionnonesecuritytlssni${hostName}fprandomizedtypewshost${hostName}path%2F%3Fed%3D2048#${hostName};const hashSeparator ################################################################; /** * * param {string} userID - 单个或逗号分隔的 userID * param {string | null} hostName * returns {string} */ function getVLESSConfiguserIDs hostName { const commonUrlPart 443encryptionnonesecuritytlssni${hostName}fprandomizedtypewshost${hostName}path%2F%3Fed%3D2048#${hostName}; const hashSeparator “################################################################”;// Split the userIDs into an arrayconst userIDArray userIDs.split(,); 将 userID 拆分为一个数组 const userIDArray userIDs.split“”;// Prepare output string for each userIDconst output userIDArray.map((userID) {const vlessMain vless://${userID}${hostName}${commonUrlPart};const vlessSec vless://${userID}${proxyIP}${commonUrlPart};return h2UUID: ${userID}/h2${hashSeparator}\nv2ray default ip --------------------------------------------------------------- ${vlessMain} button onclickcopyToClipboard(${vlessMain})i classfa fa-clipboard/i Copy vlessMain/button --------------------------------------------------------------- v2ray with bestip --------------------------------------------------------------- ${vlessSec} button onclickcopyToClipboard(${vlessSec})i classfa fa-clipboard/i Copy vlessSec/button ---------------------------------------------------------------;}).join(\n);const sublink https://${hostName}/sub/${userIDArray[0]}?formatclashconst subbestip https://${hostName}/bestip/${userIDArray[0]};const clash_link https://api.v1.mk/sub?targetclashurl${encodeURIComponent(sublink)}insertfalseemojitruelistfalsetfofalsescvtruefdnfalsesortfalsenew_nametrue;// Prepare header stringconst header p aligncenterimg srchttps://cloudflare-ipfs.com/ipfs/bafybeigd6i5aavwpr6wvnwuyayklq3omonggta4x2q7kpmgafj357nkcky alt图片描述 stylemargin-bottom: -50px; b stylefont-size: 15px;Welcome! This function generates configuration for VLESS protocol. If you found this useful, please check our GitHub project for more:/b b stylefont-size: 15px;欢迎这是生成 VLESS 协议的配置。如果您发现这个项目很好用请查看我们的 GitHub 项目给我一个star/b a hrefhttps://github.com/3Kmfi6HP/EDtunnel target_blankEDtunnel - https://github.com/3Kmfi6HP/EDtunnel/a iframe srchttps://ghbtns.com/github-btn.html?userUSERNAMErepoREPOSITORYtypestarcounttruesizelarge frameborder0 scrolling0 width170 height30 titleGitHub/iframe a href//${hostName}/sub/${userIDArray[0]} target_blankVLESS 节点订阅连接/a a hrefclash://install-config?url${encodeURIComponent(https://${hostName}/sub/${userIDArray[0]}?formatclash)}} target_blankClash for Windows 节点订阅连接/a a href${clash_link} target_blankClash 节点订阅连接/a a href${subbestip} target_blank优选IP自动节点订阅/a a hrefclash://install-config?url${encodeURIComponent(subbestip)} target_blankClash优选IP自动/a a hrefsing-box://import-remote-profile?url${encodeURIComponent(subbestip)} target_blanksingbox优选IP自动/a a hrefsn://subscription?url${encodeURIComponent(subbestip)} target_blanknekobox优选IP自动/a a hrefv2rayng://install-config?url${encodeURIComponent(subbestip)} target_blankv2rayNG优选IP自动/a/p;为每个用户 ID 准备输出字符串 const output userIDArray.mapuserID { const vlessMain vless://${userID}${hostName}${commonUrlPart}; const vlessSec vless://${userID}${proxyIP}${commonUrlPart}; return h2UUID ${userID}/h2${hashSeparator}\nv2ray default ip --------------------------------------------------------------- ${vlessMain} button onclickcopyToClipboard“${vlessMain}”i class“fa fa-clipboard”/i 复制 vlessMain/button--------------------------------------------------------------- v2ray with bestip --------------------------------------------------------------- ${vlessSec} button onclickcopyToClipboard“${vlessSec}”i class“fa fa-clipboard”/i Copy vlessSec/button ---------------------------------------------------------------; }。联接\n;const sublink https://${hostName}/sub/${userIDArray[0]}formatclash const subbestip https://${hostName}/bestip/${userIDArray[0]};const clash_link https://api.v1.mk/sub?targetclashurl${encodeURIComponentsublink}insertfalseemojitruelistfalsetfofalsescvtruefdnfalsesortfalsenew_nametrue;准备头文件字符串 const header p aligncenterimg srchttps//cloudflare-ipfs.com/ipfs/bafybeigd6i5aavwpr6wvnwuyayklq3omonggta4x2q7kpmgafj357nkcky alt图片描述 stylemargin-bottom -50px; b stylefont-size 15px;欢迎此函数生成 VLESS 协议的配置。如果您觉得这很有用请查看我们的 GitHub 项目了解更多信息/b b stylefont-size 15px;欢迎这是生成 VLESS 协议的配置。如果您发现这个项目很好用请查看我们的 GitHub 项目给我一个星/b a hrefhttps//github.com/3Kmfi6HP/EDtunnel target_blankEDtunnel - https://github.com/3Kmfi6HP/EDtunnel/a iframe srchttps//ghbtns.com/github-btn.htmluserUSERNAMErepoREPOSITORYtypestarcounttruesizelarge frameborder0 scrolling0 width170 height30 titleGitHub/iframe a href//${hostName}/sub/${userIDArray[0]} target_blankVLESS 节点订阅连接/a a hrefclash//install-configurl${encodeURIComponenthttps//${hostName}/sub/${userIDArray[0]}formatclash}} target_blankClash for Windows 节点订阅连接/a a href${clash_link} target_blankClash 节点订阅连接/aa href${subbestip} target_blank优选IP自动节点订阅/a a hrefclash//install-configurl${encodeURIComponentsubbestip} target_blankClash优选IP自动/a a hrefsing-box//import-remote-profileurl${encodeURIComponentsubbestip} target_blanksingbox优选IP自动/a a hrefsn//subscriptionurl${encodeURIComponentsubbestip} target_blanknekobox优选IP自动/a a hrefv2rayng//install-configurl${encodeURIComponentsubbestip} target_blankv2rayNG优选IP自动/a/p;// HTML Head with CSS and FontAwesome libraryconst htmlHead headtitleEDtunnel: VLESS configuration/titlemeta namedescription contentThis is a tool for generating VLESS protocol configurations. Give us a star on GitHub https://github.com/3Kmfi6HP/EDtunnel if you found it useful!meta namekeywords contentEDtunnel, cloudflare pages, cloudflare worker, severlessmeta nameviewport contentwidthdevice-width, initial-scale1meta propertyog:site_name contentEDtunnel: VLESS configuration /meta propertyog:type contentwebsite /meta propertyog:title contentEDtunnel - VLESS configuration and subscribe output /meta propertyog:description contentUse cloudflare pages and worker severless to implement vless protocol /meta propertyog:url contenthttps://${hostName}/ /meta propertyog:image contenthttps://api.qrserver.com/v1/create-qr-code/?size500x500data${encodeURIComponent(vless://${userIDs.split(,)[0]}${hostName}${commonUrlPart})} /meta nametwitter:card contentsummary_large_image /meta nametwitter:title contentEDtunnel - VLESS configuration and subscribe output /meta nametwitter:description contentUse cloudflare pages and worker severless to implement vless protocol /meta nametwitter:url contenthttps://${hostName}/ /meta nametwitter:image contenthttps://cloudflare-ipfs.com/ipfs/bafybeigd6i5aavwpr6wvnwuyayklq3omonggta4x2q7kpmgafj357nkcky /meta propertyog:image:width content1500 /meta propertyog:image:height content1500 / 带有 CSS 和 FontAwesome 库的 HTML Head const htmlHead head titleEDtunnel VLESS 配置/title meta namedescription content这是一个用于生成 VLESS 协议配置的工具。 如果您觉得有用请在 GitHub 上给我们一颗星 https://github.com/3Kmfi6HP/EDtunnel meta namekeywords contentEDtunnel cloudflare pages cloudflare worker severless meta nameviewport contentwidthdevice-width initial-scale1meta propertyogsite_name contentEDtunnel VLESS 配置 / meta propertyogtype contentwebsite / meta propertyogtitle contentEDtunnel - VLESS 配置和订阅输出 / meta propertyogdescription content使用 cloudflare pages 和 worker severless 实现 vless 协议 / meta propertyogurl contenthttps//${hostName}/ /meta propertyogimage contenthttps//api.qrserver.com/v1/create-qr-code/size500x500data${encodeURIComponentvless//${userIDs.split“”[0]}${hostName}${commonUrlPart}} / meta nametwittercard contentsummary_large_image / meta nametwittertitle contentEDtunnel - VLESS 配置和订阅输出 / meta nametwitterdescription content使用 cloudflare pages 和 worker severless 实现 vless 协议 /meta nametwitterurl contenthttps//${hostName}/ / meta nametwitterimage contenthttps//cloudflare-ipfs.com/ipfs/bafybeigd6i5aavwpr6wvnwuyayklq3omonggta4x2q7kpmgafj357nkcky / meta propertyogimagewidth content1500 / meta propertyogimageheight content1500 /stylebody {font-family: Arial, sans-serif;background-color: #f0f0f0;color: #333;padding: 10px;} style body { font-family Arial sans-serif; background-color #f0f0f0; color #333; padding 10px; }a {color: #1a0dab;text-decoration: none;}img {max-width: 100%;height: auto;} a { color #1a0dab; text-decoration none; } img { max-width 100%; height auto; }pre {white-space: pre-wrap;word-wrap: break-word;background-color: #fff;border: 1px solid #ddd;padding: 15px;margin: 10px 0;}/* Dark mode */media (prefers-color-scheme: dark) {body {background-color: #333;color: #f0f0f0;} pre { white-space pre-wrap; word-wrap break-word; background-color #fff; border 1px solid #ddd; padding 15px; margin 10px 0; } /* 深色模式 */ media prefers-color-scheme dark { body { background-color #333; color #f0f0f0; }a {color: #9db4ff;} a { 颜色 #9db4ff;pre {background-color: #282a36;border-color: #6272a4;}}/style!-- Add FontAwesome library --link relstylesheet hrefhttps://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css/head; !-- 添加 FontAwesome 库 -- link relstylesheet hrefhttps//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css /head ;// Join output with newlines, wrap inside html and bodyreturn html${htmlHead}bodypre stylebackground-color: transparent; border: none;${header}/prepre${output}/pre/bodyscriptfunction copyToClipboard(text) {navigator.clipboard.writeText(text).then(() {alert(Copied to clipboard);}).catch((err) {console.error(Failed to copy to clipboard:, err);});}/script/html; } 用换行符连接输出在里面html换行并body返回 html ${htmlHead} body pre stylebackground-color transparent; border none;${header}/pre pre${output}/pre /body script function copyToClipboardtext { navigator.clipboard.writeTexttext .then { alert“复制到剪贴板”; } .catcherr { console.error“无法复制到剪贴板” err; /script /html };;} const portSet_http new Set([80, 8080, 8880, 2052, 2086, 2095, 2082]); const portSet_https new Set([443, 8443, 2053, 2096, 2087, 2083]); const portSet_http 新集[80 8080 8880 2052 2086 2095 2082];常量 portSet_https 新集[443 8443 2053 2096 2087 2083]; function createVLESSSub(userID_Path, hostName) {const userIDArray userID_Path.includes(,) ? userID_Path.split(,) : [userID_Path];const commonUrlPart_http ?encryptionnonesecuritynonefprandomtypewshost${hostName}path%2F%3Fed%3D2048#;const commonUrlPart_https ?encryptionnonesecuritytlssni${hostName}fprandomtypewshost${hostName}path%2F%3Fed%3D2048#; 函数 createVLESSSubuserID_Path hostName { const userIDArray userID_Path.includes userID_Path.split [userID_Path]; const commonUrlPart_http encryptionnonesecuritynonefprandomtypewshost${hostName}path%2F%3Fed%3D2048#; const commonUrlPart_https encryptionnonesecuritytlssni${hostName}fprandomtypewshost${hostName}path%2F%3Fed%3D2048#;const output userIDArray.flatMap((userID) {const httpConfigurations Array.from(portSet_http).flatMap((port) {if (!hostName.includes(pages.dev)) {const urlPart ${hostName}-HTTP-${port};const vlessMainHttp vless://${userID}${hostName}:${port}${commonUrlPart_http}${urlPart};return proxyIPs.flatMap((proxyIP) {const vlessSecHttp vless://${userID}${proxyIP}:${port}${commonUrlPart_http}${urlPart}-${proxyIP}-EDtunnel;return [vlessMainHttp, vlessSecHttp];});}return [];}); const output userIDArray.flatMapuserID { const httpConfigurations Array.fromportSet_http.flatMapport { if hostName.includespages.dev { const urlPart ${hostName}-HTTP-${port}; const vlessMainHttp vless://${userID}${hostName}${port}${commonUrlPart_http}${urlPart}; return proxyIPs.flatMapproxyIP { const vlessSecHttp vless://${userID}${proxyIP}${port}${commonUrlPart_http}${urlPart}-${proxyIP}-EDtunnel; 返回 [vlessMainHttpvlessSecHttp];});} 返回 [];});const httpsConfigurations Array.from(portSet_https).flatMap((port) {const urlPart ${hostName}-HTTPS-${port};const vlessMainHttps vless://${userID}${hostName}:${port}${commonUrlPart_https}${urlPart};return proxyIPs.flatMap((proxyIP) {const vlessSecHttps vless://${userID}${proxyIP}:${port}${commonUrlPart_https}${urlPart}-${proxyIP}-EDtunnel;return [vlessMainHttps, vlessSecHttps];});}); const httpsConfigurations Array.fromportSet_https.flatMapport { const urlPart ${hostName}-HTTPS-${port}; const vlessMainHttps vless://${userID}${hostName}${port}${commonUrlPart_https}${urlPart}; return proxyIPs.flatMapproxyIP { const vlessSecHttps vless://${userID}${proxyIP}${port}${commonUrlPart_https}${urlPart}-${proxyIP}-EDtunnel; return [vlessMainHttps vlessSecHttps]; };return [...httpConfigurations, ...httpsConfigurations];}); 返回 [...httpConfigurations、...https配置];});return output.join(\n); } 返回 output.join\n;} const cn_hostnames [weibo.com, // Weibo - A popular social media platformwww.baidu.com, // Baidu - The largest search engine in Chinawww.qq.com, // QQ - A widely used instant messaging platformwww.taobao.com, // Taobao - An e-commerce website owned by Alibaba Groupwww.jd.com, // JD.com - One of the largest online retailers in Chinawww.sina.com.cn, // Sina - A Chinese online media companywww.sohu.com, // Sohu - A Chinese internet service providerwww.tmall.com, // Tmall - An online retail platform owned by Alibaba Groupwww.163.com, // NetEase Mail - One of the major email providers in Chinawww.zhihu.com, // Zhihu - A popular question-and-answer websitewww.youku.com, // Youku - A Chinese video sharing platformwww.xinhuanet.com, // Xinhua News Agency - Official news agency of Chinawww.douban.com, // Douban - A Chinese social networking servicewww.meituan.com, // Meituan - A Chinese group buying website for local serviceswww.toutiao.com, // Toutiao - A news and information content platformwww.ifeng.com, // iFeng - A popular news website in Chinawww.autohome.com.cn, // Autohome - A leading Chinese automobile online platformwww.360.cn, // 360 - A Chinese internet security companywww.douyin.com, // Douyin - A Chinese short video platformwww.kuaidi100.com, // Kuaidi100 - A Chinese express delivery tracking servicewww.wechat.com, // WeChat - A popular messaging and social media appwww.csdn.net, // CSDN - A Chinese technology community websitewww.imgo.tv, // ImgoTV - A Chinese live streaming platformwww.aliyun.com, // Alibaba Cloud - A Chinese cloud computing companywww.eyny.com, // Eyny - A Chinese multimedia resource-sharing websitewww.mgtv.com, // MGTV - A Chinese online video platformwww.xunlei.com, // Xunlei - A Chinese download manager and torrent clientwww.hao123.com, // Hao123 - A Chinese web directory servicewww.bilibili.com, // Bilibili - A Chinese video sharing and streaming platformwww.youth.cn, // Youth.cn - A China Youth Daily news portalwww.hupu.com, // Hupu - A Chinese sports community and forumwww.youzu.com, // Youzu Interactive - A Chinese game developer and publisherwww.panda.tv, // Panda TV - A Chinese live streaming platformwww.tudou.com, // Tudou - A Chinese video-sharing websitewww.zol.com.cn, // ZOL - A Chinese electronics and gadgets websitewww.toutiao.io, // Toutiao - A news and information appwww.tiktok.com, // TikTok - A Chinese short-form video appwww.netease.com, // NetEase - A Chinese internet technology companywww.cnki.net, // CNKI - China National Knowledge Infrastructure, an information aggregatorwww.zhibo8.cc, // Zhibo8 - A website providing live sports streamswww.zhangzishi.cc, // Zhangzishi - Personal website of Zhang Zishi, a public intellectual in Chinawww.xueqiu.com, // Xueqiu - A Chinese online social platform for investors and traderswww.qqgongyi.com, // QQ Gongyi - Tencents charitable foundation platformwww.ximalaya.com, // Ximalaya - A Chinese online audio platformwww.dianping.com, // Dianping - A Chinese online platform for finding and reviewing local businesseswww.suning.com, // Suning - A leading Chinese online retailerwww.zhaopin.com, // Zhaopin - A Chinese job recruitment platformwww.jianshu.com, // Jianshu - A Chinese online writing platformwww.mafengwo.cn, // Mafengwo - A Chinese travel information sharing platformwww.51cto.com, // 51CTO - A Chinese IT technical community websitewww.qidian.com, // Qidian - A Chinese web novel platformwww.ctrip.com, // Ctrip - A Chinese travel services providerwww.pconline.com.cn, // PConline - A Chinese technology news and review websitewww.cnzz.com, // CNZZ - A Chinese web analytics service providerwww.telegraph.co.uk, // The Telegraph - A British newspaper website www.ynet.com, // Ynet - A Chinese news portalwww.ted.com, // TED - A platform for ideas worth spreadingwww.renren.com, // Renren - A Chinese social networking servicewww.pptv.com, // PPTV - A Chinese online video streaming platformwww.liepin.com, // Liepin - A Chinese online recruitment websitewww.881903.com, // 881903 - A Hong Kong radio station websitewww.aipai.com, // Aipai - A Chinese online video sharing platformwww.ttpaihang.com, // Ttpaihang - A Chinese celebrity popularity ranking websitewww.quyaoya.com, // Quyaoya - A Chinese online ticketing platformwww.91.com, // 91.com - A Chinese software download websitewww.dianyou.cn, // Dianyou - A Chinese game information websitewww.tmtpost.com, // TMTPost - A Chinese technology media platformwww.douban.com, // Douban - A Chinese social networking servicewww.guancha.cn, // Guancha - A Chinese news and commentary websitewww.so.com, // So.com - A Chinese search enginewww.58.com, // 58.com - A Chinese classified advertising websitewww.cnblogs.com, // Cnblogs - A Chinese technology blog communitywww.cntv.cn, // CCTV - China Central Television official websitewww.secoo.com, // Secoo - A Chinese luxury e-commerce platform ]; const cn_hostnames [ weibo.com // 微博 - 流行的社交媒体平台 www.baidu.com // 百度 - 中国最大的搜索引擎 www.qq.com // QQ - 广泛使用的即时通讯平台 www.taobao.com // 淘宝 - 阿里巴巴集团旗下的电子商务网站 www.jd.com // JD.com - 中国最大的在线零售商之一 www.sina.com.cn // 新浪 - 中国在线媒体公司 www.sohu.com // 搜狐 - 中国互联网服务提供商 www.tmall.com 天猫 - 阿里巴巴集团旗下的在线零售平台 “www.163.com” // 网易邮箱 - 中国主要的电子邮件提供商之一 “www.zhihu.com” // 知乎 - 一个受欢迎的问答网站 “www.youku.com” // 优酷 - 中国视频分享平台“www.xinhuanet.com” // 新华社 - 中国官方通讯社“www.douban.com” // 豆瓣 - 中国社交网络服务“www.meituan.com” // 美团 - 一个中国的本地服务团购网站www.toutiao.com // 今日头条 - 新闻和信息内容平台 www.ifeng.com // 爱风 - 中国流行的新闻网站 www.autohome.com.cn // 汽车之家 - 中国领先的汽车在线平台www.360.cn // 360 - 中国互联网安全公司 www.douyin.com // 抖音 - 中国短视频平台www.kuaidi100.com // 快的100 - 中国快递跟踪服务www.wechat.com // 微信 - 流行的消息传递和社交媒体应用程序www.csdn.net // CSDN - 中国科技社区网站 www.imgo.tv // ImgoTV - 中国直播平台www.aliyun.com // 阿里云 - 中国云计算公司 www.eyny.com // Eyny - 中国多媒体资源共享网站www.mgtv.com // MGTV - 中国在线视频平台www.xunlei.com // 迅雷 - 中国下载管理器和种子客户端 www.hao123.com // Hao123 - 中国网络目录服务 www.bilibili.com // 哔哩哔哩 - 中国视频分享和流媒体平台www.youth.cn // Youth.cn - 中国青年报新闻门户网站www.hupu.com // 虎浦 - 中国体育社区和论坛 www.youzu.com // 游豆互动 - 中国游戏开发商和发行商 www.panda.tv // 熊猫电视 - 中国直播平台www.tudou.com 土豆 - 中国视频分享网站“www.zol.com.cn” // ZOL - 中国电子和小工具网站“www.toutiao.io” // 今日头条 - 新闻和信息应用程序“www.tiktok.com” // TikTok - 中国短视频应用程序“www.netease.com” // 网易 - 中国互联网科技公司“www.cnki.net” // CNKI - 中国国家知识基础设施信息聚合器“www.zhibo8.cc” // Zhibo8 - 提供体育直播的网站 www.zhangzishi.cc // 张子石 - 中国公共知识分子张子石的个人网站 “www.xueqiu.com” // 雪球 - 面向投资者和交易者的中国在线社交平台 “www.qqgongyi.com” // QQ公益 - 腾讯慈善基金会平台“www.ximalaya.com” // 喜马拉雅 - 中国在线音频平台“www.dianping.com” // 大众点评 - 寻找和评论本地企业的中国在线平台 “www.suning.com” // 苏宁 - 中国领先的在线零售商 “www.zhaopin.com” // 智联招聘 - A中国招聘平台www.jianshu.com // 建书 - 中国在线写作平台www.mafengwo.cn // 马峰窝 - 中国旅游信息共享平台www.51cto.com // 51CTO - 中国IT技术社区网站www.qidian.com // 启电 - 中国网络小说平台www.ctrip.com // 携程 - 中国旅游服务提供商 www.pconline.com.cn // PConline - 中国科技新闻和评论网站 www.cnzz.com // CNZZ - 中国网络分析服务提供商 www.telegraph.co.uk // The Telegraph - 英国报纸网站 www.ynet.com // Ynet - 中国新闻门户网站 www.ted.com // TED - 一个值得传播思想的平台 “www.renren.com” // 人人网 - 中国社交网络服务 www.pptv.com // PPTV - 一个中文在线视频流媒体平台“www.liepin.com” // 列品 - 中国在线招聘网站“www.881903.com” // 881903 - 香港广播电台网站“www.aipai.com” // 爱拍 - 中国在线视频分享平台“www.ttpaihang.com” // Ttpaihang - 中国名人人气排行榜网站“www.quyaoya.com” // 曲耀雅 - 中国在线票务平台“www.91.com” // 91.com - 中国软件下载网站“www.dianyou.cn” // 点游 - 中国游戏信息网站www.tmtpost.com // TMTPost - 中国科技媒体平台www.douban.com // 豆瓣 - 中国社交网络服务www.guancha.cn // 关查 - 中国新闻评论网站www.so.com // So.com - 中国搜索引擎www.58.com // 58.com - 中国分类广告网站www.cnblogs.com // Cnblogs - 中国科技博客社区www.cntv.cn // 央视 - 中国中央电视台官方网站www.secoo.com // 寺库 - 中国奢侈品电商平台 ]; 仓库https://github.com/Li468446/workers.js/tree/main --------------------------------------------------------------------------------------------------------------------------------- 导入完成后我们需要修改两个地方分别是UUID和CDN-IP。CDN-IP必须是反代IP不能是官方IP 4、UUID生成 UUID的大概解释在本文开头的知识链条中有比较标准的解释大家可以作为参考。UUID因其属性随机生成且基本不会重合我们现在去生成它将它放入代码中即可。这里给大家推荐一个UUID在线随机生成的网站希望能帮到各位开发者和极客玩家open网址 https://1024tools.com/uuid 进入后点击生成即可然后随便选择一个就行UUID非常重要请把你使用的UUID保存一份副本避免后续的操作无法进行 这里我则第二个复制出来后回到实例代码中修改UUID为生成的这个。 5、cloud flare-proxy-IP 、proxy域的选择 优质域名推荐 cdn-all.xn--b6gac.eu.org cdn.xn--b6gac.eu.org cdn-b100.xn--b6gac.eu.org edgetunnel.anycast.eu.org cdn.anycast.eu.org亚洲地区 jp.cloudflarest.link achk.cloudflarest.link阿里香港优选 这里给大家两种优选cloud flare优质IP的方案 2、个人推荐 113.64.186.198 103.200.112.108 199.15.76.35edgetunnel.anycast.eu.org美国的加速CDN cdn.anycast.eu.org香港日本新加坡加速CDN香港优选IP20.187.89.16 日本高速优选IP:146.56.149.205 美国优选IP172.64.135.146 韩国高速优选IP:129.154.199.251 日本高速优选IP:146.56.149.205cdn-all.xn--b6gac.eu.org cdn.xn--b6gac.eu.org cdn-b100.xn--b6gac.eu.org edgetunnel.anycast.eu.org cdn.anycast.eu.org 同时也可以选出运营商的最优反代IP放入实例代码中的CDN-IP位置即可。这里我就直接使用这个IP。 113.64.186.198 填入后点击部署即可。 我已经保存部署过了所以这里这个按钮是灰色的 到这里cloud flare的实例部署就已经完成了。 三、使用方法无域名 生成的实例流量转发的协议为vless所以Vtwo2ray是个不错的选择. 1、V222222222222rayn 复制刚刚创建的代码地址格式为https://vless.xxx.workers.dev/其中 vless 为创建的脚本名称xxx 为 CloudFlare 用户名。 复制出来后后面加个/UUID如下 https://ceshi.xiaorantang68.workers.dev/37959939-2926-4e4c-a0d2-6468a1b9f7f7 这样我们就获取到了vless服务器的两个节点信息 复制红框内的内容后粘贴进v222222222222rayn 添加完成但是现在这个服务器还不能使用需要对节点进行进一步的修改。 因为不使用域名所以加密方式不需要选择将TLS改为空 如下图 端口呢也不能使用443端口这里我切换为80端口不使用TLS可以将端口改为80或2052 2、修改地址 现在就可以进行IP的优选了脚本可以在我的仓库下载https://github.com/Li468446/workers.js 填入v222222222rayn的vless服务器连接信息中即可。 lanzouhttps://pan.lanpw.com/b0742hkxehttps://pan.lanpw.com/b0742hkxe 下载下来后运行jp.bat批处理程序即可自动优选。优选前请关闭所有的系统代理避免优选出现误差 优选结果会写入rest.csv文件内填入vless服务器IP中即可这里就不多做解答 优选出来的IP直接填入vless服务器的地址栏即可确定后切换为活动服务器访问谷歌尝试 到这里v2222222222222rayn的配置就完成了可以进行测试 四、实例测试 我这里优选出来的本地IP是104.19.170.**填入后访问谷歌测试成功。 查看cloud flare的实例有正常的请求正常工作。 实验成功 五、总结 需要有一定的web基础和网络代理的基础过程繁琐在这个过程中最容易出错的地方就在于实例中的workers的proxy IP和v222222222222rayn的客户端连接的CF优选IP容易搞混淆Proxy-IP必须是反向代理IP否则实例的反向代理会出现问题。 最后建议各位开发者们仔细观看认真学习我在文中如有表达不够清晰存在疑问的可以在下方评论区提出我会一一为大家解答有错误的地方也请大佬指点一二共同学习一起进步。 本章节就到这里感谢大家的支持
http://www.zqtcl.cn/news/517941/

相关文章:

  • 查网站死链必用工具微信 wordpress
  • 做网站凡科新手如何开微商城店
  • 网站空间维护个人怎么注册一个品牌
  • 连云港网站设计城乡建设网站 资料员
  • 网络优化工程师有多累seo前线
  • 囊谦县公司网站建设新沂网页定制
  • 公众平台网页版wordpress换主题影响seo吗
  • 网站建设什么是静态网页设置wordpress文章标题高亮的代码
  • 男女做那事是什 网站wordpress怎么上传ppt
  • 电商网站图片处理东莞网络营销策划
  • 做知识产权相关的网站网站怎么做登录界面
  • 网站空间备份东莞企业网站教程
  • 新桥企业网站建设有关网站建设的毕业设计
  • 中山网站建设工作修改wordpress后台地址
  • 西安app网站开发如何制作一个自己的网页
  • 陇西学做网站鄂州网约车
  • 做类似58类型网站免费源码分享
  • 个人做的网站有什么危险网站模板怎样发布
  • 设计建设网站公司网站wordpress k2
  • 公司网站被抄袭网络宣传
  • 企业网站设计收费专业网络推广公司排名
  • 视频网站模板源码深圳网站建设明细报价表
  • nike官方网站定制二级域名网站有哪些
  • 越秀移动网站建设房门户网站如何做优化
  • 什么软件可以做动漫视频网站开发一个小程序大概要多少钱
  • 微网站可以做成域名访问株洲网站做的好的公司
  • 建设网站去工信部备案需要什么资料网站建设相关博客
  • 十度网站建设网站建立的企业
  • 婚庆公司网站国外网站阻止国内访问怎么做
  • 乐山高端网站建设wordpress openload