Skip to content

Instantly share code, notes, and snippets.

@ntzyz
Created October 25, 2017 11:32
Show Gist options
  • Save ntzyz/38f31c979f4fce979e56a349f536b8b2 to your computer and use it in GitHub Desktop.
Save ntzyz/38f31c979f4fce979e56a349f536b8b2 to your computer and use it in GitHub Desktop.
const net = require('net');
const TYPE = {
IPV4: 0x01,
DOMAIN: 0x03,
IPV6: 0x04,
};
const server = net.createServer(socket => {
// 准备接受客户端的握手
socket.on('data', handshake);
function handshake (packet) {
// 握手只有连接建立后需要完成,因此握手函数被调用之后,就不再需要了
socket.removeListener('data', handshake);
// SOCKS 5
if (packet[0] !== 5) {
console.log('Version error.');
}
// 准备接受客户端的请求
socket.on('data', request);
// 不需要加密,向客户端发送不需要更多认证信息
socket.write(new Buffer([0x05, 0x00]));
}
function request (packet) {
// 请求也只有一次,道理同上
socket.removeListener('data', request);
// 请求报文内容
const payload = {
version: packet[0],
command: packet[1],
reversed: packet[2],
type: packet[3],
address: null,
port: null,
}
let offset = 4;
// 解析地址(IP or Domain)
switch (payload.type) {
case TYPE.IPV4:
payload.address = `${packet[offset]}.${packet[offset + 1]}.${packet[offset + 2]}.${packet[offset + 3]}`;
payload.port = packet.readUInt16BE(offset + 4);
break;
case TYPE.DOMAIN:
payload.address = packet.slice(offset + 1, packet[offset] + offset + 1).toString();
payload.port = packet.readUInt16BE(packet[offset] + offset + 1);
break;
default:
upstreamOnError();
return;
}
// 刷个屏
console.log(`Connecting to ${payload.address}:${payload.port}`);
// 上游服务器建立失败,比如 Timeout 或者 reset 这种,直接向客户端发送 SOCKS server failure
function upstreamOnError () {
const response = new Buffer(packet.length);
packet.copy(response);
response[1] = 0x01; // general SOCKS server failure
socket.write(response);
}
// 成功建立连接,向客户端发送成功信息,然后准备交换数据
function upstreamOnConnect () {
const response = new Buffer(packet.length);
packet.copy(response);
response[1] = 0x00;
socket.write(response);
// 这里大概就是一个管道,把 upstream 的所有 output 传给 客户端,反之亦然
upstream.on('data', data => socket.writable ? socket.write(data) : closeConnection());
socket.on('data', data => upstream.writable ? upstream.write(data) : closeConnection());
// 任意一方终止连接之后,关闭双方的连接
upstream.on('end', () => closeConnection());
socket.on('end', () => closeConnection());
}
function closeConnection () {
upstream.end();
socket.end();
}
const upstream = net.createConnection(payload.port, payload.address);
upstream.on('connect', () => upstreamOnConnect())
upstream.on('error', () => upstreamOnError());
socket.on('error', error => {
console.log(`${payload.address}:${payload.port} -> ERROR: ${error.message}`);
closeConnection();
});
}
});
server.listen(1086);
setInterval(() => { console.log(`RAM Used: ${process.memoryUsage().heapUsed / 1048576}MB`) }, 1000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment