From 27676c5a3f8fa4447f44497aa1487e8cd8be04f6 Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Sun, 20 Sep 2026 17:26:11 +0100 Subject: [PATCH] Fix client access scope --- .../setup/build-host-iptables-scripts.ts | 31 +++- .../backend/setup/setup-wireguard-host.ts | 3 + .../(sections)/edit-host-form-section.tsx | 142 ------------------ .../admin/hosts/[host_id]/edit/index.tsx | 1 - 4 files changed, 28 insertions(+), 149 deletions(-) delete mode 100644 src/pages/admin/hosts/[host_id]/edit/(sections)/edit-host-form-section.tsx diff --git a/src/functions/backend/setup/build-host-iptables-scripts.ts b/src/functions/backend/setup/build-host-iptables-scripts.ts index 06b02f2..a896d99 100644 --- a/src/functions/backend/setup/build-host-iptables-scripts.ts +++ b/src/functions/backend/setup/build-host-iptables-scripts.ts @@ -1,6 +1,7 @@ import type { BUN_SQLITE_WGUI_CLIENT_RULES } from "@/db/types/db"; import parsePortList from "@/src/utils/parse-port-list"; import validateIpv4 from "@/src/utils/validate-ipv4"; +import validateIpv4Cidr from "@/src/utils/validate-ipv4-cidr"; import deriveIptablesChainNames from "./derive-iptables-chain-names"; import normalizeIptablesDestination from "./normalize-iptables-destination"; import validateClientRule from "./validate-client-rule"; @@ -15,6 +16,7 @@ type Params = { host_id: number; interface_name: string; target_interface: string; + host_subnet?: string; clients?: HostIptablesClient[]; }; @@ -123,6 +125,7 @@ export default function buildHostIptablesScripts({ host_id, interface_name, target_interface, + host_subnet, clients, }: Params) { if (!Number.isInteger(host_id) || host_id < 0) { @@ -146,6 +149,15 @@ export default function buildHostIptablesScripts({ }; } + const scoped_subnet = host_subnet?.trim(); + + if (scoped_subnet && !validateIpv4Cidr({ value: scoped_subnet })) { + return { + success: false, + msg: `Invalid host subnet "${scoped_subnet}"`, + }; + } + const { forward, input } = deriveIptablesChainNames({ host_id }); const accept_lines: string[] = []; const host_clients = clients || []; @@ -193,12 +205,19 @@ export default function buildHostIptablesScripts({ } if (rule.rule_type == "all") { - accept_lines.push( - `iptables -A ${forward} -s ${source} -j ACCEPT`, - ); - accept_lines.push( - `iptables -A ${input} -s ${source} -j ACCEPT`, - ); + if (scoped_subnet) { + accept_lines.push( + `iptables -A ${forward} -s ${source} -d ${scoped_subnet} -j ACCEPT`, + `iptables -A ${forward} -s ${source} -o ${target_interface} -j ACCEPT`, + `iptables -A ${input} -s ${source} -d ${scoped_subnet} -j ACCEPT`, + ); + } else { + accept_lines.push( + `iptables -A ${forward} -s ${source} -j ACCEPT`, + `iptables -A ${input} -s ${source} -j ACCEPT`, + ); + } + continue; } diff --git a/src/functions/backend/setup/setup-wireguard-host.ts b/src/functions/backend/setup/setup-wireguard-host.ts index 869f3b9..fe5f0d1 100644 --- a/src/functions/backend/setup/setup-wireguard-host.ts +++ b/src/functions/backend/setup/setup-wireguard-host.ts @@ -172,10 +172,13 @@ export default async function setupWireguardHost({ sh += `cd ${HOST_CONFIG_DIR}\n`; + const HOST_SUBNET = `${HOST_WG_IP.split(".").slice(0, 3).join(".")}.0/24`; + const iptables_scripts = buildHostIptablesScripts({ host_id: Number(HOST_ID), interface_name: INTERFACE_NAME, target_interface: TARGET_INTERFACE || "eth0", + host_subnet: HOST_SUBNET, clients: clients.map((client) => ({ id: client.id, wg_ip_address: client.wg_ip_address, diff --git a/src/pages/admin/hosts/[host_id]/edit/(sections)/edit-host-form-section.tsx b/src/pages/admin/hosts/[host_id]/edit/(sections)/edit-host-form-section.tsx deleted file mode 100644 index 69ca94c..0000000 --- a/src/pages/admin/hosts/[host_id]/edit/(sections)/edit-host-form-section.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { useContext, useState } from "react"; -import { CircleCheck, TriangleAlert } from "lucide-react"; -import AdminCard from "@/src/components/general/admin-card"; -import HostWgIpField, { - type HostWgIpFieldStatus, -} from "@/src/components/general/host-wg-ip-field"; -import useStatus from "@/src/components/twui/hooks/useStatus"; -import fetchApi from "@/src/components/twui/utils/fetch/fetchApi"; -import H3 from "@/src/components/twui/layout/H3"; -import P from "@/src/components/twui/layout/P"; -import Row from "@/src/components/twui/layout/Row"; -import Span from "@/src/components/twui/layout/Span"; -import Stack from "@/src/components/twui/layout/Stack"; -import Tag from "@/src/components/twui/elements/Tag"; -import Button from "@/src/components/twui/layout/Button"; -import { AppContext } from "@/src/pages/__root"; -import HostPublicIpSection from "../../../(sections)/host-public-ip-section"; -import type { ApiReqParams } from "@/src/types"; -import type { APIResponseObject } from "@moduletrace/bunext/types"; - -export default function EditHostFormSection() { - const { pageProps, query } = useContext(AppContext); - - const host_id = Number(query?.host_id || pageProps?.host?.id || 0); - const host = pageProps?.host; - - const { loading, setLoading, status, setStatus } = useStatus(); - - const [wgIP, setWgIP] = useState(host?.wg_ip_address || ""); - const [ipStatus, setIpStatus] = useState("checking"); - - function handleSave() { - if (!window.confirm("Update this host configuration?")) return; - - setStatus(undefined); - setLoading(true); - - fetchApi( - `/api/admin/update-host-wg-ip`, - { - method: "POST", - body: { - host_id, - wg_ip_address: wgIP, - }, - }, - ) - .then((res) => { - if (res.success) { - window.location.pathname = `/admin/hosts/${host_id}`; - return; - } - - setStatus({ - error: true, - success: false, - msg: res.msg || "Could not update the host", - }); - }) - .catch((error: any) => { - setStatus({ - error: true, - success: false, - msg: error.message || "Could not update the host", - }); - }) - .finally(() => { - setLoading(false); - }); - } - - return ( - <> - - -

- WireGuard subnet -

-

- The private subnet the host listens on (e.g. - 10.1.0.1/24). Updating it rewrites the host config and - restarts the tunnel. -

-
- - {/* */} - - {status?.error && status.msg ? ( - - - - {status.msg} - - - ) : null} - {status?.success && status.msg ? ( - - - - {status.msg} - - - ) : null} - - - - -
- - - - ); -} diff --git a/src/pages/admin/hosts/[host_id]/edit/index.tsx b/src/pages/admin/hosts/[host_id]/edit/index.tsx index cb894e5..feeef8f 100644 --- a/src/pages/admin/hosts/[host_id]/edit/index.tsx +++ b/src/pages/admin/hosts/[host_id]/edit/index.tsx @@ -8,7 +8,6 @@ import EmptyContent from "@/src/components/twui/elements/EmptyContent"; import { ArrowLeft } from "lucide-react"; import { useContext } from "react"; import { AppContext } from "@/src/pages/__root"; -import EditHostFormSection from "./(sections)/edit-host-form-section"; import AddHostForm from "../../add/(partials)/add-host-form/add-host-form"; import _ from "lodash"; import type { BUN_SQLITE_WGUI_HOSTS_JOIN } from "@/src/types/sql-joins";