- Renamed port proxy and SNI handler source files to classes.pp.portproxy.js and classes.pp.snihandler.js respectively - Updated import paths in index.ts and test files (e.g. in test.ts and test.router.ts) to reference the new file names - This refactor improves code organization but breaks direct imports from the old paths
214 lines
6.3 KiB
TypeScript
214 lines
6.3 KiB
TypeScript
import type{ IPortProxySettings } from './classes.pp.interfaces.js';
|
|
|
|
/**
|
|
* Manages port ranges and port-based configuration
|
|
*/
|
|
export class PortRangeManager {
|
|
constructor(private settings: IPortProxySettings) {}
|
|
|
|
/**
|
|
* Get all ports that should be listened on
|
|
*/
|
|
public getListeningPorts(): Set<number> {
|
|
const listeningPorts = new Set<number>();
|
|
|
|
// Always include the main fromPort
|
|
listeningPorts.add(this.settings.fromPort);
|
|
|
|
// Add ports from global port ranges if defined
|
|
if (this.settings.globalPortRanges && this.settings.globalPortRanges.length > 0) {
|
|
for (const range of this.settings.globalPortRanges) {
|
|
for (let port = range.from; port <= range.to; port++) {
|
|
listeningPorts.add(port);
|
|
}
|
|
}
|
|
}
|
|
|
|
return listeningPorts;
|
|
}
|
|
|
|
/**
|
|
* Check if a port should use NetworkProxy for forwarding
|
|
*/
|
|
public shouldUseNetworkProxy(port: number): boolean {
|
|
return !!this.settings.useNetworkProxy && this.settings.useNetworkProxy.includes(port);
|
|
}
|
|
|
|
/**
|
|
* Check if port should use global forwarding
|
|
*/
|
|
public shouldUseGlobalForwarding(port: number): boolean {
|
|
return (
|
|
!!this.settings.forwardAllGlobalRanges &&
|
|
this.isPortInGlobalRanges(port)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if a port is in global ranges
|
|
*/
|
|
public isPortInGlobalRanges(port: number): boolean {
|
|
return (
|
|
this.settings.globalPortRanges &&
|
|
this.isPortInRanges(port, this.settings.globalPortRanges)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if a port falls within the specified ranges
|
|
*/
|
|
public isPortInRanges(port: number, ranges: Array<{ from: number; to: number }>): boolean {
|
|
return ranges.some((range) => port >= range.from && port <= range.to);
|
|
}
|
|
|
|
/**
|
|
* Get forwarding port for a specific listening port
|
|
* This determines what port to connect to on the target
|
|
*/
|
|
public getForwardingPort(listeningPort: number): number {
|
|
// If using global forwarding, forward to the original port
|
|
if (this.settings.forwardAllGlobalRanges && this.isPortInGlobalRanges(listeningPort)) {
|
|
return listeningPort;
|
|
}
|
|
|
|
// Otherwise use the configured toPort
|
|
return this.settings.toPort;
|
|
}
|
|
|
|
/**
|
|
* Find domain-specific port ranges that include a given port
|
|
*/
|
|
public findDomainPortRange(port: number): {
|
|
domainIndex: number,
|
|
range: { from: number, to: number }
|
|
} | undefined {
|
|
for (let i = 0; i < this.settings.domainConfigs.length; i++) {
|
|
const domain = this.settings.domainConfigs[i];
|
|
if (domain.portRanges) {
|
|
for (const range of domain.portRanges) {
|
|
if (port >= range.from && port <= range.to) {
|
|
return { domainIndex: i, range };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
/**
|
|
* Get a list of all configured ports
|
|
* This includes the fromPort, NetworkProxy ports, and ports from all ranges
|
|
*/
|
|
public getAllConfiguredPorts(): number[] {
|
|
const ports = new Set<number>();
|
|
|
|
// Add main listening port
|
|
ports.add(this.settings.fromPort);
|
|
|
|
// Add NetworkProxy port if configured
|
|
if (this.settings.networkProxyPort) {
|
|
ports.add(this.settings.networkProxyPort);
|
|
}
|
|
|
|
// Add NetworkProxy ports
|
|
if (this.settings.useNetworkProxy) {
|
|
for (const port of this.settings.useNetworkProxy) {
|
|
ports.add(port);
|
|
}
|
|
}
|
|
|
|
// Add ACME HTTP challenge port if enabled
|
|
if (this.settings.acme?.enabled && this.settings.acme.port) {
|
|
ports.add(this.settings.acme.port);
|
|
}
|
|
|
|
// Add global port ranges
|
|
if (this.settings.globalPortRanges) {
|
|
for (const range of this.settings.globalPortRanges) {
|
|
for (let port = range.from; port <= range.to; port++) {
|
|
ports.add(port);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add domain-specific port ranges
|
|
for (const domain of this.settings.domainConfigs) {
|
|
if (domain.portRanges) {
|
|
for (const range of domain.portRanges) {
|
|
for (let port = range.from; port <= range.to; port++) {
|
|
ports.add(port);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add domain-specific NetworkProxy port if configured
|
|
if (domain.useNetworkProxy && domain.networkProxyPort) {
|
|
ports.add(domain.networkProxyPort);
|
|
}
|
|
}
|
|
|
|
return Array.from(ports);
|
|
}
|
|
|
|
/**
|
|
* Validate port configuration
|
|
* Returns array of warning messages
|
|
*/
|
|
public validateConfiguration(): string[] {
|
|
const warnings: string[] = [];
|
|
|
|
// Check for overlapping port ranges
|
|
const portMappings = new Map<number, string[]>();
|
|
|
|
// Track global port ranges
|
|
if (this.settings.globalPortRanges) {
|
|
for (const range of this.settings.globalPortRanges) {
|
|
for (let port = range.from; port <= range.to; port++) {
|
|
if (!portMappings.has(port)) {
|
|
portMappings.set(port, []);
|
|
}
|
|
portMappings.get(port)!.push('Global Port Range');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Track domain-specific port ranges
|
|
for (const domain of this.settings.domainConfigs) {
|
|
if (domain.portRanges) {
|
|
for (const range of domain.portRanges) {
|
|
for (let port = range.from; port <= range.to; port++) {
|
|
if (!portMappings.has(port)) {
|
|
portMappings.set(port, []);
|
|
}
|
|
portMappings.get(port)!.push(`Domain: ${domain.domains.join(', ')}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for ports with multiple mappings
|
|
for (const [port, mappings] of portMappings.entries()) {
|
|
if (mappings.length > 1) {
|
|
warnings.push(`Port ${port} has multiple mappings: ${mappings.join(', ')}`);
|
|
}
|
|
}
|
|
|
|
// Check if main ports are used elsewhere
|
|
if (portMappings.has(this.settings.fromPort) && portMappings.get(this.settings.fromPort)!.length > 0) {
|
|
warnings.push(`Main listening port ${this.settings.fromPort} is also used in port ranges`);
|
|
}
|
|
|
|
if (this.settings.networkProxyPort && portMappings.has(this.settings.networkProxyPort)) {
|
|
warnings.push(`NetworkProxy port ${this.settings.networkProxyPort} is also used in port ranges`);
|
|
}
|
|
|
|
// Check ACME port
|
|
if (this.settings.acme?.enabled && this.settings.acme.port) {
|
|
if (portMappings.has(this.settings.acme.port)) {
|
|
warnings.push(`ACME HTTP challenge port ${this.settings.acme.port} is also used in port ranges`);
|
|
}
|
|
}
|
|
|
|
return warnings;
|
|
}
|
|
} |