|
|
@@ -90,6 +90,14 @@ local function get_opt(s, k, default, conv)
|
|
|
return v
|
|
|
end
|
|
|
|
|
|
+-- get_opt wrapper that correctly returns default only when the section
|
|
|
+-- is missing. The plain `s and get_opt(...) or default` pattern fails
|
|
|
+-- for falsy values like false (a `bool` option set to '0').
|
|
|
+local function opt(s, k, default, conv)
|
|
|
+ if not s then return default end
|
|
|
+ return get_opt(s, k, default, conv)
|
|
|
+end
|
|
|
+
|
|
|
local function get_list(s, k)
|
|
|
return s._lists[k] or {}
|
|
|
end
|
|
|
@@ -101,95 +109,98 @@ local function build_config(sections)
|
|
|
-- general
|
|
|
local sg = find_section(sections, "general")
|
|
|
cfg.general = {
|
|
|
- host = sg and get_opt(sg, "host", "openwrt") or "openwrt",
|
|
|
- dry_run = sg and get_opt(sg, "dry_run", false, "bool") or false,
|
|
|
- log_level = sg and get_opt(sg, "log_level", "info") or "info",
|
|
|
+ host = opt(sg, "host", "openwrt"),
|
|
|
+ dry_run = opt(sg, "dry_run", false, "bool"),
|
|
|
+ log_level = opt(sg, "log_level", "info"),
|
|
|
}
|
|
|
|
|
|
-- health
|
|
|
local sh = find_section(sections, "health")
|
|
|
cfg.health = {
|
|
|
- probe_interval = sh and get_opt(sh, "probe_interval", 2, "duration") or 2,
|
|
|
- window_size = sh and get_opt(sh, "window_size", 10, "int") or 10,
|
|
|
- down_threshold = sh and get_opt(sh, "down_threshold", 5, "int") or 5,
|
|
|
- up_threshold = sh and get_opt(sh, "up_threshold", 10, "int") or 10,
|
|
|
- icmp_timeout = sh and get_opt(sh, "icmp_timeout", 1, "duration") or 1,
|
|
|
- tcp_timeout = sh and get_opt(sh, "tcp_timeout", 2, "duration") or 2,
|
|
|
- dns_timeout = sh and get_opt(sh, "dns_timeout", 2, "duration") or 2,
|
|
|
- tcp_targets = sh and get_list(sh, "tcp_target") or {"1.1.1.1:443", "8.8.8.8:53"},
|
|
|
- dns_probe_domain = sh and get_opt(sh, "dns_probe_domain", "example.com") or "example.com",
|
|
|
- icmp_enabled = sh and get_opt(sh, "icmp_enabled", true, "bool") or true,
|
|
|
- tcp_enabled = sh and get_opt(sh, "tcp_enabled", true, "bool") or true,
|
|
|
- dns_enabled = sh and get_opt(sh, "dns_enabled", true, "bool") or true,
|
|
|
+ probe_interval = opt(sh, "probe_interval", 2, "duration"),
|
|
|
+ window_size = opt(sh, "window_size", 10, "int"),
|
|
|
+ down_threshold = opt(sh, "down_threshold", 5, "int"),
|
|
|
+ up_threshold = opt(sh, "up_threshold", 10, "int"),
|
|
|
+ icmp_timeout = opt(sh, "icmp_timeout", 1, "duration"),
|
|
|
+ tcp_timeout = opt(sh, "tcp_timeout", 2, "duration"),
|
|
|
+ dns_timeout = opt(sh, "dns_timeout", 2, "duration"),
|
|
|
+ tcp_targets = opt(sh, "tcp_target", nil) and get_list(sh, "tcp_target")
|
|
|
+ or {"1.1.1.1:443", "8.8.8.8:53"},
|
|
|
+ dns_probe_domain = opt(sh, "dns_probe_domain", "example.com"),
|
|
|
+ icmp_enabled = opt(sh, "icmp_enabled", true, "bool"),
|
|
|
+ tcp_enabled = opt(sh, "tcp_enabled", true, "bool"),
|
|
|
+ dns_enabled = opt(sh, "dns_enabled", true, "bool"),
|
|
|
}
|
|
|
|
|
|
-- wans (two sections)
|
|
|
cfg.wans = {}
|
|
|
for _, id in ipairs({"wan-a", "wan-b"}) do
|
|
|
local sw = find_section(sections, "wan", id)
|
|
|
+ local def_iface = id == "wan-a" and "eth0" or "eth1"
|
|
|
cfg.wans[#cfg.wans + 1] = {
|
|
|
id = id,
|
|
|
- interface = sw and get_opt(sw, "interface", id == "wan-a" and "eth0" or "eth1") or (id == "wan-a" and "eth0" or "eth1"),
|
|
|
- address = sw and get_opt(sw, "address", "") or "",
|
|
|
- gateway = sw and get_opt(sw, "gateway", "") or "",
|
|
|
- preference = sw and get_opt(sw, "preference", id == "wan-a" and 100 or 50, "int") or (id == "wan-a" and 100 or 50),
|
|
|
- probe_target = sw and get_opt(sw, "probe_target", "") or "",
|
|
|
+ interface = opt(sw, "interface", def_iface),
|
|
|
+ address = opt(sw, "address", ""),
|
|
|
+ gateway = opt(sw, "gateway", ""),
|
|
|
+ preference = opt(sw, "preference", id == "wan-a" and 100 or 50, "int"),
|
|
|
+ probe_target = opt(sw, "probe_target", ""),
|
|
|
}
|
|
|
end
|
|
|
|
|
|
-- routing
|
|
|
local sr = find_section(sections, "routing")
|
|
|
cfg.routing = {
|
|
|
- table_a = sr and get_opt(sr, "table_a", 100, "int") or 100,
|
|
|
- table_b = sr and get_opt(sr, "table_b", 101, "int") or 101,
|
|
|
- mark_a = sr and get_opt(sr, "mark_active_a", 0x1, "int") or 0x1,
|
|
|
- mark_b = sr and get_opt(sr, "mark_active_b", 0x2, "int") or 0x2,
|
|
|
+ table_a = opt(sr, "table_a", 100, "int"),
|
|
|
+ table_b = opt(sr, "table_b", 101, "int"),
|
|
|
+ mark_a = opt(sr, "mark_active_a", 0x1, "int"),
|
|
|
+ mark_b = opt(sr, "mark_active_b", 0x2, "int"),
|
|
|
}
|
|
|
|
|
|
-- wireguard
|
|
|
local sw = find_section(sections, "wireguard")
|
|
|
cfg.wireguard = {
|
|
|
- enabled = sw and get_opt(sw, "enabled", false, "bool") or false,
|
|
|
- interface = sw and get_opt(sw, "interface", "wg0") or "wg0",
|
|
|
- public_key = sw and get_opt(sw, "public_key", "") or "",
|
|
|
- allowed_ips = sw and get_list(sw, "allowed_ip") or {"10.10.0.0/24"},
|
|
|
- endpoint_a = sw and get_opt(sw, "endpoint_wan_a", "") or "",
|
|
|
- endpoint_b = sw and get_opt(sw, "endpoint_wan_b", "") or "",
|
|
|
- handshake_max_age = sw and get_opt(sw, "handshake_max_age", 180, "duration") or 180,
|
|
|
- switch_handshake_wait = sw and get_opt(sw, "switch_handshake_wait", 5, "duration") or 5,
|
|
|
- prewarm_on_standby = sw and get_opt(sw, "prewarm_on_standby", true, "bool") or true,
|
|
|
+ enabled = opt(sw, "enabled", false, "bool"),
|
|
|
+ interface = opt(sw, "interface", "wg0"),
|
|
|
+ public_key = opt(sw, "public_key", ""),
|
|
|
+ allowed_ips = opt(sw, "allowed_ip", nil) and get_list(sw, "allowed_ip")
|
|
|
+ or {"10.10.0.0/24"},
|
|
|
+ endpoint_a = opt(sw, "endpoint_wan_a", ""),
|
|
|
+ endpoint_b = opt(sw, "endpoint_wan_b", ""),
|
|
|
+ handshake_max_age = opt(sw, "handshake_max_age", 180, "duration"),
|
|
|
+ switch_handshake_wait = opt(sw, "switch_handshake_wait", 5, "duration"),
|
|
|
+ prewarm_on_standby = opt(sw, "prewarm_on_standby", true, "bool"),
|
|
|
}
|
|
|
|
|
|
-- notifier
|
|
|
local sn = find_section(sections, "notifier")
|
|
|
cfg.notifier = {
|
|
|
- webhook_url = sn and get_opt(sn, "webhook_url", "") or "",
|
|
|
- webhook_secret = sn and get_opt(sn, "webhook_secret", "") or "",
|
|
|
- batch_window = sn and get_opt(sn, "batch_window", 0.2, "duration") or 0.2,
|
|
|
- max_attempts = sn and get_opt(sn, "max_attempts", 24, "int") or 24,
|
|
|
- initial_backoff = sn and get_opt(sn, "initial_backoff", 1, "duration") or 1,
|
|
|
- max_backoff = sn and get_opt(sn, "max_backoff", 300, "duration") or 300,
|
|
|
- outbox_capacity = sn and get_opt(sn, "outbox_capacity", 10000, "int") or 10000,
|
|
|
- cb_threshold = sn and get_opt(sn, "cb_threshold", 5, "int") or 5,
|
|
|
- cb_cooldown = sn and get_opt(sn, "cb_cooldown", 60, "duration") or 60,
|
|
|
- ca_file = sn and get_opt(sn, "ca_file", "") or "",
|
|
|
- gzip_min_size = sn and get_opt(sn, "gzip_min_size", 1024, "int") or 1024,
|
|
|
+ webhook_url = opt(sn, "webhook_url", ""),
|
|
|
+ webhook_secret = opt(sn, "webhook_secret", ""),
|
|
|
+ batch_window = opt(sn, "batch_window", 0.2, "duration"),
|
|
|
+ max_attempts = opt(sn, "max_attempts", 24, "int"),
|
|
|
+ initial_backoff = opt(sn, "initial_backoff", 1, "duration"),
|
|
|
+ max_backoff = opt(sn, "max_backoff", 300, "duration"),
|
|
|
+ outbox_capacity = opt(sn, "outbox_capacity", 10000, "int"),
|
|
|
+ cb_threshold = opt(sn, "cb_threshold", 5, "int"),
|
|
|
+ cb_cooldown = opt(sn, "cb_cooldown", 60, "duration"),
|
|
|
+ ca_file = opt(sn, "ca_file", ""),
|
|
|
+ gzip_min_size = opt(sn, "gzip_min_size", 1024, "int"),
|
|
|
}
|
|
|
|
|
|
-- flap
|
|
|
local sf = find_section(sections, "flap")
|
|
|
cfg.flap = {
|
|
|
- switch_count = sf and get_opt(sf, "switch_count", 3, "int") or 3,
|
|
|
- window = sf and get_opt(sf, "window", 300, "duration") or 300,
|
|
|
- recovery_grace = sf and get_opt(sf, "recovery_grace", 300, "duration") or 300,
|
|
|
+ switch_count = opt(sf, "switch_count", 3, "int"),
|
|
|
+ window = opt(sf, "window", 300, "duration"),
|
|
|
+ recovery_grace = opt(sf, "recovery_grace", 300, "duration"),
|
|
|
}
|
|
|
|
|
|
-- features
|
|
|
local sfe = find_section(sections, "features")
|
|
|
cfg.features = {
|
|
|
- hot_reload = sfe and get_opt(sfe, "hot_reload", false, "bool") or false,
|
|
|
- trace_ids = sfe and get_opt(sfe, "trace_ids", false, "bool") or false,
|
|
|
- seccomp = sfe and get_opt(sfe, "seccomp", false, "bool") or false,
|
|
|
+ hot_reload = opt(sfe, "hot_reload", false, "bool"),
|
|
|
+ trace_ids = opt(sfe, "trace_ids", false, "bool"),
|
|
|
+ seccomp = opt(sfe, "seccomp", false, "bool"),
|
|
|
}
|
|
|
|
|
|
-- store
|