13 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	
			13 KiB
		
	
	
	
	
	
	
	
SmartProxy Unified Forwarding Configuration Plan
Project Goal
Create a clean, use-case driven forwarding configuration interface for SmartProxy that elegantly handles all forwarding scenarios: SNI-based forwarding, termination-based forwarding (NetworkProxy), HTTP forwarding, and ACME challenge forwarding.
Current State
Currently, SmartProxy has several different forwarding mechanisms configured separately:
- HTTPS/SNI forwarding via 
IDomainConfigproperties - NetworkProxy forwarding via 
useNetworkProxyin domain configs - HTTP forwarding via Port80Handler's 
forwardconfiguration - ACME challenge forwarding via 
acmeForwardconfiguration 
This separation creates configuration complexity and reduced cohesion between related settings.
Proposed Solution: Clean Use-Case Driven Forwarding Interface
Phase 1: Design Streamlined Forwarding Interface
- Create a use-case driven 
IForwardConfiginterface that simplifies configuration: 
export interface IForwardConfig {
  // Define the primary forwarding type - use-case driven approach
  type: 'http-only' | 'https-passthrough' | 'https-terminate-to-http' | 'https-terminate-to-https';
  
  // Target configuration
  target: {
    host: string | string[];  // Support single host or round-robin
    port: number;
  };
  
  // HTTP-specific options
  http?: {
    enabled?: boolean;                 // Defaults to true for http-only, optional for others
    redirectToHttps?: boolean;         // Redirect HTTP to HTTPS
    headers?: Record<string, string>;  // Custom headers for HTTP responses
  };
  
  // HTTPS-specific options
  https?: {
    customCert?: {                    // Use custom cert instead of auto-provisioned
      key: string;
      cert: string;
    };
    forwardSni?: boolean;             // Forward SNI info in passthrough mode
  };
  
  // ACME certificate handling
  acme?: {
    enabled?: boolean;                // Enable ACME certificate provisioning  
    maintenance?: boolean;            // Auto-renew certificates
    production?: boolean;             // Use production ACME servers
    forwardChallenges?: {             // Forward ACME challenges
      host: string;
      port: number;
      useTls?: boolean;
    };
  };
  
  // Security options
  security?: { 
    allowedIps?: string[];            // IPs allowed to connect
    blockedIps?: string[];            // IPs blocked from connecting
    maxConnections?: number;          // Max simultaneous connections
  };
  
  // Advanced options
  advanced?: {
    portRanges?: Array<{ from: number; to: number }>; // Allowed port ranges
    networkProxyPort?: number;        // Custom NetworkProxy port if using terminate mode
    keepAlive?: boolean;              // Enable TCP keepalive
    timeout?: number;                 // Connection timeout in ms
    headers?: Record<string, string>; // Custom headers with support for variables like {sni}
  };
}
Phase 2: Create New Domain Configuration Interface
- Replace existing 
IDomainConfiginterface with a new one using the forwarding pattern: 
export interface IDomainConfig {
  // Core properties
  domains: string[];  // Domain patterns to match
  
  // Unified forwarding configuration
  forwarding: IForwardConfig;
}
Phase 3: Implement Forwarding Handler System
- Create an implementation strategy focused on the new forwarding types:
 
/**
 * Base class for all forwarding handlers
 */
abstract class ForwardingHandler {
  constructor(protected config: IForwardConfig) {}
  
  abstract handleConnection(socket: Socket): void;
  abstract handleHttpRequest(req: IncomingMessage, res: ServerResponse): void;
}
/**
 * Factory for creating the appropriate handler based on forwarding type
 */
