125 lines
2.7 KiB
JavaScript
125 lines
2.7 KiB
JavaScript
import { spawnSync } from "node:child_process";
|
|
import { settings } from "./config.js";
|
|
import { deviceCidrs, normalizeCidr } from "./devices.js";
|
|
|
|
const DEFAULT_NAT_BYPASS_CIDRS =
|
|
"0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4";
|
|
|
|
function splitCidrs(value) {
|
|
return String(value || "")
|
|
.split(/[\s,]+/)
|
|
.map((item) => normalizeCidr(item))
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function unique(list) {
|
|
return [...new Set(list)];
|
|
}
|
|
|
|
export function sourceBypassCidrs(
|
|
profiles,
|
|
envCidrs = process.env.TPROXY_BYPASS_SOURCE_CIDRS || "",
|
|
) {
|
|
return unique([
|
|
...splitCidrs(envCidrs),
|
|
...deviceCidrs(profiles?.devices || [], "bypass"),
|
|
]);
|
|
}
|
|
|
|
export function buildSourceBypassIptablesCommands(
|
|
cidrs,
|
|
{
|
|
chain = settings.tproxySourceBypassChain,
|
|
forwardChain = settings.tproxySourceForwardChain,
|
|
natChain = settings.tproxySourceNatChain,
|
|
natBypassCidrs = splitCidrs(
|
|
process.env.BYPASS_CIDRS || DEFAULT_NAT_BYPASS_CIDRS,
|
|
),
|
|
} = {},
|
|
) {
|
|
return [
|
|
["-w", "-t", "mangle", "-F", chain],
|
|
["-w", "-F", forwardChain],
|
|
["-w", "-t", "nat", "-F", natChain],
|
|
...cidrs.map((cidr) => [
|
|
"-w",
|
|
"-t",
|
|
"mangle",
|
|
"-A",
|
|
chain,
|
|
"-s",
|
|
cidr,
|
|
"-j",
|
|
"ACCEPT",
|
|
]),
|
|
...cidrs.flatMap((cidr) => [
|
|
["-w", "-A", forwardChain, "-s", cidr, "-j", "ACCEPT"],
|
|
[
|
|
"-w",
|
|
"-A",
|
|
forwardChain,
|
|
"-d",
|
|
cidr,
|
|
"-m",
|
|
"conntrack",
|
|
"--ctstate",
|
|
"RELATED,ESTABLISHED",
|
|
"-j",
|
|
"ACCEPT",
|
|
],
|
|
]),
|
|
...natBypassCidrs.map((cidr) => [
|
|
"-w",
|
|
"-t",
|
|
"nat",
|
|
"-A",
|
|
natChain,
|
|
"-d",
|
|
cidr,
|
|
"-j",
|
|
"RETURN",
|
|
]),
|
|
...cidrs.map((cidr) => [
|
|
"-w",
|
|
"-t",
|
|
"nat",
|
|
"-A",
|
|
natChain,
|
|
"-s",
|
|
cidr,
|
|
"-j",
|
|
"MASQUERADE",
|
|
]),
|
|
];
|
|
}
|
|
|
|
export function syncTproxySourceBypass(profiles, options = {}) {
|
|
if (settings.appMode !== "gateway") {
|
|
return { success: true, skipped: true, cidrs: [] };
|
|
}
|
|
|
|
const cidrs = sourceBypassCidrs(
|
|
profiles,
|
|
options.envCidrs ?? process.env.TPROXY_BYPASS_SOURCE_CIDRS,
|
|
);
|
|
const commands = buildSourceBypassIptablesCommands(cidrs, options);
|
|
|
|
for (const args of commands) {
|
|
const result = spawnSync("iptables", args, {
|
|
encoding: "utf8",
|
|
timeout: 1000,
|
|
});
|
|
if (result.error || result.status !== 0) {
|
|
return {
|
|
success: false,
|
|
cidrs,
|
|
error:
|
|
result.error?.message ||
|
|
(result.stderr || result.stdout || "iptables command failed").trim(),
|
|
};
|
|
}
|
|
}
|
|
|
|
return { success: true, cidrs };
|
|
}
|