@push.rocks/smartproxy 18.0.0 → 18.0.2

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.
Files changed (35) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/core/utils/route-utils.d.ts +3 -3
  3. package/dist_ts/core/utils/route-utils.js +9 -9
  4. package/dist_ts/proxies/network-proxy/http-request-handler.js +3 -2
  5. package/dist_ts/proxies/nftables-proxy/models/interfaces.d.ts +2 -2
  6. package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +21 -21
  7. package/dist_ts/proxies/smart-proxy/index.d.ts +1 -0
  8. package/dist_ts/proxies/smart-proxy/index.js +2 -1
  9. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +1 -0
  10. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +14 -0
  11. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  12. package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +82 -0
  13. package/dist_ts/proxies/smart-proxy/nftables-manager.js +235 -0
  14. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +42 -1
  15. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +6 -1
  16. package/dist_ts/proxies/smart-proxy/smart-proxy.js +46 -2
  17. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +1 -0
  18. package/dist_ts/proxies/smart-proxy/utils/index.js +3 -2
  19. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +77 -0
  20. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +119 -1
  21. package/package.json +4 -4
  22. package/readme.plan.md +618 -110
  23. package/ts/00_commitinfo_data.ts +1 -1
  24. package/ts/core/utils/route-utils.ts +9 -9
  25. package/ts/proxies/network-proxy/http-request-handler.ts +3 -2
  26. package/ts/proxies/nftables-proxy/models/interfaces.ts +2 -2
  27. package/ts/proxies/nftables-proxy/nftables-proxy.ts +20 -20
  28. package/ts/proxies/smart-proxy/index.ts +1 -0
  29. package/ts/proxies/smart-proxy/models/interfaces.ts +3 -0
  30. package/ts/proxies/smart-proxy/models/route-types.ts +20 -0
  31. package/ts/proxies/smart-proxy/nftables-manager.ts +268 -0
  32. package/ts/proxies/smart-proxy/route-connection-handler.ts +55 -0
  33. package/ts/proxies/smart-proxy/smart-proxy.ts +60 -1
  34. package/ts/proxies/smart-proxy/utils/index.ts +2 -1
  35. package/ts/proxies/smart-proxy/utils/route-helpers.ts +192 -0
@@ -9,6 +9,7 @@ import { TimeoutManager } from './timeout-manager.js';
9
9
  import { PortManager } from './port-manager.js';
10
10
  import { RouteManager } from './route-manager.js';
11
11
  import { RouteConnectionHandler } from './route-connection-handler.js';
12
+ import { NFTablesManager } from './nftables-manager.js';
12
13
 
13
14
  // External dependencies
14
15
  import { Port80Handler } from '../../http/port80/port80-handler.js';
@@ -50,6 +51,7 @@ export class SmartProxy extends plugins.EventEmitter {
50
51
  private timeoutManager: TimeoutManager;
51
52
  public routeManager: RouteManager; // Made public for route management
52
53
  private routeConnectionHandler: RouteConnectionHandler;
54
+ private nftablesManager: NFTablesManager;
53
55
 
54
56
  // Port80Handler for ACME certificate management
55
57
  private port80Handler: Port80Handler | null = null;
@@ -82,7 +84,7 @@ export class SmartProxy extends plugins.EventEmitter {
82
84
  * ],
83
85
  * defaults: {
84
86
  * target: { host: 'localhost', port: 8080 },
85
- * security: { allowedIps: ['*'] }
87
+ * security: { ipAllowList: ['*'] }
86
88
  * }
87
89
  * });