class ForwardingHandlerFactory {
  public static createHandler(config: IForwardConfig): ForwardingHandler {
    switch (config.type) {
      case 'http-only':
        return new HttpForwardingHandler(config);
        
      case 'https-passthrough':
        return new HttpsPassthroughHandler(config);
        
      case 'https-terminate-to-http':
        return new HttpsTerminateToHttpHandler(config);
        
      case 'https-terminate-to-https':
        return new HttpsTerminateToHttpsHandler(config);
        
      default:
        throw new Error(`Unknown forwarding type: ${config.type}`);
    }
  }
}
Usage Examples for Common Scenarios
1. Basic HTTP Server
{
  domains: ['example.com'],
  forwarding: {
    type: 'http-only',
    target: {
      host: 'localhost',
      port: 3000
    }
  }
}
2. HTTPS Termination with HTTP Backend
{
  domains: ['secure.example.com'],
  forwarding: {
    type: 'https-terminate-to-http',
    target: {
      host: 'localhost',
      port: 3000
    },
    acme: {
      production: true  // Use production Let's Encrypt
    }
  }
}
3. HTTPS Termination with HTTPS Backend
{
  domains: ['secure-backend.example.com'],
  forwarding: {
    type: 'https-terminate-to-https',
    target: {
      host: 'internal-api',
      port: 8443
    },
    http: {
      redirectToHttps: true  // Redirect HTTP requests to HTTPS
    }
  }
}
4. SNI Passthrough
{
  domains: ['passthrough.example.com'],
  forwarding: {
    type: 'https-passthrough',
    target: {
      host: '10.0.0.5',
      port: 443
    }
  }
}
5. Mixed HTTP/HTTPS with Custom ACME Forwarding
{
  domains: ['mixed.example.com'],
  forwarding: {
    type: 'https-terminate-to-http',
    target: {
      host: 'localhost',
      port: 3000
    },
    http: {
      redirectToHttps: false  // Allow both HTTP and HTTPS access
    },
    acme: {
      enabled: true,
      maintenance: true,
      forwardChallenges: {
        host: '192.168.1.100',
        port: 8080
      }
    }
  }
}
6. Load-Balanced Backend
{
  domains: ['api.example.com'],
  forwarding: {
    type: 'https-terminate-to-https',
    target: {
      host: ['10.0.0.10', '10.0.0.11', '10.0.0.12'], // Round-robin
      port: 8443
    },
    security: {
      allowedIps: ['10.0.0.*', '192.168.1.*']  // Restrict access
    }
  }
}
7. Advanced Proxy Chain with Custom Headers
{
  domains: ['secure-chain.example.com'],
  forwarding: {
    type: 'https-terminate-to-https',
    target: {
      host: 'backend-gateway.internal',
      port: 443
    },
    advanced: {
      // Pass original client info to backend
      headers: {
        'X-Original-SNI': '{sni}',
        'X-Client-IP': '{clientIp}'
      }
    }
  }
}
Implementation Plan
Task 1: Core Types and Interfaces (Week 1)
- Create the new 
IForwardConfiginterface inclasses.pp.interfaces.ts - Design the new 
IDomainConfiginterface using the forwarding property - Define the internal data types for expanded configuration
 
Task 2: Forwarding Handlers (Week 1-2)
- Create abstract 
ForwardingHandlerbase class - Implement concrete handlers for each forwarding type:
HttpForwardingHandler- For HTTP-only configurationsHttpsPassthroughHandler- For SNI passthroughHttpsTerminateToHttpHandler- For TLS termination to HTTP backendsHttpsTerminateToHttpsHandler- For TLS termination to HTTPS backends
 - Implement 
ForwardingHandlerFactoryto create the appropriate handler 
Task 3: SmartProxy Integration (Week 2-3)
- Update 
SmartProxyclass to use the new forwarding system - Modify 
ConnectionHandlerto delegate to forwarding handlers - Refactor domain configuration processing to use forwarding types
 - Update 
Port80Handlerintegration to work with the new system 
Task 4: Certificate Management (Week 3)
- Create a certificate management system that works with forwarding types
 - Implement automatic ACME provisioning based on forwarding type
 - Add custom certificate support
 
Task 5: Testing & Helper Functions (Week 4)
- Create helper functions for common forwarding patterns
 - Implement comprehensive test suite for each forwarding handler
 - Add validation for forwarding configurations
 
Task 6: Documentation (Week 4)
- Create detailed documentation for the new forwarding system
 - Document the forwarding types and their use cases
 - Update README with the new configuration examples
 
Detailed Type Documentation
Core Forwarding Types
/**
 * The primary forwarding types supported by SmartProxy
 */
export type ForwardingType = 
  | 'http-only'                // HTTP forwarding only (no HTTPS)
  | 'https-passthrough'        // Pass-through TLS traffic (SNI forwarding)
  | 'https-terminate-to-http'  // Terminate TLS and forward to HTTP backend
  | 'https-terminate-to-https'; // Terminate TLS and forward to HTTPS backend
Type-Specific Behavior
Each forwarding type has specific default behavior:
HTTP-Only
- Handles only HTTP traffic
 - No TLS/HTTPS support
 - No certificate management
 
