green-tunnel 2.0.2 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/dist/core/config.d.ts +13 -0
  2. package/dist/core/config.d.ts.map +1 -0
  3. package/dist/core/config.js +87 -0
  4. package/dist/core/config.js.map +1 -0
  5. package/dist/core/dns/decode.d.ts +12 -0
  6. package/dist/core/dns/decode.d.ts.map +1 -0
  7. package/dist/core/dns/decode.js +23 -0
  8. package/dist/core/dns/decode.js.map +1 -0
  9. package/dist/core/dns/doh.d.ts +19 -0
  10. package/dist/core/dns/doh.d.ts.map +1 -0
  11. package/dist/core/dns/doh.js +54 -0
  12. package/dist/core/dns/doh.js.map +1 -0
  13. package/dist/core/dns/dot.d.ts +13 -0
  14. package/dist/core/dns/dot.d.ts.map +1 -0
  15. package/dist/core/dns/dot.js +79 -0
  16. package/dist/core/dns/dot.js.map +1 -0
  17. package/dist/core/dns/index.d.ts +8 -0
  18. package/dist/core/dns/index.d.ts.map +1 -0
  19. package/dist/core/dns/index.js +18 -0
  20. package/dist/core/dns/index.js.map +1 -0
  21. package/dist/core/dns/plain.d.ts +17 -0
  22. package/dist/core/dns/plain.d.ts.map +1 -0
  23. package/dist/core/dns/plain.js +45 -0
  24. package/dist/core/dns/plain.js.map +1 -0
  25. package/dist/core/dns/resolver.d.ts +27 -0
  26. package/dist/core/dns/resolver.d.ts.map +1 -0
  27. package/dist/core/dns/resolver.js +81 -0
  28. package/dist/core/dns/resolver.js.map +1 -0
  29. package/dist/core/errors.d.ts +32 -0
  30. package/dist/core/errors.d.ts.map +1 -0
  31. package/dist/core/errors.js +37 -0
  32. package/dist/core/errors.js.map +1 -0
  33. package/dist/core/http/head.d.ts +40 -0
  34. package/dist/core/http/head.d.ts.map +1 -0
  35. package/dist/core/http/head.js +122 -0
  36. package/dist/core/http/head.js.map +1 -0
  37. package/dist/core/http/rewriter.d.ts +20 -0
  38. package/dist/core/http/rewriter.d.ts.map +1 -0
  39. package/dist/core/http/rewriter.js +184 -0
  40. package/dist/core/http/rewriter.js.map +1 -0
  41. package/dist/core/index.d.ts +28 -0
  42. package/dist/core/index.d.ts.map +1 -0
  43. package/dist/core/index.js +27 -0
  44. package/dist/core/index.js.map +1 -0
  45. package/dist/core/logger.d.ts +38 -0
  46. package/dist/core/logger.d.ts.map +1 -0
  47. package/dist/core/logger.js +92 -0
  48. package/dist/core/logger.js.map +1 -0
  49. package/dist/core/net/socket.d.ts +30 -0
  50. package/dist/core/net/socket.d.ts.map +1 -0
  51. package/dist/core/net/socket.js +98 -0
  52. package/dist/core/net/socket.js.map +1 -0
  53. package/dist/core/proxy/connect-tunnel.d.ts +14 -0
  54. package/dist/core/proxy/connect-tunnel.d.ts.map +1 -0
  55. package/dist/core/proxy/connect-tunnel.js +44 -0
  56. package/dist/core/proxy/connect-tunnel.js.map +1 -0
  57. package/dist/core/proxy/connection.d.ts +12 -0
  58. package/dist/core/proxy/connection.d.ts.map +1 -0
  59. package/dist/core/proxy/connection.js +88 -0
  60. package/dist/core/proxy/connection.js.map +1 -0
  61. package/dist/core/proxy/context.d.ts +15 -0
  62. package/dist/core/proxy/context.d.ts.map +1 -0
  63. package/dist/core/proxy/context.js +2 -0
  64. package/dist/core/proxy/context.js.map +1 -0
  65. package/dist/core/proxy/index.d.ts +33 -0
  66. package/dist/core/proxy/index.d.ts.map +1 -0
  67. package/dist/core/proxy/index.js +162 -0
  68. package/dist/core/proxy/index.js.map +1 -0
  69. package/dist/core/proxy/pipe.d.ts +12 -0
  70. package/dist/core/proxy/pipe.d.ts.map +1 -0
  71. package/dist/core/proxy/pipe.js +42 -0
  72. package/dist/core/proxy/pipe.js.map +1 -0
  73. package/dist/core/proxy/plain-tunnel.d.ts +12 -0
  74. package/dist/core/proxy/plain-tunnel.d.ts.map +1 -0
  75. package/dist/core/proxy/plain-tunnel.js +29 -0
  76. package/dist/core/proxy/plain-tunnel.js.map +1 -0
  77. package/dist/core/system-proxy/darwin.d.ts +32 -0
  78. package/dist/core/system-proxy/darwin.d.ts.map +1 -0
  79. package/dist/core/system-proxy/darwin.js +146 -0
  80. package/dist/core/system-proxy/darwin.js.map +1 -0
  81. package/dist/core/system-proxy/driver.d.ts +21 -0
  82. package/dist/core/system-proxy/driver.d.ts.map +1 -0
  83. package/dist/core/system-proxy/driver.js +2 -0
  84. package/dist/core/system-proxy/driver.js.map +1 -0
  85. package/dist/core/system-proxy/exec.d.ts +21 -0
  86. package/dist/core/system-proxy/exec.d.ts.map +1 -0
  87. package/dist/core/system-proxy/exec.js +62 -0
  88. package/dist/core/system-proxy/exec.js.map +1 -0
  89. package/dist/core/system-proxy/index.d.ts +45 -0
  90. package/dist/core/system-proxy/index.d.ts.map +1 -0
  91. package/dist/core/system-proxy/index.js +151 -0
  92. package/dist/core/system-proxy/index.js.map +1 -0
  93. package/dist/core/system-proxy/linux.d.ts +18 -0
  94. package/dist/core/system-proxy/linux.d.ts.map +1 -0
  95. package/dist/core/system-proxy/linux.js +100 -0
  96. package/dist/core/system-proxy/linux.js.map +1 -0
  97. package/dist/core/system-proxy/recovery.d.ts +23 -0
  98. package/dist/core/system-proxy/recovery.d.ts.map +1 -0
  99. package/dist/core/system-proxy/recovery.js +147 -0
  100. package/dist/core/system-proxy/recovery.js.map +1 -0
  101. package/dist/core/system-proxy/windows.d.ts +15 -0
  102. package/dist/core/system-proxy/windows.d.ts.map +1 -0
  103. package/dist/core/system-proxy/windows.js +96 -0
  104. package/dist/core/system-proxy/windows.js.map +1 -0
  105. package/dist/core/tls/fragment.d.ts +28 -0
  106. package/dist/core/tls/fragment.d.ts.map +1 -0
  107. package/dist/core/tls/fragment.js +81 -0
  108. package/dist/core/tls/fragment.js.map +1 -0
  109. package/dist/core/types.d.ts +138 -0
  110. package/dist/core/types.d.ts.map +1 -0
  111. package/dist/core/types.js +7 -0
  112. package/dist/core/types.js.map +1 -0
  113. package/dist/index.d.ts +11 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +11 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/main.d.ts +3 -0
  118. package/dist/main.d.ts.map +1 -0
  119. package/dist/main.js +155 -0
  120. package/dist/main.js.map +1 -0
  121. package/dist/options.d.ts +25 -0
  122. package/dist/options.d.ts.map +1 -0
  123. package/dist/options.js +144 -0
  124. package/dist/options.js.map +1 -0
  125. package/dist/ui.d.ts +17 -0
  126. package/dist/ui.d.ts.map +1 -0
  127. package/dist/ui.js +89 -0
  128. package/dist/ui.js.map +1 -0
  129. package/dist/version.d.ts +3 -0
  130. package/dist/version.d.ts.map +1 -0
  131. package/dist/version.js +13 -0
  132. package/dist/version.js.map +1 -0
  133. package/package.json +31 -30
  134. package/LICENSE +0 -21
  135. package/README.md +0 -172
  136. package/bin/gt.js +0 -170
  137. package/src/config.js +0 -15
  138. package/src/dns/base.js +0 -47
  139. package/src/dns/https.js +0 -30
  140. package/src/dns/tls.js +0 -15
  141. package/src/dns/unencrypted.js +0 -25
  142. package/src/handlers/http.js +0 -65
  143. package/src/handlers/https.js +0 -78
  144. package/src/handlers/request.js +0 -32
  145. package/src/http/request.js +0 -45
  146. package/src/http/response.js +0 -45
  147. package/src/http/utils.js +0 -86
  148. package/src/index.cjs +0 -7
  149. package/src/index.js +0 -4
  150. package/src/logger.js +0 -11
  151. package/src/proxy.js +0 -74
  152. package/src/scripts/windows/wininet-reset-settings.ps1 +0 -14
  153. package/src/utils/analytics.js +0 -59
  154. package/src/utils/buffer.js +0 -35
  155. package/src/utils/socket.js +0 -32
  156. package/src/utils/system-proxy.js +0 -153
