UNPKG

kaven-utils

Version:

Utils for Node.js.

98 lines (97 loc) 3.63 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: 2025-10-14 22:58:04.829 * @version: 6.1.0 * @times: 40 * @lines: 122 * @copyright: Copyright © 2022-2025 Kaven. All Rights Reserved. * @description: [description] * @license: [license] ********************************************************************/ import { ReplaceAll, Strings_CR, Strings_CR_LF, TrimEnd } from "kaven-basic"; import { createConnection } from "node:net"; import { createServer } from "node:tls"; export class TlsProxyServer { server; EnableKeyLog = false; Authenticate; Logger; constructor(options) { this.server = createServer(options, socket => { this.onConnected(socket); }); this.server.on("keylog", (line, tlsSocket) => { if (this.EnableKeyLog) { this.Logger?.Info(`[${tlsSocket.remoteAddress}] ${line.toString()}`); } }); this.server.on("tlsClientError", (err, tlsSocket) => { this.Logger?.Error(`[${tlsSocket.remoteAddress}] ${err.toString()}`); }); } Start(port, host) { if (host === undefined) { host = "0.0.0.0"; } this.server.listen(port, host, () => { this.Logger?.Info(`Server bound to ${host}:${port}`); }); } Stop() { this.server.close(err => { this.Logger?.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 = (data) => { this.Logger?.Info(`${logPrefix}${data}`); }; const logError = (data) => { this.Logger?.Error(`${logPrefix}${data}`); }; 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 = TrimEnd(data.toString(), 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(ReplaceAll(`${err}`, 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); }); } }