Fix client access scope

This commit is contained in:
2026-09-20 17:26:11 +01:00
parent aa0a292943
commit 27676c5a3f
4 changed files with 28 additions and 149 deletions
@@ -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;
}
@@ -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,
@@ -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<string>(host?.wg_ip_address || "");
const [ipStatus, setIpStatus] = useState<HostWgIpFieldStatus>("checking");
function handleSave() {
if (!window.confirm("Update this host configuration?")) return;
setStatus(undefined);
setLoading(true);
fetchApi<ApiReqParams, APIResponseObject>(
`/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 (
<>
<AdminCard className="w-full p-5 flex flex-col gap-4">
<Stack className="gap-1">
<H3 className="text-[14px] font-semibold mb-0!">
WireGuard subnet
</H3>
<P
noMargin
className="text-[12.5px] text-foreground-light/45 dark:text-foreground-dark/45"
>
The private subnet the host listens on (e.g.
10.1.0.1/24). Updating it rewrites the host config and
restarts the tunnel.
</P>
</Stack>
{/* <HostWgIpField
value={wgIP}
onChange={setWgIP}
onStatus={setIpStatus}
current_value={host?.wg_ip_address || ""}
autoFocus
/> */}
{status?.error && status.msg ? (
<Tag
variant="outlined"
color="error"
className="w-full py-1.5 outline-error/50 bg-error/5!"
>
<Row>
<TriangleAlert size={15} />
<Span>{status.msg}</Span>
</Row>
</Tag>
) : null}
{status?.success && status.msg ? (
<Tag
variant="outlined"
color="success"
className="w-full py-1.5 outline-success/50 bg-success/5!"
>
<Row>
<CircleCheck size={15} />
<Span>{status.msg}</Span>
</Row>
</Tag>
) : null}
<Row className="w-full items-center gap-2">
<Button
title="Save Changes"
disabled={
ipStatus !== "available" && ipStatus !== "current"
}
loading={loading}
onClick={handleSave}
>
Save Changes
</Button>
</Row>
</AdminCard>
<HostPublicIpSection
host_id={host_id}
current_ip={host?.public_ip_address || ""}
/>
</>
);
}
@@ -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";