@serve.zone/dcrouter 13.38.4 → 13.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deno.json +1 -1
- package/dist_serve/bundle.js +350 -343
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/db/documents/classes.remote-ingress-edge.doc.d.ts +2 -0
- package/dist_ts/db/documents/classes.remote-ingress-edge.doc.js +8 -2
- package/dist_ts/http3/http3-route-augmentation.d.ts +1 -1
- package/dist_ts/http3/http3-route-augmentation.js +3 -17
- package/dist_ts/monitoring/classes.metricsmanager.d.ts +2 -0
- package/dist_ts/monitoring/classes.metricsmanager.js +53 -19
- package/dist_ts/opsserver/handlers/remoteingress.handler.js +3 -2
- package/dist_ts/opsserver/handlers/security.handler.d.ts +2 -0
- package/dist_ts/opsserver/handlers/security.handler.js +50 -73
- package/dist_ts/radius/classes.radius.server.d.ts +0 -5
- package/dist_ts/radius/classes.radius.server.js +46 -78
- package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +4 -2
- package/dist_ts/remoteingress/classes.remoteingress-manager.js +9 -21
- package/dist_ts_interfaces/data/remoteingress.d.ts +10 -0
- package/dist_ts_interfaces/requests/remoteingress.d.ts +3 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +2 -0
- package/dist_ts_web/appstate.js +3 -1
- package/dist_ts_web/elements/network/ops-view-remoteingress.d.ts +2 -0
- package/dist_ts_web/elements/network/ops-view-remoteingress.js +55 -2
- package/dist_ts_web/elements/overview/ops-view-config.js +4 -1
- package/package.json +3 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/db/documents/classes.remote-ingress-edge.doc.ts +4 -0
- package/ts/http3/http3-route-augmentation.ts +2 -18
- package/ts/monitoring/classes.metricsmanager.ts +59 -21
- package/ts/opsserver/handlers/remoteingress.handler.ts +2 -0
- package/ts/opsserver/handlers/security.handler.ts +57 -109
- package/ts/radius/classes.radius.server.ts +54 -80
- package/ts/remoteingress/classes.remoteingress-manager.ts +12 -21
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +4 -0
- package/ts_web/elements/network/ops-view-remoteingress.ts +57 -1
- package/ts_web/elements/overview/ops-view-config.ts +10 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
3
|
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
4
|
-
import { MetricsManager } from '../../monitoring/index.js';
|
|
5
4
|
import { requireOpsAuth } from '../helpers/auth.js';
|
|
6
5
|
|
|
7
6
|
export class SecurityHandler {
|
|
@@ -46,18 +45,7 @@ export class SecurityHandler {
|
|
|
46
45
|
'getActiveConnections',
|
|
47
46
|
async (dataArg, toolsArg) => {
|
|
48
47
|
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'stats:read' });
|
|
49
|
-
const
|
|
50
|
-
const connectionInfos: interfaces.data.IConnectionInfo[] = connections.map(conn => ({
|
|
51
|
-
id: conn.id,
|
|
52
|
-
remoteAddress: conn.source.ip,
|
|
53
|
-
localAddress: conn.destination.ip,
|
|
54
|
-
startTime: conn.startTime,
|
|
55
|
-
protocol: conn.type === 'http' ? 'https' : conn.type as any,
|
|
56
|
-
state: conn.status === 'active' ? 'connected' : conn.status as any,
|
|
57
|
-
bytesReceived: (conn as any)._throughputIn || 0,
|
|
58
|
-
bytesSent: (conn as any)._throughputOut || 0,
|
|
59
|
-
connectionCount: conn.bytesTransferred || 1,
|
|
60
|
-
}));
|
|
48
|
+
const connectionInfos = await this.getActiveConnections(dataArg.protocol, dataArg.state);
|
|
61
49
|
const totalConnections = connectionInfos.reduce((sum, conn) => sum + (conn.connectionCount || 1), 0);
|
|
62
50
|
|
|
63
51
|
const summary = {
|
|
@@ -362,106 +350,66 @@ export class SecurityHandler {
|
|
|
362
350
|
private async getActiveConnections(
|
|
363
351
|
protocol?: 'http' | 'https' | 'smtp' | 'smtps',
|
|
364
352
|
state?: string
|
|
365
|
-
): Promise<
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
port: number;
|
|
371
|
-
country?: string;
|
|
372
|
-
};
|
|
373
|
-
destination: {
|
|
374
|
-
ip: string;
|
|
375
|
-
port: number;
|
|
376
|
-
service?: string;
|
|
377
|
-
};
|
|
378
|
-
startTime: number;
|
|
379
|
-
bytesTransferred: number;
|
|
380
|
-
status: 'active' | 'idle' | 'closing';
|
|
381
|
-
}>> {
|
|
382
|
-
const connections: Array<{
|
|
383
|
-
id: string;
|
|
384
|
-
type: 'http' | 'smtp' | 'dns';
|
|
385
|
-
source: {
|
|
386
|
-
ip: string;
|
|
387
|
-
port: number;
|
|
388
|
-
country?: string;
|
|
389
|
-
};
|
|
390
|
-
destination: {
|
|
391
|
-
ip: string;
|
|
392
|
-
port: number;
|
|
393
|
-
service?: string;
|
|
394
|
-
};
|
|
395
|
-
startTime: number;
|
|
396
|
-
bytesTransferred: number;
|
|
397
|
-
status: 'active' | 'idle' | 'closing';
|
|
398
|
-
}> = [];
|
|
399
|
-
|
|
400
|
-
// Get connection info and network stats from MetricsManager if available
|
|
401
|
-
if (this.opsServerRef.dcRouterRef.metricsManager) {
|
|
402
|
-
const connectionInfo = await this.opsServerRef.dcRouterRef.metricsManager.getConnectionInfo();
|
|
403
|
-
const networkStats = await this.opsServerRef.dcRouterRef.metricsManager.getNetworkStats();
|
|
404
|
-
|
|
405
|
-
// One aggregate row per IP with real throughput data
|
|
406
|
-
if (networkStats.connectionsByIP && networkStats.connectionsByIP.size > 0) {
|
|
407
|
-
let connIndex = 0;
|
|
408
|
-
const publicIp = this.opsServerRef.dcRouterRef.options.publicIp || 'server';
|
|
353
|
+
): Promise<interfaces.data.IConnectionInfo[]> {
|
|
354
|
+
const metricsManager = this.opsServerRef.dcRouterRef.metricsManager;
|
|
355
|
+
if (!metricsManager) {
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
409
358
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
// Fallback to route-based connection info if no IP data available
|
|
433
|
-
connectionInfo.forEach((info, index) => {
|
|
434
|
-
connections.push({
|
|
435
|
-
id: `conn-${index}`,
|
|
436
|
-
type: 'http',
|
|
437
|
-
source: {
|
|
438
|
-
ip: 'unknown',
|
|
439
|
-
port: 0,
|
|
440
|
-
},
|
|
441
|
-
destination: {
|
|
442
|
-
ip: this.opsServerRef.dcRouterRef.options.publicIp || 'server',
|
|
443
|
-
port: 443,
|
|
444
|
-
service: info.source,
|
|
445
|
-
},
|
|
446
|
-
startTime: info.lastActivity.getTime(),
|
|
447
|
-
bytesTransferred: 0,
|
|
448
|
-
status: 'active',
|
|
449
|
-
});
|
|
450
|
-
});
|
|
359
|
+
const snapshots = await metricsManager.getActiveConnectionSnapshots({ limit: 10000 });
|
|
360
|
+
const connections = snapshots.map((snapshot): interfaces.data.IConnectionInfo => ({
|
|
361
|
+
id: String(snapshot.id),
|
|
362
|
+
remoteAddress: snapshot.sourcePort === null
|
|
363
|
+
? snapshot.sourceIp
|
|
364
|
+
: `${snapshot.sourceIp}:${snapshot.sourcePort}`,
|
|
365
|
+
localAddress: snapshot.targetHost
|
|
366
|
+
? `${snapshot.targetHost}:${snapshot.targetPort ?? snapshot.localPort}`
|
|
367
|
+
: `${this.opsServerRef.dcRouterRef.options.publicIp || 'server'}:${snapshot.localPort}`,
|
|
368
|
+
startTime: snapshot.startedAtMs,
|
|
369
|
+
protocol: this.mapSnapshotProtocol(snapshot),
|
|
370
|
+
state: this.mapSnapshotState(snapshot.state),
|
|
371
|
+
bytesReceived: snapshot.bytesIn,
|
|
372
|
+
bytesSent: snapshot.bytesOut,
|
|
373
|
+
}));
|
|
374
|
+
|
|
375
|
+
return connections.filter((connection) => {
|
|
376
|
+
if (protocol && connection.protocol !== protocol) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
if (state && connection.state !== state) {
|
|
380
|
+
return false;
|
|
451
381
|
}
|
|
382
|
+
return true;
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private mapSnapshotProtocol(
|
|
387
|
+
snapshot: plugins.smartproxy.IActiveConnectionSnapshot,
|
|
388
|
+
): interfaces.data.IConnectionInfo['protocol'] {
|
|
389
|
+
if (snapshot.localPort === 465) {
|
|
390
|
+
return 'smtps';
|
|
452
391
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
if (protocol) {
|
|
456
|
-
return connections.filter(conn => {
|
|
457
|
-
if (protocol === 'https' || protocol === 'http') {
|
|
458
|
-
return conn.type === 'http';
|
|
459
|
-
}
|
|
460
|
-
return conn.type === protocol.replace('s', ''); // smtp/smtps -> smtp
|
|
461
|
-
});
|
|
392
|
+
if ([25, 587, 2525].includes(snapshot.localPort)) {
|
|
393
|
+
return 'smtp';
|
|
462
394
|
}
|
|
463
|
-
|
|
464
|
-
|
|
395
|
+
|
|
396
|
+
switch (snapshot.protocol) {
|
|
397
|
+
case 'http':
|
|
398
|
+
return 'http';
|
|
399
|
+
case 'https':
|
|
400
|
+
case 'tls':
|
|
401
|
+
case 'tls-passthrough':
|
|
402
|
+
case 'tls-reencrypt':
|
|
403
|
+
case 'tls-socket-handler':
|
|
404
|
+
case 'quic':
|
|
405
|
+
return 'https';
|
|
406
|
+
default:
|
|
407
|
+
return snapshot.localPort === 80 ? 'http' : 'https';
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
private mapSnapshotState(state: string): interfaces.data.IConnectionInfo['state'] {
|
|
412
|
+
return state === 'closing' ? 'closing' : 'connected';
|
|
465
413
|
}
|
|
466
414
|
|
|
467
415
|
private async getRateLimitStatus(
|
|
@@ -91,7 +91,6 @@ export class RadiusServer {
|
|
|
91
91
|
private vlanManager: VlanManager;
|
|
92
92
|
private accountingManager: AccountingManager;
|
|
93
93
|
private config: IRadiusServerConfig;
|
|
94
|
-
private clientSecrets: Map<string, string> = new Map();
|
|
95
94
|
private running: boolean = false;
|
|
96
95
|
|
|
97
96
|
// Statistics
|
|
@@ -138,24 +137,18 @@ export class RadiusServer {
|
|
|
138
137
|
await this.vlanManager.importMappings(this.config.vlanAssignment.mappings);
|
|
139
138
|
}
|
|
140
139
|
|
|
141
|
-
|
|
142
|
-
this.buildClientSecretsMap();
|
|
140
|
+
const cidrSecrets = this.buildClientSecretsMap();
|
|
143
141
|
|
|
144
142
|
// Create the RADIUS server
|
|
145
143
|
this.radiusServer = new plugins.smartradius.RadiusServer({
|
|
146
144
|
authPort: this.config.authPort,
|
|
147
145
|
acctPort: this.config.acctPort,
|
|
148
146
|
bindAddress: this.config.bindAddress,
|
|
149
|
-
|
|
147
|
+
cidrSecrets,
|
|
150
148
|
authenticationHandler: this.handleAuthentication.bind(this),
|
|
151
149
|
accountingHandler: this.handleAccounting.bind(this),
|
|
152
150
|
});
|
|
153
151
|
|
|
154
|
-
// Configure per-client secrets
|
|
155
|
-
for (const [ip, secret] of this.clientSecrets) {
|
|
156
|
-
this.radiusServer.setClientSecret(ip, secret);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
152
|
// Start the server
|
|
160
153
|
await this.radiusServer.start();
|
|
161
154
|
|
|
@@ -189,19 +182,22 @@ export class RadiusServer {
|
|
|
189
182
|
/**
|
|
190
183
|
* Handle authentication request
|
|
191
184
|
*/
|
|
192
|
-
private async handleAuthentication(
|
|
185
|
+
private async handleAuthentication(
|
|
186
|
+
request: plugins.smartradius.IAuthenticationRequest,
|
|
187
|
+
): Promise<plugins.smartradius.IAuthenticationResponse> {
|
|
193
188
|
this.stats.authRequests++;
|
|
194
189
|
|
|
195
190
|
const authData: IAuthRequestData = {
|
|
196
|
-
username: request.
|
|
197
|
-
password: request.
|
|
198
|
-
nasIpAddress: request.
|
|
199
|
-
nasPort: request.
|
|
200
|
-
nasPortType: request.
|
|
201
|
-
nasIdentifier: request.
|
|
202
|
-
calledStationId: request.
|
|
203
|
-
callingStationId: request.
|
|
204
|
-
serviceType: request.
|
|
191
|
+
username: request.username || '',
|
|
192
|
+
password: request.password,
|
|
193
|
+
nasIpAddress: request.nasIpAddress || request.clientAddress || '',
|
|
194
|
+
nasPort: request.nasPort,
|
|
195
|
+
nasPortType: request.nasPortType !== undefined ? String(request.nasPortType) : undefined,
|
|
196
|
+
nasIdentifier: request.nasIdentifier,
|
|
197
|
+
calledStationId: request.calledStationId,
|
|
198
|
+
callingStationId: request.callingStationId,
|
|
199
|
+
serviceType: request.serviceType !== undefined ? String(request.serviceType) : undefined,
|
|
200
|
+
framedMtu: request.framedMtu,
|
|
205
201
|
};
|
|
206
202
|
|
|
207
203
|
logger.log('debug', `RADIUS Auth Request: user=${authData.username}, NAS=${authData.nasIpAddress}`);
|
|
@@ -215,15 +211,15 @@ export class RadiusServer {
|
|
|
215
211
|
logger.log('info', `RADIUS Auth Accept: user=${authData.username}, VLAN=${result.vlanId}`);
|
|
216
212
|
|
|
217
213
|
// Build response with VLAN attributes
|
|
218
|
-
const response:
|
|
214
|
+
const response: plugins.smartradius.IAuthenticationResponse = {
|
|
219
215
|
code: plugins.smartradius.ERadiusCode.AccessAccept,
|
|
220
216
|
replyMessage: result.replyMessage,
|
|
221
217
|
};
|
|
222
218
|
|
|
223
219
|
// Add VLAN attributes if assigned
|
|
224
220
|
if (result.vlanId !== undefined) {
|
|
225
|
-
response.tunnelType =
|
|
226
|
-
response.tunnelMediumType =
|
|
221
|
+
response.tunnelType = plugins.smartradius.ETunnelType.Vlan;
|
|
222
|
+
response.tunnelMediumType = plugins.smartradius.ETunnelMediumType.Ieee802;
|
|
227
223
|
response.tunnelPrivateGroupId = String(result.vlanId);
|
|
228
224
|
}
|
|
229
225
|
|
|
@@ -257,34 +253,37 @@ export class RadiusServer {
|
|
|
257
253
|
/**
|
|
258
254
|
* Handle accounting request
|
|
259
255
|
*/
|
|
260
|
-
private async handleAccounting(
|
|
256
|
+
private async handleAccounting(
|
|
257
|
+
request: plugins.smartradius.IAccountingRequest,
|
|
258
|
+
): Promise<plugins.smartradius.IAccountingResponse> {
|
|
261
259
|
this.stats.accountingRequests++;
|
|
262
260
|
|
|
263
261
|
if (!this.config.accounting?.enabled) {
|
|
264
262
|
// Still respond even if not tracking
|
|
265
|
-
return {
|
|
263
|
+
return { success: true };
|
|
266
264
|
}
|
|
267
265
|
|
|
268
|
-
const statusType = request.
|
|
269
|
-
const sessionId = request.
|
|
266
|
+
const statusType = request.statusType;
|
|
267
|
+
const sessionId = request.sessionId || '';
|
|
270
268
|
|
|
271
269
|
const accountingData = {
|
|
272
270
|
sessionId,
|
|
273
|
-
username: request.
|
|
274
|
-
macAddress: request.
|
|
275
|
-
nasIpAddress: request.
|
|
276
|
-
nasPort: request.
|
|
277
|
-
nasPortType: request.
|
|
278
|
-
nasIdentifier: request.
|
|
279
|
-
calledStationId: request.
|
|
280
|
-
callingStationId: request.
|
|
281
|
-
inputOctets: request.
|
|
282
|
-
outputOctets: request.
|
|
283
|
-
inputPackets: request.
|
|
284
|
-
outputPackets: request.
|
|
285
|
-
sessionTime: request.
|
|
286
|
-
terminateCause: request.
|
|
287
|
-
|
|
271
|
+
username: request.username || '',
|
|
272
|
+
macAddress: request.callingStationId,
|
|
273
|
+
nasIpAddress: request.nasIpAddress || request.clientAddress || '',
|
|
274
|
+
nasPort: request.nasPort,
|
|
275
|
+
nasPortType: request.nasPortType !== undefined ? String(request.nasPortType) : undefined,
|
|
276
|
+
nasIdentifier: request.nasIdentifier,
|
|
277
|
+
calledStationId: request.calledStationId,
|
|
278
|
+
callingStationId: request.callingStationId,
|
|
279
|
+
inputOctets: request.inputOctets,
|
|
280
|
+
outputOctets: request.outputOctets,
|
|
281
|
+
inputPackets: request.inputPackets,
|
|
282
|
+
outputPackets: request.outputPackets,
|
|
283
|
+
sessionTime: request.sessionTime,
|
|
284
|
+
terminateCause: request.terminateCause !== undefined ? String(request.terminateCause) : undefined,
|
|
285
|
+
framedIpAddress: request.framedIpAddress,
|
|
286
|
+
serviceType: request.serviceType !== undefined ? String(request.serviceType) : undefined,
|
|
288
287
|
};
|
|
289
288
|
|
|
290
289
|
try {
|
|
@@ -311,7 +310,7 @@ export class RadiusServer {
|
|
|
311
310
|
logger.log('error', `RADIUS accounting error: ${(error as Error).message}`);
|
|
312
311
|
}
|
|
313
312
|
|
|
314
|
-
return {
|
|
313
|
+
return { success: true };
|
|
315
314
|
}
|
|
316
315
|
|
|
317
316
|
/**
|
|
@@ -391,37 +390,18 @@ export class RadiusServer {
|
|
|
391
390
|
/**
|
|
392
391
|
* Build client secrets map from configuration
|
|
393
392
|
*/
|
|
394
|
-
private buildClientSecretsMap():
|
|
395
|
-
|
|
393
|
+
private buildClientSecretsMap(): Record<string, string> {
|
|
394
|
+
const cidrSecrets: Record<string, string> = {};
|
|
396
395
|
|
|
397
396
|
for (const client of this.config.clients) {
|
|
398
397
|
if (!client.enabled) {
|
|
399
398
|
continue;
|
|
400
399
|
}
|
|
401
400
|
|
|
402
|
-
|
|
403
|
-
if (client.ipRange.includes('/')) {
|
|
404
|
-
// For CIDR ranges, we'll use the network address as key
|
|
405
|
-
// In practice, smartradius may handle this differently
|
|
406
|
-
const [network] = client.ipRange.split('/');
|
|
407
|
-
this.clientSecrets.set(network, client.secret);
|
|
408
|
-
} else {
|
|
409
|
-
this.clientSecrets.set(client.ipRange, client.secret);
|
|
410
|
-
}
|
|
401
|
+
cidrSecrets[client.ipRange] = client.secret;
|
|
411
402
|
}
|
|
412
|
-
}
|
|
413
403
|
|
|
414
|
-
|
|
415
|
-
* Get default secret for unknown clients
|
|
416
|
-
*/
|
|
417
|
-
private getDefaultSecret(): string {
|
|
418
|
-
// Use first enabled client's secret as default, or a random one
|
|
419
|
-
for (const client of this.config.clients) {
|
|
420
|
-
if (client.enabled) {
|
|
421
|
-
return client.secret;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
return plugins.crypto.randomBytes(16).toString('hex');
|
|
404
|
+
return cidrSecrets;
|
|
425
405
|
}
|
|
426
406
|
|
|
427
407
|
/**
|
|
@@ -430,21 +410,19 @@ export class RadiusServer {
|
|
|
430
410
|
async addClient(client: IRadiusClient): Promise<void> {
|
|
431
411
|
// Check if client already exists
|
|
432
412
|
const existingIndex = this.config.clients.findIndex(c => c.name === client.name);
|
|
413
|
+
const previousClient = existingIndex >= 0 ? this.config.clients[existingIndex] : undefined;
|
|
433
414
|
if (existingIndex >= 0) {
|
|
434
415
|
this.config.clients[existingIndex] = client;
|
|
435
416
|
} else {
|
|
436
417
|
this.config.clients.push(client);
|
|
437
418
|
}
|
|
438
419
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
this.
|
|
445
|
-
} else {
|
|
446
|
-
this.radiusServer.setClientSecret(client.ipRange, client.secret);
|
|
447
|
-
this.clientSecrets.set(client.ipRange, client.secret);
|
|
420
|
+
if (this.running && this.radiusServer) {
|
|
421
|
+
if (previousClient) {
|
|
422
|
+
this.radiusServer.removeNetworkSecret(previousClient.ipRange);
|
|
423
|
+
}
|
|
424
|
+
if (client.enabled) {
|
|
425
|
+
this.radiusServer.setNetworkSecret(client.ipRange, client.secret);
|
|
448
426
|
}
|
|
449
427
|
}
|
|
450
428
|
|
|
@@ -460,12 +438,8 @@ export class RadiusServer {
|
|
|
460
438
|
const client = this.config.clients[index];
|
|
461
439
|
this.config.clients.splice(index, 1);
|
|
462
440
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const [network] = client.ipRange.split('/');
|
|
466
|
-
this.clientSecrets.delete(network);
|
|
467
|
-
} else {
|
|
468
|
-
this.clientSecrets.delete(client.ipRange);
|
|
441
|
+
if (this.radiusServer) {
|
|
442
|
+
this.radiusServer.removeNetworkSecret(client.ipRange);
|
|
469
443
|
}
|
|
470
444
|
|
|
471
445
|
logger.log('info', `RADIUS client removed: ${name}`);
|
|
@@ -1,29 +1,13 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
|
-
import type { IRemoteIngress, IDcRouterRouteConfig } from '../../ts_interfaces/data/remoteingress.js';
|
|
2
|
+
import type { IRemoteIngress, IRemoteIngressPerformanceConfig, IDcRouterRouteConfig } from '../../ts_interfaces/data/remoteingress.js';
|
|
3
3
|
import { RemoteIngressEdgeDoc } from '../db/index.js';
|
|
4
4
|
|
|
5
5
|
interface IRemoteIngressFirewallConfig {
|
|
6
6
|
blockedIps?: string[];
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*/
|
|
12
|
-
function extractPorts(portRange: number | Array<number | { from: number; to: number }>): number[] {
|
|
13
|
-
const ports = new Set<number>();
|
|
14
|
-
if (typeof portRange === 'number') {
|
|
15
|
-
ports.add(portRange);
|
|
16
|
-
} else if (Array.isArray(portRange)) {
|
|
17
|
-
for (const entry of portRange) {
|
|
18
|
-
if (typeof entry === 'number') {
|
|
19
|
-
ports.add(entry);
|
|
20
|
-
} else if (typeof entry === 'object' && 'from' in entry && 'to' in entry) {
|
|
21
|
-
for (let p = entry.from; p <= entry.to; p++) {
|
|
22
|
-
ports.add(p);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
9
|
+
function extractPorts(portRange: plugins.smartproxy.IRouteConfig['match']['ports']): number[] {
|
|
10
|
+
const ports = new Set<number>(plugins.smartproxy.expandPortRange(portRange) as number[]);
|
|
27
11
|
return [...ports].sort((a, b) => a - b);
|
|
28
12
|
}
|
|
29
13
|
|
|
@@ -59,6 +43,7 @@ export class RemoteIngressManager {
|
|
|
59
43
|
listenPortsUdp: doc.listenPortsUdp,
|
|
60
44
|
enabled: doc.enabled,
|
|
61
45
|
autoDerivePorts: doc.autoDerivePorts,
|
|
46
|
+
performance: doc.performance,
|
|
62
47
|
tags: doc.tags,
|
|
63
48
|
createdAt: doc.createdAt,
|
|
64
49
|
updatedAt: doc.updatedAt,
|
|
@@ -189,6 +174,7 @@ export class RemoteIngressManager {
|
|
|
189
174
|
listenPorts: number[] = [],
|
|
190
175
|
tags?: string[],
|
|
191
176
|
autoDerivePorts: boolean = true,
|
|
177
|
+
performance?: IRemoteIngressPerformanceConfig,
|
|
192
178
|
): Promise<IRemoteIngress> {
|
|
193
179
|
const id = plugins.uuid.v4();
|
|
194
180
|
const secret = plugins.crypto.randomBytes(32).toString('hex');
|
|
@@ -201,6 +187,7 @@ export class RemoteIngressManager {
|
|
|
201
187
|
listenPorts,
|
|
202
188
|
enabled: true,
|
|
203
189
|
autoDerivePorts,
|
|
190
|
+
performance,
|
|
204
191
|
tags: tags || [],
|
|
205
192
|
createdAt: now,
|
|
206
193
|
updatedAt: now,
|
|
@@ -237,6 +224,7 @@ export class RemoteIngressManager {
|
|
|
237
224
|
listenPorts?: number[];
|
|
238
225
|
autoDerivePorts?: boolean;
|
|
239
226
|
enabled?: boolean;
|
|
227
|
+
performance?: IRemoteIngressPerformanceConfig;
|
|
240
228
|
tags?: string[];
|
|
241
229
|
},
|
|
242
230
|
): Promise<IRemoteIngress | null> {
|
|
@@ -249,6 +237,7 @@ export class RemoteIngressManager {
|
|
|
249
237
|
if (updates.listenPorts !== undefined) edge.listenPorts = updates.listenPorts;
|
|
250
238
|
if (updates.autoDerivePorts !== undefined) edge.autoDerivePorts = updates.autoDerivePorts;
|
|
251
239
|
if (updates.enabled !== undefined) edge.enabled = updates.enabled;
|
|
240
|
+
if (updates.performance !== undefined) edge.performance = updates.performance;
|
|
252
241
|
if (updates.tags !== undefined) edge.tags = updates.tags;
|
|
253
242
|
edge.updatedAt = Date.now();
|
|
254
243
|
|
|
@@ -317,17 +306,19 @@ export class RemoteIngressManager {
|
|
|
317
306
|
* Get the list of allowed edges (enabled only) for the Rust hub.
|
|
318
307
|
* Includes listenPortsUdp when routes with transport 'udp' or 'all' are present.
|
|
319
308
|
*/
|
|
320
|
-
public getAllowedEdges(): Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[]; firewallConfig?: IRemoteIngressFirewallConfig }> {
|
|
321
|
-
const result: Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[]; firewallConfig?: IRemoteIngressFirewallConfig }> = [];
|
|
309
|
+
public getAllowedEdges(): Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[]; firewallConfig?: IRemoteIngressFirewallConfig; performance?: IRemoteIngressPerformanceConfig }> {
|
|
310
|
+
const result: Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[]; firewallConfig?: IRemoteIngressFirewallConfig; performance?: IRemoteIngressPerformanceConfig }> = [];
|
|
322
311
|
for (const edge of this.edges.values()) {
|
|
323
312
|
if (edge.enabled) {
|
|
324
313
|
const listenPortsUdp = this.getEffectiveListenPortsUdp(edge);
|
|
314
|
+
const performance = edge.performance && Object.keys(edge.performance).length > 0 ? edge.performance : undefined;
|
|
325
315
|
result.push({
|
|
326
316
|
id: edge.id,
|
|
327
317
|
secret: edge.secret,
|
|
328
318
|
listenPorts: this.getEffectiveListenPorts(edge),
|
|
329
319
|
...(listenPortsUdp.length > 0 ? { listenPortsUdp } : {}),
|
|
330
320
|
...(this.firewallConfig ? { firewallConfig: this.firewallConfig } : {}),
|
|
321
|
+
...(performance ? { performance } : {}),
|
|
331
322
|
});
|
|
332
323
|
}
|
|
333
324
|
}
|
package/ts_web/appstate.ts
CHANGED
|
@@ -1120,6 +1120,7 @@ export const createRemoteIngressAction = remoteIngressStatePart.createAction<{
|
|
|
1120
1120
|
name: string;
|
|
1121
1121
|
listenPorts?: number[];
|
|
1122
1122
|
autoDerivePorts?: boolean;
|
|
1123
|
+
performance?: interfaces.data.IRemoteIngressPerformanceConfig;
|
|
1123
1124
|
tags?: string[];
|
|
1124
1125
|
}>(async (statePartArg, dataArg, actionContext): Promise<IRemoteIngressState> => {
|
|
1125
1126
|
const context = getActionContext();
|
|
@@ -1135,6 +1136,7 @@ export const createRemoteIngressAction = remoteIngressStatePart.createAction<{
|
|
|
1135
1136
|
name: dataArg.name,
|
|
1136
1137
|
listenPorts: dataArg.listenPorts,
|
|
1137
1138
|
autoDerivePorts: dataArg.autoDerivePorts,
|
|
1139
|
+
performance: dataArg.performance,
|
|
1138
1140
|
tags: dataArg.tags,
|
|
1139
1141
|
});
|
|
1140
1142
|
|
|
@@ -1187,6 +1189,7 @@ export const updateRemoteIngressAction = remoteIngressStatePart.createAction<{
|
|
|
1187
1189
|
name?: string;
|
|
1188
1190
|
listenPorts?: number[];
|
|
1189
1191
|
autoDerivePorts?: boolean;
|
|
1192
|
+
performance?: interfaces.data.IRemoteIngressPerformanceConfig;
|
|
1190
1193
|
tags?: string[];
|
|
1191
1194
|
}>(async (statePartArg, dataArg, actionContext): Promise<IRemoteIngressState> => {
|
|
1192
1195
|
const context = getActionContext();
|
|
@@ -1203,6 +1206,7 @@ export const updateRemoteIngressAction = remoteIngressStatePart.createAction<{
|
|
|
1203
1206
|
name: dataArg.name,
|
|
1204
1207
|
listenPorts: dataArg.listenPorts,
|
|
1205
1208
|
autoDerivePorts: dataArg.autoDerivePorts,
|
|
1209
|
+
performance: dataArg.performance,
|
|
1206
1210
|
tags: dataArg.tags,
|
|
1207
1211
|
});
|
|
1208
1212
|
|