UNPKG

@mesh-tech/mesh-cli

Version:

CLI for Mesh platform development utilities

75 lines (74 loc) 2.63 kB
import * as net from "node:net"; export function ipv4ToBytes(ip) { const parts = ip.split("."); if (parts.length !== 4) throw new Error(`not an IPv4 address: ${ip}`); return parts.map((p) => { const n = Number(p); if (!Number.isInteger(n) || n < 0 || n > 255 || !/^\d+$/.test(p)) { throw new Error(`not an IPv4 address: ${ip}`); } return n; }); } export function socks5ConnectRequest(ip, port) { return Buffer.from([0x05, 0x01, 0x00, 0x01, ...ipv4ToBytes(ip), (port >> 8) & 0xff, port & 0xff]); } const SOCKS_REPLY_MESSAGES = { 0: "succeeded", 1: "general SOCKS server failure", 2: "connection not allowed by ruleset", 3: "network unreachable", 4: "host unreachable", 5: "connection refused", 6: "TTL expired", 7: "command not supported", 8: "address type not supported", }; export function interpretSocksReply(code) { return { ok: code === 0, message: SOCKS_REPLY_MESSAGES[code] ?? `unknown SOCKS reply ${code}` }; } export function createForwarder(opts) { const socksHost = opts.socksHost ?? "127.0.0.1"; const server = net.createServer((client) => { const up = net.connect(opts.socksPort, socksHost); let buf = Buffer.alloc(0); let phase = 0; up.on("connect", () => up.write(Buffer.from([0x05, 0x01, 0x00]))); up.on("data", (d) => { if (phase === 2) return; buf = Buffer.concat([buf, d]); if (phase === 0) { if (buf.length < 2) return; buf = buf.subarray(2); phase = 1; up.write(socks5ConnectRequest(opts.targetIp, opts.targetPort)); } if (phase === 1) { if (buf.length < 10) return; const reply = interpretSocksReply(buf[1]); const leftover = buf.subarray(10); phase = 2; if (!reply.ok) { up.destroy(); client.destroy(); return; } if (leftover.length) client.write(leftover); client.pipe(up); up.pipe(client); } }); client.on("error", () => up.destroy()); up.on("error", () => client.destroy()); client.on("close", () => up.destroy()); up.on("close", () => client.destroy()); }); server.on("error", (err) => opts.onError?.(err)); server.listen(opts.listenPort, "127.0.0.1"); return server; }