Skip to content

Commit

Permalink
Refactor huge try-catch by buffer length checking.
Browse files Browse the repository at this point in the history
  • Loading branch information
mrluanma committed Mar 6, 2024
1 parent 8f19e8a commit c1fc88a
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 172 deletions.
212 changes: 110 additions & 102 deletions local.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ var server = net.createServer(function (connection) {
});
const encryptor = new Encryptor(KEY, METHOD);
let stage = 0;
let headerLength = 0;
let cachedPieces = [];
let addrLen = 0;
let ws = null;
let remoteAddr = null;
let remotePort = null;
Expand All @@ -115,126 +113,136 @@ var server = net.createServer(function (connection) {
return;
}
if (stage === 1) {
try {
// +----+-----+-------+------+----------+----------+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
// +----+-----+-------+------+----------+----------+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+

//cmd and addrtype
const cmd = data[1];
const addrtype = data[3];
if (cmd !== 1) {
console.log('unsupported cmd:', cmd);
const reply = Buffer.from('\u0005\u0007\u0000\u0001', 'binary');
connection.end(reply);
let headerLength = 5;

if (data.length < headerLength) {
connection.end();
return;
}
const cmd = data[1];
const addrtype = data[3];
if (cmd !== 1) {
console.log('unsupported cmd:', cmd);
const reply = Buffer.from('\u0005\u0007\u0000\u0001', 'binary');
connection.end(reply);
return;
}
if (![1, 3, 4].includes(addrtype)) {
console.log('unsupported addrtype:', addrtype);
connection.end();
return;
}
addrToSend = data.slice(3, 4).toString('binary');

// read address and port
if (addrtype === 1) {
// ipv4
headerLength = 4 + 4 + 2;
if (data.length < headerLength) {
connection.end();
return;
}
if (addrtype === 3) {
addrLen = data[4];
} else if (addrtype !== 1 && addrtype !== 4) {
console.log('unsupported addrtype:', addrtype);
remoteAddr = inetNtoa(4, data.slice(4, 8));
addrToSend += data.slice(4, 10).toString('binary');
remotePort = data.readUInt16BE(8);
} else if (addrtype === 4) {
// ipv6
headerLength = 4 + 16 + 2;
if (data.length < headerLength) {
connection.end();
return;
}
addrToSend = data.slice(3, 4).toString('binary');
// read address and port
if (addrtype === 1) {
// ipv4
remoteAddr = inetNtoa(4, data.slice(4, 8));
addrToSend += data.slice(4, 10).toString('binary');
remotePort = data.readUInt16BE(8);
headerLength = 10;
} else if (addrtype === 4) {
// ipv6
remoteAddr = inetNtoa(6, data.slice(4, 20));
addrToSend += data.slice(4, 22).toString('binary');
remotePort = data.readUInt16BE(20);
headerLength = 22;
} else {
remoteAddr = data.slice(5, 5 + addrLen).toString('binary');
addrToSend += data.slice(4, 5 + addrLen + 2).toString('binary');
remotePort = data.readUInt16BE(5 + addrLen);
headerLength = 5 + addrLen + 2;
remoteAddr = inetNtoa(6, data.slice(4, 20));
addrToSend += data.slice(4, 22).toString('binary');
remotePort = data.readUInt16BE(20);
} else {
const addrLen = data[4];
headerLength = 5 + addrLen + 2;
if (data.length < headerLength) {
connection.end();
return;
}
let buf = Buffer.alloc(10);
buf.write('\u0005\u0000\u0000\u0001', 0, 4, 'binary');
buf.write('\u0000\u0000\u0000\u0000', 4, 4, 'binary');
buf.writeUInt16BE(remotePort, 8);
connection.write(buf);
// connect to remote server
// ws = new WebSocket aServer, protocol: "binary"
remoteAddr = data.slice(5, 5 + addrLen).toString('binary');
addrToSend += data.slice(4, 5 + addrLen + 2).toString('binary');
remotePort = data.readUInt16BE(5 + addrLen);
}
let buf = Buffer.alloc(10);
buf.write('\u0005\u0000\u0000\u0001', 0, 4, 'binary');
buf.write('\u0000\u0000\u0000\u0000', 4, 4, 'binary');
buf.writeUInt16BE(remotePort, 8);
connection.write(buf);
// connect to remote server
// ws = new WebSocket aServer, protocol: "binary"

if (HTTPPROXY) {
// WebSocket endpoint for the proxy to connect to
const endpoint = aServer;
const parsed = url.parse(endpoint);
//console.log('attempting to connect to WebSocket %j', endpoint);
if (HTTPPROXY) {
// WebSocket endpoint for the proxy to connect to
const endpoint = aServer;
const parsed = url.parse(endpoint);
//console.log('attempting to connect to WebSocket %j', endpoint);

// create an instance of the `HttpsProxyAgent` class with the proxy server information
const opts = url.parse(HTTPPROXY);
// create an instance of the `HttpsProxyAgent` class with the proxy server information
const opts = url.parse(HTTPPROXY);

// IMPORTANT! Set the `secureEndpoint` option to `false` when connecting
// over "ws://", but `true` when connecting over "wss://"
opts.secureEndpoint = parsed.protocol
? parsed.protocol == 'wss:'
: false;
// IMPORTANT! Set the `secureEndpoint` option to `false` when connecting
// over "ws://", but `true` when connecting over "wss://"
opts.secureEndpoint = parsed.protocol
? parsed.protocol == 'wss:'
: false;

const agent = new HttpsProxyAgent(opts);
const agent = new HttpsProxyAgent(opts);

ws = new WebSocket(aServer, {
protocol: 'binary',
agent,
});
} else {
ws = new WebSocket(aServer, {
protocol: 'binary',
});
}

ws.on('open', function () {
console.log(`connecting ${remoteAddr} via ${aServer}`);
let addrToSendBuf = Buffer.from(addrToSend, 'binary');
addrToSendBuf = encryptor.encrypt(addrToSendBuf);
ws.send(addrToSendBuf, {binary: true});
ws.send(encryptor.encrypt(Buffer.concat(cachedPieces)), {
binary: true,
});
cachedPieces = null; // save memory
stage = 5;
ws = new WebSocket(aServer, {
protocol: 'binary',
agent,
});

ws.on('message', function (data, flags) {
data = encryptor.decrypt(data);
connection.write(data);
} else {
ws = new WebSocket(aServer, {
protocol: 'binary',
});
}

ws.on('close', function () {
console.log('remote disconnected');
connection.destroy();
ws.on('open', function () {
console.log(`connecting ${remoteAddr} via ${aServer}`);
let addrToSendBuf = Buffer.from(addrToSend, 'binary');
addrToSendBuf = encryptor.encrypt(addrToSendBuf);
ws.send(addrToSendBuf, {binary: true});
ws.send(encryptor.encrypt(Buffer.concat(cachedPieces)), {
binary: true,
});
cachedPieces = null; // save memory
stage = 5;
});

ws.on('error', function (e) {
console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`);
connection.destroy();
server.getConnections(function (err, count) {
console.log('concurrent connections:', count);
});
});
ws.on('message', function (data, flags) {
data = encryptor.decrypt(data);
connection.write(data);
});

if (data.length > headerLength) {
let buf = Buffer.alloc(data.length - headerLength);
data.copy(buf, 0, headerLength);
cachedPieces.push(buf);
}
stage = 4;
} catch (error) {
// may encounter index out of range
const e = error;
console.log(e);
ws.on('close', function () {
console.log('remote disconnected');
connection.destroy();
});

ws.on('error', function (e) {
console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`);
connection.destroy();
server.getConnections(function (err, count) {
console.log('concurrent connections:', count);
});
});

if (data.length > headerLength) {
let buf = Buffer.alloc(data.length - headerLength);
data.copy(buf, 0, headerLength);
cachedPieces.push(buf);
}
stage = 4;
} else if (stage === 4) {
// remote server not connected
// cache received buffers
Expand Down
Loading

0 comments on commit c1fc88a

Please sign in to comment.