import * as plugins from '../../../plugins.js'; import type { WrappedSocket } from '../../../core/models/wrapped-socket.js'; // Certificate types removed - define IAcmeOptions locally export interface IAcmeOptions { enabled?: boolean; email?: string; // Required when any route uses certificate: 'auto' environment?: 'production' | 'staging'; accountEmail?: string; // Alias for email port?: number; // Port for HTTP-01 challenges (default: 80) useProduction?: boolean; // Use Let's Encrypt production (default: false) renewThresholdDays?: number; // Days before expiry to renew (default: 30) autoRenew?: boolean; // Enable automatic renewal (default: true) skipConfiguredCerts?: boolean; renewCheckIntervalHours?: number; // How often to check for renewals (default: 24) routeForwards?: any[]; } /** * Consumer-provided certificate storage. * SmartProxy never writes certs to disk — the consumer owns all persistence. */ export interface ISmartProxyCertStore { /** Load all stored certs on startup (called once before cert provisioning) */ loadAll: () => Promise>; /** Save a cert after successful provisioning */ save: (domain: string, publicKey: string, privateKey: string, ca?: string) => Promise; /** Remove a cert (optional) */ remove?: (domain: string) => Promise; } import type { IRouteConfig } from './route-types.js'; /** * Provision object for static or HTTP-01 certificate */ export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01'; /** * Communication channel passed as second argument to certProvisionFunction. * Allows the callback to report metadata back to SmartProxy for event emission. */ export interface ICertProvisionEventComms { /** Informational log */ log: (message: string) => void; /** Warning (non-fatal) */ warn: (message: string) => void; /** Error */ error: (message: string) => void; /** Set the certificate expiry date (for the issued event) */ setExpiryDate: (date: Date) => void; /** Set the source/method used for provisioning (e.g. 'smartacme-dns-01') */ setSource: (source: string) => void; } /** Payload for 'certificate-issued' and 'certificate-renewed' events */ export interface ICertificateIssuedEvent { domain: string; expiryDate?: string; // ISO 8601 source: string; // e.g. 'certProvisionFunction', 'smartacme-dns-01' isRenewal?: boolean; } /** Payload for 'certificate-failed' event */ export interface ICertificateFailedEvent { domain: string; error: string; source: string; } // Legacy options and type checking functions have been removed /** * SmartProxy configuration options */ export interface ISmartProxyOptions { // The unified configuration array (required) routes: IRouteConfig[]; // Port configuration preserveSourceIP?: boolean; // Preserve client IP when forwarding // PROXY protocol configuration proxyIPs?: string[]; // List of trusted proxy IPs that can send PROXY protocol acceptProxyProtocol?: boolean; // Global option to accept PROXY protocol (defaults based on proxyIPs) sendProxyProtocol?: boolean; // Global option to send PROXY protocol to all targets // Global/default settings defaults?: { target?: { host: string; // Default host to use when not specified in routes port: number; // Default port to use when not specified in routes }; security?: { ipAllowList?: string[]; // Default allowed IPs ipBlockList?: string[]; // Default blocked IPs maxConnections?: number; // Default max connections }; preserveSourceIP?: boolean; // Default source IP preservation }; // TLS options pfx?: Buffer; key?: string | Buffer | Array; passphrase?: string; cert?: string | Buffer | Array; ca?: string | Buffer | Array; ciphers?: string; honorCipherOrder?: boolean; rejectUnauthorized?: boolean; secureProtocol?: string; servername?: string; minVersion?: string; maxVersion?: string; // Timeout settings connectionTimeout?: number; // Timeout for establishing connection to backend (ms), default: 30000 (30s) initialDataTimeout?: number; // Timeout for initial data/SNI (ms), default: 60000 (60s) socketTimeout?: number; // Socket inactivity timeout (ms), default: 3600000 (1h) inactivityCheckInterval?: number; // How often to check for inactive connections (ms), default: 60000 (60s) maxConnectionLifetime?: number; // Default max connection lifetime (ms), default: 86400000 (24h) inactivityTimeout?: number; // Inactivity timeout (ms), default: 14400000 (4h) gracefulShutdownTimeout?: number; // (ms) maximum time to wait for connections to close during shutdown // Socket optimization settings noDelay?: boolean; // Disable Nagle's algorithm (default: true) keepAlive?: boolean; // Enable TCP keepalive (default: true) keepAliveInitialDelay?: number; // Initial delay before sending keepalive probes (ms) maxPendingDataSize?: number; // Maximum bytes to buffer during connection setup // Enhanced features disableInactivityCheck?: boolean; // Disable inactivity checking entirely enableKeepAliveProbes?: boolean; // Enable TCP keep-alive probes enableDetailedLogging?: boolean; // Enable detailed connection logging enableTlsDebugLogging?: boolean; // Enable TLS handshake debug logging enableRandomizedTimeouts?: boolean; // Randomize timeouts slightly to prevent thundering herd // Rate limiting and security maxConnectionsPerIP?: number; // Maximum simultaneous connections from a single IP connectionRateLimitPerMinute?: number; // Max new connections per minute from a single IP // Enhanced keep-alive settings keepAliveTreatment?: 'standard' | 'extended' | 'immortal'; // How to treat keep-alive connections keepAliveInactivityMultiplier?: number; // Multiplier for inactivity timeout for keep-alive connections extendedKeepAliveLifetime?: number; // Extended lifetime for keep-alive connections (ms) // Metrics configuration metrics?: { enabled?: boolean; sampleIntervalMs?: number; retentionSeconds?: number; }; /** * Global ACME configuration options for SmartProxy * * When set, these options will be used as defaults for all routes * with certificate: 'auto' that don't have their own ACME configuration. * Route-specific ACME settings will override these defaults. * * Example: * ```ts * acme: { * email: 'ssl@example.com', * useProduction: false, * port: 80 * } * ``` */ acme?: IAcmeOptions; /** * Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges, * or a static certificate object for immediate provisioning. */ certProvisionFunction?: (domain: string, eventComms: ICertProvisionEventComms) => Promise; /** * Whether to fallback to ACME if custom certificate provision fails. * Default: true */ certProvisionFallbackToAcme?: boolean; /** * Per-domain timeout in ms for certProvisionFunction calls. * If a single domain's provisioning takes longer than this, it's aborted * and a certificate-failed event is emitted. * Default: 300000 (5 minutes) */ certProvisionTimeout?: number; /** * Maximum number of domains to provision certificates for concurrently. * Prevents overwhelming ACME providers when many domains provision at once. * Default: 4 */ certProvisionConcurrency?: number; /** * Disable the default self-signed fallback certificate. * When false (default), a self-signed cert is generated at startup and loaded * as '*' so TLS handshakes never fail due to missing certs. */ disableDefaultCert?: boolean; /** * Consumer-provided cert storage. SmartProxy never writes certs to disk. * On startup, loadAll() is called to pre-load persisted certs. * After each successful cert provision, save() is called. */ certStore?: ISmartProxyCertStore; /** * Path to the RustProxy binary. If not set, the binary is located * automatically via env var, platform package, local build, or PATH. */ rustBinaryPath?: string; } /** * Enhanced connection record */ export interface IConnectionRecord { id: string; // Unique connection identifier incoming: plugins.net.Socket | WrappedSocket; outgoing: plugins.net.Socket | WrappedSocket | null; incomingStartTime: number; outgoingStartTime?: number; outgoingClosedTime?: number; lockedDomain?: string; // Used to lock this connection to the initial SNI connectionClosed: boolean; // Flag to prevent multiple cleanup attempts cleanupTimer?: NodeJS.Timeout | null; // Timer for max lifetime/inactivity alertFallbackTimeout?: NodeJS.Timeout; // Timer for fallback after alert lastActivity: number; // Last activity timestamp for inactivity detection pendingData: Buffer[]; // Buffer to hold data during connection setup pendingDataSize: number; // Track total size of pending data // Enhanced tracking fields bytesReceived: number; // Total bytes received bytesSent: number; // Total bytes sent remoteIP: string; // Remote IP (cached for logging after socket close) remotePort: number; // Remote port (cached for logging after socket close) localPort: number; // Local port (cached for logging) isTLS: boolean; // Whether this connection is a TLS connection tlsHandshakeComplete: boolean; // Whether the TLS handshake is complete hasReceivedInitialData: boolean; // Whether initial data has been received routeConfig?: IRouteConfig; // Associated route config for this connection routeId?: string; // ID of the route this connection is associated with // Target information (for dynamic port/host mapping) targetHost?: string; // Resolved target host targetPort?: number; // Resolved target port tlsVersion?: string; // TLS version (for routing context) // Keep-alive tracking hasKeepAlive: boolean; // Whether keep-alive is enabled for this connection inactivityWarningIssued?: boolean; // Whether an inactivity warning has been issued incomingTerminationReason?: string | null; // Reason for incoming termination outgoingTerminationReason?: string | null; // Reason for outgoing termination // NetworkProxy tracking usingNetworkProxy?: boolean; // Whether this connection is using a NetworkProxy // Renegotiation handler renegotiationHandler?: (chunk: Buffer) => void; // Handler for renegotiation detection // Browser connection tracking isBrowserConnection?: boolean; // Whether this connection appears to be from a browser domainSwitches?: number; // Number of times the domain has been switched on this connection // NFTables tracking nftablesHandled?: boolean; // Whether this connection is being handled by NFTables at kernel level // HTTP-specific information (extracted from protocol detection) httpInfo?: { method?: string; path?: string; headers?: Record; }; }