88
90
  * ```
@@ -167,6 +169,9 @@ export class SmartProxy extends plugins.EventEmitter {
167
169
 
168
170
  // Initialize port manager
169
171
  this.portManager = new PortManager(this.settings, this.routeConnectionHandler);
172
+
173
+ // Initialize NFTablesManager
174
+ this.nftablesManager = new NFTablesManager(this.settings);
170
175
  }
171
176
 
172
177
  /**
@@ -270,6 +275,13 @@ export class SmartProxy extends plugins.EventEmitter {
270
275
  // Get listening ports from RouteManager
271
276
  const listeningPorts = this.routeManager.getListeningPorts();
272
277
 
278
+ // Provision NFTables rules for routes that use NFTables
279
+ for (const route of this.settings.routes) {
280
+ if (route.action.forwardingEngine === 'nftables') {
281
+ await this.nftablesManager.provisionRoute(route);
282
+ }
283
+ }
284
+
273
285
  // Start port listeners using the PortManager
274
286
  await this.portManager.addPorts(listeningPorts);
275
287
 
@@ -364,6 +376,10 @@ export class SmartProxy extends plugins.EventEmitter {
364
376
  await this.certProvisioner.stop();
365
377
  console.log('CertProvisioner stopped');
366
378
  }
379
+
380
+ // Stop NFTablesManager
381
+ await this.nftablesManager.stop();
382
+ console.log('NFTablesManager stopped');
367
383
 
368
384
  // Stop the Port80Handler if running
369
385
  if (this.port80Handler) {
@@ -432,6 +448,39 @@ export class SmartProxy extends plugins.EventEmitter {
432
448
  public async updateRoutes(newRoutes: IRouteConfig[]): Promise<void> {
433
449
  console.log(`Updating routes (${newRoutes.length} routes)`);
434
450
 
451
+ // Get existing routes that use NFTables
452
+ const oldNfTablesRoutes = this.settings.routes.filter(
453
+ r => r.action.forwardingEngine === 'nftables'
454
+ );
455
+
456
+ // Get new routes that use NFTables
457
+ const newNfTablesRoutes = newRoutes.filter(
458
+ r => r.action.forwardingEngine === 'nftables'
459
+ );
460
+
461
+ // Find routes to remove, update, or add
462
+ for (const oldRoute of oldNfTablesRoutes) {
463
+ const newRoute = newNfTablesRoutes.find(r => r.name === oldRoute.name);
464
+
465
+ if (!newRoute) {
466
+ // Route was removed
467
+ await this.nftablesManager.deprovisionRoute(oldRoute);
468
+ } else {
469
+ // Route was updated
470
+ await this.nftablesManager.updateRoute(oldRoute, newRoute);
471
+ }
472
+ }
473
+
474
+ // Find new routes to add
475
+ for (const newRoute of newNfTablesRoutes) {
476
+ const oldRoute = oldNfTablesRoutes.find(r => r.name === newRoute.name);
477
+
478
+ if (!oldRoute) {
479
+ // New route
480
+ await this.nftablesManager.provisionRoute(newRoute);
481
+ }
482
+ }
483
+
435
484
  // Update routes in RouteManager
436
485
  this.routeManager.updateRoutes(newRoutes);
437
486
 
@@ -440,6 +489,9 @@ export class SmartProxy extends plugins.EventEmitter {
440
489
 
441
490
  // Update port listeners to match the new configuration
442
491
  await this.portManager.updatePorts(requiredPorts);
492
+
493
+ // Update settings with the new routes
494
+ this.settings.routes = newRoutes;
443
495
 
444
496
  // If NetworkProxy is initialized, resync the configurations
445
497
  if (this.networkProxyBridge.getNetworkProxy()) {
@@ -676,6 +728,13 @@ export class SmartProxy extends plugins.EventEmitter {
676
728
  return domains;
677
729
  }
678
730
 
731
+ /**
732
+ * Get NFTables status
733
+ */
734
+ public async getNfTablesStatus(): Promise<Record<string, any>> {
735
+ return this.nftablesManager.getStatus();
736
+ }
737
+
679
738
  /**
680
739
  * Get status of certificates managed by Port80Handler
681
740
  */
@@ -5,7 +5,8 @@
5
5
  * including helpers, validators, utilities, and patterns for working with routes.
6
6
  */
7
7
 
8
- // Route helpers have been consolidated in route-patterns.js
8
+ // Export route helpers for creating route configurations
9
+ export * from './route-helpers.js';
9
10
 
10
11
  // Export route validators for validating route configurations
11
12
  export * from './route-validators.js';
@@ -16,6 +16,7 @@
16
16
  * - WebSocket routes (createWebSocketRoute)
17
17
  * - Port mapping routes (createPortMappingRoute, createOffsetPortMappingRoute)
18
18
  * - Dynamic routing (createDynamicRoute, createSmartLoadBalancer)
19
+ * - NFTables routes (createNfTablesRoute, createNfTablesTerminateRoute)
19
20
  */
20
21
 
21
22
  import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget, TPortRange, IRouteContext } from '../models/route-types.js';
@@ -618,4 +619,195 @@ export function createSmartLoadBalancer(options: {
618
619
  priority: options.priority,
619
620
  ...options
620
621
  };
622
+ }
623
+
624
+ /**
625
+ * Create an NFTables-based route for high-performance packet forwarding
626
+ * @param nameOrDomains Name or domain(s) to match
627
+ * @param target Target host and port
628
+ * @param options Additional route options
629
+ * @returns Route configuration object
630
+ */
631
+ export function createNfTablesRoute(
632
+ nameOrDomains: string | string[],
633
+ target: { host: string; port: number | 'preserve' },
634
+ options: {
635
+ ports?: TPortRange;
636
+ protocol?: 'tcp' | 'udp' | 'all';
637
+ preserveSourceIP?: boolean;
638
+ ipAllowList?: string[];
639
+ ipBlockList?: string[];
640
+ maxRate?: string;
641
+ priority?: number;
642
+ useTls?: boolean;
643
+ tableName?: string;
644
+ useIPSets?: boolean;
645
+ useAdvancedNAT?: boolean;
646
+ } = {}
647
+ ): IRouteConfig {
648
+ // Determine if this is a name or domain
649
+ let name: string;
650
+ let domains: string | string[] | undefined;
651
+
652
+ if (Array.isArray(nameOrDomains) || (typeof nameOrDomains === 'string' && nameOrDomains.includes('.'))) {
653
+ domains = nameOrDomains;
654
+ name = Array.isArray(nameOrDomains) ? nameOrDomains[0] : nameOrDomains;
655
+ } else {
656
+ name = nameOrDomains;
657
+ domains = undefined; // No domains
658
+ }
659
+
660
+ // Create route match
661
+ const match: IRouteMatch = {
662
+ domains,
663
+ ports: options.ports || 80
664
+ };
665
+
666
+ // Create route action
667
+ const action: IRouteAction = {
668
+ type: 'forward',
669
+ target: {
670
+ host: target.host,
671
+ port: target.port
672
+ },
673
+ forwardingEngine: 'nftables',
674
+ nftables: {
675
+ protocol: options.protocol || 'tcp',
676
+ preserveSourceIP: options.preserveSourceIP,
677
+ maxRate: options.maxRate,
678
+ priority: options.priority,
679
+ tableName: options.tableName,
680
+ useIPSets: options.useIPSets,
681
+ useAdvancedNAT: options.useAdvancedNAT
682
+ }
683
+ };
684
+
685
+ // Add security if allowed or blocked IPs are specified
686
+ if (options.ipAllowList?.length || options.ipBlockList?.length) {
687
+ action.security = {
688
+ ipAllowList: options.ipAllowList,
689
+ ipBlockList: options.ipBlockList
690
+ };
691
+ }
692
+
693
+ // Add TLS options if needed
694
+ if (options.useTls) {
695
+ action.tls = {
696
+ mode: 'passthrough'
697
+ };
698
+ }
699
+
700
+ // Create the route config
701
+ return {
702
+ name,
703
+ match,
704
+ action
705
+ };
706
+ }
707
+
708
+ /**
709
+ * Create an NFTables-based TLS termination route
710
+ * @param nameOrDomains Name or domain(s) to match
711
+ * @param target Target host and port
712
+ * @param options Additional route options
713
+ * @returns Route configuration object
714
+ */
715
+ export function createNfTablesTerminateRoute(
716
+ nameOrDomains: string | string[],
717
+ target: { host: string; port: number | 'preserve' },
718
+ options: {
719
+ ports?: TPortRange;
720
+ protocol?: 'tcp' | 'udp' | 'all';
721
+ preserveSourceIP?: boolean;
722
+ ipAllowList?: string[];
723
+ ipBlockList?: string[];
724
+ maxRate?: string;
725
+ priority?: number;
726
+ tableName?: string;
727
+ useIPSets?: boolean;
728
+ useAdvancedNAT?: boolean;
729
+ certificate?: 'auto' | { key: string; cert: string };
730
+ } = {}
731
+ ): IRouteConfig {
732
+ // Create basic NFTables route
733
+ const route = createNfTablesRoute(
734
+ nameOrDomains,
735
+ target,
736
+ {
737
+ ...options,
738
+ ports: options.ports || 443,
739
+ useTls: false
740
+ }
741
+ );
742
+
743
+ // Set TLS termination
744
+ route.action.tls = {
745
+ mode: 'terminate',
746
+ certificate: options.certificate || 'auto'
747
+ };
748
+
749
+ return route;
750
+ }
751
+
752
+ /**
753
+ * Create a complete NFTables-based HTTPS setup with HTTP redirect
754
+ * @param nameOrDomains Name or domain(s) to match
755
+ * @param target Target host and port
756
+ * @param options Additional route options
757
+ * @returns Array of two route configurations (HTTPS and HTTP redirect)
758
+ */
759
+ export function createCompleteNfTablesHttpsServer(
760
+ nameOrDomains: string | string[],
761
+ target: { host: string; port: number | 'preserve' },
762
+ options: {
763
+ httpPort?: TPortRange;
764
+ httpsPort?: TPortRange;
765
+ protocol?: 'tcp' | 'udp' | 'all';
766
+ preserveSourceIP?: boolean;
767
+ ipAllowList?: string[];
768
+ ipBlockList?: string[];
769
+ maxRate?: string;
770
+ priority?: number;
771
+ tableName?: string;
772
+ useIPSets?: boolean;
773
+ useAdvancedNAT?: boolean;
774
+ certificate?: 'auto' | { key: string; cert: string };
775
+ } = {}
776
+ ): IRouteConfig[] {
777
+ // Create the HTTPS route using NFTables
778
+ const httpsRoute = createNfTablesTerminateRoute(
779
+ nameOrDomains,
780
+ target,
781
+ {
782
+ ...options,
783
+ ports: options.httpsPort || 443
784
+ }
785
+ );
786
+
787
+ // Determine the domain(s) for HTTP redirect
788
+ const domains = typeof nameOrDomains === 'string' && !nameOrDomains.includes('.')
789
+ ? undefined
790
+ : nameOrDomains;
791
+
792
+ // Extract the HTTPS port for the redirect destination
793
+ const httpsPort = typeof options.httpsPort === 'number'
794
+ ? options.httpsPort
795
+ : Array.isArray(options.httpsPort) && typeof options.httpsPort[0] === 'number'
796
+ ? options.httpsPort[0]
797
+ : 443;
798
+
799
+ // Create the HTTP redirect route (this uses standard forwarding, not NFTables)
800
+ const httpRedirectRoute = createHttpToHttpsRedirect(
801
+ domains as any, // Type cast needed since domains can be undefined now
802
+ httpsPort,
803
+ {
804
+ match: {
805
+ ports: options.httpPort || 80,
806
+ domains: domains as any // Type cast needed since domains can be undefined now
807
+ },
808
+ name: `HTTP to HTTPS Redirect for ${Array.isArray(domains) ? domains.join(', ') : domains || 'all domains'}`
809
+ }
810
+ );
811
+
812
+ return [httpsRoute, httpRedirectRoute];
621
813
  }