显示标签为“免费VPN”的博文。显示所有博文
显示标签为“免费VPN”的博文。显示所有博文

2024年5月5日星期日

永久免费翻墙,永久免费节点,使用Cloudflare Worker 搭建免费Trojan协议节点!

大佬项目:https://github.com/ca110us/epeius


 worker.js

  1. // src/worker.js  
  2. import { connect } from "cloudflare:sockets";  
  3. const proxyIPs = ['cdn.xn--b6gac.eu.org''cdn-all.xn--b6gac.eu.org''workers.cloudflare.cyou'];  
  4.   
  5. let proxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)];  
  6.   
  7. let sha224Password = 'xxxx';  
  8.   
  9. const worker_default = {  
  10.    /** 
  11.     * @param {import("@cloudflare/workers-types").Request} request 
  12.     * @param {{UUID: string, PROXYIP: string}} env 
  13.     * @param {import("@cloudflare/workers-types").ExecutionContext} ctx 
  14.     * @returns {Promise<Response>} 
  15.     */  
  16.    async fetch(request, env, ctx) {  
  17.        try {  
  18.            proxyIP = env.PROXYIP || proxyIP;  
  19.            const upgradeHeader = request.headers.get("Upgrade");  
  20.            if (!upgradeHeader || upgradeHeader !== "websocket") {  
  21.                const url = new URL(request.url);  
  22.                switch (url.pathname) {  
  23.                    case "/link":  
  24.                        const host = request.headers.get('Host');  
  25.                        return new Response(`trojan://ca110us@${host}:443/?type=ws&host=${host}&security=tls`, {  
  26.                            status: 200,  
  27.                            headers: {  
  28.                                "Content-Type""text/plain;charset=utf-8",  
  29.                           }  
  30.                       });  
  31.                    default:  
  32.                        return new Response("404 Not found", { status: 404 });  
  33.               }  
  34.           } else {  
  35.                return await trojanOverWSHandler(request);  
  36.           }  
  37.       } catch (err) {  
  38.            let e = err;  
  39.            return new Response(e.toString());  
  40.       }  
  41.   }  
  42. };  
  43.   
  44. async function trojanOverWSHandler(request) {  
  45.    const webSocketPair = new WebSocketPair();  
  46.    const [client, webSocket] = Object.values(webSocketPair);  
  47.    webSocket.accept();  
  48.    let address = "";  
  49.    let portWithRandomLog = "";  
  50.    const log = (info, event) => {  
  51.        console.log(`[${address}:${portWithRandomLog}] ${info}`, event || "");  
  52.   };  
  53.    const earlyDataHeader = request.headers.get("sec-websocket-protocol") || "";  
  54.    const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log);  
  55.    let remoteSocketWapper = {  
  56.        value: null  
  57.   };  
  58.    let udpStreamWrite = null;  
  59.    readableWebSocketStream.pipeTo(new WritableStream({  
  60.        async write(chunk, controller) {  
  61.            if (udpStreamWrite) {  
  62.                return udpStreamWrite(chunk);  
  63.           }  
  64.            if (remoteSocketWapper.value) {  
  65.                const writer = remoteSocketWapper.value.writable.getWriter();  
  66.                await writer.write(chunk);  
  67.                writer.releaseLock();  
  68.                return;  
  69.           }  
  70.            const {  
  71.                hasError,  
  72.                message,  
  73.                portRemote = 443,  
  74.                addressRemote = "",  
  75.                rawClientData  
  76.           } = await parseTrojanHeader(chunk);  
  77.            address = addressRemote;  
  78.            portWithRandomLog = `${portRemote}--${Math.random()} tcp`;  
  79.            if (hasError) {  
  80.                throw new Error(message);  
  81.                return;  
  82.           }  
  83.            handleTCPOutBound(remoteSocketWapper, addressRemote, portRemote, rawClientData, webSocket, log);  
  84.       },  
  85.        close() {  
  86.            log(`readableWebSocketStream is closed`);  
  87.       },  
  88.        abort(reason) {  
  89.            log(`readableWebSocketStream is aborted`, JSON.stringify(reason));  
  90.       }  
  91.   })).catch((err) => {  
  92.        log("readableWebSocketStream pipeTo error", err);  
  93.   });  
  94.    return new Response(null, {  
  95.        status: 101,  
  96.        // @ts-ignore  
  97.        webSocket: client  
  98.   });  
  99. }  
  100.   
  101. async function parseTrojanHeader(buffer) {  
  102.    if (buffer.byteLength < 56) {  
  103.        return {  
  104.            hasError: true,  
  105.            message: "invalid data"  
  106.       };  
  107.   }  
  108.    let crLfIndex = 56;  
  109.    if (new Uint8Array(buffer.slice(56, 57))[0] !== 0x0d || new Uint8Array(buffer.slice(57, 58))[0] !== 0x0a) {  
  110.        return {  
  111.            hasError: true,  
  112.            message: "invalid header format (missing CR LF)"  
  113.       };  
  114.   }  
  115.    const password = new TextDecoder().decode(buffer.slice(0, crLfIndex));  
  116.    if (password !== sha224Password) {  
  117.        return {  
  118.            hasError: true,  
  119.            message: "invalid password"  
  120.       };  
  121.   }  
  122.   
  123.    const socks5DataBuffer = buffer.slice(crLfIndex + 2);  
  124.    if (socks5DataBuffer.byteLength < 6) {  
  125.        return {  
  126.            hasError: true,  
  127.            message: "invalid SOCKS5 request data"  
  128.       };  
  129.   }  
  130.   
  131.    const view = new DataView(socks5DataBuffer);  
  132.    const cmd = view.getUint8(0);  
  133.    if (cmd !== 1) {  
  134.        return {  
  135.            hasError: true,  
  136.            message: "unsupported command, only TCP (CONNECT) is allowed"  
  137.       };  
  138.   }  
  139.   
  140.    const atype = view.getUint8(1);  
  141.    // 0x01: IPv4 address  
  142.    // 0x03: Domain name  
  143.    // 0x04: IPv6 address  
  144.    let addressLength = 0;  
  145.    let addressIndex = 2;  
  146.    let address = "";  
  147.    switch (atype) {  
  148.        case 1:  
  149.            addressLength = 4;  
  150.            address = new Uint8Array(  
  151.              socks5DataBuffer.slice(addressIndex, addressIndex + addressLength)  
  152.           ).join(".");  
  153.            break;  
  154.        case 3:  
  155.            addressLength = new Uint8Array(  
  156.              socks5DataBuffer.slice(addressIndex, addressIndex + 1)  
  157.           )[0];  
  158.            addressIndex += 1;  
  159.            address = new TextDecoder().decode(  
  160.              socks5DataBuffer.slice(addressIndex, addressIndex + addressLength)  
  161.           );  
  162.            break;  
  163.        case 4:  
  164.            addressLength = 16;  
  165.            const dataView = new DataView(socks5DataBuffer.slice(addressIndex, addressIndex + addressLength));  
  166.            const ipv6 = [];  
  167.            for (let i = 0; i < 8; i++) {  
  168.                ipv6.push(dataView.getUint16(i * 2).toString(16));  
  169.           }  
  170.            address = ipv6.join(":");  
  171.            break;  
  172.        default:  
  173.            return {  
  174.                hasError: true,  
  175.                message: `invalid addressType is ${atype}`  
  176.           };  
  177.   }  
  178.   
  179.    if (!address) {  
  180.        return {  
  181.            hasError: true,  
  182.            message: `address is empty, addressType is ${atype}`  
  183.       };  
  184.   }  
  185.   
  186.    const portIndex = addressIndex + addressLength;  
  187.    const portBuffer = socks5DataBuffer.slice(portIndex, portIndex + 2);  
  188.    const portRemote = new DataView(portBuffer).getUint16(0);  
  189.    return {  
  190.        hasError: false,  
  191.        addressRemote: address,  
  192.        portRemote,  
  193.        rawClientData: socks5DataBuffer.slice(portIndex + 4)  
  194.   };  
  195. }  
  196.   
  197. async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, log) {  
  198.    async function connectAndWrite(address, port) {  
  199.        const tcpSocket2 = connect({  
  200.            hostname: address,  
  201.            port  
  202.       });  
  203.        remoteSocket.value = tcpSocket2;  
  204.        log(`connected to ${address}:${port}`);  
  205.        const writer = tcpSocket2.writable.getWriter();  
  206.        await writer.write(rawClientData);  
  207.        writer.releaseLock();  
  208.        return tcpSocket2;  
  209.   }  
  210.    async function retry() {  
  211.        const tcpSocket2 = await connectAndWrite(proxyIP || addressRemote, portRemote);  
  212.        tcpSocket2.closed.catch((error) => {  
  213.            console.log("retry tcpSocket closed error", error);  
  214.       }).finally(() => {  
  215.            safeCloseWebSocket(webSocket);  
  216.       });  
  217.        remoteSocketToWS(tcpSocket2, webSocket, null, log);  
  218.   }  
  219.    const tcpSocket = await connectAndWrite(addressRemote, portRemote);  
  220.    remoteSocketToWS(tcpSocket, webSocket, retry, log);  
  221. }  
  222.   
  223. function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) {  
  224.    let readableStreamCancel = false;  
  225.    const stream = new ReadableStream({  
  226.        start(controller) {  
  227.            webSocketServer.addEventListener("message", (event) => {  
  228.                if (readableStreamCancel) {  
  229.                    return;  
  230.               }  
  231.                const message = event.data;  
  232.                controller.enqueue(message);  
  233.           });  
  234.            webSocketServer.addEventListener("close", () => {  
  235.                safeCloseWebSocket(webSocketServer);  
  236.                if (readableStreamCancel) {  
  237.                    return;  
  238.               }  
  239.                controller.close();  
  240.           });  
  241.            webSocketServer.addEventListener("error", (err) => {  
  242.                log("webSocketServer error");  
  243.                controller.error(err);  
  244.           });  
  245.            const { earlyData, error } = base64ToArrayBuffer(earlyDataHeader);  
  246.            if (error) {  
  247.                controller.error(error);  
  248.           } else if (earlyData) {  
  249.                controller.enqueue(earlyData);  
  250.           }  
  251.       },  
  252.        pull(controller) {},  
  253.        cancel(reason) {  
  254.            if (readableStreamCancel) {  
  255.                return;  
  256.           }  
  257.            log(`readableStream was canceled, due to ${reason}`);  
  258.            readableStreamCancel = true;  
  259.            safeCloseWebSocket(webSocketServer);  
  260.       }  
  261.   });  
  262.    return stream;  
  263. }  
  264.   
  265. async function remoteSocketToWS(remoteSocket, webSocket, retry, log) {  
  266.    let hasIncomingData = false;  
  267.    await remoteSocket.readable.pipeTo(  
  268.        new WritableStream({  
  269.            start() {},  
  270.            /** 
  271.             * 
  272.             * @param {Uint8Array} chunk 
  273.             * @param {*} controller 
  274.             */  
  275.            async write(chunk, controller) {  
  276.                hasIncomingData = true;  
  277.                if (webSocket.readyState !== WS_READY_STATE_OPEN) {  
  278.                    controller.error(  
  279.                        "webSocket connection is not open"  
  280.                   );  
  281.               }  
  282.                webSocket.send(chunk);  
  283.           },  
  284.            close() {  
  285.                log(`remoteSocket.readable is closed, hasIncomingData: ${hasIncomingData}`);  
  286.           },  
  287.            abort(reason) {  
  288.                console.error("remoteSocket.readable abort", reason);  
  289.           }  
  290.       })  
  291.   ).catch((error) => {  
  292.        console.error(  
  293.            `remoteSocketToWS error:`,  
  294.            error.stack || error  
  295.       );  
  296.        safeCloseWebSocket(webSocket);  
  297.   });  
  298.    if (hasIncomingData === false && retry) {  
  299.        log(`retry`);  
  300.        retry();  
  301.   }  
  302. }  
  303.   
  304. function base64ToArrayBuffer(base64Str) {  
  305.    if (!base64Str) {  
  306.        return { error: null };  
  307.   }  
  308.    try {  
  309.        base64Str = base64Str.replace(/-/g, "+").replace(/_/g, "/");  
  310.        const decode = atob(base64Str);  
  311.        const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0));  
  312.        return { earlyData: arryBuffer.buffer, error: null };  
  313.   } catch (error) {  
  314.        return { error };  
  315.   }  
  316. }  
  317.   
  318. let WS_READY_STATE_OPEN = 1;  
  319. let WS_READY_STATE_CLOSING = 2;  
  320.   
  321. function safeCloseWebSocket(socket) {  
  322.    try {  
  323.        if (socket.readyState === WS_READY_STATE_OPEN || socket.readyState === WS_READY_STATE_CLOSING) {  
  324.            socket.close();  
  325.       }  
  326.   } catch (error) {  
  327.        console.error("safeCloseWebSocket error", error);  
  328.   }  
  329. }  
  330. export {  
  331.    worker_default as  
  332.    default  
  333. };  
  334. //# sourceMappingURL=worker.js.map