168 lines
4.1 KiB
JavaScript
168 lines
4.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
const {
|
|
deviceCidrs,
|
|
normalizeDeviceProfiles,
|
|
} = await import("../../src/server/devices.js");
|
|
const { matchRoute } = await import("../../src/server/routeMatcher.js");
|
|
const {
|
|
sourceBypassCidrs,
|
|
buildSourceBypassIptablesCommands,
|
|
} = await import("../../src/server/tproxySourceBypass.js");
|
|
const { settings } = await import("../../src/server/config.js");
|
|
|
|
test("default source bypass chain name fits iptables chain length limit", () => {
|
|
assert.equal(settings.tproxySourceBypassChain, "VPN_PROXY_SRC_BYPASS");
|
|
assert.equal(settings.tproxySourceForwardChain, "VPN_PROXY_FWD_BYPASS");
|
|
assert.equal(settings.tproxySourceNatChain, "VPN_PROXY_NAT_BYPASS");
|
|
assert.ok(settings.tproxySourceBypassChain.length <= 28);
|
|
assert.ok(settings.tproxySourceForwardChain.length <= 28);
|
|
assert.ok(settings.tproxySourceNatChain.length <= 28);
|
|
});
|
|
|
|
test("device profiles preserve bypass mode for kernel-level TProxy bypass", () => {
|
|
const profiles = normalizeDeviceProfiles({
|
|
devices: [
|
|
{
|
|
id: "pc",
|
|
name: "PC",
|
|
enabled: true,
|
|
ip: "192.168.50.25",
|
|
mode: "bypass",
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.equal(profiles.devices[0].mode, "bypass");
|
|
assert.deepEqual(deviceCidrs(profiles.devices, "bypass"), [
|
|
"192.168.50.25/32",
|
|
]);
|
|
});
|
|
|
|
test("route checker reports transparent bypass before sing-box rules", () => {
|
|
const result = matchRoute(
|
|
{
|
|
host: "example.com",
|
|
ip: "93.184.216.34",
|
|
sourceIp: "192.168.50.25",
|
|
inbound: "tproxy-in",
|
|
},
|
|
[
|
|
{
|
|
id: "vpn-all",
|
|
enabled: true,
|
|
name: "VPN all",
|
|
domains: ["example.com"],
|
|
outbound: "vpn",
|
|
},
|
|
],
|
|
{
|
|
vpnTag: "test-vpn",
|
|
deviceProfiles: {
|
|
defaultTransparentMode: "vpn",
|
|
proxyDefaultMode: "vpn",
|
|
devices: [
|
|
{
|
|
id: "pc",
|
|
name: "PC",
|
|
enabled: true,
|
|
ip: "192.168.50.25",
|
|
mode: "bypass",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
);
|
|
|
|
assert.equal(result.matched, "kernel-bypass");
|
|
assert.equal(result.ruleName, "PC -> bypass TProxy");
|
|
assert.equal(result.outbound, "direct");
|
|
});
|
|
|
|
test("source bypass sync combines env CIDRs and bypass-mode devices", () => {
|
|
const cidrs = sourceBypassCidrs(
|
|
{
|
|
devices: [
|
|
{ enabled: true, ip: "192.168.50.25", mode: "bypass" },
|
|
{ enabled: false, ip: "192.168.50.26", mode: "bypass" },
|
|
{ enabled: true, ip: "192.168.50.27", mode: "direct" },
|
|
],
|
|
},
|
|
"192.168.50.30/32",
|
|
);
|
|
|
|
assert.deepEqual(cidrs, ["192.168.50.30/32", "192.168.50.25/32"]);
|
|
});
|
|
|
|
test("source bypass iptables commands use ACCEPT inside the managed subchain", () => {
|
|
assert.deepEqual(
|
|
buildSourceBypassIptablesCommands(["192.168.50.25/32"], {
|
|
chain: "VPN_PROXY_SOURCE_BYPASS",
|
|
forwardChain: "VPN_PROXY_FWD_BYPASS",
|
|
natChain: "VPN_PROXY_NAT_BYPASS",
|
|
natBypassCidrs: ["10.0.0.0/8"],
|
|
}),
|
|
[
|
|
["-w", "-t", "mangle", "-F", "VPN_PROXY_SOURCE_BYPASS"],
|
|
["-w", "-F", "VPN_PROXY_FWD_BYPASS"],
|
|
["-w", "-t", "nat", "-F", "VPN_PROXY_NAT_BYPASS"],
|
|
[
|
|
"-w",
|
|
"-t",
|
|
"mangle",
|
|
"-A",
|
|
"VPN_PROXY_SOURCE_BYPASS",
|
|
"-s",
|
|
"192.168.50.25/32",
|
|
"-j",
|
|
"ACCEPT",
|
|
],
|
|
[
|
|
"-w",
|
|
"-A",
|
|
"VPN_PROXY_FWD_BYPASS",
|
|
"-s",
|
|
"192.168.50.25/32",
|
|
"-j",
|
|
"ACCEPT",
|
|
],
|
|
[
|
|
"-w",
|
|
"-A",
|
|
"VPN_PROXY_FWD_BYPASS",
|
|
"-d",
|
|
"192.168.50.25/32",
|
|
"-m",
|
|
"conntrack",
|
|
"--ctstate",
|
|
"RELATED,ESTABLISHED",
|
|
"-j",
|
|
"ACCEPT",
|
|
],
|
|
[
|
|
"-w",
|
|
"-t",
|
|
"nat",
|
|
"-A",
|
|
"VPN_PROXY_NAT_BYPASS",
|
|
"-d",
|
|
"10.0.0.0/8",
|
|
"-j",
|
|
"RETURN",
|
|
],
|
|
[
|
|
"-w",
|
|
"-t",
|
|
"nat",
|
|
"-A",
|
|
"VPN_PROXY_NAT_BYPASS",
|
|
"-s",
|
|
"192.168.50.25/32",
|
|
"-j",
|
|
"MASQUERADE",
|
|
],
|
|
],
|
|
);
|
|
});
|