fix(smartproxy): Update dynamic port mapping to support
This commit is contained in:
parent
2d6f06a9b3
commit
340823296a
15
changelog.md
15
changelog.md
@ -1,5 +1,20 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-05-14 - 16.0.4 - fix(smartproxy)
|
||||||
|
Update dynamic port mapping to support 'preserve' target port value
|
||||||
|
|
||||||
|
- Refactored NetworkProxy to use a default port for 'preserve' values, correctly falling back to the incoming port when target.port is set to 'preserve'.
|
||||||
|
- Updated RequestHandler and WebSocketHandler to check for 'preserve' target port instead of legacy preservePort flag.
|
||||||
|
- Modified IRouteTarget type definitions to allow 'preserve' as a valid target port value.
|
||||||
|
|
||||||
|
## 2025-05-14 - 16.0.4 - fix(smartproxy)
|
||||||
|
Fix dynamic port mapping: update target port resolution to properly handle 'preserve' values across route configurations. Now, when a route's target port is set to 'preserve', the incoming port is used consistently in NetworkProxy, RequestHandler, WebSocketHandler, and RouteConnectionHandler. Also update type definitions in IRouteTarget to support 'preserve'.
|
||||||
|
|
||||||
|
- Refactored port resolution in NetworkProxy to use a default port for 'preserve' and then correctly fall back to the incoming port when 'preserve' is specified.
|
||||||
|
- Updated RequestHandler and WebSocketHandler to check if target.port equals 'preserve' instead of using a legacy 'preservePort' flag.
|
||||||
|
- Modified RouteConnectionHandler to correctly resolve dynamic port mappings with 'preserve'.
|
||||||
|
- Updated route type definitions to allow 'preserve' as a valid target port value.
|
||||||
|
|
||||||
## 2025-05-14 - 16.0.3 - fix(network-proxy, route-utils, route-manager)
|
## 2025-05-14 - 16.0.3 - fix(network-proxy, route-utils, route-manager)
|
||||||
Normalize IPv6-mapped IPv4 addresses in IP matching functions and remove deprecated legacy configuration methods in NetworkProxy. Update route-utils and route-manager to compare both canonical and IPv6-mapped IP forms, adjust tests accordingly, and clean up legacy exports.
|
Normalize IPv6-mapped IPv4 addresses in IP matching functions and remove deprecated legacy configuration methods in NetworkProxy. Update route-utils and route-manager to compare both canonical and IPv6-mapped IP forms, adjust tests accordingly, and clean up legacy exports.
|
||||||
|
|
||||||
|
468
docs/porthandling.md
Normal file
468
docs/porthandling.md
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
# SmartProxy Port Handling
|
||||||
|
|
||||||
|
This document covers all the port handling capabilities in SmartProxy, including port range specification, dynamic port mapping, and runtime port management.
|
||||||
|
|
||||||
|
## Port Range Syntax
|
||||||
|
|
||||||
|
SmartProxy offers flexible port range specification through the `TPortRange` type, which can be defined in three different ways:
|
||||||
|
|
||||||
|
### 1. Single Port
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Match a single port
|
||||||
|
{
|
||||||
|
match: {
|
||||||
|
ports: 443
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Array of Specific Ports
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Match multiple specific ports
|
||||||
|
{
|
||||||
|
match: {
|
||||||
|
ports: [80, 443, 8080]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Port Range
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Match a range of ports
|
||||||
|
{
|
||||||
|
match: {
|
||||||
|
ports: [{ from: 8000, to: 8100 }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Mixed Port Specifications
|
||||||
|
|
||||||
|
You can combine different port specification methods in a single rule:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Match both specific ports and port ranges
|
||||||
|
{
|
||||||
|
match: {
|
||||||
|
ports: [80, 443, { from: 8000, to: 8100 }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Port Forwarding Options
|
||||||
|
|
||||||
|
SmartProxy offers several ways to handle port forwarding from source to target:
|
||||||
|
|
||||||
|
### 1. Static Port Forwarding
|
||||||
|
|
||||||
|
Forward to a fixed target port:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'backend.example.com',
|
||||||
|
port: 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Preserve Source Port
|
||||||
|
|
||||||
|
Forward to the same port on the target:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'backend.example.com',
|
||||||
|
port: 'preserve'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Dynamic Port Mapping
|
||||||
|
|
||||||
|
Use a function to determine the target port based on connection context:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'backend.example.com',
|
||||||
|
port: (context) => {
|
||||||
|
// Calculate port based on request details
|
||||||
|
return 8000 + (context.port % 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Port Selection Context
|
||||||
|
|
||||||
|
When using dynamic port mapping functions, you have access to a rich context object that provides details about the connection:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IRouteContext {
|
||||||
|
// Connection information
|
||||||
|
port: number; // The matched incoming port
|
||||||
|
domain?: string; // The domain from SNI or Host header
|
||||||
|
clientIp: string; // The client's IP address
|
||||||
|
serverIp: string; // The server's IP address
|
||||||
|
path?: string; // URL path (for HTTP connections)
|
||||||
|
query?: string; // Query string (for HTTP connections)
|
||||||
|
headers?: Record<string, string>; // HTTP headers (for HTTP connections)
|
||||||
|
|
||||||
|
// TLS information
|
||||||
|
isTls: boolean; // Whether the connection is TLS
|
||||||
|
tlsVersion?: string; // TLS version if applicable
|
||||||
|
|
||||||
|
// Route information
|
||||||
|
routeName?: string; // The name of the matched route
|
||||||
|
routeId?: string; // The ID of the matched route
|
||||||
|
|
||||||
|
// Additional properties
|
||||||
|
timestamp: number; // The request timestamp
|
||||||
|
connectionId: string; // Unique connection identifier
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Port Mapping Patterns
|
||||||
|
|
||||||
|
### 1. Port Offset Mapping
|
||||||
|
|
||||||
|
Forward traffic to target ports with a fixed offset:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'backend.example.com',
|
||||||
|
port: (context) => context.port + 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Domain-Based Port Mapping
|
||||||
|
|
||||||
|
Forward to different backend ports based on the domain:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'backend.example.com',
|
||||||
|
port: (context) => {
|
||||||
|
switch (context.domain) {
|
||||||
|
case 'api.example.com': return 8001;
|
||||||
|
case 'admin.example.com': return 8002;
|
||||||
|
case 'staging.example.com': return 8003;
|
||||||
|
default: return 8000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Load Balancing with Hash-Based Distribution
|
||||||
|
|
||||||
|
Distribute connections across a port range using a deterministic hash function:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'backend.example.com',
|
||||||
|
port: (context) => {
|
||||||
|
// Simple hash function to ensure consistent mapping
|
||||||
|
const hostname = context.domain || '';
|
||||||
|
const hash = hostname.split('').reduce((a, b) => a + b.charCodeAt(0), 0);
|
||||||
|
return 8000 + (hash % 10); // Map to ports 8000-8009
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## IPv6-Mapped IPv4 Compatibility
|
||||||
|
|
||||||
|
SmartProxy automatically handles IPv6-mapped IPv4 addresses for optimal compatibility. When a connection from an IPv4 address (e.g., `192.168.1.1`) arrives as an IPv6-mapped address (`::ffff:192.168.1.1`), the system normalizes these addresses for consistent matching.
|
||||||
|
|
||||||
|
This is particularly important when:
|
||||||
|
|
||||||
|
1. Matching client IP restrictions in route configurations
|
||||||
|
2. Preserving source IP for outgoing connections
|
||||||
|
3. Tracking connections and rate limits
|
||||||
|
|
||||||
|
No special configuration is needed - the system handles this normalization automatically.
|
||||||
|
|
||||||
|
## Dynamic Port Management
|
||||||
|
|
||||||
|
SmartProxy allows for runtime port configuration changes without requiring a restart.
|
||||||
|
|
||||||
|
### Adding and Removing Ports
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Get the SmartProxy instance
|
||||||
|
const proxy = new SmartProxy({ /* config */ });
|
||||||
|
|
||||||
|
// Add a new listening port
|
||||||
|
await proxy.addListeningPort(8081);
|
||||||
|
|
||||||
|
// Remove a listening port
|
||||||
|
await proxy.removeListeningPort(8082);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Runtime Route Updates
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Get current routes
|
||||||
|
const currentRoutes = proxy.getRoutes();
|
||||||
|
|
||||||
|
// Add new route for the new port
|
||||||
|
const newRoute = {
|
||||||
|
name: 'New Dynamic Route',
|
||||||
|
match: {
|
||||||
|
ports: 8081,
|
||||||
|
domains: ['dynamic.example.com']
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'backend.example.com',
|
||||||
|
port: 9000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update the route configuration
|
||||||
|
await proxy.updateRoutes([...currentRoutes, newRoute]);
|
||||||
|
|
||||||
|
// Remove routes for a specific port
|
||||||
|
const routesWithout8082 = currentRoutes.filter(route => {
|
||||||
|
const ports = proxy.routeManager.expandPortRange(route.match.ports);
|
||||||
|
return !ports.includes(8082);
|
||||||
|
});
|
||||||
|
await proxy.updateRoutes(routesWithout8082);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Port Range Expansion
|
||||||
|
|
||||||
|
When using large port ranges, SmartProxy uses internal caching to optimize performance. For example, a range like `{ from: 1000, to: 2000 }` is expanded only once and then cached for future use.
|
||||||
|
|
||||||
|
### Port Range Validation
|
||||||
|
|
||||||
|
The system automatically validates port ranges to ensure:
|
||||||
|
|
||||||
|
1. Port numbers are within the valid range (1-65535)
|
||||||
|
2. The "from" value is not greater than the "to" value in range specifications
|
||||||
|
3. Port ranges do not contain duplicate entries
|
||||||
|
|
||||||
|
Invalid port ranges will be logged as warnings and skipped during configuration.
|
||||||
|
|
||||||
|
## Configuration Recipes
|
||||||
|
|
||||||
|
### Global Port Range
|
||||||
|
|
||||||
|
Listen on a large range of ports and forward to the same ports on a backend:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
name: 'Global port range forwarding',
|
||||||
|
match: {
|
||||||
|
ports: [{ from: 8000, to: 9000 }]
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'backend.example.com',
|
||||||
|
port: 'preserve'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Domain-Specific Port Ranges
|
||||||
|
|
||||||
|
Different port ranges for different domain groups:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'API port range',
|
||||||
|
match: {
|
||||||
|
ports: [{ from: 8000, to: 8099 }]
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'api.backend.example.com',
|
||||||
|
port: 'preserve'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Admin port range',
|
||||||
|
match: {
|
||||||
|
ports: [{ from: 9000, to: 9099 }]
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'admin.backend.example.com',
|
||||||
|
port: 'preserve'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mixed Internal/External Port Forwarding
|
||||||
|
|
||||||
|
Forward specific high-numbered ports to standard ports on internal servers:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'Web server forwarding',
|
||||||
|
match: {
|
||||||
|
ports: [8080, 8443]
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'web.internal',
|
||||||
|
port: (context) => context.port === 8080 ? 80 : 443
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Database forwarding',
|
||||||
|
match: {
|
||||||
|
ports: [15432]
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'db.internal',
|
||||||
|
port: 5432
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging Port Configurations
|
||||||
|
|
||||||
|
When troubleshooting port forwarding issues, enable detailed logging:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const proxy = new SmartProxy({
|
||||||
|
routes: [ /* your routes */ ],
|
||||||
|
enableDetailedLogging: true
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
This will log:
|
||||||
|
- Port configuration during startup
|
||||||
|
- Port matching decisions during routing
|
||||||
|
- Dynamic port function results
|
||||||
|
- Connection details including source and target ports
|
||||||
|
|
||||||
|
## Port Security Considerations
|
||||||
|
|
||||||
|
### Restricting Ports
|
||||||
|
|
||||||
|
For security, you may want to restrict which ports can be accessed by specific clients:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
name: 'Restricted port range',
|
||||||
|
match: {
|
||||||
|
ports: [{ from: 8000, to: 9000 }],
|
||||||
|
clientIp: ['10.0.0.0/8'] // Only internal network can access these ports
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'internal.example.com',
|
||||||
|
port: 'preserve'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rate Limiting by Port
|
||||||
|
|
||||||
|
Apply different rate limits for different port ranges:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
name: 'API ports with rate limiting',
|
||||||
|
match: {
|
||||||
|
ports: [{ from: 8000, to: 8100 }]
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
target: {
|
||||||
|
host: 'api.example.com',
|
||||||
|
port: 'preserve'
|
||||||
|
},
|
||||||
|
security: {
|
||||||
|
rateLimit: {
|
||||||
|
enabled: true,
|
||||||
|
maxRequests: 100,
|
||||||
|
window: 60 // 60 seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use Specific Port Ranges**: Instead of large ranges (e.g., 1-65535), use specific ranges for specific purposes
|
||||||
|
|
||||||
|
2. **Prioritize Routes**: When multiple routes could match, use the `priority` field to ensure the most specific route is matched first
|
||||||
|
|
||||||
|
3. **Name Your Routes**: Use descriptive names to make debugging easier, especially when using port ranges
|
||||||
|
|
||||||
|
4. **Use Preserve Port Where Possible**: Using `port: 'preserve'` is more efficient and easier to maintain than creating multiple specific mappings
|
||||||
|
|
||||||
|
5. **Limit Dynamic Port Functions**: While powerful, complex port functions can be harder to debug; prefer simple map or math-based functions
|
||||||
|
|
||||||
|
6. **Use Port Variables**: For complex setups, define your port ranges as variables for easier maintenance:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const API_PORTS = [{ from: 8000, to: 8099 }];
|
||||||
|
const ADMIN_PORTS = [{ from: 9000, to: 9099 }];
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
name: 'API Routes',
|
||||||
|
match: { ports: API_PORTS, /* ... */ },
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Admin Routes',
|
||||||
|
match: { ports: ADMIN_PORTS, /* ... */ },
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartproxy',
|
name: '@push.rocks/smartproxy',
|
||||||
version: '16.0.3',
|
version: '16.0.4',
|
||||||
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
||||||
}
|
}
|
||||||
|
@ -447,6 +447,8 @@ export class NetworkProxy implements IMetricsTracker {
|
|||||||
|
|
||||||
// Create legacy proxy configs for the router
|
// Create legacy proxy configs for the router
|
||||||
// This is only needed for backward compatibility with ProxyRouter
|
// This is only needed for backward compatibility with ProxyRouter
|
||||||
|
|
||||||
|
const defaultPort = 443; // Default port for HTTPS when using 'preserve'
|
||||||
// and will be removed in the future
|
// and will be removed in the future
|
||||||
const legacyConfigs: IReverseProxyConfig[] = [];
|
const legacyConfigs: IReverseProxyConfig[] = [];
|
||||||
|
|
||||||
@ -472,7 +474,8 @@ export class NetworkProxy implements IMetricsTracker {
|
|||||||
? route.action.target.host
|
? route.action.target.host
|
||||||
: [route.action.target.host];
|
: [route.action.target.host];
|
||||||
|
|
||||||
const targetPort = route.action.target.port;
|
// Handle 'preserve' port value
|
||||||
|
const targetPort = route.action.target.port === 'preserve' ? defaultPort : route.action.target.port;
|
||||||
|
|
||||||
// Get certificate information
|
// Get certificate information
|
||||||
const certData = certificateUpdates.get(domain);
|
const certData = certificateUpdates.get(domain);
|
||||||
|
@ -540,7 +540,7 @@ export class RequestHandler {
|
|||||||
this.logger.debug(`Resolved function-based port to: ${resolvedPort}`);
|
this.logger.debug(`Resolved function-based port to: ${resolvedPort}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
targetPort = matchingRoute.action.target.port;
|
targetPort = matchingRoute.action.target.port === 'preserve' ? routeContext.port : matchingRoute.action.target.port as number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select a single host if an array was provided
|
// Select a single host if an array was provided
|
||||||
@ -760,7 +760,7 @@ export class RequestHandler {
|
|||||||
this.logger.debug(`Resolved HTTP/2 function-based port to: ${resolvedPort}`);
|
this.logger.debug(`Resolved HTTP/2 function-based port to: ${resolvedPort}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
targetPort = matchingRoute.action.target.port;
|
targetPort = matchingRoute.action.target.port === 'preserve' ? routeContext.port : matchingRoute.action.target.port as number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select a single host if an array was provided
|
// Select a single host if an array was provided
|
||||||
|
@ -204,7 +204,7 @@ export class WebSocketHandler {
|
|||||||
targetPort = route.action.target.port(toBaseContext(routeContext));
|
targetPort = route.action.target.port(toBaseContext(routeContext));
|
||||||
this.logger.debug(`Resolved function-based port for WebSocket: ${targetPort}`);
|
this.logger.debug(`Resolved function-based port for WebSocket: ${targetPort}`);
|
||||||
} else {
|
} else {
|
||||||
targetPort = route.action.target.port;
|
targetPort = route.action.target.port === 'preserve' ? routeContext.port : route.action.target.port as number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select a single host if an array was provided
|
// Select a single host if an array was provided
|
||||||
|
@ -69,8 +69,7 @@ export interface IRouteContext {
|
|||||||
*/
|
*/
|
||||||
export interface IRouteTarget {
|
export interface IRouteTarget {
|
||||||
host: string | string[] | ((context: IRouteContext) => string | string[]); // Host or hosts with optional function for dynamic resolution
|
host: string | string[] | ((context: IRouteContext) => string | string[]); // Host or hosts with optional function for dynamic resolution
|
||||||
port: number | ((context: IRouteContext) => number); // Port with optional function for dynamic mapping
|
port: number | 'preserve' | ((context: IRouteContext) => number); // Port with optional function for dynamic mapping (use 'preserve' to keep the incoming port)
|
||||||
preservePort?: boolean; // Use incoming port as target port (ignored if port is a function)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -434,8 +434,8 @@ export class RouteConnectionHandler {
|
|||||||
this.connectionManager.cleanupConnection(record, 'port_mapping_error');
|
this.connectionManager.cleanupConnection(record, 'port_mapping_error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (action.target.preservePort) {
|
} else if (action.target.port === 'preserve') {
|
||||||
// Use incoming port if preservePort is true
|
// Use incoming port if port is 'preserve'
|
||||||
targetPort = record.localPort;
|
targetPort = record.localPort;
|
||||||
} else {
|
} else {
|
||||||
// Use static port from configuration
|
// Use static port from configuration
|
||||||
@ -525,7 +525,7 @@ export class RouteConnectionHandler {
|
|||||||
let targetPort: number;
|
let targetPort: number;
|
||||||
if (typeof action.target.port === 'function') {
|
if (typeof action.target.port === 'function') {
|
||||||
targetPort = action.target.port(routeContext);
|
targetPort = action.target.port(routeContext);
|
||||||
} else if (action.target.preservePort) {
|
} else if (action.target.port === 'preserve') {
|
||||||
targetPort = record.localPort;
|
targetPort = record.localPort;
|
||||||
} else {
|
} else {
|
||||||
targetPort = action.target.port;
|
targetPort = action.target.port;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user