Allow wildcard rule access host public IP ports
This commit is contained in:
+2
-1
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "bunext-mariadb-preset",
|
||||
"name": "wireguard-ui",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "sudo bun src/server.ts",
|
||||
|
||||
@@ -66,12 +66,43 @@ describe("buildHostIptablesScripts", () => {
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
expect(res.post_up).toContain(
|
||||
"iptables -A WGUI0FWD -s 10.0.0.3/32 -p tcp -m multiport --dports 80,443 -j ACCEPT",
|
||||
"iptables -A WGUI0FWD -s 10.0.0.3/32 -d 192.168.1.10/32 -p tcp -m multiport --dports 80,443 -j ACCEPT",
|
||||
);
|
||||
expect(res.post_up).toContain(
|
||||
"iptables -A WGUI0IN -s 10.0.0.3/32 -p tcp -m multiport --dports 80,443 -j ACCEPT",
|
||||
"iptables -A WGUI0IN -s 10.0.0.3/32 -d 192.168.1.10/32 -p tcp -m multiport --dports 80,443 -j ACCEPT",
|
||||
);
|
||||
});
|
||||
|
||||
test("destination overrides the host subnet scope on input", () => {
|
||||
const res = buildHostIptablesScripts({
|
||||
...base,
|
||||
host_subnet: "10.5.0.0/24",
|
||||
clients: [
|
||||
{
|
||||
id: 8,
|
||||
wg_ip_address: "10.5.0.2",
|
||||
rules: [
|
||||
{
|
||||
rule_type: "destination",
|
||||
destination: "65.108.81.79",
|
||||
ports: "443",
|
||||
protocol: "tcp",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
expect(res.post_up).toContain(
|
||||
"iptables -A WGUI0FWD -s 10.5.0.2/32 -d 65.108.81.79/32 -p tcp --dport 443 -j ACCEPT",
|
||||
);
|
||||
expect(res.post_up).toContain(
|
||||
"iptables -A WGUI0IN -s 10.5.0.2/32 -d 65.108.81.79/32 -p tcp --dport 443 -j ACCEPT",
|
||||
);
|
||||
expect(res.post_up).not.toContain(
|
||||
"iptables -A WGUI0IN -s 10.5.0.2/32 -d 10.5.0.0/24 -p tcp --dport 443 -j ACCEPT",
|
||||
);
|
||||
expect(res.post_up).not.toContain("-d 192.168.1.10/32");
|
||||
});
|
||||
|
||||
test("protocol any with ports emits tcp and udp", () => {
|
||||
@@ -310,6 +341,120 @@ describe("buildHostIptablesScripts", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("allow_all_ips clients get full input and forward access", () => {
|
||||
const res = buildHostIptablesScripts({
|
||||
...base,
|
||||
host_subnet: "10.7.0.0/24",
|
||||
clients: [
|
||||
{
|
||||
id: 9,
|
||||
wg_ip_address: "10.7.0.3",
|
||||
allow_all_ips: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
expect(res.post_up).toContain(
|
||||
"iptables -A WGUI0FWD -s 10.7.0.3/32 -j ACCEPT",
|
||||
);
|
||||
expect(res.post_up).toContain(
|
||||
"iptables -A WGUI0IN -s 10.7.0.3/32 -j ACCEPT",
|
||||
);
|
||||
expect(res.post_up).not.toContain("-d 10.7.0.0/24");
|
||||
});
|
||||
|
||||
test("allow_all_ips clients still cannot jump to sibling host subnets", () => {
|
||||
const res = buildHostIptablesScripts({
|
||||
...base,
|
||||
host_subnet: "10.7.0.0/24",
|
||||
sibling_subnets: ["10.3.0.0/24"],
|
||||
clients: [
|
||||
{
|
||||
id: 10,
|
||||
wg_ip_address: "10.7.0.4",
|
||||
allow_all_ips: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
const post_up = res.post_up ?? "";
|
||||
|
||||
const sibling_drop =
|
||||
"iptables -A WGUI0IN -s 10.7.0.4/32 -d 10.3.0.0/24 -j DROP";
|
||||
const input_accept = "iptables -A WGUI0IN -s 10.7.0.4/32 -j ACCEPT";
|
||||
|
||||
expect(post_up).toContain(sibling_drop);
|
||||
expect(post_up).toContain(input_accept);
|
||||
expect(post_up.indexOf(input_accept)).toBeGreaterThan(
|
||||
post_up.indexOf(sibling_drop),
|
||||
);
|
||||
});
|
||||
|
||||
test("explicit rules are ignored for allow_all_ips clients", () => {
|
||||
const res = buildHostIptablesScripts({
|
||||
...base,
|
||||
clients: [
|
||||
{
|
||||
id: 11,
|
||||
wg_ip_address: "10.7.0.5",
|
||||
allow_all_ips: true,
|
||||
rules: [
|
||||
{
|
||||
rule_type: "destination",
|
||||
destination: "192.0.2.1",
|
||||
ports: "80",
|
||||
protocol: "tcp",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
expect(res.post_up).toContain(
|
||||
"iptables -A WGUI0FWD -s 10.7.0.5/32 -j ACCEPT",
|
||||
);
|
||||
expect(res.post_up).not.toContain("192.0.2.1");
|
||||
});
|
||||
|
||||
test("destination rules cannot bypass sibling subnet isolation", () => {
|
||||
const res = buildHostIptablesScripts({
|
||||
...base,
|
||||
host_subnet: "10.0.0.0/24",
|
||||
sibling_subnets: ["10.1.0.0/24"],
|
||||
clients: [
|
||||
{
|
||||
id: 12,
|
||||
wg_ip_address: "10.0.0.6",
|
||||
rules: [
|
||||
{
|
||||
rule_type: "destination",
|
||||
destination: "10.1.0.25",
|
||||
ports: "80",
|
||||
protocol: "tcp",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
const post_up = res.post_up ?? "";
|
||||
|
||||
const sibling_drop =
|
||||
"iptables -A WGUI0IN -s 10.0.0.6/32 -d 10.1.0.0/24 -j DROP";
|
||||
const accept =
|
||||
"iptables -A WGUI0IN -s 10.0.0.6/32 -d 10.1.0.25/32 -p tcp --dport 80 -j ACCEPT";
|
||||
|
||||
expect(post_up).toContain(sibling_drop);
|
||||
expect(post_up).toContain(accept);
|
||||
expect(post_up.indexOf(accept)).toBeGreaterThan(
|
||||
post_up.indexOf(sibling_drop),
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects oversized host id", () => {
|
||||
const res = buildHostIptablesScripts({
|
||||
...base,
|
||||
|
||||
@@ -9,6 +9,7 @@ import validateClientRule from "./validate-client-rule";
|
||||
type HostIptablesClient = {
|
||||
id?: number | "";
|
||||
wg_ip_address?: string;
|
||||
allow_all_ips?: boolean;
|
||||
rules?: BUN_SQLITE_WGUI_CLIENT_RULES[];
|
||||
};
|
||||
|
||||
@@ -85,6 +86,7 @@ function acceptLines({
|
||||
source,
|
||||
protocol,
|
||||
ports,
|
||||
destination,
|
||||
host_subnet,
|
||||
}: {
|
||||
forward_chain: string;
|
||||
@@ -92,6 +94,7 @@ function acceptLines({
|
||||
source: string;
|
||||
protocol?: string;
|
||||
ports: string[];
|
||||
destination?: string;
|
||||
host_subnet?: string;
|
||||
}) {
|
||||
const lines: string[] = [];
|
||||
@@ -109,11 +112,14 @@ function acceptLines({
|
||||
const port_match_str = proto
|
||||
? portMatch({ ports: chunk })
|
||||
: undefined;
|
||||
const direction = destination ? `-d ${destination}` : undefined;
|
||||
const input_destination = destination || host_subnet;
|
||||
|
||||
lines.push(
|
||||
joinArgs([
|
||||
`iptables -A ${forward_chain}`,
|
||||
`-s ${source}`,
|
||||
direction,
|
||||
proto ? `-p ${proto}` : undefined,
|
||||
port_match_str,
|
||||
`-j ACCEPT`,
|
||||
@@ -124,7 +130,7 @@ function acceptLines({
|
||||
joinArgs([
|
||||
`iptables -A ${input_chain}`,
|
||||
`-s ${source}`,
|
||||
host_subnet ? `-d ${host_subnet}` : undefined,
|
||||
input_destination ? `-d ${input_destination}` : undefined,
|
||||
proto ? `-p ${proto}` : undefined,
|
||||
port_match_str,
|
||||
`-j ACCEPT`,
|
||||
@@ -212,6 +218,15 @@ export default function buildHostIptablesScripts({
|
||||
);
|
||||
}
|
||||
|
||||
if (client.allow_all_ips) {
|
||||
accept_lines.push(
|
||||
`iptables -A ${forward} -s ${source} -j ACCEPT`,
|
||||
`iptables -A ${input} -s ${source} -j ACCEPT`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let r = 0; r < rules.length; r++) {
|
||||
const rule = rules[r];
|
||||
|
||||
@@ -255,6 +270,10 @@ export default function buildHostIptablesScripts({
|
||||
};
|
||||
}
|
||||
|
||||
const destination = normalizeIptablesDestination({
|
||||
destination: rule.destination,
|
||||
});
|
||||
|
||||
accept_lines.push(
|
||||
...acceptLines({
|
||||
forward_chain: forward,
|
||||
@@ -262,6 +281,7 @@ export default function buildHostIptablesScripts({
|
||||
source,
|
||||
protocol: rule.protocol || "any",
|
||||
ports: parsed_ports.ports,
|
||||
destination,
|
||||
host_subnet: scoped_subnet,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -205,6 +205,7 @@ export default async function setupWireguardHost({
|
||||
clients: clients.map((client) => ({
|
||||
id: client.id,
|
||||
wg_ip_address: client.wg_ip_address,
|
||||
allow_all_ips: client.allow_all_ips == 1,
|
||||
rules:
|
||||
client.id && typeof client.id == "number"
|
||||
? rules_by_client_id.get(client.id) || []
|
||||
|
||||
Reference in New Issue
Block a user