内网专用轻量级 SOCKS5 代理实现(nodejs )
安全警告
⚠️ 本实现专为内网测试场景设计,严禁直接用于公网环境。使用时必须注意:
强制配置IP白名单,防止未授权访问
生产环境应使用专业代理软件(如Squid、Dante)
协议交互流程(SOCKS5)
阶段
客户端行为
服务端响应
版本协商 (Handshake)
发送支持的认证方式列表
返回选择的认证方式
认证协商 (Auth)
根据认证方式发送凭证(本实现跳过)
返回认证结果(本实现始终无认证)
请求处理 (Request)
发送目标地址和端口
建立连接并转发数据
核心实现代码(Node.js)
支持白名单配置
严格的协议版本校验
完善的错误响应机制
完整支持 IPv4/IPv6/域名解析
符合 RFC 1928 规范的状态码返回
const net = require('net');
const dns = require('dns');
// 配置参数(建议改为环境变量)
const CONFIG = {
PORT: 6532, // SOCKS5 代理端口
ALLOWED_IPS: new Set(['127.0.0.1', '192.168.1.100']), // 允许访问的IP
PROTOCOL_VERSION: 0x05
};
// SOCKS5 响应码生成器
const RESPONSE = {
SUCCESS: Buffer.from([0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0]),
AUTH_FAIL: Buffer.from([0x05, 0xFF]),
CONNECT_REFUSED: Buffer.from([0x05, 0x05, 0x00, 0x01, 0, 0, 0, 0, 0, 0]),
HOST_UNREACHABLE: Buffer.from([0x05, 0x04, 0x00, 0x01, 0, 0, 0, 0, 0, 0])
};
const server = net.createServer((clientSocket) => {
// 客户端IP验证(兼容IPv4/IPv6)
const remoteAddress = clientSocket.remoteAddress.replace(/^::ffff:/, '');
if (!CONFIG.ALLOWED_IPS.has(remoteAddress)) {
console.warn(`[SECURITY] 非法访问尝试来自 ${remoteAddress}`);
clientSocket.destroy();
return;
}
// 连接目标服务器
const connectTarget = (ip, port) => {
const remoteSocket = net.connect(port, ip, () => {
clientSocket.write(RESPONSE.SUCCESS);
clientSocket.pipe(remoteSocket).pipe(clientSocket); // 双向数据转发
});
remoteSocket.on('error', () => clientSocket.end(RESPONSE.CONNECT_REFUSED));
};
// 协议握手处理
clientSocket.once('data', data => {
// 校验协议版本
if (data[0] !== CONFIG.PROTOCOL_VERSION) {
clientSocket.end();
return;
}
// 认证方式协商(仅支持无认证)
clientSocket.write(Buffer.from([0x05, 0x00]));
// 请求处理
clientSocket.once('data', req => {
// 命令类型校验(仅支持CONNECT)
if (req[0] !== 0x05 || req[1] !== 0x01) {
clientSocket.end(RESPONSE.AUTH_FAIL);
return;
}
// 地址类型解析
const [atyp, offset] = [req[3], 4];
try {
let addr, port;
switch (atyp) {
case 0x01: // IPv4
addr = req.slice(offset, offset + 4).join('.');
port = req.readUInt16BE(offset + 4);
break;
case 0x03: // 域名
const len = req[offset];
addr = req.slice(offset + 1, offset + 1 + len).toString();
port = req.readUInt16BE(offset + 1 + len);
dns.lookup(addr, (err, ip) => {
err ? clientSocket.end(RESPONSE.HOST_UNREACHABLE) : connectTarget(ip, port);
});
return;
case 0x04: // IPv6
addr = req.slice(offset, offset + 16);
port = req.readUInt16BE(offset + 16);
break;
default:
throw new Error('Unsupported address type');
}
connectTarget(addr, port);
} catch (e) {
clientSocket.end(RESPONSE.HOST_UNREACHABLE);
}
});
});
});
server.listen(CONFIG.PORT, () => {
console.log(`SOCKS5代理已启动,监听端口:${CONFIG.PORT}\n允许访问IP:${[...CONFIG.ALLOWED_IPS].join(', ')}`);
});
使用方法
node socks5.js