Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
12de96a7d5 | |||
296e1fcdc7 | |||
8459e4013c | |||
191c8ac0e6 | |||
3ab483d164 | |||
fcd80dc56b | |||
8ddffcd6e5 | |||
a5a7781c17 | |||
d647e77cdf | |||
9161336197 | |||
2e63d13dd4 | |||
af6ed735d5 | |||
7d38f29ef3 | |||
0df26d4367 | |||
f9a6e2d748 | |||
1cb6302750 | |||
f336f25535 | |||
5d6b707440 | |||
622ad2ff20 | |||
dd23efd28d |
70
changelog.md
70
changelog.md
@ -1,5 +1,75 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-03-03 - 3.22.1 - fix(PortProxy)
|
||||||
|
Fix connection timeout and IP validation handling for PortProxy
|
||||||
|
|
||||||
|
- Adjusted initial data timeout setting for SNI-enabled connections in PortProxy.
|
||||||
|
- Restored IP validation logic to original behavior, ensuring compatibility with domain configurations.
|
||||||
|
|
||||||
|
## 2025-03-03 - 3.22.0 - feat(classes.portproxy)
|
||||||
|
Enhanced PortProxy to support initial data timeout and improved IP handling
|
||||||
|
|
||||||
|
- Added `initialDataTimeout` to PortProxy settings for handling data flow in chained proxies.
|
||||||
|
- Improved IP validation by allowing relaxed checks in chained proxy setups.
|
||||||
|
- Introduced dynamic logging for connection lifecycle and proxy configurations.
|
||||||
|
- Enhanced timeout handling for better proxy resilience.
|
||||||
|
|
||||||
|
## 2025-03-03 - 3.21.0 - feat(PortProxy)
|
||||||
|
Enhancements to connection management in PortProxy
|
||||||
|
|
||||||
|
- Introduced a unique ID for each connection record for improved tracking.
|
||||||
|
- Enhanced cleanup mechanism for connections with dual states: initiated and executed.
|
||||||
|
- Implemented shutdown process handling to ensure graceful connection closure.
|
||||||
|
- Added logging for better tracing of connection activities and states.
|
||||||
|
- Improved connection setup with explicit timeouts and data flow management.
|
||||||
|
- Integrated inactivity and parity checks to monitor connection health.
|
||||||
|
|
||||||
|
## 2025-03-01 - 3.20.2 - fix(PortProxy)
|
||||||
|
Enhance connection cleanup handling in PortProxy
|
||||||
|
|
||||||
|
- Add checks to ensure timers are reset only if outgoing socket is active
|
||||||
|
- Prevent setting outgoingActive if the connection is already closed
|
||||||
|
|
||||||
|
## 2025-03-01 - 3.20.1 - fix(PortProxy)
|
||||||
|
Improve IP allowance check for forced domains
|
||||||
|
|
||||||
|
- Enhanced IP allowance check logic by incorporating blocked IPs and default allowed IPs for forced domains within port proxy configurations.
|
||||||
|
|
||||||
|
## 2025-03-01 - 3.20.0 - feat(PortProxy)
|
||||||
|
Enhance PortProxy with advanced connection cleanup and logging
|
||||||
|
|
||||||
|
- Introduced `cleanupConnection` method for improved connection management.
|
||||||
|
- Added logging for connection cleanup including special conditions.
|
||||||
|
- Implemented parity check to clean up connections when outgoing side closes but incoming remains active.
|
||||||
|
- Improved logging during interval checks for active connections and their durations.
|
||||||
|
|
||||||
|
## 2025-03-01 - 3.19.0 - feat(PortProxy)
|
||||||
|
Enhance PortProxy with default blocked IPs
|
||||||
|
|
||||||
|
- Introduced defaultBlockedIPs in IPortProxySettings to handle globally blocked IPs.
|
||||||
|
- Added logic for merging domain-specific and default allowed and blocked IPs for effective IP filtering.
|
||||||
|
- Refactored helper functions for IP and port range checks to improve modularity in PortProxy.
|
||||||
|
|
||||||
|
## 2025-02-27 - 3.18.2 - fix(portproxy)
|
||||||
|
Fixed typographical errors in comments within PortProxy class.
|
||||||
|
|
||||||
|
- Corrected typographical errors in comments within the PortProxy class.
|
||||||
|
|
||||||
|
## 2025-02-27 - 3.18.1 - fix(PortProxy)
|
||||||
|
Refactor and enhance PortProxy test cases and handling
|
||||||
|
|
||||||
|
- Refactored test cases in test/test.portproxy.ts for clarity and added coverage.
|
||||||
|
- Improved TCP server helper functions for better flexibility.
|
||||||
|
- Fixed issues with domain handling in PortProxy configuration.
|
||||||
|
- Introduced round-robin logic for multi-IP domains in PortProxy.
|
||||||
|
- Ensured proper cleanup and stopping of test servers in the test suite.
|
||||||
|
|
||||||
|
## 2025-02-27 - 3.18.0 - feat(PortProxy)
|
||||||
|
Add SNI-based renegotiation handling in PortProxy
|
||||||
|
|
||||||
|
- Introduced a new field 'lockedDomain' in IConnectionRecord to store initial SNI.
|
||||||
|
- Enhanced connection management by enforcing termination if rehandshake is detected with different SNI.
|
||||||
|
|
||||||
## 2025-02-27 - 3.17.1 - fix(PortProxy)
|
## 2025-02-27 - 3.17.1 - fix(PortProxy)
|
||||||
Fix handling of SNI re-negotiation in PortProxy
|
Fix handling of SNI re-negotiation in PortProxy
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartproxy",
|
"name": "@push.rocks/smartproxy",
|
||||||
"version": "3.17.1",
|
"version": "3.22.1",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, and dynamic routing with authentication options.",
|
"description": "A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, and dynamic routing with authentication options.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
|
@ -8,31 +8,30 @@ const TEST_SERVER_PORT = 4000;
|
|||||||
const PROXY_PORT = 4001;
|
const PROXY_PORT = 4001;
|
||||||
const TEST_DATA = 'Hello through port proxy!';
|
const TEST_DATA = 'Hello through port proxy!';
|
||||||
|
|
||||||
// Helper function to create a test TCP server
|
// Helper: Creates a test TCP server that listens on a given port and host.
|
||||||
function createTestServer(port: number): Promise<net.Server> {
|
function createTestServer(port: number, host: string = 'localhost'): Promise<net.Server> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const server = net.createServer((socket) => {
|
const server = net.createServer((socket) => {
|
||||||
socket.on('data', (data) => {
|
socket.on('data', (data) => {
|
||||||
// Echo the received data back
|
// Echo the received data back with a prefix.
|
||||||
socket.write(`Echo: ${data.toString()}`);
|
socket.write(`Echo: ${data.toString()}`);
|
||||||
});
|
});
|
||||||
socket.on('error', (error) => {
|
socket.on('error', (error) => {
|
||||||
console.error('[Test Server] Socket error:', error);
|
console.error(`[Test Server] Socket error on ${host}:${port}:`, error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
server.listen(port, () => {
|
server.listen(port, host, () => {
|
||||||
console.log(`[Test Server] Listening on port ${port}`);
|
console.log(`[Test Server] Listening on ${host}:${port}`);
|
||||||
resolve(server);
|
resolve(server);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to create a test client connection
|
// Helper: Creates a test client connection.
|
||||||
function createTestClient(port: number, data: string): Promise<string> {
|
function createTestClient(port: number, data: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const client = new net.Socket();
|
const client = new net.Socket();
|
||||||
let response = '';
|
let response = '';
|
||||||
|
|
||||||
client.connect(port, 'localhost', () => {
|
client.connect(port, 'localhost', () => {
|
||||||
console.log('[Test Client] Connected to server');
|
console.log('[Test Client] Connected to server');
|
||||||
client.write(data);
|
client.write(data);
|
||||||
@ -41,47 +40,44 @@ function createTestClient(port: number, data: string): Promise<string> {
|
|||||||
response += chunk.toString();
|
response += chunk.toString();
|
||||||
client.end();
|
client.end();
|
||||||
});
|
});
|
||||||
client.on('end', () => {
|
client.on('end', () => resolve(response));
|
||||||
resolve(response);
|
client.on('error', (error) => reject(error));
|
||||||
});
|
|
||||||
client.on('error', (error) => {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup test environment
|
// SETUP: Create a test server and a PortProxy instance.
|
||||||
tap.test('setup port proxy test environment', async () => {
|
tap.test('setup port proxy test environment', async () => {
|
||||||
testServer = await createTestServer(TEST_SERVER_PORT);
|
testServer = await createTestServer(TEST_SERVER_PORT);
|
||||||
portProxy = new PortProxy({
|
portProxy = new PortProxy({
|
||||||
fromPort: PROXY_PORT,
|
fromPort: PROXY_PORT,
|
||||||
toPort: TEST_SERVER_PORT,
|
toPort: TEST_SERVER_PORT,
|
||||||
targetIP: 'localhost',
|
targetIP: 'localhost',
|
||||||
domains: [],
|
domainConfigs: [],
|
||||||
sniEnabled: false,
|
sniEnabled: false,
|
||||||
defaultAllowedIPs: ['127.0.0.1'],
|
defaultAllowedIPs: ['127.0.0.1'],
|
||||||
globalPortRanges: []
|
globalPortRanges: []
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test that the proxy starts and its servers are listening.
|
||||||
tap.test('should start port proxy', async () => {
|
tap.test('should start port proxy', async () => {
|
||||||
await portProxy.start();
|
await portProxy.start();
|
||||||
// Since netServers is private, we cast to any to verify that all created servers are listening.
|
|
||||||
expect((portProxy as any).netServers.every((server: net.Server) => server.listening)).toBeTrue();
|
expect((portProxy as any).netServers.every((server: net.Server) => server.listening)).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test basic TCP forwarding.
|
||||||
tap.test('should forward TCP connections and data to localhost', async () => {
|
tap.test('should forward TCP connections and data to localhost', async () => {
|
||||||
const response = await createTestClient(PROXY_PORT, TEST_DATA);
|
const response = await createTestClient(PROXY_PORT, TEST_DATA);
|
||||||
expect(response).toEqual(`Echo: ${TEST_DATA}`);
|
expect(response).toEqual(`Echo: ${TEST_DATA}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test proxy with a custom target host.
|
||||||
tap.test('should forward TCP connections to custom host', async () => {
|
tap.test('should forward TCP connections to custom host', async () => {
|
||||||
// Create a new proxy instance with a custom host (targetIP)
|
|
||||||
const customHostProxy = new PortProxy({
|
const customHostProxy = new PortProxy({
|
||||||
fromPort: PROXY_PORT + 1,
|
fromPort: PROXY_PORT + 1,
|
||||||
toPort: TEST_SERVER_PORT,
|
toPort: TEST_SERVER_PORT,
|
||||||
targetIP: '127.0.0.1',
|
targetIP: '127.0.0.1',
|
||||||
domains: [],
|
domainConfigs: [],
|
||||||
sniEnabled: false,
|
sniEnabled: false,
|
||||||
defaultAllowedIPs: ['127.0.0.1'],
|
defaultAllowedIPs: ['127.0.0.1'],
|
||||||
globalPortRanges: []
|
globalPortRanges: []
|
||||||
@ -93,153 +89,151 @@ tap.test('should forward TCP connections to custom host', async () => {
|
|||||||
await customHostProxy.stop();
|
await customHostProxy.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should forward connections based on domain-specific target IP', async () => {
|
// Test forced domain routing via port-range configuration.
|
||||||
// Create a second test server on a different port
|
// In this test, we want to forward to a different IP (using '127.0.0.2')
|
||||||
const TEST_SERVER_PORT_2 = TEST_SERVER_PORT + 100;
|
// while keeping the same port. We create a test server on '127.0.0.2'.
|
||||||
const testServer2 = await createTestServer(TEST_SERVER_PORT_2);
|
tap.test('should forward connections based on domain-specific target IP (forced domain via port-range)', async () => {
|
||||||
|
const forcedProxyPort = PROXY_PORT + 2;
|
||||||
|
// Create a test server listening on '127.0.0.2' at forcedProxyPort.
|
||||||
|
const testServer2 = await createTestServer(forcedProxyPort, '127.0.0.2');
|
||||||
|
|
||||||
// Create a proxy with domain-specific target IPs
|
|
||||||
const domainProxy = new PortProxy({
|
const domainProxy = new PortProxy({
|
||||||
fromPort: PROXY_PORT + 2,
|
fromPort: forcedProxyPort,
|
||||||
toPort: TEST_SERVER_PORT, // default port (for non-port-range handling)
|
toPort: TEST_SERVER_PORT, // default target port (unused for forced domain)
|
||||||
targetIP: 'localhost', // default target IP
|
targetIP: 'localhost',
|
||||||
domains: [{
|
domainConfigs: [{
|
||||||
domain: 'domain1.test',
|
domains: ['forced.test'],
|
||||||
allowedIPs: ['127.0.0.1'],
|
allowedIPs: ['127.0.0.1'],
|
||||||
targetIP: '127.0.0.1'
|
targetIPs: ['127.0.0.2'], // Use a different IP than the default.
|
||||||
}, {
|
portRanges: [{ from: forcedProxyPort, to: forcedProxyPort }]
|
||||||
domain: 'domain2.test',
|
|
||||||
allowedIPs: ['127.0.0.1'],
|
|
||||||
targetIP: 'localhost'
|
|
||||||
}],
|
}],
|
||||||
sniEnabled: false,
|
sniEnabled: false,
|
||||||
defaultAllowedIPs: ['127.0.0.1'],
|
defaultAllowedIPs: ['127.0.0.1'],
|
||||||
globalPortRanges: []
|
globalPortRanges: [{ from: forcedProxyPort, to: forcedProxyPort }]
|
||||||
});
|
});
|
||||||
|
|
||||||
await domainProxy.start();
|
await domainProxy.start();
|
||||||
|
|
||||||
// Test default connection (should use default targetIP)
|
// When connecting to forcedProxyPort, forced domain handling triggers,
|
||||||
const response1 = await createTestClient(PROXY_PORT + 2, TEST_DATA);
|
// so the proxy will connect to '127.0.0.2' on the same port.
|
||||||
expect(response1).toEqual(`Echo: ${TEST_DATA}`);
|
const response = await createTestClient(forcedProxyPort, TEST_DATA);
|
||||||
|
expect(response).toEqual(`Echo: ${TEST_DATA}`);
|
||||||
// Create another proxy with a different default targetIP
|
|
||||||
const domainProxy2 = new PortProxy({
|
|
||||||
fromPort: PROXY_PORT + 3,
|
|
||||||
toPort: TEST_SERVER_PORT,
|
|
||||||
targetIP: '127.0.0.1',
|
|
||||||
domains: [],
|
|
||||||
sniEnabled: false,
|
|
||||||
defaultAllowedIPs: ['127.0.0.1'],
|
|
||||||
globalPortRanges: []
|
|
||||||
});
|
|
||||||
|
|
||||||
await domainProxy2.start();
|
|
||||||
const response2 = await createTestClient(PROXY_PORT + 3, TEST_DATA);
|
|
||||||
expect(response2).toEqual(`Echo: ${TEST_DATA}`);
|
|
||||||
|
|
||||||
await domainProxy.stop();
|
await domainProxy.stop();
|
||||||
await domainProxy2.stop();
|
|
||||||
await new Promise<void>((resolve) => testServer2.close(() => resolve()));
|
await new Promise<void>((resolve) => testServer2.close(() => resolve()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test handling of multiple concurrent connections.
|
||||||
tap.test('should handle multiple concurrent connections', async () => {
|
tap.test('should handle multiple concurrent connections', async () => {
|
||||||
const concurrentRequests = 5;
|
const concurrentRequests = 5;
|
||||||
const requests = Array(concurrentRequests).fill(null).map((_, i) =>
|
const requests = Array(concurrentRequests).fill(null).map((_, i) =>
|
||||||
createTestClient(PROXY_PORT, `${TEST_DATA} ${i + 1}`)
|
createTestClient(PROXY_PORT, `${TEST_DATA} ${i + 1}`)
|
||||||
);
|
);
|
||||||
|
|
||||||
const responses = await Promise.all(requests);
|
const responses = await Promise.all(requests);
|
||||||
|
|
||||||
responses.forEach((response, i) => {
|
responses.forEach((response, i) => {
|
||||||
expect(response).toEqual(`Echo: ${TEST_DATA} ${i + 1}`);
|
expect(response).toEqual(`Echo: ${TEST_DATA} ${i + 1}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test connection timeout handling.
|
||||||
tap.test('should handle connection timeouts', async () => {
|
tap.test('should handle connection timeouts', async () => {
|
||||||
const client = new net.Socket();
|
const client = new net.Socket();
|
||||||
await new Promise<void>((resolve) => {
|
await new Promise<void>((resolve) => {
|
||||||
client.connect(PROXY_PORT, 'localhost', () => {
|
client.connect(PROXY_PORT, 'localhost', () => {
|
||||||
// Don't send any data, just wait for timeout
|
// Do not send any data to trigger a timeout.
|
||||||
client.on('close', () => {
|
client.on('close', () => resolve());
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test stopping the port proxy.
|
||||||
tap.test('should stop port proxy', async () => {
|
tap.test('should stop port proxy', async () => {
|
||||||
await portProxy.stop();
|
await portProxy.stop();
|
||||||
expect((portProxy as any).netServers.every((server: net.Server) => !server.listening)).toBeTrue();
|
expect((portProxy as any).netServers.every((server: net.Server) => !server.listening)).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cleanup chained proxies tests
|
// Test chained proxies with and without source IP preservation.
|
||||||
tap.test('should support optional source IP preservation in chained proxies', async () => {
|
tap.test('should support optional source IP preservation in chained proxies', async () => {
|
||||||
// Test 1: Without IP preservation (default behavior)
|
// Chained proxies without IP preservation.
|
||||||
const firstProxyDefault = new PortProxy({
|
const firstProxyDefault = new PortProxy({
|
||||||
fromPort: PROXY_PORT + 4,
|
fromPort: PROXY_PORT + 4,
|
||||||
toPort: PROXY_PORT + 5,
|
toPort: PROXY_PORT + 5,
|
||||||
targetIP: 'localhost',
|
targetIP: 'localhost',
|
||||||
domains: [],
|
domainConfigs: [],
|
||||||
sniEnabled: false,
|
sniEnabled: false,
|
||||||
defaultAllowedIPs: ['127.0.0.1', '::ffff:127.0.0.1'],
|
defaultAllowedIPs: ['127.0.0.1', '::ffff:127.0.0.1'],
|
||||||
globalPortRanges: []
|
globalPortRanges: []
|
||||||
});
|
});
|
||||||
|
|
||||||
const secondProxyDefault = new PortProxy({
|
const secondProxyDefault = new PortProxy({
|
||||||
fromPort: PROXY_PORT + 5,
|
fromPort: PROXY_PORT + 5,
|
||||||
toPort: TEST_SERVER_PORT,
|
toPort: TEST_SERVER_PORT,
|
||||||
targetIP: 'localhost',
|
targetIP: 'localhost',
|
||||||
domains: [],
|
domainConfigs: [],
|
||||||
sniEnabled: false,
|
sniEnabled: false,
|
||||||
defaultAllowedIPs: ['127.0.0.1', '::ffff:127.0.0.1'],
|
defaultAllowedIPs: ['127.0.0.1', '::ffff:127.0.0.1'],
|
||||||
globalPortRanges: []
|
globalPortRanges: []
|
||||||
});
|
});
|
||||||
|
|
||||||
await secondProxyDefault.start();
|
await secondProxyDefault.start();
|
||||||
await firstProxyDefault.start();
|
await firstProxyDefault.start();
|
||||||
|
|
||||||
// This should work because we explicitly allow both IPv4 and IPv6 formats
|
|
||||||
const response1 = await createTestClient(PROXY_PORT + 4, TEST_DATA);
|
const response1 = await createTestClient(PROXY_PORT + 4, TEST_DATA);
|
||||||
expect(response1).toEqual(`Echo: ${TEST_DATA}`);
|
expect(response1).toEqual(`Echo: ${TEST_DATA}`);
|
||||||
|
|
||||||
await firstProxyDefault.stop();
|
await firstProxyDefault.stop();
|
||||||
await secondProxyDefault.stop();
|
await secondProxyDefault.stop();
|
||||||
|
|
||||||
// Test 2: With IP preservation
|
// Chained proxies with IP preservation.
|
||||||
const firstProxyPreserved = new PortProxy({
|
const firstProxyPreserved = new PortProxy({
|
||||||
fromPort: PROXY_PORT + 6,
|
fromPort: PROXY_PORT + 6,
|
||||||
toPort: PROXY_PORT + 7,
|
toPort: PROXY_PORT + 7,
|
||||||
targetIP: 'localhost',
|
targetIP: 'localhost',
|
||||||
domains: [],
|
domainConfigs: [],
|
||||||
sniEnabled: false,
|
sniEnabled: false,
|
||||||
defaultAllowedIPs: ['127.0.0.1'],
|
defaultAllowedIPs: ['127.0.0.1'],
|
||||||
preserveSourceIP: true,
|
preserveSourceIP: true,
|
||||||
globalPortRanges: []
|
globalPortRanges: []
|
||||||
});
|
});
|
||||||
|
|
||||||
const secondProxyPreserved = new PortProxy({
|
const secondProxyPreserved = new PortProxy({
|
||||||
fromPort: PROXY_PORT + 7,
|
fromPort: PROXY_PORT + 7,
|
||||||
toPort: TEST_SERVER_PORT,
|
toPort: TEST_SERVER_PORT,
|
||||||
targetIP: 'localhost',
|
targetIP: 'localhost',
|
||||||
domains: [],
|
domainConfigs: [],
|
||||||
sniEnabled: false,
|
sniEnabled: false,
|
||||||
defaultAllowedIPs: ['127.0.0.1'],
|
defaultAllowedIPs: ['127.0.0.1'],
|
||||||
preserveSourceIP: true,
|
preserveSourceIP: true,
|
||||||
globalPortRanges: []
|
globalPortRanges: []
|
||||||
});
|
});
|
||||||
|
|
||||||
await secondProxyPreserved.start();
|
await secondProxyPreserved.start();
|
||||||
await firstProxyPreserved.start();
|
await firstProxyPreserved.start();
|
||||||
|
|
||||||
// This should work with just IPv4 because source IP is preserved
|
|
||||||
const response2 = await createTestClient(PROXY_PORT + 6, TEST_DATA);
|
const response2 = await createTestClient(PROXY_PORT + 6, TEST_DATA);
|
||||||
expect(response2).toEqual(`Echo: ${TEST_DATA}`);
|
expect(response2).toEqual(`Echo: ${TEST_DATA}`);
|
||||||
|
|
||||||
await firstProxyPreserved.stop();
|
await firstProxyPreserved.stop();
|
||||||
await secondProxyPreserved.stop();
|
await secondProxyPreserved.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test round-robin behavior for multiple target IPs in a domain config.
|
||||||
|
tap.test('should use round robin for multiple target IPs in domain config', async () => {
|
||||||
|
const domainConfig = {
|
||||||
|
domains: ['rr.test'],
|
||||||
|
allowedIPs: ['127.0.0.1'],
|
||||||
|
targetIPs: ['hostA', 'hostB']
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const proxyInstance = new PortProxy({
|
||||||
|
fromPort: 0,
|
||||||
|
toPort: 0,
|
||||||
|
targetIP: 'localhost',
|
||||||
|
domainConfigs: [domainConfig],
|
||||||
|
sniEnabled: false,
|
||||||
|
defaultAllowedIPs: [],
|
||||||
|
globalPortRanges: []
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstTarget = (proxyInstance as any).getTargetIP(domainConfig);
|
||||||
|
const secondTarget = (proxyInstance as any).getTargetIP(domainConfig);
|
||||||
|
expect(firstTarget).toEqual('hostA');
|
||||||
|
expect(secondTarget).toEqual('hostB');
|
||||||
|
});
|
||||||
|
|
||||||
|
// CLEANUP: Tear down the test server.
|
||||||
tap.test('cleanup port proxy test environment', async () => {
|
tap.test('cleanup port proxy test environment', async () => {
|
||||||
await new Promise<void>((resolve) => testServer.close(() => resolve()));
|
await new Promise<void>((resolve) => testServer.close(() => resolve()));
|
||||||
});
|
});
|
||||||
@ -248,7 +242,6 @@ process.on('exit', () => {
|
|||||||
if (testServer) {
|
if (testServer) {
|
||||||
testServer.close();
|
testServer.close();
|
||||||
}
|
}
|
||||||
// Use a cast to access the private property for cleanup.
|
|
||||||
if (portProxy && (portProxy as any).netServers) {
|
if (portProxy && (portProxy as any).netServers) {
|
||||||
portProxy.stop();
|
portProxy.stop();
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartproxy',
|
name: '@push.rocks/smartproxy',
|
||||||
version: '3.17.1',
|
version: '3.22.1',
|
||||||
description: 'A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, and dynamic routing with authentication options.'
|
description: 'A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, and dynamic routing with authentication options.'
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user