feat(nft): add source IP filtering for DNAT rules and expose table existence checks
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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.'
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user