feat(nftables):add nftables support for nftables

This commit is contained in:
2025-05-15 14:35:01 +00:00
parent cf96ff8a47
commit a2e3e38025
22 changed files with 2331 additions and 201 deletions

View File

@ -31,8 +31,8 @@ export interface NfTableProxyOptions {
logFormat?: 'plain' | 'json'; // Format for logs
// Source filtering
allowedSourceIPs?: string[]; // If provided, only these IPs are allowed
bannedSourceIPs?: string[]; // If provided, these IPs are blocked
ipAllowList?: string[]; // If provided, only these IPs are allowed
ipBlockList?: string[]; // If provided, these IPs are blocked
useIPSets?: boolean; // Use nftables sets for efficient IP management
// Rule management

View File

@ -134,8 +134,8 @@ export class NfTablesProxy {
}
};
validateIPs(settings.allowedSourceIPs);
validateIPs(settings.bannedSourceIPs);
validateIPs(settings.ipAllowList);
validateIPs(settings.ipBlockList);
// Validate toHost - only allow hostnames or IPs
if (settings.toHost) {
@ -426,7 +426,7 @@ export class NfTablesProxy {
* Adds source IP filtering rules, potentially using IP sets for efficiency
*/
private async addSourceIPFilters(isIpv6: boolean = false): Promise<boolean> {
if (!this.settings.allowedSourceIPs && !this.settings.bannedSourceIPs) {
if (!this.settings.ipAllowList && !this.settings.ipBlockList) {
return true; // Nothing to do
}
@ -441,9 +441,9 @@ export class NfTablesProxy {
// Using IP sets for more efficient rule processing with large IP lists
if (this.settings.useIPSets) {
// Create sets for banned and allowed IPs if needed
if (this.settings.bannedSourceIPs && this.settings.bannedSourceIPs.length > 0) {
if (this.settings.ipBlockList && this.settings.ipBlockList.length > 0) {
const setName = 'banned_ips';
await this.createIPSet(family, setName, this.settings.bannedSourceIPs, setType as any);
await this.createIPSet(family, setName, this.settings.ipBlockList, setType as any);
// Add rule to drop traffic from banned IPs
const rule = `add rule ${family} ${this.tableName} ${chain} ip${isIpv6 ? '6' : ''} saddr @${setName} drop comment "${this.ruleTag}:BANNED_SET"`;
@ -458,9 +458,9 @@ export class NfTablesProxy {
});
}
if (this.settings.allowedSourceIPs && this.settings.allowedSourceIPs.length > 0) {
if (this.settings.ipAllowList && this.settings.ipAllowList.length > 0) {
const setName = 'allowed_ips';
await this.createIPSet(family, setName, this.settings.allowedSourceIPs, setType as any);
await this.createIPSet(family, setName, this.settings.ipAllowList, setType as any);
// Add rule to allow traffic from allowed IPs
const rule = `add rule ${family} ${this.tableName} ${chain} ip${isIpv6 ? '6' : ''} saddr @${setName} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} accept comment "${this.ruleTag}:ALLOWED_SET"`;
@ -490,8 +490,8 @@ export class NfTablesProxy {
// Traditional approach without IP sets - less efficient for large IP lists
// Ban specific IPs first
if (this.settings.bannedSourceIPs && this.settings.bannedSourceIPs.length > 0) {
for (const ip of this.settings.bannedSourceIPs) {
if (this.settings.ipBlockList && this.settings.ipBlockList.length > 0) {
for (const ip of this.settings.ipBlockList) {
// Skip IPv4 addresses for IPv6 rules and vice versa
if (isIpv6 && ip.includes('.')) continue;
if (!isIpv6 && ip.includes(':')) continue;
@ -510,9 +510,9 @@ export class NfTablesProxy {
}
// Allow specific IPs
if (this.settings.allowedSourceIPs && this.settings.allowedSourceIPs.length > 0) {
if (this.settings.ipAllowList && this.settings.ipAllowList.length > 0) {
// Add rules to allow specific IPs
for (const ip of this.settings.allowedSourceIPs) {
for (const ip of this.settings.ipAllowList) {
// Skip IPv4 addresses for IPv6 rules and vice versa
if (isIpv6 && ip.includes('.')) continue;
if (!isIpv6 && ip.includes(':')) continue;
@ -1398,28 +1398,28 @@ export class NfTablesProxy {
// Source IP filters
if (this.settings.useIPSets) {
if (this.settings.bannedSourceIPs?.length) {
if (this.settings.ipBlockList?.length) {
commands.push(`add set ip ${this.tableName} banned_ips { type ipv4_addr; }`);
commands.push(`add element ip ${this.tableName} banned_ips { ${this.settings.bannedSourceIPs.join(', ')} }`);
commands.push(`add element ip ${this.tableName} banned_ips { ${this.settings.ipBlockList.join(', ')} }`);
commands.push(`add rule ip ${this.tableName} nat_prerouting ip saddr @banned_ips drop comment "${this.ruleTag}:BANNED_SET"`);
}
if (this.settings.allowedSourceIPs?.length) {
if (this.settings.ipAllowList?.length) {
commands.push(`add set ip ${this.tableName} allowed_ips { type ipv4_addr; }`);
commands.push(`add element ip ${this.tableName} allowed_ips { ${this.settings.allowedSourceIPs.join(', ')} }`);
commands.push(`add element ip ${this.tableName} allowed_ips { ${this.settings.ipAllowList.join(', ')} }`);
commands.push(`add rule ip ${this.tableName} nat_prerouting ip saddr @allowed_ips ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} accept comment "${this.ruleTag}:ALLOWED_SET"`);
commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} drop comment "${this.ruleTag}:DENY_ALL"`);
}
} else if (this.settings.bannedSourceIPs?.length || this.settings.allowedSourceIPs?.length) {
} else if (this.settings.ipBlockList?.length || this.settings.ipAllowList?.length) {
// Traditional approach without IP sets
if (this.settings.bannedSourceIPs?.length) {
for (const ip of this.settings.bannedSourceIPs) {
if (this.settings.ipBlockList?.length) {
for (const ip of this.settings.ipBlockList) {
commands.push(`add rule ip ${this.tableName} nat_prerouting ip saddr ${ip} drop comment "${this.ruleTag}:BANNED"`);
}
}
if (this.settings.allowedSourceIPs?.length) {
for (const ip of this.settings.allowedSourceIPs) {
if (this.settings.ipAllowList?.length) {
for (const ip of this.settings.ipAllowList) {
commands.push(`add rule ip ${this.tableName} nat_prerouting ip saddr ${ip} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} accept comment "${this.ruleTag}:ALLOWED"`);
}
commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} drop comment "${this.ruleTag}:DENY_ALL"`);