[网络技巧] CF Worker搭建vless协议代理
作者:CC下载站 日期:2023-08-02 11:25:24 浏览:46 分类:web
1、复制如下代码到worker中
注意自己可修改uuid 具体搜索
3e036e57-4d74-469a-b312-b97b59680ec3
// ../node_modules/uuid/dist/esm-browser/regex.js var regex_default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; // ../node_modules/uuid/dist/esm-browser/validate.js function validate(uuid) { return typeof uuid === "string" && regex_default.test(uuid); } var validate_default = validate; // ../node_modules/uuid/dist/esm-browser/stringify.js var 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 (!validate_default(uuid)) { throw TypeError("Stringified UUID is invalid"); } return uuid; } var stringify_default = stringify; // vless-js/lib/vless-js.ts var WS_READY_STATE_OPEN = 1; function makeReadableWebSocketStream(ws, earlyDataHeader, log) { let readableStreamCancel = false; return new ReadableStream({ start(controller) { ws.addEventListener("message", async (e) => { if (readableStreamCancel) { return; } const vlessBuffer = e.data; controller.enqueue(vlessBuffer); }); ws.addEventListener("error", (e) => { log("socket has error"); readableStreamCancel = true; controller.error(e); }); ws.addEventListener("close", () => { try { log("webSocket is close"); if (readableStreamCancel) { return; } controller.close(); } catch (error2) { log(`websocketStream can't close DUE to `, error2); } }); const { earlyData, error } = base64ToArrayBuffer(earlyDataHeader); if (error) { log(`earlyDataHeader has invaild base64`); safeCloseWebSocket(ws); return; } if (earlyData) { controller.enqueue(earlyData); } }, pull(controller) { }, cancel(reason) { log(`websocketStream is cancel DUE to `, reason); if (readableStreamCancel) { return; } readableStreamCancel = true; safeCloseWebSocket(ws); } }); } function base64ToArrayBuffer(base64Str) { if (!base64Str) { return { error: null }; } try { base64Str = 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 }; } } function safeCloseWebSocket(socket) { try { if (socket.readyState === WS_READY_STATE_OPEN) { socket.close(); } } catch (error) { console.error("safeCloseWebSocket error", error); } } 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_default(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]; const command = new Uint8Array( vlessBuffer.slice(18 + optLength, 18 + optLength + 1) )[0]; if (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); const portRemote = new DataView(portBuffer).getInt16(0); let addressIndex = portIndex + 2; const addressBuffer = new Uint8Array( vlessBuffer.slice(addressIndex, addressIndex + 1) ); const 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) ); const ipv6 = []; for (let i = 0; i < 8; i++) { ipv6.push(dataView.getUint16(i * 2).toString(16)); } addressValue = ipv6.join(":"); break; default: console.log(`invild addressType is ${addressType}`); } if (!addressValue) { return { hasError: true, message: `addressValue is empty, addressType is ${addressType}` }; } return { hasError: false, addressType, addressRemote: addressValue, portRemote, rawDataIndex: addressValueIndex + addressLength, vlessVersion: version, isUDP }; } // index.ts import { connect } from "cloudflare:sockets"; // dns.ts var doh = "https://cloudflare-dns.com/dns-query"; var dns = async (domain) => { const response = await fetch(`${doh}?name=${domain}`, { method: "GET", headers: { "Accept": "application/dns-json" } }); const data = await response.json(); const ans = data?.Answer; return ans?.find((record) => record.type === 1)?.data; }; var isCloudFlareIP = (ip) => { const CFIP = [ [2918526976, -4096], [1729491968, -1024], [1729546240, -1024], [1730085888, -1024], [2372222976, -16384], [1822605312, -16384], [3193827328, -4096], [3161612288, -4096], [3320508416, -1024], [3324608512, -32768], [2728263680, -131072], [1745879040, -524288], [1746403328, -262144], [2889875456, -524288], [2197833728, -1024] ]; const isIp4InCidr = (ip2, cidr) => { const [a, b, c, d] = ip2.split(".").map(Number); ip2 = a << 24 | b << 16 | c << 8 | d; const [range, mask] = cidr; return (ip2 & mask) === range; }; return CFIP.some((cidr) => isIp4InCidr(ip, cidr)); }; // index.ts var HTML404 = "Script by zizifn, modified by MisakaNo"; function delay2(ms) { return new Promise((resolve, rej) => { setTimeout(resolve, ms); }); } var workers_default = { async fetch(request, env, ctx) { let address = ""; let portWithRandomLog = ""; const userID = env.UUID || "3e036e57-4d74-469a-b312-b97b59680ec3"; const log = (info, event) => { console.log(`[${address}:${portWithRandomLog}] ${info}`, event || ""); }; const upgradeHeader = request.headers.get("Upgrade"); if (!upgradeHeader || upgradeHeader !== "websocket") { return new Response(HTML404, { status: 404, headers: new Headers({ "Content-Type": "text/html" }) }); } const webSocketPair = new WebSocketPair(); const [client, webSocket] = Object.values(webSocketPair); const earlyDataHeader = request.headers.get("sec-websocket-protocol") || ""; let remoteSocket = null; webSocket.accept(); const readableWebSocketStream = makeReadableWebSocketStream( webSocket, earlyDataHeader, log ); let vlessResponseHeader = new Uint8Array([0, 0]); let remoteConnectionReadyResolve; readableWebSocketStream.pipeTo( new WritableStream({ async write(chunk, controller) { if (remoteSocket) { const writer2 = remoteSocket.writable.getWriter(); await writer2.write(chunk); writer2.releaseLock(); return; } const { hasError, message, portRemote, addressType, addressRemote, rawDataIndex, vlessVersion, isUDP } = processVlessHeader(chunk, userID); address = addressRemote || ""; portWithRandomLog = `${portRemote} -- ${isUDP ? "udp " : "tcp "} `; if (isUDP && portRemote != 53) { controller.error("UDP proxy only enable for DNS which is port 53"); webSocket.close(); return; } if (hasError) { controller.error(message); webSocket.close(); return; } vlessResponseHeader = new Uint8Array([vlessVersion[0], 0]); const rawClientData = chunk.slice(rawDataIndex); let queryip = ""; if (addressType === 2) { queryip = await dns(addressRemote); if (queryip && isCloudFlareIP(queryip)) { queryip = "64.68.192." + Math.floor(Math.random() * 255); } } remoteSocket = connect({ hostname: queryip ? queryip : addressRemote, port: portRemote }); log(`connected`); const writer = remoteSocket.writable.getWriter(); await writer.write(rawClientData); writer.releaseLock(); remoteConnectionReadyResolve(remoteSocket); }, close() { console.log( `[${address}:${portWithRandomLog}] readableWebSocketStream is close` ); }, abort(reason) { console.log( `[${address}:${portWithRandomLog}] readableWebSocketStream is abort`, JSON.stringify(reason) ); } }) ); (async () => { await new Promise((resolve) => remoteConnectionReadyResolve = resolve); let count = 0; remoteSocket.readable.pipeTo( new WritableStream({ start() { if (webSocket.readyState === WebSocket.READY_STATE_OPEN) { webSocket.send(vlessResponseHeader); } }, async write(chunk, controller) { if (webSocket.readyState === WebSocket.READY_STATE_OPEN) { if (count++ > 2e4) { await delay2(1); } webSocket.send(chunk); } else { controller.error( "webSocket.readyState is not open, maybe close" ); } }, close() { console.log( `[${address}:${portWithRandomLog}] remoteConnection!.readable is close` ); }, abort(reason) { console.error( `[${address}:${portWithRandomLog}] remoteConnection!.readable abort`, reason ); } }) ).catch((error) => { console.error( `[${address}:${portWithRandomLog}] processWebSocket has exception `, error.stack || error ); safeCloseWebSocket2(webSocket); }); })(); return new Response(null, { status: 101, webSocket: client }); } }; function safeCloseWebSocket2(ws) { try { if (ws.readyState !== WebSocket.READY_STATE_CLOSED) { ws.close(); } } catch (error) { console.error("safeCloseWebSocket error", error); } } export { workers_default as default }; //# sourceMappingURL=index.js.map
2、节点配置如下
协议:Vless 地址:CF优选IP / 域名 端口:80 或 CF 支持的 HTTPS 端口 UUID/密码:设置的UUID(如未设置则为 `3e036e57-4d74-469a-b312-b97b59680ec3`) 传输协议:ws 伪装域名:设置的 Workers 自定义域名 路径:/
由于目前worker自带域名已被X,建议使用自己的域名
协议:Vless 地址:CF优选IP / 自己的域名 端口:443 或 CF 支持的 HTTPS 端口 UUID/密码:设置的UUID(如未设置则为 `3e036e57-4d74-469a-b312-b97b59680ec3`) 传输协议:ws 伪装域名:自己的域名 路径:/ 传输安全:TLS 跳过证书验证:true 或 false 都可以
参考文章
https://web.archive.org/web/20230526070655/https://blog.misaka.rest/2023/05/26/cf-wkrs-vless/
参考githun相关项目
https://github.com/zizifn/edgetunnel
The text was updated successfully, but these errors were encountered: |
猜你还喜欢
- 04-01 [科学上网] 直连、中转、专线机场有什么区别|良心高效专线机场推荐|hy2机场推荐
- 03-29 [web] 免费公共DNS大全(IPv6+IPv4)
- 03-29 [玩技术] CTFHUB刷题笔记
- 03-22 [AI配音] 有哪些好用的AI智能配音工具值得推荐?
- 03-15 [web] 轻松申请免费域名并绑定到个人网站 | link顶级域名
- 03-15 [运营] 亚马逊如何选品?产品市场分析怎么做?包括哪些方面?
- 03-15 [web] 3分钟,免费拥有你的专属域名——免费一级域名注册申请及域名解析教程
- 03-14 [学习] 必看!手把手教你自动续期微软E5账号,长期畅享5T OneDrive云盘!
- 03-14 [学习] 白嫖5T微软的OneDrive云盘,微软E5申请,真正的免费不限速!
- 03-14 [学习] 微软onedrive E5创建子账号,实现125T云盘空间25账号,附带Office365激活
- 03-08 [web] 手把手教你开通新加坡华侨银行OCBC账户-保姆级教程
- 03-05 [web] PT站是什么?开放注册的国外国内PT站推荐汇总
取消回复欢迎 你 发表评论:
- 精品推荐!
-
- 最新文章
- 热门文章
- 热评文章
[文件传输] 双轨快传 v1.1.1 (同时使用USB和WIFI传输文件到电脑)
[系统辅助] 最快快捷键V1.2.47 一键切换窗口、启动程序、复制粘贴、按键映射、切换输入法
[实用工具] 老板键工具-呼来唤去v0.6.0 一键显隐窗口
[书籍] 《炁体源流(上下册)》 道家养生经典辑录 米晶子[pdf]
[即时翻译] 实时打字翻译工具-Typing-translationV3.0
[转换工具] TMSpeech 1.0免费实时语音转字幕软件
[Android] 电工计算器 v10.0.2.1-h
[美食] 曾经的黑龙江第一城,藏着中国烧烤王者
[媒体编辑] pyVideoTrans视频翻译和配音 v1.42
[趣味工具] 【桌面动态小装扮】蝴蝶1.0、蟑螂1.2、苍蝇1.3
[资料] [大学期末救急课] 猴博士+高斯课堂+斐多课堂,全集视频合集
[云资源] 价值2万元的老男孩Python教程
[书库] 史上最全摄影书推荐(附700本PDF版打包下载)
[云资源] 花了一千多元买的私人健身教程
[下载工具] Internet Download Manager 6.42.7 (IDM)
[影视] 灌篮高手 WEB-DL版下载/Slam Dunk/スラムダンク/灌篮高手:THE FIRST/灌篮高手电影版 2022 The First Slam Dunk 61.35G
[资料] 3000 套电影电视剧 LOGO 宣传片常用音效合集包
[安卓软件] 酷我音乐APP_v10.7.6.4 去广告破解豪华VIP版
[即时通讯] 微信PC版WeChat 3.9.9.43 多开防撤回绿色版
[安卓软件] Solid Explorer文件管理器APP 2.8.38 破解版
[云资源] 价值2万元的老男孩Python教程
[影视] 灌篮高手 WEB-DL版下载/Slam Dunk/スラムダンク/灌篮高手:THE FIRST/灌篮高手电影版 2022 The First Slam Dunk 61.35G
[云资源] 花了一千多元买的私人健身教程
[书库] 史上最全摄影书推荐(附700本PDF版打包下载)
[动画] 北斗神拳(1984) [两季合集] [MKV]
[资料] 抗战阵亡将士资料+续编
[电视剧] 三体 (2024) 全8集 网飞版本 中文字幕 合集
[纪录片] 河西走廊【10集 国语 中文字幕 1080P 10.8G MP4】
[电影] 2024年喜剧片·热辣滚烫 [mp4]
[影视] 铁爪 WEB-DL版下载 2023 The Iron Claw 23.48G
- 最新评论
-
我想看看mw2ddyy 评论于:04-26 好东西阿zfy123123 评论于:04-18 谢谢楼主xiaoqi 评论于:04-12 勿在线解压,勿手机解压,请在电脑上用最新款压缩软件解压!推荐360压缩或者好压CC下载站 评论于:04-10 无法解压啊,客服能不能给个解压教程ravengrey 评论于:04-10 谢谢支持!!CC下载站 评论于:03-26 很棒的资源,感谢分享云体风身 评论于:03-26 感谢分享,好东西云体风身 评论于:03-26 谢谢支持!CC下载站 评论于:03-14 央视精品,感谢付出提供。qwer9009 评论于:03-14
- 热门tag