@@ -0,0 +1,30 @@
1
+ import net from 'node:net';
2
+ export interface ConnectOptions {
3
+ readonly host: string;
4
+ readonly port: number;
5
+ readonly timeoutMs: number;
6
+ readonly signal?: AbortSignal;
7
+ }
8
+ /**
9
+ * Open a TCP connection, rejecting on error, timeout or abort.
10
+ *
11
+ * v2's `createConnection` only ever resolved: a refused or black-holed upstream
12
+ * left the promise — and the client socket — hanging forever.
13
+ */
14
+ export declare function connect(options: ConnectOptions): Promise<net.Socket>;
15
+ /**
16
+ * Write pieces one at a time, honouring backpressure and an optional pause
17
+ * between them. Ignoring the return value of `write()` — as v2 did — lets a
18
+ * fast peer balloon the kernel-side buffer in memory.
19
+ */
20
+ export declare function writeSequentially(socket: net.Socket, pieces: readonly Buffer[], delayMs?: number): Promise<void>;
21
+ /** Promisified `socket.write` that waits for `drain` when the buffer is full. */
22
+ export declare function write(socket: net.Socket, chunk: Buffer): Promise<void>;
23
+ /** Destroy every socket, ignoring already-destroyed ones. */
24
+ export declare function destroyAll(...sockets: readonly (net.Socket | undefined)[]): void;
25
+ /**
26
+ * Arm an inactivity timeout that destroys the socket. `0` disables it.
27
+ * Returns a disposer.
28
+ */
29
+ export declare function armIdleTimeout(socket: net.Socket, idleTimeoutMs: number): () => void;
30
+ //# sourceMappingURL=socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../../src/core/net/socket.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAI3B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAyC1E;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,GAAG,CAAC,MAAM,EAClB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,OAAO,SAAI,GACV,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,iFAAiF;AACjF,wBAAgB,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtE;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAIhF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,IAAI,CAUpF"}
@@ -0,0 +1,98 @@
1
+ import net from 'node:net';
2
+ import { setTimeout as delay } from 'node:timers/promises';
3
+ import { ConnectError, toError } from '../errors.js';
4
+ /**
5
+ * Open a TCP connection, rejecting on error, timeout or abort.
6
+ *
7
+ * v2's `createConnection` only ever resolved: a refused or black-holed upstream
8
+ * left the promise — and the client socket — hanging forever.
9
+ */
10
+ export async function connect(options) {
11
+ const { host, port, timeoutMs, signal } = options;
12
+ signal?.throwIfAborted();
13
+ return new Promise((resolve, reject) => {
14
+ const socket = net.connect({ host, port, noDelay: true });
15
+ const cleanup = () => {
16
+ socket.setTimeout(0);
17
+ socket.off('connect', onConnect);
18
+ socket.off('error', onError);
19
+ socket.off('timeout', onTimeout);
20
+ signal?.removeEventListener('abort', onAbort);
21
+ };
22
+ const fail = (message, cause) => {
23
+ cleanup();
24
+ socket.destroy();
25
+ reject(new ConnectError(host, port, message, cause ? { cause } : undefined));
26
+ };
27
+ function onConnect() {
28
+ cleanup();
29
+ resolve(socket);
30
+ }
31
+ function onError(error) {
32
+ fail(error.message, error);
33
+ }
34
+ function onTimeout() {
35
+ fail(`timed out after ${String(timeoutMs)}ms`);
36
+ }
37
+ function onAbort() {
38
+ fail('aborted');
39
+ }
40
+ if (timeoutMs > 0)
41
+ socket.setTimeout(timeoutMs);
42
+ socket.once('connect', onConnect);
43
+ socket.once('error', onError);
44
+ socket.once('timeout', onTimeout);
45
+ signal?.addEventListener('abort', onAbort, { once: true });
46
+ });
47
+ }
48
+ /**
49
+ * Write pieces one at a time, honouring backpressure and an optional pause
50
+ * between them. Ignoring the return value of `write()` — as v2 did — lets a
51
+ * fast peer balloon the kernel-side buffer in memory.
52
+ */
53
+ export async function writeSequentially(socket, pieces, delayMs = 0) {
54
+ for (const [index, piece] of pieces.entries()) {
55
+ if (socket.destroyed)
56
+ return;
57
+ if (delayMs > 0 && index > 0)
58
+ await delay(delayMs);
59
+ await write(socket, piece);
60
+ }
61
+ }
62
+ /** Promisified `socket.write` that waits for `drain` when the buffer is full. */
63
+ export function write(socket, chunk) {
64
+ return new Promise((resolve, reject) => {
65
+ const flushed = socket.write(chunk, (error) => {
66
+ if (error)
67
+ reject(toError(error));
68
+ else if (flushed)
69
+ resolve();
70
+ });
71
+ if (!flushed)
72
+ socket.once('drain', resolve);
73
+ });
74
+ }
75
+ /** Destroy every socket, ignoring already-destroyed ones. */
76
+ export function destroyAll(...sockets) {
77
+ for (const socket of sockets) {
78
+ if (socket && !socket.destroyed)
79
+ socket.destroy();
80
+ }
81
+ }
82
+ /**
83
+ * Arm an inactivity timeout that destroys the socket. `0` disables it.
84
+ * Returns a disposer.
85
+ */
86
+ export function armIdleTimeout(socket, idleTimeoutMs) {
87
+ if (idleTimeoutMs <= 0)
88
+ return () => undefined;
89
+ const onTimeout = () => {
90
+ socket.destroy();
91
+ };
92
+ socket.setTimeout(idleTimeoutMs, onTimeout);
93
+ return () => {
94
+ socket.setTimeout(0);
95
+ socket.off('timeout', onTimeout);
96
+ };
97
+ }
98
+ //# sourceMappingURL=socket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket.js","sourceRoot":"","sources":["../../../src/core/net/socket.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type net from 'node:net';
2
+ import type { TunnelContext } from './context.js';
3
+ /**
4
+ * The CONNECT path — this is where GreenTunnel actually does its job.
5
+ *
6
+ * Once the tunnel is up, the client's first payload is the TLS ClientHello
7
+ * carrying the SNI. We split it so no single TCP segment (or TLS record)
8
+ * contains a whole hostname, then get out of the way.
9
+ */
10
+ export declare function openConnectTunnel(client: net.Socket, leftover: Buffer, target: {
11
+ host: string;
12
+ port: number;
13
+ }, ctx: TunnelContext): Promise<void>;
14
+ //# sourceMappingURL=connect-tunnel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect-tunnel.d.ts","sourceRoot":"","sources":["../../../src/core/proxy/connect-tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAKhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIlD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,GAAG,CAAC,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACtC,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -0,0 +1,44 @@
1
+ import { connect, write, writeSequentially } from '../net/socket.js';
2
+ import { fragmentClientHello, isClientHello } from '../tls/fragment.js';
3
+ import { readChunk } from './connection.js';
4
+ import { tunnel } from './pipe.js';
5
+ const CONNECTION_ESTABLISHED = Buffer.from('HTTP/1.1 200 Connection Established\r\n\r\n', 'latin1');
6
+ /**
7
+ * The CONNECT path — this is where GreenTunnel actually does its job.
8
+ *
9
+ * Once the tunnel is up, the client's first payload is the TLS ClientHello
10
+ * carrying the SNI. We split it so no single TCP segment (or TLS record)
11
+ * contains a whole hostname, then get out of the way.
12
+ */
13
+ export async function openConnectTunnel(client, leftover, target, ctx) {
14
+ const { settings, dns, logger } = ctx;
15
+ const address = await dns.resolve(target.host);
16
+ const server = await connect({
17
+ host: address,
18
+ port: target.port,
19
+ timeoutMs: settings.connectTimeoutMs,
20
+ signal: ctx.signal,
21
+ });
22
+ ctx.onOpen({
23
+ id: ctx.nextTunnelId(),
24
+ kind: 'https',
25
+ host: target.host,
26
+ port: target.port,
27
+ startedAt: Date.now(),
28
+ });
29
+ await write(client, CONNECTION_ESTABLISHED);
30
+ // Either the client pipelined the ClientHello behind the CONNECT head, or we
31
+ // wait one round-trip for it.
32
+ const hello = leftover.length > 0 ? leftover : await readChunk(client, settings.connectTimeoutMs);
33
+ const pieces = fragmentClientHello(hello, settings.fragment);
34
+ if (pieces.length > 1) {
35
+ const unit = settings.fragment.tlsRecords ? 'records' : 'segments';
36
+ logger.debug(`${target.host}: split ClientHello into ${String(pieces.length)} ${unit}`);
37
+ }
38
+ else if (settings.fragment.enabled && !isClientHello(hello)) {
39
+ logger.debug(`${target.host}: not a ClientHello, forwarding untouched`);
40
+ }
41
+ await writeSequentially(server, pieces, settings.fragment.delayMs);
42
+ await tunnel(client, server, settings.idleTimeoutMs);
43
+ }
44
+ //# sourceMappingURL=connect-tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect-tunnel.js","sourceRoot":"","sources":["../../../src/core/proxy/connect-tunnel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGnC,MAAM,sBAAsB,GAAG,MAAM,CAAC,IAAI,CAAC,6CAA6C,EAAE,QAAQ,CAAC,CAAC;AAEpG;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAkB,EAClB,QAAgB,EAChB,MAAsC,EACtC,GAAkB;IAElB,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAEtC,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;QAC3B,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,QAAQ,CAAC,gBAAgB;QACpC,MAAM,EAAE,GAAG,CAAC,MAAM;KACnB,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC;QACT,EAAE,EAAE,GAAG,CAAC,YAAY,EAAE;QACtB,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAE5C,6EAA6E;IAC7E,8BAA8B;IAC9B,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAClG,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAE7D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,IAAI,4BAA4B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC1F,CAAC;SAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,IAAI,2CAA2C,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEnE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type net from 'node:net';
2
+ import type { TunnelContext } from './context.js';
3
+ /**
4
+ * Read the first request head off a freshly accepted socket and route it.
5
+ *
6
+ * The server is created with `pauseOnConnect`, so nothing is read until we ask.
7
+ * Whatever we over-read is handed to the tunnel rather than dropped.
8
+ */
9
+ export declare function handleConnection(client: net.Socket, ctx: TunnelContext): Promise<void>;
10
+ /** Read exactly one more chunk, or throw if the client goes away first. */
11
+ export declare function readChunk(socket: net.Socket, timeoutMs: number): Promise<Buffer>;
12
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/core/proxy/connection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAKhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKlD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5F;AAgCD,2EAA2E;AAC3E,wBAAsB,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUtF"}
@@ -0,0 +1,88 @@
1
+ import { on } from 'node:events';
2
+ import { ProtocolError } from '../errors.js';
3
+ import { parseRequestHead, resolveUpstream, splitAuthority } from '../http/head.js';
4
+ import { openConnectTunnel } from './connect-tunnel.js';
5
+ import { openPlainTunnel } from './plain-tunnel.js';
6
+ const HEAD_TERMINATOR = '\r\n\r\n';
7
+ const MAX_HEAD_BYTES = 64 * 1024;
8
+ /**
9
+ * Read the first request head off a freshly accepted socket and route it.
10
+ *
11
+ * The server is created with `pauseOnConnect`, so nothing is read until we ask.
12
+ * Whatever we over-read is handed to the tunnel rather than dropped.
13
+ */
14
+ export async function handleConnection(client, ctx) {
15
+ const { raw, rest } = await readRequestHead(client, ctx.settings.connectTimeoutMs);
16
+ const head = parseRequestHead(raw);
17
+ if (head.method.toUpperCase() === 'CONNECT') {
18
+ await openConnectTunnel(client, rest, splitAuthority(head.target, 443), ctx);
19
+ return;
20
+ }
21
+ if (ctx.settings.httpsOnly) {
22
+ respond(client, 403, 'Forbidden', 'GreenTunnel is running in HTTPS-only mode.\n');
23
+ throw new ProtocolError(`Blocked plain HTTP request to ${head.target}`);
24
+ }
25
+ const initial = Buffer.concat([Buffer.from(raw + HEAD_TERMINATOR, 'latin1'), rest]);
26
+ await openPlainTunnel(client, initial, resolveUpstream(head, 80), ctx);
27
+ }
28
+ /** Accumulate bytes until the blank line that ends an HTTP head. */
29
+ async function readRequestHead(socket, timeoutMs) {
30
+ let buffer = Buffer.alloc(0);
31
+ socket.resume();
32
+ try {
33
+ for await (const chunk of readChunks(socket, timeoutMs)) {
34
+ buffer = buffer.length === 0 ? chunk : Buffer.concat([buffer, chunk]);
35
+ const end = buffer.indexOf(HEAD_TERMINATOR);
36
+ if (end >= 0) {
37
+ return {
38
+ raw: buffer.subarray(0, end).toString('latin1'),
39
+ rest: buffer.subarray(end + HEAD_TERMINATOR.length),
40
+ };
41
+ }
42
+ if (buffer.length > MAX_HEAD_BYTES) {
43
+ throw new ProtocolError(`Request head exceeds ${String(MAX_HEAD_BYTES)} bytes`);
44
+ }
45
+ }
46
+ }
47
+ finally {
48
+ socket.pause();
49
+ }
50
+ throw new ProtocolError('Client closed before sending a complete request head');
51
+ }
52
+ /** Read exactly one more chunk, or throw if the client goes away first. */
53
+ export async function readChunk(socket, timeoutMs) {
54
+ socket.resume();
55
+ try {
56
+ for await (const chunk of readChunks(socket, timeoutMs)) {
57
+ return chunk;
58
+ }
59
+ }
60
+ finally {
61
+ socket.pause();
62
+ }
63
+ throw new ProtocolError('Client closed before sending any payload');
64
+ }
65
+ /**
66
+ * `events.on` as a typed async iterator that also stops on `end`/`close` and
67
+ * rejects on `error` — so a stalled client can never leak the connection the
68
+ * way v2's bare `once('data')` promise did.
69
+ */
70
+ function readChunks(socket, timeoutMs) {
71
+ const iterator = on(socket, 'data', {
72
+ signal: AbortSignal.timeout(timeoutMs),
73
+ close: ['end', 'close'],
74
+ });
75
+ return (async function* unwrap() {
76
+ for await (const [chunk] of iterator)
77
+ yield chunk;
78
+ })();
79
+ }
80
+ function respond(socket, status, reason, body) {
81
+ const payload = Buffer.from(body, 'utf8');
82
+ socket.write(`HTTP/1.1 ${String(status)} ${reason}\r\n` +
83
+ 'Content-Type: text/plain; charset=utf-8\r\n' +
84
+ `Content-Length: ${String(payload.length)}\r\n` +
85
+ 'Connection: close\r\n\r\n');
86
+ socket.end(payload);
87
+ }
88
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../src/core/proxy/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { DnsResolver } from '../dns/index.js';
2
+ import type { Logger } from '../logger.js';
3
+ import type { ProxySettings, TunnelInfo } from '../types.js';
4
+ /** Everything a single connection needs, injected rather than reached for. */
5
+ export interface TunnelContext {
6
+ readonly settings: ProxySettings;
7
+ readonly dns: DnsResolver;
8
+ readonly logger: Logger;
9
+ /** Aborted when the proxy shuts down. */
10
+ readonly signal: AbortSignal;
11
+ readonly nextTunnelId: () => number;
12
+ /** Called once the upstream target is known and the tunnel is live. */
13
+ readonly onOpen: (info: TunnelInfo) => void;
14
+ }
15
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/core/proxy/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE7D,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,MAAM,CAAC;IACpC,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CAC7C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/core/proxy/context.ts"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { type DnsResolver } from '../dns/index.js';
3
+ import { Logger } from '../logger.js';
4
+ import type { ProxyAddress, ProxyEventMap, ProxyOptions, ProxySettings, ProxyStats } from '../types.js';
5
+ export interface ProxyDependencies {
6
+ readonly logger?: Logger;
7
+ /** Override the resolver, mainly for tests. */
8
+ readonly dns?: DnsResolver;
9
+ }
10
+ /**
11
+ * The DPI-evading proxy server.
12
+ *
13
+ * Unlike v2 this class does **not** touch the OS proxy configuration — that is
14
+ * `SystemProxy`'s job. Keeping them apart means the engine is testable without
15
+ * root, and a crash can't leave the machine pointed at a dead port.
16
+ *
17
+ * Emits `error` in the Node convention: attach a listener or an emitted error
18
+ * will throw.
19
+ */
20
+ export declare class Proxy extends EventEmitter<ProxyEventMap> {
21
+ #private;
22
+ readonly settings: ProxySettings;
23
+ constructor(options?: ProxyOptions, dependencies?: ProxyDependencies);
24
+ get running(): boolean;
25
+ /** The bound address, or `null` while stopped. */
26
+ get address(): ProxyAddress | null;
27
+ get stats(): ProxyStats;
28
+ /** Idempotent: starting an already-running proxy returns its address. */
29
+ start(): Promise<ProxyAddress>;
30
+ /** Idempotent. Tears down every live tunnel, then the listener. */
31
+ stop(): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/proxy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,aAAa,EACb,UAAU,EAEX,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,qBAAa,KAAM,SAAQ,YAAY,CAAC,aAAa,CAAC;;IACpD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;gBAerB,OAAO,GAAE,YAAiB,EAAE,YAAY,GAAE,iBAAsB;IAQ5E,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,kDAAkD;IAClD,IAAI,OAAO,IAAI,YAAY,GAAG,IAAI,CAIjC;IAED,IAAI,KAAK,IAAI,UAAU,CAStB;IAED,yEAAyE;IACnE,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC;IA4CpC,mEAAmE;IAC7D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAkE5B"}
@@ -0,0 +1,162 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import net from 'node:net';
3
+ import { assertValidSettings, resolveSettings } from '../config.js';
4
+ import { createDnsResolver } from '../dns/index.js';
5
+ import { GreenTunnelError, toError } from '../errors.js';
6
+ import { Logger } from '../logger.js';
7
+ import { destroyAll } from '../net/socket.js';
8
+ import { handleConnection } from './connection.js';
9
+ /**
10
+ * The DPI-evading proxy server.
11
+ *
12
+ * Unlike v2 this class does **not** touch the OS proxy configuration — that is
13
+ * `SystemProxy`'s job. Keeping them apart means the engine is testable without
14
+ * root, and a crash can't leave the machine pointed at a dead port.
15
+ *
16
+ * Emits `error` in the Node convention: attach a listener or an emitted error
17
+ * will throw.
18
+ */
19
+ export class Proxy extends EventEmitter {
20
+ settings;
21
+ #logger;
22
+ #dns;
23
+ #sockets = new Set();
24
+ #server = null;
25
+ #abort = null;
26
+ #startedAt = null;
27
+ #nextTunnelId = 1;
28
+ #totalTunnels = 0;
29
+ #failedTunnels = 0;
30
+ #bytesSent = 0;
31
+ #bytesReceived = 0;
32
+ constructor(options = {}, dependencies = {}) {
33
+ super();
34
+ this.settings = resolveSettings(options);
35
+ assertValidSettings(this.settings);
36
+ this.#logger = dependencies.logger ?? new Logger('green-tunnel');
37
+ this.#dns = dependencies.dns ?? createDnsResolver(this.settings.dns);
38
+ }
39
+ get running() {
40
+ return this.#server !== null;
41
+ }
42
+ /** The bound address, or `null` while stopped. */
43
+ get address() {
44
+ const address = this.#server?.address();
45
+ if (address === null || address === undefined || typeof address === 'string')
46
+ return null;
47
+ return { host: address.address, port: address.port };
48
+ }
49
+ get stats() {
50
+ return {
51
+ activeTunnels: this.#sockets.size,
52
+ totalTunnels: this.#totalTunnels,
53
+ failedTunnels: this.#failedTunnels,
54
+ bytesSent: this.#bytesSent,
55
+ bytesReceived: this.#bytesReceived,
56
+ startedAt: this.#startedAt,
57
+ };
58
+ }
59
+ /** Idempotent: starting an already-running proxy returns its address. */
60
+ async start() {
61
+ const current = this.address;
62
+ if (current)
63
+ return current;
64
+ const abort = new AbortController();
65
+ const server = net.createServer({ pauseOnConnect: true, noDelay: true });
66
+ server.on('connection', (socket) => {
67
+ void this.#onConnection(socket, abort.signal);
68
+ });
69
+ server.on('error', (error) => {
70
+ this.emit('error', toError(error));
71
+ });
72
+ await new Promise((resolve, reject) => {
73
+ const onError = (error) => {
74
+ reject(toError(error));
75
+ };
76
+ server.once('error', onError);
77
+ server.listen({ host: this.settings.host, port: this.settings.port }, () => {
78
+ server.off('error', onError);
79
+ resolve();
80
+ });
81
+ });
82
+ // Read the address off the server directly rather than via `this.address`:
83
+ // the early-return above narrowed that getter to `null` for the rest of the
84
+ // function, and TypeScript has no way to know `#server` changed underneath.
85
+ const bound = server.address();
86
+ if (bound === null || typeof bound === 'string') {
87
+ server.close();
88
+ throw new GreenTunnelError('Proxy started but reported no address');
89
+ }
90
+ const address = { host: bound.address, port: bound.port };
91
+ this.#server = server;
92
+ this.#abort = abort;
93
+ this.#startedAt = Date.now();
94
+ this.#logger.info(`listening on ${address.host}:${String(address.port)}`);
95
+ this.emit('listening', address);
96
+ return address;
97
+ }
98
+ /** Idempotent. Tears down every live tunnel, then the listener. */
99
+ async stop() {
100
+ const server = this.#server;
101
+ if (!server)
102
+ return;
103
+ this.#server = null;
104
+ this.#abort?.abort();
105
+ this.#abort = null;
106
+ this.#startedAt = null;
107
+ destroyAll(...this.#sockets);
108
+ this.#sockets.clear();
109
+ await new Promise((resolve) => {
110
+ server.close(() => {
111
+ resolve();
112
+ });
113
+ });
114
+ this.#dns.close();
115
+ this.#logger.info('stopped');
116
+ this.emit('close');
117
+ }
118
+ async #onConnection(client, signal) {
119
+ this.#sockets.add(client);
120
+ // A socket that errors with no listener would take the process down.
121
+ client.on('error', () => undefined);
122
+ client.once('close', () => this.#sockets.delete(client));
123
+ let info;
124
+ const context = {
125
+ settings: this.settings,
126
+ dns: this.#dns,
127
+ logger: this.#logger,
128
+ signal,
129
+ nextTunnelId: () => this.#nextTunnelId++,
130
+ onOpen: (tunnel) => {
131
+ info = tunnel;
132
+ this.#totalTunnels++;
133
+ this.emit('tunnel:open', tunnel);
134
+ client.once('close', () => {
135
+ // `bytesRead` is what the client sent us; `bytesWritten` is what we
136
+ // sent back. No counting streams needed.
137
+ this.#bytesSent += client.bytesRead;
138
+ this.#bytesReceived += client.bytesWritten;
139
+ this.emit('tunnel:close', {
140
+ ...tunnel,
141
+ bytesSent: client.bytesRead,
142
+ bytesReceived: client.bytesWritten,
143
+ });
144
+ });
145
+ },
146
+ };
147
+ try {
148
+ await handleConnection(client, context);
149
+ }
150
+ catch (cause) {
151
+ const error = toError(cause);
152
+ this.#failedTunnels++;
153
+ this.#logger.debug(`connection failed: ${error.message}`);
154
+ if (info)
155
+ this.emit('tunnel:error', info, error);
156
+ }
157
+ finally {
158
+ destroyAll(client);
159
+ }
160
+ }
161
+ }
162
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/proxy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAoB,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAS9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AASnD;;;;;;;;;GASG;AACH,MAAM,OAAO,KAAM,SAAQ,YAA2B;IAC3C,QAAQ,CAAgB;IAExB,OAAO,CAAS;IAChB,IAAI,CAAc;IAClB,QAAQ,GAAG,IAAI,GAAG,EAAc,CAAC;IAE1C,OAAO,GAAsB,IAAI,CAAC;IAClC,MAAM,GAA2B,IAAI,CAAC;IACtC,UAAU,GAAkB,IAAI,CAAC;IACjC,aAAa,GAAG,CAAC,CAAC;IAClB,aAAa,GAAG,CAAC,CAAC;IAClB,cAAc,GAAG,CAAC,CAAC;IACnB,UAAU,GAAG,CAAC,CAAC;IACf,cAAc,GAAG,CAAC,CAAC;IAEnB,YAAY,UAAwB,EAAE,EAAE,eAAkC,EAAE;QAC1E,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QACzC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC,MAAM,IAAI,IAAI,MAAM,CAAC,cAAc,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;IAC/B,CAAC;IAED,kDAAkD;IAClD,IAAI,OAAO;QACT,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;QACxC,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC1F,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;IACvD,CAAC;IAED,IAAI,KAAK;QACP,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YACjC,YAAY,EAAE,IAAI,CAAC,aAAa;YAChC,aAAa,EAAE,IAAI,CAAC,cAAc;YAClC,SAAS,EAAE,IAAI,CAAC,UAAU;YAC1B,aAAa,EAAE,IAAI,CAAC,cAAc;YAClC,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,KAAK;QACT,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAE5B,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzE,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;YACjC,KAAK,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,MAAM,OAAO,GAAG,CAAC,KAAY,EAAQ,EAAE;gBACrC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE;gBACzE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC7B,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,2EAA2E;QAC3E,4EAA4E;QAC5E,4EAA4E;QAC5E,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAChD,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,gBAAgB,CAAC,uCAAuC,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,OAAO,GAAiB,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QAExE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,mEAAmE;IACnE,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QAEvB,UAAU,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAEtB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;gBAChB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,MAAkB,EAAE,MAAmB;QACzD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1B,qEAAqE;QACrE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAEzD,IAAI,IAA4B,CAAC;QAEjC,MAAM,OAAO,GAAkB;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,GAAG,EAAE,IAAI,CAAC,IAAI;YACd,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,MAAM;YACN,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE;YACxC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;gBACjB,IAAI,GAAG,MAAM,CAAC;gBACd,IAAI,CAAC,aAAa,EAAE,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;gBACjC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;oBACxB,oEAAoE;oBACpE,yCAAyC;oBACzC,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC;oBACpC,IAAI,CAAC,cAAc,IAAI,MAAM,CAAC,YAAY,CAAC;oBAC3C,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;wBACxB,GAAG,MAAM;wBACT,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,aAAa,EAAE,MAAM,CAAC,YAAY;qBACnC,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC;SACF,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAC7B,IAAI,CAAC,cAAc,EAAE,CAAC;YACtB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,sBAAsB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1D,IAAI,IAAI;gBAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACnD,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import type net from 'node:net';
2
+ /**
3
+ * Join two sockets into a bidirectional tunnel and resolve when both halves are
4
+ * done.
5
+ *
6
+ * `pipeline` (rather than v2's raw `.on('data')` + `.write()`) gives us
7
+ * backpressure, half-close propagation and guaranteed teardown on error.
8
+ * `allSettled` matters: when one direction fails the other almost always fails
9
+ * too, and an unobserved rejection there would crash the process.
10
+ */
11
+ export declare function tunnel(client: net.Socket, server: net.Socket, idleTimeoutMs: number, transform?: NodeJS.ReadWriteStream): Promise<void>;
12
+ //# sourceMappingURL=pipe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipe.d.ts","sourceRoot":"","sources":["../../../src/core/proxy/pipe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAmBhC;;;;;;;;GAQG;AACH,wBAAsB,MAAM,CAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,EAClB,MAAM,EAAE,GAAG,CAAC,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,MAAM,CAAC,eAAe,GACjC,OAAO,CAAC,IAAI,CAAC,CAkBf"}
@@ -0,0 +1,42 @@
1
+ import { pipeline } from 'node:stream/promises';
2
+ import { armIdleTimeout, destroyAll } from '../net/socket.js';
3
+ import { toError } from '../errors.js';
4
+ /** Errors that just mean "the other side hung up" — not worth reporting. */
5
+ const BENIGN_CODES = new Set([
6
+ 'ECONNRESET',
7
+ 'EPIPE',
8
+ 'ERR_STREAM_PREMATURE_CLOSE',
9
+ 'ERR_STREAM_DESTROYED',
10
+ 'ABORT_ERR',
11
+ ]);
12
+ function isBenign(error) {
13
+ const code = error?.code;
14
+ return code !== undefined && BENIGN_CODES.has(code);
15
+ }
16
+ /**
17
+ * Join two sockets into a bidirectional tunnel and resolve when both halves are
18
+ * done.
19
+ *
20
+ * `pipeline` (rather than v2's raw `.on('data')` + `.write()`) gives us
21
+ * backpressure, half-close propagation and guaranteed teardown on error.
22
+ * `allSettled` matters: when one direction fails the other almost always fails
23
+ * too, and an unobserved rejection there would crash the process.
24
+ */
25
+ export async function tunnel(client, server, idleTimeoutMs, transform) {
26
+ const disarm = [armIdleTimeout(client, idleTimeoutMs), armIdleTimeout(server, idleTimeoutMs)];
27
+ const upstream = transform ? pipeline(client, transform, server) : pipeline(client, server);
28
+ const downstream = pipeline(server, client);
29
+ try {
30
+ const results = await Promise.allSettled([upstream, downstream]);
31
+ const failure = results.find((result) => result.status === 'rejected' && !isBenign(result.reason));
32
+ if (failure?.status === 'rejected') {
33
+ throw toError(failure.reason);
34
+ }
35
+ }
36
+ finally {
37
+ for (const off of disarm)
38
+ off();
39
+ destroyAll(client, server);
40
+ }
41
+ }
42
+ //# sourceMappingURL=pipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipe.js","sourceRoot":"","sources":["../../../src/core/proxy/pipe.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,4EAA4E;AAC5E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC3B,YAAY;IACZ,OAAO;IACP,4BAA4B;IAC5B,sBAAsB;IACtB,WAAW;CACZ,CAAC,CAAC;AAEH,SAAS,QAAQ,CAAC,KAAc;IAC9B,MAAM,IAAI,GAAI,KAA2C,EAAE,IAAI,CAAC;IAChE,OAAO,IAAI,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,MAAkB,EAClB,MAAkB,EAClB,aAAqB,EACrB,SAAkC;IAElC,MAAM,MAAM,GAAG,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IAE9F,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5F,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAC1B,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CACrE,CAAC;QACF,IAAI,OAAO,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;YACnC,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;YAAS,CAAC;QACT,KAAK,MAAM,GAAG,IAAI,MAAM;YAAE,GAAG,EAAE,CAAC;QAChC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type net from 'node:net';
2
+ import type { TunnelContext } from './context.js';
3
+ /**
4
+ * Plain-HTTP proxying. No fragmentation happens here — there is no SNI to hide,
5
+ * and the Host header is in cleartext regardless. Its only job is to relay the
6
+ * stream while rewriting absolute-form request targets into origin-form.
7
+ */
8
+ export declare function openPlainTunnel(client: net.Socket, initial: Buffer, target: {
9
+ host: string;
10
+ port: number;
11
+ }, ctx: TunnelContext): Promise<void>;
12
+ //# sourceMappingURL=plain-tunnel.d.ts.map