Browse Source

check for iptables before enabling the firewall and inform the user if

it is missing
pull/2418/head
Ian Foster 6 months ago
parent
commit
a9264b94e1
  1. 2
      src/nuxt.config.ts
  2. 19
      src/server/api/admin/interface/index.post.ts
  3. 16
      src/server/utils/WireGuard.ts
  4. 42
      src/server/utils/firewall.ts

2
src/nuxt.config.ts

@ -147,6 +147,7 @@ export default defineNuxtConfig({
},
alias: {
'#db': fileURLToPath(new URL('./server/database/', import.meta.url)),
'#utils': fileURLToPath(new URL('./server/utils/', import.meta.url)),
},
externals: {
traceInclude: [fileURLToPath(new URL('./cli/index.ts', import.meta.url))],
@ -155,5 +156,6 @@ export default defineNuxtConfig({
alias: {
// for typecheck reasons (https://github.com/nuxt/cli/issues/323)
'#db': fileURLToPath(new URL('./server/database/', import.meta.url)),
'#utils': fileURLToPath(new URL('./server/utils/', import.meta.url)),
},
});

19
src/server/api/admin/interface/index.post.ts

@ -1,4 +1,5 @@
import { InterfaceUpdateSchema } from '#db/repositories/interface/types';
import { firewall } from '#utils/firewall';
export default definePermissionEventHandler(
'admin',
@ -8,6 +9,24 @@ export default definePermissionEventHandler(
event,
validateZod(InterfaceUpdateSchema, event)
);
// If enabling firewall, check if iptables is available
if (data.firewallEnabled) {
// Clear cache to force fresh check
firewall.clearAvailabilityCache();
const iptablesAvailable = await firewall.isAvailable(!WG_ENV.DISABLE_IPV6);
if (!iptablesAvailable) {
const requiredTools = WG_ENV.DISABLE_IPV6
? 'iptables'
: 'iptables and ip6tables';
throw createError({
statusCode: 400,
statusMessage: `Per-Client Firewall requires ${requiredTools} to be installed on the host system. Please install ${requiredTools} before enabling this feature.`,
});
}
}
await Database.interfaces.update(data);
await WireGuard.saveConfig();
return { success: true };

16
src/server/utils/WireGuard.ts

@ -266,6 +266,22 @@ class WireGuard {
await this.#syncWireguardConfig(wgInterface);
WG_DEBUG(`Wireguard Interface ${wgInterface.name} started successfully.`);
// Check if firewall was enabled but iptables isn't available
if (wgInterface.firewallEnabled) {
const enableIpv6 = !WG_ENV.DISABLE_IPV6;
const iptablesAvailable = await firewall.isAvailable(enableIpv6);
if (!iptablesAvailable) {
const requiredTools = enableIpv6
? 'iptables/ip6tables'
: 'iptables';
console.warn(
`WARNING: Per-Client Firewall is enabled but ${requiredTools} is not available. Disabling firewall feature. Please install ${requiredTools} to use this feature.`
);
await Database.interfaces.update({ firewallEnabled: false });
wgInterface.firewallEnabled = false; // Update local copy
}
}
WG_DEBUG('Applying firewall rules...');
await this.#applyFirewallRules(wgInterface);
WG_DEBUG('Firewall rules applied successfully.');

42
src/server/utils/firewall.ts

@ -13,6 +13,9 @@ const CHAIN_NAME = 'WG_CLIENTS';
let rebuildInProgress = false;
let rebuildQueued = false;
// Cache iptables availability check result
let iptablesAvailable: boolean | null = null;
type ParsedEntry = {
ip: string;
port?: number;
@ -249,4 +252,43 @@ export const firewall = {
await exec(`iptables -X ${CHAIN_NAME} 2>/dev/null || true`);
await exec(`ip6tables -X ${CHAIN_NAME} 2>/dev/null || true`);
},
/**
* Check if iptables (and optionally ip6tables) are available on the system.
* @param enableIpv6 - If true, also check for ip6tables. Defaults to true.
*/
async isAvailable(enableIpv6: boolean = true): Promise<boolean> {
// Return cached result if we've already checked
if (iptablesAvailable !== null) {
return iptablesAvailable;
}
try {
// Check for iptables (always required)
await exec('iptables --version');
FW_DEBUG('iptables is available');
// Check for ip6tables (only if IPv6 is enabled)
if (enableIpv6) {
await exec('ip6tables --version');
FW_DEBUG('ip6tables is available');
} else {
FW_DEBUG('IPv6 disabled, skipping ip6tables check');
}
iptablesAvailable = true;
return true;
} catch (error) {
iptablesAvailable = false;
FW_DEBUG('iptables/ip6tables is not available:', error);
return false;
}
},
/**
* Clear the availability cache to force a re-check
*/
clearAvailabilityCache(): void {
iptablesAvailable = null;
},
};

Loading…
Cancel
Save