@push.rocks/smartproxy 19.5.9 → 19.5.11
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.
- package/dist_ts/core/utils/socket-utils.d.ts +13 -0
- package/dist_ts/core/utils/socket-utils.js +29 -1
- package/dist_ts/forwarding/handlers/https-passthrough-handler.js +91 -62
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +32 -12
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +2 -2
- package/package.json +1 -1
- package/readme.hints.md +45 -1
- package/readme.plan.md +124 -296
- package/ts/core/utils/socket-utils.ts +43 -0
- package/ts/forwarding/handlers/https-passthrough-handler.ts +104 -73
- package/ts/forwarding/handlers/https-terminate-to-http-handler.ts +35 -13
- package/ts/forwarding/handlers/https-terminate-to-https-handler.ts +1 -1
|
@@ -2,7 +2,7 @@ import * as plugins from '../../plugins.js';
|
|
|
2
2
|
import { ForwardingHandler } from './base-handler.js';
|
|
3
3
|
import type { IForwardConfig } from '../config/forwarding-types.js';
|
|
4
4
|
import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
|
|
5
|
-
import { createIndependentSocketHandlers, setupSocketHandlers } from '../../core/utils/socket-utils.js';
|
|
5
|
+
import { createIndependentSocketHandlers, setupSocketHandlers, createSocketWithErrorHandler } from '../../core/utils/socket-utils.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Handler for HTTPS passthrough (SNI forwarding without termination)
|
|
@@ -48,91 +48,122 @@ export class HttpsPassthroughHandler extends ForwardingHandler {
|
|
|
48
48
|
target: `${target.host}:${target.port}`
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
// Create a connection to the target server
|
|
52
|
-
const serverSocket = plugins.net.connect(target.port, target.host);
|
|
53
|
-
|
|
54
51
|
// Track data transfer for logging
|
|
55
52
|
let bytesSent = 0;
|
|
56
53
|
let bytesReceived = 0;
|
|
54
|
+
let serverSocket: plugins.net.Socket | null = null;
|
|
55
|
+
let cleanupClient: ((reason: string) => Promise<void>) | null = null;
|
|
56
|
+
let cleanupServer: ((reason: string) => Promise<void>) | null = null;
|
|
57
57
|
|
|
58
|
-
// Create
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
(
|
|
58
|
+
// Create a connection to the target server with immediate error handling
|
|
59
|
+
serverSocket = createSocketWithErrorHandler({
|
|
60
|
+
port: target.port,
|
|
61
|
+
host: target.host,
|
|
62
|
+
onError: async (error) => {
|
|
63
|
+
// Server connection failed - clean up client socket immediately
|
|
64
|
+
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
65
|
+
error: error.message,
|
|
66
|
+
code: (error as any).code || 'UNKNOWN',
|
|
67
|
+
remoteAddress,
|
|
68
|
+
target: `${target.host}:${target.port}`
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Clean up the client socket since we can't forward
|
|
72
|
+
if (!clientSocket.destroyed) {
|
|
73
|
+
clientSocket.destroy();
|
|
74
|
+
}
|
|
75
|
+
|
|
63
76
|
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
64
77
|
remoteAddress,
|
|
65
|
-
bytesSent,
|
|
66
|
-
bytesReceived,
|
|
67
|
-
reason
|
|
78
|
+
bytesSent: 0,
|
|
79
|
+
bytesReceived: 0,
|
|
80
|
+
reason: `server_connection_failed: ${error.message}`
|
|
68
81
|
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
bytesSent += data.length;
|
|
88
|
-
|
|
89
|
-
// Check if server socket is writable
|
|
90
|
-
if (serverSocket.writable) {
|
|
91
|
-
const flushed = serverSocket.write(data);
|
|
82
|
+
},
|
|
83
|
+
onConnect: () => {
|
|
84
|
+
// Connection successful - set up forwarding handlers
|
|
85
|
+
const handlers = createIndependentSocketHandlers(
|
|
86
|
+
clientSocket,
|
|
87
|
+
serverSocket!,
|
|
88
|
+
(reason) => {
|
|
89
|
+
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
90
|
+
remoteAddress,
|
|
91
|
+
bytesSent,
|
|
92
|
+
bytesReceived,
|
|
93
|
+
reason
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
cleanupClient = handlers.cleanupClient;
|
|
99
|
+
cleanupServer = handlers.cleanupServer;
|
|
92
100
|
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
// Setup handlers with custom timeout handling that doesn't close connections
|
|
102
|
+
const timeout = this.getTimeout();
|
|
103
|
+
|
|
104
|
+
setupSocketHandlers(clientSocket, cleanupClient, (socket) => {
|
|
105
|
+
// Just reset timeout, don't close
|
|
106
|
+
socket.setTimeout(timeout);
|
|
107
|
+
}, 'client');
|
|
108
|
+
|
|
109
|
+
setupSocketHandlers(serverSocket!, cleanupServer, (socket) => {
|
|
110
|
+
// Just reset timeout, don't close
|
|
111
|
+
socket.setTimeout(timeout);
|
|
112
|
+
}, 'server');
|
|
113
|
+
|
|
114
|
+
// Forward data from client to server
|
|
115
|
+
clientSocket.on('data', (data) => {
|
|
116
|
+
bytesSent += data.length;
|
|
117
|
+
|
|
118
|
+
// Check if server socket is writable
|
|
119
|
+
if (serverSocket && serverSocket.writable) {
|
|
120
|
+
const flushed = serverSocket.write(data);
|
|
121
|
+
|
|
122
|
+
// Handle backpressure
|
|
123
|
+
if (!flushed) {
|
|
124
|
+
clientSocket.pause();
|
|
125
|
+
serverSocket.once('drain', () => {
|
|
126
|
+
clientSocket.resume();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
this.emit(ForwardingHandlerEvents.DATA_FORWARDED, {
|
|
132
|
+
direction: 'outbound',
|
|
133
|
+
bytes: data.length,
|
|
134
|
+
total: bytesSent
|
|
98
135
|
});
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this.emit(ForwardingHandlerEvents.DATA_FORWARDED, {
|
|
103
|
-
direction: 'outbound',
|
|
104
|
-
bytes: data.length,
|
|
105
|
-
total: bytesSent
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Forward data from server to client
|
|
110
|
-
serverSocket.on('data', (data) => {
|
|
111
|
-
bytesReceived += data.length;
|
|
112
|
-
|
|
113
|
-
// Check if client socket is writable
|
|
114
|
-
if (clientSocket.writable) {
|
|
115
|
-
const flushed = clientSocket.write(data);
|
|
136
|
+
});
|
|
116
137
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
138
|
+
// Forward data from server to client
|
|
139
|
+
serverSocket!.on('data', (data) => {
|
|
140
|
+
bytesReceived += data.length;
|
|
141
|
+
|
|
142
|
+
// Check if client socket is writable
|
|
143
|
+
if (clientSocket.writable) {
|
|
144
|
+
const flushed = clientSocket.write(data);
|
|
145
|
+
|
|
146
|
+
// Handle backpressure
|
|
147
|
+
if (!flushed) {
|
|
148
|
+
serverSocket!.pause();
|
|
149
|
+
clientSocket.once('drain', () => {
|
|
150
|
+
serverSocket!.resume();
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
this.emit(ForwardingHandlerEvents.DATA_FORWARDED, {
|
|
156
|
+
direction: 'inbound',
|
|
157
|
+
bytes: data.length,
|
|
158
|
+
total: bytesReceived
|
|
122
159
|
});
|
|
123
|
-
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Set initial timeouts - they will be reset on each timeout event
|
|
163
|
+
clientSocket.setTimeout(timeout);
|
|
164
|
+
serverSocket!.setTimeout(timeout);
|
|
124
165
|
}
|
|
125
|
-
|
|
126
|
-
this.emit(ForwardingHandlerEvents.DATA_FORWARDED, {
|
|
127
|
-
direction: 'inbound',
|
|
128
|
-
bytes: data.length,
|
|
129
|
-
total: bytesReceived
|
|
130
|
-
});
|
|
131
166
|
});
|
|
132
|
-
|
|
133
|
-
// Set initial timeouts - they will be reset on each timeout event
|
|
134
|
-
clientSocket.setTimeout(timeout);
|
|
135
|
-
serverSocket.setTimeout(timeout);
|
|
136
167
|
}
|
|
137
168
|
|
|
138
169
|
/**
|
|
@@ -2,7 +2,7 @@ import * as plugins from '../../plugins.js';
|
|
|
2
2
|
import { ForwardingHandler } from './base-handler.js';
|
|
3
3
|
import type { IForwardConfig } from '../config/forwarding-types.js';
|
|
4
4
|
import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
|
|
5
|
-
import { createSocketCleanupHandler, setupSocketHandlers } from '../../core/utils/socket-utils.js';
|
|
5
|
+
import { createSocketCleanupHandler, setupSocketHandlers, createSocketWithErrorHandler } from '../../core/utils/socket-utils.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Handler for HTTPS termination with HTTP backend
|
|
@@ -141,19 +141,41 @@ export class HttpsTerminateToHttpHandler extends ForwardingHandler {
|
|
|
141
141
|
if (dataBuffer.includes(Buffer.from('\r\n\r\n')) && !connectionEstablished) {
|
|
142
142
|
const target = this.getTargetFromConfig();
|
|
143
143
|
|
|
144
|
-
// Create backend connection
|
|
145
|
-
backendSocket =
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
144
|
+
// Create backend connection with immediate error handling
|
|
145
|
+
backendSocket = createSocketWithErrorHandler({
|
|
146
|
+
port: target.port,
|
|
147
|
+
host: target.host,
|
|
148
|
+
onError: (error) => {
|
|
149
|
+
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
150
|
+
error: error.message,
|
|
151
|
+
code: (error as any).code || 'UNKNOWN',
|
|
152
|
+
remoteAddress,
|
|
153
|
+
target: `${target.host}:${target.port}`
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Clean up the TLS socket since we can't forward
|
|
157
|
+
if (!tlsSocket.destroyed) {
|
|
158
|
+
tlsSocket.destroy();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
162
|
+
remoteAddress,
|
|
163
|
+
reason: `backend_connection_failed: ${error.message}`
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
onConnect: () => {
|
|
167
|
+
connectionEstablished = true;
|
|
168
|
+
|
|
169
|
+
// Send buffered data
|
|
170
|
+
if (dataBuffer.length > 0) {
|
|
171
|
+
backendSocket!.write(dataBuffer);
|
|
172
|
+
dataBuffer = Buffer.alloc(0);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Set up bidirectional data flow
|
|
176
|
+
tlsSocket.pipe(backendSocket!);
|
|
177
|
+
backendSocket!.pipe(tlsSocket);
|
|
152
178
|
}
|
|
153
|
-
|
|
154
|
-
// Set up bidirectional data flow
|
|
155
|
-
tlsSocket.pipe(backendSocket!);
|
|
156
|
-
backendSocket!.pipe(tlsSocket);
|
|
157
179
|
});
|
|
158
180
|
|
|
159
181
|
// Update the cleanup handler with the backend socket
|
|
@@ -2,7 +2,7 @@ import * as plugins from '../../plugins.js';
|
|
|
2
2
|
import { ForwardingHandler } from './base-handler.js';
|
|
3
3
|
import type { IForwardConfig } from '../config/forwarding-types.js';
|
|
4
4
|
import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
|
|
5
|
-
import { createSocketCleanupHandler, setupSocketHandlers } from '../../core/utils/socket-utils.js';
|
|
5
|
+
import { createSocketCleanupHandler, setupSocketHandlers, createSocketWithErrorHandler } from '../../core/utils/socket-utils.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Handler for HTTPS termination with HTTPS backend
|