|
|
|
@ -1,11 +1,178 @@
|
|
|
|
|
# @push.rocks/smartproxy
|
|
|
|
|
|
|
|
|
|
A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, and dynamic routing with authentication options.
|
|
|
|
|
A high-performance proxy toolkit for Node.js, offering:
|
|
|
|
|
- HTTP/HTTPS reverse proxy with TLS termination and WebSocket support
|
|
|
|
|
- Automatic ACME certificate management (HTTP-01)
|
|
|
|
|
- Low-level port forwarding via nftables
|
|
|
|
|
- HTTP-to-HTTPS and custom URL redirects
|
|
|
|
|
- Advanced TCP/SNI-based proxying with IP filtering and rules
|
|
|
|
|
|
|
|
|
|
## Exports
|
|
|
|
|
The following classes and interfaces are provided:
|
|
|
|
|
|
|
|
|
|
- **NetworkProxy** (ts/networkproxy/classes.np.networkproxy.ts)
|
|
|
|
|
HTTP/HTTPS reverse proxy with TLS termination, WebSocket support,
|
|
|
|
|
connection pooling, and optional ACME integration.
|
|
|
|
|
- **Port80Handler** (ts/port80handler/classes.port80handler.ts)
|
|
|
|
|
ACME HTTP-01 challenge handler and certificate manager.
|
|
|
|
|
- **NfTablesProxy** (ts/nfttablesproxy/classes.nftablesproxy.ts)
|
|
|
|
|
Low-level port forwarding using nftables NAT rules.
|
|
|
|
|
- **Redirect**, **SslRedirect** (ts/redirect/classes.redirect.ts)
|
|
|
|
|
HTTP/HTTPS redirect server and shortcut for HTTP→HTTPS.
|
|
|
|
|
- **SmartProxy** (ts/smartproxy/classes.smartproxy.ts)
|
|
|
|
|
TCP/SNI-based proxy with dynamic routing, IP filtering, and unified certificates.
|
|
|
|
|
- **SniHandler** (ts/smartproxy/classes.pp.snihandler.ts)
|
|
|
|
|
Static utilities to extract SNI hostnames from TLS handshakes.
|
|
|
|
|
- **Interfaces**
|
|
|
|
|
- IPortProxySettings, IDomainConfig (ts/smartproxy/classes.pp.interfaces.ts)
|
|
|
|
|
- INetworkProxyOptions (ts/networkproxy/classes.np.types.ts)
|
|
|
|
|
- IAcmeOptions, IDomainOptions, IForwardConfig (ts/common/types.ts)
|
|
|
|
|
- INfTableProxySettings (ts/nfttablesproxy/classes.nftablesproxy.ts)
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
Install via npm:
|
|
|
|
|
```bash
|
|
|
|
|
npm install @push.rocks/smartproxy
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Quick Start
|
|
|
|
|
|
|
|
|
|
### 1. HTTP(S) Reverse Proxy (NetworkProxy)
|
|
|
|
|
```typescript
|
|
|
|
|
import { NetworkProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
const proxy = new NetworkProxy({ port: 443 });
|
|
|
|
|
await proxy.start();
|
|
|
|
|
|
|
|
|
|
await proxy.updateProxyConfigs([
|
|
|
|
|
{
|
|
|
|
|
hostName: 'example.com',
|
|
|
|
|
destinationIps: ['127.0.0.1'],
|
|
|
|
|
destinationPorts: [3000],
|
|
|
|
|
publicKey: fs.readFileSync('cert.pem', 'utf8'),
|
|
|
|
|
privateKey: fs.readFileSync('key.pem', 'utf8'),
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Add default headers to all responses
|
|
|
|
|
await proxy.addDefaultHeaders({
|
|
|
|
|
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
|
|
|
|
|
});
|
|
|
|
|
// ...
|
|
|
|
|
await proxy.stop();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 2. HTTP→HTTPS Redirect (Redirect / SslRedirect)
|
|
|
|
|
```typescript
|
|
|
|
|
import { Redirect, SslRedirect } from '@push.rocks/smartproxy';
|
|
|
|
|
import * as fs from 'fs';
|
|
|
|
|
|
|
|
|
|
// Custom redirect rules
|
|
|
|
|
const redirect = new Redirect({
|
|
|
|
|
httpPort: 80,
|
|
|
|
|
httpsPort: 443,
|
|
|
|
|
sslOptions: {
|
|
|
|
|
key: fs.readFileSync('key.pem'),
|
|
|
|
|
cert: fs.readFileSync('cert.pem'),
|
|
|
|
|
},
|
|
|
|
|
rules: [
|
|
|
|
|
{
|
|
|
|
|
fromProtocol: 'http',
|
|
|
|
|
fromHost: '*',
|
|
|
|
|
toProtocol: 'https',
|
|
|
|
|
toHost: '$1',
|
|
|
|
|
statusCode: 301
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
await redirect.start();
|
|
|
|
|
|
|
|
|
|
// Quick HTTP→HTTPS helper on port 80
|
|
|
|
|
const quick = new SslRedirect(80);
|
|
|
|
|
await quick.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3. Automatic Certificates (ACME Port80Handler)
|
|
|
|
|
```typescript
|
|
|
|
|
import { Port80Handler } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Configure ACME on port 80 with contact email
|
|
|
|
|
const acme = new Port80Handler({
|
|
|
|
|
port: 80,
|
|
|
|
|
contactEmail: 'admin@example.com',
|
|
|
|
|
useProduction: true,
|
|
|
|
|
renewThresholdDays: 30
|
|
|
|
|
});
|
|
|
|
|
acme.on('certificate-issued', evt => {
|
|
|
|
|
console.log(`Certificate ready for ${evt.domain}, expires ${evt.expiryDate}`);
|
|
|
|
|
});
|
|
|
|
|
await acme.start();
|
|
|
|
|
acme.addDomain({
|
|
|
|
|
domainName: 'example.com',
|
|
|
|
|
sslRedirect: true,
|
|
|
|
|
acmeMaintenance: true
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 4. Low-Level Port Forwarding (NfTablesProxy)
|
|
|
|
|
```typescript
|
|
|
|
|
import { NfTablesProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Forward port 80→8080 with source IP preservation
|
|
|
|
|
const nft = new NfTablesProxy({
|
|
|
|
|
fromPort: 80,
|
|
|
|
|
toPort: 8080,
|
|
|
|
|
toHost: 'localhost',
|
|
|
|
|
preserveSourceIP: true,
|
|
|
|
|
deleteOnExit: true
|
|
|
|
|
});
|
|
|
|
|
await nft.start();
|
|
|
|
|
// ...
|
|
|
|
|
await nft.stop();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 5. TCP/SNI Proxy (SmartProxy)
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
const smart = new SmartProxy({
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
toPort: 8443,
|
|
|
|
|
domainConfigs: [
|
|
|
|
|
{
|
|
|
|
|
domains: ['example.com', '*.example.com'],
|
|
|
|
|
allowedIPs: ['*'],
|
|
|
|
|
targetIPs: ['127.0.0.1'],
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
sniEnabled: true
|
|
|
|
|
});
|
|
|
|
|
smart.on('certificate', evt => console.log(evt));
|
|
|
|
|
await smart.start();
|
|
|
|
|
// Update domains later
|
|
|
|
|
await smart.updateDomainConfigs([/* new configs */]);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 6. SNI Utilities (SniHandler)
|
|
|
|
|
```js
|
|
|
|
|
import { SniHandler } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Extract SNI from a TLS ClientHello buffer
|
|
|
|
|
const sni = SniHandler.extractSNI(buffer);
|
|
|
|
|
|
|
|
|
|
// Reassemble fragmented ClientHello
|
|
|
|
|
const complete = SniHandler.handleFragmentedClientHello(buf, connId);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## API Reference
|
|
|
|
|
For full configuration options and type definitions, see the TypeScript interfaces in the `ts/` directory:
|
|
|
|
|
- `INetworkProxyOptions` (ts/networkproxy/classes.np.types.ts)
|
|
|
|
|
- `IAcmeOptions`, `IDomainOptions`, `IForwardConfig` (ts/common/types.ts)
|
|
|
|
|
- `INfTableProxySettings` (ts/nfttablesproxy/classes.nftablesproxy.ts)
|
|
|
|
|
- `IPortProxySettings`, `IDomainConfig` (ts/smartproxy/classes.pp.interfaces.ts)
|
|
|
|
|
|
|
|
|
|
## Architecture & Flow Diagrams
|
|
|
|
|
|
|
|
|
|
### Component Architecture
|
|
|
|
|
The diagram below illustrates the main components of SmartProxy and how they interact:
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
flowchart TB
|
|
|
|
@ -13,12 +180,12 @@ flowchart TB
|
|
|
|
|
|
|
|
|
|
subgraph "SmartProxy Components"
|
|
|
|
|
direction TB
|
|
|
|
|
HTTP80[HTTP Port 80\nSslRedirect]
|
|
|
|
|
HTTPS443[HTTPS Port 443\nNetworkProxy]
|
|
|
|
|
SmartProxy[SmartProxy\nwith SNI routing]
|
|
|
|
|
HTTP80["HTTP Port 80<br>Redirect / SslRedirect"]
|
|
|
|
|
HTTPS443["HTTPS Port 443<br>NetworkProxy"]
|
|
|
|
|
SmartProxy["SmartProxy<br>(TCP/SNI Proxy)"]
|
|
|
|
|
NfTables[NfTablesProxy]
|
|
|
|
|
Router[ProxyRouter]
|
|
|
|
|
ACME[Port80Handler\nACME/Let's Encrypt]
|
|
|
|
|
ACME["Port80Handler<br>(ACME HTTP-01)"]
|
|
|
|
|
Certs[(SSL Certificates)]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
@ -190,470 +357,104 @@ sequenceDiagram
|
|
|
|
|
|
|
|
|
|
## Features
|
|
|
|
|
|
|
|
|
|
- **HTTPS Reverse Proxy** - Route traffic to backend services based on hostname with TLS termination
|
|
|
|
|
- **WebSocket Support** - Full WebSocket proxying with heartbeat monitoring
|
|
|
|
|
- **TCP Connection Handling** - Advanced connection handling with SNI inspection and domain-based routing
|
|
|
|
|
- **Enhanced TLS Handling** - Robust TLS handshake processing with improved certificate error handling
|
|
|
|
|
- **HTTP to HTTPS Redirection** - Automatically redirect HTTP requests to HTTPS
|
|
|
|
|
- **Let's Encrypt Integration** - Automatic certificate management using ACME protocol
|
|
|
|
|
- **IP Filtering** - Control access with IP allow/block lists using glob patterns
|
|
|
|
|
- **NfTables Integration** - Direct manipulation of nftables for advanced low-level port forwarding
|
|
|
|
|
- HTTP/HTTPS Reverse Proxy (NetworkProxy)
|
|
|
|
|
• TLS termination, virtual-host routing, HTTP/2 & WebSocket support, pooling & metrics
|
|
|
|
|
|
|
|
|
|
## Certificate Provider Hook & Events
|
|
|
|
|
- Automatic ACME Certificates (Port80Handler)
|
|
|
|
|
• HTTP-01 challenge handling, certificate issuance/renewal, pluggable storage
|
|
|
|
|
|
|
|
|
|
You can customize how certificates are provisioned per domain by using the `certProvider` callback and listen for certificate events emitted by `SmartProxy`.
|
|
|
|
|
- Low-Level Port Forwarding (NfTablesProxy)
|
|
|
|
|
• nftables NAT rules for ports/ranges, IPv4/IPv6, IP filtering, QoS & ipset support
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
import * as fs from 'fs';
|
|
|
|
|
- Custom Redirects (Redirect / SslRedirect)
|
|
|
|
|
• URL redirects with wildcard host/path, template variables & status codes
|
|
|
|
|
|
|
|
|
|
// Example certProvider: static for a specific domain, HTTP-01 otherwise
|
|
|
|
|
const certProvider = async (domain: string) => {
|
|
|
|
|
if (domain === 'static.example.com') {
|
|
|
|
|
// Load from disk or vault
|
|
|
|
|
return {
|
|
|
|
|
id: 'static-cert',
|
|
|
|
|
domainName: domain,
|
|
|
|
|
created: Date.now(),
|
|
|
|
|
validUntil: Date.now() + 90 * 24 * 60 * 60 * 1000,
|
|
|
|
|
privateKey: fs.readFileSync('/etc/ssl/private/static.key', 'utf8'),
|
|
|
|
|
publicKey: fs.readFileSync('/etc/ssl/certs/static.crt', 'utf8'),
|
|
|
|
|
csr: ''
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
// Fallback to ACME HTTP-01 challenge
|
|
|
|
|
return 'http01';
|
|
|
|
|
};
|
|
|
|
|
- TCP/SNI Proxy (SmartProxy)
|
|
|
|
|
• SNI-based routing, IP allow/block lists, port ranges, timeouts & graceful shutdown
|
|
|
|
|
|
|
|
|
|
const proxy = new SmartProxy({
|
|
|
|
|
fromPort: 80,
|
|
|
|
|
toPort: 8080,
|
|
|
|
|
domainConfigs: [{
|
|
|
|
|
domains: ['static.example.com', 'dynamic.example.com'],
|
|
|
|
|
allowedIPs: ['*']
|
|
|
|
|
}],
|
|
|
|
|
certProvider
|
|
|
|
|
});
|
|
|
|
|
- SNI Utilities (SniHandler)
|
|
|
|
|
• Robust ClientHello parsing, fragmentation & session resumption support
|
|
|
|
|
|
|
|
|
|
// Listen for certificate issuance or renewal
|
|
|
|
|
proxy.on('certificate', (evt) => {
|
|
|
|
|
console.log(`Certificate for ${evt.domain} ready, expires on ${evt.expiryDate}`);
|
|
|
|
|
});
|
|
|
|
|
## Certificate Hooks & Events
|
|
|
|
|
|
|
|
|
|
await proxy.start();
|
|
|
|
|
```
|
|
|
|
|
Listen for certificate events via EventEmitter:
|
|
|
|
|
- **Port80Handler**:
|
|
|
|
|
- `certificate-issued`, `certificate-renewed`, `certificate-failed`
|
|
|
|
|
- `manager-started`, `manager-stopped`, `request-forwarded`
|
|
|
|
|
- **SmartProxy**:
|
|
|
|
|
- `certificate` (domain, publicKey, privateKey, expiryDate, source, isRenewal)
|
|
|
|
|
|
|
|
|
|
Provide a `certProvider(domain)` in SmartProxy settings to supply static certs or return `'http01'`.
|
|
|
|
|
|
|
|
|
|
## Configuration Options
|
|
|
|
|
|
|
|
|
|
### backendProtocol
|
|
|
|
|
### NetworkProxy (INetworkProxyOptions)
|
|
|
|
|
- `port` (number, required)
|
|
|
|
|
- `backendProtocol` ('http1'|'http2', default 'http1')
|
|
|
|
|
- `maxConnections` (number, default 10000)
|
|
|
|
|
- `keepAliveTimeout` (ms, default 120000)
|
|
|
|
|
- `headersTimeout` (ms, default 60000)
|
|
|
|
|
- `cors` (object)
|
|
|
|
|
- `connectionPoolSize` (number, default 50)
|
|
|
|
|
- `logLevel` ('error'|'warn'|'info'|'debug')
|
|
|
|
|
- `acme` (IAcmeOptions)
|
|
|
|
|
- `useExternalPort80Handler` (boolean)
|
|
|
|
|
- `portProxyIntegration` (boolean)
|
|
|
|
|
|
|
|
|
|
Type: 'http1' | 'http2' (default: 'http1')
|
|
|
|
|
### Port80Handler (IAcmeOptions)
|
|
|
|
|
- `enabled` (boolean, default true)
|
|
|
|
|
- `port` (number, default 80)
|
|
|
|
|
- `contactEmail` (string)
|
|
|
|
|
- `useProduction` (boolean, default false)
|
|
|
|
|
- `renewThresholdDays` (number, default 30)
|
|
|
|
|
- `autoRenew` (boolean, default true)
|
|
|
|
|
- `certificateStore` (string)
|
|
|
|
|
- `skipConfiguredCerts` (boolean)
|
|
|
|
|
- `domainForwards` (IDomainForwardConfig[])
|
|
|
|
|
|
|
|
|
|
Controls the protocol used when proxying requests to backend services. By default, the proxy uses HTTP/1.x (`http.request`). Setting `backendProtocol: 'http2'` establishes HTTP/2 client sessions (`http2.connect`) to your backends for full end-to-end HTTP/2 support (assuming your backend servers support HTTP/2).
|
|
|
|
|
### NfTablesProxy (INfTableProxySettings)
|
|
|
|
|
- `fromPort` / `toPort` (number|range|array)
|
|
|
|
|
- `toHost` (string, default 'localhost')
|
|
|
|
|
- `preserveSourceIP`, `deleteOnExit`, `protocol`, `enableLogging`, `ipv6Support` (booleans)
|
|
|
|
|
- `allowedSourceIPs`, `bannedSourceIPs` (string[])
|
|
|
|
|
- `useIPSets` (boolean, default true)
|
|
|
|
|
- `qos`, `netProxyIntegration` (objects)
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
```js
|
|
|
|
|
import { NetworkProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
### Redirect / SslRedirect
|
|
|
|
|
- Constructor options: `httpPort`, `httpsPort`, `sslOptions`, `rules` (RedirectRule[])
|
|
|
|
|
|
|
|
|
|
const proxy = new NetworkProxy({
|
|
|
|
|
port: 8443,
|
|
|
|
|
backendProtocol: 'http2',
|
|
|
|
|
// other options...
|
|
|
|
|
});
|
|
|
|
|
proxy.start();
|
|
|
|
|
```
|
|
|
|
|
- **Basic Authentication** - Support for basic auth on proxied routes
|
|
|
|
|
- **Connection Management** - Intelligent connection tracking and cleanup with configurable timeouts
|
|
|
|
|
- **Browser Compatibility** - Optimized for modern browsers with fixes for common TLS handshake issues
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
npm install @push.rocks/smartproxy
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
### Basic Reverse Proxy Setup
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { NetworkProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Create a reverse proxy listening on port 443
|
|
|
|
|
const proxy = new NetworkProxy({
|
|
|
|
|
port: 443
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Define reverse proxy configurations
|
|
|
|
|
const proxyConfigs = [
|
|
|
|
|
{
|
|
|
|
|
hostName: 'example.com',
|
|
|
|
|
destinationIps: ['127.0.0.1'],
|
|
|
|
|
destinationPorts: [3000],
|
|
|
|
|
publicKey: 'your-cert-content',
|
|
|
|
|
privateKey: 'your-key-content',
|
|
|
|
|
rewriteHostHeader: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
hostName: 'api.example.com',
|
|
|
|
|
destinationIps: ['127.0.0.1'],
|
|
|
|
|
destinationPorts: [4000],
|
|
|
|
|
publicKey: 'your-cert-content',
|
|
|
|
|
privateKey: 'your-key-content',
|
|
|
|
|
// Optional basic auth
|
|
|
|
|
authentication: {
|
|
|
|
|
type: 'Basic',
|
|
|
|
|
user: 'admin',
|
|
|
|
|
pass: 'secret'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Start the proxy and update configurations
|
|
|
|
|
(async () => {
|
|
|
|
|
await proxy.start();
|
|
|
|
|
await proxy.updateProxyConfigs(proxyConfigs);
|
|
|
|
|
|
|
|
|
|
// Add default headers to all responses
|
|
|
|
|
await proxy.addDefaultHeaders({
|
|
|
|
|
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload'
|
|
|
|
|
});
|
|
|
|
|
})();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### HTTP to HTTPS Redirection
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SslRedirect } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Create and start HTTP to HTTPS redirect service on port 80
|
|
|
|
|
const redirector = new SslRedirect(80);
|
|
|
|
|
redirector.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### TCP Connection Handling with Domain-based Routing
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Configure SmartProxy with domain-based routing
|
|
|
|
|
const smartProxy = new SmartProxy({
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
toPort: 8443,
|
|
|
|
|
targetIP: 'localhost', // Default target host
|
|
|
|
|
sniEnabled: true, // Enable SNI inspection
|
|
|
|
|
|
|
|
|
|
// Enhanced reliability settings
|
|
|
|
|
initialDataTimeout: 60000, // 60 seconds for initial TLS handshake
|
|
|
|
|
socketTimeout: 3600000, // 1 hour socket timeout
|
|
|
|
|
maxConnectionLifetime: 3600000, // 1 hour connection lifetime
|
|
|
|
|
inactivityTimeout: 3600000, // 1 hour inactivity timeout
|
|
|
|
|
maxPendingDataSize: 10 * 1024 * 1024, // 10MB buffer for large TLS handshakes
|
|
|
|
|
|
|
|
|
|
// Browser compatibility enhancement
|
|
|
|
|
enableTlsDebugLogging: false, // Enable for troubleshooting TLS issues
|
|
|
|
|
|
|
|
|
|
// Port and IP configuration
|
|
|
|
|
globalPortRanges: [{ from: 443, to: 443 }],
|
|
|
|
|
defaultAllowedIPs: ['*'], // Allow all IPs by default
|
|
|
|
|
|
|
|
|
|
// Socket optimizations for better connection stability
|
|
|
|
|
noDelay: true, // Disable Nagle's algorithm
|
|
|
|
|
keepAlive: true, // Enable TCP keepalive
|
|
|
|
|
enableKeepAliveProbes: true, // Enhanced keepalive for stability
|
|
|
|
|
|
|
|
|
|
// Domain-specific routing configuration
|
|
|
|
|
domainConfigs: [
|
|
|
|
|
{
|
|
|
|
|
domains: ['example.com', '*.example.com'], // Glob patterns for matching domains
|
|
|
|
|
allowedIPs: ['192.168.1.*'], // Restrict access by IP
|
|
|
|
|
blockedIPs: ['192.168.1.100'], // Block specific IPs
|
|
|
|
|
targetIPs: ['10.0.0.1', '10.0.0.2'], // Round-robin between multiple targets
|
|
|
|
|
portRanges: [{ from: 443, to: 443 }],
|
|
|
|
|
connectionTimeout: 7200000 // Domain-specific timeout (2 hours)
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
preserveSourceIP: true
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
smartProxy.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### NfTables Port Forwarding
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { NfTablesProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Basic usage - forward single port
|
|
|
|
|
const basicProxy = new NfTablesProxy({
|
|
|
|
|
fromPort: 80,
|
|
|
|
|
toPort: 8080,
|
|
|
|
|
toHost: 'localhost',
|
|
|
|
|
preserveSourceIP: true,
|
|
|
|
|
deleteOnExit: true // Automatically clean up rules on process exit
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Forward port ranges
|
|
|
|
|
const rangeProxy = new NfTablesProxy({
|
|
|
|
|
fromPort: { from: 3000, to: 3010 }, // Forward ports 3000-3010
|
|
|
|
|
toPort: { from: 8000, to: 8010 }, // To ports 8000-8010
|
|
|
|
|
protocol: 'tcp', // TCP protocol (default)
|
|
|
|
|
ipv6Support: true, // Enable IPv6 support
|
|
|
|
|
enableLogging: true // Enable detailed logging
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Multiple port specifications with IP filtering
|
|
|
|
|
const advancedProxy = new NfTablesProxy({
|
|
|
|
|
fromPort: [80, 443, { from: 8000, to: 8010 }], // Multiple ports/ranges
|
|
|
|
|
toPort: [8080, 8443, { from: 18000, to: 18010 }],
|
|
|
|
|
allowedSourceIPs: ['10.0.0.0/8', '192.168.1.0/24'], // Only allow these IPs
|
|
|
|
|
bannedSourceIPs: ['192.168.1.100'], // Explicitly block these IPs
|
|
|
|
|
useIPSets: true, // Use IP sets for efficient IP management
|
|
|
|
|
forceCleanSlate: false // Clean all NfTablesProxy rules before starting
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Advanced features: QoS, connection tracking, and NetworkProxy integration
|
|
|
|
|
const advancedProxy = new NfTablesProxy({
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
toPort: 8443,
|
|
|
|
|
toHost: 'localhost',
|
|
|
|
|
useAdvancedNAT: true, // Use connection tracking for stateful NAT
|
|
|
|
|
qos: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
maxRate: '10mbps', // Limit bandwidth
|
|
|
|
|
priority: 1 // Set traffic priority (1-10)
|
|
|
|
|
},
|
|
|
|
|
netProxyIntegration: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
redirectLocalhost: true, // Redirect localhost traffic to NetworkProxy
|
|
|
|
|
sslTerminationPort: 8443 // Port where NetworkProxy handles SSL
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Start any of the proxies
|
|
|
|
|
await basicProxy.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Automatic HTTPS Certificate Management
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { Port80Handler } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Create an ACME handler for Let's Encrypt
|
|
|
|
|
const acmeHandler = new Port80Handler({
|
|
|
|
|
port: 80,
|
|
|
|
|
contactEmail: 'admin@example.com',
|
|
|
|
|
useProduction: true, // Use Let's Encrypt production servers (default is staging)
|
|
|
|
|
renewThresholdDays: 30, // Renew certificates 30 days before expiry
|
|
|
|
|
httpsRedirectPort: 443 // Redirect HTTP to HTTPS on this port
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Add domains to manage certificates for
|
|
|
|
|
acmeHandler.addDomain({
|
|
|
|
|
domainName: 'example.com',
|
|
|
|
|
sslRedirect: true,
|
|
|
|
|
acmeMaintenance: true
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
acmeHandler.addDomain({
|
|
|
|
|
domainName: 'api.example.com',
|
|
|
|
|
sslRedirect: true,
|
|
|
|
|
acmeMaintenance: true
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Support for glob pattern domains for routing (certificates not issued for glob patterns)
|
|
|
|
|
acmeHandler.addDomain({
|
|
|
|
|
domainName: '*.example.com',
|
|
|
|
|
sslRedirect: true,
|
|
|
|
|
acmeMaintenance: false, // Can't issue certificates for wildcard domains via HTTP-01
|
|
|
|
|
forward: { ip: '192.168.1.10', port: 8080 } // Forward requests to this target
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Configuration Options
|
|
|
|
|
|
|
|
|
|
### NetworkProxy Options
|
|
|
|
|
|
|
|
|
|
| Option | Description | Default |
|
|
|
|
|
|----------------|---------------------------------------------------|---------|
|
|
|
|
|
| `port` | Port to listen on for HTTPS connections | - |
|
|
|
|
|
| `maxConnections` | Maximum concurrent connections | 10000 |
|
|
|
|
|
| `keepAliveTimeout` | Keep-alive timeout in milliseconds | 60000 |
|
|
|
|
|
| `headersTimeout` | Headers timeout in milliseconds | 60000 |
|
|
|
|
|
| `logLevel` | Logging level ('error', 'warn', 'info', 'debug') | 'info' |
|
|
|
|
|
| `cors` | CORS configuration object | - |
|
|
|
|
|
| `rewriteHostHeader` | Whether to rewrite the Host header | false |
|
|
|
|
|
|
|
|
|
|
### SmartProxy Settings
|
|
|
|
|
|
|
|
|
|
| Option | Description | Default |
|
|
|
|
|
|---------------------------|--------------------------------------------------------|-------------|
|
|
|
|
|
| `fromPort` | Port to listen on | - |
|
|
|
|
|
| `toPort` | Destination port to forward to | - |
|
|
|
|
|
| `targetIP` | Default destination IP if not specified in domainConfig | 'localhost' |
|
|
|
|
|
| `sniEnabled` | Enable SNI inspection for TLS connections | false |
|
|
|
|
|
| `defaultAllowedIPs` | IP patterns allowed by default | - |
|
|
|
|
|
| `defaultBlockedIPs` | IP patterns blocked by default | - |
|
|
|
|
|
| `preserveSourceIP` | Preserve the original client IP | false |
|
|
|
|
|
| `maxConnectionLifetime` | Maximum time in ms to keep a connection open | 3600000 |
|
|
|
|
|
| `initialDataTimeout` | Timeout for initial data/handshake in ms | 60000 |
|
|
|
|
|
| `socketTimeout` | Socket inactivity timeout in ms | 3600000 |
|
|
|
|
|
| `inactivityTimeout` | Connection inactivity check timeout in ms | 3600000 |
|
|
|
|
|
| `inactivityCheckInterval` | How often to check for inactive connections in ms | 60000 |
|
|
|
|
|
| `maxPendingDataSize` | Maximum bytes to buffer during connection setup | 10485760 |
|
|
|
|
|
| `globalPortRanges` | Array of port ranges to listen on | - |
|
|
|
|
|
| `forwardAllGlobalRanges` | Forward all global range connections to targetIP | false |
|
|
|
|
|
| `gracefulShutdownTimeout` | Time in ms to wait during shutdown | 30000 |
|
|
|
|
|
| `noDelay` | Disable Nagle's algorithm | true |
|
|
|
|
|
| `keepAlive` | Enable TCP keepalive | true |
|
|
|
|
|
| `keepAliveInitialDelay` | Initial delay before sending keepalive probes in ms | 30000 |
|
|
|
|
|
| `enableKeepAliveProbes` | Enable enhanced TCP keep-alive probes | false |
|
|
|
|
|
| `enableTlsDebugLogging` | Enable detailed TLS handshake debugging | false |
|
|
|
|
|
| `enableDetailedLogging` | Enable detailed connection logging | false |
|
|
|
|
|
| `enableRandomizedTimeouts`| Randomize timeouts slightly to prevent thundering herd | true |
|
|
|
|
|
|
|
|
|
|
### NfTablesProxy Settings
|
|
|
|
|
|
|
|
|
|
| Option | Description | Default |
|
|
|
|
|
|-----------------------|---------------------------------------------------|-------------|
|
|
|
|
|
| `fromPort` | Source port(s) or range(s) to forward from | - |
|
|
|
|
|
| `toPort` | Destination port(s) or range(s) to forward to | - |
|
|
|
|
|
| `toHost` | Destination host to forward to | 'localhost' |
|
|
|
|
|
| `preserveSourceIP` | Preserve the original client IP | false |
|
|
|
|
|
| `deleteOnExit` | Remove nftables rules when process exits | false |
|
|
|
|
|
| `protocol` | Protocol to forward ('tcp', 'udp', or 'all') | 'tcp' |
|
|
|
|
|
| `enableLogging` | Enable detailed logging | false |
|
|
|
|
|
| `logFormat` | Format for logs ('plain' or 'json') | 'plain' |
|
|
|
|
|
| `ipv6Support` | Enable IPv6 support | false |
|
|
|
|
|
| `allowedSourceIPs` | Array of IP addresses/CIDR allowed to connect | - |
|
|
|
|
|
| `bannedSourceIPs` | Array of IP addresses/CIDR blocked from connecting | - |
|
|
|
|
|
| `useIPSets` | Use nftables sets for efficient IP management | true |
|
|
|
|
|
| `forceCleanSlate` | Clear all NfTablesProxy rules before starting | false |
|
|
|
|
|
| `tableName` | Custom table name | 'portproxy' |
|
|
|
|
|
| `maxRetries` | Maximum number of retries for failed commands | 3 |
|
|
|
|
|
| `retryDelayMs` | Delay between retries in milliseconds | 1000 |
|
|
|
|
|
| `useAdvancedNAT` | Use connection tracking for stateful NAT | false |
|
|
|
|
|
| `qos` | Quality of Service options (object) | - |
|
|
|
|
|
| `netProxyIntegration` | NetworkProxy integration options (object) | - |
|
|
|
|
|
|
|
|
|
|
## Advanced Features
|
|
|
|
|
|
|
|
|
|
### TLS Handshake Optimization
|
|
|
|
|
|
|
|
|
|
The enhanced `SmartProxy` implementation includes significant improvements for TLS handshake handling:
|
|
|
|
|
|
|
|
|
|
- Robust SNI extraction with improved error handling
|
|
|
|
|
- Increased buffer size for complex TLS handshakes (10MB)
|
|
|
|
|
- Longer initial handshake timeout (60 seconds)
|
|
|
|
|
- Detection and tracking of TLS connection states
|
|
|
|
|
- Optional detailed TLS debug logging for troubleshooting
|
|
|
|
|
- Browser compatibility fixes for Chrome certificate errors
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Example configuration to solve Chrome certificate errors
|
|
|
|
|
const portProxy = new SmartProxy({
|
|
|
|
|
// ... other settings
|
|
|
|
|
initialDataTimeout: 60000, // Give browser more time for handshake
|
|
|
|
|
maxPendingDataSize: 10 * 1024 * 1024, // Larger buffer for complex handshakes
|
|
|
|
|
enableTlsDebugLogging: true, // Enable when troubleshooting
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Connection Management and Monitoring
|
|
|
|
|
|
|
|
|
|
The `SmartProxy` class includes built-in connection tracking and monitoring:
|
|
|
|
|
|
|
|
|
|
- Automatic cleanup of idle connections with configurable timeouts
|
|
|
|
|
- Timeouts for connections that exceed maximum lifetime
|
|
|
|
|
- Detailed logging of connection states
|
|
|
|
|
- Termination statistics
|
|
|
|
|
- Randomized timeouts to prevent "thundering herd" problems
|
|
|
|
|
- Per-domain timeout configuration
|
|
|
|
|
|
|
|
|
|
### WebSocket Support
|
|
|
|
|
|
|
|
|
|
The `NetworkProxy` class provides WebSocket support with:
|
|
|
|
|
|
|
|
|
|
- WebSocket connection proxying
|
|
|
|
|
- Automatic heartbeat monitoring
|
|
|
|
|
- Connection cleanup for inactive WebSockets
|
|
|
|
|
|
|
|
|
|
### SNI-based Routing
|
|
|
|
|
|
|
|
|
|
The `SmartProxy` class can inspect the SNI (Server Name Indication) field in TLS handshakes to route connections based on the requested domain:
|
|
|
|
|
|
|
|
|
|
- Multiple backend targets per domain
|
|
|
|
|
- Round-robin load balancing
|
|
|
|
|
- Domain-specific allowed IP ranges
|
|
|
|
|
- Protection against SNI renegotiation attacks
|
|
|
|
|
|
|
|
|
|
### Enhanced NfTables Management
|
|
|
|
|
|
|
|
|
|
The `NfTablesProxy` class offers advanced capabilities:
|
|
|
|
|
|
|
|
|
|
- Support for multiple port ranges and individual ports
|
|
|
|
|
- More efficient IP filtering using nftables sets
|
|
|
|
|
- IPv6 support with full feature parity
|
|
|
|
|
- Quality of Service (QoS) features including bandwidth limiting and traffic prioritization
|
|
|
|
|
- Advanced connection tracking for stateful NAT
|
|
|
|
|
- Robust error handling with retry mechanisms
|
|
|
|
|
- Structured logging with JSON support
|
|
|
|
|
- NetworkProxy integration for SSL termination
|
|
|
|
|
- Comprehensive cleanup on shutdown
|
|
|
|
|
|
|
|
|
|
### Port80Handler with Glob Pattern Support
|
|
|
|
|
|
|
|
|
|
The `Port80Handler` class includes support for glob pattern domain matching:
|
|
|
|
|
|
|
|
|
|
- Supports wildcard domains like `*.example.com` for HTTP request routing
|
|
|
|
|
- Detects glob patterns and skips certificate issuance for them
|
|
|
|
|
- Smart routing that first attempts exact matches, then tries pattern matching
|
|
|
|
|
- Supports forwarding HTTP requests to backend services
|
|
|
|
|
- Separate forwarding configuration for ACME challenges
|
|
|
|
|
### SmartProxy (IPortProxySettings)
|
|
|
|
|
- `fromPort`, `toPort` (number)
|
|
|
|
|
- `domainConfigs` (IDomainConfig[])
|
|
|
|
|
- `sniEnabled`, `defaultAllowedIPs`, `preserveSourceIP` (booleans)
|
|
|
|
|
- Timeouts: `initialDataTimeout`, `socketTimeout`, `inactivityTimeout`, etc.
|
|
|
|
|
- Socket opts: `noDelay`, `keepAlive`, `enableKeepAliveProbes`
|
|
|
|
|
- `acme` (IAcmeOptions), `certProvider` (callback)
|
|
|
|
|
- `useNetworkProxy` (number[]), `networkProxyPort` (number)
|
|
|
|
|
|
|
|
|
|
## Troubleshooting
|
|
|
|
|
|
|
|
|
|
### Browser Certificate Errors
|
|
|
|
|
### NetworkProxy
|
|
|
|
|
- Verify ports, certificates and `rejectUnauthorized` for TLS errors
|
|
|
|
|
- Configure CORS or use `addDefaultHeaders` for preflight issues
|
|
|
|
|
- Increase `maxConnections` or `connectionPoolSize` under load
|
|
|
|
|
|
|
|
|
|
If you experience certificate errors in browsers, especially in Chrome, try these solutions:
|
|
|
|
|
### Port80Handler
|
|
|
|
|
- Run as root or grant CAP_NET_BIND_SERVICE for port 80
|
|
|
|
|
- Inspect `certificate-failed` events and switch staging/production
|
|
|
|
|
|
|
|
|
|
1. **Increase Initial Data Timeout**: Set `initialDataTimeout` to 60 seconds or higher
|
|
|
|
|
2. **Increase Buffer Size**: Set `maxPendingDataSize` to 10MB or higher
|
|
|
|
|
3. **Enable TLS Debug Logging**: Set `enableTlsDebugLogging: true` to troubleshoot handshake issues
|
|
|
|
|
4. **Enable Keep-Alive Probes**: Set `enableKeepAliveProbes: true` for better connection stability
|
|
|
|
|
5. **Check Certificate Chain**: Ensure your certificate chain is complete and in the correct order
|
|
|
|
|
### NfTablesProxy
|
|
|
|
|
- Ensure `nft` is installed and run with sufficient privileges
|
|
|
|
|
- Use `forceCleanSlate:true` to clear conflicting rules
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Configuration to fix Chrome certificate errors
|
|
|
|
|
const smartProxy = new SmartProxy({
|
|
|
|
|
// ... other settings
|
|
|
|
|
initialDataTimeout: 60000,
|
|
|
|
|
maxPendingDataSize: 10 * 1024 * 1024,
|
|
|
|
|
enableTlsDebugLogging: true,
|
|
|
|
|
enableKeepAliveProbes: true
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
### Redirect / SslRedirect
|
|
|
|
|
- Check `fromHost`/`fromPath` patterns and Host headers
|
|
|
|
|
- Validate `sslOptions` key/cert correctness
|
|
|
|
|
|
|
|
|
|
### Connection Stability
|
|
|
|
|
|
|
|
|
|
For improved connection stability in high-traffic environments:
|
|
|
|
|
|
|
|
|
|
1. **Set Appropriate Timeouts**: Use longer timeouts for long-lived connections
|
|
|
|
|
2. **Use Domain-Specific Timeouts**: Configure per-domain timeouts for different types of services
|
|
|
|
|
3. **Enable TCP Keep-Alive**: Ensure `keepAlive` is set to `true`
|
|
|
|
|
4. **Monitor Connection Statistics**: Enable detailed logging to track termination reasons
|
|
|
|
|
5. **Fine-tune Inactivity Checks**: Adjust `inactivityCheckInterval` based on your traffic patterns
|
|
|
|
|
|
|
|
|
|
### NfTables Troubleshooting
|
|
|
|
|
|
|
|
|
|
If you're experiencing issues with NfTablesProxy:
|
|
|
|
|
|
|
|
|
|
1. **Enable Detailed Logging**: Set `enableLogging: true` to see all rule operations
|
|
|
|
|
2. **Force Clean Slate**: Use `forceCleanSlate: true` to remove any lingering rules
|
|
|
|
|
3. **Use IP Sets**: Enable `useIPSets: true` for cleaner rule management
|
|
|
|
|
4. **Check Permissions**: Ensure your process has sufficient permissions to modify nftables
|
|
|
|
|
5. **Verify IPv6 Support**: If using `ipv6Support: true`, ensure ip6tables is available
|
|
|
|
|
### SmartProxy & SniHandler
|
|
|
|
|
- Increase `initialDataTimeout`/`maxPendingDataSize` for large ClientHello
|
|
|
|
|
- Enable `enableTlsDebugLogging` to trace handshake
|
|
|
|
|
- Ensure `allowSessionTicket` and fragmentation support for resumption
|
|
|
|
|
|
|
|
|
|
## License and Legal Information
|
|
|
|
|
|
|
|
|
|