HTTPS Passthrough
- Forwards raw TLS traffic to backend (no termination)
 - Passes SNI information through
 - No HTTP support (TLS only)
 - No certificate management
 
HTTPS Terminate to HTTP
- Terminates TLS at SmartProxy
 - Connects to backend using HTTP (non-TLS)
 - Manages certificates automatically (ACME)
 - Supports HTTP requests with option to redirect to HTTPS
 
HTTPS Terminate to HTTPS
- Terminates client TLS at SmartProxy
 - Creates new TLS connection to backend
 - Manages certificates automatically (ACME)
 - Supports HTTP requests with option to redirect to HTTPS
 
Handler Implementation Strategy
/**
 * Handler for HTTP-only forwarding
 */
class HttpForwardingHandler extends ForwardingHandler {
  public handleConnection(socket: Socket): void {
    // Process HTTP connection
    // For HTTP-only, we'll mostly defer to handleHttpRequest
  }
  
  public handleHttpRequest(req: IncomingMessage, res: ServerResponse): void {
    // Forward HTTP request to target
    const target = this.getTargetFromConfig();
    this.proxyRequest(req, res, target);
  }
}
/**
 * Handler for HTTPS passthrough (SNI forwarding)
 */
class HttpsPassthroughHandler extends ForwardingHandler {
  public handleConnection(socket: Socket): void {
    // Extract SNI from TLS ClientHello if needed
    // Forward raw TLS traffic to target without termination
    const target = this.getTargetFromConfig();
    this.forwardTlsConnection(socket, target);
  }
  
  public handleHttpRequest(req: IncomingMessage, res: ServerResponse): void {
    // HTTP not supported in SNI passthrough mode
    res.statusCode = 404;
    res.end('HTTP not supported for this domain');
  }
}
/**
 * Handler for HTTPS termination with HTTP backend
 */
class HttpsTerminateToHttpHandler extends ForwardingHandler {
  private tlsContext: SecureContext;
  
  public async initialize(): Promise<void> {
    // Set up TLS termination context
    this.tlsContext = await this.createTlsContext();
  }
  
  public handleConnection(socket: Socket): void {
    // Terminate TLS
    const tlsSocket = this.createTlsSocket(socket, this.tlsContext);
    
    // Forward to HTTP backend after TLS termination
    tlsSocket.on('data', (data) => {
      this.forwardToHttpBackend(data);
    });
  }
  
  public handleHttpRequest(req: IncomingMessage, res: ServerResponse): void {
    if (this.config.http?.redirectToHttps) {
      // Redirect to HTTPS if configured
      this.redirectToHttps(req, res);
    } else {
      // Handle HTTP request
      const target = this.getTargetFromConfig();
      this.proxyRequest(req, res, target);
    }
  }
}
/**
 * Handler for HTTPS termination with HTTPS backend
 */
class HttpsTerminateToHttpsHandler extends ForwardingHandler {
  private tlsContext: SecureContext;
  
  public async initialize(): Promise<void> {
    // Set up TLS termination context
    this.tlsContext = await this.createTlsContext();
  }
  
  public handleConnection(socket: Socket): void {
    // Terminate client TLS
    const tlsSocket = this.createTlsSocket(socket, this.tlsContext);
    
    // Create new TLS connection to backend
    tlsSocket.on('data', (data) => {
      this.forwardToHttpsBackend(data);
    });
  }
  
  public handleHttpRequest(req: IncomingMessage, res: ServerResponse): void {
    if (this.config.http?.redirectToHttps) {
      // Redirect to HTTPS if configured
      this.redirectToHttps(req, res);
    } else {
      // Handle HTTP request via HTTPS to backend
      const target = this.getTargetFromConfig();
      this.proxyRequestOverHttps(req, res, target);
    }
  }
}
Benefits of This Approach
- 
Clean, Type-Driven Design
- Forwarding types clearly express intent
 - No backward compatibility compromises
 - Code structure follows the domain model
 
 - 
Explicit Configuration
- Configuration directly maps to behavior
 - Reduced chance of unexpected behavior
 
 - 
Modular Implementation
- Each forwarding type handled by dedicated class
 - Clear separation of concerns
 - Easier to test and extend
 
 - 
Simplified Mental Model
- Users think in terms of use cases, not low-level settings
 - Configuration matches mental model
 
 - 
Future-Proof
- Easy to add new forwarding types
 - Clean extension points for new features