nodejs搭建简单的代理服务

仅支持socks5http代理

代码

/**
 * node:net
 */
const net = require("net");

/**
* 0x05 处理器
* @param { net.Socket } socket
* @param { Buffer } buffer
*/
const SOCKS5Handel = (socket, buffer) => {
    // 根据协议添加协议验证与响应
    socket.write(Buffer.from([5, 0]), (error) => {
        // 添加协议验证与响应失败
        if (error) {
            console.error("proxyServer:SOCKS5Handel.添加协议验证与响应失败:", error);
            socket.destroy();
            return;
        }

        // 主机 端口
        let host, port, hostLen = 0;

        // 协议验证与响应
        socket.once("data", (data) => {
            // 只支持 CONNECT
            if (data.length < 7 || data[1] !== 0x01) {
                console.error("proxyServer:SOCKS5Handel.只支持CONNECT:", error);
                socket.destroy();
                return;
            }

            try {
                // ADDRESS_TYPE 目标服务器地址类型
                let addrtype = data[3];

                /**
                 * 0x03 域名地址(没有打错,就是没有0x02)
                 * 域名地址的第1个字节为域名长度,剩下字节为域名名称字节数组
                 */
                if (addrtype === 3) hostLen = data[4];
                else if (addrtype !== 1 && addrtype !== 4) {
                    socket.destroy();
                    return;
                }

                // 最后两位为端口值
                port = data.readUInt16BE(data.length - 2);

                /**
                 * 0x01 IP V4地址
                 * 0x04 IP V6地址 remoteLink = data.slice(3, 19);//IP V6长度为 16 (不支持IP V6)
                 * 0x03 域名地址(没有打错,就是没有0x02),域名地址的第1个字节为域名长度,剩下字节为域名名称字节数组
                 */
                if (addrtype === 1) host = data.slice(3, 7).join(".");
                else if (addrtype === 4) {
                    socket.write(Buffer.from([0x05, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,]));
                    return;
                } else host = data.slice(5, 5 + hostLen).toString("binary");

                // 连接
                connectServer(socket, () => socket.write(Buffer.from([0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,])), {
                    port,
                    host,
                    timeout: 30 * 60 * 1000,
                    keepAlive: true,
                });
            } catch (error) {
                console.error("proxyServer:SOCKS5Handel.解析期间发生异常:", error);
                socket.destroy();
            }
        });
    });
};

/**
 * HTTP 处理器
 * @param { net.Socket } socket
 * @param { Buffer } buffer
 */
const HTTPHandel = (socket, buffer) => {
    try {
        let connect = buffer.toString().match(/CONNECT (.+?) HTTP/);
        // 主机 端口
        let host, port, callback;
        if (connect) {
            [host, port] = connect[1].split(":");
            callback = () => socket.write("HTTP/1.1 200 OK\r\n\r\n");
        } else {
            if (!!buffer.toString().match(/Host: (.*):(\d+)/i)) {
                [, host, port] = buffer.toString().match(/Host: (.*):(\d+)/i);
            } else if (!!buffer.toString().match(/Host: (.*)/i)) {
                [, host] = buffer.toString().match(/Host: (.*)/i);
            }
            if (!port) port = 80;
            callback = (server) => server.write(buffer);
        }

        // 连接
        connectServer(socket, callback, {
            port,
            host,
            timeout: 30 * 60 * 1000,
            keepAlive: true,
        });
    } catch (error) {
        console.error("proxyServer:HTTPHandel.解析期间发生异常:", error);
        socket.destroy();
    }
};

/**
 * 实现代理服务链接
 * @param { net.Socket } socket
 * @param { function } callback
 * @param { net.NetConnectOpts } options
 */
const connectServer = (socket, callback = (server = net.Socket) => { }, options) => {
    console.log(`proxyServer.connectServer<${options.host}:${options.port}>`);
    // 创建到目标服务器的连接
    let server = net.connect(options);
    // 连接回调
    callback(server);
    // 将数据从客户端转发到目标服务器
    socket.pipe(server);
    // 将数据从目标服务器转发回客户端
    server.pipe(socket);

    server.on("error", (error) => {
        console.error("proxyServer.connectServer.error:", options, error);
        socket.destroy();
        server.destroy();
    });
};

/**
 * 创建代理服务
 */
let proxyServer = net.createServer((socket) => {
    // 设置超时时间
    socket.setTimeout(30 * 60 * 1000);

    /**
     * 获取首次代理请求的数据
     */
    socket.once("data", (buffer) => {
        if (buffer[0] === 0x05) SOCKS5Handel(socket, buffer);
        else HTTPHandel(socket, buffer);
    });

    /**
     * 监听请求异常
     */
    socket.on("error", (error) => {
        console.error("proxyServer:socket.on.error:", error);
        socket.destroy();
    });
});

/**
 * 启动代理
 */
proxyServer.listen(8080, () => console.log(`%cProxy run success: port is 8080.`, "color:#02E700"));
文章作者: CaptainTwo
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 CaptainTwo
笔记 NodeJs
喜欢就支持一下吧