@push.rocks/smartnftables 1.0.1
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/changelog.md +10 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/index.d.ts +10 -0
- package/dist_ts/index.js +14 -0
- package/dist_ts/nft.executor.d.ts +32 -0
- package/dist_ts/nft.executor.js +59 -0
- package/dist_ts/nft.manager.d.ts +59 -0
- package/dist_ts/nft.manager.firewall.d.ts +49 -0
- package/dist_ts/nft.manager.firewall.js +121 -0
- package/dist_ts/nft.manager.js +132 -0
- package/dist_ts/nft.manager.nat.d.ts +34 -0
- package/dist_ts/nft.manager.nat.js +61 -0
- package/dist_ts/nft.manager.ratelimit.d.ts +26 -0
- package/dist_ts/nft.manager.ratelimit.js +39 -0
- package/dist_ts/nft.rulebuilder.firewall.d.ts +30 -0
- package/dist_ts/nft.rulebuilder.firewall.js +119 -0
- package/dist_ts/nft.rulebuilder.nat.d.ts +15 -0
- package/dist_ts/nft.rulebuilder.nat.js +51 -0
- package/dist_ts/nft.rulebuilder.ratelimit.d.ts +16 -0
- package/dist_ts/nft.rulebuilder.ratelimit.js +61 -0
- package/dist_ts/nft.rulebuilder.table.d.ts +13 -0
- package/dist_ts/nft.rulebuilder.table.js +27 -0
- package/dist_ts/nft.types.d.ts +88 -0
- package/dist_ts/nft.types.js +2 -0
- package/dist_ts/plugins.d.ts +6 -0
- package/dist_ts/plugins.js +9 -0
- package/license +21 -0
- package/package.json +57 -0
- package/readme.md +357 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/index.ts +59 -0
- package/ts/nft.executor.ts +74 -0
- package/ts/nft.manager.firewall.ts +148 -0
- package/ts/nft.manager.nat.ts +76 -0
- package/ts/nft.manager.ratelimit.ts +43 -0
- package/ts/nft.manager.ts +157 -0
- package/ts/nft.rulebuilder.firewall.ts +173 -0
- package/ts/nft.rulebuilder.nat.ts +82 -0
- package/ts/nft.rulebuilder.ratelimit.ts +89 -0
- package/ts/nft.rulebuilder.table.ts +30 -0
- package/ts/nft.types.ts +102 -0
- package/ts/plugins.ts +16 -0
package/changelog.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* autocreated commitinfo by @push.rocks/commitinfo
|
|
3
|
+
*/
|
|
4
|
+
export const commitinfo = {
|
|
5
|
+
name: '@push.rocks/smartnftables',
|
|
6
|
+
version: '1.0.1',
|
|
7
|
+
description: 'A TypeScript module for managing nftables rules including NAT, firewall, and rate limiting with a high-level API.'
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSwyQkFBMkI7SUFDakMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLG1IQUFtSDtDQUNqSSxDQUFBIn0=
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { SmartNftables } from './nft.manager.js';
|
|
2
|
+
export { NatManager } from './nft.manager.nat.js';
|
|
3
|
+
export { FirewallManager } from './nft.manager.firewall.js';
|
|
4
|
+
export { RateLimitManager } from './nft.manager.ratelimit.js';
|
|
5
|
+
export { NftExecutor, NftNotRootError, NftCommandError } from './nft.executor.js';
|
|
6
|
+
export { buildTableSetup, buildFilterChains, buildTableCleanup, } from './nft.rulebuilder.table.js';
|
|
7
|
+
export { buildDnatRules, buildSnatRule, buildMasqueradeRule, } from './nft.rulebuilder.nat.js';
|
|
8
|
+
export { buildRateLimitRule, buildPerIpRateLimitRule, buildConnectionRateRule, } from './nft.rulebuilder.ratelimit.js';
|
|
9
|
+
export { buildFirewallRule, buildIPSetCreate, buildIPSetAddElements, buildIPSetRemoveElements, buildIPSetDelete, buildIPSetMatchRule, } from './nft.rulebuilder.firewall.js';
|
|
10
|
+
export type { TNftProtocol, TNftFamily, TNftChainHook, TNftChainType, TNftPolicy, TFirewallAction, TCtState, INftDnatRule, INftSnatRule, INftMasqueradeRule, INftRateLimitRule, INftConnectionRateRule, INftFirewallRule, INftIPSetConfig, INftRuleGroup, ISmartNftablesOptions, INftStatus, } from './nft.types.js';
|
package/dist_ts/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Main facade
|
|
2
|
+
export { SmartNftables } from './nft.manager.js';
|
|
3
|
+
// Sub-managers
|
|
4
|
+
export { NatManager } from './nft.manager.nat.js';
|
|
5
|
+
export { FirewallManager } from './nft.manager.firewall.js';
|
|
6
|
+
export { RateLimitManager } from './nft.manager.ratelimit.js';
|
|
7
|
+
// Executor
|
|
8
|
+
export { NftExecutor, NftNotRootError, NftCommandError } from './nft.executor.js';
|
|
9
|
+
// Rule builders (for advanced usage)
|
|
10
|
+
export { buildTableSetup, buildFilterChains, buildTableCleanup, } from './nft.rulebuilder.table.js';
|
|
11
|
+
export { buildDnatRules, buildSnatRule, buildMasqueradeRule, } from './nft.rulebuilder.nat.js';
|
|
12
|
+
export { buildRateLimitRule, buildPerIpRateLimitRule, buildConnectionRateRule, } from './nft.rulebuilder.ratelimit.js';
|
|
13
|
+
export { buildFirewallRule, buildIPSetCreate, buildIPSetAddElements, buildIPSetRemoveElements, buildIPSetDelete, buildIPSetMatchRule, } from './nft.rulebuilder.firewall.js';
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjO0FBQ2QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRWpELGVBQWU7QUFDZixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzVELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRTlELFdBQVc7QUFDWCxPQUFPLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUVsRixxQ0FBcUM7QUFDckMsT0FBTyxFQUNMLGVBQWUsRUFDZixpQkFBaUIsRUFDakIsaUJBQWlCLEdBQ2xCLE1BQU0sNEJBQTRCLENBQUM7QUFFcEMsT0FBTyxFQUNMLGNBQWMsRUFDZCxhQUFhLEVBQ2IsbUJBQW1CLEdBQ3BCLE1BQU0sMEJBQTBCLENBQUM7QUFFbEMsT0FBTyxFQUNMLGtCQUFrQixFQUNsQix1QkFBdUIsRUFDdkIsdUJBQXVCLEdBQ3hCLE1BQU0sZ0NBQWdDLENBQUM7QUFFeEMsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixnQkFBZ0IsRUFDaEIscUJBQXFCLEVBQ3JCLHdCQUF3QixFQUN4QixnQkFBZ0IsRUFDaEIsbUJBQW1CLEdBQ3BCLE1BQU0sK0JBQStCLENBQUMifQ==
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare class NftNotRootError extends Error {
|
|
2
|
+
constructor();
|
|
3
|
+
}
|
|
4
|
+
export declare class NftCommandError extends Error {
|
|
5
|
+
readonly command: string;
|
|
6
|
+
readonly stderr: string;
|
|
7
|
+
constructor(command: string, stderr: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Low-level executor for nft CLI commands.
|
|
11
|
+
*/
|
|
12
|
+
export declare class NftExecutor {
|
|
13
|
+
private dryRun;
|
|
14
|
+
constructor(options?: {
|
|
15
|
+
dryRun?: boolean;
|
|
16
|
+
});
|
|
17
|
+
/** Check if running as root (euid 0). */
|
|
18
|
+
isRoot(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Execute a single nft command.
|
|
21
|
+
* The command may or may not start with "nft " — the prefix is stripped if present.
|
|
22
|
+
* Returns stdout on success.
|
|
23
|
+
*/
|
|
24
|
+
exec(command: string): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Execute multiple nft commands sequentially.
|
|
27
|
+
* By default stops on first failure. Set continueOnError to keep going.
|
|
28
|
+
*/
|
|
29
|
+
execBatch(commands: string[], options?: {
|
|
30
|
+
continueOnError?: boolean;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
const execFile = plugins.util.promisify(plugins.childProcess.execFile);
|
|
3
|
+
export class NftNotRootError extends Error {
|
|
4
|
+
constructor() {
|
|
5
|
+
super('Not running as root — nftables commands require root privileges');
|
|
6
|
+
this.name = 'NftNotRootError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class NftCommandError extends Error {
|
|
10
|
+
constructor(command, stderr) {
|
|
11
|
+
super(`nft command failed: ${command} — ${stderr}`);
|
|
12
|
+
this.name = 'NftCommandError';
|
|
13
|
+
this.command = command;
|
|
14
|
+
this.stderr = stderr;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Low-level executor for nft CLI commands.
|
|
19
|
+
*/
|
|
20
|
+
export class NftExecutor {
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.dryRun = options?.dryRun ?? false;
|
|
23
|
+
}
|
|
24
|
+
/** Check if running as root (euid 0). */
|
|
25
|
+
isRoot() {
|
|
26
|
+
return process.getuid?.() === 0;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Execute a single nft command.
|
|
30
|
+
* The command may or may not start with "nft " — the prefix is stripped if present.
|
|
31
|
+
* Returns stdout on success.
|
|
32
|
+
*/
|
|
33
|
+
async exec(command) {
|
|
34
|
+
if (this.dryRun) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
// Strip "nft " prefix if present
|
|
38
|
+
const args = command.startsWith('nft ') ? command.slice(4) : command;
|
|
39
|
+
const { stdout } = await execFile('nft', args.split(/\s+/));
|
|
40
|
+
return stdout;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Execute multiple nft commands sequentially.
|
|
44
|
+
* By default stops on first failure. Set continueOnError to keep going.
|
|
45
|
+
*/
|
|
46
|
+
async execBatch(commands, options) {
|
|
47
|
+
for (const cmd of commands) {
|
|
48
|
+
try {
|
|
49
|
+
await this.exec(cmd);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (!options?.continueOnError) {
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0LmV4ZWN1dG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvbmZ0LmV4ZWN1dG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBRXhDLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7QUFFdkUsTUFBTSxPQUFPLGVBQWdCLFNBQVEsS0FBSztJQUN4QztRQUNFLEtBQUssQ0FBQyxpRUFBaUUsQ0FBQyxDQUFDO1FBQ3pFLElBQUksQ0FBQyxJQUFJLEdBQUcsaUJBQWlCLENBQUM7SUFDaEMsQ0FBQztDQUNGO0FBRUQsTUFBTSxPQUFPLGVBQWdCLFNBQVEsS0FBSztJQUl4QyxZQUFZLE9BQWUsRUFBRSxNQUFjO1FBQ3pDLEtBQUssQ0FBQyx1QkFBdUIsT0FBTyxNQUFNLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDcEQsSUFBSSxDQUFDLElBQUksR0FBRyxpQkFBaUIsQ0FBQztRQUM5QixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0NBQ0Y7QUFFRDs7R0FFRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBR3RCLFlBQVksT0FBOEI7UUFDeEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLEVBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQztJQUN6QyxDQUFDO0lBRUQseUNBQXlDO0lBQ2xDLE1BQU07UUFDWCxPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBZTtRQUMvQixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7UUFFRCxpQ0FBaUM7UUFDakMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO1FBRXJFLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxNQUFNLFFBQVEsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQzVELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxLQUFLLENBQUMsU0FBUyxDQUNwQixRQUFrQixFQUNsQixPQUF1QztRQUV2QyxLQUFLLE1BQU0sR0FBRyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQzNCLElBQUksQ0FBQztnQkFDSCxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDdkIsQ0FBQztZQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7Z0JBQ2IsSUFBSSxDQUFDLE9BQU8sRUFBRSxlQUFlLEVBQUUsQ0FBQztvQkFDOUIsTUFBTSxHQUFHLENBQUM7Z0JBQ1osQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztDQUNGIn0=
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { NftExecutor } from './nft.executor.js';
|
|
2
|
+
import { NatManager } from './nft.manager.nat.js';
|
|
3
|
+
import { FirewallManager } from './nft.manager.firewall.js';
|
|
4
|
+
import { RateLimitManager } from './nft.manager.ratelimit.js';
|
|
5
|
+
import type { TNftFamily, INftRuleGroup, INftStatus, ISmartNftablesOptions } from './nft.types.js';
|
|
6
|
+
/**
|
|
7
|
+
* SmartNftables — high-level facade for managing nftables rules.
|
|
8
|
+
*
|
|
9
|
+
* Provides sub-managers for NAT, firewall, and rate limiting.
|
|
10
|
+
* All rules are tracked in logical groups and can be removed individually or cleaned up entirely.
|
|
11
|
+
*/
|
|
12
|
+
export declare class SmartNftables {
|
|
13
|
+
readonly nat: NatManager;
|
|
14
|
+
readonly firewall: FirewallManager;
|
|
15
|
+
readonly rateLimit: RateLimitManager;
|
|
16
|
+
readonly tableName: string;
|
|
17
|
+
readonly family: TNftFamily;
|
|
18
|
+
readonly executor: NftExecutor;
|
|
19
|
+
private initialized;
|
|
20
|
+
private hasFilterChains;
|
|
21
|
+
private warnedNonRoot;
|
|
22
|
+
private ruleGroups;
|
|
23
|
+
constructor(options?: ISmartNftablesOptions);
|
|
24
|
+
/**
|
|
25
|
+
* Initialize the nftables table and NAT chains. Idempotent.
|
|
26
|
+
*/
|
|
27
|
+
initialize(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Ensure filter chains (input/forward/output) are created.
|
|
30
|
+
* Called automatically when firewall or rate-limit rules are added.
|
|
31
|
+
*/
|
|
32
|
+
ensureFilterChains(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Ensure the table is initialized before applying rules.
|
|
35
|
+
*/
|
|
36
|
+
ensureInitialized(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Apply a group of nft commands and track them under the given ID.
|
|
39
|
+
*/
|
|
40
|
+
applyRuleGroup(groupId: string, commands: string[]): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Remove a tracked rule group. Removes from tracking.
|
|
43
|
+
* Note: full kernel cleanup requires cleanup() — individual rule removal
|
|
44
|
+
* would require handle-based tracking.
|
|
45
|
+
*/
|
|
46
|
+
removeRuleGroup(groupId: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Get a tracked rule group by ID.
|
|
49
|
+
*/
|
|
50
|
+
getRuleGroup(groupId: string): INftRuleGroup | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Delete the entire nftables table and clear all tracking.
|
|
53
|
+
*/
|
|
54
|
+
cleanup(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Get status report of the managed nftables state.
|
|
57
|
+
*/
|
|
58
|
+
status(): INftStatus;
|
|
59
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { SmartNftables } from './nft.manager.js';
|
|
2
|
+
import type { INftFirewallRule, INftIPSetConfig } from './nft.types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Manages firewall (filter) rules, IP sets, and convenience methods.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FirewallManager {
|
|
7
|
+
private parent;
|
|
8
|
+
constructor(parent: SmartNftables);
|
|
9
|
+
/**
|
|
10
|
+
* Add a firewall rule (input/output/forward).
|
|
11
|
+
*/
|
|
12
|
+
addRule(groupId: string, rule: INftFirewallRule): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Remove a firewall rule group.
|
|
15
|
+
*/
|
|
16
|
+
removeRule(groupId: string): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Create a named IP set.
|
|
19
|
+
*/
|
|
20
|
+
createIPSet(config: INftIPSetConfig): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Add elements to an existing IP set.
|
|
23
|
+
*/
|
|
24
|
+
addToIPSet(setName: string, elements: string[]): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Remove elements from an IP set.
|
|
27
|
+
*/
|
|
28
|
+
removeFromIPSet(setName: string, elements: string[]): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Delete an IP set entirely.
|
|
31
|
+
*/
|
|
32
|
+
deleteIPSet(setName: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Convenience: block an IP or CIDR subnet.
|
|
35
|
+
*/
|
|
36
|
+
blockIP(ip: string, options?: {
|
|
37
|
+
direction?: 'input' | 'forward';
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Convenience: allow only specific IPs on a port.
|
|
41
|
+
* Adds accept rules for each IP, then a drop rule for everything else on that port.
|
|
42
|
+
*/
|
|
43
|
+
allowOnlyIPs(groupId: string, ips: string[], port?: number, protocol?: 'tcp' | 'udp' | 'both'): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Convenience: enable stateful connection tracking.
|
|
46
|
+
* Allows established+related, drops invalid.
|
|
47
|
+
*/
|
|
48
|
+
enableStatefulTracking(chain?: 'input' | 'forward' | 'output'): Promise<void>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { buildFirewallRule, buildIPSetCreate, buildIPSetAddElements, buildIPSetRemoveElements, buildIPSetDelete, buildIPSetMatchRule, } from './nft.rulebuilder.firewall.js';
|
|
2
|
+
/**
|
|
3
|
+
* Manages firewall (filter) rules, IP sets, and convenience methods.
|
|
4
|
+
*/
|
|
5
|
+
export class FirewallManager {
|
|
6
|
+
constructor(parent) {
|
|
7
|
+
this.parent = parent;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Add a firewall rule (input/output/forward).
|
|
11
|
+
*/
|
|
12
|
+
async addRule(groupId, rule) {
|
|
13
|
+
await this.parent.ensureFilterChains();
|
|
14
|
+
const commands = buildFirewallRule(this.parent.tableName, this.parent.family, rule);
|
|
15
|
+
await this.parent.applyRuleGroup(`fw:${groupId}`, commands);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Remove a firewall rule group.
|
|
19
|
+
*/
|
|
20
|
+
async removeRule(groupId) {
|
|
21
|
+
await this.parent.removeRuleGroup(`fw:${groupId}`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create a named IP set.
|
|
25
|
+
*/
|
|
26
|
+
async createIPSet(config) {
|
|
27
|
+
await this.parent.ensureInitialized();
|
|
28
|
+
const commands = buildIPSetCreate(this.parent.tableName, this.parent.family, config);
|
|
29
|
+
await this.parent.applyRuleGroup(`ipset:${config.name}`, commands);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Add elements to an existing IP set.
|
|
33
|
+
*/
|
|
34
|
+
async addToIPSet(setName, elements) {
|
|
35
|
+
const commands = buildIPSetAddElements(this.parent.tableName, this.parent.family, setName, elements);
|
|
36
|
+
if (commands.length > 0) {
|
|
37
|
+
await this.parent.executor.execBatch(commands);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Remove elements from an IP set.
|
|
42
|
+
*/
|
|
43
|
+
async removeFromIPSet(setName, elements) {
|
|
44
|
+
const commands = buildIPSetRemoveElements(this.parent.tableName, this.parent.family, setName, elements);
|
|
45
|
+
if (commands.length > 0) {
|
|
46
|
+
await this.parent.executor.execBatch(commands);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Delete an IP set entirely.
|
|
51
|
+
*/
|
|
52
|
+
async deleteIPSet(setName) {
|
|
53
|
+
const commands = buildIPSetDelete(this.parent.tableName, this.parent.family, setName);
|
|
54
|
+
await this.parent.executor.execBatch(commands);
|
|
55
|
+
await this.parent.removeRuleGroup(`ipset:${setName}`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convenience: block an IP or CIDR subnet.
|
|
59
|
+
*/
|
|
60
|
+
async blockIP(ip, options) {
|
|
61
|
+
const direction = options?.direction ?? 'input';
|
|
62
|
+
const safeId = ip.replace(/[/.]/g, '_');
|
|
63
|
+
await this.addRule(`block-${safeId}`, {
|
|
64
|
+
direction,
|
|
65
|
+
action: 'drop',
|
|
66
|
+
sourceIP: ip,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Convenience: allow only specific IPs on a port.
|
|
71
|
+
* Adds accept rules for each IP, then a drop rule for everything else on that port.
|
|
72
|
+
*/
|
|
73
|
+
async allowOnlyIPs(groupId, ips, port, protocol) {
|
|
74
|
+
await this.parent.ensureFilterChains();
|
|
75
|
+
const commands = [];
|
|
76
|
+
for (const ip of ips) {
|
|
77
|
+
const acceptCmds = buildFirewallRule(this.parent.tableName, this.parent.family, {
|
|
78
|
+
direction: 'input',
|
|
79
|
+
action: 'accept',
|
|
80
|
+
sourceIP: ip,
|
|
81
|
+
destPort: port,
|
|
82
|
+
protocol,
|
|
83
|
+
});
|
|
84
|
+
commands.push(...acceptCmds);
|
|
85
|
+
}
|
|
86
|
+
// Drop everything else on that port
|
|
87
|
+
const dropCmds = buildFirewallRule(this.parent.tableName, this.parent.family, {
|
|
88
|
+
direction: 'input',
|
|
89
|
+
action: 'drop',
|
|
90
|
+
destPort: port,
|
|
91
|
+
protocol,
|
|
92
|
+
});
|
|
93
|
+
commands.push(...dropCmds);
|
|
94
|
+
await this.parent.applyRuleGroup(`fw:allowonly:${groupId}`, commands);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Convenience: enable stateful connection tracking.
|
|
98
|
+
* Allows established+related, drops invalid.
|
|
99
|
+
*/
|
|
100
|
+
async enableStatefulTracking(chain) {
|
|
101
|
+
await this.parent.ensureFilterChains();
|
|
102
|
+
const direction = chain ?? 'input';
|
|
103
|
+
const commands = [];
|
|
104
|
+
// Allow established and related connections
|
|
105
|
+
const allowCmds = buildFirewallRule(this.parent.tableName, this.parent.family, {
|
|
106
|
+
direction,
|
|
107
|
+
action: 'accept',
|
|
108
|
+
ctStates: ['established', 'related'],
|
|
109
|
+
});
|
|
110
|
+
commands.push(...allowCmds);
|
|
111
|
+
// Drop invalid connections
|
|
112
|
+
const dropCmds = buildFirewallRule(this.parent.tableName, this.parent.family, {
|
|
113
|
+
direction,
|
|
114
|
+
action: 'drop',
|
|
115
|
+
ctStates: ['invalid'],
|
|
116
|
+
});
|
|
117
|
+
commands.push(...dropCmds);
|
|
118
|
+
await this.parent.applyRuleGroup(`fw:stateful:${direction}`, commands);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0Lm1hbmFnZXIuZmlyZXdhbGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9uZnQubWFuYWdlci5maXJld2FsbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNoQixxQkFBcUIsRUFDckIsd0JBQXdCLEVBQ3hCLGdCQUFnQixFQUNoQixtQkFBbUIsR0FDcEIsTUFBTSwrQkFBK0IsQ0FBQztBQUV2Qzs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQzFCLFlBQW9CLE1BQXFCO1FBQXJCLFdBQU0sR0FBTixNQUFNLENBQWU7SUFBRyxDQUFDO0lBRTdDOztPQUVHO0lBQ0ksS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFlLEVBQUUsSUFBc0I7UUFDMUQsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDdkMsTUFBTSxRQUFRLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDcEYsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxNQUFNLE9BQU8sRUFBRSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxVQUFVLENBQUMsT0FBZTtRQUNyQyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLE1BQU0sT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQXVCO1FBQzlDLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3RDLE1BQU0sUUFBUSxHQUFHLGdCQUFnQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FB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
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { NftExecutor } from './nft.executor.js';
|
|
2
|
+
import { buildTableSetup, buildFilterChains, buildTableCleanup } from './nft.rulebuilder.table.js';
|
|
3
|
+
import { NatManager } from './nft.manager.nat.js';
|
|
4
|
+
import { FirewallManager } from './nft.manager.firewall.js';
|
|
5
|
+
import { RateLimitManager } from './nft.manager.ratelimit.js';
|
|
6
|
+
/**
|
|
7
|
+
* SmartNftables — high-level facade for managing nftables rules.
|
|
8
|
+
*
|
|
9
|
+
* Provides sub-managers for NAT, firewall, and rate limiting.
|
|
10
|
+
* All rules are tracked in logical groups and can be removed individually or cleaned up entirely.
|
|
11
|
+
*/
|
|
12
|
+
export class SmartNftables {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.initialized = false;
|
|
15
|
+
this.hasFilterChains = false;
|
|
16
|
+
this.warnedNonRoot = false;
|
|
17
|
+
this.ruleGroups = new Map();
|
|
18
|
+
this.tableName = options?.tableName ?? 'smartnftables';
|
|
19
|
+
this.family = options?.family ?? 'ip';
|
|
20
|
+
this.executor = new NftExecutor({ dryRun: options?.dryRun });
|
|
21
|
+
this.nat = new NatManager(this);
|
|
22
|
+
this.firewall = new FirewallManager(this);
|
|
23
|
+
this.rateLimit = new RateLimitManager(this);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the nftables table and NAT chains. Idempotent.
|
|
27
|
+
*/
|
|
28
|
+
async initialize() {
|
|
29
|
+
if (this.initialized)
|
|
30
|
+
return;
|
|
31
|
+
if (!this.executor.isRoot()) {
|
|
32
|
+
if (!this.warnedNonRoot) {
|
|
33
|
+
console.warn('smartnftables: not running as root. Rules are tracked but not applied to kernel.');
|
|
34
|
+
this.warnedNonRoot = true;
|
|
35
|
+
}
|
|
36
|
+
this.initialized = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const commands = buildTableSetup(this.tableName, this.family);
|
|
40
|
+
await this.executor.execBatch(commands);
|
|
41
|
+
this.initialized = true;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Ensure filter chains (input/forward/output) are created.
|
|
45
|
+
* Called automatically when firewall or rate-limit rules are added.
|
|
46
|
+
*/
|
|
47
|
+
async ensureFilterChains() {
|
|
48
|
+
if (this.hasFilterChains)
|
|
49
|
+
return;
|
|
50
|
+
await this.ensureInitialized();
|
|
51
|
+
if (this.executor.isRoot()) {
|
|
52
|
+
const commands = buildFilterChains(this.tableName, this.family);
|
|
53
|
+
await this.executor.execBatch(commands);
|
|
54
|
+
}
|
|
55
|
+
this.hasFilterChains = true;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Ensure the table is initialized before applying rules.
|
|
59
|
+
*/
|
|
60
|
+
async ensureInitialized() {
|
|
61
|
+
if (!this.initialized) {
|
|
62
|
+
await this.initialize();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Apply a group of nft commands and track them under the given ID.
|
|
67
|
+
*/
|
|
68
|
+
async applyRuleGroup(groupId, commands) {
|
|
69
|
+
// Always track the group locally
|
|
70
|
+
this.ruleGroups.set(groupId, {
|
|
71
|
+
id: groupId,
|
|
72
|
+
commands,
|
|
73
|
+
createdAt: Date.now(),
|
|
74
|
+
});
|
|
75
|
+
if (!this.executor.isRoot()) {
|
|
76
|
+
if (!this.warnedNonRoot) {
|
|
77
|
+
console.warn('smartnftables: not running as root. Rules are tracked but not applied to kernel.');
|
|
78
|
+
this.warnedNonRoot = true;
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
await this.ensureInitialized();
|
|
83
|
+
await this.executor.execBatch(commands);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Remove a tracked rule group. Removes from tracking.
|
|
87
|
+
* Note: full kernel cleanup requires cleanup() — individual rule removal
|
|
88
|
+
* would require handle-based tracking.
|
|
89
|
+
*/
|
|
90
|
+
async removeRuleGroup(groupId) {
|
|
91
|
+
this.ruleGroups.delete(groupId);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get a tracked rule group by ID.
|
|
95
|
+
*/
|
|
96
|
+
getRuleGroup(groupId) {
|
|
97
|
+
return this.ruleGroups.get(groupId);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Delete the entire nftables table and clear all tracking.
|
|
101
|
+
*/
|
|
102
|
+
async cleanup() {
|
|
103
|
+
if (this.executor.isRoot() && this.initialized) {
|
|
104
|
+
const commands = buildTableCleanup(this.tableName, this.family);
|
|
105
|
+
await this.executor.execBatch(commands, { continueOnError: true });
|
|
106
|
+
}
|
|
107
|
+
this.ruleGroups.clear();
|
|
108
|
+
this.initialized = false;
|
|
109
|
+
this.hasFilterChains = false;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get status report of the managed nftables state.
|
|
113
|
+
*/
|
|
114
|
+
status() {
|
|
115
|
+
const groups = {};
|
|
116
|
+
for (const [id, group] of this.ruleGroups) {
|
|
117
|
+
groups[id] = {
|
|
118
|
+
ruleCount: group.commands.length,
|
|
119
|
+
createdAt: group.createdAt,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
initialized: this.initialized,
|
|
124
|
+
tableName: this.tableName,
|
|
125
|
+
family: this.family,
|
|
126
|
+
isRoot: this.executor.isRoot(),
|
|
127
|
+
activeGroups: this.ruleGroups.size,
|
|
128
|
+
groups,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0Lm1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9uZnQubWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDaEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxpQkFBaUIsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ25HLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFHOUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQWN4QixZQUFZLE9BQStCO1FBTG5DLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLG9CQUFlLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLGtCQUFhLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLGVBQVUsR0FBK0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUd6RCxJQUFJLENBQUMsU0FBUyxHQUFHLE9BQU8sRUFBRSxTQUFTLElBQUksZUFBZSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxNQUFNLEdBQUcsT0FBTyxFQUFFLE1BQU0sSUFBSSxJQUFJLENBQUM7UUFDdEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLFdBQVcsQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUU3RCxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hDLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzlDLENBQUM7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
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { SmartNftables } from './nft.manager.js';
|
|
2
|
+
import type { INftDnatRule, INftSnatRule, INftMasqueradeRule, TNftProtocol } from './nft.types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Manages NAT (DNAT/SNAT/masquerade) rules.
|
|
5
|
+
*/
|
|
6
|
+
export declare class NatManager {
|
|
7
|
+
private parent;
|
|
8
|
+
constructor(parent: SmartNftables);
|
|
9
|
+
/**
|
|
10
|
+
* Add a port forwarding rule (DNAT + optional masquerade).
|
|
11
|
+
*/
|
|
12
|
+
addPortForwarding(groupId: string, rule: INftDnatRule): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Remove a previously added port forwarding group.
|
|
15
|
+
*/
|
|
16
|
+
removePortForwarding(groupId: string): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Add SNAT (source NAT) rule.
|
|
19
|
+
*/
|
|
20
|
+
addSnat(groupId: string, rule: INftSnatRule): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Add masquerade rule for outgoing traffic.
|
|
23
|
+
*/
|
|
24
|
+
addMasquerade(groupId: string, rule: INftMasqueradeRule): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Add port forwarding for a range of ports.
|
|
27
|
+
* Maps sourceStart..sourceStart+count to targetStart..targetStart+count.
|
|
28
|
+
*/
|
|
29
|
+
addPortRange(groupId: string, sourceStart: number, sourceEnd: number, targetHost: string, targetStart: number, protocol?: TNftProtocol): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Remove a port range forwarding group.
|
|
32
|
+
*/
|
|
33
|
+
removePortRange(groupId: string): Promise<void>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { buildDnatRules, buildSnatRule, buildMasqueradeRule } from './nft.rulebuilder.nat.js';
|
|
2
|
+
/**
|
|
3
|
+
* Manages NAT (DNAT/SNAT/masquerade) rules.
|
|
4
|
+
*/
|
|
5
|
+
export class NatManager {
|
|
6
|
+
constructor(parent) {
|
|
7
|
+
this.parent = parent;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Add a port forwarding rule (DNAT + optional masquerade).
|
|
11
|
+
*/
|
|
12
|
+
async addPortForwarding(groupId, rule) {
|
|
13
|
+
const commands = buildDnatRules(this.parent.tableName, this.parent.family, rule);
|
|
14
|
+
await this.parent.applyRuleGroup(`nat:${groupId}`, commands);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Remove a previously added port forwarding group.
|
|
18
|
+
*/
|
|
19
|
+
async removePortForwarding(groupId) {
|
|
20
|
+
await this.parent.removeRuleGroup(`nat:${groupId}`);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Add SNAT (source NAT) rule.
|
|
24
|
+
*/
|
|
25
|
+
async addSnat(groupId, rule) {
|
|
26
|
+
const commands = buildSnatRule(this.parent.tableName, this.parent.family, rule);
|
|
27
|
+
await this.parent.applyRuleGroup(`nat:snat:${groupId}`, commands);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Add masquerade rule for outgoing traffic.
|
|
31
|
+
*/
|
|
32
|
+
async addMasquerade(groupId, rule) {
|
|
33
|
+
const commands = buildMasqueradeRule(this.parent.tableName, this.parent.family, rule);
|
|
34
|
+
await this.parent.applyRuleGroup(`nat:masq:${groupId}`, commands);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Add port forwarding for a range of ports.
|
|
38
|
+
* Maps sourceStart..sourceStart+count to targetStart..targetStart+count.
|
|
39
|
+
*/
|
|
40
|
+
async addPortRange(groupId, sourceStart, sourceEnd, targetHost, targetStart, protocol) {
|
|
41
|
+
const allCommands = [];
|
|
42
|
+
const count = sourceEnd - sourceStart;
|
|
43
|
+
for (let i = 0; i <= count; i++) {
|
|
44
|
+
const commands = buildDnatRules(this.parent.tableName, this.parent.family, {
|
|
45
|
+
sourcePort: sourceStart + i,
|
|
46
|
+
targetHost,
|
|
47
|
+
targetPort: targetStart + i,
|
|
48
|
+
protocol,
|
|
49
|
+
});
|
|
50
|
+
allCommands.push(...commands);
|
|
51
|
+
}
|
|
52
|
+
await this.parent.applyRuleGroup(`nat:range:${groupId}`, allCommands);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Remove a port range forwarding group.
|
|
56
|
+
*/
|
|
57
|
+
async removePortRange(groupId) {
|
|
58
|
+
await this.parent.removeRuleGroup(`nat:range:${groupId}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0Lm1hbmFnZXIubmF0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvbmZ0Lm1hbmFnZXIubmF0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxjQUFjLEVBQUUsYUFBYSxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFOUY7O0dBRUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUNyQixZQUFvQixNQUFxQjtRQUFyQixXQUFNLEdBQU4sTUFBTSxDQUFlO0lBQUcsQ0FBQztJQUU3Qzs7T0FFRztJQUNJLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxPQUFlLEVBQUUsSUFBa0I7UUFDaEUsTUFBTSxRQUFRLEdBQUcsY0FBYyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ2pGLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsT0FBTyxPQUFPLEVBQUUsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsb0JBQW9CLENBQUMsT0FBZTtRQUMvQyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLE9BQU8sT0FBTyxFQUFFLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQWUsRUFBRSxJQUFrQjtRQUN0RCxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDaEYsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxZQUFZLE9BQU8sRUFBRSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxhQUFhLENBQUMsT0FBZSxFQUFFLElBQXdCO1FBQ2xFLE1BQU0sUUFBUSxHQUFHLG1CQUFtQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ3RGLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsWUFBWSxPQUFPLEVBQUUsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSyxDQUFDLFlBQVksQ0FDdkIsT0FBZSxFQUNmLFdBQW1CLEVBQ25CLFNBQWlCLEVBQ2pCLFVBQWtCLEVBQ2xCLFdBQW1CLEVBQ25CLFFBQXVCO1FBRXZCLE1BQU0sV0FBVyxHQUFhLEVBQUUsQ0FBQztRQUNqQyxNQUFNLEtBQUssR0FBRyxTQUFTLEdBQUcsV0FBVyxDQUFDO1FBRXRDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNoQyxNQUFNLFFBQVEsR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUU7Z0JBQ3pFLFVBQVUsRUFBRSxXQUFXLEdBQUcsQ0FBQztnQkFDM0IsVUFBVTtnQkFDVixVQUFVLEVBQUUsV0FBVyxHQUFHLENBQUM7Z0JBQzNCLFFBQVE7YUFDVCxDQUFDLENBQUM7WUFDSCxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUM7UUFDaEMsQ0FBQztRQUVELE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsYUFBYSxPQUFPLEVBQUUsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsZUFBZSxDQUFDLE9BQWU7UUFDMUMsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxhQUFhLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDNUQsQ0FBQztDQUNGIn0=
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SmartNftables } from './nft.manager.js';
|
|
2
|
+
import type { INftRateLimitRule, INftConnectionRateRule } from './nft.types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Manages rate limiting rules using nft meters and limit expressions.
|
|
5
|
+
*/
|
|
6
|
+
export declare class RateLimitManager {
|
|
7
|
+
private parent;
|
|
8
|
+
constructor(parent: SmartNftables);
|
|
9
|
+
/**
|
|
10
|
+
* Add a rate limit rule (global or per-IP).
|
|
11
|
+
*/
|
|
12
|
+
addRateLimit(groupId: string, rule: INftRateLimitRule): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Remove a rate limit rule group.
|
|
15
|
+
*/
|
|
16
|
+
removeRateLimit(groupId: string): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Add a new-connection rate limit rule.
|
|
19
|
+
* Limits the rate of new TCP/UDP connections (ct state new).
|
|
20
|
+
*/
|
|
21
|
+
addConnectionRateLimit(groupId: string, rule: INftConnectionRateRule): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Remove a connection rate limit rule group.
|
|
24
|
+
*/
|
|
25
|
+
removeConnectionRateLimit(groupId: string): Promise<void>;
|
|
26
|
+
}
|