fix(core,nft,singbox,luci): resolve parental domain blocking priority, client bypass and CI apt hash mismatch
This commit is contained in:
@@ -41,6 +41,7 @@ jobs:
|
|||||||
- name: Build ucode
|
- name: Build ucode
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
sudo rm -f /etc/apt/sources.list.d/google-chrome.list
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential cmake git libjson-c-dev pkg-config nodejs curl
|
sudo apt-get install -y build-essential cmake git libjson-c-dev pkg-config nodejs curl
|
||||||
git clone --depth 1 --branch v0.0.20250529 https://github.com/jow-/ucode.git /tmp/ucode
|
git clone --depth 1 --branch v0.0.20250529 https://github.com/jow-/ucode.git /tmp/ucode
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install ShellCheck
|
- name: Install ShellCheck
|
||||||
run: |
|
run: |
|
||||||
|
sudo rm -f /etc/apt/sources.list.d/google-chrome.list
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y shellcheck
|
sudo apt-get install -y shellcheck
|
||||||
|
|
||||||
|
|||||||
@@ -133,12 +133,14 @@ ensure_host_deps() {
|
|||||||
|
|
||||||
echo "Installing missing host dependencies: ${APT_PACKAGES[*]}" >&2
|
echo "Installing missing host dependencies: ${APT_PACKAGES[*]}" >&2
|
||||||
if [[ "$(id -u)" -eq 0 ]]; then
|
if [[ "$(id -u)" -eq 0 ]]; then
|
||||||
|
rm -f /etc/apt/sources.list.d/google-chrome.list 2>/dev/null || true
|
||||||
apt-get update
|
apt-get update
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y "${APT_PACKAGES[@]}"
|
DEBIAN_FRONTEND=noninteractive apt-get install -y "${APT_PACKAGES[@]}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then
|
if command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then
|
||||||
|
sudo rm -f /etc/apt/sources.list.d/google-chrome.list 2>/dev/null || true
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "${APT_PACKAGES[@]}"
|
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "${APT_PACKAGES[@]}"
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -6295,3 +6295,21 @@ msgstr "Скачивание и обработка списков"
|
|||||||
|
|
||||||
msgid "Applying rules and subnet lists"
|
msgid "Applying rules and subnet lists"
|
||||||
msgstr "Применение правил и списков подсетей"
|
msgstr "Применение правил и списков подсетей"
|
||||||
|
|
||||||
|
msgid "Always Active (24/7)"
|
||||||
|
msgstr "Всегда активно (24/7)"
|
||||||
|
|
||||||
|
msgid "Active Hours Mode"
|
||||||
|
msgstr "Режим часов активности"
|
||||||
|
|
||||||
|
msgid "Choose whether this schedule rule is permanently active (24/7) or restricted to specific hours."
|
||||||
|
msgstr "Выберите, действует ли расписание круглосуточно (24/7) или только в заданные часы."
|
||||||
|
|
||||||
|
msgid "Scheduled Hours (Time window)"
|
||||||
|
msgstr "По расписанию (интервал времени)"
|
||||||
|
|
||||||
|
msgid "Allow always"
|
||||||
|
msgstr "Разрешено всегда"
|
||||||
|
|
||||||
|
msgid "Block always"
|
||||||
|
msgstr "Заблокировано всегда"
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ const DOMAIN_PRESETS = {
|
|||||||
|
|
||||||
function validateTime(sectionId, value) {
|
function validateTime(sectionId, value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return _("Time is required (e.g. 22:00)");
|
return true;
|
||||||
}
|
}
|
||||||
const str = `${value}`.trim();
|
const str = `${value}`.trim();
|
||||||
if (!/^([01][0-9]|2[0-3]):[0-5][0-9]$/.test(str)) {
|
if (!/^([01][0-9]|2[0-3]):[0-5][0-9]$/.test(str)) {
|
||||||
@@ -218,8 +218,8 @@ function isScheduleCurrentlyActive(sectionId) {
|
|||||||
const enabled = uci.get(UCI_PACKAGE, sectionId, "enabled") !== "0";
|
const enabled = uci.get(UCI_PACKAGE, sectionId, "enabled") !== "0";
|
||||||
if (!enabled) return false;
|
if (!enabled) return false;
|
||||||
|
|
||||||
const startTime = uci.get(UCI_PACKAGE, sectionId, "start_time") || "00:00";
|
const startTime = uci.get(UCI_PACKAGE, sectionId, "start_time");
|
||||||
const endTime = uci.get(UCI_PACKAGE, sectionId, "end_time") || "23:59";
|
const endTime = uci.get(UCI_PACKAGE, sectionId, "end_time");
|
||||||
const rawDays = uci.get(UCI_PACKAGE, sectionId, "days");
|
const rawDays = uci.get(UCI_PACKAGE, sectionId, "days");
|
||||||
const days = normalizeDays(rawDays);
|
const days = normalizeDays(rawDays);
|
||||||
|
|
||||||
@@ -230,10 +230,14 @@ function isScheduleCurrentlyActive(sectionId) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!startTime && !endTime) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const currentMinutes = now.getHours() * 60 + now.getMinutes();
|
const currentMinutes = now.getHours() * 60 + now.getMinutes();
|
||||||
|
|
||||||
const [sH, sM] = startTime.split(":").map(Number);
|
const [sH, sM] = (startTime || "00:00").split(":").map(Number);
|
||||||
const [eH, eM] = endTime.split(":").map(Number);
|
const [eH, eM] = (endTime || "23:59").split(":").map(Number);
|
||||||
const startMinutes = (sH || 0) * 60 + (sM || 0);
|
const startMinutes = (sH || 0) * 60 + (sM || 0);
|
||||||
const endMinutes = (eH || 0) * 60 + (eM || 0);
|
const endMinutes = (eH || 0) * 60 + (eM || 0);
|
||||||
|
|
||||||
@@ -822,22 +826,31 @@ function createParentalContent(section) {
|
|||||||
o.modalonly = false;
|
o.modalonly = false;
|
||||||
o.cfgvalue = function (sectionId) {
|
o.cfgvalue = function (sectionId) {
|
||||||
const action = uci.get(UCI_PACKAGE, sectionId, "action") || "block";
|
const action = uci.get(UCI_PACKAGE, sectionId, "action") || "block";
|
||||||
|
const s = uci.get(UCI_PACKAGE, sectionId, "start_time");
|
||||||
|
const e = uci.get(UCI_PACKAGE, sectionId, "end_time");
|
||||||
|
const is247 = !s && !e;
|
||||||
if (action === "allow") {
|
if (action === "allow") {
|
||||||
return (
|
return (
|
||||||
'<span style="color:var(--success-color-medium, #38a169);font-weight:500;">✅ ' +
|
'<span style="color:var(--success-color-medium, #38a169);font-weight:500;">✅ ' +
|
||||||
_("Allow in interval") +
|
(is247 ? _("Allow always") : _("Allow in interval")) +
|
||||||
"</span>"
|
"</span>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
'<span style="color:var(--error-color-medium, #e53e3e);font-weight:500;">🚫 ' +
|
'<span style="color:var(--error-color-medium, #e53e3e);font-weight:500;">🚫 ' +
|
||||||
_("Block in interval") +
|
(is247 ? _("Block always") : _("Block in interval")) +
|
||||||
"</span>"
|
"</span>"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
o.textvalue = function (sectionId) {
|
o.textvalue = function (sectionId) {
|
||||||
const action = uci.get(UCI_PACKAGE, sectionId, "action") || "block";
|
const action = uci.get(UCI_PACKAGE, sectionId, "action") || "block";
|
||||||
return action === "allow" ? _("Allow in interval") : _("Block in interval");
|
const s = uci.get(UCI_PACKAGE, sectionId, "start_time");
|
||||||
|
const e = uci.get(UCI_PACKAGE, sectionId, "end_time");
|
||||||
|
const is247 = !s && !e;
|
||||||
|
if (action === "allow") {
|
||||||
|
return is247 ? _("Allow always") : _("Allow in interval");
|
||||||
|
}
|
||||||
|
return is247 ? _("Block always") : _("Block in interval");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Schedule column in table
|
// Schedule column in table
|
||||||
@@ -845,24 +858,36 @@ function createParentalContent(section) {
|
|||||||
o.rawhtml = true;
|
o.rawhtml = true;
|
||||||
o.modalonly = false;
|
o.modalonly = false;
|
||||||
o.cfgvalue = function (sectionId) {
|
o.cfgvalue = function (sectionId) {
|
||||||
const s = uci.get(UCI_PACKAGE, sectionId, "start_time") || "00:00";
|
const s = uci.get(UCI_PACKAGE, sectionId, "start_time");
|
||||||
const e = uci.get(UCI_PACKAGE, sectionId, "end_time") || "23:59";
|
const e = uci.get(UCI_PACKAGE, sectionId, "end_time");
|
||||||
const days = formatDaysDisplay(uci.get(UCI_PACKAGE, sectionId, "days"));
|
const days = formatDaysDisplay(uci.get(UCI_PACKAGE, sectionId, "days"));
|
||||||
|
if (!s && !e) {
|
||||||
|
return (
|
||||||
|
'<div style="line-height:1.3;"><strong style="color:var(--success-color, #38a169);">⚡ ' +
|
||||||
|
_("Always Active (24/7)") +
|
||||||
|
'</strong><br><small style="opacity:0.75;">' +
|
||||||
|
days +
|
||||||
|
"</small></div>"
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
'<div style="line-height:1.3;"><strong style="color:inherit;">' +
|
'<div style="line-height:1.3;"><strong style="color:inherit;">' +
|
||||||
s +
|
(s || "00:00") +
|
||||||
" — " +
|
" — " +
|
||||||
e +
|
(e || "23:59") +
|
||||||
'</strong><br><small style="opacity:0.75;">' +
|
'</strong><br><small style="opacity:0.75;">' +
|
||||||
days +
|
days +
|
||||||
"</small></div>"
|
"</small></div>"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
o.textvalue = function (sectionId) {
|
o.textvalue = function (sectionId) {
|
||||||
const s = uci.get(UCI_PACKAGE, sectionId, "start_time") || "00:00";
|
const s = uci.get(UCI_PACKAGE, sectionId, "start_time");
|
||||||
const e = uci.get(UCI_PACKAGE, sectionId, "end_time") || "23:59";
|
const e = uci.get(UCI_PACKAGE, sectionId, "end_time");
|
||||||
const days = formatDaysDisplay(uci.get(UCI_PACKAGE, sectionId, "days"));
|
const days = formatDaysDisplay(uci.get(UCI_PACKAGE, sectionId, "days"));
|
||||||
return `${s} - ${e}, ${days}`;
|
if (!s && !e) {
|
||||||
|
return `${_("Always Active (24/7)")}, ${days}`;
|
||||||
|
}
|
||||||
|
return `${s || "00:00"} - ${e || "23:59"}, ${days}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Daily quota column in table
|
// Daily quota column in table
|
||||||
@@ -1091,6 +1116,31 @@ function createParentalContent(section) {
|
|||||||
o.value("block", _("Block / Disable in scheduled hours (Standard)"));
|
o.value("block", _("Block / Disable in scheduled hours (Standard)"));
|
||||||
o.value("allow", _("Allow / Enable ONLY in scheduled hours (White period)"));
|
o.value("allow", _("Allow / Enable ONLY in scheduled hours (White period)"));
|
||||||
|
|
||||||
|
// Schedule Active Hours Mode (24/7 vs Specific Time Window)
|
||||||
|
o = section.option(
|
||||||
|
form.ListValue,
|
||||||
|
"_time_mode",
|
||||||
|
_("Active Hours Mode"),
|
||||||
|
_(
|
||||||
|
"Choose whether this schedule rule is permanently active (24/7) or restricted to specific hours.",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
o.modalonly = true;
|
||||||
|
o.default = "always";
|
||||||
|
o.value("always", _("Always Active (24/7)"));
|
||||||
|
o.value("interval", _("Scheduled Hours (Time window)"));
|
||||||
|
o.cfgvalue = function (sectionId) {
|
||||||
|
const s = uci.get(UCI_PACKAGE, sectionId, "start_time");
|
||||||
|
const e = uci.get(UCI_PACKAGE, sectionId, "end_time");
|
||||||
|
return s || e ? "interval" : "always";
|
||||||
|
};
|
||||||
|
o.write = function (sectionId, value) {
|
||||||
|
if (value === "always") {
|
||||||
|
uci.unset(UCI_PACKAGE, sectionId, "start_time");
|
||||||
|
uci.unset(UCI_PACKAGE, sectionId, "end_time");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Start Time
|
// Start Time
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Value,
|
form.Value,
|
||||||
@@ -1099,8 +1149,10 @@ function createParentalContent(section) {
|
|||||||
_("Beginning of the schedule interval (e.g. 22:00)"),
|
_("Beginning of the schedule interval (e.g. 22:00)"),
|
||||||
);
|
);
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
|
o.depends("_time_mode", "interval");
|
||||||
o.default = "22:00";
|
o.default = "22:00";
|
||||||
o.placeholder = "22:00";
|
o.placeholder = "22:00";
|
||||||
|
o.rmempty = true;
|
||||||
o.validate = validateTime;
|
o.validate = validateTime;
|
||||||
|
|
||||||
// End Time
|
// End Time
|
||||||
@@ -1113,8 +1165,10 @@ function createParentalContent(section) {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
|
o.depends("_time_mode", "interval");
|
||||||
o.default = "08:00";
|
o.default = "08:00";
|
||||||
o.placeholder = "08:00";
|
o.placeholder = "08:00";
|
||||||
|
o.rmempty = true;
|
||||||
o.validate = validateTime;
|
o.validate = validateTime;
|
||||||
|
|
||||||
// Days of week
|
// Days of week
|
||||||
|
|||||||
@@ -6295,3 +6295,21 @@ msgstr "Скачивание и обработка списков"
|
|||||||
|
|
||||||
msgid "Applying rules and subnet lists"
|
msgid "Applying rules and subnet lists"
|
||||||
msgstr "Применение правил и списков подсетей"
|
msgstr "Применение правил и списков подсетей"
|
||||||
|
|
||||||
|
msgid "Always Active (24/7)"
|
||||||
|
msgstr "Всегда активно (24/7)"
|
||||||
|
|
||||||
|
msgid "Active Hours Mode"
|
||||||
|
msgstr "Режим часов активности"
|
||||||
|
|
||||||
|
msgid "Choose whether this schedule rule is permanently active (24/7) or restricted to specific hours."
|
||||||
|
msgstr "Выберите, действует ли расписание круглосуточно (24/7) или только в заданные часы."
|
||||||
|
|
||||||
|
msgid "Scheduled Hours (Time window)"
|
||||||
|
msgstr "По расписанию (интервал времени)"
|
||||||
|
|
||||||
|
msgid "Allow always"
|
||||||
|
msgstr "Разрешено всегда"
|
||||||
|
|
||||||
|
msgid "Block always"
|
||||||
|
msgstr "Заблокировано всегда"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env ucode
|
#!/usr/bin/env ucode
|
||||||
|
|
||||||
|
let fs = require("fs");
|
||||||
let common = require("core.common");
|
let common = require("core.common");
|
||||||
let as_string = common.as_string;
|
let as_string = common.as_string;
|
||||||
|
|
||||||
@@ -143,6 +144,77 @@ function ipv6_supported() {
|
|||||||
return common.ipv6_supported();
|
return common.ipv6_supported();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolve_mac_to_ips(mac) {
|
||||||
|
mac = lc(replace(trim(as_string(mac)), "-", ":"));
|
||||||
|
if (mac == "")
|
||||||
|
return [];
|
||||||
|
let matched = [];
|
||||||
|
let seen = {};
|
||||||
|
|
||||||
|
let lease_files = [ "/tmp/dhcp.leases", "/var/lib/misc/dnsmasq.leases", "/tmp/hosts/dhcp" ];
|
||||||
|
for (let lpath in lease_files) {
|
||||||
|
let data = fs.readfile(lpath);
|
||||||
|
if (!data)
|
||||||
|
continue;
|
||||||
|
for (let line in split(as_string(data), "\n")) {
|
||||||
|
line = trim(line);
|
||||||
|
if (line == "" || index(line, "#") == 0)
|
||||||
|
continue;
|
||||||
|
let fields = split(line, /[ \t]+/);
|
||||||
|
if (length(fields) >= 3) {
|
||||||
|
let m = lc(replace(fields[1], "-", ":"));
|
||||||
|
let ip = fields[2];
|
||||||
|
if (m == mac && valid_ip(ip) && !seen[ip]) {
|
||||||
|
seen[ip] = true;
|
||||||
|
push(matched, ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let arp_data = fs.readfile("/proc/net/arp");
|
||||||
|
if (arp_data) {
|
||||||
|
for (let line in split(as_string(arp_data), "\n")) {
|
||||||
|
line = trim(line);
|
||||||
|
if (line == "" || index(line, "IP address") == 0)
|
||||||
|
continue;
|
||||||
|
let fields = split(line, /[ \t]+/);
|
||||||
|
if (length(fields) >= 4) {
|
||||||
|
let ip = fields[0];
|
||||||
|
let m = lc(replace(fields[3], "-", ":"));
|
||||||
|
if (m == mac && valid_ip(ip) && !seen[ip]) {
|
||||||
|
seen[ip] = true;
|
||||||
|
push(matched, ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let uci_core = require("core.uci");
|
||||||
|
let cursor = uci_core ? uci_core.cursor() : null;
|
||||||
|
if (cursor) {
|
||||||
|
cursor.load("dhcp");
|
||||||
|
cursor.foreach("dhcp", "host", function(host) {
|
||||||
|
let m_list = host.mac;
|
||||||
|
if (type(m_list) != "array")
|
||||||
|
m_list = [ m_list ];
|
||||||
|
for (let m in m_list) {
|
||||||
|
if (lc(replace(trim(as_string(m)), "-", ":")) == mac) {
|
||||||
|
let ip = host.ip;
|
||||||
|
if (ip && valid_ip(ip) && !seen[ip]) {
|
||||||
|
seen[ip] = true;
|
||||||
|
push(matched, ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
valid_ipv4,
|
valid_ipv4,
|
||||||
valid_ipv4_cidr,
|
valid_ipv4_cidr,
|
||||||
@@ -154,5 +226,6 @@ return {
|
|||||||
nft_ip_or_cidr,
|
nft_ip_or_cidr,
|
||||||
ip_family,
|
ip_family,
|
||||||
format_ipv6_tproxy_target,
|
format_ipv6_tproxy_target,
|
||||||
ipv6_supported
|
ipv6_supported,
|
||||||
|
resolve_mac_to_ips
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1504,6 +1504,51 @@ function nft_create_runtime_base(table, localv4_set, common_set, port_set, ip_po
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let excluded_clients_list = [];
|
||||||
|
append_array(excluded_clients_list, list_option(uci_settings(), "excluded_clients"));
|
||||||
|
append_array(excluded_clients_list, list_option(uci_settings(), "excluded_ips"));
|
||||||
|
if (length(excluded_clients_list) > 0) {
|
||||||
|
let exc_v4 = [];
|
||||||
|
let exc_v6 = [];
|
||||||
|
let exc_mac = [];
|
||||||
|
for (let item in excluded_clients_list) {
|
||||||
|
let val = trim(as_string(item));
|
||||||
|
if (val == "") continue;
|
||||||
|
let is_mac = match(val, /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/) != null;
|
||||||
|
if (is_mac) {
|
||||||
|
push(exc_mac, lc(replace(val, "-", ":")));
|
||||||
|
for (let res_ip in core_ip.resolve_mac_to_ips(val)) {
|
||||||
|
if (core_ip.ip_family(res_ip) == 4) push(exc_v4, res_ip);
|
||||||
|
else if (core_ip.ip_family(res_ip) == 6) push(exc_v6, res_ip);
|
||||||
|
}
|
||||||
|
} else if (core_ip.ip_family(val) == 4 || (core_ip.valid_ip_cidr(val) && index(val, ":") == -1)) {
|
||||||
|
push(exc_v4, val);
|
||||||
|
} else if (core_ip.ip_family(val) == 6 || (core_ip.valid_ip_cidr(val) && index(val, ":") != -1)) {
|
||||||
|
push(exc_v6, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let mac in exc_mac) {
|
||||||
|
if (!nft_add_rule(table, "mangle", [ "iifname", "@" + as_string(interface_set), "ether", "saddr", mac, "counter", "return" ]))
|
||||||
|
return false;
|
||||||
|
if (!nft_add_rule(table, "dns_redirect", [ "iifname", "@" + as_string(interface_set), "ether", "saddr", mac, "counter", "return" ]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (length(exc_v4) > 0) {
|
||||||
|
if (!nft_create_ipv4_set(table, "tachyon_excluded") ||
|
||||||
|
!nft_add_set_elements(table, "tachyon_excluded", join(",", exc_v4)) ||
|
||||||
|
!nft_add_rule(table, "mangle", [ "iifname", "@" + as_string(interface_set), "ip", "saddr", "@tachyon_excluded", "counter", "return" ]) ||
|
||||||
|
!nft_add_rule(table, "dns_redirect", [ "iifname", "@" + as_string(interface_set), "ip", "saddr", "@tachyon_excluded", "counter", "return" ]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (length(exc_v6) > 0) {
|
||||||
|
if (!nft_create_ipv6_set(table, "tachyon_excluded6") ||
|
||||||
|
!nft_add_set_elements(table, "tachyon_excluded6", join(",", exc_v6)) ||
|
||||||
|
!nft_add_rule(table, "mangle", [ "iifname", "@" + as_string(interface_set), "ip6", "saddr", "@tachyon_excluded6", "counter", "return" ]) ||
|
||||||
|
!nft_add_rule(table, "dns_redirect", [ "iifname", "@" + as_string(interface_set), "ip6", "saddr", "@tachyon_excluded6", "counter", "return" ]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!nft_add_rule(table, "mangle", [ "jump", "priority_rules" ]) ||
|
if (!nft_add_rule(table, "mangle", [ "jump", "priority_rules" ]) ||
|
||||||
!nft_add_rule(table, "mangle", [ "iifname", "@" + as_string(interface_set), "ip", "daddr", "@" + as_string(common_set), "meta", "l4proto", "tcp", "meta", "mark", "set", fakeip_mark, "counter" ]) ||
|
!nft_add_rule(table, "mangle", [ "iifname", "@" + as_string(interface_set), "ip", "daddr", "@" + as_string(common_set), "meta", "l4proto", "tcp", "meta", "mark", "set", fakeip_mark, "counter" ]) ||
|
||||||
!nft_add_rule(table, "mangle", [ "iifname", "@" + as_string(interface_set), "ip", "daddr", "@" + as_string(common_set), "meta", "l4proto", "udp", "meta", "mark", "set", fakeip_mark, "counter" ]) ||
|
!nft_add_rule(table, "mangle", [ "iifname", "@" + as_string(interface_set), "ip", "daddr", "@" + as_string(common_set), "meta", "l4proto", "udp", "meta", "mark", "set", fakeip_mark, "counter" ]) ||
|
||||||
@@ -2335,6 +2380,8 @@ function nft_runtime_signature_from_settings_and_sections(settings, sections, sc
|
|||||||
body = signature_add_value(body, "settings.exclude_ntp", bool_option(settings, "exclude_ntp", false) ? "1" : "0");
|
body = signature_add_value(body, "settings.exclude_ntp", bool_option(settings, "exclude_ntp", false) ? "1" : "0");
|
||||||
body = signature_add_value(body, "settings.game_console_optimizer", option(settings, "game_console_optimizer", "0"));
|
body = signature_add_value(body, "settings.game_console_optimizer", option(settings, "game_console_optimizer", "0"));
|
||||||
body = signature_add_value(body, "settings.game_console_ips", option(settings, "game_console_ips", ""));
|
body = signature_add_value(body, "settings.game_console_ips", option(settings, "game_console_ips", ""));
|
||||||
|
body = signature_add_value(body, "settings.excluded_clients", option(settings, "excluded_clients", ""));
|
||||||
|
body = signature_add_value(body, "settings.excluded_ips", option(settings, "excluded_ips", ""));
|
||||||
|
|
||||||
for (let section in sections)
|
for (let section in sections)
|
||||||
body = nft_rule_signature_body(body, object_or_empty(section));
|
body = nft_rule_signature_body(body, object_or_empty(section));
|
||||||
@@ -2654,6 +2701,12 @@ function source_aware_dns_values(sections, deferred_sections) {
|
|||||||
push(values, value);
|
push(values, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (let value in nft_csv_values(section_source_ip_values(section))) {
|
||||||
|
if (!seen[value]) {
|
||||||
|
seen[value] = true;
|
||||||
|
push(values, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == "dns") {
|
if (action == "dns") {
|
||||||
@@ -2666,6 +2719,27 @@ function source_aware_dns_values(sections, deferred_sections) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let settings = uci_settings();
|
||||||
|
let exc_items = [];
|
||||||
|
append_array(exc_items, list_option(settings, "excluded_clients"));
|
||||||
|
append_array(exc_items, list_option(settings, "excluded_ips"));
|
||||||
|
for (let item in exc_items) {
|
||||||
|
let val = trim(as_string(item));
|
||||||
|
if (val == "") continue;
|
||||||
|
let is_mac = match(val, /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/) != null;
|
||||||
|
if (is_mac) {
|
||||||
|
for (let res_ip in core_ip.resolve_mac_to_ips(val)) {
|
||||||
|
if (!seen[res_ip]) {
|
||||||
|
seen[res_ip] = true;
|
||||||
|
push(values, res_ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!seen[val]) {
|
||||||
|
seen[val] = true;
|
||||||
|
push(values, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -935,6 +935,8 @@ function nft_runtime_signature_body(settings, sections) {
|
|||||||
body = signature_add_value(body, "settings.exclude_ntp", bool_option(settings, "exclude_ntp", false) ? "1" : "0");
|
body = signature_add_value(body, "settings.exclude_ntp", bool_option(settings, "exclude_ntp", false) ? "1" : "0");
|
||||||
body = signature_add_value(body, "settings.game_console_optimizer", option(settings, "game_console_optimizer", "0"));
|
body = signature_add_value(body, "settings.game_console_optimizer", option(settings, "game_console_optimizer", "0"));
|
||||||
body = signature_add_value(body, "settings.game_console_ips", option(settings, "game_console_ips", ""));
|
body = signature_add_value(body, "settings.game_console_ips", option(settings, "game_console_ips", ""));
|
||||||
|
body = signature_add_value(body, "settings.excluded_clients", option(settings, "excluded_clients", ""));
|
||||||
|
body = signature_add_value(body, "settings.excluded_ips", option(settings, "excluded_ips", ""));
|
||||||
|
|
||||||
for (let section in sections) {
|
for (let section in sections) {
|
||||||
section = object_or_empty(section);
|
section = object_or_empty(section);
|
||||||
|
|||||||
@@ -773,6 +773,10 @@ function schedule_has_time_window(schedule) {
|
|||||||
trim(option(schedule, "end_time", "")) != "";
|
trim(option(schedule, "end_time", "")) != "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolve_mac_to_ips(mac) {
|
||||||
|
return core_ip.resolve_mac_to_ips(mac);
|
||||||
|
}
|
||||||
|
|
||||||
function profile_source_ip_cidrs(profile) {
|
function profile_source_ip_cidrs(profile) {
|
||||||
let result = [];
|
let result = [];
|
||||||
for (let raw in schedule_list_value(profile, "device_ip")) {
|
for (let raw in schedule_list_value(profile, "device_ip")) {
|
||||||
@@ -780,8 +784,14 @@ function profile_source_ip_cidrs(profile) {
|
|||||||
if (device == "")
|
if (device == "")
|
||||||
continue;
|
continue;
|
||||||
let is_mac = match(device, /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/) != null;
|
let is_mac = match(device, /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/) != null;
|
||||||
if (is_mac)
|
if (is_mac) {
|
||||||
|
for (let ip in resolve_mac_to_ips(device)) {
|
||||||
|
let cidr = core_ip.valid_ipv6(ip) ? ip + "/128" : ip + "/32";
|
||||||
|
if (index(result, cidr) < 0)
|
||||||
|
push(result, cidr);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (core_ip.valid_ip(device)) {
|
if (core_ip.valid_ip(device)) {
|
||||||
let cidr = core_ip.valid_ipv6(device) ? device + "/128" : device + "/32";
|
let cidr = core_ip.valid_ipv6(device) ? device + "/128" : device + "/32";
|
||||||
if (index(result, cidr) < 0) push(result, cidr);
|
if (index(result, cidr) < 0) push(result, cidr);
|
||||||
@@ -799,8 +809,14 @@ function schedule_source_ip_cidrs(schedule) {
|
|||||||
if (device == "")
|
if (device == "")
|
||||||
continue;
|
continue;
|
||||||
let is_mac = match(device, /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/) != null;
|
let is_mac = match(device, /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/) != null;
|
||||||
if (is_mac)
|
if (is_mac) {
|
||||||
|
for (let ip in resolve_mac_to_ips(device)) {
|
||||||
|
let cidr = core_ip.valid_ipv6(ip) ? ip + "/128" : ip + "/32";
|
||||||
|
if (index(result, cidr) < 0)
|
||||||
|
push(result, cidr);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (core_ip.valid_ip(device)) {
|
if (core_ip.valid_ip(device)) {
|
||||||
let cidr = core_ip.valid_ipv6(device) ? device + "/128" : device + "/32";
|
let cidr = core_ip.valid_ipv6(device) ? device + "/128" : device + "/32";
|
||||||
if (index(result, cidr) < 0) push(result, cidr);
|
if (index(result, cidr) < 0) push(result, cidr);
|
||||||
@@ -907,10 +923,14 @@ function enabled_safesearch_profiles() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_safesearch_dns_rules(config, profiles) {
|
function add_safesearch_dns_rules(target, profiles) {
|
||||||
if (length(profiles) == 0)
|
if (length(profiles) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
let rules_arr = (type(target) == "object" && type(target.dns) == "object" && type(target.dns.rules) == "array")
|
||||||
|
? target.dns.rules
|
||||||
|
: target;
|
||||||
|
|
||||||
let all_sources = [];
|
let all_sources = [];
|
||||||
for (let profile in profiles) {
|
for (let profile in profiles) {
|
||||||
for (let cidr in profile_source_ip_cidrs(profile)) {
|
for (let cidr in profile_source_ip_cidrs(profile)) {
|
||||||
@@ -951,7 +971,7 @@ function add_safesearch_dns_rules(config, profiles) {
|
|||||||
};
|
};
|
||||||
if (length(all_sources) > 0)
|
if (length(all_sources) > 0)
|
||||||
rule.source_ip_cidr = all_sources;
|
rule.source_ip_cidr = all_sources;
|
||||||
push(config.dns.rules, rule);
|
push(rules_arr, rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -965,7 +985,10 @@ function add_content_block_dns_inbound(config) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_content_block_dns_rules(config, schedules) {
|
function add_content_block_dns_rules(target, schedules) {
|
||||||
|
let rules_arr = (type(target) == "object" && type(target.dns) == "object" && type(target.dns.rules) == "array")
|
||||||
|
? target.dns.rules
|
||||||
|
: target;
|
||||||
let added = false;
|
let added = false;
|
||||||
for (let schedule in schedules) {
|
for (let schedule in schedules) {
|
||||||
let mode = option(schedule, "mode", "block");
|
let mode = option(schedule, "mode", "block");
|
||||||
@@ -989,14 +1012,17 @@ function add_content_block_dns_rules(config, schedules) {
|
|||||||
rule.source_ip_cidr = sources;
|
rule.source_ip_cidr = sources;
|
||||||
if (mode == "allow")
|
if (mode == "allow")
|
||||||
rule.invert = true;
|
rule.invert = true;
|
||||||
push(config.dns.rules, rule);
|
push(rules_arr, rule);
|
||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_content_block_route_rules(config, schedules) {
|
function add_content_block_route_rules(target, schedules) {
|
||||||
|
let rules_arr = (type(target) == "object" && type(target.route) == "object" && type(target.route.rules) == "array")
|
||||||
|
? target.route.rules
|
||||||
|
: target;
|
||||||
for (let schedule in schedules) {
|
for (let schedule in schedules) {
|
||||||
if (schedule_has_time_window(schedule))
|
if (schedule_has_time_window(schedule))
|
||||||
continue;
|
continue;
|
||||||
@@ -1012,7 +1038,7 @@ function add_content_block_route_rules(config, schedules) {
|
|||||||
rule.source_ip_cidr = sources;
|
rule.source_ip_cidr = sources;
|
||||||
if (mode == "allow")
|
if (mode == "allow")
|
||||||
rule.invert = true;
|
rule.invert = true;
|
||||||
push(config.route.rules, rule);
|
push(rules_arr, rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1029,11 +1055,25 @@ function add_content_blocking(config) {
|
|||||||
action: "hijack-dns",
|
action: "hijack-dns",
|
||||||
inbound: [ runtime_constants.DNS_BLOCK_INBOUND_TAG ]
|
inbound: [ runtime_constants.DNS_BLOCK_INBOUND_TAG ]
|
||||||
});
|
});
|
||||||
add_content_block_dns_rules(config, schedules);
|
|
||||||
add_content_block_dns_rules(config, profiles);
|
let new_dns_rules = [];
|
||||||
add_safesearch_dns_rules(config, safesearch_profiles);
|
add_content_block_dns_rules(new_dns_rules, schedules);
|
||||||
add_content_block_route_rules(config, schedules);
|
add_content_block_dns_rules(new_dns_rules, profiles);
|
||||||
add_content_block_route_rules(config, profiles);
|
add_safesearch_dns_rules(new_dns_rules, safesearch_profiles);
|
||||||
|
|
||||||
|
// Place content blocking DNS rules at the front of config.dns.rules so
|
||||||
|
// queries on dns-block-in are rejected before any section FakeIP rule matches!
|
||||||
|
for (let i = length(new_dns_rules) - 1; i >= 0; i--)
|
||||||
|
unshift(config.dns.rules, new_dns_rules[i]);
|
||||||
|
|
||||||
|
let new_route_rules = [];
|
||||||
|
add_content_block_route_rules(new_route_rules, schedules);
|
||||||
|
add_content_block_route_rules(new_route_rules, profiles);
|
||||||
|
|
||||||
|
// Insert content blocking route rules right after hijack-dns (index 1)
|
||||||
|
// so sniffed domains from blocked clients are rejected before any section proxy route matches!
|
||||||
|
for (let i = length(new_route_rules) - 1; i >= 0; i--)
|
||||||
|
splice(config.route.rules, 1, 0, new_route_rules[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function single_or_array(values) {
|
function single_or_array(values) {
|
||||||
@@ -1044,7 +1084,48 @@ function single_or_array(values) {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
function source_aware_dns_sources(sections) {
|
function get_excluded_client_cidrs(settings) {
|
||||||
|
let result = [];
|
||||||
|
let seen = {};
|
||||||
|
let add_cidr = function(ip) {
|
||||||
|
ip = trim(as_string(ip));
|
||||||
|
if (ip == "") return;
|
||||||
|
let is_mac = match(ip, /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/) != null;
|
||||||
|
if (is_mac) {
|
||||||
|
for (let res_ip in resolve_mac_to_ips(ip)) {
|
||||||
|
let cidr = core_ip.valid_ipv6(res_ip) ? res_ip + "/128" : res_ip + "/32";
|
||||||
|
if (!seen[cidr]) {
|
||||||
|
seen[cidr] = true;
|
||||||
|
push(result, cidr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (core_ip.valid_ip(ip)) {
|
||||||
|
let cidr = core_ip.valid_ipv6(ip) ? ip + "/128" : ip + "/32";
|
||||||
|
if (!seen[cidr]) {
|
||||||
|
seen[cidr] = true;
|
||||||
|
push(result, cidr);
|
||||||
|
}
|
||||||
|
} else if (core_ip.valid_ip_cidr(ip)) {
|
||||||
|
if (!seen[ip]) {
|
||||||
|
seen[ip] = true;
|
||||||
|
push(result, ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (settings) {
|
||||||
|
for (let item in list_option(settings, "excluded_clients"))
|
||||||
|
add_cidr(item);
|
||||||
|
for (let item in list_option(settings, "excluded_ips"))
|
||||||
|
add_cidr(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function source_aware_dns_sources(sections, settings) {
|
||||||
let sources = [];
|
let sources = [];
|
||||||
let seen = {};
|
let seen = {};
|
||||||
let add_source = function(value) {
|
let add_source = function(value) {
|
||||||
@@ -1055,6 +1136,11 @@ function source_aware_dns_sources(sections) {
|
|||||||
push(sources, value);
|
push(sources, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (settings) {
|
||||||
|
for (let cidr in get_excluded_client_cidrs(settings))
|
||||||
|
add_source(cidr);
|
||||||
|
}
|
||||||
|
|
||||||
for (let section in sections) {
|
for (let section in sections) {
|
||||||
let action = option(section, "action", "");
|
let action = option(section, "action", "");
|
||||||
let has_dns_matchers = connections.has_dns_matchers(section);
|
let has_dns_matchers = connections.has_dns_matchers(section);
|
||||||
@@ -1067,6 +1153,8 @@ function source_aware_dns_sources(sections) {
|
|||||||
if (action == "bypass") {
|
if (action == "bypass") {
|
||||||
for (let ip in list_option(section, "fully_routed_ips"))
|
for (let ip in list_option(section, "fully_routed_ips"))
|
||||||
add_source(ip);
|
add_source(ip);
|
||||||
|
for (let ip in list_option(section, "source_ip_cidr"))
|
||||||
|
add_source(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == "dns") {
|
if (action == "dns") {
|
||||||
@@ -1099,12 +1187,25 @@ function add_source_aware_dns_fallback(config, source_aware_dns) {
|
|||||||
let settings = runtime_settings_cache || {};
|
let settings = runtime_settings_cache || {};
|
||||||
let rewrite_ttl = int_option(settings, "dns_rewrite_ttl", "60");
|
let rewrite_ttl = int_option(settings, "dns_rewrite_ttl", "60");
|
||||||
|
|
||||||
push(config.dns.rules, {
|
let rule = {
|
||||||
action: "route",
|
action: "route",
|
||||||
server: runtime_constants.DNSMASQ_DNS_SERVER_TAG,
|
server: runtime_constants.DNSMASQ_DNS_SERVER_TAG,
|
||||||
inbound: [ runtime_constants.SOURCE_DNS_INBOUND_TAG ],
|
inbound: [ runtime_constants.SOURCE_DNS_INBOUND_TAG ],
|
||||||
source_ip_cidr: single_or_array(source_aware_dns),
|
source_ip_cidr: single_or_array(source_aware_dns),
|
||||||
rewrite_ttl
|
rewrite_ttl
|
||||||
|
};
|
||||||
|
unshift(config.dns.rules, rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_excluded_clients_route_rule(config, settings) {
|
||||||
|
let excluded_cidrs = get_excluded_client_cidrs(settings);
|
||||||
|
if (length(excluded_cidrs) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
splice(config.route.rules, 1, 0, {
|
||||||
|
action: "route",
|
||||||
|
outbound: runtime_constants.BYPASS_OUTBOUND_TAG,
|
||||||
|
source_ip_cidr: single_or_array(excluded_cidrs)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1124,7 +1225,7 @@ function generate_config(output_path, service_address, mwan3_active, supports_xh
|
|||||||
if (length(sections) == 0 && length(servers) == 0)
|
if (length(sections) == 0 && length(servers) == 0)
|
||||||
runtime_generate_unsupported("no enabled sections");
|
runtime_generate_unsupported("no enabled sections");
|
||||||
|
|
||||||
let source_aware_dns = source_aware_dns_sources(sections);
|
let source_aware_dns = source_aware_dns_sources(sections, settings);
|
||||||
let config = base_config(settings, service_address, {
|
let config = base_config(settings, service_address, {
|
||||||
mwan3_active: cli_bool(mwan3_active),
|
mwan3_active: cli_bool(mwan3_active),
|
||||||
source_aware_dns: length(source_aware_dns) > 0
|
source_aware_dns: length(source_aware_dns) > 0
|
||||||
@@ -1137,10 +1238,22 @@ function generate_config(output_path, service_address, mwan3_active, supports_xh
|
|||||||
for (let section in sections)
|
for (let section in sections)
|
||||||
add_outbound_for_section(config, section, taken, sections);
|
add_outbound_for_section(config, section, taken, sections);
|
||||||
add_service_route_rules(config, sections);
|
add_service_route_rules(config, sections);
|
||||||
for (let section in sections)
|
|
||||||
add_route_for_section(config, section);
|
// Add block and bypass sections before proxy sections so exceptions take precedence
|
||||||
|
for (let section in sections) {
|
||||||
|
let act = option(section, "action", "");
|
||||||
|
if (act == "block" || act == "bypass")
|
||||||
|
add_route_for_section(config, section);
|
||||||
|
}
|
||||||
|
for (let section in sections) {
|
||||||
|
let act = option(section, "action", "");
|
||||||
|
if (act != "block" && act != "bypass")
|
||||||
|
add_route_for_section(config, section);
|
||||||
|
}
|
||||||
|
|
||||||
add_server_routes(config, servers, sections);
|
add_server_routes(config, servers, sections);
|
||||||
add_source_aware_dns_fallback(config, source_aware_dns);
|
add_source_aware_dns_fallback(config, source_aware_dns);
|
||||||
|
add_excluded_clients_route_rule(config, settings);
|
||||||
|
|
||||||
// Append dns_hosts predefined rules AFTER section DNS rules so that
|
// Append dns_hosts predefined rules AFTER section DNS rules so that
|
||||||
// FakeIP/section-level DNS routing takes precedence over hardcoded IPs
|
// FakeIP/section-level DNS routing takes precedence over hardcoded IPs
|
||||||
|
|||||||
@@ -676,6 +676,10 @@ br-lan tun0
|
|||||||
0
|
0
|
||||||
[settings.game_console_ips]
|
[settings.game_console_ips]
|
||||||
|
|
||||||
|
[settings.excluded_clients]
|
||||||
|
|
||||||
|
[settings.excluded_ips]
|
||||||
|
|
||||||
[rule.text_rule.action]
|
[rule.text_rule.action]
|
||||||
bypass
|
bypass
|
||||||
[rule.text_rule.ip_cidr]
|
[rule.text_rule.ip_cidr]
|
||||||
@@ -766,6 +770,10 @@ br-lan tun0
|
|||||||
0
|
0
|
||||||
[settings.game_console_ips]
|
[settings.game_console_ips]
|
||||||
|
|
||||||
|
[settings.excluded_clients]
|
||||||
|
|
||||||
|
[settings.excluded_ips]
|
||||||
|
|
||||||
[rule.enabled.action]
|
[rule.enabled.action]
|
||||||
bypass
|
bypass
|
||||||
[rule.enabled.ip_cidr]
|
[rule.enabled.ip_cidr]
|
||||||
@@ -812,12 +820,28 @@ br-lan
|
|||||||
0
|
0
|
||||||
[settings.game_console_ips]
|
[settings.game_console_ips]
|
||||||
|
|
||||||
|
[settings.excluded_clients]
|
||||||
|
|
||||||
|
[settings.excluded_ips]
|
||||||
|
|
||||||
EOF_EXPECTED
|
EOF_EXPECTED
|
||||||
expected_signature="$(md5sum "$WORK_DIR/signature-defaults-expected.txt" | awk '{print $1}')"
|
expected_signature="$(md5sum "$WORK_DIR/signature-defaults-expected.txt" | awk '{print $1}')"
|
||||||
assert_eq "$expected_signature" \
|
assert_eq "$expected_signature" \
|
||||||
"$(nft_ucode nft-runtime-signature-fixture "$WORK_DIR/signature-defaults-fixture.json")" \
|
"$(nft_ucode nft-runtime-signature-fixture "$WORK_DIR/signature-defaults-fixture.json")" \
|
||||||
"nft runtime signature defaults"
|
"nft runtime signature defaults"
|
||||||
|
|
||||||
|
cat >"$WORK_DIR/signature-excluded-clients-fixture.json" <<'JSON'
|
||||||
|
{
|
||||||
|
"settings": {
|
||||||
|
"excluded_clients": "192.168.1.50 00:11:22:33:44:55"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JSON
|
||||||
|
sig_with_excluded="$(nft_ucode nft-runtime-signature-fixture "$WORK_DIR/signature-excluded-clients-fixture.json")"
|
||||||
|
if [ "$sig_with_excluded" = "$expected_signature" ]; then
|
||||||
|
fail "nft runtime signature must change when excluded_clients is set"
|
||||||
|
fi
|
||||||
|
|
||||||
: > "$NFT_LOG"
|
: > "$NFT_LOG"
|
||||||
nft_ucode nft-populate-runtime-sets-fixture "$WORK_DIR/populate-fixture.json" 0 "" TachyonTable tachyon_subnets tachyon_ports tachyon_ip_ports tachyon_interfaces localv4 0x00100000
|
nft_ucode nft-populate-runtime-sets-fixture "$WORK_DIR/populate-fixture.json" 0 "" TachyonTable tachyon_subnets tachyon_ports tachyon_ip_ports tachyon_interfaces localv4 0x00100000
|
||||||
[ ! -s "$NFT_LOG" ] || fail "disabled nft population should not call nft"
|
[ ! -s "$NFT_LOG" ] || fail "disabled nft population should not call nft"
|
||||||
|
|||||||
Reference in New Issue
Block a user