import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as net from 'net'; import { SmartProxy } from '../ts/proxies/smart-proxy/smart-proxy.js'; let testServer: net.Server; let smartProxy: SmartProxy; tap.test('setup test server', async () => { // Create a test server that handles connections testServer = await new Promise((resolve) => { const server = net.createServer((socket) => { console.log('Test server: Client connected'); socket.write('Welcome from test server\n'); socket.on('data', (data) => { console.log(`Test server received: ${data.toString().trim()}`); socket.write(`Echo: ${data}`); }); socket.on('close', () => { console.log('Test server: Client disconnected'); }); }); server.listen(6789, () => { console.log('Test server listening on port 6789'); resolve(server); }); }); }); tap.test('regular forward route should work correctly', async () => { smartProxy = new SmartProxy({ routes: [{ id: 'test-forward', name: 'Test Forward Route', match: { ports: 7890 }, action: { type: 'forward', target: { host: 'localhost', port: 6789 } } }] }); await smartProxy.start(); // Create a client connection const client = await new Promise((resolve, reject) => { const socket = net.connect(7890, 'localhost', () => { console.log('Client connected to proxy'); resolve(socket); }); socket.on('error', reject); }); // Test data exchange const response = await new Promise((resolve) => { client.on('data', (data) => { resolve(data.toString()); }); }); expect(response).toContain('Welcome from test server'); // Send data through proxy client.write('Test message'); const echo = await new Promise((resolve) => { client.once('data', (data) => { resolve(data.toString()); }); }); expect(echo).toContain('Echo: Test message'); client.end(); await smartProxy.stop(); }); tap.test('NFTables forward route should not terminate connections', async () => { smartProxy = new SmartProxy({ routes: [{ id: 'nftables-test', name: 'NFTables Test Route', match: { ports: 7891 }, action: { type: 'forward', forwardingEngine: 'nftables', target: { host: 'localhost', port: 6789 } } }] }); await smartProxy.start(); // Create a client connection const client = await new Promise((resolve, reject) => { const socket = net.connect(7891, 'localhost', () => { console.log('Client connected to NFTables proxy'); resolve(socket); }); socket.on('error', reject); }); // With NFTables, the connection should stay open at the application level // even though forwarding happens at kernel level let connectionClosed = false; client.on('close', () => { connectionClosed = true; }); // Wait a bit to ensure connection isn't immediately closed await new Promise(resolve => setTimeout(resolve, 1000)); expect(connectionClosed).toBe(false); console.log('NFTables connection stayed open as expected'); client.end(); await smartProxy.stop(); }); tap.test('cleanup', async () => { if (testServer) { testServer.close(); } if (smartProxy) { await smartProxy.stop(); } }); export default tap.start();