update
This commit is contained in:
@ -153,7 +153,7 @@ export function convertLegacyConfigToRouteConfig(
|
||||
|
||||
// Add authentication if present
|
||||
if (legacyConfig.authentication) {
|
||||
routeConfig.action.security = {
|
||||
routeConfig.security = {
|
||||
authentication: {
|
||||
type: 'basic',
|
||||
credentials: [{
|
||||
|
@ -233,9 +233,6 @@ export interface IRouteAction {
|
||||
// Load balancing options
|
||||
loadBalancing?: IRouteLoadBalancing;
|
||||
|
||||
// Security options
|
||||
security?: IRouteSecurity;
|
||||
|
||||
// Advanced options
|
||||
advanced?: IRouteAdvanced;
|
||||
|
||||
|
@ -175,13 +175,12 @@ export class NFTablesManager {
|
||||
};
|
||||
|
||||
// Add security-related options
|
||||
const security = action.security || route.security;
|
||||
if (security?.ipAllowList?.length) {
|
||||
options.ipAllowList = security.ipAllowList;
|
||||
if (route.security?.ipAllowList?.length) {
|
||||
options.ipAllowList = route.security.ipAllowList;
|
||||
}
|
||||
|
||||
if (security?.ipBlockList?.length) {
|
||||
options.ipBlockList = security.ipBlockList;
|
||||
if (route.security?.ipBlockList?.length) {
|
||||
options.ipBlockList = route.security.ipBlockList;
|
||||
}
|
||||
|
||||
// Add QoS options
|
||||
|
@ -146,18 +146,42 @@ export class RouteConnectionHandler {
|
||||
);
|
||||
}
|
||||
|
||||
// Start TLS SNI handling
|
||||
this.handleTlsConnection(socket, record);
|
||||
// Handle the connection - wait for initial data to determine if it's TLS
|
||||
this.handleInitialData(socket, record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a connection and wait for TLS handshake for SNI extraction if needed
|
||||
* Handle initial data from a connection to determine routing
|
||||
*/
|
||||
private handleTlsConnection(socket: plugins.net.Socket, record: IConnectionRecord): void {
|
||||
private handleInitialData(socket: plugins.net.Socket, record: IConnectionRecord): void {
|
||||
const connectionId = record.id;
|
||||
const localPort = record.localPort;
|
||||
let initialDataReceived = false;
|
||||
|
||||
// Check if any routes on this port require TLS handling
|
||||
const allRoutes = this.routeManager.getAllRoutes();
|
||||
const needsTlsHandling = allRoutes.some(route => {
|
||||
// Check if route matches this port
|
||||
const matchesPort = this.routeManager.getRoutesForPort(localPort).includes(route);
|
||||
|
||||
return matchesPort &&
|
||||
route.action.type === 'forward' &&
|
||||
route.action.tls &&
|
||||
(route.action.tls.mode === 'terminate' ||
|
||||
route.action.tls.mode === 'passthrough');
|
||||
});
|
||||
|
||||
// If no routes require TLS handling and it's not port 443, route immediately
|
||||
if (!needsTlsHandling && localPort !== 443) {
|
||||
// Set up error handler
|
||||
socket.on('error', this.connectionManager.handleError('incoming', record));
|
||||
|
||||
// Route immediately for non-TLS connections
|
||||
this.routeConnection(socket, record, '', undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, wait for initial data to check if it's TLS
|
||||
// Set an initial timeout for handshake data
|
||||
let initialTimeout: NodeJS.Timeout | null = setTimeout(() => {
|
||||
if (!initialDataReceived) {
|
||||
@ -382,6 +406,56 @@ export class RouteConnectionHandler {
|
||||
});
|
||||
}
|
||||
|
||||
// Apply route-specific security checks
|
||||
if (route.security) {
|
||||
// Check IP allow/block lists
|
||||
if (route.security.ipAllowList || route.security.ipBlockList) {
|
||||
const isIPAllowed = this.securityManager.isIPAuthorized(
|
||||
remoteIP,
|
||||
route.security.ipAllowList || [],
|
||||
route.security.ipBlockList || []
|
||||
);
|
||||
|
||||
if (!isIPAllowed) {
|
||||
logger.log('warn', `IP ${remoteIP} blocked by route security for route ${route.name || 'unnamed'} (connection: ${connectionId})`, {
|
||||
connectionId,
|
||||
remoteIP,
|
||||
routeName: route.name || 'unnamed',
|
||||
component: 'route-handler'
|
||||
});
|
||||
socket.end();
|
||||
this.connectionManager.cleanupConnection(record, 'route_ip_blocked');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check max connections per route
|
||||
if (route.security.maxConnections !== undefined) {
|
||||
// TODO: Implement per-route connection tracking
|
||||
// For now, log that this feature is not yet implemented
|
||||
if (this.settings.enableDetailedLogging) {
|
||||
logger.log('warn', `Route ${route.name} has maxConnections=${route.security.maxConnections} configured but per-route connection limits are not yet implemented`, {
|
||||
connectionId,
|
||||
routeName: route.name,
|
||||
component: 'route-handler'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Check authentication requirements
|
||||
if (route.security.authentication || route.security.basicAuth || route.security.jwtAuth) {
|
||||
// Authentication checks would typically happen at the HTTP layer
|
||||
// For non-HTTP connections or passthrough, we can't enforce authentication
|
||||
if (route.action.type === 'forward' && route.action.tls?.mode !== 'terminate') {
|
||||
logger.log('warn', `Route ${route.name} has authentication configured but it cannot be enforced for non-terminated connections`, {
|
||||
connectionId,
|
||||
routeName: route.name,
|
||||
tlsMode: route.action.tls?.mode || 'none',
|
||||
component: 'route-handler'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the route based on its action type
|
||||
switch (route.action.type) {
|
||||
|
@ -211,9 +211,10 @@ export class RouteManager extends plugins.EventEmitter {
|
||||
|
||||
/**
|
||||
* Check if a client IP is allowed by a route's security settings
|
||||
* @deprecated Security is now checked in route-connection-handler.ts after route matching
|
||||
*/
|
||||
private isClientIpAllowed(route: IRouteConfig, clientIp: string): boolean {
|
||||
const security = route.action.security;
|
||||
const security = route.security;
|
||||
|
||||
if (!security) {
|
||||
return true; // No security settings means allowed
|
||||
@ -371,12 +372,8 @@ export class RouteManager extends plugins.EventEmitter {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check security settings
|
||||
if (!this.isClientIpAllowed(route, clientIp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// All checks passed, this route matches
|
||||
// NOTE: Security is checked AFTER route matching in route-connection-handler.ts
|
||||
return { route };
|
||||
}
|
||||
|
||||
|
@ -625,14 +625,6 @@ export function createNfTablesRoute(
|
||||
}
|
||||
};
|
||||
|
||||
// Add security if allowed or blocked IPs are specified
|
||||
if (options.ipAllowList?.length || options.ipBlockList?.length) {
|
||||
action.security = {
|
||||
ipAllowList: options.ipAllowList,
|
||||
ipBlockList: options.ipBlockList
|
||||
};
|
||||
}
|
||||
|
||||
// Add TLS options if needed
|
||||
if (options.useTls) {
|
||||
action.tls = {
|
||||
@ -641,11 +633,21 @@ export function createNfTablesRoute(
|
||||
}
|
||||
|
||||
// Create the route config
|
||||
return {
|
||||
const routeConfig: IRouteConfig = {
|
||||
name,
|
||||
match,
|
||||
action
|
||||
};
|
||||
|
||||
// Add security if allowed or blocked IPs are specified
|
||||
if (options.ipAllowList?.length || options.ipBlockList?.length) {
|
||||
routeConfig.security = {
|
||||
ipAllowList: options.ipAllowList,
|
||||
ipBlockList: options.ipBlockList
|
||||
};
|
||||
}
|
||||
|
||||
return routeConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user