UNPKG

shadowsocks-manager

Version:

A shadowsocks manager tool for multi user and traffic control.

145 lines (123 loc) 3.93 kB
"use strict"; const log4js = require('log4js'); const logger = log4js.getLogger('system'); const knex = appRequire('init/knex').knex; const crypto = require('crypto'); const path = require('path'); const config = appRequire('services/config').all(); const password = config.manager.password; const host = config.manager.address.split(':')[0]; const port = +config.manager.address.split(':')[1]; const shadowsocks = appRequire('services/shadowsocks'); const net = require('net'); const receiveData = (receive, data) => { receive.data = Buffer.concat([receive.data, data]); checkData(receive); }; const checkCode = (data, password, code) => { const time = Number.parseInt(data.slice(0, 6).toString('hex'), 16); if (Math.abs(Date.now() - time) > 10 * 60 * 1000) { return false; } const command = data.slice(6).toString(); const md5 = crypto.createHash('md5').update(time + command + password).digest('hex'); return md5.substr(0, 8) === code.toString('hex'); }; const receiveCommand = async (data, code) => { try { const time = Number.parseInt(data.slice(0, 6).toString('hex'), 16); await knex('command').whereBetween('time', [0, Date.now() - 10 * 60 * 1000]).del(); await knex('command').insert({ code: code.toString('hex'), time }); const message = JSON.parse(data.slice(6).toString()); logger.info(message); if (message.command === 'add') { const port = +message.port; const password = message.password; return shadowsocks.addAccount(port, password); } else if (message.command === 'del') { const port = +message.port; return shadowsocks.removeAccount(port); } else if (message.command === 'list') { return shadowsocks.listAccount(); } else if (message.command === 'pwd') { const port = +message.port; const password = message.password; return shadowsocks.changePassword(port, password); } else if (message.command === 'flow') { const options = message.options; return shadowsocks.getFlow(options); } else if (message.command === 'version') { return shadowsocks.getVersion(); } else if (message.command === 'ip') { return shadowsocks.getClientIp(message.port); } else { return Promise.reject(); } } catch (err) { throw err; } }; const pack = data => { const message = JSON.stringify(data); const dataBuffer = Buffer.from(message); const length = dataBuffer.length; const lengthBuffer = Buffer.from(('0000' + length.toString(16)).substr(-4), 'hex'); const pack = Buffer.concat([lengthBuffer, dataBuffer]); return pack; }; const checkData = receive => { const buffer = receive.data; let length = 0; let data; let code; if (buffer.length < 2) { return; } length = buffer[0] * 256 + buffer[1]; if (buffer.length >= length + 2) { data = buffer.slice(2, length - 2); code = buffer.slice(length - 2); // receive.data = buffer.slice(length + 2, buffer.length); if (!checkCode(data, password, code)) { receive.socket.end(); // receive.socket.close(); return; } receiveCommand(data, code).then(s => { receive.socket.end(pack({ code: 0, data: s })); // receive.socket.close(); }, e => { logger.error(e); receive.socket.end(pack({ code: 1 })); // receive.socket.close(); }); if (buffer.length > length + 2) { checkData(receive); } } }; const server = net.createServer(socket => { const receive = { data: Buffer.from(''), socket: socket }; socket.on('data', data => { receiveData(receive, data); }); socket.on('end', () => {// console.log('end'); }); socket.on('close', () => {// console.log('close'); }); }).on('error', err => { logger.error(`socket error: `, err); }); server.listen({ port, host }, () => { logger.info(`server listen on ${host}:${port}`); });