UNPKG

allproxy

Version:

AllProxy: MITM HTTP Debugging Tool.

201 lines 10.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const net_1 = __importDefault(require("net")); const tls_1 = __importDefault(require("tls")); const Global_1 = __importDefault(require("./Global")); const SocketIoMessage_1 = __importDefault(require("./SocketIoMessage")); const HexFormatter_1 = __importDefault(require("./formatters/HexFormatter")); const SqlFormatter_1 = __importDefault(require("./formatters/SqlFormatter")); const MongoFormatter_1 = __importDefault(require("./formatters/MongoFormatter")); const RedisFormatter_1 = __importDefault(require("./formatters/RedisFormatter")); const Message_1 = require("../../common/Message"); const GenerateCertKey_1 = __importDefault(require("./GenerateCertKey")); const ConsoleLog_1 = __importDefault(require("./ConsoleLog")); const MAX_URL = 1024; class TcpProxy { constructor(proxyConfig) { this.startProxy(proxyConfig); } static destructor(proxyConfig) { if (proxyConfig._server) proxyConfig._server.close(); } /** * Star proxy * @param proxyConfig */ startProxy(proxyConfig) { return __awaiter(this, void 0, void 0, function* () { const sourcePort = proxyConfig.path; const targetHost = proxyConfig.hostname; const targetPort = proxyConfig.port; let server; if (proxyConfig.isSecure) { const tlsOptions = yield (0, GenerateCertKey_1.default)(proxyConfig.hostname); server = tls_1.default.createServer(tlsOptions, onConnect); } else { server = net_1.default.createServer(onConnect); } let retries = 0; let wait = 1000; server.on('error', (err) => { if (++retries < 10) { setTimeout(() => listen(server), wait *= 2); } else { console.error('TcpProxy server error', err); } }); listen(server); function listen(server) { server.listen(sourcePort, function () { ConsoleLog_1.default.info('Listening on port ' + sourcePort + ' for target host ' + targetHost + ':' + targetPort); }); proxyConfig._server = server; } // Create server (source) socket function onConnect(sourceSocket) { const requests = []; // Connect to target host let targetSocket; if (!proxyConfig.isSecure) { targetSocket = net_1.default.connect(targetPort, targetHost, () => { // ConsoleLog.info('connected to target'); }); } else { targetSocket = tls_1.default.connect(targetPort, targetHost, {}, () => { // ConsoleLog.info('connected to target'); }); } sourceSocket.on('error', (err) => { ConsoleLog_1.default.debug(`TcpProxy client error ${sourcePort}: ${err}`); }); targetSocket.on('error', (err) => { ConsoleLog_1.default.debug(`TcpProxy server error ${sourcePort}: ${err}`); }); // Handle data from source (client) sourceSocket.on('data', (data) => __awaiter(this, void 0, void 0, function* () { const request = { data, startTime: Date.now(), sequenceNumber: Global_1.default.nextSequenceNumber(), }; requests.push(request); targetSocket.write(data); yield processData(request, null); })); // Handle data from target (e.g., database) targetSocket.on('data', (data) => __awaiter(this, void 0, void 0, function* () { sourceSocket.write(data); if (requests.length > 0) { const request = requests.pop(); yield processData(request, data); } })); // Handle source socket closed sourceSocket.on('close', () => { targetSocket.end(); }); // Handle target socket closed targetSocket.on('close', () => { sourceSocket.end(); }); function processData(request, response) { return __awaiter(this, void 0, void 0, function* () { // eslint-disable-next-line no-async-promise-executor return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { let requestString = ''; let responseString = ''; let url = ''; let status = 0; let noResponseRequired = false; switch (proxyConfig.protocol) { case 'mysql:': { const sqlFormatter = new SqlFormatter_1.default(request.data, response); requestString = sqlFormatter.getQuery(); responseString = sqlFormatter.getResults(); status = sqlFormatter.getErrorCode(); for (const line of requestString.split('\n')) { if (line.indexOf('/*') !== -1) continue; url += line + ' '; if (url.length >= 64) break; } noResponseRequired = sqlFormatter.getCommand() === 'Close'; break; } case 'mongo:': { const mongoFormatter = new MongoFormatter_1.default(request.data, response); requestString = mongoFormatter.getRequest(); responseString = mongoFormatter.getResponse(); url = requestString.split('\n')[0]; break; } case 'redis:': { const redisFormatter = new RedisFormatter_1.default(request.data, response); requestString = redisFormatter.getRequest(); responseString = redisFormatter.getResponse(); for (const line of requestString.split('\n')) { url += line + ' '; if (url.length >= 64) break; } break; } default: requestString = HexFormatter_1.default.format(request.data); responseString = response ? '\n' + HexFormatter_1.default.format(response) + '\n' : Message_1.NO_RESPONSE; if (requestString.length > MAX_URL) { url = requestString.substring(0, MAX_URL); } else { url = requestString; } break; } if (requestString.length > 0) { const endpoint = ''; const message = yield SocketIoMessage_1.default.buildRequest(request.startTime, request.sequenceNumber, {}, // headers '', // method url, // url endpoint, // endpoint { allproxy_inner_body: requestString }, // req body sourceSocket.remoteAddress, // clientIp targetHost + ':' + targetPort, // serverHost '', // path Date.now() - request.startTime); SocketIoMessage_1.default.appendResponse(message, {}, responseString, status, Date.now() - request.startTime); message.protocol = proxyConfig.protocol; Global_1.default.socketIoManager.emitMessageToBrowser(response === null ? responseString === Message_1.NO_RESPONSE && noResponseRequired === false ? Message_1.MessageType.REQUEST : Message_1.MessageType.REQUEST_AND_RESPONSE : Message_1.MessageType.RESPONSE, message, proxyConfig); } resolve(0); })); }); } } }); } } exports.default = TcpProxy; //# sourceMappingURL=TcpProxy.js.map