@push.rocks/smartnftables 1.0.1 → 1.2.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/changelog.md +15 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/nft.manager.d.ts +7 -2
- package/dist_ts/nft.manager.firewall.d.ts +6 -1
- package/dist_ts/nft.manager.firewall.js +32 -1
- package/dist_ts/nft.manager.js +19 -3
- package/dist_ts/nft.rulebuilder.firewall.d.ts +1 -0
- package/dist_ts/nft.rulebuilder.firewall.js +5 -3
- package/dist_ts/nft.rulebuilder.nat.js +3 -2
- package/dist_ts/nft.types.d.ts +20 -0
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +2 -0
- package/ts/nft.manager.firewall.ts +36 -1
- package/ts/nft.manager.ts +19 -3
- package/ts/nft.rulebuilder.firewall.ts +5 -2
- package/ts/nft.rulebuilder.nat.ts +2 -1
- package/ts/nft.types.ts +22 -0
package/changelog.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-04-26 - 1.2.0 - feat(firewall)
|
|
4
|
+
add IP set blocking convenience API with CIDR interval support and optional rule comments
|
|
5
|
+
|
|
6
|
+
- introduces firewall.blockIPSet() to create a set, populate it with IPs or CIDR ranges, and apply a single drop rule
|
|
7
|
+
- adds interval set support so CIDR entries can be stored in nftables sets
|
|
8
|
+
- supports optional comments on generated IP set match rules
|
|
9
|
+
- adds forced cleanup support and allows table existence checks without requiring prior initialization
|
|
10
|
+
|
|
11
|
+
## 2026-03-30 - 1.1.0 - feat(nft)
|
|
12
|
+
add source IP filtering for DNAT rules and expose table existence checks
|
|
13
|
+
|
|
14
|
+
- Adds an optional sourceIP field to NAT rule definitions to restrict DNAT rules to matching source addresses or subnets.
|
|
15
|
+
- Updates DNAT rule generation to include an ip saddr match when sourceIP is provided.
|
|
16
|
+
- Introduces a tableExists() manager method to detect whether the managed nftables table is still present in the kernel.
|
|
17
|
+
|
|
3
18
|
## 2026-03-26 - 1.0.1 - fix(repo)
|
|
4
19
|
no changes to commit
|
|
5
20
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartnftables',
|
|
6
|
-
version: '1.0
|
|
6
|
+
version: '1.2.0',
|
|
7
7
|
description: 'A TypeScript module for managing nftables rules including NAT, firewall, and rate limiting with a high-level API.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSwyQkFBMkI7SUFDakMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLG1IQUFtSDtDQUNqSSxDQUFBIn0=
|
package/dist_ts/index.d.ts
CHANGED
|
@@ -7,4 +7,4 @@ export { buildTableSetup, buildFilterChains, buildTableCleanup, } from './nft.ru
|
|
|
7
7
|
export { buildDnatRules, buildSnatRule, buildMasqueradeRule, } from './nft.rulebuilder.nat.js';
|
|
8
8
|
export { buildRateLimitRule, buildPerIpRateLimitRule, buildConnectionRateRule, } from './nft.rulebuilder.ratelimit.js';
|
|
9
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';
|
|
10
|
+
export type { TNftProtocol, TNftFamily, TNftChainHook, TNftChainType, TNftPolicy, TFirewallAction, TCtState, INftDnatRule, INftSnatRule, INftMasqueradeRule, INftRateLimitRule, INftConnectionRateRule, INftFirewallRule, INftIPSetBlockOptions, INftIPSetConfig, INftCleanupOptions, INftRuleGroup, ISmartNftablesOptions, INftStatus, } from './nft.types.js';
|
package/dist_ts/nft.manager.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { NftExecutor } from './nft.executor.js';
|
|
|
2
2
|
import { NatManager } from './nft.manager.nat.js';
|
|
3
3
|
import { FirewallManager } from './nft.manager.firewall.js';
|
|
4
4
|
import { RateLimitManager } from './nft.manager.ratelimit.js';
|
|
5
|
-
import type { TNftFamily, INftRuleGroup, INftStatus, ISmartNftablesOptions } from './nft.types.js';
|
|
5
|
+
import type { TNftFamily, INftCleanupOptions, INftRuleGroup, INftStatus, ISmartNftablesOptions } from './nft.types.js';
|
|
6
6
|
/**
|
|
7
7
|
* SmartNftables — high-level facade for managing nftables rules.
|
|
8
8
|
*
|
|
@@ -51,7 +51,12 @@ export declare class SmartNftables {
|
|
|
51
51
|
/**
|
|
52
52
|
* Delete the entire nftables table and clear all tracking.
|
|
53
53
|
*/
|
|
54
|
-
cleanup(): Promise<void>;
|
|
54
|
+
cleanup(options?: INftCleanupOptions): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Check if the managed nftables table exists in the kernel.
|
|
57
|
+
* Returns false if not root, not initialized, or the table was removed externally.
|
|
58
|
+
*/
|
|
59
|
+
tableExists(): Promise<boolean>;
|
|
55
60
|
/**
|
|
56
61
|
* Get status report of the managed nftables state.
|
|
57
62
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SmartNftables } from './nft.manager.js';
|
|
2
|
-
import type { INftFirewallRule, INftIPSetConfig } from './nft.types.js';
|
|
2
|
+
import type { INftFirewallRule, INftIPSetBlockOptions, INftIPSetConfig } from './nft.types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Manages firewall (filter) rules, IP sets, and convenience methods.
|
|
5
5
|
*/
|
|
@@ -36,6 +36,11 @@ export declare class FirewallManager {
|
|
|
36
36
|
blockIP(ip: string, options?: {
|
|
37
37
|
direction?: 'input' | 'forward';
|
|
38
38
|
}): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Convenience: block many IPs or CIDR subnets using one nftables set and
|
|
41
|
+
* one matching drop rule. This is substantially cheaper than one rule per IP.
|
|
42
|
+
*/
|
|
43
|
+
blockIPSet(groupId: string, options: INftIPSetBlockOptions): Promise<void>;
|
|
39
44
|
/**
|
|
40
45
|
* Convenience: allow only specific IPs on a port.
|
|
41
46
|
* Adds accept rules for each IP, then a drop rule for everything else on that port.
|
|
@@ -66,6 +66,37 @@ export class FirewallManager {
|
|
|
66
66
|
sourceIP: ip,
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Convenience: block many IPs or CIDR subnets using one nftables set and
|
|
71
|
+
* one matching drop rule. This is substantially cheaper than one rule per IP.
|
|
72
|
+
*/
|
|
73
|
+
async blockIPSet(groupId, options) {
|
|
74
|
+
const ips = [...new Set(options.ips)].filter(Boolean).sort();
|
|
75
|
+
if (ips.length === 0) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
await this.parent.ensureFilterChains();
|
|
79
|
+
const setName = options.setName ?? `${groupId.replace(/[^a-zA-Z0-9_]/g, '_')}_set`;
|
|
80
|
+
const setType = options.type ?? (this.parent.family === 'ip6' ? 'ipv6_addr' : 'ipv4_addr');
|
|
81
|
+
const needsIntervalSet = ips.some((ip) => ip.includes('/'));
|
|
82
|
+
const direction = options.direction ?? 'input';
|
|
83
|
+
const commands = [
|
|
84
|
+
...buildIPSetCreate(this.parent.tableName, this.parent.family, {
|
|
85
|
+
name: setName,
|
|
86
|
+
type: setType,
|
|
87
|
+
elements: ips,
|
|
88
|
+
interval: needsIntervalSet,
|
|
89
|
+
}),
|
|
90
|
+
...buildIPSetMatchRule(this.parent.tableName, this.parent.family, {
|
|
91
|
+
setName,
|
|
92
|
+
direction,
|
|
93
|
+
matchField: 'saddr',
|
|
94
|
+
action: 'drop',
|
|
95
|
+
comment: options.comment,
|
|
96
|
+
}),
|
|
97
|
+
];
|
|
98
|
+
await this.parent.applyRuleGroup(`fw:blockset:${groupId}`, commands);
|
|
99
|
+
}
|
|
69
100
|
/**
|
|
70
101
|
* Convenience: allow only specific IPs on a port.
|
|
71
102
|
* Adds accept rules for each IP, then a drop rule for everything else on that port.
|
|
@@ -118,4 +149,4 @@ export class FirewallManager {
|
|
|
118
149
|
await this.parent.applyRuleGroup(`fw:stateful:${direction}`, commands);
|
|
119
150
|
}
|
|
120
151
|
}
|
|
121
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
152
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0Lm1hbmFnZXIuZmlyZXdhbGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9uZnQubWFuYWdlci5maXJld2FsbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNoQixxQkFBcUIsRUFDckIsd0JBQXdCLEVBQ3hCLGdCQUFnQixFQUNoQixtQkFBbUIsR0FDcEIsTUFBTSwrQkFBK0IsQ0FBQztBQUV2Qzs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQzFCLFlBQW9CLE1BQXFCO1FBQXJCLFdBQU0sR0FBTixNQUFNLENBQWU7SUFBRyxDQUFDO0lBRTdDOztPQUVHO0lBQ0ksS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFlLEVBQUUsSUFBc0I7UUFDMUQsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDdkMsTUFBTSxRQUFRLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDcEYsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxNQUFNLE9BQU8sRUFBRSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxVQUFVLENBQUMsT0FBZTtRQUNyQyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLE1BQU0sT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQXVCO1FBQzlDLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3RDLE1BQU0sUUFBUSxHQUFHLGdCQUFnQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3JGLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsU0FBUyxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFVBQVUsQ0FBQyxPQUFlLEVBQUUsUUFBa0I7UUFDekQsTUFBTSxRQUFRLEdBQUcscUJBQXFCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ3JHLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4QixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNqRCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLGVBQWUsQ0FBQyxPQUFlLEVBQUUsUUFBa0I7UUFDOUQsTUFBTSxRQUFRLEdBQUcsd0JBQXdCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ3hHLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4QixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNqRCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFdBQVcsQ0FBQyxPQUFlO1FBQ3RDLE1BQU0sUUFBUSxHQUFHLGdCQUFnQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3RGLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQy9DLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsU0FBUyxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBVSxFQUFFLE9BQTZDO1FBQzVFLE1BQU0sU0FBUyxHQUFHLE9BQU8sRUFBRSxTQUFTLElBQUksT0FBTyxDQUFDO1FBQ2hELE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLE1BQU0sRUFBRSxFQUFFO1lBQ3BDLFNBQVM7WUFDVCxNQUFNLEVBQUUsTUFBTTtZQUNkLFFBQVEsRUFBRSxFQUFFO1NBQ2IsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxVQUFVLENBQUMsT0FBZSxFQUFFLE9BQThCO1FBQ3JFLE1BQU0sR0FBRyxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDN0QsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3JCLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFFdkMsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sSUFBSSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQztRQUNuRixNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzNGLE1BQU0sZ0JBQWdCLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzVELE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxTQUFTLElBQUksT0FBTyxDQUFDO1FBQy9DLE1BQU0sUUFBUSxHQUFHO1lBQ2YsR0FBRyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRTtnQkFDN0QsSUFBSSxFQUFFLE9BQU87Z0JBQ2IsSUFBSSxFQUFFLE9BQU87Z0JBQ2IsUUFBUSxFQUFFLEdBQUc7Z0JBQ2IsUUFBUSxFQUFFLGdCQUFnQjthQUMzQixDQUFDO1lBQ0YsR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRTtnQkFDaEUsT0FBTztnQkFDUCxTQUFTO2dCQUNULFVBQVUsRUFBRSxPQUFPO2dCQUNuQixNQUFNLEVBQUUsTUFBTTtnQkFDZCxPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU87YUFDekIsQ0FBQztTQUNILENBQUM7UUFFRixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLGVBQWUsT0FBTyxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDdkUsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxZQUFZLENBQ3ZCLE9BQWUsRUFDZixHQUFhLEVBQ2IsSUFBYSxFQUNiLFFBQWlDO1FBRWpDLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sUUFBUSxHQUFhLEVBQUUsQ0FBQztRQUU5QixLQUFLLE1BQU0sRUFBRSxJQUFJLEdBQUcsRUFBRSxDQUFDO1lBQ3JCLE1BQU0sVUFBVSxHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFO2dCQUM5RSxTQUFTLEVBQUUsT0FBTztnQkFDbEIsTUFBTSxFQUFFLFFBQVE7Z0JBQ2hCLFFBQVEsRUFBRSxFQUFFO2dCQUNaLFFBQVEsRUFBRSxJQUFJO2dCQUNkLFFBQVE7YUFDVCxDQUFDLENBQUM7WUFDSCxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsVUFBVSxDQUFDLENBQUM7UUFDL0IsQ0FBQztRQUVELG9DQUFvQztRQUNwQyxNQUFNLFFBQVEsR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRTtZQUM1RSxTQUFTLEVBQUUsT0FBTztZQUNsQixNQUFNLEVBQUUsTUFBTTtZQUNkLFFBQVEsRUFBRSxJQUFJO1lBQ2QsUUFBUTtTQUNULENBQUMsQ0FBQztRQUNILFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxRQUFRLENBQUMsQ0FBQztRQUUzQixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLGdCQUFnQixPQUFPLEVBQUUsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSyxDQUFDLHNCQUFzQixDQUFDLEtBQXNDO1FBQ3hFLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sU0FBUyxHQUFHLEtBQUssSUFBSSxPQUFPLENBQUM7UUFDbkMsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO1FBRTlCLDRDQUE0QztRQUM1QyxNQUFNLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRTtZQUM3RSxTQUFTO1lBQ1QsTUFBTSxFQUFFLFFBQVE7WUFDaEIsUUFBUSxFQUFFLENBQUMsYUFBYSxFQUFFLFNBQVMsQ0FBQztTQUNyQyxDQUFDLENBQUM7UUFDSCxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsU0FBUyxDQUFDLENBQUM7UUFFNUIsMkJBQTJCO1FBQzNCLE1BQU0sUUFBUSxHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFO1lBQzVFLFNBQVM7WUFDVCxNQUFNLEVBQUUsTUFBTTtZQUNkLFFBQVEsRUFBRSxDQUFDLFNBQVMsQ0FBQztTQUN0QixDQUFDLENBQUM7UUFDSCxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUM7UUFFM0IsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxlQUFlLFNBQVMsRUFBRSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3pFLENBQUM7Q0FDRiJ9
|
package/dist_ts/nft.manager.js
CHANGED
|
@@ -99,8 +99,8 @@ export class SmartNftables {
|
|
|
99
99
|
/**
|
|
100
100
|
* Delete the entire nftables table and clear all tracking.
|
|
101
101
|
*/
|
|
102
|
-
async cleanup() {
|
|
103
|
-
if (this.executor.isRoot() && this.initialized) {
|
|
102
|
+
async cleanup(options = {}) {
|
|
103
|
+
if (this.executor.isRoot() && (this.initialized || options.force)) {
|
|
104
104
|
const commands = buildTableCleanup(this.tableName, this.family);
|
|
105
105
|
await this.executor.execBatch(commands, { continueOnError: true });
|
|
106
106
|
}
|
|
@@ -108,6 +108,22 @@ export class SmartNftables {
|
|
|
108
108
|
this.initialized = false;
|
|
109
109
|
this.hasFilterChains = false;
|
|
110
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Check if the managed nftables table exists in the kernel.
|
|
113
|
+
* Returns false if not root, not initialized, or the table was removed externally.
|
|
114
|
+
*/
|
|
115
|
+
async tableExists() {
|
|
116
|
+
if (!this.executor.isRoot()) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
await this.executor.exec(`nft list table ${this.family} ${this.tableName}`);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
111
127
|
/**
|
|
112
128
|
* Get status report of the managed nftables state.
|
|
113
129
|
*/
|
|
@@ -129,4 +145,4 @@ export class SmartNftables {
|
|
|
129
145
|
};
|
|
130
146
|
}
|
|
131
147
|
}
|
|
132
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
148
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0Lm1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9uZnQubWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDaEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxpQkFBaUIsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ25HLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFHOUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQWN4QixZQUFZLE9BQStCO1FBTG5DLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLG9CQUFlLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLGtCQUFhLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLGVBQVUsR0FBK0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUd6RCxJQUFJLENBQUMsU0FBUyxHQUFHLE9BQU8sRUFBRSxTQUFTLElBQUksZUFBZSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxNQUFNLEdBQUcsT0FBTyxFQUFFLE1BQU0sSUFBSSxJQUFJLENBQUM7UUFDdEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLFdBQVcsQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUU3RCxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hDLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzlDLENBQUM7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
|
|
@@ -62,8 +62,9 @@ export function buildFirewallRule(tableName, family, rule) {
|
|
|
62
62
|
*/
|
|
63
63
|
export function buildIPSetCreate(tableName, family, config) {
|
|
64
64
|
const commands = [];
|
|
65
|
+
const flags = config.interval ? ' flags interval \\;' : '';
|
|
65
66
|
// Create the set
|
|
66
|
-
commands.push(`nft add set ${family} ${tableName} ${config.name} { type ${config.type}
|
|
67
|
+
commands.push(`nft add set ${family} ${tableName} ${config.name} { type ${config.type} \\;${flags} }`);
|
|
67
68
|
// Add initial elements if provided
|
|
68
69
|
if (config.elements && config.elements.length > 0) {
|
|
69
70
|
commands.push(`nft add element ${family} ${tableName} ${config.name} { ${config.elements.join(', ')} }`);
|
|
@@ -102,8 +103,9 @@ export function buildIPSetDelete(tableName, family, setName) {
|
|
|
102
103
|
* Build a rule that matches against a named set.
|
|
103
104
|
*/
|
|
104
105
|
export function buildIPSetMatchRule(tableName, family, options) {
|
|
106
|
+
const comment = options.comment ? ` comment "${options.comment}"` : '';
|
|
105
107
|
return [
|
|
106
|
-
`nft add rule ${family} ${tableName} ${options.direction} ip ${options.matchField} @${options.setName} ${options.action}`
|
|
108
|
+
`nft add rule ${family} ${tableName} ${options.direction} ip ${options.matchField} @${options.setName}${comment} ${options.action}`
|
|
107
109
|
];
|
|
108
110
|
}
|
|
109
111
|
// ─── Internal helpers ─────────────────────────────────────────────
|
|
@@ -116,4 +118,4 @@ function expandProtocols(protocol) {
|
|
|
116
118
|
case 'both': return ['tcp', 'udp'];
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
121
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0LnJ1bGVidWlsZGVyLmZpcmV3YWxsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvbmZ0LnJ1bGVidWlsZGVyLmZpcmV3YWxsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUMvQixTQUFpQixFQUNqQixNQUFrQixFQUNsQixJQUFzQjtJQUV0QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDO0lBQzdCLE1BQU0sS0FBSyxHQUFhLENBQUMsZ0JBQWdCLE1BQU0sSUFBSSxTQUFTLElBQUksS0FBSyxFQUFFLENBQUMsQ0FBQztJQUV6RSw2QkFBNkI7SUFDN0IsSUFBSSxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQzlDLEtBQUssQ0FBQyxJQUFJLENBQUMsY0FBYyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVELDZCQUE2QjtJQUM3QixNQUFNLFNBQVMsR0FBRyxlQUFlLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2pELE1BQU0sUUFBUSxHQUFhLEVBQUUsQ0FBQztJQUU5QixLQUFLLE1BQU0sS0FBSyxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQzlCLE1BQU0sU0FBUyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQztRQUU3QixJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNsQixTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hCLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNsQixTQUFTLENBQUMsSUFBSSxDQUFDLFlBQVksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDOUMsQ0FBQztRQUVELElBQUksSUFB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
|
|
@@ -18,7 +18,8 @@ export function buildDnatRules(tableName, family, rule) {
|
|
|
18
18
|
const commands = [];
|
|
19
19
|
for (const proto of protocols) {
|
|
20
20
|
// DNAT rule
|
|
21
|
-
|
|
21
|
+
const saddrFilter = rule.sourceIP ? `ip saddr ${rule.sourceIP} ` : '';
|
|
22
|
+
commands.push(`nft add rule ${family} ${tableName} prerouting ${saddrFilter}${proto} dport ${rule.sourcePort} dnat to ${rule.targetHost}:${rule.targetPort}`);
|
|
22
23
|
// Masquerade (SNAT) unless preserveSourceIP is set
|
|
23
24
|
if (!rule.preserveSourceIP) {
|
|
24
25
|
commands.push(`nft add rule ${family} ${tableName} postrouting ${proto} dport ${rule.targetPort} masquerade`);
|
|
@@ -48,4 +49,4 @@ export function buildMasqueradeRule(tableName, family, rule) {
|
|
|
48
49
|
}
|
|
49
50
|
return commands;
|
|
50
51
|
}
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
52
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0LnJ1bGVidWlsZGVyLm5hdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL25mdC5ydWxlYnVpbGRlci5uYXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7O0dBRUc7QUFDSCxTQUFTLGVBQWUsQ0FBQyxRQUF1QjtJQUM5QyxRQUFRLFFBQVEsSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUMxQixLQUFLLEtBQUssQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMzQixLQUFLLEtBQUssQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMzQixLQUFLLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDckMsQ0FBQztBQUNILENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FDNUIsU0FBaUIsRUFDakIsTUFBa0IsRUFDbEIsSUFBa0I7SUFFbEIsTUFBTSxTQUFTLEdBQUcsZUFBZSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNqRCxNQUFNLFFBQVEsR0FBYSxFQUFFLENBQUM7SUFFOUIsS0FBSyxNQUFNLEtBQUssSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUM5QixZQUFZO1FBQ1osTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsWUFBWSxJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN0RSxRQUFRLENBQUMsSUFBSSxDQUNYLGdCQUFnQixNQUFNLElBQUksU0FBUyxlQUFlLFdBQVcsR0FBRyxLQUFLLFVBQVUsSUFBSSxDQUFDLFVBQVUsWUFBWSxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FDL0ksQ0FBQztRQUVGLG1EQUFtRDtRQUNuRCxJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDM0IsUUFBUSxDQUFDLElBQUksQ0FDWCxnQkFBZ0IsTUFBTSxJQUFJLFNBQVMsZ0JBQWdCLEtBQUssVUFBVSxJQUFJLENBQUMsVUFBVSxhQUFhLENBQy9GLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sUUFBUSxDQUFDO0FBQ2xCLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSxhQUFhLENBQzNCLFNBQWlCLEVBQ2pCLE1BQWtCLEVBQ2xCLElBQWtCO0lBRWxCLE1BQU0sU0FBUyxHQUFHLGVBQWUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDakQsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO0lBRTlCLEtBQUssTUFBTSxLQUFLLElBQUksU0FBUyxFQUFFLENBQUM7UUFDOUIsUUFBUSxDQUFDLElBQUksQ0FDWCxnQkFBZ0IsTUFBTSxJQUFJLFNBQVMsZ0JBQWdCLEtBQUssVUFBVSxJQUFJLENBQUMsVUFBVSxZQUFZLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FDbEgsQ0FBQztJQUNKLENBQUM7SUFFRCxPQUFPLFFBQVEsQ0FBQztBQUNsQixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsbUJBQW1CLENBQ2pDLFNBQWlCLEVBQ2pCLE1BQWtCLEVBQ2xCLElBQXdCO0lBRXhCLE1BQU0sU0FBUyxHQUFHLGVBQWUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDakQsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO0lBRTlCLEtBQUssTUFBTSxLQUFLLElBQUksU0FBUyxFQUFFLENBQUM7UUFDOUIsUUFBUSxDQUFDLElBQUksQ0FDWCxnQkFBZ0IsTUFBTSxJQUFJLFNBQVMsZ0JBQWdCLEtBQUssVUFBVSxJQUFJLENBQUMsVUFBVSxhQUFhLENBQy9GLENBQUM7SUFDSixDQUFDO0lBRUQsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQyJ9
|
package/dist_ts/nft.types.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export interface INftDnatRule {
|
|
|
11
11
|
targetPort: number;
|
|
12
12
|
protocol?: TNftProtocol;
|
|
13
13
|
preserveSourceIP?: boolean;
|
|
14
|
+
/** Filter by source IP/subnet (e.g. '10.8.0.0/24'). Only matching traffic gets DNAT'd. */
|
|
15
|
+
sourceIP?: string;
|
|
14
16
|
}
|
|
15
17
|
export interface INftSnatRule {
|
|
16
18
|
sourceAddress: string;
|
|
@@ -60,8 +62,26 @@ export interface INftIPSetConfig {
|
|
|
60
62
|
name: string;
|
|
61
63
|
type: 'ipv4_addr' | 'ipv6_addr' | 'inet_service';
|
|
62
64
|
elements?: string[];
|
|
65
|
+
/** Enable interval sets so CIDR/range elements can be stored. */
|
|
66
|
+
interval?: boolean;
|
|
67
|
+
comment?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface INftIPSetBlockOptions {
|
|
70
|
+
/** Name of the nftables set to create and match against. */
|
|
71
|
+
setName?: string;
|
|
72
|
+
/** IPs or CIDR ranges to add to the set. */
|
|
73
|
+
ips: string[];
|
|
74
|
+
/** Chain to apply the block rule to. Default: input. */
|
|
75
|
+
direction?: 'input' | 'forward';
|
|
76
|
+
/** Set type. Defaults to ipv4_addr for the default ip family. */
|
|
77
|
+
type?: 'ipv4_addr' | 'ipv6_addr';
|
|
78
|
+
/** Optional rule comment. */
|
|
63
79
|
comment?: string;
|
|
64
80
|
}
|
|
81
|
+
export interface INftCleanupOptions {
|
|
82
|
+
/** Delete the table even when this process did not initialize it. */
|
|
83
|
+
force?: boolean;
|
|
84
|
+
}
|
|
65
85
|
export interface INftRuleGroup {
|
|
66
86
|
id: string;
|
|
67
87
|
commands: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartnftables",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A TypeScript module for managing nftables rules including NAT, firewall, and rate limiting with a high-level API.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SmartNftables } from './nft.manager.js';
|
|
2
|
-
import type { INftFirewallRule, INftIPSetConfig } from './nft.types.js';
|
|
2
|
+
import type { INftFirewallRule, INftIPSetBlockOptions, INftIPSetConfig } from './nft.types.js';
|
|
3
3
|
import {
|
|
4
4
|
buildFirewallRule,
|
|
5
5
|
buildIPSetCreate,
|
|
@@ -82,6 +82,41 @@ export class FirewallManager {
|
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Convenience: block many IPs or CIDR subnets using one nftables set and
|
|
87
|
+
* one matching drop rule. This is substantially cheaper than one rule per IP.
|
|
88
|
+
*/
|
|
89
|
+
public async blockIPSet(groupId: string, options: INftIPSetBlockOptions): Promise<void> {
|
|
90
|
+
const ips = [...new Set(options.ips)].filter(Boolean).sort();
|
|
91
|
+
if (ips.length === 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await this.parent.ensureFilterChains();
|
|
96
|
+
|
|
97
|
+
const setName = options.setName ?? `${groupId.replace(/[^a-zA-Z0-9_]/g, '_')}_set`;
|
|
98
|
+
const setType = options.type ?? (this.parent.family === 'ip6' ? 'ipv6_addr' : 'ipv4_addr');
|
|
99
|
+
const needsIntervalSet = ips.some((ip) => ip.includes('/'));
|
|
100
|
+
const direction = options.direction ?? 'input';
|
|
101
|
+
const commands = [
|
|
102
|
+
...buildIPSetCreate(this.parent.tableName, this.parent.family, {
|
|
103
|
+
name: setName,
|
|
104
|
+
type: setType,
|
|
105
|
+
elements: ips,
|
|
106
|
+
interval: needsIntervalSet,
|
|
107
|
+
}),
|
|
108
|
+
...buildIPSetMatchRule(this.parent.tableName, this.parent.family, {
|
|
109
|
+
setName,
|
|
110
|
+
direction,
|
|
111
|
+
matchField: 'saddr',
|
|
112
|
+
action: 'drop',
|
|
113
|
+
comment: options.comment,
|
|
114
|
+
}),
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
await this.parent.applyRuleGroup(`fw:blockset:${groupId}`, commands);
|
|
118
|
+
}
|
|
119
|
+
|
|
85
120
|
/**
|
|
86
121
|
* Convenience: allow only specific IPs on a port.
|
|
87
122
|
* Adds accept rules for each IP, then a drop rule for everything else on that port.
|
package/ts/nft.manager.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { buildTableSetup, buildFilterChains, buildTableCleanup } from './nft.rul
|
|
|
3
3
|
import { NatManager } from './nft.manager.nat.js';
|
|
4
4
|
import { FirewallManager } from './nft.manager.firewall.js';
|
|
5
5
|
import { RateLimitManager } from './nft.manager.ratelimit.js';
|
|
6
|
-
import type { TNftFamily, INftRuleGroup, INftStatus, ISmartNftablesOptions } from './nft.types.js';
|
|
6
|
+
import type { TNftFamily, INftCleanupOptions, INftRuleGroup, INftStatus, ISmartNftablesOptions } from './nft.types.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* SmartNftables — high-level facade for managing nftables rules.
|
|
@@ -122,8 +122,8 @@ export class SmartNftables {
|
|
|
122
122
|
/**
|
|
123
123
|
* Delete the entire nftables table and clear all tracking.
|
|
124
124
|
*/
|
|
125
|
-
public async cleanup(): Promise<void> {
|
|
126
|
-
if (this.executor.isRoot() && this.initialized) {
|
|
125
|
+
public async cleanup(options: INftCleanupOptions = {}): Promise<void> {
|
|
126
|
+
if (this.executor.isRoot() && (this.initialized || options.force)) {
|
|
127
127
|
const commands = buildTableCleanup(this.tableName, this.family);
|
|
128
128
|
await this.executor.execBatch(commands, { continueOnError: true });
|
|
129
129
|
}
|
|
@@ -133,6 +133,22 @@ export class SmartNftables {
|
|
|
133
133
|
this.hasFilterChains = false;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Check if the managed nftables table exists in the kernel.
|
|
138
|
+
* Returns false if not root, not initialized, or the table was removed externally.
|
|
139
|
+
*/
|
|
140
|
+
public async tableExists(): Promise<boolean> {
|
|
141
|
+
if (!this.executor.isRoot()) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
await this.executor.exec(`nft list table ${this.family} ${this.tableName}`);
|
|
146
|
+
return true;
|
|
147
|
+
} catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
136
152
|
/**
|
|
137
153
|
* Get status report of the managed nftables state.
|
|
138
154
|
*/
|
|
@@ -84,10 +84,11 @@ export function buildIPSetCreate(
|
|
|
84
84
|
config: INftIPSetConfig,
|
|
85
85
|
): string[] {
|
|
86
86
|
const commands: string[] = [];
|
|
87
|
+
const flags = config.interval ? ' flags interval \\;' : '';
|
|
87
88
|
|
|
88
89
|
// Create the set
|
|
89
90
|
commands.push(
|
|
90
|
-
`nft add set ${family} ${tableName} ${config.name} { type ${config.type}
|
|
91
|
+
`nft add set ${family} ${tableName} ${config.name} { type ${config.type} \\;${flags} }`
|
|
91
92
|
);
|
|
92
93
|
|
|
93
94
|
// Add initial elements if provided
|
|
@@ -154,10 +155,12 @@ export function buildIPSetMatchRule(
|
|
|
154
155
|
direction: 'input' | 'output' | 'forward';
|
|
155
156
|
matchField: 'saddr' | 'daddr';
|
|
156
157
|
action: 'accept' | 'drop' | 'reject';
|
|
158
|
+
comment?: string;
|
|
157
159
|
},
|
|
158
160
|
): string[] {
|
|
161
|
+
const comment = options.comment ? ` comment "${options.comment}"` : '';
|
|
159
162
|
return [
|
|
160
|
-
`nft add rule ${family} ${tableName} ${options.direction} ip ${options.matchField} @${options.setName} ${options.action}`
|
|
163
|
+
`nft add rule ${family} ${tableName} ${options.direction} ip ${options.matchField} @${options.setName}${comment} ${options.action}`
|
|
161
164
|
];
|
|
162
165
|
}
|
|
163
166
|
|
|
@@ -26,8 +26,9 @@ export function buildDnatRules(
|
|
|
26
26
|
|
|
27
27
|
for (const proto of protocols) {
|
|
28
28
|
// DNAT rule
|
|
29
|
+
const saddrFilter = rule.sourceIP ? `ip saddr ${rule.sourceIP} ` : '';
|
|
29
30
|
commands.push(
|
|
30
|
-
`nft add rule ${family} ${tableName} prerouting ${proto} dport ${rule.sourcePort} dnat to ${rule.targetHost}:${rule.targetPort}`
|
|
31
|
+
`nft add rule ${family} ${tableName} prerouting ${saddrFilter}${proto} dport ${rule.sourcePort} dnat to ${rule.targetHost}:${rule.targetPort}`
|
|
31
32
|
);
|
|
32
33
|
|
|
33
34
|
// Masquerade (SNAT) unless preserveSourceIP is set
|
package/ts/nft.types.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface INftDnatRule {
|
|
|
14
14
|
targetPort: number;
|
|
15
15
|
protocol?: TNftProtocol;
|
|
16
16
|
preserveSourceIP?: boolean;
|
|
17
|
+
/** Filter by source IP/subnet (e.g. '10.8.0.0/24'). Only matching traffic gets DNAT'd. */
|
|
18
|
+
sourceIP?: string;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export interface INftSnatRule {
|
|
@@ -71,9 +73,29 @@ export interface INftIPSetConfig {
|
|
|
71
73
|
name: string;
|
|
72
74
|
type: 'ipv4_addr' | 'ipv6_addr' | 'inet_service';
|
|
73
75
|
elements?: string[];
|
|
76
|
+
/** Enable interval sets so CIDR/range elements can be stored. */
|
|
77
|
+
interval?: boolean;
|
|
78
|
+
comment?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface INftIPSetBlockOptions {
|
|
82
|
+
/** Name of the nftables set to create and match against. */
|
|
83
|
+
setName?: string;
|
|
84
|
+
/** IPs or CIDR ranges to add to the set. */
|
|
85
|
+
ips: string[];
|
|
86
|
+
/** Chain to apply the block rule to. Default: input. */
|
|
87
|
+
direction?: 'input' | 'forward';
|
|
88
|
+
/** Set type. Defaults to ipv4_addr for the default ip family. */
|
|
89
|
+
type?: 'ipv4_addr' | 'ipv6_addr';
|
|
90
|
+
/** Optional rule comment. */
|
|
74
91
|
comment?: string;
|
|
75
92
|
}
|
|
76
93
|
|
|
94
|
+
export interface INftCleanupOptions {
|
|
95
|
+
/** Delete the table even when this process did not initialize it. */
|
|
96
|
+
force?: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
77
99
|
// ─── Rule Group (tracking unit) ───────────────────────────────────
|
|
78
100
|
export interface INftRuleGroup {
|
|
79
101
|
id: string;
|