UNPKG

@cliz/inlets

Version:
98 lines (97 loc) 4.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createTCPMonitor = void 0; const doreamon_1 = require("@zodash/doreamon"); const hmac = require("@zodash/hmac"); const net = require("net"); const constants_1 = require("../../common/constants"); const debug = require('debug')('inlets:monitor:tcp'); const logger = doreamon_1.default.logger.getLogger('monitor:tcp '); function createTCPMonitor(ctx, options) { const emitter = new doreamon_1.default.event.Event(); const server = createTCPServer(options.domain, options.port, (server) => { }, (socket) => { }, async (id) => { const container = ctx.container.get(id); if (!container) { return null; } return await options.token(container.authType, container.clientId); }, (containerId, requestId, targetSocket, server) => { logger.info(`[tunnel:client] connected (container id: ${containerId}, request id: ${requestId})`); ctx.container.connectRequest(containerId, requestId, targetSocket); }); return server; } exports.createTCPMonitor = createTCPMonitor; function createTCPServer(domain, port, onServerCreate, onSocketConnect, onGetToken, onAuthenticate) { const server = net.createServer((socket) => { let requestId = null; logger.info(`[tunnel:client][connect][1] ip ${socket.remoteAddress}`); socket.on('error', error => { logger.error(`socket error:`, error); }); socket.on('end', () => { logger.info(`[tunnel:client][close] request id: ${requestId}, ip ${socket.remoteAddress}`); }); const s = socket; socket.on('data', async (data) => { if (s.isAuthenticated) return; const flag = data.slice(0, constants_1.TUNNEL_TCP_FLAG.length).toString(); if (flag !== constants_1.TUNNEL_TCP_FLAG) { logger.error(`unknown flag: ${flag}, should be ${constants_1.TUNNEL_TCP_FLAG}`); socket.write(`${constants_1.TUNNEL_TCP_FLAG}401 unauthorized`); socket.destroy(); return; } const UID_LENGTH = 36; const REQUEST_ID_LENGTH = 36; const SIGNATURE_LENGTH = 64; const ID_END = constants_1.TUNNEL_TCP_FLAG.length + UID_LENGTH; const REQUEST_ID_END = ID_END + REQUEST_ID_LENGTH; const SIGN_END = REQUEST_ID_END + SIGNATURE_LENGTH; const _id = data.slice(constants_1.TUNNEL_TCP_FLAG.length, ID_END).toString(); const _request_id = data.slice(ID_END, REQUEST_ID_END).toString(); const _sign = data.slice(REQUEST_ID_END, SIGN_END).toString(); debug(`id: ${_id}, request_id: ${_request_id}, sign: ${_sign}`); let signedSecret; try { const res = await onGetToken(_id); signedSecret = res.token; if (!signedSecret) { logger.error(`invalid client(id:${_id}): ${_sign}`); socket.write(`${constants_1.TUNNEL_TCP_FLAG}403 invlid client`); socket.destroy(); return; } } catch (error) { logger.error(`invalid client(id:${_id}): ${_sign}:`, error); socket.write(`${constants_1.TUNNEL_TCP_FLAG}404 invlid client`); socket.destroy(); return; } const expectedSign = hmac.hmacSHA256(_id, signedSecret); if (_sign !== expectedSign) { logger.error(`invalid signature(id:${_id}): ${_sign}, expected: ${expectedSign}`); socket.write(`${constants_1.TUNNEL_TCP_FLAG}402 invlid signature`); socket.destroy(); return; } if (!requestId) { requestId = _request_id; socket.requestId = requestId; logger.info(`[tunnel:client][connect][2] request id: ${requestId}, ip ${socket.remoteAddress}`); } s.isAuthenticated = true; socket.write(constants_1.TUNNEL_TCP_OK_FLAG); onAuthenticate(_id, _request_id, socket, server); }); onSocketConnect(socket); }); server.listen(port, '0.0.0.0', () => { onServerCreate(server); }); return server; }