feat(firewall): add IP set blocking convenience API with CIDR interval support and optional rule comments

This commit is contained in:
2026-04-26 15:05:50 +00:00
parent 75dacef68e
commit 6e7c0d90d8
9 changed files with 106 additions and 8 deletions
+36 -1
View File
@@ -1,5 +1,5 @@
import type { SmartNftables } from './nft.manager.js';
import type { INftFirewallRule, INftIPSetConfig } from './nft.types.js';
import type { INftFirewallRule, INftIPSetBlockOptions, INftIPSetConfig } from './nft.types.js';
import {
buildFirewallRule,
buildIPSetCreate,
@@ -82,6 +82,41 @@ export class FirewallManager {
});
}
/**
* Convenience: block many IPs or CIDR subnets using one nftables set and
* one matching drop rule. This is substantially cheaper than one rule per IP.
*/
public async blockIPSet(groupId: string, options: INftIPSetBlockOptions): Promise<void> {
const ips = [...new Set(options.ips)].filter(Boolean).sort();
if (ips.length === 0) {
return;
}
await this.parent.ensureFilterChains();
const setName = options.setName ?? `${groupId.replace(/[^a-zA-Z0-9_]/g, '_')}_set`;
const setType = options.type ?? (this.parent.family === 'ip6' ? 'ipv6_addr' : 'ipv4_addr');
const needsIntervalSet = ips.some((ip) => ip.includes('/'));
const direction = options.direction ?? 'input';
const commands = [
...buildIPSetCreate(this.parent.tableName, this.parent.family, {
name: setName,
type: setType,
elements: ips,
interval: needsIntervalSet,
}),
...buildIPSetMatchRule(this.parent.tableName, this.parent.family, {
setName,
direction,
matchField: 'saddr',
action: 'drop',
comment: options.comment,
}),
];
await this.parent.applyRuleGroup(`fw:blockset:${groupId}`, commands);
}
/**
* Convenience: allow only specific IPs on a port.
* Adds accept rules for each IP, then a drop rule for everything else on that port.