feat(nftables): Add NFTables integration for kernel-level forwarding and update documentation, tests, and helper functions
This commit is contained in:
		| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@push.rocks/smartproxy', | ||||
|   version: '18.0.2', | ||||
|   version: '18.1.0', | ||||
|   description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.' | ||||
| } | ||||
|   | ||||
| @@ -115,6 +115,8 @@ export class WebSocketHandler { | ||||
|    * Handle a new WebSocket connection | ||||
|    */ | ||||
|   private handleWebSocketConnection(wsIncoming: IWebSocketWithHeartbeat, req: plugins.http.IncomingMessage): void { | ||||
|     this.logger.debug(`WebSocket connection initiated from ${req.headers.host}`); | ||||
|      | ||||
|     try { | ||||
|       // Initialize heartbeat tracking | ||||
|       wsIncoming.isAlive = true; | ||||
| @@ -217,6 +219,8 @@ export class WebSocketHandler { | ||||
|             host: selectedHost, | ||||
|             port: targetPort | ||||
|           }; | ||||
|            | ||||
|           this.logger.debug(`WebSocket destination resolved: ${selectedHost}:${targetPort}`); | ||||
|         } catch (err) { | ||||
|           this.logger.error(`Error evaluating function-based target for WebSocket: ${err}`); | ||||
|           wsIncoming.close(1011, 'Internal server error'); | ||||
| @@ -240,7 +244,10 @@ export class WebSocketHandler { | ||||
|       } | ||||
|        | ||||
|       // Build target URL with potential path rewriting | ||||
|       const protocol = (req.socket as any).encrypted ? 'wss' : 'ws'; | ||||
|       // Determine protocol based on the target's configuration | ||||
|       // For WebSocket connections, we use ws for HTTP backends and wss for HTTPS backends | ||||
|       const isTargetSecure = destination.port === 443; | ||||
|       const protocol = isTargetSecure ? 'wss' : 'ws'; | ||||
|       let targetPath = req.url || '/'; | ||||
|  | ||||
|       // Apply path rewriting if configured | ||||
| @@ -319,7 +326,12 @@ export class WebSocketHandler { | ||||
|       } | ||||
|  | ||||
|       // Create outgoing WebSocket connection | ||||
|       this.logger.debug(`Creating WebSocket connection to ${targetUrl} with options:`, { | ||||
|         headers: wsOptions.headers, | ||||
|         protocols: wsOptions.protocols | ||||
|       }); | ||||
|       const wsOutgoing = new plugins.wsDefault(targetUrl, wsOptions); | ||||
|       this.logger.debug(`WebSocket instance created, waiting for connection...`); | ||||
|        | ||||
|       // Handle connection errors | ||||
|       wsOutgoing.on('error', (err) => { | ||||
| @@ -331,6 +343,7 @@ export class WebSocketHandler { | ||||
|        | ||||
|       // Handle outgoing connection open | ||||
|       wsOutgoing.on('open', () => { | ||||
|         this.logger.debug(`WebSocket target connection opened to ${targetUrl}`); | ||||
|         // Set up custom ping interval if configured | ||||
|         let pingInterval: NodeJS.Timeout | null = null; | ||||
|         if (route?.action.websocket?.pingInterval && route.action.websocket.pingInterval > 0) { | ||||
| @@ -376,6 +389,7 @@ export class WebSocketHandler { | ||||
|  | ||||
|         // Forward incoming messages to outgoing connection | ||||
|         wsIncoming.on('message', (data, isBinary) => { | ||||
|           this.logger.debug(`WebSocket forwarding message from client to target: ${data.toString()}`); | ||||
|           if (wsOutgoing.readyState === wsOutgoing.OPEN) { | ||||
|             // Check message size if limit is set | ||||
|             const messageSize = getMessageSize(data); | ||||
| @@ -386,13 +400,18 @@ export class WebSocketHandler { | ||||
|             } | ||||
|  | ||||
|             wsOutgoing.send(data, { binary: isBinary }); | ||||
|           } else { | ||||
|             this.logger.warn(`WebSocket target connection not open (state: ${wsOutgoing.readyState})`); | ||||
|           } | ||||
|         }); | ||||
|  | ||||
|         // Forward outgoing messages to incoming connection | ||||
|         wsOutgoing.on('message', (data, isBinary) => { | ||||
|           this.logger.debug(`WebSocket forwarding message from target to client: ${data.toString()}`); | ||||
|           if (wsIncoming.readyState === wsIncoming.OPEN) { | ||||
|             wsIncoming.send(data, { binary: isBinary }); | ||||
|           } else { | ||||
|             this.logger.warn(`WebSocket client connection not open (state: ${wsIncoming.readyState})`); | ||||
|           } | ||||
|         }); | ||||
|  | ||||
| @@ -400,7 +419,9 @@ export class WebSocketHandler { | ||||
|         wsIncoming.on('close', (code, reason) => { | ||||
|           this.logger.debug(`WebSocket client connection closed: ${code} ${reason}`); | ||||
|           if (wsOutgoing.readyState === wsOutgoing.OPEN) { | ||||
|             wsOutgoing.close(code, reason); | ||||
|             const validCode = code || 1000; | ||||
|             const reasonString = toBuffer(reason).toString(); | ||||
|             wsOutgoing.close(validCode, reasonString); | ||||
|           } | ||||
|  | ||||
|           // Clean up timers | ||||
| @@ -411,7 +432,9 @@ export class WebSocketHandler { | ||||
|         wsOutgoing.on('close', (code, reason) => { | ||||
|           this.logger.debug(`WebSocket target connection closed: ${code} ${reason}`); | ||||
|           if (wsIncoming.readyState === wsIncoming.OPEN) { | ||||
|             wsIncoming.close(code, reason); | ||||
|             const validCode = code || 1000; | ||||
|             const reasonString = toBuffer(reason).toString(); | ||||
|             wsIncoming.close(validCode, reasonString); | ||||
|           } | ||||
|  | ||||
|           // Clean up timers | ||||
|   | ||||
		Reference in New Issue
	
	Block a user