@push.rocks/smartnftables 1.2.0 → 1.3.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 +38 -1
- package/dist_rust/smartnftables_linux_amd64_musl +0 -0
- package/dist_rust/smartnftables_linux_amd64_musl.tsrust-build.json +14 -0
- package/dist_rust/smartnftables_linux_arm64_musl +0 -0
- package/dist_rust/smartnftables_linux_arm64_musl.tsrust-build.json +14 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.managednftables.d.ts +21 -0
- package/dist_ts/classes.managednftables.js +176 -0
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/managed.types.d.ts +99 -0
- package/dist_ts/managed.types.js +2 -0
- package/dist_ts/nft.executor.d.ts +1 -0
- package/dist_ts/nft.executor.js +66 -4
- package/dist_ts/nft.rulebuilder.firewall.js +16 -31
- package/dist_ts/plugins.d.ts +5 -2
- package/dist_ts/plugins.js +6 -3
- package/native-notices/crates/block-buffer-0.10.4/license-apache +201 -0
- package/native-notices/crates/block-buffer-0.10.4/license-mit +25 -0
- package/native-notices/crates/cfg-if-1.0.4/license-apache +201 -0
- package/native-notices/crates/cfg-if-1.0.4/license-mit +25 -0
- package/native-notices/crates/cpufeatures-0.2.17/license-apache +201 -0
- package/native-notices/crates/cpufeatures-0.2.17/license-mit +25 -0
- package/native-notices/crates/crypto-common-0.1.7/license-apache +201 -0
- package/native-notices/crates/crypto-common-0.1.7/license-mit +25 -0
- package/native-notices/crates/digest-0.10.7/license-apache +201 -0
- package/native-notices/crates/digest-0.10.7/license-mit +25 -0
- package/native-notices/crates/generic-array-0.14.7/license +21 -0
- package/native-notices/crates/itoa-1.0.18/license-apache +176 -0
- package/native-notices/crates/itoa-1.0.18/license-mit +23 -0
- package/native-notices/crates/libc-0.2.189/license-apache +176 -0
- package/native-notices/crates/libc-0.2.189/license-mit +25 -0
- package/native-notices/crates/memchr-2.8.3/copying +3 -0
- package/native-notices/crates/memchr-2.8.3/license-mit +21 -0
- package/native-notices/crates/proc-macro2-1.0.107/license-apache +176 -0
- package/native-notices/crates/proc-macro2-1.0.107/license-mit +23 -0
- package/native-notices/crates/quote-1.0.47/license-apache +176 -0
- package/native-notices/crates/quote-1.0.47/license-mit +23 -0
- package/native-notices/crates/serde-1.0.229/license-apache +176 -0
- package/native-notices/crates/serde-1.0.229/license-mit +23 -0
- package/native-notices/crates/serde_core-1.0.229/license-apache +176 -0
- package/native-notices/crates/serde_core-1.0.229/license-mit +23 -0
- package/native-notices/crates/serde_derive-1.0.229/license-apache +176 -0
- package/native-notices/crates/serde_derive-1.0.229/license-mit +23 -0
- package/native-notices/crates/serde_json-1.0.151/license-apache +176 -0
- package/native-notices/crates/serde_json-1.0.151/license-mit +23 -0
- package/native-notices/crates/sha2-0.10.9/license-apache +201 -0
- package/native-notices/crates/sha2-0.10.9/license-mit +27 -0
- package/native-notices/crates/syn-3.0.5/license-apache +176 -0
- package/native-notices/crates/syn-3.0.5/license-mit +23 -0
- package/native-notices/crates/typenum-1.20.1/license +1 -0
- package/native-notices/crates/typenum-1.20.1/license-apache +201 -0
- package/native-notices/crates/typenum-1.20.1/license-mit +21 -0
- package/native-notices/crates/unicode-ident-1.0.24/license-apache +176 -0
- package/native-notices/crates/unicode-ident-1.0.24/license-mit +23 -0
- package/native-notices/crates/unicode-ident-1.0.24/license-unicode +39 -0
- package/native-notices/crates/version_check-0.9.5/license-apache +201 -0
- package/native-notices/crates/version_check-0.9.5/license-mit +19 -0
- package/native-notices/crates/zmij-1.0.23/license-mit +23 -0
- package/native-notices/manifest.json +520 -0
- package/native-notices/readme.md +36 -0
- package/native-notices/rust-standard-library/addr2line-0.25.1-license-apache +201 -0
- package/native-notices/rust-standard-library/addr2line-0.25.1-license-mit +25 -0
- package/native-notices/rust-standard-library/cargo.lock +522 -0
- package/native-notices/rust-standard-library/compiler-builtins-license.txt +275 -0
- package/native-notices/rust-standard-library/dependency-notices.html +9072 -0
- package/native-notices/rust-standard-library/license-apache +176 -0
- package/native-notices/rust-standard-library/license-mit +25 -0
- package/native-notices/rust-standard-library/llvm-libunwind-license.txt +311 -0
- package/native-notices/rust-standard-library/musl-1.2.5-copyright.txt +193 -0
- package/native-notices/rust-standard-library/unicode-license.txt +39 -0
- package/package.json +32 -16
- package/readme.md +140 -3
- package/rust/.cargo/config.toml +2 -0
- package/rust/Cargo.lock +192 -0
- package/rust/Cargo.toml +13 -0
- package/rust/src/main.rs +141 -0
- package/rust/src/owner.rs +604 -0
- package/rust/src/owner_tests.rs +795 -0
- package/rust/src/policy.rs +427 -0
- package/rust/src/tests.rs +97 -0
- package/rust/src/wire.rs +437 -0
- package/scripts/check-native-notices.mjs +27 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.managednftables.ts +148 -0
- package/ts/index.ts +2 -0
- package/ts/managed.types.ts +87 -0
- package/ts/nft.executor.ts +71 -4
- package/ts/nft.rulebuilder.firewall.ts +16 -31
- package/ts/plugins.ts +6 -0
- /package/{license → license.md} +0 -0
package/changelog.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-09-09 - 1.3.1
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- rename managed policy hints document (docs)
|
|
8
|
+
- Moves managed policy implementation guidance from readme.hints.md to hints.md without content changes.
|
|
9
|
+
|
|
10
|
+
## 2026-09-09 - 1.3.0
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- add native managed nftables policy engine (managednftables)
|
|
15
|
+
- Export ManagedNftables, ManagedNftablesError, and managed policy types from the TypeScript entrypoint.
|
|
16
|
+
- Implement a Rust management binary for policy preparation, reconciliation, inspection, release, and cleanup.
|
|
17
|
+
- Bridge the TypeScript manager to the native binary with bounded IPC payloads and serialized request admission.
|
|
18
|
+
- Add Node and isolated native qualification tests for managed policy behavior.
|
|
19
|
+
- Integrate Rust targets into the build and published package contents.
|
|
20
|
+
|
|
21
|
+
### Fixes
|
|
22
|
+
|
|
23
|
+
- update package publishing configuration and toolchain versions (package)
|
|
24
|
+
- Add publish metadata for native executable artifacts
|
|
25
|
+
- Update release preflight configuration and development tool versions
|
|
26
|
+
- Clarify close and release cleanup semantics in documentation
|
|
27
|
+
- bump @git.zone/tstest to 5.0.0 (dev-deps)
|
|
28
|
+
- Updates the @git.zone/tstest dev dependency from 4.1.1 to 5.0.0.
|
|
29
|
+
|
|
30
|
+
## 2026-07-31 - 1.2.1
|
|
31
|
+
|
|
32
|
+
### Fixes
|
|
33
|
+
|
|
34
|
+
- normalize command execution and firewall rule generation (nft)
|
|
35
|
+
- Preserve quoted values and escaped semicolons when executing nft commands.
|
|
36
|
+
- Default port-only firewall rules to TCP and use meta l4proto for protocol-only rules.
|
|
37
|
+
- Escape rule comments so generated nft commands remain parseable.
|
|
38
|
+
- Update tests, documentation, release configuration, and package tooling dependencies.
|
|
39
|
+
|
|
3
40
|
## 2026-04-26 - 1.2.0 - feat(firewall)
|
|
4
41
|
add IP set blocking convenience API with CIDR interval support and optional rule comments
|
|
5
42
|
|
|
@@ -22,4 +59,4 @@ no changes to commit
|
|
|
22
59
|
## 2026-03-26 - 1.0.0 - project
|
|
23
60
|
Initial release.
|
|
24
61
|
|
|
25
|
-
- Project initialized with first commit.
|
|
62
|
+
- Project initialized with first commit.
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": "tsrust.build-provenance.v2",
|
|
3
|
+
"binarySha256": "ca5b8c77de7f91f0027f95f1a83e54a3b41af724ca7e0e2f49f422538c628687",
|
|
4
|
+
"buildInfo": {
|
|
5
|
+
"projectName": "@push.rocks/smartnftables",
|
|
6
|
+
"projectVersion": "1.3.1",
|
|
7
|
+
"gitCommit": "454e4d4c44300f5ca67c3afd9d4507040ed674be",
|
|
8
|
+
"gitDirty": false,
|
|
9
|
+
"builtAt": "2026-09-09T13:04:41.744Z",
|
|
10
|
+
"tsrustVersion": "1.13.0",
|
|
11
|
+
"binary": "smartnftables",
|
|
12
|
+
"target": "linux_amd64_musl"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": "tsrust.build-provenance.v2",
|
|
3
|
+
"binarySha256": "65913ced75089fa08d77913b22aa13f8ad2804d1e742aeca749ff23a6aeca4d7",
|
|
4
|
+
"buildInfo": {
|
|
5
|
+
"projectName": "@push.rocks/smartnftables",
|
|
6
|
+
"projectVersion": "1.3.1",
|
|
7
|
+
"gitCommit": "454e4d4c44300f5ca67c3afd9d4507040ed674be",
|
|
8
|
+
"gitDirty": false,
|
|
9
|
+
"builtAt": "2026-09-09T13:04:41.873Z",
|
|
10
|
+
"tsrustVersion": "1.13.0",
|
|
11
|
+
"binary": "smartnftables",
|
|
12
|
+
"target": "linux_arm64_musl"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartnftables',
|
|
6
|
-
version: '1.
|
|
6
|
+
version: '1.3.1',
|
|
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=
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { IManagedNftOptions, IManagedNftPolicy, IManagedNftTransition, IAppliedManagedNftPolicy, IPreparedManagedNftPolicy, IManagedNftStatus } from './managed.types.js';
|
|
2
|
+
export declare class ManagedNftablesError extends Error {
|
|
3
|
+
readonly code: string;
|
|
4
|
+
constructor(code: string);
|
|
5
|
+
}
|
|
6
|
+
/** One private native/netlink owner. Persistence and workload link lifetimes belong to its caller. */
|
|
7
|
+
export declare class ManagedNftables {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(options: IManagedNftOptions);
|
|
10
|
+
get state(): string;
|
|
11
|
+
/** Starts only the compiler/IPC owner. The returned idle status is not enforcement. */
|
|
12
|
+
start(): Promise<IManagedNftStatus>;
|
|
13
|
+
prepare(policy: IManagedNftPolicy): Promise<IPreparedManagedNftPolicy>;
|
|
14
|
+
reconcile(transition: IManagedNftTransition): Promise<IAppliedManagedNftPolicy>;
|
|
15
|
+
inspect(): Promise<IManagedNftStatus>;
|
|
16
|
+
release(expected: IAppliedManagedNftPolicy): Promise<{
|
|
17
|
+
released: true;
|
|
18
|
+
}>;
|
|
19
|
+
/** Join policy operations and owned-table deletion, then native termination; packet/allocation fencing belongs to the caller. */
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
export class ManagedNftablesError extends Error {
|
|
3
|
+
constructor(code) {
|
|
4
|
+
super(`Managed nftables ${code}.`);
|
|
5
|
+
this.code = code;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Capture inert input without evaluating getters, proxies, coercions or toJSON. */
|
|
9
|
+
function snapshot(input) {
|
|
10
|
+
let count = 0;
|
|
11
|
+
let stringBytes = 0;
|
|
12
|
+
const string = (value) => {
|
|
13
|
+
if (value.length > 240_000 || (stringBytes += Buffer.byteLength(value)) > 240_000)
|
|
14
|
+
throw new ManagedNftablesError('INVALID');
|
|
15
|
+
return value;
|
|
16
|
+
};
|
|
17
|
+
const copy = (value, depth) => {
|
|
18
|
+
if (++count > 16_384 || depth > 20)
|
|
19
|
+
throw new ManagedNftablesError('INVALID');
|
|
20
|
+
if (typeof value === 'string')
|
|
21
|
+
return string(value);
|
|
22
|
+
if (value === null || typeof value === 'boolean')
|
|
23
|
+
return value;
|
|
24
|
+
if (typeof value === 'number' && Number.isSafeInteger(value))
|
|
25
|
+
return value;
|
|
26
|
+
if (typeof value !== 'object' || plugins.util.types.isProxy(value))
|
|
27
|
+
throw new ManagedNftablesError('INVALID');
|
|
28
|
+
const array = Array.isArray(value);
|
|
29
|
+
if (Object.getPrototypeOf(value) !== (array ? Array.prototype : Object.prototype))
|
|
30
|
+
throw new ManagedNftablesError('INVALID');
|
|
31
|
+
const keys = Reflect.ownKeys(value);
|
|
32
|
+
if (keys.length > 16_384 - count)
|
|
33
|
+
throw new ManagedNftablesError('INVALID');
|
|
34
|
+
for (const key of keys)
|
|
35
|
+
if (typeof key === 'string')
|
|
36
|
+
string(key);
|
|
37
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
38
|
+
const result = array ? [] : {};
|
|
39
|
+
if (array && keys.length !== value.length + 1)
|
|
40
|
+
throw new ManagedNftablesError('INVALID');
|
|
41
|
+
for (const key of keys) {
|
|
42
|
+
if (array && key === 'length')
|
|
43
|
+
continue;
|
|
44
|
+
const descriptor = descriptors[key];
|
|
45
|
+
if (typeof key !== 'string' || !descriptor.enumerable || !('value' in descriptor)
|
|
46
|
+
|| array && !/^(0|[1-9][0-9]*)$/.test(key))
|
|
47
|
+
throw new ManagedNftablesError('INVALID');
|
|
48
|
+
Object.defineProperty(result, key, { value: copy(descriptor.value, depth + 1), enumerable: true, configurable: true, writable: true });
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
const result = copy(input, 0);
|
|
53
|
+
if (Buffer.byteLength(JSON.stringify(result)) > 240_000)
|
|
54
|
+
throw new ManagedNftablesError('INVALID');
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
/** One private native/netlink owner. Persistence and workload link lifetimes belong to its caller. */
|
|
58
|
+
export class ManagedNftables {
|
|
59
|
+
#options;
|
|
60
|
+
#bridge = null;
|
|
61
|
+
#state = 'new';
|
|
62
|
+
#work = null;
|
|
63
|
+
#close = null;
|
|
64
|
+
#nativeMayOwn = false;
|
|
65
|
+
constructor(options) {
|
|
66
|
+
this.#options = snapshot(options);
|
|
67
|
+
if (Object.keys(this.#options).some((key) => !['ownerId', 'instanceId', 'tableName', 'binaryPath'].includes(key))
|
|
68
|
+
|| ![this.#options.ownerId, this.#options.instanceId, this.#options.tableName].every((value) => typeof value === 'string' && /^[A-Za-z0-9_-]{1,64}$/.test(value))
|
|
69
|
+
|| this.#options.instanceId.length < 16 || !this.#options.tableName.startsWith('snft_')
|
|
70
|
+
|| this.#options.binaryPath !== undefined && (!plugins.path.isAbsolute(this.#options.binaryPath) || this.#options.binaryPath.includes('\0'))) {
|
|
71
|
+
throw new ManagedNftablesError('INVALID');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
get state() { return this.#state; }
|
|
75
|
+
/** Starts only the compiler/IPC owner. The returned idle status is not enforcement. */
|
|
76
|
+
start() {
|
|
77
|
+
if (this.#state !== 'new')
|
|
78
|
+
return Promise.reject(new ManagedNftablesError('UNAVAILABLE'));
|
|
79
|
+
this.#state = 'starting';
|
|
80
|
+
const work = (async () => {
|
|
81
|
+
if (process.platform !== 'linux' || !['x64', 'arm64'].includes(process.arch))
|
|
82
|
+
throw new ManagedNftablesError('UNSUPPORTED_PLATFORM');
|
|
83
|
+
const root = plugins.url.fileURLToPath(new URL('../', import.meta.url));
|
|
84
|
+
this.#bridge = new plugins.smartrust.RustBridge({
|
|
85
|
+
binaryName: 'smartnftables', binaryPath: this.#options.binaryPath
|
|
86
|
+
?? plugins.path.join(root, 'dist_rust', `smartnftables_linux_${process.arch === 'x64' ? 'amd64' : 'arm64'}_musl`),
|
|
87
|
+
localPaths: [], searchSystemPath: false, cliArgs: ['--management'],
|
|
88
|
+
readyTimeoutMs: 3000, requestTimeoutMs: 30_000, maxPayloadSize: 262_144,
|
|
89
|
+
maxPendingRequestsByMethod: { preparePolicy: 1, openOwner: 1, reconcilePolicy: 1, inspectPolicy: 1, releasePolicy: 1, closeOwner: 1 },
|
|
90
|
+
});
|
|
91
|
+
this.#bridge.on('exit', () => {
|
|
92
|
+
if (!['closing', 'stopped'].includes(this.#state))
|
|
93
|
+
this.#state = 'failed-owned';
|
|
94
|
+
});
|
|
95
|
+
if (!await this.#bridge.spawn())
|
|
96
|
+
throw new ManagedNftablesError('UNAVAILABLE');
|
|
97
|
+
const { ownerId, instanceId, tableName } = this.#options;
|
|
98
|
+
const status = snapshot(await this.#bridge.sendCommand('openOwner', { ownerId, instanceId, tableName }));
|
|
99
|
+
if (this.#state !== 'starting')
|
|
100
|
+
throw new ManagedNftablesError('UNAVAILABLE');
|
|
101
|
+
this.#state = 'ready';
|
|
102
|
+
return status;
|
|
103
|
+
})();
|
|
104
|
+
return this.#track(work);
|
|
105
|
+
}
|
|
106
|
+
prepare(policy) {
|
|
107
|
+
return this.#invoke('preparePolicy', policy);
|
|
108
|
+
}
|
|
109
|
+
reconcile(transition) {
|
|
110
|
+
return this.#invoke('reconcilePolicy', transition);
|
|
111
|
+
}
|
|
112
|
+
inspect() { return this.#invoke('inspectPolicy', {}); }
|
|
113
|
+
release(expected) {
|
|
114
|
+
return this.#invoke('releasePolicy', expected);
|
|
115
|
+
}
|
|
116
|
+
/** Join policy operations and owned-table deletion, then native termination; packet/allocation fencing belongs to the caller. */
|
|
117
|
+
close() {
|
|
118
|
+
if (this.#close)
|
|
119
|
+
return this.#close;
|
|
120
|
+
if (this.#state === 'stopped')
|
|
121
|
+
return Promise.resolve();
|
|
122
|
+
this.#state = 'closing';
|
|
123
|
+
this.#close = (async () => {
|
|
124
|
+
await this.#work?.catch(() => undefined);
|
|
125
|
+
if (this.#bridge) {
|
|
126
|
+
if (this.#nativeMayOwn) {
|
|
127
|
+
const result = await this.#bridge.sendCommand('closeOwner', {});
|
|
128
|
+
if (result.released !== true)
|
|
129
|
+
throw new ManagedNftablesError('PROTOCOL');
|
|
130
|
+
}
|
|
131
|
+
await this.#bridge.terminate({ gracePeriodMs: 1000 });
|
|
132
|
+
}
|
|
133
|
+
this.#bridge = null;
|
|
134
|
+
this.#state = 'stopped';
|
|
135
|
+
})().catch(() => {
|
|
136
|
+
this.#state = 'failed-owned';
|
|
137
|
+
this.#close = null;
|
|
138
|
+
throw new ManagedNftablesError('CLEANUP_UNCONFIRMED');
|
|
139
|
+
});
|
|
140
|
+
return this.#close;
|
|
141
|
+
}
|
|
142
|
+
#invoke(method, params) {
|
|
143
|
+
if (!['ready', 'failed-owned'].includes(this.#state) || !this.#bridge || this.#work)
|
|
144
|
+
return Promise.reject(new ManagedNftablesError('UNAVAILABLE'));
|
|
145
|
+
let captured;
|
|
146
|
+
try {
|
|
147
|
+
captured = snapshot(params);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return Promise.reject(new ManagedNftablesError('INVALID'));
|
|
151
|
+
}
|
|
152
|
+
if (method === 'reconcilePolicy' || method === 'releasePolicy')
|
|
153
|
+
this.#nativeMayOwn = true;
|
|
154
|
+
return this.#track(this.#bridge.sendCommand(method, captured).then((result) => {
|
|
155
|
+
const capturedResult = snapshot(result);
|
|
156
|
+
if (method === 'releasePolicy')
|
|
157
|
+
this.#nativeMayOwn = false;
|
|
158
|
+
if (this.#state !== 'closing' && (method === 'reconcilePolicy' || method === 'releasePolicy'
|
|
159
|
+
|| method === 'inspectPolicy' && capturedResult.error === null))
|
|
160
|
+
this.#state = 'ready';
|
|
161
|
+
return capturedResult;
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
#track(work) {
|
|
165
|
+
const owned = work.catch((error) => {
|
|
166
|
+
if (this.#state !== 'closing')
|
|
167
|
+
this.#state = 'failed-owned';
|
|
168
|
+
const code = error instanceof plugins.smartrust.RustBridgeRequestError ? error.responseErrorCode : undefined;
|
|
169
|
+
throw new ManagedNftablesError(typeof code === 'string' && /^[A-Z_]{1,64}$/.test(code) ? code : 'UNAVAILABLE');
|
|
170
|
+
});
|
|
171
|
+
this.#work = owned;
|
|
172
|
+
void owned.then(() => { this.#work = null; }, () => { this.#work = null; });
|
|
173
|
+
return owned;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tYW5hZ2VkbmZ0YWJsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm1hbmFnZWRuZnRhYmxlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUl4QyxNQUFNLE9BQU8sb0JBQXFCLFNBQVEsS0FBSztJQUM3QyxZQUE0QixJQUFZO1FBQUksS0FBSyxDQUFDLG9CQUFvQixJQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQW5ELFNBQUksR0FBSixJQUFJLENBQVE7SUFBd0MsQ0FBQztDQUNsRjtBQUVELG9GQUFvRjtBQUNwRixTQUFTLFFBQVEsQ0FBSSxLQUFRO0lBQzNCLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNkLElBQUksV0FBVyxHQUFHLENBQUMsQ0FBQztJQUNwQixNQUFNLE1BQU0sR0FBRyxDQUFDLEtBQWEsRUFBVSxFQUFFO1FBQ3ZDLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxPQUFPLElBQUksQ0FBQyxXQUFXLElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLE9BQU87WUFBRSxNQUFNLElBQUksb0JBQW9CLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDN0gsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDLENBQUM7SUFDRixNQUFNLElBQUksR0FBRyxDQUFDLEtBQWMsRUFBRSxLQUFhLEVBQVcsRUFBRTtRQUN0RCxJQUFJLEVBQUUsS0FBSyxHQUFHLE1BQU0sSUFBSSxLQUFLLEdBQUcsRUFBRTtZQUFFLE1BQU0sSUFBSSxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM5RSxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVE7WUFBRSxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNwRCxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksT0FBTyxLQUFLLEtBQUssU0FBUztZQUFFLE9BQU8sS0FBSyxD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
|
package/dist_ts/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { SmartNftables } from './nft.manager.js';
|
|
2
|
+
export { ManagedNftables, ManagedNftablesError } from './classes.managednftables.js';
|
|
3
|
+
export type * from './managed.types.js';
|
|
2
4
|
export { NatManager } from './nft.manager.nat.js';
|
|
3
5
|
export { FirewallManager } from './nft.manager.firewall.js';
|
|
4
6
|
export { RateLimitManager } from './nft.manager.ratelimit.js';
|
package/dist_ts/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Main facade
|
|
2
2
|
export { SmartNftables } from './nft.manager.js';
|
|
3
|
+
export { ManagedNftables, ManagedNftablesError } from './classes.managednftables.js';
|
|
3
4
|
// Sub-managers
|
|
4
5
|
export { NatManager } from './nft.manager.nat.js';
|
|
5
6
|
export { FirewallManager } from './nft.manager.firewall.js';
|
|
@@ -11,4 +12,4 @@ export { buildTableSetup, buildFilterChains, buildTableCleanup, } from './nft.ru
|
|
|
11
12
|
export { buildDnatRules, buildSnatRule, buildMasqueradeRule, } from './nft.rulebuilder.nat.js';
|
|
12
13
|
export { buildRateLimitRule, buildPerIpRateLimitRule, buildConnectionRateRule, } from './nft.rulebuilder.ratelimit.js';
|
|
13
14
|
export { buildFirewallRule, buildIPSetCreate, buildIPSetAddElements, buildIPSetRemoveElements, buildIPSetDelete, buildIPSetMatchRule, } from './nft.rulebuilder.firewall.js';
|
|
14
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
15
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjO0FBQ2QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxlQUFlLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUdyRixlQUFlO0FBQ2YsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUU5RCxXQUFXO0FBQ1gsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFbEYscUNBQXFDO0FBQ3JDLE9BQU8sRUFDTCxlQUFlLEVBQ2YsaUJBQWlCLEVBQ2pCLGlCQUFpQixHQUNsQixNQUFNLDRCQUE0QixDQUFDO0FBRXBDLE9BQU8sRUFDTCxjQUFjLEVBQ2QsYUFBYSxFQUNiLG1CQUFtQixHQUNwQixNQUFNLDBCQUEwQixDQUFDO0FBRWxDLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsdUJBQXVCLEVBQ3ZCLHVCQUF1QixHQUN4QixNQUFNLGdDQUFnQyxDQUFDO0FBRXhDLE9BQU8sRUFDTCxpQkFBaUIsRUFDakIsZ0JBQWdCLEVBQ2hCLHFCQUFxQixFQUNyQix3QkFBd0IsRUFDeEIsZ0JBQWdCLEVBQ2hCLG1CQUFtQixHQUNwQixNQUFNLCtCQUErQixDQUFDIn0=
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** The caller owns these workload links and keeps them disabled until apply is confirmed. */
|
|
2
|
+
export interface IManagedNftEndpoint {
|
|
3
|
+
id: string;
|
|
4
|
+
interfaceIndex: number;
|
|
5
|
+
interfaceName: string;
|
|
6
|
+
/** Routed, unbridged veth or L3 TUN; TAP/bridge/uplink interfaces reject. */
|
|
7
|
+
interfaceKind: 'veth' | 'tun';
|
|
8
|
+
sourcePrefixes: string[];
|
|
9
|
+
}
|
|
10
|
+
/** Null selects the actual local host (input/output only), never an unbound forwarding side. */
|
|
11
|
+
export interface IManagedNftRule {
|
|
12
|
+
sourceEndpoint: string | null;
|
|
13
|
+
destinationEndpoint: string | null;
|
|
14
|
+
sourcePrefix: string;
|
|
15
|
+
destinationPrefix: string;
|
|
16
|
+
protocol: 'any' | 'tcp' | 'udp';
|
|
17
|
+
sourcePort: number | null;
|
|
18
|
+
destinationPort: number | null;
|
|
19
|
+
}
|
|
20
|
+
export interface IManagedNftPolicy {
|
|
21
|
+
schemaVersion: 1;
|
|
22
|
+
revision: number;
|
|
23
|
+
endpoints: IManagedNftEndpoint[];
|
|
24
|
+
rules: IManagedNftRule[];
|
|
25
|
+
}
|
|
26
|
+
export interface IPreparedManagedNftPolicy {
|
|
27
|
+
policy: IManagedNftPolicy;
|
|
28
|
+
digest: string;
|
|
29
|
+
}
|
|
30
|
+
export interface IManagedNftIdentity {
|
|
31
|
+
ownerId: string;
|
|
32
|
+
instanceId: string;
|
|
33
|
+
tableName: string;
|
|
34
|
+
bootId: string;
|
|
35
|
+
namespaceDevice: string;
|
|
36
|
+
namespaceInode: string;
|
|
37
|
+
}
|
|
38
|
+
export interface IManagedNftReceipt {
|
|
39
|
+
identity: IManagedNftIdentity;
|
|
40
|
+
tableHandle: string;
|
|
41
|
+
revision: number;
|
|
42
|
+
digest: string;
|
|
43
|
+
}
|
|
44
|
+
export interface IAppliedManagedNftPolicy {
|
|
45
|
+
receipt: IManagedNftReceipt;
|
|
46
|
+
prepared: IPreparedManagedNftPolicy;
|
|
47
|
+
}
|
|
48
|
+
/** Persist this complete command before reconcile, then retain its complete result. */
|
|
49
|
+
export interface IManagedNftTransition {
|
|
50
|
+
previous: IAppliedManagedNftPolicy | null;
|
|
51
|
+
target: IPreparedManagedNftPolicy;
|
|
52
|
+
}
|
|
53
|
+
export interface IManagedNftStatus {
|
|
54
|
+
identity: IManagedNftIdentity;
|
|
55
|
+
state: 'idle' | 'applied' | 'failed-owned' | 'released';
|
|
56
|
+
enforced: boolean;
|
|
57
|
+
applied: IAppliedManagedNftPolicy | null;
|
|
58
|
+
pending: IManagedNftTransition | null;
|
|
59
|
+
error: string | null;
|
|
60
|
+
}
|
|
61
|
+
export interface IManagedNftOptions {
|
|
62
|
+
ownerId: string;
|
|
63
|
+
/** Caller-retained unique operation identity, at least 16 identifier characters. */
|
|
64
|
+
instanceId: string;
|
|
65
|
+
/** Dedicated name beginning snft_; existing foreign tables always reject. */
|
|
66
|
+
tableName: string;
|
|
67
|
+
/** Explicit executable selection for qualified distributions and isolated tests. */
|
|
68
|
+
binaryPath?: string;
|
|
69
|
+
}
|
|
70
|
+
export type TManagedNftCommands = {
|
|
71
|
+
preparePolicy: {
|
|
72
|
+
params: IManagedNftPolicy;
|
|
73
|
+
result: IPreparedManagedNftPolicy;
|
|
74
|
+
};
|
|
75
|
+
openOwner: {
|
|
76
|
+
params: Omit<IManagedNftOptions, 'binaryPath'>;
|
|
77
|
+
result: IManagedNftStatus;
|
|
78
|
+
};
|
|
79
|
+
reconcilePolicy: {
|
|
80
|
+
params: IManagedNftTransition;
|
|
81
|
+
result: IAppliedManagedNftPolicy;
|
|
82
|
+
};
|
|
83
|
+
inspectPolicy: {
|
|
84
|
+
params: Record<string, never>;
|
|
85
|
+
result: IManagedNftStatus;
|
|
86
|
+
};
|
|
87
|
+
releasePolicy: {
|
|
88
|
+
params: IAppliedManagedNftPolicy;
|
|
89
|
+
result: {
|
|
90
|
+
released: true;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
closeOwner: {
|
|
94
|
+
params: Record<string, never>;
|
|
95
|
+
result: {
|
|
96
|
+
released: true;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
};
|
package/dist_ts/nft.executor.js
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
2
|
const execFile = plugins.util.promisify(plugins.childProcess.execFile);
|
|
3
|
+
export function normalizeNftCommand(command) {
|
|
4
|
+
let input = command.trim();
|
|
5
|
+
if (!input) {
|
|
6
|
+
throw new Error('Invalid nft command: command is empty');
|
|
7
|
+
}
|
|
8
|
+
if (input === 'nft') {
|
|
9
|
+
throw new Error('Invalid nft command: command is empty');
|
|
10
|
+
}
|
|
11
|
+
if (/^nft\s/.test(input)) {
|
|
12
|
+
input = input.slice(3).trimStart();
|
|
13
|
+
}
|
|
14
|
+
let normalized = '';
|
|
15
|
+
let quote;
|
|
16
|
+
for (let index = 0; index < input.length; index++) {
|
|
17
|
+
const character = input[index];
|
|
18
|
+
if (quote === 'single') {
|
|
19
|
+
normalized += character;
|
|
20
|
+
if (character === "'") {
|
|
21
|
+
quote = undefined;
|
|
22
|
+
}
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (quote === 'double') {
|
|
26
|
+
normalized += character;
|
|
27
|
+
if (character === '"') {
|
|
28
|
+
quote = undefined;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (character === '\\') {
|
|
32
|
+
const nextCharacter = input[index + 1];
|
|
33
|
+
if (nextCharacter === undefined) {
|
|
34
|
+
throw new Error('Invalid nft command: trailing escape in double-quoted string');
|
|
35
|
+
}
|
|
36
|
+
normalized += nextCharacter;
|
|
37
|
+
index++;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (character === "'") {
|
|
43
|
+
quote = 'single';
|
|
44
|
+
}
|
|
45
|
+
else if (character === '"') {
|
|
46
|
+
quote = 'double';
|
|
47
|
+
}
|
|
48
|
+
else if (character === '\\') {
|
|
49
|
+
const nextCharacter = input[index + 1];
|
|
50
|
+
if (nextCharacter === undefined) {
|
|
51
|
+
throw new Error('Invalid nft command: trailing escape');
|
|
52
|
+
}
|
|
53
|
+
if (nextCharacter === ';') {
|
|
54
|
+
normalized += ';';
|
|
55
|
+
index++;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
normalized += character;
|
|
60
|
+
}
|
|
61
|
+
if (quote) {
|
|
62
|
+
throw new Error(`Invalid nft command: unterminated ${quote}-quoted string`);
|
|
63
|
+
}
|
|
64
|
+
return normalized;
|
|
65
|
+
}
|
|
3
66
|
export class NftNotRootError extends Error {
|
|
4
67
|
constructor() {
|
|
5
68
|
super('Not running as root — nftables commands require root privileges');
|
|
@@ -31,12 +94,11 @@ export class NftExecutor {
|
|
|
31
94
|
* Returns stdout on success.
|
|
32
95
|
*/
|
|
33
96
|
async exec(command) {
|
|
97
|
+
const normalizedCommand = normalizeNftCommand(command);
|
|
34
98
|
if (this.dryRun) {
|
|
35
99
|
return '';
|
|
36
100
|
}
|
|
37
|
-
|
|
38
|
-
const args = command.startsWith('nft ') ? command.slice(4) : command;
|
|
39
|
-
const { stdout } = await execFile('nft', args.split(/\s+/));
|
|
101
|
+
const { stdout } = await execFile('nft', [normalizedCommand]);
|
|
40
102
|
return stdout;
|
|
41
103
|
}
|
|
42
104
|
/**
|
|
@@ -56,4 +118,4 @@ export class NftExecutor {
|
|
|
56
118
|
}
|
|
57
119
|
}
|
|
58
120
|
}
|
|
59
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
121
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmZ0LmV4ZWN1dG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvbmZ0LmV4ZWN1dG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBRXhDLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7QUFFdkUsTUFBTSxVQUFVLG1CQUFtQixDQUFDLE9BQWU7SUFDakQsSUFBSSxLQUFLLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzNCLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNYLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBQ0QsSUFBSSxLQUFLLEtBQUssS0FBSyxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQyx1Q0FBdUMsQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFDRCxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN6QixLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUNyQyxDQUFDO0lBRUQsSUFBSSxVQUFVLEdBQUcsRUFBRSxDQUFDO0lBQ3BCLElBQUksS0FBc0MsQ0FBQztJQUUzQyxLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQ2xELE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUUvQixJQUFJLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN2QixVQUFVLElBQUksU0FBUyxDQUFDO1lBQ3hCLElBQUksU0FBUyxLQUFLLEdBQUcsRUFBRSxDQUFDO2dCQUN0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
|