feat(nft): add source IP filtering for DNAT rules and expose table existence checks

This commit is contained in:
2026-03-30 14:19:44 +00:00
parent e4bb314b5f
commit 46a492443e
5 changed files with 28 additions and 2 deletions

View File

@@ -1,5 +1,12 @@
# Changelog
## 2026-03-30 - 1.1.0 - feat(nft)
add source IP filtering for DNAT rules and expose table existence checks
- Adds an optional sourceIP field to NAT rule definitions to restrict DNAT rules to matching source addresses or subnets.
- Updates DNAT rule generation to include an ip saddr match when sourceIP is provided.
- Introduces a tableExists() manager method to detect whether the managed nftables table is still present in the kernel.
## 2026-03-26 - 1.0.1 - fix(repo)
no changes to commit

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartnftables',
version: '1.0.1',
version: '1.1.0',
description: 'A TypeScript module for managing nftables rules including NAT, firewall, and rate limiting with a high-level API.'
}

View File

@@ -133,6 +133,22 @@ export class SmartNftables {
this.hasFilterChains = false;
}
/**
* Check if the managed nftables table exists in the kernel.
* Returns false if not root, not initialized, or the table was removed externally.
*/
public async tableExists(): Promise<boolean> {
if (!this.executor.isRoot() || !this.initialized) {
return false;
}
try {
await this.executor.exec(`nft list table ${this.family} ${this.tableName}`);
return true;
} catch {
return false;
}
}
/**
* Get status report of the managed nftables state.
*/

View File

@@ -26,8 +26,9 @@ export function buildDnatRules(
for (const proto of protocols) {
// DNAT rule
const saddrFilter = rule.sourceIP ? `ip saddr ${rule.sourceIP} ` : '';
commands.push(
`nft add rule ${family} ${tableName} prerouting ${proto} dport ${rule.sourcePort} dnat to ${rule.targetHost}:${rule.targetPort}`
`nft add rule ${family} ${tableName} prerouting ${saddrFilter}${proto} dport ${rule.sourcePort} dnat to ${rule.targetHost}:${rule.targetPort}`
);
// Masquerade (SNAT) unless preserveSourceIP is set

View File

@@ -14,6 +14,8 @@ export interface INftDnatRule {
targetPort: number;
protocol?: TNftProtocol;
preserveSourceIP?: boolean;
/** Filter by source IP/subnet (e.g. '10.8.0.0/24'). Only matching traffic gets DNAT'd. */
sourceIP?: string;
}
export interface INftSnatRule {