标签 脚本 下的文章 - 🥝 E 家 分 享 🥝
首页
📋 留言板
🔗 友情链接
🛠️ E家百宝箱
❤️ 关于
推荐
🔍 VPS监控
🐉 青龙面板
💽 E家网盘
----------
🔗 CloudFlare
🔗 甲骨文云
🔗 RackNerd
搜 索
1
自动提取 ChromeGo 一键翻墙包内的免费节点
145 阅读
2
【汇总:免费节点 - 每周更新】
113 阅读
3
GigaFile - 日本免费大文件加密分享服务,最长保留文档100天
71 阅读
4
【E家分享月刊系列】2024-12
56 阅读
5
CloudFlare WARP 免费 VPN 搭建教程
55 阅读
精选网站
网站搭建
科学上网搭建
有感而发
软件技巧
Excel技巧
WordPress技巧
登录
搜 索
标签搜索
WordPress
脚本
GitHub
科学上网
哈佛管理导师
E家分享月刊系列
V2ray
Mac软件
AI
Cloudflare
Docker
免费节点
建站在线工具
Excel技巧
Notion
Nginx
ChatGPT
图像编辑
免费图床
网盘资源
E家之长
累计撰写
195
篇文章
累计收到
245
条评论
首页
栏目
精选网站
网站搭建
科学上网搭建
有感而发
软件技巧
Excel技巧
WordPress技巧
页面
📋 留言板
🔗 友情链接
🛠️ E家百宝箱
❤️ 关于
推荐
🔍 VPS监控
🐉 青龙面板
💽 E家网盘
----------
🔗 CloudFlare
🔗 甲骨文云
🔗 RackNerd
用户登录
登录
找到
15
篇与
脚本
相关的结果
2024-03-23
甲骨文云闲置实例保号活跃方法
前言自从去年甲骨文云对闲置实例实施回收政策以后,时不时的就会收到警告提示邮件,曾经还有一次实例被暂停,因此从网上收集了一些保号活跃方法,一旦被警告,马上运行一段时间,确保不被回收。官方回收条款:回收空闲计算实例空闲 Always Free 计算实例可能是 被甲骨文回收。Oracle 将虚拟机和裸机计算视为 如果在 7 天内出现以下情况,则实例为空闲:第 95 个百分位数的 CPU 利用率低于 20% 网络利用率低于 20% 内存利用率低于 20%(仅适用于 A1 配置)我的理解是在七天的周期内,如果服务器的CPU、内存跟网络占用低于 20% 就会停用,应该是必须要三个同时满足才会判定是空闲,稍后被停机回收。保号活跃脚本使用的是 Oracle\_OneKey\_Active 脚本,参考地址:https://github.com/Mrmineduce21/Oracle\_OneKey\_ActiveCPU 占用脚本,自定义占用率。cd /root && wget -qO OneKeyFuck_OCPU.sh https://raw.githubusercontent.com/Mrmineduce21/Oracle_OneKey_Active/main/OneKeyFuck_OCPU.sh && chmod +x OneKeyFuck_OCPU.sh && bash OneKeyFuck_OCPU.sh内存占用脚本。固定吃2G内存,可叠加使用cd /root && wget -qO memory_usage.sh https://raw.githubusercontent.com/Mrmineduce21/Oracle_OneKey_Active/main/memory_usage.sh && chmod +x memory_usage.sh && bash memory_usage.sh consume 2G网络占用脚本。每半个小时下载一次资源,随后自动删除。全自动执行cd /root && wget -qO FuckNetWork.sh https://raw.githubusercontent.com/Mrmineduce21/Oracle_OneKey_Active/main/FuckNetWork.sh && chmod +x FuckNetWork.sh && nohup ./FuckNetWork.sh &不想占用资源了,直接重启服务器即可。reboot搭建个人网站通过 80 跟 443 端口搭建一个正常的博客网站,博客不一定在用,目的就是让甲骨文云看到你这个服务器真正有业务在上面。如果甲骨文释放掉你的服务器,会对你的数据产生影响,所以这个方式相对是比较安全的。搭建网站可以通过 KEJILION 的一键脚本搭建 WordPress 的个人博客。curl -sS -O https://kejilion.pro/kejilion.sh && chmod +x kejilion.sh && ./kejilion.sh搭建其他的服务如果博客比较难的话,大家可以通过一键脚本安装比如说 Alist、Cloudreve 等内容,将 80 跟 443 端口改成服务的端口,目的就是让甲骨文云看到你正在使用。【END】
2024年03月23日
38 阅读
0 评论
0 点赞
2024-01-06
自动提取 ChromeGo 一键翻墙包内的免费节点
ChromeGo:Chrome一键翻墙包介绍ChromeGo一个集成 Goflyway、v2ray、Daze、SSR、Brook、Lightsocks、trojan、蓝灯、psiphon 等N多翻墙工具的电脑翻墙包(推荐按前面所列顺序依次尝试),所有工具全部内置免费服务器,长期更新。Github 项目地址:https://github.com/bannedbook/fanqiang由于集成的工具过多,各个节点过于分散,没有做到一个很好的聚合,于是就有了下面介绍的几种提取免费节点的聚会脚本。利用 Python 脚本提取绵羊的金属精炼器参考文档:https://blog.mareep.net/posts/38493/ChromeGo 里面用到的节点池:https://github.com/Alvin9999/pac2/tree/master聚合过程就是提取他各个客户端里面的节点,用了 Python 进行了简单的处理转换,然后放 action 里面每天跑两次。具体操作见 Github 项目地址:https://github.com/vveg26/chromego\_merge演示视频:chromegopacsGithub 项目地址:https://github.com/vveg26/chromego\_merge项目介绍:提取 ChromeGo 经常更新维护的部分节点,显示节点地理位置,6小时运行一次 action 资源。订阅链接:https://raw.githubusercontent.com/markbang/chromegopacs/main/hy2pac.txt利用 Cloudflare Wokers 自动提取Github 项目地址:https://github.com/shiteThings/extractNodesCloudflare 创建 Workers登录 Cloudflare,点击左侧 Workers 和 Pages,点击右侧的 创建应用程序 按钮。点击 创建 Worker 按钮。 命名新的脚本名称,点击 部署 按钮。提示创建成功,点击 编辑代码。删除系统默认代码,复制粘贴下面代码。最后点击 保存与部署。addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { // 定义要发送请求的地址数组,每个元素包含一个 url 和一个处理函数 const sites = [ , , , , , , , , //hy2 , , , , , , , , //xray , , , , , , , //singbox , , , // 添加更多的网站地址和类型... ]; // 存储拼接后的字符串,用于去重 const uniqueStrings = new Set(); // 发送请求并处理响应 async function fetchData(site) { try { const response = await fetch(site.url); const data = await response.json(); // 根据网站类型选择对应的处理函数 let formattedString ; if(site.type === "hysteria") { formattedString = processHysteri(data) } else if(site.type === "hysteria2") { formattedString = processHysteria2(data) } else if(site.type === "xray"){ formattedString = processXray(data) } else { formattedString = processSingbox(data) } // 将拼接的字符串添加到集合中 uniqueStrings.add(formattedString); } catch (error) { console.error(`Error fetching data from $: $`); } } // 处理类型1的数据 function processHysteri(data) { // 从 JSON 数据中提取字段,并按指定格式拼接字符串 const up_mps = data.up_mbps; const down_mps = data.down_mbps; const auth_Str = data.auth_str; const server_name = data.server_name; const alpn = data.alpn; const server = data.server; return `hysteria://$?upmbps=$&downmbps=$&auth=$&insecure=1&peer=$&alpn=$`; } // 处理类型2的数据 function processHysteria2(data) { // 根据类型2的数据提取字段,并按指定格式拼接字符串 // 这里提供一个示例,实际情况需要根据实际数据结构调整 // 从 JSON 数据中提取所需字段 const auth = data.auth || ''; const server = data.server || ''; // 根据 data.insecure 的值设置 insecure const insecure = data.tls.insecure ? 1 : 0; const sni = data.tls.sni || ''; return `hy2://$@$?insecure=$&sni=$`; } // 处理xray的数据 function processXray(data) { let protocol, address, port, id, encryption, type, security, sni, fp, path, host; let outboundConfig = data.outbounds[0]; protocol = outboundConfig.protocol; id = outboundConfig.settings?.vnext?.[0]?.users?.[0]?.id; address = outboundConfig.settings?.vnext?.[0]?.address; port = outboundConfig.settings?.vnext?.[0]?.port; encryption = outboundConfig.settings?.vnext?.[0]?.users?.[0]?.encryption; type = outboundConfig?.streamSettings?.network; security = outboundConfig?.streamSettings?.security; sni = outboundConfig?.streamSettings?.tlsSettings?.serverName; fp = outboundConfig?.streamSettings?.tlsSettings?.fingerprint; path = outboundConfig?.streamSettings?.wsSettings?.path; host = outboundConfig?.streamSettings?.wsSettings?.headers?.Host; return `$://$@$:$?security=$&sni=$&fp=$&type=$&path=$&host=$`; } // 处理singbox的数据 function processSingbox(data) { const outbounds = data.outbounds[0]; const up_mps = outbounds.up_mbps; const down_mps = outbounds.down_mbps; const auth_Str = outbounds.auth_str; const server_name = outbounds.tls.server_name; const alpn = outbounds.tls.alpn[0]; const server = outbounds.server; const port = outbounds.server_port; return `hysteria://$:$?upmbps=$&downmbps=$&auth=$&insecure=1&peer=$&alpn=$`; } // 遍历所有地址并发送请求 const promises = sites.map(site => fetchData(site)); await Promise.all(promises); // 构建最终字符串 const finalStrings = [...uniqueStrings]; // 生成 HTML 页面内容 const htmlContent = finalStrings.map(str => `<p>$</p>`).join('\n'); return new Response(htmlContent, { headers: , }); }查看提取的免费节点接下来就可以通过访问 https://chromego.xxxx.workers.dev/ 的形式,查看自动提取出的免费节点。注意:由于 Cloudflare Workers 被滥用,打开上述链接,有可能需要通过代理(2024-01-10更新)该脚本作者提供了自己维护的提取地址(要开代理才能访问):worker 订阅链接:https://chromegolatest.amazinglinyy.workers.dev/自定义域订阅链接:https://chromenodes.marcol.top/NekoRay - 运行 Hysteria 代理核心参考文档:https://blog.echosec.top/p/nekoray-hysteria/上面提取的节点都是以链接形式呈现的,尤其是 Hysteria 节点,俗称歇斯底里,无法直接复制粘贴到 V2ray 中使用。这里推荐使用 NekoRay 客户端可直接复制粘贴使用提取的免费节点。介绍NekoRay 基于 Qt 的跨平台代理配置管理器 (后端 v2ray / sing-box),目前支持 Windows / Linux 开箱即用。GitHub 项目地址:https://github.com/MatsuriDayo/nekoray项目网址:https://matsuridayo.github.io/项目帮助文档:https://matsuridayo.github.io/index\_docs/使用方法跟 V2ray 类似,支持订阅更新,节点导入支持手动和剪贴板。这里重点介绍一下如何配置使用 Hysteria 协议。下载 Hysteria进入 Hysteria 项目最新下载页面:https://github.com/apernet/hysteria/releases ,下载最新版的 hysteria-windows-amd64.exe,将其放置在 NekoRay 配置目录下,例如:\nekoray\\config\\hysteria-windows-amd64.exe。配置 NekoRay 代理核心这里以最新版 3.26 版本为例:打开 NekoRay,进入「首选项」->「基本设置」->「其他核心」界面,选择 hysteria 的绝对路径,即刚下载的 hysteria-windows-amd64.exe 文件绝对路径。导入启动节点接下来从剪贴板导入节点,测试没问题后,启动节点,即可使用提取的免费节点进行科学上网了。设置绕过局域网和大陆的路由规则依次点击“首选项”→“路由设置”,转到“简易路由”页,点击“预设”里的“绕过局域网和大陆”,然后点击“确定”即可。【END】
2024年01月06日
145 阅读
0 评论
0 点赞
2023-11-04
解除 YouTube 对广告拦截器的封锁!
前言最近打开 YouTube,会弹出一个对话框,提示“使用广告拦截器违反 YouTube 服务条款”。点击“允许展示 YouTube 广告”,弹出一个界面让你点击刷新页面,但是仍然出现违反服务条款的对话框。解决方法(2023-12-20更新)新增用户规则:打开网址:https://axol.lol/阻擋破解点击“复制代码”按钮,复制以下代码youtube.com##+js(set, yt.config_.openPopupConfig.supportedPopups.adBlockMessageViewModel, false) youtube.com##+js(set, Object.prototype.adBlocksFound, 0) youtube.com##+js(set, ytplayer.config.args.raw_player_response.adPlacements, []) youtube.com##+js(set, Object.prototype.hasAllowedInstreamAd, true)打开浏览器广告拦截器的扩展选项,这里以 AdGuard 为例在“用户过滤器”中粘贴刚才复制的代码,点击“保存”按钮 再次打开 YouTube 视频,弹窗不见了新增油猴脚本新建油猴脚本输入以下代码:// ==UserScript== // @name 自动跳过YouTube广告 // @namespace youtube // @version 1.0 // @description 在YouTube网页上自动跳过广告 // @author Joey Gambler // @match *://www.youtube.com/* // @grant none // ==/UserScript== (function () { 'use strict'; function skipAd() { var skipButton = document.querySelector('.ytp-ad-text.ytp-ad-skip-button-text'); if (skipButton) { skipButton.click(); console.log("Click button"); } } // 设置检测时间间隔 var timer = setInterval(skipAd, 1000); // 1000毫秒 = 1秒 })();或直接添加油猴脚本地址: YouTube去广告 (greasyfork.org)")如果对您有帮助,欢迎点赞分享哦!参考文档https://github.com/JoeyGambler/youtube-ad-skip/blob/main/ad-skip.js【END】
2023年11月04日
8 阅读
2 评论
0 点赞
2023-08-06
CloudFlare Workers VLESS 永久免费节点搭建
前言近期很火的利用 CloudFlare Workers 搭建 VLESS 节点,支持自定义伪装网页,可以 CDN 自选域名,13个端口随便换。注册 CloudFlare相信很多人都有 CloudFlare 帐户,这里额外介绍一个临时邮箱地址,用于注册 CloudFlare。 临时邮箱:https://www.linshiyouxiang.net/CloudFlare Workers vless 代码部署登录 CloudFlare:https://dash.cloudflare.com/点击 Workers 和 Pages,点击 创建 Workers。 创建一个脚本名称,比如 vless,点击 部署。 点击 配置 Worker,点击 快速编辑。清除默认代码。将下面章节提到的代码,粘贴到代码框中。找到 let userID = 和 let proxyIP,更改 UUID 和推荐的 CDN 加速 IP。点击 保存并部署。以下介绍两组代码供选择使用,强烈建议更换默认的 userID,如果不更换,容易被扫描盗用。生成 UUID在线生成地址:https://1024tools.com/uuid打开 V2ray 客户端,选择 添加 VLESS 服务器,在弹出的对话框中,点击 生成 按钮,即可生成 UUID。CDN 加速 IPcdn-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(阿里香港优选)vless 部署代码1代码引用地址:https://github.com/zizifn/edgetunnel/blob/main/src/worker-vless.js 注意:需要更改 UUID, 添加 proxyIP 地址。// <!--GAMFC-->version base on commit 43fad05dcdae3b723c53c226f8181fc5bd47223e, time is 2023-06-22 15:20:02 UTC<!--GAMFC-END-->. // @ts-ignore import from 'cloudflare:sockets'; // 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'; let proxyIP = ''; if (!isValidUUID(userID)) { throw new Error('uuid is not valid'); } export default { /** * @param request * @param } env * @param ctx * @returns */ 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), ); case `/$`: { const vlessConfig = getVLESSConfig(userID, request.headers.get('Host')); return new Response(`$`, { status: 200, headers: { "Content-Type": "text/plain;charset=utf-8", } }); } default: return new Response('Not found', ); } } else { return await vlessOverWSHandler(request); } } catch (err) { /** @type */ let e = err; return new Response(e.toString()); } }, }; /** * * @param request */ async function vlessOverWSHandler(request) { /** @type */ // @ts-ignore const webSocketPair = new WebSocketPair(); const [client, webSocket] = Object.values(webSocketPair); webSocket.accept(); let address = ''; let portWithRandomLog = ''; const log = (/** @type */ info, /** @type */ event) => { console.log(`[$:$] $`, event || ''); }; const earlyDataHeader = request.headers.get('sec-websocket-protocol') || ''; const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log); /** @type }*/ let remoteSocketWapper = { value: null, }; let udpStreamWrite = null; let isDns = false; // ws --> remote readableWebSocketStream.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 = `$--$ ${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 it if (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 stream return; } } // ["version", "附加信息长度 N"] const vlessResponseHeader = new Uint8Array([vlessVersion[0], 0]); const rawClientData = chunk.slice(rawDataIndex); // TODO: support udp here when cf runtime has udp support if (isDns) { const = 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-ignore webSocket: client, }); } /** * Handles outbound TCP connections. * * @param remoteSocket * @param addressRemote The remote address to connect to. * @param portRemote The remote port to connect to. * @param rawClientData The raw client data to write. * @param webSocket The WebSocket to pass the remote socket to. * @param vlessResponseHeader The VLESS response header. * @param log The logging function. * @returns The remote socket. */ async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log,) { async function connectAndWrite(address, port) { /** @type */ const tcpSocket = connect({ hostname: address, port: port, }); remoteSocket.value = tcpSocket; log(`connected to $:$`); const writer = tcpSocket.writable.getWriter(); await writer.write(rawClientData); // first write, nomal is tls client hello writer.releaseLock(); return tcpSocket; } // if the cf connect tcp socket have no incoming data, we retry to redirect ip async function retry() { const tcpSocket = await connectAndWrite(proxyIP || addressRemote, portRemote) // no matter retry success or not, close websocket tcpSocket.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--> ws remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, retry, log); } /** * * @param webSocketServer * @param earlyDataHeader for ws 0rtt * @param 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.close safeCloseWebSocket(webSocketServer); if (readableStreamCancel) { return; } controller.close(); } ); webSocketServer.addEventListener('error', (err) => { log('webSocketServer has error'); controller.error(err); } ); // for ws 0rtt const = 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 cancel if (readableStreamCancel) { return; } log(`ReadableStream was canceled, due to $`) 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 vlessBuffer * @param 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 now const command = new Uint8Array( vlessBuffer.slice(18 + optLength, 18 + optLength + 1) )[0]; // 0x01 TCP // 0x02 UDP // 0x03 MUX if (command === 1) { } else if (command === 2) { isUDP = true; } else { return { hasError: true, message: `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 == 0x005d const 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 addressLength=addressBuffer[1] // 3--> ipv6 addressLength =16 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) ); // 2001:0db8:85a3:0000:0000:8a2e:0370:7334 const ipv6 = []; for (let i = 0; i < 8; i++) { ipv6.push(dataView.getUint16(i * 2).toString(16)); } addressValue = ipv6.join(':'); // seems no need add [] for ipv6 break; default: return { hasError: true, message: `invild addressType is $`, }; } if (!addressValue) { return { hasError: true, message: `addressValue is empty, addressType is $`, }; } return { hasError: false, addressRemote: addressValue, addressType, portRemote, rawDataIndex: addressValueIndex + addressLength, vlessVersion: version, isUDP, }; } /** * * @param remoteSocket * @param webSocket * @param vlessResponseHeader * @param retry * @param log */ async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) { // remote--> ws let remoteChunkCount = 0; let chunks = []; /** @type */ let vlessHeader = vlessResponseHeader; let hasIncomingData = false; // check if remoteSocket has incoming data await remoteSocket.readable .pipeTo( new WritableStream({ start() { }, /** * * @param 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 $`); // 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 coming if (hasIncomingData === false && retry) { log(`retry`) retry(); } } /** * * @param base64Str * @returns */ function base64ToArrayBuffer(base64Str) { if (!base64Str) { return ; } try { // go use modified Base64 for URL rfc4648 which js atob not support base64Str = base64Str.replace(/-/g, '+').replace(/_/g, '/'); const decode = atob(base64Str); const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0)); return ; } catch (error) { return ; } } /** * This is not real UUID validation * @param uuid */ function isValidUUID(uuid) { const uuidRegex = /^[0-9a-f]-[0-9a-f]-[4][0-9a-f]-[89ab][0-9a-f]-[0-9a-f]$/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 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 webSocket * @param vlessResponseHeader * @param 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 message for (let index = 0; index < chunk.byteLength;) { const lengthBuffer = chunk.slice(index, index + 2); const udpPakcetLength = new DataView(lengthBuffer).getUint16(0); const udpData = new Uint8Array( chunk.slice(index + 2, index + 2 + udpPakcetLength) ); index = index + 2 + udpPakcetLength; controller.enqueue(udpData); } }, flush(controller) { } }); // only handle dns udp for now transformStream.readable.pipeTo(new WritableStream({ async write(chunk) { const resp = await fetch('https://1.1.1.1/dns-query', { method: 'POST', headers: { 'content-type': 'application/dns-message', }, body: chunk, }) const dnsQueryResult = await resp.arrayBuffer(); const udpSize = dnsQueryResult.byteLength; // console.log([...new Uint8Array(dnsQueryResult)].map((x) => x.toString(16))); const udpSizeBuffer = new Uint8Array([(udpSize >> 8) & 0xff, udpSize & 0xff]); if (webSocket.readyState === WS_READY_STATE_OPEN) { log(`doh success and dns message length is $`); 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 chunk */ write(chunk) { writer.write(chunk); } }; } /** * * @param userID * @param hostName * @returns */ function getVLESSConfig(userID, hostName) { const vlessMain = `vless://$@$:443?encryption=none&security=tls&sni=$&fp=randomized&type=ws&host=$&path=%2F%3Fed%3D2048#$` return ` ################################################################ v2ray --------------------------------------------------------------- $ --------------------------------------------------------------- ################################################################ clash-meta --------------------------------------------------------------- - type: vless name: $ server: $ port: 443 uuid: $ network: ws tls: true udp: false sni: $ client-fingerprint: chrome ws-opts: path: "/?ed=2048" headers: host: $ --------------------------------------------------------------- ################################################################ `; }vless 部署代码2代码引用地址:https://github.com/yonggekkk/CF-workers-pages-vless/blob/main/\_worker.js需要更改 UUID自带 CloudFlare 证书的 proxyIP 地址代码104行,支持自定义伪装网页,修改对应的网页地址即可。代码中地址为 CCTV 官网// <!--GAMFC-->version base on commit 43fad05dcdae3b723c53c226f8181fc5bd47223e, time is 2023-06-22 15:20:02 UTC<!--GAMFC-END-->. // @ts-ignore import from 'cloudflare:sockets'; // 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'; const proxyIPs = ['cdn-all.xn--b6gac.eu.org', 'cdn-all.xijingping.link', 'cdn.xn--b6gac.eu.org', 'cdn-b100.xn--b6gac.eu.org', 'edgetunnel.anycast.eu.org', 'cdn.anycast.eu.org']; let proxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)]; let dohURL = 'https://sky.rethinkdns.com/1:-Pf_____9_8A_AMAIgE8kMABVDDmKOHTAKg='; // https://cloudflare-dns.com/dns-query or https://dns.google/dns-query // v2board api environment variables let nodeId = ''; // 1 let apiToken = ''; //abcdefghijklmnopqrstuvwxyz123456 let apiHost = ''; // api.v2board.com if (!isValidUUID(userID)) { throw new Error('uuid is not valid'); } export default { /** * @param request * @param } env * @param ctx * @returns */ async fetch(request, env, ctx) { try { userID = env.UUID || userID; proxyIP = env.PROXYIP || proxyIP; dohURL = env.DNS_RESOLVER_URL || dohURL; nodeId = env.NODE_ID || nodeId; apiToken = env.API_TOKEN || apiToken; apiHost = env.API_HOST || apiHost; 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;charset=utf-8", }, }); case '/connect': // for test connect to cf socket const [hostname, port] = ['cloudflare.com', '80']; console.log(`Connecting to $:$...`); try { const socket = await connect({ hostname: hostname, port: parseInt(port, 10), }); const writer = socket.writable.getWriter(); try { await writer.write(new TextEncoder().encode('GET / HTTP/1.1\r\nHost: ' + hostname + '\r\n\r\n')); } catch (writeError) { writer.releaseLock(); await socket.close(); return new Response(writeError.message, ); } writer.releaseLock(); const reader = socket.readable.getReader(); let value; try { const result = await reader.read(); value = result.value; } catch (readError) { await reader.releaseLock(); await socket.close(); return new Response(readError.message, ); } await reader.releaseLock(); await socket.close(); return new Response(new TextDecoder().decode(value), ); } catch (connectError) { return new Response(connectError.message, ); } case `/$`: { const vlessConfig = getVLESSConfig(userID, request.headers.get('Host')); return new Response(`$`, { status: 200, headers: { "Content-Type": "text/plain;charset=utf-8", } }); } default: // return new Response('Not found', ); // For any other path, reverse proxy to 'www.fmprc.gov.cn' and return the original response url.hostname = 'tv.cctv.com'; url.protocol = 'https:'; request = new Request(url, request); return await fetch(request); } } else { return await vlessOverWSHandler(request); } } catch (err) { /** @type */ let e = err; return new Response(e.toString()); } }, }; /** * * @param request */ async function vlessOverWSHandler(request) { /** @type */ // @ts-ignore const webSocketPair = new WebSocketPair(); const [client, webSocket] = Object.values(webSocketPair); webSocket.accept(); let address = ''; let portWithRandomLog = ''; const log = (/** @type */ info, /** @type */ event) => { console.log(`[$:$] $`, event || ''); }; const earlyDataHeader = request.headers.get('sec-websocket-protocol') || ''; const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log); /** @type }*/ let remoteSocketWapper = { value: null, }; let udpStreamWrite = null; let isDns = false; // ws --> remote readableWebSocketStream.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, } = await processVlessHeader(chunk, userID); address = addressRemote; portWithRandomLog = `$--$ ${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 it if (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 stream return; } } // ["version", "附加信息长度 N"] const vlessResponseHeader = new Uint8Array([vlessVersion[0], 0]); const rawClientData = chunk.slice(rawDataIndex); // TODO: support udp here when cf runtime has udp support if (isDns) { const = 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-ignore webSocket: client, }); } let apiResponseCache = null; let cacheTimeout = null; /** * Fetches the API response from the server and caches it for future use. * @returns A Promise that resolves to the API response object or null if there was an error. */ async function fetchApiResponse() { const requestOptions = { method: 'GET', redirect: 'follow' }; try { const response = await fetch(`https://$/api/v1/server/UniProxy/user?node_id=$&node_type=v2ray&token=$`, requestOptions); if (!response.ok) { console.error('Error: Network response was not ok'); return null; } const apiResponse = await response.json(); apiResponseCache = apiResponse; // Refresh the cache every 5 minutes (300000 milliseconds) if (cacheTimeout) { clearTimeout(cacheTimeout); } cacheTimeout = setTimeout(() => fetchApiResponse(), 300000); return apiResponse; } catch (error) { console.error('Error:', error); return null; } } /** * Returns the cached API response if it exists, otherwise fetches the API response from the server and caches it for future use. * @returns A Promise that resolves to the cached API response object or the fetched API response object, or null if there was an error. */ async function getApiResponse() { if (!apiResponseCache) { return await fetchApiResponse(); } return apiResponseCache; } /** * Checks if a given UUID is present in the API response. * @param targetUuid The UUID to search for. * @returns A Promise that resolves to true if the UUID is present in the API response, false otherwise. */ async function checkUuidInApiResponse(targetUuid) { // Check if any of the environment variables are empty if (!nodeId || !apiToken || !apiHost) { return false; } try { const apiResponse = await getApiResponse(); if (!apiResponse) { return false; } const isUuidInResponse = apiResponse.users.some(user => user.uuid === targetUuid); return isUuidInResponse; } catch (error) { console.error('Error:', error); return false; } } // Usage example: // const targetUuid = "65590e04-a94c-4c59-a1f2-571bce925aad"; // checkUuidInApiResponse(targetUuid).then(result => console.log(result)); /** * Handles outbound TCP connections. * * @param remoteSocket * @param addressRemote The remote address to connect to. * @param portRemote The remote port to connect to. * @param rawClientData The raw client data to write. * @param webSocket The WebSocket to pass the remote socket to. * @param vlessResponseHeader The VLESS response header. * @param log The logging function. * @returns The remote socket. */ async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log,) { async function connectAndWrite(address, port) { /** @type */ const tcpSocket = connect({ hostname: address, port: port, }); remoteSocket.value = tcpSocket; log(`connected to $:$`); const writer = tcpSocket.writable.getWriter(); await writer.write(rawClientData); // first write, nomal is tls client hello writer.releaseLock(); return tcpSocket; } // if the cf connect tcp socket have no incoming data, we retry to redirect ip async function retry() { const tcpSocket = await connectAndWrite(proxyIP || addressRemote, portRemote) // no matter retry success or not, close websocket tcpSocket.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--> ws remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, retry, log); } /** * * @param webSocketServer * @param earlyDataHeader for ws 0rtt * @param 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.close safeCloseWebSocket(webSocketServer); if (readableStreamCancel) { return; } controller.close(); } ); webSocketServer.addEventListener('error', (err) => { log('webSocketServer has error'); controller.error(err); } ); // for ws 0rtt const = 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 cancel if (readableStreamCancel) { return; } log(`ReadableStream was canceled, due to $`) 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 vlessBuffer * @param userID * @returns */ async 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; const slicedBuffer = new Uint8Array(vlessBuffer.slice(1, 17)); const slicedBufferString = stringify(slicedBuffer); const uuids = userID.includes(',') ? userID.split(",") : [userID]; const checkUuidInApi = await checkUuidInApiResponse(slicedBufferString); isValidUser = uuids.some(userUuid => checkUuidInApi || slicedBufferString === userUuid.trim()); console.log(`checkUuidInApi: $, userID: $`); if (!isValidUser) { return { hasError: true, message: 'invalid user', }; } const optLength = new Uint8Array(vlessBuffer.slice(17, 18))[0]; //skip opt for now const command = new Uint8Array( vlessBuffer.slice(18 + optLength, 18 + optLength + 1) )[0]; // 0x01 TCP // 0x02 UDP // 0x03 MUX if (command === 1) { } else if (command === 2) { isUDP = true; } else { return { hasError: true, message: `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 == 0x005d const 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 addressLength=addressBuffer[1] // 3--> ipv6 addressLength =16 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) ); // 2001:0db8:85a3:0000:0000:8a2e:0370:7334 const ipv6 = []; for (let i = 0; i < 8; i++) { ipv6.push(dataView.getUint16(i * 2).toString(16)); } addressValue = ipv6.join(':'); // seems no need add [] for ipv6 break; default: return { hasError: true, message: `invild addressType is $`, }; } if (!addressValue) { return { hasError: true, message: `addressValue is empty, addressType is $`, }; } return { hasError: false, addressRemote: addressValue, addressType, portRemote, rawDataIndex: addressValueIndex + addressLength, vlessVersion: version, isUDP, }; } /** * * @param remoteSocket * @param webSocket * @param vlessResponseHeader * @param retry * @param log */ async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) { // remote--> ws let remoteChunkCount = 0; let chunks = []; /** @type */ let vlessHeader = vlessResponseHeader; let hasIncomingData = false; // check if remoteSocket has incoming data await remoteSocket.readable .pipeTo( new WritableStream({ start() { }, /** * * @param 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 $`); // 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 coming if (hasIncomingData === false && retry) { log(`retry`) retry(); } } /** * * @param base64Str * @returns */ function base64ToArrayBuffer(base64Str) { if (!base64Str) { return ; } try { // go use modified Base64 for URL rfc4648 which js atob not support base64Str = base64Str.replace(/-/g, '+').replace(/_/g, '/'); const decode = atob(base64Str); const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0)); return ; } catch (error) { return ; } } /** * This is not real UUID validation * @param uuid */ function isValidUUID(uuid) { const uuidRegex = /^[0-9a-f]-[0-9a-f]-[4][0-9a-f]-[89ab][0-9a-f]-[0-9a-f]$/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 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 webSocket * @param vlessResponseHeader * @param 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 message for (let index = 0; index < chunk.byteLength;) { const lengthBuffer = chunk.slice(index, index + 2); const udpPakcetLength = new DataView(lengthBuffer).getUint16(0); const udpData = new Uint8Array( chunk.slice(index + 2, index + 2 + udpPakcetLength) ); index = index + 2 + udpPakcetLength; controller.enqueue(udpData); } }, flush(controller) { } }); // only handle dns udp for now transformStream.readable.pipeTo(new WritableStream({ async write(chunk) { const resp = await fetch(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 $`); 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 chunk */ write(chunk) { writer.write(chunk); } }; } /** * * @param userID * @param hostName * @returns */ function getVLESSConfig(userID, hostName) { const vlessws = `vless://$@time.cloudflare.com:8880?encryption=none&type=ws&host=$&path=%2F%3Fed%3D2048#$` const vlesswstls = `vless://$@time.cloudflare.com:8443?encryption=none&security=tls&type=ws&host=兄弟,你的自定义域名呢?&path=%2F%3Fed%3D2048#$` return ` ==========================配置详解============================== ################################################################ 一、CF-workers-vless+ws节点,分享链接如下: $ --------------------------------------------------------------- 注意:当前节点无需域名,TLS选项关闭 --------------------------------------------------------------- 客户端必要文明参数如下: 客户端地址(address):自选域名 或者 自选IP 端口(port):7个http端口可任意选择(80、8080、8880、2052、2082、2086、2095) 用户ID(uuid):$ 传输协议(network):ws/websocket 伪装域名(host):$ 路径(path):/?ed=2048 ################################################################ ################################################################ 二、CF-workers-vless+ws+tls节点,分享链接如下: $ --------------------------------------------------------------- 注意:客户端ws选项后的伪装域名host必须改为你自定义的域名 --------------------------------------------------------------- 客户端必要文明参数如下: 客户端地址(address):自选域名 或者 自选IP 端口(port):6个https端口可任意选择(443、8443、2053、2083、2087、2096) 用户ID(uuid):$ 传输协议(network):ws/websocket 伪装域名(host):兄弟,你的自定义域名呢? 路径(path):/?ed=2048 传输安全(TLS):开启 跳过证书验证(allowlnsecure):false ################################################################ ################################################################ clash-meta --------------------------------------------------------------- - type: vless name: $ server: $ port: 443 uuid: $ network: ws tls: true udp: false sni: $ client-fingerprint: chrome ws-opts: path: "/?ed=2048" headers: host: $ --------------------------------------------------------------- ################################################################ `; }V2ray 使用 CloudFlare Workers vless 节点(无域名)复制刚刚创建的代码地址,格式为:https://vless.xxx.workers.dev/,其中 vless 为创建的脚本名称,xxx 为 CloudFlare 用户名。在浏览器地址栏中粘贴代码地址后,如果出现一段字符,即表明创建成功。接下来在该地址后输入 /UUID字符串,回车即可看到 vless 地址。 将页面中的 V2ray 地址复制,打开 V2ray 软件,点击 服务器 选项,选择 从剪贴板导入批量URL,即可看到创建的节点。双击刚刚创建的节点,将端口(port)改为 2052,传输层安全(TLS) 设置为空,传输协议(network) 为 ws,地址(address) 改为优选 IP。 注:7个 http 端口可任意选择:80、8080、8880、2052、2082、2086、2095 Workers 专用 IP 优选工具CloudFlare 优质 IP 自动切换:https://stock.hostmonit.com/CloudFlareYes172.64.32.1/24 (推荐移动,走香港) 104.28.14.0/24 (推荐移动,走新加坡) 104.23.240.0 ~ 104.23.243.254 (推荐联通、移动,线路未知) 108.162.236.1/24 (推荐联通,走美国) 104.20.157.0/24 (推荐联通,走日本) 104.16.160.1/24 (推荐电信,走洛杉矶) 172.64.0.0/24 (推荐电信,走旧金山) 172.64.32.* (走欧洲)优选工具 Windows 版本下载地址,断开所有 VPN 和科学上网方式,选择运行任意批处理文件,在运行后的结果中,选择 PING 值低的 IP 地址,复制到 V2ray 的 地址(address) 中。 CloudFlare 自选域名自选域名下载地址,断开所有 VPN 和科学上网方式,选择自选域名程序单文件,运行后在相同文件夹下中打开 txt 文件,选择 PING 值低的域名,复制到 V2ray 的 地址(address) 中。V2ray 使用 CloudFlare Workers vless 节点(有域名)在 CloudFlare Workers 中,打开刚才创建的脚本,点击 查看,点击 添加自定义域。 在自定义域对话框中输入已经在 CloudFlare 注册域名的二级域名,点击 添加自定义域。比如:vless.5iehome.cf。接下来只需在浏览器地址栏中粘贴输入 https://vless.5iehome.cf/UUID字符串,回车即可看到 vless 地址。将页面中的 V2ray 地址复制,打开 V2ray 软件,点击 服务器 选项,选择 从剪贴板导入批量URL,即可看到创建的节点。双击刚刚创建的节点,将端口(port)改为 443,传输层安全(TLS) 设置为 tls,传输协议(network) 为 ws,地址(address) 改为优选 IP。 注:6个 http 端口可任意选择:443、8443、2053、2083、2087、2096 节点测速V2ray 下测试节点速度,要选择 测试服务器真连接延迟(多选)(Ctrl+R),延迟数值为大于 0 即为导通,数值为 -1 即为不导通。IP 地址查看https://whatismyipaddress.com/https://ip.gs文中程序下载CloudFlare Workers VLESS 永久免费节点搭建https://www.aliyundrive.com/s/mXFeMtdBF2T 提取码: c1m7https://www.123pan.com/s/Oy5RVv-swXB.html 提取码: V3iX参考文章https://jdssl.top/index.php/2023/07/21/2023vpn/https://www.youtube.com/watch?v=5fvhws6ZXrMhttps://ygkkk.blogspot.com/2023/07/cfworkers-vless.htmlhttps://www.youtube.com/watch?v=9V9CQxmfwoA【END】
2023年08月06日
27 阅读
3 评论
0 点赞
2023-08-06
CloudFlare WARP 免费 VPN 搭建教程
前言最近比较火的科学上网的方法,是使用 CloudFlare WARP 免费 VPN,并且可以优选 IP,提高上网速度。CloudFlare WARP 免费 VPNWARP 介绍1.1.1.1 的 WARP 应用以一个经过优化的现代协议来代替您的设备和 Internet 之间的连接。具有快速、免费、私密的特点,最关键的通过优选 IP 后,可以大幅度提高上网速度。下载安装WARP 支持各个平台,Windows 的下载地址为:Microsoft应用中心1.1.1.1下载后双击安装即可。直接使用 WARP在状态栏打开软件,点击连接按钮即可使用。默认情况下,软件会自动分配一个普通账号,只有 1GB 的使用流量。获取 WARP+ 永久免费流量打开 Telegram,搜索 @generatewarpplusbot按照提示,关联相关订阅后,获取 WARP 账户许可证密钥 (26个字符),格式为:xxxxxxxx-xxxxxxxx-xxxxxxxx使用 WARP+ 免费流量方法一:更改 WARP 帐户直接在 WARP 中选择 帐户,点击 使用其他密钥 按钮,在弹出的对话框中输入在 Telegram 上得到的许可证密钥。方法二:使用 WireGuard下载 WireGuard,下载对应客户端。经测试,下载及安装都需要代理才能完成。在线生成 WARP 的 WireGuard 配置文件,打开生成配置文件网址,点击 Run,在运行代码框中输入 2,即 WARP+。然后输入在 Telegram 上得到的26位许可证密钥。设备名设置可有可无。 将生成的配置文件输入到 WireGuard 中,就可以连接使用了。 WireGuard 可以脱离 CloudFlare WARP 独立使用。CloudFlare 优化 IPWARP+ IP 优选工具下载:https://gitlab.com/Misaka-blog/warp-script/-/blob/main/files/warp-yxip/warp-yxip-win.7z断开所有 VPN 和科学上网方式,双击 warp-yxip.bat,选择默认 1 IPv4 优选地址即可。打开 result.csv,选择延迟小,丢包率为 0 的 IP 地址即可。 复制延迟小,丢包率为 0 的 IP 地址及端口号,将 WireGuard 配置文件 Endpoint 地址替换,保存后再连接,就会发现速度有了明显改善。 文中软件下载地址「CloudFlare WARP.exe」https://www.123pan.com/s/Oy5RVv-wwXB.html 提取码: 7iAahttps://www.aliyundrive.com/s/Rn7dPV86Nqn 提取码: 6ep3【END】
2023年08月06日
55 阅读
0 评论
0 点赞
1
2
3