| 
						 
						
						
						
						 
					 | 
					 | 
					@@ -1,5 +1,9 @@
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import * as plugins from './plugins.js';
 | 
					 | 
					 | 
					 | 
					import * as plugins from './plugins.js';
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import type { IConnectionRecord, IDomainConfig, IPortProxySettings } from './classes.pp.interfaces.js';
 | 
					 | 
					 | 
					 | 
					import type {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  IConnectionRecord,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  IDomainConfig,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  IPortProxySettings,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					} from './classes.pp.interfaces.js';
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import { ConnectionManager } from './classes.pp.connectionmanager.js';
 | 
					 | 
					 | 
					 | 
					import { ConnectionManager } from './classes.pp.connectionmanager.js';
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import { SecurityManager } from './classes.pp.securitymanager.js';
 | 
					 | 
					 | 
					 | 
					import { SecurityManager } from './classes.pp.securitymanager.js';
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import { DomainConfigManager } from './classes.pp.domainconfigmanager.js';
 | 
					 | 
					 | 
					 | 
					import { DomainConfigManager } from './classes.pp.domainconfigmanager.js';
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -73,8 +77,8 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if (this.settings.enableDetailedLogging) {
 | 
					 | 
					 | 
					 | 
					    if (this.settings.enableDetailedLogging) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      console.log(
 | 
					 | 
					 | 
					 | 
					      console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        `[${connectionId}] New connection from ${remoteIP} on port ${localPort}. ` +
 | 
					 | 
					 | 
					 | 
					        `[${connectionId}] New connection from ${remoteIP} on port ${localPort}. ` +
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        `Keep-Alive: ${record.hasKeepAlive ? 'Enabled' : 'Disabled'}. ` +
 | 
					 | 
					 | 
					 | 
					          `Keep-Alive: ${record.hasKeepAlive ? 'Enabled' : 'Disabled'}. ` +
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        `Active connections: ${this.connectionManager.getConnectionCount()}`
 | 
					 | 
					 | 
					 | 
					          `Active connections: ${this.connectionManager.getConnectionCount()}`
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      );
 | 
					 | 
					 | 
					 | 
					      );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } else {
 | 
					 | 
					 | 
					 | 
					    } else {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      console.log(
 | 
					 | 
					 | 
					 | 
					      console.log(
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -94,7 +98,10 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /**
 | 
					 | 
					 | 
					 | 
					  /**
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * Handle a connection that should be forwarded to NetworkProxy
 | 
					 | 
					 | 
					 | 
					   * Handle a connection that should be forwarded to NetworkProxy
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   */
 | 
					 | 
					 | 
					 | 
					   */
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  private handleNetworkProxyConnection(socket: plugins.net.Socket, record: IConnectionRecord): void {
 | 
					 | 
					 | 
					 | 
					  private handleNetworkProxyConnection(
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    socket: plugins.net.Socket,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    record: IConnectionRecord
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  ): void {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const connectionId = record.id;
 | 
					 | 
					 | 
					 | 
					    const connectionId = record.id;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let initialDataReceived = false;
 | 
					 | 
					 | 
					 | 
					    let initialDataReceived = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -104,7 +111,7 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        console.log(
 | 
					 | 
					 | 
					 | 
					        console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          `[${connectionId}] Initial data warning (${this.settings.initialDataTimeout}ms) for connection from ${record.remoteIP}`
 | 
					 | 
					 | 
					 | 
					          `[${connectionId}] Initial data warning (${this.settings.initialDataTimeout}ms) for connection from ${record.remoteIP}`
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        );
 | 
					 | 
					 | 
					 | 
					        );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Add a grace period instead of immediate termination
 | 
					 | 
					 | 
					 | 
					        // Add a grace period instead of immediate termination
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        setTimeout(() => {
 | 
					 | 
					 | 
					 | 
					        setTimeout(() => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (!initialDataReceived) {
 | 
					 | 
					 | 
					 | 
					          if (!initialDataReceived) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -144,7 +151,7 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (!this.tlsManager.isTlsHandshake(chunk) && localPort === 443) {
 | 
					 | 
					 | 
					 | 
					      if (!this.tlsManager.isTlsHandshake(chunk) && localPort === 443) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        console.log(
 | 
					 | 
					 | 
					 | 
					        console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          `[${connectionId}] Non-TLS connection detected on port 443. ` +
 | 
					 | 
					 | 
					 | 
					          `[${connectionId}] Non-TLS connection detected on port 443. ` +
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          `Terminating connection - only TLS traffic is allowed on standard HTTPS port.`
 | 
					 | 
					 | 
					 | 
					            `Terminating connection - only TLS traffic is allowed on standard HTTPS port.`
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        );
 | 
					 | 
					 | 
					 | 
					        );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (record.incomingTerminationReason === null) {
 | 
					 | 
					 | 
					 | 
					        if (record.incomingTerminationReason === null) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          record.incomingTerminationReason = 'non_tls_blocked';
 | 
					 | 
					 | 
					 | 
					          record.incomingTerminationReason = 'non_tls_blocked';
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -159,8 +166,8 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (this.tlsManager.isTlsHandshake(chunk)) {
 | 
					 | 
					 | 
					 | 
					      if (this.tlsManager.isTlsHandshake(chunk)) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        record.isTLS = true;
 | 
					 | 
					 | 
					 | 
					        record.isTLS = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Check session tickets if they're disabled
 | 
					 | 
					 | 
					 | 
					        // Check for ClientHello to extract SNI - but don't enforce it for NetworkProxy
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (this.settings.allowSessionTicket === false && this.tlsManager.isClientHello(chunk)) {
 | 
					 | 
					 | 
					 | 
					        if (this.tlsManager.isClientHello(chunk)) {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // Create connection info for SNI extraction
 | 
					 | 
					 | 
					 | 
					          // Create connection info for SNI extraction
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          const connInfo = {
 | 
					 | 
					 | 
					 | 
					          const connInfo = {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            sourceIp: record.remoteIP,
 | 
					 | 
					 | 
					 | 
					            sourceIp: record.remoteIP,
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -169,83 +176,46 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            destPort: socket.localPort || 0,
 | 
					 | 
					 | 
					 | 
					            destPort: socket.localPort || 0,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          };
 | 
					 | 
					 | 
					 | 
					          };
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // Extract SNI for domain-specific NetworkProxy handling
 | 
					 | 
					 | 
					 | 
					          // Extract SNI for domain-specific NetworkProxy handling if available
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          const serverName = this.tlsManager.extractSNI(chunk, connInfo);
 | 
					 | 
					 | 
					 | 
					          const serverName = this.tlsManager.extractSNI(chunk, connInfo);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // If allowSessionTicket is false and we can't determine SNI, terminate the connection
 | 
					 | 
					 | 
					 | 
					          // For NetworkProxy connections, we'll allow session tickets even without SNI
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (!serverName) {
 | 
					 | 
					 | 
					 | 
					          // We'll only use the serverName if available to determine the specific NetworkProxy port
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // Always block when allowSessionTicket is false and there's no SNI
 | 
					 | 
					 | 
					 | 
					          if (serverName) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            console.log(
 | 
					 | 
					 | 
					 | 
					            // Save domain config and SNI in connection record
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              `[${connectionId}] No SNI detected in ClientHello and allowSessionTicket=false. ` +
 | 
					 | 
					 | 
					 | 
					            const domainConfig = this.domainConfigManager.findDomainConfig(serverName);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              `Terminating connection to force new TLS handshake with SNI.`
 | 
					 | 
					 | 
					 | 
					            record.domainConfig = domainConfig;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            );
 | 
					 | 
					 | 
					 | 
					            record.lockedDomain = serverName;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // Send a proper TLS alert before ending the connection
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // Using "unrecognized_name" (112) alert which is a warning level alert (1) 
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // that encourages clients to retry with proper SNI
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            const alertData = Buffer.from([
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x15,       // Alert record type
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x03, 0x03, // TLS 1.2 version
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x00, 0x02, // Length
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x01,       // Warning alert level (not fatal)
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x70        // unrecognized_name alert (code 112)
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            ]);
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            try {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              socket.write(alertData, () => {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                // Only close the socket after we're sure the alert was sent
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                // Give the alert time to be processed by the client
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                setTimeout(() => {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  socket.end();
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  // Ensure complete cleanup happens a bit later
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  setTimeout(() => {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    if (!socket.destroyed) {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                      socket.destroy();
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    }
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  }, 100);
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                }, 100);
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              });
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            } catch (err) {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              // If we can't send the alert, fall back to immediate termination
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              socket.end();
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            }
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            if (record.incomingTerminationReason === null) {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              record.incomingTerminationReason = 'session_ticket_blocked_no_sni';
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              this.connectionManager.incrementTerminationStat('incoming', 'session_ticket_blocked_no_sni');
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            }
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            return;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          }
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // Save domain config and SNI in connection record
 | 
					 | 
					 | 
					 | 
					            // Use domain-specific NetworkProxy port if configured
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          const domainConfig = this.domainConfigManager.findDomainConfig(serverName);
 | 
					 | 
					 | 
					 | 
					            if (domainConfig && this.domainConfigManager.shouldUseNetworkProxy(domainConfig)) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          record.domainConfig = domainConfig;
 | 
					 | 
					 | 
					 | 
					              const networkProxyPort = this.domainConfigManager.getNetworkProxyPort(domainConfig);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          record.lockedDomain = serverName;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // Use domain-specific NetworkProxy port if configured
 | 
					 | 
					 | 
					 | 
					              if (this.settings.enableDetailedLogging) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (domainConfig && this.domainConfigManager.shouldUseNetworkProxy(domainConfig)) {
 | 
					 | 
					 | 
					 | 
					                console.log(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            const networkProxyPort = this.domainConfigManager.getNetworkProxyPort(domainConfig);
 | 
					 | 
					 | 
					 | 
					                  `[${connectionId}] Using domain-specific NetworkProxy for ${serverName} on port ${networkProxyPort}`
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            if (this.settings.enableDetailedLogging) {
 | 
					 | 
					 | 
					 | 
					              // Forward to NetworkProxy with domain-specific port
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              console.log(
 | 
					 | 
					 | 
					 | 
					              this.networkProxyBridge.forwardToNetworkProxy(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                `[${connectionId}] Using domain-specific NetworkProxy for ${serverName} on port ${networkProxyPort}`
 | 
					 | 
					 | 
					 | 
					                connectionId,
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                socket,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                record,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                chunk,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                networkProxyPort,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                (reason) => this.connectionManager.initiateCleanupOnce(record, reason)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              );
 | 
					 | 
					 | 
					 | 
					              );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              return;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            }
 | 
					 | 
					 | 
					 | 
					            }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					          } else if (
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // Forward to NetworkProxy with domain-specific port
 | 
					 | 
					 | 
					 | 
					            this.settings.allowSessionTicket === false &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            this.networkProxyBridge.forwardToNetworkProxy(
 | 
					 | 
					 | 
					 | 
					            this.settings.enableDetailedLogging
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              connectionId,
 | 
					 | 
					 | 
					 | 
					          ) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              socket,
 | 
					 | 
					 | 
					 | 
					            // Log that we're allowing a session resumption without SNI for NetworkProxy
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              record,
 | 
					 | 
					 | 
					 | 
					            console.log(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              chunk,
 | 
					 | 
					 | 
					 | 
					              `[${connectionId}] Allowing session resumption without SNI for NetworkProxy forwarding`
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              networkProxyPort,
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              (reason) => this.connectionManager.initiateCleanupOnce(record, reason)
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            );
 | 
					 | 
					 | 
					 | 
					            );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            return;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          }
 | 
					 | 
					 | 
					 | 
					          }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -260,14 +230,10 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        );
 | 
					 | 
					 | 
					 | 
					        );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      } else {
 | 
					 | 
					 | 
					 | 
					      } else {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // If not TLS, use normal direct connection
 | 
					 | 
					 | 
					 | 
					        // If not TLS, use normal direct connection
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        console.log(`[${connectionId}] Non-TLS connection on NetworkProxy port ${record.localPort}`);
 | 
					 | 
					 | 
					 | 
					        console.log(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        this.setupDirectConnection(
 | 
					 | 
					 | 
					 | 
					          `[${connectionId}] Non-TLS connection on NetworkProxy port ${record.localPort}`
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          socket,
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          record,
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          undefined,
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          undefined,
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          chunk
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        );
 | 
					 | 
					 | 
					 | 
					        );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        this.setupDirectConnection(socket, record, undefined, undefined, chunk);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      }
 | 
					 | 
					 | 
					 | 
					      }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    });
 | 
					 | 
					 | 
					 | 
					    });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }
 | 
					 | 
					 | 
					 | 
					  }
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -300,7 +266,7 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          console.log(
 | 
					 | 
					 | 
					 | 
					          console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            `[${connectionId}] Initial data warning (${this.settings.initialDataTimeout}ms) for connection from ${record.remoteIP}`
 | 
					 | 
					 | 
					 | 
					            `[${connectionId}] Initial data warning (${this.settings.initialDataTimeout}ms) for connection from ${record.remoteIP}`
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          );
 | 
					 | 
					 | 
					 | 
					          );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // Add a grace period instead of immediate termination
 | 
					 | 
					 | 
					 | 
					          // Add a grace period instead of immediate termination
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          setTimeout(() => {
 | 
					 | 
					 | 
					 | 
					          setTimeout(() => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            if (!initialDataReceived) {
 | 
					 | 
					 | 
					 | 
					            if (!initialDataReceived) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -385,14 +351,13 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      record.domainConfig = domainConfig;
 | 
					 | 
					 | 
					 | 
					      record.domainConfig = domainConfig;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Check if this domain should use NetworkProxy (domain-specific setting)
 | 
					 | 
					 | 
					 | 
					      // Check if this domain should use NetworkProxy (domain-specific setting)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (domainConfig && 
 | 
					 | 
					 | 
					 | 
					      if (
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          this.domainConfigManager.shouldUseNetworkProxy(domainConfig) && 
 | 
					 | 
					 | 
					 | 
					        domainConfig &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          this.networkProxyBridge.getNetworkProxy()) {
 | 
					 | 
					 | 
					 | 
					        this.domainConfigManager.shouldUseNetworkProxy(domainConfig) &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					        this.networkProxyBridge.getNetworkProxy()
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      ) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (this.settings.enableDetailedLogging) {
 | 
					 | 
					 | 
					 | 
					        if (this.settings.enableDetailedLogging) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          console.log(
 | 
					 | 
					 | 
					 | 
					          console.log(`[${connectionId}] Domain ${serverName} is configured to use NetworkProxy`);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            `[${connectionId}] Domain ${serverName} is configured to use NetworkProxy`
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          );
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        const networkProxyPort = this.domainConfigManager.getNetworkProxyPort(domainConfig);
 | 
					 | 
					 | 
					 | 
					        const networkProxyPort = this.domainConfigManager.getNetworkProxyPort(domainConfig);
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -414,23 +379,24 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // IP validation
 | 
					 | 
					 | 
					 | 
					      // IP validation
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (domainConfig) {
 | 
					 | 
					 | 
					 | 
					      if (domainConfig) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        const ipRules = this.domainConfigManager.getEffectiveIPRules(domainConfig);
 | 
					 | 
					 | 
					 | 
					        const ipRules = this.domainConfigManager.getEffectiveIPRules(domainConfig);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Skip IP validation if allowedIPs is empty
 | 
					 | 
					 | 
					 | 
					        // Skip IP validation if allowedIPs is empty
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (
 | 
					 | 
					 | 
					 | 
					        if (
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          domainConfig.allowedIPs.length > 0 &&
 | 
					 | 
					 | 
					 | 
					          domainConfig.allowedIPs.length > 0 &&
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          !this.securityManager.isIPAuthorized(record.remoteIP, ipRules.allowedIPs, ipRules.blockedIPs)
 | 
					 | 
					 | 
					 | 
					          !this.securityManager.isIPAuthorized(
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            record.remoteIP,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ipRules.allowedIPs,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ipRules.blockedIPs
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          )
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        ) {
 | 
					 | 
					 | 
					 | 
					        ) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          return rejectIncomingConnection(
 | 
					 | 
					 | 
					 | 
					          return rejectIncomingConnection(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            'rejected',
 | 
					 | 
					 | 
					 | 
					            'rejected',
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            `Connection rejected: IP ${record.remoteIP} not allowed for domain ${domainConfig.domains.join(
 | 
					 | 
					 | 
					 | 
					            `Connection rejected: IP ${
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              ', '
 | 
					 | 
					 | 
					 | 
					              record.remoteIP
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            )}`
 | 
					 | 
					 | 
					 | 
					            } not allowed for domain ${domainConfig.domains.join(', ')}`
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          );
 | 
					 | 
					 | 
					 | 
					          );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      } else if (
 | 
					 | 
					 | 
					 | 
					      } else if (this.settings.defaultAllowedIPs && this.settings.defaultAllowedIPs.length > 0) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        this.settings.defaultAllowedIPs &&
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        this.settings.defaultAllowedIPs.length > 0
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      ) {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (
 | 
					 | 
					 | 
					 | 
					        if (
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          !this.securityManager.isIPAuthorized(
 | 
					 | 
					 | 
					 | 
					          !this.securityManager.isIPAuthorized(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            record.remoteIP,
 | 
					 | 
					 | 
					 | 
					            record.remoteIP,
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -497,28 +463,36 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      } else {
 | 
					 | 
					 | 
					 | 
					      } else {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Attempt to find a matching forced domain config based on the local port.
 | 
					 | 
					 | 
					 | 
					        // Attempt to find a matching forced domain config based on the local port.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        const forcedDomain = this.domainConfigManager.findDomainConfigForPort(localPort);
 | 
					 | 
					 | 
					 | 
					        const forcedDomain = this.domainConfigManager.findDomainConfigForPort(localPort);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (forcedDomain) {
 | 
					 | 
					 | 
					 | 
					        if (forcedDomain) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          const ipRules = this.domainConfigManager.getEffectiveIPRules(forcedDomain);
 | 
					 | 
					 | 
					 | 
					          const ipRules = this.domainConfigManager.getEffectiveIPRules(forcedDomain);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (!this.securityManager.isIPAuthorized(record.remoteIP, ipRules.allowedIPs, ipRules.blockedIPs)) {
 | 
					 | 
					 | 
					 | 
					          if (
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            !this.securityManager.isIPAuthorized(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              record.remoteIP,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              ipRules.allowedIPs,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              ipRules.blockedIPs
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            )
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          ) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            console.log(
 | 
					 | 
					 | 
					 | 
					            console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              `[${connectionId}] Connection from ${record.remoteIP} rejected: IP not allowed for domain ${forcedDomain.domains.join(
 | 
					 | 
					 | 
					 | 
					              `[${connectionId}] Connection from ${
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                record.remoteIP
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              } rejected: IP not allowed for domain ${forcedDomain.domains.join(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                ', '
 | 
					 | 
					 | 
					 | 
					                ', '
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              )} on port ${localPort}.`
 | 
					 | 
					 | 
					 | 
					              )} on port ${localPort}.`
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            );
 | 
					 | 
					 | 
					 | 
					            );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            socket.end();
 | 
					 | 
					 | 
					 | 
					            socket.end();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            return;
 | 
					 | 
					 | 
					 | 
					            return;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          }
 | 
					 | 
					 | 
					 | 
					          }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (this.settings.enableDetailedLogging) {
 | 
					 | 
					 | 
					 | 
					          if (this.settings.enableDetailedLogging) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            console.log(
 | 
					 | 
					 | 
					 | 
					            console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              `[${connectionId}] Port-based connection from ${record.remoteIP} on port ${localPort} matched domain ${forcedDomain.domains.join(
 | 
					 | 
					 | 
					 | 
					              `[${connectionId}] Port-based connection from ${
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                ', '
 | 
					 | 
					 | 
					 | 
					                record.remoteIP
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              )}.`
 | 
					 | 
					 | 
					 | 
					              } on port ${localPort} matched domain ${forcedDomain.domains.join(', ')}.`
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            );
 | 
					 | 
					 | 
					 | 
					            );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          }
 | 
					 | 
					 | 
					 | 
					          }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          setupConnection('', undefined, forcedDomain, localPort);
 | 
					 | 
					 | 
					 | 
					          setupConnection('', undefined, forcedDomain, localPort);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          return;
 | 
					 | 
					 | 
					 | 
					          return;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -536,14 +510,14 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          clearTimeout(initialTimeout);
 | 
					 | 
					 | 
					 | 
					          clearTimeout(initialTimeout);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          initialTimeout = null;
 | 
					 | 
					 | 
					 | 
					          initialTimeout = null;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        initialDataReceived = true;
 | 
					 | 
					 | 
					 | 
					        initialDataReceived = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Block non-TLS connections on port 443
 | 
					 | 
					 | 
					 | 
					        // Block non-TLS connections on port 443
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (!this.tlsManager.isTlsHandshake(chunk) && localPort === 443) {
 | 
					 | 
					 | 
					 | 
					        if (!this.tlsManager.isTlsHandshake(chunk) && localPort === 443) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          console.log(
 | 
					 | 
					 | 
					 | 
					          console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            `[${connectionId}] Non-TLS connection detected on port 443 in SNI handler. ` +
 | 
					 | 
					 | 
					 | 
					            `[${connectionId}] Non-TLS connection detected on port 443 in SNI handler. ` +
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            `Terminating connection - only TLS traffic is allowed on standard HTTPS port.`
 | 
					 | 
					 | 
					 | 
					              `Terminating connection - only TLS traffic is allowed on standard HTTPS port.`
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          );
 | 
					 | 
					 | 
					 | 
					          );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (record.incomingTerminationReason === null) {
 | 
					 | 
					 | 
					 | 
					          if (record.incomingTerminationReason === null) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            record.incomingTerminationReason = 'non_tls_blocked';
 | 
					 | 
					 | 
					 | 
					            record.incomingTerminationReason = 'non_tls_blocked';
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -576,56 +550,105 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // Extract SNI
 | 
					 | 
					 | 
					 | 
					          // Extract SNI
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          serverName = this.tlsManager.extractSNI(chunk, connInfo) || '';
 | 
					 | 
					 | 
					 | 
					          serverName = this.tlsManager.extractSNI(chunk, connInfo) || '';
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // If allowSessionTicket is false and this is a ClientHello with no SNI, terminate the connection
 | 
					 | 
					 | 
					 | 
					          // If allowSessionTicket is false and this is a ClientHello with no SNI, terminate the connection
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (this.settings.allowSessionTicket === false && 
 | 
					 | 
					 | 
					 | 
					          if (
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              this.tlsManager.isClientHello(chunk) && 
 | 
					 | 
					 | 
					 | 
					            this.settings.allowSessionTicket === false &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              !serverName) {
 | 
					 | 
					 | 
					 | 
					            this.tlsManager.isClientHello(chunk) &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					            !serverName
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // Always block ClientHello without SNI when allowSessionTicket is false
 | 
					 | 
					 | 
					 | 
					          ) {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            // Block ClientHello without SNI when allowSessionTicket is false
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            console.log(
 | 
					 | 
					 | 
					 | 
					            console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              `[${connectionId}] No SNI detected in ClientHello and allowSessionTicket=false. ` +
 | 
					 | 
					 | 
					 | 
					              `[${connectionId}] No SNI detected in ClientHello and allowSessionTicket=false. ` +
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              `Terminating connection to force new TLS handshake with SNI.`
 | 
					 | 
					 | 
					 | 
					                `Sending warning unrecognized_name alert to encourage immediate retry with SNI.`
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            );
 | 
					 | 
					 | 
					 | 
					            );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // Send a proper TLS alert before ending the connection
 | 
					 | 
					 | 
					 | 
					            // Set the termination reason first
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // Using "unrecognized_name" (112) alert which is a warning level alert (1) 
 | 
					 | 
					 | 
					 | 
					            if (record.incomingTerminationReason === null) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // that encourages clients to retry with proper SNI
 | 
					 | 
					 | 
					 | 
					              record.incomingTerminationReason = 'session_ticket_blocked_no_sni';
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            const alertData = Buffer.from([
 | 
					 | 
					 | 
					 | 
					              this.connectionManager.incrementTerminationStat(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x15,       // Alert record type
 | 
					 | 
					 | 
					 | 
					                'incoming',
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x03, 0x03, // TLS 1.2 version
 | 
					 | 
					 | 
					 | 
					                'session_ticket_blocked_no_sni'
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x00, 0x02, // Length
 | 
					 | 
					 | 
					 | 
					              );
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x01,       // Warning alert level (not fatal)
 | 
					 | 
					 | 
					 | 
					            }
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              0x70        // unrecognized_name alert (code 112)
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            // Create a warning-level alert for unrecognized_name
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            // This encourages Chrome to retry immediately with SNI
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            const serverNameUnknownAlertData = Buffer.from([
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x15, // Alert record type
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x03,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x03, // TLS 1.2 version
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x00,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x02, // Length
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x01, // Warning alert level (not fatal)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x70, // unrecognized_name alert (code 112)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            ]);
 | 
					 | 
					 | 
					 | 
					            ]);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            // Send a handshake_failure alert instead of unrecognized_name
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            const sslHandshakeFailureAlertData = Buffer.from([
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x15, // Alert record type
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x03,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x03, // TLS 1.2 version
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x00,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x02, // Length
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x01, // Warning alert level (not fatal)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x28, // handshake_failure alert (40) instead of unrecognized_name (112)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ]);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            const closeNotifyAlert = Buffer.from([
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x15, // Alert record type
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x03,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x03, // TLS 1.2 version
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x00,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x02, // Length
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x01, // Warning alert level (1)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              0x00, // close_notify alert (0)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ]);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            try {
 | 
					 | 
					 | 
					 | 
					            try {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              socket.write(alertData, () => {
 | 
					 | 
					 | 
					 | 
					              // Use cork/uncork to ensure the alert is sent as a single packet
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                // Only close the socket after we're sure the alert was sent
 | 
					 | 
					 | 
					 | 
					              socket.cork();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                // Give the alert time to be processed by the client
 | 
					 | 
					 | 
					 | 
					              const writeSuccessful = socket.write(closeNotifyAlert);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              socket.uncork();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              // Function to handle the clean socket termination
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              const finishConnection = () => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                // First call end() to initiate a graceful close (sends FIN)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                socket.end();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                // Allow a short delay for the alert and FIN to be transmitted
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                // before we fully close the socket
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                setTimeout(() => {
 | 
					 | 
					 | 
					 | 
					                setTimeout(() => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  socket.end();
 | 
					 | 
					 | 
					 | 
					                  if (!socket.destroyed) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  
 | 
					 | 
					 | 
					 | 
					                    socket.destroy();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  // Ensure complete cleanup happens a bit later
 | 
					 | 
					 | 
					 | 
					                  }
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  setTimeout(() => {
 | 
					 | 
					 | 
					 | 
					                  this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    if (!socket.destroyed) {
 | 
					 | 
					 | 
					 | 
					                }, 150); // Short delay, but longer than the standard TCP ACK timeout
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                      socket.destroy();
 | 
					 | 
					 | 
					 | 
					              };
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    }
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
 | 
					 | 
					 | 
					 | 
					              if (writeSuccessful) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                  }, 100);
 | 
					 | 
					 | 
					 | 
					                // If the data was successfully written to the kernel buffer,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                }, 100);
 | 
					 | 
					 | 
					 | 
					                // we can finish the connection after a short delay to ensure transmission
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              });
 | 
					 | 
					 | 
					 | 
					                setTimeout(finishConnection, 50);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              } else {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                // If the kernel buffer was full, wait for the drain event
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                socket.once('drain', () => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                  setTimeout(finishConnection, 50);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                // Set a safety timeout in case drain never happens
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                setTimeout(() => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                  socket.removeAllListeners('drain');
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                  finishConnection();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                }, 250);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            } catch (err) {
 | 
					 | 
					 | 
					 | 
					            } catch (err) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              // If we can't send the alert, fall back to immediate termination
 | 
					 | 
					 | 
					 | 
					              // If we can't send the alert, fall back to immediate termination
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              console.log(`[${connectionId}] Error sending TLS alert: ${err.message}`);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              socket.end();
 | 
					 | 
					 | 
					 | 
					              socket.end();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
 | 
					 | 
					 | 
					 | 
					              this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            }
 | 
					 | 
					 | 
					 | 
					            }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            if (record.incomingTerminationReason === null) {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              record.incomingTerminationReason = 'session_ticket_blocked_no_sni';
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              this.connectionManager.incrementTerminationStat('incoming', 'session_ticket_blocked_no_sni');
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            }
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            return;
 | 
					 | 
					 | 
					 | 
					            return;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          }
 | 
					 | 
					 | 
					 | 
					          }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -674,23 +697,21 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    overridePort?: number
 | 
					 | 
					 | 
					 | 
					    overridePort?: number
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  ): void {
 | 
					 | 
					 | 
					 | 
					  ): void {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const connectionId = record.id;
 | 
					 | 
					 | 
					 | 
					    const connectionId = record.id;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Determine target host
 | 
					 | 
					 | 
					 | 
					    // Determine target host
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const targetHost = domainConfig 
 | 
					 | 
					 | 
					 | 
					    const targetHost = domainConfig
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      ? this.domainConfigManager.getTargetIP(domainConfig) 
 | 
					 | 
					 | 
					 | 
					      ? this.domainConfigManager.getTargetIP(domainConfig)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      : this.settings.targetIP!;
 | 
					 | 
					 | 
					 | 
					      : this.settings.targetIP!;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Determine target port
 | 
					 | 
					 | 
					 | 
					    // Determine target port
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const targetPort = overridePort !== undefined 
 | 
					 | 
					 | 
					 | 
					    const targetPort = overridePort !== undefined ? overridePort : this.settings.toPort;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      ? overridePort 
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      : this.settings.toPort;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Setup connection options
 | 
					 | 
					 | 
					 | 
					    // Setup connection options
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const connectionOptions: plugins.net.NetConnectOpts = {
 | 
					 | 
					 | 
					 | 
					    const connectionOptions: plugins.net.NetConnectOpts = {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      host: targetHost,
 | 
					 | 
					 | 
					 | 
					      host: targetHost,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      port: targetPort,
 | 
					 | 
					 | 
					 | 
					      port: targetPort,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    };
 | 
					 | 
					 | 
					 | 
					    };
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Preserve source IP if configured
 | 
					 | 
					 | 
					 | 
					    // Preserve source IP if configured
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if (this.settings.preserveSourceIP) {
 | 
					 | 
					 | 
					 | 
					    if (this.settings.preserveSourceIP) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      connectionOptions.localAddress = record.remoteIP.replace('::ffff:', '');
 | 
					 | 
					 | 
					 | 
					      connectionOptions.localAddress = record.remoteIP.replace('::ffff:', '');
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -947,18 +968,20 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Process any remaining data in the queue before switching to piping
 | 
					 | 
					 | 
					 | 
					      // Process any remaining data in the queue before switching to piping
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      processDataQueue();
 | 
					 | 
					 | 
					 | 
					      processDataQueue();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Set up piping immediately
 | 
					 | 
					 | 
					 | 
					      // Set up piping immediately
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      pipingEstablished = true;
 | 
					 | 
					 | 
					 | 
					      pipingEstablished = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Flush all pending data to target
 | 
					 | 
					 | 
					 | 
					      // Flush all pending data to target
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (record.pendingData.length > 0) {
 | 
					 | 
					 | 
					 | 
					      if (record.pendingData.length > 0) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        const combinedData = Buffer.concat(record.pendingData);
 | 
					 | 
					 | 
					 | 
					        const combinedData = Buffer.concat(record.pendingData);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (this.settings.enableDetailedLogging) {
 | 
					 | 
					 | 
					 | 
					        if (this.settings.enableDetailedLogging) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          console.log(`[${connectionId}] Forwarding ${combinedData.length} bytes of initial data to target`);
 | 
					 | 
					 | 
					 | 
					          console.log(
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            `[${connectionId}] Forwarding ${combinedData.length} bytes of initial data to target`
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          );
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Write pending data immediately
 | 
					 | 
					 | 
					 | 
					        // Write pending data immediately
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        targetSocket.write(combinedData, (err) => {
 | 
					 | 
					 | 
					 | 
					        targetSocket.write(combinedData, (err) => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (err) {
 | 
					 | 
					 | 
					 | 
					          if (err) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -966,19 +989,19 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            return this.connectionManager.initiateCleanupOnce(record, 'write_error');
 | 
					 | 
					 | 
					 | 
					            return this.connectionManager.initiateCleanupOnce(record, 'write_error');
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          }
 | 
					 | 
					 | 
					 | 
					          }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        });
 | 
					 | 
					 | 
					 | 
					        });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Clear the buffer now that we've processed it
 | 
					 | 
					 | 
					 | 
					        // Clear the buffer now that we've processed it
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        record.pendingData = [];
 | 
					 | 
					 | 
					 | 
					        record.pendingData = [];
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        record.pendingDataSize = 0;
 | 
					 | 
					 | 
					 | 
					        record.pendingDataSize = 0;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      }
 | 
					 | 
					 | 
					 | 
					      }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Setup piping in both directions without any delays
 | 
					 | 
					 | 
					 | 
					      // Setup piping in both directions without any delays
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      socket.pipe(targetSocket);
 | 
					 | 
					 | 
					 | 
					      socket.pipe(targetSocket);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      targetSocket.pipe(socket);
 | 
					 | 
					 | 
					 | 
					      targetSocket.pipe(socket);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Resume the socket to ensure data flows
 | 
					 | 
					 | 
					 | 
					      // Resume the socket to ensure data flows
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      socket.resume();
 | 
					 | 
					 | 
					 | 
					      socket.resume();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Process any data that might be queued in the interim
 | 
					 | 
					 | 
					 | 
					      // Process any data that might be queued in the interim
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (dataQueue.length > 0) {
 | 
					 | 
					 | 
					 | 
					      if (dataQueue.length > 0) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Write any remaining queued data directly to the target socket
 | 
					 | 
					 | 
					 | 
					        // Write any remaining queued data directly to the target socket
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -989,7 +1012,7 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        dataQueue.length = 0;
 | 
					 | 
					 | 
					 | 
					        dataQueue.length = 0;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        queueSize = 0;
 | 
					 | 
					 | 
					 | 
					        queueSize = 0;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      }
 | 
					 | 
					 | 
					 | 
					      }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (this.settings.enableDetailedLogging) {
 | 
					 | 
					 | 
					 | 
					      if (this.settings.enableDetailedLogging) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        console.log(
 | 
					 | 
					 | 
					 | 
					        console.log(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          `[${connectionId}] Connection established: ${record.remoteIP} -> ${targetHost}:${connectionOptions.port}` +
 | 
					 | 
					 | 
					 | 
					          `[${connectionId}] Connection established: ${record.remoteIP} -> ${targetHost}:${connectionOptions.port}` +
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1054,15 +1077,12 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      }
 | 
					 | 
					 | 
					 | 
					      }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Set connection timeout
 | 
					 | 
					 | 
					 | 
					      // Set connection timeout
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      record.cleanupTimer = this.timeoutManager.setupConnectionTimeout(
 | 
					 | 
					 | 
					 | 
					      record.cleanupTimer = this.timeoutManager.setupConnectionTimeout(record, (record, reason) => {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        record,
 | 
					 | 
					 | 
					 | 
					        console.log(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        (record, reason) => {
 | 
					 | 
					 | 
					 | 
					          `[${connectionId}] Connection from ${record.remoteIP} exceeded max lifetime, forcing cleanup.`
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          console.log(
 | 
					 | 
					 | 
					 | 
					        );
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            `[${connectionId}] Connection from ${record.remoteIP} exceeded max lifetime, forcing cleanup.`
 | 
					 | 
					 | 
					 | 
					        this.connectionManager.initiateCleanupOnce(record, reason);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          );
 | 
					 | 
					 | 
					 | 
					      });
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          this.connectionManager.initiateCleanupOnce(record, reason);
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      );
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Mark TLS handshake as complete for TLS connections
 | 
					 | 
					 | 
					 | 
					      // Mark TLS handshake as complete for TLS connections
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (record.isTLS) {
 | 
					 | 
					 | 
					 | 
					      if (record.isTLS) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1076,4 +1096,4 @@ export class ConnectionHandler {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      }
 | 
					 | 
					 | 
					 | 
					      }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    });
 | 
					 | 
					 | 
					 | 
					    });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }
 | 
					 | 
					 | 
					 | 
					  }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
				
				
			
		
	
		
		
	
	
		
		
			
				
					
					| 
						 
						
						
						
						 
					 | 
					 | 
					 
 |