UNPKG

kaven-utils

Version:

Utils for Node.js.

98 lines (97 loc) 3.69 kB
/******************************************************************** * @author: Kaven * @email: kaven@wuwenkai.com * @website: http://blog.kaven.xyz * @file: [Kaven-Utils] /src/net/proxy/TlsProxyServer.ts * @create: 2022-04-20 13:48:35.117 * @modify: 2024-11-01 10:48:07.309 * @version: 5.4.5 * @times: 34 * @lines: 122 * @copyright: Copyright © 2022-2024 Kaven. All Rights Reserved. * @description: [description] * @license: [license] ********************************************************************/ import { Strings_CR, Strings_CR_LF } from "kaven-basic"; import { createConnection } from "node:net"; import { createServer } from "node:tls"; import { InternalLogger } from "../../KavenUtility.Internal.js"; export class TlsProxyServer { server; EnableKeyLog = false; Authenticate; constructor(options) { this.server = createServer(options, socket => { this.onConnected(socket); }); this.server.on("keylog", (line, tlsSocket) => { if (this.EnableKeyLog) { InternalLogger()?.Info(`[${tlsSocket.remoteAddress}] ${line.toString()}`); } }); this.server.on("tlsClientError", (err, tlsSocket) => { InternalLogger()?.Error(`[${tlsSocket.remoteAddress}] ${err.toString()}`); }); } Start(port, host) { if (host === undefined) { host = "0.0.0.0"; } this.server.listen(port, host, () => { InternalLogger()?.Info(`Server bound to ${host}:${port}`); }); } Stop() { this.server.close(err => { InternalLogger()?.Info(`Server closed: ${err}`); }); } onConnected(socket) { const remote = `${socket.remoteAddress}:${socket.remotePort}`; const local = `${socket.localAddress}:${socket.localPort}`; const remoteToLocal = `[${remote} -> ${local}]`; const logPrefix = `[TlsProxyServer]${remoteToLocal}`; const log = (...args) => { InternalLogger()?.Info(logPrefix, ...args); }; const logError = (...args) => { InternalLogger()?.Error(logPrefix, ...args); }; if (this.Authenticate) { if (!socket.remoteAddress || !this.Authenticate(socket.remoteAddress)) { log(`Invalid client connected, authorized: ${socket.authorized}`); socket.destroy(); return; } } log(`New client connected, authorized: ${socket.authorized}`); socket.once("data", (data) => { const line = data.toString().TrimEnd(Strings_CR_LF); log(`Try connect to: ${line}`); const [host, port] = line.split(":"); let isConnected = false; const destSocket = createConnection(Number(port), host, () => { isConnected = true; log(`Successfully connected to ${line}`); socket.write("OK" + Strings_CR_LF); socket.pipe(destSocket); destSocket.pipe(socket); }); destSocket.on("error", err => { if (!isConnected) { socket.write(`${err}`.ReplaceAll(Strings_CR_LF, Strings_CR) + Strings_CR_LF); } logError("destSocket error", err); }); destSocket.once("close", () => { socket.end(); }); socket.once("close", () => { destSocket.end(); }); }); socket.on("error", (err) => { logError(err); }); } }