nodejs搭建简单的代理服务
仅支持socks5
和http
/**
* 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) return socket.destroy();
// 最后两位为端口值
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) return socket.write(Buffer.from([0x05, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
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();
}
};
/**
* HTTP 处理器
* @param { net.Socket } socket
* @param { function } callback
* @param { net.NetConnectOpts } options
*/
const connectServer = (socket, callback = (server = net.Socket) => { }, options) => {
/**
* 域名IP拦截
*/
if (!proxySet.has(options.host)) {
console.warn(`proxyServer.connectServer:白名单拦截<${options.host}:${options.port}>`);
socket.destroy();
return;
}
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(3030, () => console.log(`Proxy run success: port is 3030.`));
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
CaptainTwo!
喜欢就支持一下吧