Created
October 25, 2017 11:32
-
-
Save ntzyz/38f31c979f4fce979e56a349f536b8b2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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