allproxy
Version:
AllProxy: MITM HTTP Debugging Tool.
201 lines • 10.7 kB
JavaScript
;
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