Skip to content

Commit d5384d9

Browse files
fix(cli): validate firewall adapter IP inputs (#35)
Co-authored-by: rissrice2105-agent <rissrice2105-agent@users.noreply.github.com>
1 parent 3256819 commit d5384d9

1 file changed

Lines changed: 16 additions & 3 deletions

File tree

apps/cli/src/daemon/firewall/adapters.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { execSync, spawnSync } from 'node:child_process';
2+
import { isIP } from 'node:net';
23

34
export interface FirewallAdapter {
45
name: string;
@@ -9,6 +10,12 @@ export interface FirewallAdapter {
910
listBlocked(): Promise<string[]>;
1011
}
1112

13+
function assertValidFirewallIp(ip: string): void {
14+
if (isIP(ip) !== 4) {
15+
throw new Error(`Invalid IPv4 address: ${ip}`);
16+
}
17+
}
18+
1219
export class NftablesAdapter implements FirewallAdapter {
1320
name = 'nftables';
1421
private table = 'threatcrush';
@@ -31,17 +38,20 @@ export class NftablesAdapter implements FirewallAdapter {
3138
}
3239

3340
async block(ip: string): Promise<void> {
41+
assertValidFirewallIp(ip);
3442
this.ensureSetup();
3543
execSync(`nft add element inet ${this.table} ${this.set} '{ ${ip} }'`);
3644
}
3745

3846
async unblock(ip: string): Promise<void> {
47+
assertValidFirewallIp(ip);
3948
try {
4049
execSync(`nft delete element inet ${this.table} ${this.set} '{ ${ip} }'`);
4150
} catch { /* element may not exist */ }
4251
}
4352

4453
async isBlocked(ip: string): Promise<boolean> {
54+
assertValidFirewallIp(ip);
4555
try {
4656
const output = execSync(`nft list set inet ${this.table} ${this.set}`, { encoding: 'utf-8' });
4757
return output.includes(ip);
@@ -77,17 +87,20 @@ export class IptablesAdapter implements FirewallAdapter {
7787
}
7888

7989
async block(ip: string): Promise<void> {
90+
assertValidFirewallIp(ip);
8091
this.ensureChain();
8192
if (await this.isBlocked(ip)) return;
8293
execSync(`iptables -A ${this.chain} -s ${ip} -j DROP`);
8394
}
8495

8596
async unblock(ip: string): Promise<void> {
97+
assertValidFirewallIp(ip);
8698
try { execSync(`iptables -D ${this.chain} -s ${ip} -j DROP`); }
8799
catch { /* rule may not exist */ }
88100
}
89101

90102
async isBlocked(ip: string): Promise<boolean> {
103+
assertValidFirewallIp(ip);
91104
try {
92105
const output = execSync(`iptables -n -L ${this.chain}`, { encoding: 'utf-8' });
93106
return output.includes(ip);
@@ -112,9 +125,9 @@ export class DryRunAdapter implements FirewallAdapter {
112125
private blocked = new Set<string>();
113126

114127
isAvailable(): boolean { return true; }
115-
async block(ip: string): Promise<void> { this.blocked.add(ip); }
116-
async unblock(ip: string): Promise<void> { this.blocked.delete(ip); }
117-
async isBlocked(ip: string): Promise<boolean> { return this.blocked.has(ip); }
128+
async block(ip: string): Promise<void> { assertValidFirewallIp(ip); this.blocked.add(ip); }
129+
async unblock(ip: string): Promise<void> { assertValidFirewallIp(ip); this.blocked.delete(ip); }
130+
async isBlocked(ip: string): Promise<boolean> { assertValidFirewallIp(ip); return this.blocked.has(ip); }
118131
async listBlocked(): Promise<string[]> { return [...this.blocked]; }
119132
}
120133

0 commit comments

Comments
 (0)