22c8b03a23c6e4f531b34a06e84d087df88c7917
[feed/packages.git] / net / pbr / files / etc / init.d / pbr.init
1 #!/bin/sh /etc/rc.common
2 # Copyright 2020-2022 Stan Grishin (stangri@melmac.ca)
3 # shellcheck disable=SC1091,SC2018,SC2019,SC3043,SC3057,SC3060
4
5 # sysctl net.ipv4.conf.default.rp_filter=1
6 # sysctl net.ipv4.conf.all.rp_filter=1
7
8 # shellcheck disable=SC2034
9 START=94
10 # shellcheck disable=SC2034
11 USE_PROCD=1
12
13 if type extra_command >/dev/null 2>&1; then
14 extra_command 'status' "Generates output required to troubleshoot routing issues
15 Use '-d' option for more detailed output
16 Use '-p' option to automatically upload data under VPR paste.ee account
17 WARNING: while paste.ee uploads are unlisted, they are still publicly available
18 List domain names after options to include their lookup in report"
19 extra_command 'version' 'Show version information'
20 extra_command 'on_firewall_reload' ' Run service on firewall reload'
21 extra_command 'on_interface_reload' ' Run service on indicated interface reload'
22 else
23 # shellcheck disable=SC2034
24 EXTRA_COMMANDS='on_firewall_reload on_interface_reload status version'
25 # shellcheck disable=SC2034
26 EXTRA_HELP=" status Generates output required to troubleshoot routing issues
27 Use '-d' option for more detailed output
28 Use '-p' option to automatically upload data under VPR paste.ee account
29 WARNING: while paste.ee uploads are unlisted, they are still publicly available
30 List domain names after options to include their lookup in report"
31 fi
32
33 readonly PKG_VERSION='dev-test'
34 readonly packageName='pbr'
35 readonly serviceName="$packageName $PKG_VERSION"
36 readonly serviceTrapSignals='exit SIGHUP SIGQUIT SIGKILL'
37 readonly packageConfigFile="/etc/config/${packageName}"
38 readonly nftTempFile="/var/run/${packageName}.nft"
39 #readonly nftPermFile="/etc/nftables.d/table-post/30-pbr.nft"
40 readonly dnsmasqFile="/var/dnsmasq.d/${packageName}"
41 readonly sharedMemoryOutput="/dev/shm/$packageName-output"
42 readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m'
43 readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m'
44 readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m'
45 readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m'
46 readonly _ERROR_='\033[0;31mERROR\033[0m'
47 readonly _WARNING_='\033[0;33mWARNING\033[0m'
48 readonly ip_full='/usr/libexec/ip-full'
49 readonly ipTablePrefix='pbr'
50 # shellcheck disable=SC2155
51 readonly iptables="$(command -v iptables)"
52 # shellcheck disable=SC2155
53 readonly ip6tables="$(command -v ip6tables)"
54 # shellcheck disable=SC2155
55 readonly ipset="$(command -v ipset)"
56 readonly ipsPrefix='pbr'
57 readonly iptPrefix='PBR'
58 # shellcheck disable=SC2155
59 readonly agh="$(command -v AdGuardHome)"
60 readonly aghConfigFile='/etc/adguardhome.yaml'
61 readonly aghIpsetFile="/var/run/${packageName}.adguardhome.ipsets"
62 # shellcheck disable=SC2155
63 readonly nft="$(command -v nft)"
64 readonly nftTable="fw4"
65 readonly nftPrefix='pbr'
66 readonly chainsList='forward input output postrouting prerouting'
67
68 # package config options
69 boot_timeout=
70 enabled=
71 fw_mask=
72 icmp_interface=
73 ignored_interface=
74 ipv6_enabled=
75 procd_boot_delay=
76 procd_reload_delay=
77 resolver_set=
78 rule_create_option=
79 secure_reload=
80 strict_enforcement=
81 supported_interface=
82 verbosity=
83 wan_ip_rules_priority=
84 wan_mark=
85
86 # run-time
87 gatewaySummary=
88 errorSummary=
89 warningSummary=
90 wanIface4=
91 wanIface6=
92 ifaceMark=
93 ifaceTableID=
94 ifacePriority=
95 ifacesAll=
96 ifacesSupported=
97 wanGW4=
98 wanGW6=
99 serviceStartTrigger=
100 processPolicyError=
101 processPolicyWarning=
102 resolver_set_supported=
103 nftPrevParam4=
104 nftPrevParam6=
105
106
107 get_text() {
108 local r
109 case "$1" in
110 errorConfigValidation) r="Config ($packageConfigFile) validation failure!";;
111 errorNoIpFull) r="ip-full binary cannot be found!";;
112 errorNoIptables) r="iptables binary cannot be found!";;
113 errorNoIpset) r="Resolver set support (${resolver_set}) requires ipset, but ipset binary cannot be found!";;
114 errorNoNft) r="Resolver set support (${resolver_set}) requires nftables, but nft binary cannot be found!";;
115 errorResolverNotSupported) r="Resolver set (${resolver_set}) is not supported on this system!";;
116 errorServiceDisabled) r="The ${packageName} service is currently disabled!";;
117 errorNoWanGateway) r="The ${serviceName} service failed to discover WAN gateway!";;
118 errorIpsetNameTooLong) r="The ipset name '%s' is longer than allowed 31 characters!";;
119 errorNftsetNameTooLong) r="The nft set name '%s' is longer than allowed 31 characters!";;
120 errorUnexpectedExit) r="Unexpected exit or service termination: '%s'!";;
121 errorPolicyNoSrcDest) r="Policy '%s' has no source/destination parameters!";;
122 errorPolicyNoInterface) r="Policy '%s' has no assigned interface!";;
123 errorPolicyUnknownInterface) r="Policy '%s' has an unknown interface!";;
124 errorPolicyProcess) r="%s";;
125 errorFailedSetup) r="Failed to set up '%s'!";;
126 errorFailedReload) r="Failed to reload '%s'!";;
127 errorUserFileNotFound) r="Custom user file '%s' not found or empty!";;
128 ererrorUserFileSyntax) r="Syntax error in custom user file '%s'!";;
129 errorUserFileRunning) r="Error running custom user file '%s'!";;
130 errorUserFileNoCurl) r="Use of 'curl' is detected in custom user file '%s', but 'curl' isn't installed!";;
131 errorNoGateways) r="Failed to set up any gateway!";;
132 warningResolverNotSupported) r="Resolver set (${resolver_set}) is not supported on this system.";;
133 warningAGHVersionTooLow) r="Installed AdGuardHome (%s) doesn't support 'ipset_file' option.";;
134 warningPolicyProcess) r="%s";;
135 esac
136 echo "$r"
137 }
138
139 version() { echo "$PKG_VERSION"; }
140 output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; }
141 output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; }
142 output_fail() { s=1; output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; }
143 output_failn() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; }
144 str_replace() { printf "%b" "$1" | sed -e "s/$(printf "%b" "$2")/$(printf "%b" "$3")/g"; }
145 str_replace() { echo "${1//$2/$3}"; }
146 str_contains() { [ -n "$1" ] &&[ -n "$2" ] && [ "${1//$2}" != "$1" ]; }
147 is_greater() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
148 is_greater_or_equal() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" = "$2"; }
149 str_contains_word() { echo "$1" | grep -q -w "$2"; }
150 str_to_lower() { echo "$1" | tr 'A-Z' 'a-z'; }
151 str_to_upper() { echo "$1" | tr 'a-z' 'A-Z'; }
152 str_extras_to_underscore() { echo "$1" | tr '[\. ~`!@#$%^&*()\+/,<>?//;:]' '_'; }
153 str_extras_to_space() { echo "$1" | tr ';{}' ' '; }
154 debug() { local i j; for i in "$@"; do eval "j=\$$i"; echo "${i}: ${j} "; done; }
155 output() {
156 # Can take a single parameter (text) to be output at any verbosity
157 # Or target verbosity level and text to be output at specifc verbosity
158 local msg memmsg logmsg
159 verbosity="${verbosity:-2}"
160 if [ "$#" -ne 1 ]; then
161 if [ $((verbosity & $1)) -gt 0 ] || [ "$verbosity" = "$1" ]; then shift; else return 0; fi
162 fi
163 [ -t 1 ] && printf "%b" "$1"
164 msg="${1//$serviceName /service }";
165 if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then
166 [ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")"
167 logmsg="$(printf "%b" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')"
168 logger -t "${packageName:-service}" "$(printf "%b" "$logmsg")"
169 rm -f "$sharedMemoryOutput"
170 else
171 printf "%b" "$msg" >> "$sharedMemoryOutput"
172 fi
173 }
174 is_present() { command -v "$1" >/dev/null 2>&1; }
175 is_installed() { [ -s "/usr/lib/opkg/info/${1}.control" ]; }
176 is_variant_installed() { [ "$(echo /usr/lib/opkg/info/"${1}"*.control)" != "/usr/lib/opkg/info/${1}*.control" ]; }
177 is_nft() { [ -x "$nft" ] && ! str_contains "$resolver_set" 'ipset' && "$nft" list chains inet | grep -q "${nftPrefix}_prerouting"; }
178 _build_ifaces_all() { ifacesAll="${ifacesAll}${1} "; }
179 _build_ifaces_supported() { is_supported_interface "$1" && ifacesSupported="${ifacesSupported}${1} "; }
180 pbr_find_iface() {
181 local iface i param="$2"
182 [ "$param" = 'wan6' ] || param='wan'
183 "network_find_${param}" iface
184 is_tunnel "$iface" && unset iface
185 if [ -z "$iface" ]; then
186 for i in $ifacesAll; do
187 if "is_${param}" "$i"; then break; else unset i; fi
188 done
189 fi
190 eval "$1"='${iface:-$i}'
191 }
192 pbr_get_gateway() {
193 local iface="$2" dev="$3" gw
194 network_get_gateway gw "$iface" true
195 # if [ -z "$gw" ] || [ "$gw" = '0.0.0.0' ]; then
196 # gw="$(ubus call "network.interface.${iface}" status | jsonfilter -e "@.route[0].nexthop")"
197 # fi
198 if [ -z "$gw" ] || [ "$gw" = '0.0.0.0' ]; then
199 gw="$($ip_full -4 a list dev "$dev" 2>/dev/null | grep inet | awk '{print $2}' | awk -F "/" '{print $1}')"
200 fi
201 eval "$1"='$gw'
202 }
203 pbr_get_gateway6() {
204 local iface="$2" dev="$3" gw
205 network_get_gateway6 gw "$iface" true
206 if [ -z "$gw" ] || [ "$gw" = '::/0' ] || [ "$gw" = '::0/0' ] || [ "$gw" = '::' ]; then
207 gw="$($ip_full -6 a list dev "$dev" 2>/dev/null | grep inet6 | awk '{print $2}')"
208 fi
209 eval "$1"='$gw'
210 }
211 is_dslite() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:6}" = "dslite" ]; }
212 is_l2tp() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:4}" = "l2tp" ]; }
213 is_oc() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:11}" = "openconnect" ]; }
214 is_ovpn() { local dev; network_get_device dev "$1"; [ "${dev:0:3}" = "tun" ] || [ "${dev:0:3}" = "tap" ] || [ -f "/sys/devices/virtual/net/${dev}/tun_flags" ]; }
215 is_pptp() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:4}" = "pptp" ]; }
216 is_softether() { local dev; network_get_device dev "$1"; [ "${dev:0:4}" = "vpn_" ]; }
217 is_tor() { [ "$(str_to_lower "$1")" = "tor" ]; }
218 is_tor_running() {
219 local ret=0
220 if [ -s "/etc/tor/torrc" ]; then
221 json_load "$(ubus call service list "{ 'name': 'tor' }")"
222 json_select 'tor'; json_select 'instances'; json_select 'instance1';
223 json_get_var ret 'running'; json_cleanup
224 fi
225 if [ "$ret" = "0" ]; then return 1; else return 0; fi
226 }
227 is_wg() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:9}" = "wireguard" ]; }
228 is_tunnel() { is_dslite "$1" || is_l2tp "$1" || is_oc "$1" || is_ovpn "$1" || is_pptp "$1" || is_softether "$1" || is_tor "$1" || is_wg "$1"; }
229 is_wan() { [ "$1" = "$wanIface4" ] || { [ "${1##wan}" != "$1" ] && [ "${1##wan6}" = "$1" ]; } || [ "${1%%wan}" != "$1" ]; }
230 is_wan6() { [ -n "$wanIface6" ] && [ "$1" = "$wanIface6" ] || [ "${1/#wan6}" != "$1" ] || [ "${1/%wan6}" != "$1" ]; }
231 is_ignored_interface() { str_contains_word "$ignored_interface" "$1"; }
232 is_supported_interface() { str_contains_word "$supported_interface" "$1" || { ! is_ignored_interface "$1" && { is_wan "$1" || is_wan6 "$1" || is_tunnel "$1"; }; } || is_ignore_target "$1"; }
233 is_ignore_target() { [ "$(str_to_lower "$1")" = 'ignore' ]; }
234 is_mac_address() { expr "$1" : '[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]$' >/dev/null; }
235 is_ipv4() { expr "$1" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null; }
236 is_ipv6() { ! is_mac_address "$1" && str_contains "$1" ":"; }
237 is_family_mismatch() { ( is_netmask "${1//!}" && is_ipv6 "${2//!}" ) || ( is_ipv6 "${1//!}" && is_netmask "${2//!}" ); }
238 is_ipv6_link_local() { [ "${1:0:4}" = "fe80" ]; }
239 is_ipv6_unique_local() { [ "${1:0:2}" = "fc" ] || [ "${1:0:2}" = "fd" ]; }
240 is_ipv6_global() { [ "${1:0:4}" = "2001" ]; }
241 # is_ipv6_global() { is_ipv6 "$1" && ! is_ipv6_link_local "$1" && ! is_ipv6_link_local "$1"; }
242 is_list() { str_contains "$1" "," || str_contains "$1" " "; }
243 is_netmask() { local ip="${1%/*}"; [ "$ip" != "$1" ] && is_ipv4 "$ip"; }
244 is_domain() { str_contains "$1" '[a-zA-Z]'; }
245 is_phys_dev() { [ "${1:0:1}" = "@" ] && ip l show | grep -E -q "^\\d+\\W+${1:1}"; }
246 dnsmasq_kill() { killall -q -s HUP dnsmasq; }
247 dnsmasq_restart() { output 3 'Restarting dnsmasq '; if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then output_okn; else output_failn; fi; }
248 is_default_dev() { [ "$1" = "$($ip_full -4 r | grep -m1 'dev' | grep -Eso 'dev [^ ]*' | awk '{print $2}')" ]; }
249 is_supported_iface_dev() { local n dev; for n in $ifacesSupported; do network_get_device dev "$n"; [ "$1" = "$dev" ] && return 0; done; return 1; }
250 is_supported_protocol() { grep -o '^[^#]*' /etc/protocols | grep -w -v '0' | grep . | awk '{print $1}' | grep -q "$1"; }
251 is_service_running_iptables() { [ -x "$iptables" ] && "$iptables" -t mangle -L | grep -q "${iptPrefix}_PREROUTING" >/dev/null 2>&1; }
252 is_service_running_nft() { [ -x "$nft" ] && [ -n "$(get_mark_nft_chains)" ]; }
253 # atomic
254 # is_service_running_nft() { [ -x "$nft" ] && [ -s "$nftPermFile" ]; }
255 is_service_running() { if is_nft; then is_service_running_nft; else is_service_running_iptables; fi; }
256 is_netifd_table() { local iface="$1"; [ "$(uci -q get "network.${iface}.ip4table")" = "${packageName}_${iface%6}" ]; }
257 get_rt_tables_id() { grep "${packageName}_${iface}" /etc/iproute2/rt_tables | awk '{print $1;}'; }
258 get_rt_tables_next_id() { echo "$(($(sort -r -n /etc/iproute2/rt_tables | grep -o -E -m 1 "^[0-9]+")+1))"; }
259 _check_config() { local en; config_get_bool en "$1" 'enabled' 1; [ "$en" -gt 0 ] && _cfg_enabled=0; }
260 is_config_enabled() {
261 local cfg="$1" _cfg_enabled=1
262 [ -n "$1" ] || return 1
263 config_load "$packageName"
264 config_foreach _check_config "$cfg"
265 return "$_cfg_enabled"
266 }
267 # shellcheck disable=SC2016
268 resolveip_to_ipt() { resolveip "$@" | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d'; }
269 # shellcheck disable=SC2016
270 resolveip_to_nftset() { resolveip "$@" | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d' | tr '\n' ' '; }
271 resolveip_to_nftset4() { resolveip_to_nftset -4 "$@"; }
272 resolveip_to_nftset6() { [ -n "$ipv6_enabled" ] && resolveip_to_nftset -6 "$@"; }
273 # shellcheck disable=SC2016
274 ipv4_leases_to_nftset() { [ -s '/tmp/dhcp.leases' ] || return 1; grep "$1" '/tmp/dhcp.leases' | awk '{print $3}' | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d' | tr '\n' ' '; }
275 # shellcheck disable=SC2016
276 ipv6_leases_to_nftset() { [ -s '/tmp/hosts/odhcpd' ] || return 1; grep -v '^\#' '/tmp/hosts/odhcpd' | grep "$1" | awk '{print $1}' | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d' | tr '\n' ' '; }
277 # shellcheck disable=SC3037
278 ports_to_nftset() { echo -ne "$value"; }
279 get_mark_ipt_chains() { [ -n "$(command -v iptables-save)" ] && iptables-save | grep ":${iptPrefix}_MARK_" | awk '{ print $1 }' | sed 's/://'; }
280 get_mark_nft_chains() { [ -x "$nft" ] && "$nft" list table inet "$nftTable" 2>/dev/null | grep chain | grep "${nftPrefix}_mark_" | awk '{ print $2 }'; }
281 get_ipsets() { [ -x "$(command -v ipset)" ] && ipset list | grep "${ipsPrefix}_" | awk '{ print $2 }'; }
282 get_nft_sets() { [ -x "$nft" ] && "$nft" list table inet "$nftTable" 2>/dev/null | grep 'set' | grep "${nftPrefix}_" | awk '{ print $2 }'; }
283 is_ipset_type_supported() { ipset help hash:"$1" >/dev/null 2>&1; }
284 ubus_get_status() { ubus call service list "{ 'name': '$packageName' }" | jsonfilter -e "@.${packageName}.instances.main.data.status.${1}"; }
285 ubus_get_iface() { ubus call service list "{ 'name': '$packageName' }" | jsonfilter -e "@.${packageName}.instances.main.data.interfaces[@.name='${1}']${2:+.$2}"; }
286
287 load_package_config() {
288 config_load "$packageName"
289 config_get boot_timeout 'config' 'boot_timeout' '30'
290 config_get_bool enabled 'config' 'enabled' '0'
291 config_get fw_mask 'config' 'fw_mask' 'ff0000'
292 config_get icmp_interface 'config' 'icmp_interface'
293 config_get ignored_interface 'config' 'ignored_interface'
294 config_get_bool ipv6_enabled 'config' 'ipv6_enabled' '0'
295 config_get procd_boot_delay 'config' 'procd_boot_delay' '0'
296 config_get resolver_set 'config' 'resolver_set'
297 config_get rule_create_option 'config' 'rule_create_option' 'add'
298 config_get_bool secure_reload 'config' 'secure_reload' '1'
299 config_get_bool strict_enforcement 'config' 'strict_enforcement' '0'
300 config_get supported_interface 'config' 'supported_interface'
301 config_get verbosity 'config' 'verbosity' '2'
302 config_get wan_ip_rules_priority 'config' 'wan_ip_rules_priority' '30000'
303 config_get wan_mark 'config' 'wan_mark' '010000'
304 fw_mask="0x${fw_mask}"
305 wan_mark="0x${wan_mark}"
306 [ -n "$ipv6_enabled" ] && [ "$ipv6_enabled" -eq 0 ] && unset ipv6_enabled
307 . /lib/functions/network.sh
308 . /usr/share/libubox/jshn.sh
309 mkdir -p "${dnsmasqFile%/*}"
310 if is_nft; then
311 fw_maskXor="$(printf '%#x' "$((fw_mask ^ 0xffffffff))")"
312 fw_maskXor="${fw_maskXor:-0xff00ffff}"
313 else
314 case $rule_create_option in
315 insert|-i|-I) rule_create_option='-I';;
316 add|-a|-A|*) rule_create_option='-A';;
317 esac
318 fi
319 }
320
321 load_environment() {
322 local param="$1" validation_result="$2"
323 load_package_config
324
325 if [ "$param" = 'on_start' ]; then
326 if [ -n "$validation_result" ] && [ "$validation_result" != '0' ]; then
327 output "${_ERROR_}: The $packageName config validation failed!\\n"
328 output "Please check if the '$packageConfigFile' contains correct values for config options.\\n"
329 state add 'errorSummary' 'errorConfigValidation'
330 return 1
331 fi
332 if [ "$enabled" -eq 0 ]; then
333 state add 'errorSummary' 'errorServiceDisabled'
334 return 1
335 fi
336 if [ ! -x "$ip_full" ]; then
337 state add 'errorSummary' 'errorNoIpFull'
338 return 1
339 fi
340 if ! is_nft; then
341 if [ -z "$iptables" ] || [ ! -x "$iptables" ]; then
342 state add 'errorSummary' 'errorNoIptables'
343 return 1
344 fi
345 fi
346 resolver 'check_support'
347 fi
348
349 load_network "$param"
350 }
351
352 load_network() {
353 config_load 'network'
354 [ -z "$ifacesAll" ] && config_foreach _build_ifaces_all 'interface'
355 [ -z "$ifacesSupported" ] && config_foreach _build_ifaces_supported 'interface'
356 pbr_find_iface wanIface4 'wan'
357 [ -n "$ipv6_enabled" ] && pbr_find_iface wanIface6 'wan6'
358 [ -n "$wanIface4" ] && network_get_gateway wanGW4 "$wanIface4"
359 [ -n "$wanIface6" ] && network_get_gateway6 wanGW6 "$wanIface6"
360 wanGW="${wanGW4:-$wanGW6}"
361 }
362
363 is_wan_up() {
364 local sleepCount='1'
365 load_network
366 while [ -z "$wanGW" ] ; do
367 load_network
368 if [ $((sleepCount)) -gt $((boot_timeout)) ] || [ -n "$wanGW" ]; then break; fi
369 output "$serviceName waiting for wan gateway...\\n"
370 sleep 1
371 network_flush_cache
372 sleepCount=$((sleepCount+1))
373 done
374 if [ -n "$wanGW" ]; then
375 return 0
376 else
377 state add 'errorSummary' 'errorNoWanGateway'
378 return 1
379 fi
380 }
381
382 # shellcheck disable=SC2086
383 ipt4() {
384 local d
385 [ -x "$iptables" ] || return 1
386 for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do
387 [ "$d" != "$*" ] && "$iptables" $d >/dev/null 2>&1
388 done
389 d="$*"; "$iptables" $d >/dev/null 2>&1
390 }
391
392 # shellcheck disable=SC2086
393 ipt6() {
394 local d
395 [ -n "$ipv6_enabled" ] || return 0
396 [ -x "$ip6tables" ] || return 1
397 for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do
398 [ "$d" != "$*" ] && "$ip6tables" $d >/dev/null 2>&1
399 done
400 d="$*"
401 "$ip6tables" $d >/dev/null 2>&1
402 }
403
404 # shellcheck disable=SC2086
405 ipt() {
406 local d failFlagIpv4=1 failFlagIpv6=1
407 [ -x "$iptables" ] || return 1
408 for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do
409 if [ "$d" != "$*" ]; then
410 "$iptables" $d >/dev/null 2>&1
411 [ -x "$ip6tables" ] && "$ip6tables" $d >/dev/null 2>&1
412 fi
413 done
414 d="$*"; "$iptables" $d >/dev/null 2>&1 && failFlagIpv4=0;
415 if [ -n "$ipv6_enabled" ] && [ -x "$ip6tables" ]; then
416 "$ip6tables" $d >/dev/null 2>&1 && failFlagIpv6=0
417 fi
418 [ "$failFlagIpv4" -eq 0 ] || [ "$failFlagIpv6" -eq 0 ]
419 }
420
421 # shellcheck disable=SC2086
422 ips4() { [ -x "$ipset" ] && "$ipset" "$@" >/dev/null 2>&1; }
423 ips6() { [ -x "$ipset" ] && { if [ -n "$ipv6_enabled" ] && [ -n "$*" ]; then "$ipset" "$@" >/dev/null 2>&1; else return 1; fi; }; }
424 ips() {
425 local command="$1" iface="$2" target="${3:-dst}" type="${4:-ip}" uid="$5" comment="$6" param="$7" mark="$7"
426 local ipset4 ipset6 i
427 local ipv4_error=1 ipv6_error=1
428 ipset4="${ipsPrefix}${iface:+_$iface}_4${target:+_$target}${type:+_$type}${uid:+_$uid}"
429 ipset6="${ipsPrefix}${iface:+_$iface}_6${target:+_$target}${type:+_$type}${uid:+_$uid}"
430
431 [ -x "$ipset" ] || return 1
432
433 if [ "${#ipset4}" -gt 31 ]; then
434 state add 'errorSummary' 'errorIpsetNameTooLong' "$ipset4"
435 return 1
436 fi
437
438 case "$command" in
439 add)
440 ips4 -q -! add "$ipset4" comment "$comment" && ipv4_error=0
441 ips6 -q -! add "$ipset6" comment "$comment" && ipv6_error=0
442 ;;
443 add_agh_element)
444 [ -n "$ipv6_enabled" ] || unset ipset6
445 echo "${param}/${ipset4}${ipset6:+,$ipset6}" >> "$aghIpsetFile" && ipv4_error=0
446 ;;
447 add_dnsmasq_element)
448 [ -n "$ipv6_enabled" ] || unset ipset6
449 echo "ipset=/${param}/${ipset4}${ipset6:+,$ipset6} # $comment" >> "$dnsmasqFile" && ipv4_error=0
450 ;;
451 create)
452 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
453 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0
454 ;;
455 create_agh_set)
456 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
457 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0
458 ;;
459 create_dnsmasq_set)
460 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
461 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0
462 ;;
463 create_user_set)
464 case "$type" in
465 ip|net)
466 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
467 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv4_error=0
468 case "$target" in
469 dst)
470 ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" dst -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
471 ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" dst -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
472 ;;
473 src)
474 ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
475 ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
476 ;;
477 esac
478 ;;
479 mac)
480 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
481 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv4_error=0
482 ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
483 ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
484 ;;
485 esac
486 ;;
487 delete|destroy)
488 ips4 -q -! destroy "$ipset4" && ipv4_error=0
489 ips6 -q -! destroy "$ipset6" && ipv6_error=0
490 ;;
491 delete_user_set)
492 ips4 -q -! destroy "$ipset4" && ipv4_error=0
493 ips6 -q -! destroy "$ipset6" family inet6 && ipv6_error=0
494 case "$type" in
495 ip|net)
496 case "$target" in
497 dst)
498 ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" dst -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
499 ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" dst -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
500 ;;
501 src)
502 ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
503 ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
504 ;;
505 esac
506 ;;
507 mac)
508 ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
509 ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
510 ;;
511 esac
512 ;;
513 flush|flush_user_set)
514 ips4 -q -! flush "$ipset4" && ipv4_error=0
515 ips6 -q -! flush "$ipset6" && ipv6_error=0
516 ;;
517 esac
518 return $ipv4_error || $ipv6_error
519 }
520
521 # atomic
522 #nfta() { echo "$@" >> "$nftTempFile"; }
523 #nfta4() { echo "$@" >> "$nftTempFile"; }
524 #nfta6() { [ -z "$ipv6_enabled" ] || echo "$@" >> "$nftTempFile"; }
525 #nft() { nfta "$@"; [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; }
526 #nft4() { nfta "$@"; [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; }
527 #nft6() { nfta "$@"; [ -n "$ipv6_enabled" ] || return 0; [ -x "$nft" ] && [ -n "$*" ] && "$nft" "$@" >/dev/null 2>&1; }
528 nft() { [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; }
529 nft4() { [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; }
530 nft6() { [ -n "$ipv6_enabled" ] || return 0; [ -x "$nft" ] && [ -n "$*" ] && "$nft" "$@" >/dev/null 2>&1; }
531 nftset() {
532 local command="$1" iface="$2" target="${3:-dst}" type="${4:-ip}" uid="$5" comment="$6" param="$7" mark="$7"
533 local nftset4 nftset6 i param4 param6
534 local ipv4_error=1 ipv6_error=1
535 nftset4="${nftPrefix}${iface:+_$iface}_4${target:+_$target}${type:+_$type}${uid:+_$uid}"
536 nftset6="${nftPrefix}${iface:+_$iface}_6${target:+_$target}${type:+_$type}${uid:+_$uid}"
537
538 [ -x "$nft" ] || return 1
539
540 if [ "${#nftset4}" -gt 255 ]; then
541 state add 'errorSummary' 'errorNftsetNameTooLong' "$nftset4"
542 return 1
543 fi
544
545 case "$command" in
546 add)
547 if is_netmask "$param" || is_ipv4 "$param" || is_ipv6 "$param" \
548 || is_mac_address "$param" || is_list "$param"; then
549 nft4 add element inet "$nftTable" "$nftset4" "{ $param }" && ipv4_error=0
550 nft6 add element inet "$nftTable" "$nftset6" "{ $param }" && ipv6_error=0
551 else
552 # elif is_domain "$param"; then
553 if [ "$target" = 'src' ]; then
554 param4="$(ipv4_leases_to_nftset "$param")"
555 param6="$(ipv6_leases_to_nftset "$param")"
556 fi
557 [ -z "$param4" ] && param4="$(resolveip_to_nftset4 "$param")"
558 [ -z "$param6" ] && param6="$(resolveip_to_nftset6 "$param")"
559 nft4 add element inet "$nftTable" "$nftset4" "{ $param4 }" && ipv4_error=0
560 nft6 add element inet "$nftTable" "$nftset6" "{ $param6 }" && ipv6_error=0
561 fi
562 ;;
563 add_dnsmasq_element)
564 [ -n "$ipv6_enabled" ] || unset nftset6
565 echo "nftset=/${param}/4#inet#${nftTable}#${nftset4}${nftset6:+,6#inet#${nftTable}#$nftset6} # $comment" >> "$dnsmasqFile" && ipv4_error=0
566 ;;
567 create)
568 case "$type" in
569 ip|net)
570 nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0
571 nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0
572 ;;
573 mac)
574 nft4 add set inet "$nftTable" "$nftset4" "{ type ether_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0
575 nft6 add set inet "$nftTable" "$nftset6" "{ type ether_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0
576 ;;
577 esac
578 ;;
579 create_dnsmasq_set)
580 nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0
581 nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0
582 ;;
583 create_user_set)
584 case "$type" in
585 ip|net)
586 nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; flags interval; auto-merge; policy memory; comment \"$comment\"; }" && ipv4_error=0
587 nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; flags interval; auto-merge; policy memory; comment \"$comment\"; }" && ipv6_error=0
588 case "$target" in
589 dst)
590 nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ip daddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
591 nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ip daddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
592 ;;
593 src)
594 nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ip saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
595 nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ip saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
596 ;;
597 esac
598 ;;
599 mac)
600 nft4 add set inet "$nftTable" "$nftset4" "{ type ether_addr; flags interval; auto-merge; policy memory; comment \"$comment\"; }" && ipv4_error=0
601 nft6 add set inet "$nftTable" "$nftset6" "{ type ether_addr; flags interval; auto-merge; policy memory; comment \"$comment\"; }" && ipv6_error=0
602 nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
603 nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
604 ;;
605 esac
606 ;;
607 delete|destroy)
608 nft delete set inet "$nftTable" "$nftset4" && ipv4_error=0
609 nft delete set inet "$nftTable" "$nftset6" && ipv6_error=0
610 ;;
611 delete_user_set)
612 nft delete set inet "$nftTable" "$nftset4" && ipv4_error=0
613 nft delete set inet "$nftTable" "$nftset6" && ipv6_error=0
614 case "$type" in
615 ip|net)
616 case "$target" in
617 dst)
618 nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ip daddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
619 nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ip daddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
620 ;;
621 src)
622 nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ip saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
623 nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ip saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
624 ;;
625 esac
626 ;;
627 mac)
628 nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
629 nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
630 ;;
631 esac
632 ;;
633 flush|flush_user_set)
634 nft flush set inet "$nftTable" "$nftset4" && ipv4_error=0
635 nft flush set inet "$nftTable" "$nftset6" && ipv6_error=0
636 ;;
637 esac
638 # nft6 returns true if IPv6 support is not enabled
639 [ -z "$ipv6_enabled" ] && ipv6_error='1'
640 return $ipv4_error || $ipv6_error
641 }
642
643 cleanup_dnsmasq() { [ -s "$dnsmasqFile" ] && resolverStoredHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')" && rm "$dnsmasqFile" >/dev/null 2>&1; }
644 cleanup_main_chains() {
645 local i
646 for i in $chainsList; do
647 i="$(str_to_lower "$i")"
648 nft flush chain inet "$nftTable" "${nftPrefix}_${i}"
649 done
650 for i in $chainsList; do
651 i="$(str_to_upper "$i")"
652 ipt -t mangle -D "${i}" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}"
653 ipt -t mangle -F "${iptPrefix}_${i}"
654 ipt -t mangle -X "${iptPrefix}_${i}"
655 done
656 }
657
658 cleanup_marking_chains() {
659 local i
660 for i in $(get_mark_nft_chains); do
661 nft flush chain inet "$nftTable" "$i"
662 nft delete chain inet "$nftTable" "$i"
663 done
664 for i in $(get_mark_ipt_chains); do
665 ipt -t mangle -F "$i"
666 ipt -t mangle -X "$i"
667 done
668 }
669
670 cleanup_sets() {
671 local i
672 for i in $(get_nft_sets); do
673 nft flush set inet "$nftTable" "$i"
674 nft delete set inet "$nftTable" "$i"
675 done
676 for i in $(get_ipsets); do
677 ipset -q -! flush "$i" >/dev/null 2>&1
678 ipset -q -! destroy "$i" >/dev/null 2>&1
679 done
680 }
681
682 state() {
683 local action="$1" param="$2" value="${3//#/_}"
684 shift 3
685 # shellcheck disable=SC2124
686 local extras="$@"
687 local line error_id error_extra label
688 case "$action" in
689 add)
690 line="$(eval echo "\$$param")"
691 eval "$param"='${line:+$line#}${value}${extras:+ $extras}'
692 ;;
693 json)
694 case "$param" in
695 errorSummary)
696 json_add_array 'errors';;
697 warningSummary)
698 json_add_array 'warnings';;
699 esac
700 if [ -n "$(eval echo "\$$param")" ]; then
701 while read -r line; do
702 if str_contains "$line" ' '; then
703 # url="${c##*|}"
704 # c="${c%|*}"
705 error_id="${line% *}"
706 error_extra="${line#* }"
707 else
708 error_id="$line"
709 fi
710 json_add_object
711 json_add_string 'id' "$error_id"
712 json_add_string 'extra' "$error_extra"
713 json_close_object
714 done <<EOF
715 $(eval echo "\$$param" | tr \# \\n)
716 EOF
717 fi
718 json_close_array
719 ;;
720 print)
721 [ -z "$(eval echo "\$$param")" ] && return 0
722 case "$param" in
723 errorSummary)
724 label="${_ERROR_}:";;
725 warningSummary)
726 label="${_WARNING_}:";;
727 esac
728 while read -r line; do
729 if str_contains "$line" ' '; then
730 error_id="${line% *}"
731 error_extra="${line#* }"
732 printf "%b $(get_text "$error_id")\\n" "$label" "$error_extra"
733 else
734 error_id="$line"
735 printf "%b $(get_text "$error_id")\\n" "$label"
736 fi
737 done <<EOF
738 $(eval echo "\$$param" | tr \# \\n)
739 EOF
740 ;;
741 set)
742 eval "$param"='${value}${extras:+ $extras}'
743 ;;
744 esac
745 }
746
747 resolver() {
748 local agh_version
749 local param="$1"
750 shift
751
752 if [ "$param" = 'cleanup_all' ]; then
753 sed -i "/ipset_file: ${aghIpsetFile}/d" "$aghConfigFile" >/dev/null 2>&1
754 rm -f "$aghIpsetFile"
755 rm -f "$dnsmasqFile"
756 return 0
757 fi
758
759 case "$resolver_set" in
760 ''|none)
761 case "$param" in
762 add_resolver_element) return 1;;
763 create_resolver_set) return 1;;
764 check_support) return 0;;
765 cleanup) return 0;;
766 configure) return 0;;
767 init) return 0;;
768 init_end) return 0;;
769 kill) return 0;;
770 reload) return 0;;
771 restart) return 0;;
772 compare_hash) return 0;;
773 store_hash) return 0;;
774 esac
775 ;;
776 adguardhome.ipset)
777 case "$param" in
778 add_resolver_element)
779 [ -n "$resolver_set_supported" ] && ips 'add_agh_element' "$@";;
780 create_resolver_set)
781 [ -n "$resolver_set_supported" ] && ips 'create_agh_set' "$@";;
782 check_support)
783 if [ ! -x "$ipset" ]; then
784 state add 'errorSummary' 'errorNoIpset'
785 return 1
786 fi
787 if [ -n "$agh" ] && [ -s "$aghConfigFile" ]; then
788 agh_version="$($agh --version | sed 's|AdGuard Home, version v\(.*\)|\1|')"
789 if is_greater_or_equal "$agh_version" '0.107.13'; then
790 resolver_set_supported='true'
791 return 0
792 else
793 state add 'warningSummary' 'warningAGHVersionTooLow' "$agh_version"
794 return 1
795 fi
796 else
797 state add 'warningSummary' 'warningResolverNotSupported'
798 return 1
799 fi
800 ;;
801 cleanup)
802 [ -z "$resolver_set_supported" ] && return 0
803 rm -f "$aghIpsetFile"
804 sed -i "/ipset_file: ${aghIpsetFile}/d" "$aghConfigFile" >/dev/null 2>&1
805 ;;
806 configure)
807 [ -z "$resolver_set_supported" ] && return 1
808 mkdir -p "${aghIpsetFile%/*}"
809 touch "$aghIpsetFile"
810 sed -i '/ipset_file/d' "$aghConfigFile" >/dev/null 2>&1
811 sed -i "/ ipset:/a \ \ ipset_file: $aghIpsetFile" "$aghConfigFile"
812 ;;
813 init) :;;
814 init_end) :;;
815 kill)
816 [ -n "$resolver_set_supported" ] && [ -n "$agh" ] && killall -q -s HUP "$agh";;
817 reload)
818 [ -z "$resolver_set_supported" ] && return 1
819 output 3 'Reloading adguardhome '
820 if /etc/init.d/adguardhome reload >/dev/null 2>&1; then
821 output_okn
822 return 0
823 else
824 output_failn
825 return 1
826 fi
827 ;;
828 restart)
829 [ -z "$resolver_set_supported" ] && return 1
830 output 3 'Restarting adguardhome '
831 if /etc/init.d/adguardhome restart >/dev/null 2>&1; then
832 output_okn
833 return 0
834 else
835 output_failn
836 return 1
837 fi
838 ;;
839 compare_hash)
840 [ -z "$resolver_set_supported" ] && return 1
841 local resolverNewHash
842 if [ -s "$aghIpsetFile" ]; then
843 resolverNewHash="$(md5sum $aghIpsetFile | awk '{ print $1; }')"
844 fi
845 [ "$resolverNewHash" != "$resolverStoredHash" ]
846 ;;
847 store_hash)
848 [ -s "$aghIpsetFile" ] && resolverStoredHash="$(md5sum $aghIpsetFile | awk '{ print $1; }')";;
849 esac
850 ;;
851 dnsmasq.ipset)
852 case "$param" in
853 add_resolver_element)
854 [ -n "$resolver_set_supported" ] && ips 'add_dnsmasq_element' "$@";;
855 create_resolver_set)
856 [ -n "$resolver_set_supported" ] && ips 'create_dnsmasq_set' "$@";;
857 check_support)
858 if [ ! -x "$ipset" ]; then
859 state add 'errorSummary' 'errorNoIpset'
860 return 1
861 fi
862 if ! dnsmasq -v 2>/dev/null | grep -q 'no-ipset' && dnsmasq -v 2>/dev/null | grep -q 'ipset'; then
863 resolver_set_supported='true'
864 return 0
865 else
866 state add 'warningSummary' 'warningResolverNotSupported'
867 return 1
868 fi
869 ;;
870 cleanup)
871 [ -n "$resolver_set_supported" ] && rm -f "$dnsmasqFile";;
872 configure)
873 [ -n "$resolver_set_supported" ] && mkdir -p "${dnsmasqFile%/*}";;
874 init) :;;
875 init_end) :;;
876 kill)
877 [ -n "$resolver_set_supported" ] && killall -q -s HUP dnsmasq;;
878 reload)
879 [ -z "$resolver_set_supported" ] && return 1
880 output 3 'Reloading dnsmasq '
881 if /etc/init.d/dnsmasq reload >/dev/null 2>&1; then
882 output_okn
883 return 0
884 else
885 output_failn
886 return 1
887 fi
888 ;;
889 restart)
890 [ -z "$resolver_set_supported" ] && return 1
891 output 3 'Restarting dnsmasq '
892 if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then
893 output_okn
894 return 0
895 else
896 output_failn
897 return 1
898 fi
899 ;;
900 compare_hash)
901 [ -z "$resolver_set_supported" ] && return 1
902 local resolverNewHash
903 if [ -s "$dnsmasqFile" ]; then
904 resolverNewHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')"
905 fi
906 [ "$resolverNewHash" != "$resolverStoredHash" ]
907 ;;
908 store_hash)
909 [ -s "$dnsmasqFile" ] && resolverStoredHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')";;
910 esac
911 ;;
912 dnsmasq.nftset)
913 case "$param" in
914 add_resolver_element)
915 [ -n "$resolver_set_supported" ] && nftset 'add_dnsmasq_element' "$@";;
916 create_resolver_set)
917 [ -n "$resolver_set_supported" ] && nftset 'create_dnsmasq_set' "$@";;
918 check_support)
919 if [ ! -x "$nft" ]; then
920 state add 'errorSummary' 'errorNoNft'
921 return 1
922 fi
923 if ! dnsmasq -v 2>/dev/null | grep -q 'no-nftset' && dnsmasq -v 2>/dev/null | grep -q 'nftset'; then
924 resolver_set_supported='true'
925 return 0
926 else
927 state add 'warningSummary' 'warningResolverNotSupported'
928 return 1
929 fi
930 ;;
931 cleanup)
932 [ -n "$resolver_set_supported" ] && rm -f "$dnsmasqFile";;
933 configure)
934 [ -n "$resolver_set_supported" ] && mkdir -p "${dnsmasqFile%/*}";;
935 init) :;;
936 init_end) :;;
937 kill)
938 [ -n "$resolver_set_supported" ] && killall -q -s HUP dnsmasq;;
939 reload)
940 [ -z "$resolver_set_supported" ] && return 1
941 output 3 'Reloading dnsmasq '
942 if /etc/init.d/dnsmasq reload >/dev/null 2>&1; then
943 output_okn
944 return 0
945 else
946 output_failn
947 return 1
948 fi
949 ;;
950 restart)
951 [ -z "$resolver_set_supported" ] && return 1
952 output 3 'Restarting dnsmasq '
953 if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then
954 output_okn
955 return 0
956 else
957 output_failn
958 return 1
959 fi
960 ;;
961 compare_hash)
962 [ -z "$resolver_set_supported" ] && return 1
963 local resolverNewHash
964 if [ -s "$dnsmasqFile" ]; then
965 resolverNewHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')"
966 fi
967 [ "$resolverNewHash" != "$resolverStoredHash" ]
968 ;;
969 store_hash)
970 [ -s "$dnsmasqFile" ] && resolverStoredHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')";;
971 esac
972 ;;
973 unbound.ipset)
974 case "$param" in
975 add_resolver_element) :;;
976 create_resolver_set) :;;
977 check_support) :;;
978 cleanup) :;;
979 configure) :;;
980 init) :;;
981 init_end) :;;
982 kill) :;;
983 reload) :;;
984 restart) :;;
985 compare_hash) :;;
986 store_hash) :;;
987 esac
988 ;;
989 unbound.nftset)
990 case "$param" in
991 add_resolver_element) :;;
992 create_resolver_set) :;;
993 check_support) :;;
994 cleanup) :;;
995 configure) :;;
996 init) :;;
997 init_end) :;;
998 kill) :;;
999 reload) :;;
1000 restart) :;;
1001 compare_hash) :;;
1002 store_hash) :;;
1003 esac
1004 ;;
1005 esac
1006 }
1007
1008 trap_process() {
1009 # verbosity=0
1010 output "\\n"
1011 output "Unexpected exit or service termination: '${1}'!\\n"
1012 state add 'errorSummary' 'errorUnexpectedExit' "$1"
1013 traffic_killswitch 'remove'
1014 }
1015
1016 traffic_killswitch() {
1017 local s=0
1018 case "$1" in
1019 insert)
1020 local lan_subnet wan_device
1021 [ "$secure_reload" -ne 0 ] || return 0
1022 for i in $serviceTrapSignals; do
1023 # shellcheck disable=SC2064
1024 trap "trap_process $i" "$i"
1025 done
1026 output 3 'Activating traffic killswitch '
1027 network_get_subnet lan_subnet 'lan'
1028 network_get_physdev wan_device 'wan'
1029 if is_nft; then
1030 nft add chain inet "$nftTable" "${nftPrefix}_killswitch" '{ type filter hook forward priority 0; policy accept; }' || s=1
1031 nft add rule inet "$nftTable" "${nftPrefix}_killswitch" oifname "$wan_device" ip saddr "$lan_subnet" counter reject || s=1
1032 # nft add rule inet "$nftTable" "${nftPrefix}_killswitch" oifname '$wan_devices' ip saddr '$lan_subnet' counter reject || s=1
1033 else
1034 ipt -N "${iptPrefix}_KILLSWITCH" || s=1
1035 ipt -A "${iptPrefix}_KILLSWITCH" -s "$lan_subnet" -o "$wan_device" -j REJECT || s=1
1036 ipt -I FORWARD -j "${iptPrefix}_KILLSWITCH" || s=1
1037 fi
1038 if [ "$s" -eq 0 ]; then
1039 output_okn
1040 else
1041 output_failn
1042 fi
1043 ;;
1044 remove)
1045 if [ "$secure_reload" -ne 0 ]; then
1046 output 3 'Deactivating traffic killswitch '
1047 fi
1048 if is_nft; then
1049 nft flush chain inet "$nftTable" "${nftPrefix}_killswitch" || s=1
1050 nft delete chain inet "$nftTable" "${nftPrefix}_killswitch" || s=1
1051 else
1052 ipt -D FORWARD -j "${iptPrefix}_KILLSWITCH" || s=1
1053 ipt -F "${iptPrefix}_KILLSWITCH" || s=1
1054 ipt -X "${iptPrefix}_KILLSWITCH" || s=1
1055 fi
1056 if [ "$secure_reload" -ne 0 ]; then
1057 if [ "$s" -eq 0 ]; then
1058 output_okn
1059 else
1060 output_failn
1061 fi
1062 fi
1063 # shellcheck disable=SC2086
1064 trap - $serviceTrapSignals
1065 ;;
1066 esac
1067 }
1068
1069 policy_routing_tor() { if is_nft; then policy_routing_tor_nft "$@"; else policy_routing_tor_iptables "$@"; fi; }
1070 policy_routing_tor_iptables() {
1071 local comment="$1" iface="$2" src_addr="$3" src_port="$4" dest_addr="$5" dest_port="$6" proto chain uid="$9"
1072 proto="$(str_to_lower "$7")"
1073 chain="$(str_to_upper "$8")"
1074 chain="${chain:-PREROUTING}"
1075 if [ -n "${src_addr}${src_port}${dest_port}" ]; then
1076 processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'src_addr', 'src_port' and 'dest_port' for policy '$comment'\\n"
1077 fi
1078 if [ -n "$proto" ] && [ "$proto" != "all" ]; then
1079 processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'proto' or set 'proto' to 'all' for policy '$comment'\\n"
1080 fi
1081 if [ "$chain" != "PREROUTING" ]; then
1082 processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'chain' or set 'chain' to 'PREROUTING' for policy '$comment'\\n"
1083 fi
1084 resolver 'add_resolver_element' "$iface" 'dst' 'ip' '' "${comment}: $dest_addr" "$dest_addr" || \
1085 processPolicyError="${processPolicyError}${_ERROR_}: resolver 'add_resolver_element' '$iface' 'dst' 'ip' '${comment}: $dest_addr' '$dest_addr'\\n"
1086 return 0
1087 }
1088 policy_routing_tor_nft() {
1089 local comment="$1" iface="$2" src_addr="$3" src_port="$4" dest_addr="$5" dest_port="$6" proto chain uid="$9"
1090 proto="$(str_to_lower "$7")"
1091 chain="$(str_to_lower "$8")"
1092 chain="${chain:-prerouting}"
1093 if [ -n "${src_addr}${src_port}${dest_port}" ]; then
1094 processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'src_addr', 'src_port' and 'dest_port' for policy '$comment'\\n"
1095 fi
1096 if [ -n "$proto" ] && [ "$proto" != "all" ]; then
1097 processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'proto' or set 'proto' to 'all' for policy '$comment'\\n"
1098 fi
1099 if [ "$chain" != "prerouting" ]; then
1100 processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'chain' or set 'chain' to 'prerouting' for policy '$comment'\\n"
1101 fi
1102 resolver 'add_resolver_element' "$iface" 'dst' 'ip' '' "${comment}: $dest_addr" "$dest_addr" || \
1103 processPolicyError="${processPolicyError}${_ERROR_}: resolver 'add_resolver_element' '$iface' 'dst' 'ip' '${comment}: $dest_addr' '$dest_addr'\\n"
1104 return 0
1105 }
1106
1107 policy_routing() { if is_nft; then policy_routing_nft "$@"; else policy_routing_iptables "$@"; fi; }
1108 policy_routing_iptables() {
1109 local mark param4 param6 i negation value dest ipInsertOption="-A"
1110 local ip4error='1' ip6error='1'
1111 local name="$1" iface="$2" laddr="$3" lport="$4" raddr="$5" rport="$6" proto chain uid="$9"
1112 proto="$(str_to_lower "$7")"
1113 chain="$(str_to_upper "$8")"
1114 chain="${chain:-PREROUTING}"
1115 mark=$(eval echo "\$mark_${iface//-/_}")
1116
1117 if [ -n "$ipv6_enabled" ] && { is_ipv6 "$laddr" || is_ipv6 "$raddr"; }; then
1118 processPolicyError="${processPolicyError}${_ERROR_}: Skipping IPv6 policy '$name' as IPv6 support is disabled\\n"
1119 return 1
1120 fi
1121
1122 if [ -n "$mark" ]; then
1123 dest="-g ${iptPrefix}_MARK_${mark}"
1124 elif [ "$iface" = "ignore" ]; then
1125 dest="-j RETURN"
1126 else
1127 processPolicyError="${processPolicyError}${_ERROR_}: Unknown fw_mark for ${iface}\\n"
1128 return 1
1129 fi
1130
1131 if [ -z "$proto" ]; then
1132 if [ -n "$lport" ] || [ -n "$rport" ]; then
1133 proto='tcp udp'
1134 else
1135 proto='all'
1136 fi
1137 fi
1138
1139 if is_family_mismatch "$laddr" "$raddr"; then
1140 processPolicyError="${processPolicyError}${_ERROR_}: Mismatched IP family between '$laddr' and '$raddr' in policy '$name'\\n"
1141 return 1
1142 fi
1143
1144 for i in $proto; do
1145 if [ "$i" = 'all' ]; then
1146 param4="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest"
1147 param6="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest"
1148 elif ! is_supported_protocol "$i"; then
1149 processPolicyError="${processPolicyError}${_ERROR_}: Unknown protocol '$i' in policy '$name'\\n"
1150 return 1
1151 else
1152 param4="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest -p $i"
1153 param6="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest -p $i"
1154 fi
1155
1156 if [ -n "$laddr" ]; then
1157 if [ "${laddr:0:1}" = "!" ]; then
1158 negation='!'; value="${laddr:1}"
1159 else
1160 unset negation; value="$laddr";
1161 fi
1162 if is_phys_dev "$value"; then
1163 param4="$param4 $negation -m physdev --physdev-in ${value:1}"
1164 param6="$param6 $negation -m physdev --physdev-in ${value:1}"
1165 elif is_netmask "$value"; then
1166 local target='src' type='net'
1167 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \
1168 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then
1169 param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1170 param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1171 else
1172 param4="$param4 $negation -s $value"
1173 param6="$param6 $negation -s $value"
1174 fi
1175 elif is_mac_address "$value"; then
1176 local target='src' type='mac'
1177 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \
1178 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then
1179 param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1180 param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1181 else
1182 param4="$param4 -m mac $negation --mac-source $value"
1183 param6="$param6 -m mac $negation --mac-source $value"
1184 fi
1185 else
1186 local target='src' type='ip'
1187 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \
1188 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then
1189 param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1190 param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1191 else
1192 param4="$param4 $negation -s $(resolveip_to_ipt -4 "$value")"
1193 param6="$param6 $negation -s $(resolveip_to_ipt -6 "$value")"
1194 fi
1195 fi
1196 fi
1197
1198 if [ -n "$lport" ]; then
1199 if [ "${lport:0:1}" = "!" ]; then
1200 negation='!'; value="${lport:1}"
1201 else
1202 unset negation; value="$lport";
1203 fi
1204 param4="$param4 -m multiport $negation --sport ${value//-/:}"
1205 param6="$param6 -m multiport $negation --sport ${value//-/:}"
1206 fi
1207
1208 if [ -n "$raddr" ]; then
1209 if [ "${raddr:0:1}" = "!" ]; then
1210 negation='!'; value="${raddr:1}"
1211 else
1212 unset negation; value="$raddr";
1213 fi
1214 if is_netmask "$value"; then
1215 local target='dst' type='net'
1216 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \
1217 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then
1218 param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1219 param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1220 else
1221 param4="$param4 $negation -d $value"
1222 param6="$param6 $negation -d $value"
1223 fi
1224 elif is_domain "$value"; then
1225 local target='dst' type='ip'
1226 if resolver 'create_resolver_set' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \
1227 resolver 'add_resolver_element' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then
1228 param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1229 param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1230 elif ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \
1231 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then
1232 param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1233 param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1234 else
1235 param4="$param4 $negation -d $(resolveip_to_ipt -4 "$value")"
1236 param6="$param6 $negation -d $(resolveip_to_ipt -6 "$value")"
1237 fi
1238 else
1239 local target='dst' type='ip'
1240 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \
1241 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then
1242 param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1243 param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1244 else
1245 param4="$param4 $negation -d $value"
1246 param6="$param6 $negation -d $value"
1247 fi
1248 fi
1249 fi
1250
1251 if [ -n "$rport" ]; then
1252 if [ "${rport:0:1}" = "!" ]; then
1253 negation='!'; value="${rport:1}"
1254 else
1255 unset negation; value="$rport";
1256 fi
1257 param4="$param4 -m multiport $negation --dport ${value//-/:}"
1258 param6="$param6 -m multiport $negation --dport ${value//-/:}"
1259 fi
1260
1261 if [ -n "$name" ]; then
1262 param4="$param4 -m comment --comment $(str_extras_to_underscore "$name")"
1263 param6="$param6 -m comment --comment $(str_extras_to_underscore "$name")"
1264 fi
1265
1266 local ipv4_error='0' ipv6_error='0'
1267 if [ "$param4" = "$param6" ]; then
1268 ipt4 "$param4" || ipv4_error='1'
1269 else
1270 ipt4 "$param4" || ipv4_error='1'
1271 ipt6 "$param6" || ipv6_error='1'
1272 fi
1273
1274 # ipt6 returns true if IPv6 support is not enabled
1275 [ -z "$ipv6_enabled" ] && ipv6_error='1'
1276 if [ "$ipv4_error" -eq '1' ] && [ "$ipv6_error" -eq '1' ]; then
1277 if [ -n "$ipv6_enabled" ]; then
1278 processPolicyError="${processPolicyError}${_ERROR_}: Policy insertion failed for both IPv4 and IPv6!\\n"
1279 processPolicyError="${processPolicyError}${_ERROR_}: iptables $param4\\n"
1280 processPolicyError="${processPolicyError}${_ERROR_}: iptables $param6\\n"
1281 else
1282 processPolicyError="${processPolicyError}${_ERROR_}: iptables $param4\\n"
1283 fi
1284 fi
1285
1286 done
1287 }
1288 policy_routing_nft() {
1289 local mark param4 param6 i negation value dest nftInsertOption='add'
1290 local ip4Flag='ip' ip6Flag='ip6'
1291 local name="$1" iface="$2" laddr="$3" lport="$4" raddr="$5" rport="$6" proto chain uid="$9"
1292 proto="$(str_to_lower "$7")"
1293 chain="$(str_to_lower "$8")"
1294 chain="${chain:-prerouting}"
1295 mark=$(eval echo "\$mark_${iface//-/_}")
1296
1297 if [ -z "$ipv6_enabled" ] && { is_ipv6 "$src_addr" || is_ipv6 "$dest_addr"; }; then
1298 processPolicyError="${processPolicyError}${_ERROR_}: Skipping IPv6 policy '$name' as IPv6 support is disabled\\n"
1299 return 1
1300 fi
1301
1302 if [ -n "$mark" ]; then
1303 dest="goto ${nftPrefix}_mark_${mark}"
1304 elif [ "$iface" = "ignore" ]; then
1305 dest="return"
1306 else
1307 processPolicyError="${processPolicyError}${_ERROR_}: Unknown packet mark for ${iface}\\n"
1308 return 1
1309 fi
1310
1311 if is_family_mismatch "$src_addr" "$dest_addr"; then
1312 processPolicyError="${processPolicyError}${_ERROR_}: Mismatched IP family between '$src_addr' and '$dest_addr' in policy '$name'\\n"
1313 return 1
1314 fi
1315
1316 if [ -n "$proto" ] && ! is_supported_protocol "$proto"; then
1317 processPolicyError="${processPolicyError}${_ERROR_}: Unknown protocol '$i' in policy '$name'\\n"
1318 return 1
1319 fi
1320
1321 if [ -n "$src_addr" ]; then
1322 if [ "${src_addr:0:1}" = "!" ]; then
1323 negation='!='; value="${src_addr:1}"
1324 else
1325 unset negation; value="$src_addr";
1326 fi
1327 if is_phys_dev "$value"; then
1328 param4="$param4 iifname $negation ${value:1}"
1329 param6="$param6 iifname $negation ${value:1}"
1330 elif is_mac_address "$value"; then
1331 local target='src' type='mac'
1332 if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \
1333 nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1334 param4="$param4 ether saddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1335 param6="$param6 ether saddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1336 else
1337 param4="$param4 ether saddr $negation $value"
1338 param6="$param6 ether saddr $negation $value"
1339 fi
1340 else
1341 local target='src' type='ip'
1342 if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \
1343 nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1344 param4="$param4 $ip4Flag saddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1345 param6="$param6 $ip6Flag saddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1346 else
1347 param4="$param4 $ip4Flag saddr $negation $value"
1348 param6="$param6 $ip6Flag saddr $negation $value"
1349 fi
1350 fi
1351 fi
1352
1353 if [ -n "$dest_addr" ]; then
1354 if [ "${dest_addr:0:1}" = "!" ]; then
1355 negation='!='; value="${dest_addr:1}"
1356 else
1357 unset negation; value="$dest_addr";
1358 fi
1359 if is_phys_dev "$value"; then
1360 param4="$param4 oifname $negation ${value:1}"
1361 param6="$param6 oifname $negation ${value:1}"
1362 elif is_domain "$value"; then
1363 local target='dst' type='ip'
1364 if resolver 'create_resolver_set' "$iface" "$target" "$type" "$uid" "$name" && \
1365 resolver 'add_resolver_element' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1366 param4="$param4 $ip4Flag daddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1367 param6="$param6 $ip6Flag daddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1368 elif nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \
1369 nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1370 param4="$param4 $ip4Flag daddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1371 param6="$param6 $ip6Flag daddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1372 else
1373 param4="$param4 $ip4Flag daddr $negation {$(resolveip_to_nftset4 "$value")}"
1374 param6="$param6 $ip6Flag daddr $negation {$(resolveip_to_nftset6 "$value")}"
1375 fi
1376 else
1377 local target='dst' type='ip'
1378 if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \
1379 nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1380 param4="$param4 $ip4Flag daddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1381 param6="$param6 $ip6Flag daddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1382 else
1383 param4="$param4 $ip4Flag daddr $negation $value"
1384 param6="$param6 $ip6Flag daddr $negation $value"
1385 fi
1386 fi
1387 fi
1388
1389 if [ -n "${src_port}${dest_port}" ]; then
1390 proto="${proto:-tcp}"
1391 fi
1392
1393 if [ -n "$src_port" ]; then
1394 if [ "${src_port:0:1}" = "!" ]; then
1395 negation='!='; value="${src_port:1}"
1396 else
1397 unset negation; value="$src_port";
1398 fi
1399 param4="$param4 ${proto:+$proto }sport $negation {$(ports_to_nftset "$value")}"
1400 param6="$param6 ${proto:+$proto }sport $negation {$(ports_to_nftset "$value")}"
1401 fi
1402
1403 if [ -n "$dest_port" ]; then
1404 if [ "${dest_port:0:1}" = "!" ]; then
1405 negation='!='; value="${dest_port:1}"
1406 else
1407 unset negation; value="$dest_port";
1408 fi
1409 param4="$param4 ${proto:+$proto }dport $negation {$(ports_to_nftset "$value")}"
1410 param6="$param6 ${proto:+$proto }dport $negation {$(ports_to_nftset "$value")}"
1411 fi
1412
1413 param4="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} $param4 $dest comment \"$name\""
1414 param6="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} $param6 $dest comment \"$name\""
1415
1416 local ipv4_error='0' ipv6_error='0'
1417 if [ "$nftPrevParam4" != "$param4" ]; then
1418 nft4 "$param4" || ipv4_error='1'
1419 nftPrevParam4="$param4"
1420 fi
1421 if [ "$nftPrevParam6" != "$param6" ]; then
1422 nft6 "$param6" || ipv6_error='1'
1423 nftPrevParam6="$param6"
1424 fi
1425
1426 # nft6 returns true if IPv6 support is not enabled
1427 [ -z "$ipv6_enabled" ] && ipv6_error='1'
1428 if [ "$ipv4_error" -eq '1' ] && [ "$ipv6_error" -eq '1' ]; then
1429 if [ -n "$ipv6_enabled" ]; then
1430 processPolicyError="${processPolicyError}${_ERROR_}: Policy insertion failed for both IPv4 and IPv6!\\n"
1431 processPolicyError="${processPolicyError}${_ERROR_}: nft '$param4'\\n"
1432 processPolicyError="${processPolicyError}${_ERROR_}: nft '$param6'\\n"
1433 else
1434 processPolicyError="${processPolicyError}${_ERROR_}: nft '$param4'\\n"
1435 fi
1436 fi
1437 }
1438
1439 policy_process() {
1440 local i j uid="$9"
1441 if [ -z "$uid" ]; then # first non-recursive call
1442 [ "$enabled" -gt 0 ] || return 0
1443 unset processPolicyWarning
1444 unset processPolicyError
1445 uid="$1"
1446 if is_nft; then
1447 chain="$(str_to_lower "$chain")"
1448 else
1449 chain="$(str_to_upper "$chain")"
1450 fi
1451 proto="$(str_to_lower "$proto")"
1452 [ "$proto" = 'auto' ] && unset proto
1453 [ "$proto" = 'all' ] && unset proto
1454 output 2 "Routing '$name' via $interface "
1455 if [ -z "${src_addr}${src_port}${dest_addr}${dest_port}" ]; then
1456 state add 'errorSummary' 'errorPolicyNoSrcDest' "$name"
1457 output_fail; return 1;
1458 fi
1459 if [ -z "$interface" ]; then
1460 state add 'errorSummary' 'errorPolicyNoInterface' "$name"
1461 output_fail; return 1;
1462 fi
1463 if ! is_supported_interface "$interface"; then
1464 state add 'errorSummary' 'errorPolicyUnknownInterface' "$name"
1465 output_fail; return 1;
1466 fi
1467 src_port="${src_port// / }"; src_port="${src_port// /,}"; src_port="${src_port//,\!/ !}";
1468 dest_port="${dest_port// / }"; dest_port="${dest_port// /,}"; dest_port="${dest_port//,\!/ !}";
1469 if is_nft; then
1470 nftset 'flush' "$interface" "dst" "ip" "$uid"
1471 nftset 'flush' "$interface" "src" "ip" "$uid"
1472 nftset 'flush' "$interface" "src" "mac" "$uid"
1473 else
1474 ips 'flush' "$interface" "dst" "ip" "$uid"
1475 ips 'flush' "$interface" "src" "ip" "$uid"
1476 ips 'flush' "$interface" "src" "mac" "$uid"
1477 fi
1478 policy_process "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"
1479 if [ -n "$processPolicyWarning" ]; then
1480 state add 'warningSummary' 'warningPolicyProcess' "$processPolicyWarning"
1481 fi
1482 if [ -n "$processPolicyError" ]; then
1483 output_fail
1484 state add 'errorSummary' 'errorPolicyProcess' "$processPolicyError"
1485 else
1486 output_ok
1487 fi
1488 else # recursive call, get options from passed variables
1489 local name="$1" interface="$2" src_addr="$3" src_port="$4" dest_addr="$5" dest_port="$6" proto="$7" chain="$8"
1490 if str_contains "$src_addr" '[ ;\{\}]'; then
1491 for i in $(str_extras_to_space "$src_addr"); do [ -n "$i" ] && policy_process "$name" "$interface" "$i" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"; done
1492 elif str_contains "$src_port" '[ ;\{\}]'; then
1493 for i in $(str_extras_to_space "$src_port"); do [ -n "$i" ] && policy_process "$name" "$interface" "$src_addr" "$i" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"; done
1494 elif str_contains "$dest_addr" '[ ;\{\}]'; then
1495 for i in $(str_extras_to_space "$dest_addr"); do [ -n "$i" ] && policy_process "$name" "$interface" "$src_addr" "$src_port" "$i" "$dest_port" "$proto" "$chain" "$uid"; done
1496 elif str_contains "$dest_port" '[ ;\{\}]'; then
1497 for i in $(str_extras_to_space "$dest_port"); do [ -n "$i" ] && policy_process "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$i" "$proto" "$chain" "$uid"; done
1498 elif str_contains "$proto" '[ ;\{\}]'; then
1499 for i in $(str_extras_to_space "$proto"); do [ -n "$i" ] && policy_process "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$i" "$chain" "$uid"; done
1500 else
1501 if is_tor "$interface"; then
1502 policy_routing_tor "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"
1503 else
1504 policy_routing "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"
1505 fi
1506 fi
1507 fi
1508 }
1509
1510 interface_process_tor() { if is_nft; then interface_process_tor_nft "$@"; else interface_process_tor_iptables "$@"; fi; }
1511 interface_process_tor_iptables() {
1512 local s=0 iface="$1" action="$2"
1513 local displayText set_name4 set_name6
1514 local dnsPort trafficPort
1515 case "$action" in
1516 reload)
1517 displayText="${iface}/53->${dnsPort}/80,443->${trafficPort}"
1518 gatewaySummary="${gatewaySummary}${displayText}\\n"
1519 ;;
1520 destroy)
1521 for i in $chainsList; do
1522 i="$(str_to_upper "$i")"
1523 ipt -t nat -D "${i}" -m mark --mark "0x0/${fw_mask}" -j "${nftPrefix}_${i}"
1524 ipt -t nat -F "${nftPrefix}_${i}"; ipt -t nat -X "${nftPrefix}_${i}";
1525 done
1526 ;;
1527 create)
1528 output 2 "Creating TOR redirects "
1529 dnsPort="$(grep -m1 DNSPort /etc/tor/torrc | awk -F: '{print $2}')"
1530 trafficPort="$(grep -m1 TransPort /etc/tor/torrc | awk -F: '{print $2}')"
1531 dnsPort="${dnsPort:-9053}"; trafficPort="${trafficPort:-9040}";
1532 for i in $chainsList; do
1533 ipt -t nat -N "${nftPrefix}_${i}"
1534 ipt -t nat -A "$i" -m mark --mark "0x0/${fw_mask}" -j "${nftPrefix}_${i}"
1535 done
1536 if resolver 'create_resolver_set' "$iface" 'dst' 'ip' && ips 'flush' "$iface" 'dst' 'ip'; then
1537 set_name4="${ipsPrefix}_${iface}_4_dst_ip"
1538 for i in $chainsList; do
1539 i="$(str_to_lower "$i")"
1540 ipt -t nat -I "${nftPrefix}_${i}" -p udp -m udp --dport 53 -m set --match-set "${set_name4}" dst -j REDIRECT --to-ports "$dnsPort" -m comment --comment "TorDNS-UDP" || s=1
1541 ipt -t nat -I "${nftPrefix}_${i}" -p tcp -m tcp --dport 80 -m set --match-set "${set_name4}" dst -j REDIRECT --to-ports "$trafficPort" -m comment --comment "TorHTTP-TCP" || s=1
1542 ipt -t nat -I "${nftPrefix}_${i}" -p udp -m udp --dport 80 -m set --match-set "${set_name4}" dst -j REDIRECT --to-ports "$trafficPort" -m comment --comment "TorHTTP-UDP" || s=1
1543 ipt -t nat -I "${nftPrefix}_${i}" -p tcp -m tcp --dport 443 -m set --match-set "${set_name4}" dst -j REDIRECT --to-ports "$trafficPort" -m comment --comment "TorHTTPS-TCP" || s=1
1544 ipt -t nat -I "${nftPrefix}_${i}" -p udp -m udp --dport 443 -m set --match-set "${set_name4}" dst -j REDIRECT --to-ports "$trafficPort" -m comment --comment "TorHTTPS-UDP" || s=1
1545 done
1546 else
1547 s=1
1548 fi
1549 displayText="${iface}/53->${dnsPort}/80,443->${trafficPort}"
1550 if [ "$s" -eq 0 ]; then
1551 gatewaySummary="${gatewaySummary}${displayText}\\n"
1552 output_ok
1553 else
1554 state add 'errorSummary' 'errorFailedSetup' "$displayText"
1555 output_fail
1556 fi
1557 ;;
1558 esac
1559 return $s
1560 }
1561 interface_process_tor_nft() {
1562 local s=0 iface="$1" action="$2"
1563 local displayText set_name4 set_name6
1564 local dnsPort trafficPort
1565 case "$action" in
1566 reload)
1567 displayText="${iface}/53->${dnsPort}/80,443->${trafficPort}"
1568 gatewaySummary="${gatewaySummary}${displayText}\\n"
1569 ;;
1570 destroy)
1571 ;;
1572 create)
1573 output 2 "Creating TOR redirects "
1574 dnsPort="$(grep -m1 DNSPort /etc/tor/torrc | awk -F: '{print $2}')"
1575 trafficPort="$(grep -m1 TransPort /etc/tor/torrc | awk -F: '{print $2}')"
1576 dnsPort="${dnsPort:-9053}"; trafficPort="${trafficPort:-9040}";
1577 if resolver 'create_resolver_set' "$iface" 'dst' 'ip' && nftset 'flush' "$iface" 'dst' 'ip'; then
1578 set_name4="${nftPrefix}_${iface}_4_dst_ip"
1579 set_name6="${nftPrefix}_${iface}_6_dst_ip"
1580 nft meta nfproto ipv4 udp daddr "@${set_name4}" dport 53 counter redirect to :"$dnsPort" comment "Tor-DNS-UDP-ipv4" || s=1
1581 nft meta nfproto ipv4 tcp daddr "@${set_name4}" dport 80 counter redirect to :"$trafficPort" comment "Tor-HTTP-TCP-ipv4" || s=1
1582 nft meta nfproto ipv4 udp daddr "@${set_name4}" dport 80 counter redirect to :"$trafficPort" comment "Tor-HTTP-UDP-ipv4" || s=1
1583 nft meta nfproto ipv4 tcp daddr "@${set_name4}" dport 443 counter redirect to :"$trafficPort" comment "Tor-HTTPS-TCP-ipv4" || s=1
1584 nft meta nfproto ipv4 udp daddr "@${set_name4}" dport 443 counter redirect to :"$trafficPort" comment "Tor-HTTPS-UDP-ipv4" || s=1
1585 nft6 meta nfproto ipv6 udp daddr "@${set_name6}" dport 53 counter redirect to :"$dnsPort" comment "Tor-DNS-UDP-ipv6" || s=1
1586 nft6 meta nfproto ipv6 tcp daddr "@${set_name6}" dport 80 counter redirect to :"$trafficPort" comment "Tor-HTTP-TCP-ipv6" || s=1
1587 nft6 meta nfproto ipv6 udp daddr "@${set_name6}" dport 80 counter redirect to :"$trafficPort" comment "Tor-HTTP-UDP-ipv6" || s=1
1588 nft6 meta nfproto ipv6 tcp daddr "@${set_name6}" dport 443 counter redirect to :"$trafficPort" comment "Tor-HTTPS-TCP-ipv6" || s=1
1589 nft6 meta nfproto ipv6 udp daddr "@${set_name6}" dport 443 counter redirect to :"$trafficPort" comment "Tor-HTTPS-UDP-ipv6" || s=1
1590 else
1591 s=1
1592 fi
1593 displayText="${iface}/53->${dnsPort}/80,443->${trafficPort}"
1594 if [ "$s" -eq 0 ]; then
1595 gatewaySummary="${gatewaySummary}${displayText}\\n"
1596 output_ok
1597 else
1598 state add 'errorSummary' 'errorFailedSetup' "$displayText"
1599 output_fail
1600 fi
1601 ;;
1602 esac
1603 return $s
1604 }
1605
1606 interface_routing() {
1607 local action="$1" tid="$2" mark="$3" iface="$4" gw4="$5" dev="$6" gw6="$7" dev6="$8" priority="$9"
1608 local dscp s=0 i ipv4_error=1 ipv6_error=1
1609 if [ -z "$tid" ] || [ -z "$mark" ] || [ -z "$iface" ]; then
1610 return 1
1611 fi
1612 case "$action" in
1613 create)
1614 if is_netifd_table "$iface"; then
1615 ipv4_error=0
1616 $ip_full -4 rule del fwmark "${mark}/${fw_mask}" table "$tid" >/dev/null 2>&1
1617 $ip_full -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
1618 if is_nft; then
1619 nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1
1620 nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1
1621 nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1
1622 else
1623 ipt -t mangle -N "${iptPrefix}_MARK_${mark}" || ipv4_error=1
1624 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j MARK --set-xmark "${mark}/${fw_mask}" || ipv4_error=1
1625 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j RETURN || ipv4_error=1
1626 fi
1627 if [ -n "$ipv6_enabled" ]; then
1628 ipv6_error=0
1629 $ip_full -6 rule del fwmark "${mark}/${fw_mask}" table "$tid" >/dev/null 2>&1
1630 $ip_full -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1
1631 fi
1632 else
1633 sed -i "/${ipTablePrefix}_${iface}/d" /etc/iproute2/rt_tables
1634 $ip_full -4 rule del fwmark "${mark}/${fw_mask}" table "$tid" >/dev/null 2>&1
1635 $ip_full -4 route flush table "$tid" >/dev/null 2>&1
1636 if [ -n "$gw4" ] || [ "$strict_enforcement" -ne 0 ]; then
1637 ipv4_error=0
1638 echo "$tid ${ipTablePrefix}_${iface}" >> /etc/iproute2/rt_tables
1639 if [ -z "$gw4" ]; then
1640 $ip_full -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1
1641 else
1642 $ip_full -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1
1643 fi
1644 # shellcheck disable=SC2086
1645 while read -r i; do
1646 i="$(echo "$i" | sed 's/ linkdown$//')"
1647 i="$(echo "$i" | sed 's/ onlink$//')"
1648 idev="$(echo "$i" | grep -Eso 'dev [^ ]*' | awk '{print $2}')"
1649 if ! is_supported_iface_dev "$idev"; then
1650 $ip_full -4 route add $i table "$tid" >/dev/null 2>&1 || ipv4_error=1
1651 fi
1652 done << EOF
1653 $($ip_full -4 route list table main)
1654 EOF
1655 $ip_full -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
1656 if is_nft; then
1657 nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1
1658 nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1
1659 nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1
1660 else
1661 ipt -t mangle -N "${iptPrefix}_MARK_${mark}" || ipv4_error=1
1662 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j MARK --set-xmark "${mark}/${fw_mask}" || ipv4_error=1
1663 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j RETURN || ipv4_error=1
1664 fi
1665 fi
1666 if [ -n "$ipv6_enabled" ]; then
1667 ipv6_error=0
1668 $ip_full -6 rule del fwmark "${mark}/${fw_mask}" table "$tid" >/dev/null 2>&1
1669 $ip_full -6 route flush table "$tid" >/dev/null 2>&1
1670 if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strict_enforcement" -ne 0 ]; then
1671 if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then
1672 $ip_full -6 route add unreachable default table "$tid" || ipv6_error=1
1673 elif $ip_full -6 route list table main | grep -q " dev $dev6 "; then
1674 while read -r i; do
1675 i="$(echo "$i" | sed 's/ linkdown$//')"
1676 i="$(echo "$i" | sed 's/ onlink$//')"
1677 $ip_full -6 route add "$i" table "$tid" >/dev/null 2>&1 || ipv6_error=1
1678 done << EOF
1679 $($ip_full -6 route list table main | grep " dev $dev6 ")
1680 EOF
1681 else
1682 $ip_full -6 route add "$($ip_full -6 -o a show "$dev6" | awk '{print $4}')" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
1683 $ip_full -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
1684 fi
1685 fi
1686 $ip_full -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1
1687 fi
1688 fi
1689 if [ "$ipv4_error" -eq 0 ] || [ "$ipv6_error" -eq 0 ]; then
1690 dscp="$(uci -q get "${packageName}".config."${iface}"_dscp)"
1691 if is_nft; then
1692 if [ "${dscp:-0}" -ge 1 ] && [ "${dscp:-0}" -le 63 ]; then
1693 nft add rule inet "$nftTable" "${nftPrefix}_prerouting ip dscp ${dscp} goto ${nftPrefix}_mark_${mark}" || s=1
1694 fi
1695 if [ "$iface" = "$icmp_interface" ]; then
1696 nft add rule inet "$nftTable" "${nftPrefix}_output ip protocol icmp goto ${nftPrefix}_mark_${mark}" || s=1
1697 fi
1698 else
1699 if [ "${dscp:-0}" -ge 1 ] && [ "${dscp:-0}" -le 63 ]; then
1700 ipt -t mangle -I "${iptPrefix}_PREROUTING" -m dscp --dscp "${dscp}" -g "${iptPrefix}_MARK_${mark}" || s=1
1701 fi
1702 if [ "$iface" = "$icmp_interface" ]; then
1703 ipt -t mangle -I "${iptPrefix}_OUTPUT" -p icmp -g "${iptPrefix}_MARK_${mark}" || s=1
1704 fi
1705 fi
1706 else
1707 s=1
1708 fi
1709 return "$s"
1710 ;;
1711 create_user_set)
1712 [ -z "$createUserSets" ] && return 0;
1713 if is_nft; then
1714 nftset 'create_user_set' "$iface" 'dst' 'ip' 'user' '' "$mark" || s=1
1715 nftset 'create_user_set' "$iface" 'src' 'ip' 'user' '' "$mark" || s=1
1716 nftset 'create_user_set' "$iface" 'src' 'mac' 'user' '' "$mark" || s=1
1717 else
1718 ips 'create_user_set' "$iface" 'dst' 'ip' 'user' '' "$mark" || s=1
1719 ips 'create_user_set' "$iface" 'src' 'ip' 'user' '' "$mark" || s=1
1720 ips 'create_user_set' "$iface" 'dst' 'net' 'user' '' "$mark" || s=1
1721 ips 'create_user_set' "$iface" 'src' 'net' 'user' '' "$mark" || s=1
1722 ips 'create_user_set' "$iface" 'src' 'mac' 'user' '' "$mark" || s=1
1723 fi
1724 return "$s"
1725 ;;
1726 delete|destroy)
1727 $ip_full rule del fwmark "${mark}/${fw_mask}" table "$tid" >/dev/null 2>&1
1728 if ! is_netifd_table "$iface"; then
1729 $ip_full route flush table "$tid" >/dev/null 2>&1
1730 sed -i "/${ipTablePrefix}_${iface}/d" /etc/iproute2/rt_tables
1731 fi
1732 return "$s"
1733 ;;
1734 reload_interface)
1735 is_netifd_table "$iface" && return 0;
1736 ipv4_error=0
1737 $ip_full -4 rule del fwmark "${mark}/${fw_mask}" table "$tid" >/dev/null 2>&1
1738 $ip_full -4 route flush table "$tid" >/dev/null 2>&1
1739 if [ -n "$gw4" ] || [ "$strict_enforcement" -ne 0 ]; then
1740 if [ -z "$gw4" ]; then
1741 $ip_full -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1
1742 else
1743 $ip_full -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1
1744 fi
1745 $ip_full rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
1746 fi
1747 if [ -n "$ipv6_enabled" ]; then
1748 ipv6_error=0
1749 $ip_full -6 rule del fwmark "${mark}/${fw_mask}" table "$tid" >/dev/null 2>&1
1750 $ip_full -6 route flush table "$tid" >/dev/null 2>&1
1751 if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strict_enforcement" -ne 0 ]; then
1752 if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then
1753 $ip_full -6 route add unreachable default table "$tid" || ipv6_error=1
1754 elif $ip_full -6 route list table main | grep -q " dev $dev6 "; then
1755 while read -r i; do
1756 $ip_full -6 route add "$i" table "$tid" >/dev/null 2>&1 || ipv6_error=1
1757 done << EOF
1758 $($ip_full -6 route list table main | grep " dev $dev6 ")
1759 EOF
1760 else
1761 $ip_full -6 route add "$($ip_full -6 -o a show "$dev6" | awk '{print $4}')" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
1762 $ip_full -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
1763 fi
1764 fi
1765 $ip_full -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1
1766 fi
1767 if [ "$ipv4_error" -eq 0 ] || [ "$ipv6_error" -eq 0 ]; then
1768 s=0
1769 else
1770 s=1
1771 fi
1772 return "$s"
1773 ;;
1774 esac
1775 }
1776
1777 json_add_gateway() {
1778 local action="$1" tid="$2" mark="$3" iface="$4" gw4="$5" dev4="$6" gw6="$7" dev6="$8" priority="$9" default="${10}"
1779 json_add_object ''
1780 json_add_string name "$iface"
1781 json_add_string device_ipv4 "$dev4"
1782 json_add_string gateway_ipv4 "$gw4"
1783 json_add_string device_ipv6 "$dev6"
1784 json_add_string gateway_ipv6 "$gw6"
1785 if [ -n "$default" ]; then
1786 json_add_boolean default true
1787 else
1788 json_add_boolean default false
1789 fi
1790 json_add_string action "$action"
1791 json_add_string table_id "$tid"
1792 json_add_string mark "$mark"
1793 json_add_string priority "$priority"
1794 json_close_object
1795 }
1796
1797 interface_process() {
1798 local gw4 gw6 dev dev6 s=0 dscp iface="$1" action="$2" reloadedIface="$3"
1799 local displayText dispDev dispGw4 dispGw6 dispStatus
1800
1801 if [ "$iface" = 'all' ] && [ "$action" = 'prepare' ]; then
1802 config_load 'network'
1803 ifaceMark="$(printf '0x%06x' "$wan_mark")"
1804 ifacePriority="$wan_ip_rules_priority"
1805 return 0
1806 fi
1807
1808 is_supported_interface "$iface" || return 0
1809 is_wan6 "$iface" && return 0
1810 [ $((ifaceMark)) -gt $((fw_mask)) ] && return 1
1811
1812 network_get_device dev "$iface"
1813 if is_wan "$iface" && [ -n "$wanIface6" ] && str_contains "$wanIface6" "$iface"; then
1814 network_get_device dev6 "$wanIface6"
1815 fi
1816
1817 [ -z "$dev6" ] && dev6="$dev"
1818 [ -z "$ifaceMark" ] && ifaceMark="$(printf '0x%06x' "$wan_mark")"
1819 [ -z "$ifacePriority" ] && ifacePriority="$wan_ip_rules_priority"
1820
1821 ifaceTableID="$(get_rt_tables_id "$iface")"
1822 [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)"
1823 eval "mark_${iface//-/_}"='$ifaceMark'
1824 eval "tid_${iface//-/_}"='$ifaceTableID'
1825 pbr_get_gateway gw4 "$iface" "$dev"
1826 pbr_get_gateway6 gw6 "$iface" "$dev6"
1827 dispGw4="${gw4:-0.0.0.0}"
1828 dispGw6="${gw6:-::/0}"
1829 [ "$iface" != "$dev" ] && dispDev="$dev"
1830 is_default_dev "$dev" && dispStatus="${__OK__}"
1831 displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}"
1832
1833 case "$action" in
1834 create)
1835 output 2 "Setting up routing for '$displayText' "
1836 if interface_routing 'create' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" && \
1837 interface_routing 'create_user_set' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"; then
1838 json_add_gateway 'create' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" "$dispStatus"
1839 gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n"
1840 output_ok
1841 else
1842 state add 'errorSummary' 'errorFailedSetup' "$displayText"
1843 output_fail
1844 fi
1845 ;;
1846 # create_user_set)
1847 # interface_routing 'create_user_set' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"
1848 # ;;
1849 destroy)
1850 displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}"
1851 output 2 "Removing routing for '$displayText' "
1852 interface_routing 'destroy' "${ifaceTableID}" "${ifaceMark}" "${iface}"
1853 output_ok
1854 ;;
1855 reload)
1856 gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n"
1857 ;;
1858 reload_interface)
1859 if [ "$iface" = "$reloadedIface" ]; then
1860 output 2 "Reloading routing for '$displayText' "
1861 if interface_routing 'reload_interface' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"; then
1862 json_add_gateway 'reload_interface' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" "$dispStatus"
1863 gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n"
1864 output_ok
1865 else
1866 state add 'errorSummary' 'errorFailedReload' "$displayText"
1867 output_fail
1868 fi
1869 else
1870 gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n"
1871 fi
1872 ;;
1873 esac
1874 # ifaceTableID="$((ifaceTableID + 1))"
1875 ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))"
1876 ifacePriority="$((ifacePriority + 1))"
1877 return $s
1878 }
1879
1880 user_file_process() {
1881 local shellBin="${SHELL:-/bin/ash}"
1882 [ "$enabled" -gt 0 ] || return 0
1883 if [ ! -s "$path" ]; then
1884 state add 'errorSummary' 'errorUserFileNotFound' "$path"
1885 output_fail
1886 return 1
1887 fi
1888 if ! $shellBin -n "$path"; then
1889 state add 'errorSummary' 'ererrorUserFileSyntax' "$path"
1890 output_fail
1891 return 1
1892 fi
1893 output 2 "Running $path "
1894 # shellcheck disable=SC1090
1895 if ! . "$path"; then
1896 state add 'errorSummary' 'errorUserFileRunning' "$path"
1897 if grep -q -w 'curl' "$path" && ! is_present 'curl'; then
1898 state add 'errorSummary' 'errorUserFileNoCurl' "$path"
1899 fi
1900 output_fail
1901 return 1
1902 else
1903 output_ok
1904 return 0
1905 fi
1906 }
1907
1908 on_firewall_reload() {
1909 if [ -z "$(ubus_get_status 'gateways')" ]; then # service is not running, do not start it on firewall reload
1910 logger -t "$packageName" "Reload on firewall action aborted: service not running."
1911 return 0;
1912 else
1913 rc_procd start_service 'on_firewall_reload' "$1"
1914 fi
1915 }
1916 on_interface_reload() { rc_procd start_service 'on_interface_reload' "$1"; }
1917
1918 start_service() {
1919 local resolverStoredHash resolverNewHash i reloadedIface param="$1"
1920 local createUserSets
1921
1922 load_environment 'on_start' "$(load_validate_config)" || return 1
1923 is_wan_up || return 1
1924 rm -f "$nftTempFile"
1925
1926 case "$param" in
1927 on_boot)
1928 serviceStartTrigger='on_start'
1929 ;;
1930 on_firewall_reload)
1931 serviceStartTrigger='on_start'
1932 ;;
1933 on_interface_reload)
1934 serviceStartTrigger='on_interface_reload'
1935 reloadedIface="$2"
1936 ;;
1937 on_reload)
1938 serviceStartTrigger='on_reload'
1939 ;;
1940 on_restart)
1941 serviceStartTrigger='on_start'
1942 ;;
1943 esac
1944
1945 if [ -n "$reloadedIface" ] && ! is_supported_interface "$reloadedIface"; then
1946 return 0
1947 fi
1948
1949 if [ -n "$(ubus_get_status error)" ] || [ -n "$(ubus_get_status warning)" ]; then
1950 serviceStartTrigger='on_start'
1951 unset reloadedIface
1952 elif ! is_service_running; then
1953 serviceStartTrigger='on_start'
1954 unset reloadedIface
1955 elif [ -z "$(ubus_get_status gateway)" ]; then
1956 serviceStartTrigger='on_start'
1957 unset reloadedIface
1958 elif [ "$serviceStartTrigger" = 'on_interface_reload' ] && \
1959 [ -z "$(ubus_get_interface "$reloadedIface" 'gateway_4')" ] && \
1960 [ -z "$(ubus_get_interface "$reloadedIface" 'gateway_6')" ]; then
1961 serviceStartTrigger='on_start'
1962 unset reloadedIface
1963 else
1964 serviceStartTrigger="${serviceStartTrigger:-on_start}"
1965 fi
1966
1967 if is_config_enabled 'include'; then
1968 createUserSets='true'
1969 fi
1970
1971 procd_open_instance "main"
1972 procd_set_param command /bin/true
1973 procd_set_param stdout 1
1974 procd_set_param stderr 1
1975 procd_open_data
1976
1977 case $serviceStartTrigger in
1978 on_interface_reload)
1979 output 1 "Reloading Interface: $reloadedIface "
1980 json_add_array 'gateways'
1981 interface_process 'all' 'prepare'
1982 config_foreach interface_process 'interface' 'reload_interface' "$reloadedIface"
1983 json_close_array
1984 output 1 '\n'
1985 ;;
1986 on_reload)
1987 traffic_killswitch 'insert'
1988 resolver 'store_hash'
1989 resolver 'cleanup_all'
1990 resolver 'configure'
1991 resolver 'init'
1992 cleanup_main_chains
1993 cleanup_sets
1994 if ! is_nft; then
1995 for i in $chainsList; do
1996 i="$(str_to_upper "$i")"
1997 ipt -t mangle -N "${iptPrefix}_${i}"
1998 ipt -t mangle "$rule_create_option" "$i" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}"
1999 done
2000 fi
2001 json_add_array 'gateways'
2002 interface_process 'all' 'prepare'
2003 config_foreach interface_process 'interface' 'reload'
2004 interface_process_tor 'tor' 'destroy'
2005 is_tor_running && interface_process_tor 'tor' 'reload'
2006 json_close_array
2007 if is_config_enabled 'policy'; then
2008 output 1 'Processing policies '
2009 config_load "$packageName"
2010 config_foreach load_validate_policy 'policy' policy_process
2011 output 1 '\n'
2012 fi
2013 if is_config_enabled 'include'; then
2014 traffic_killswitch 'remove'
2015 output 1 'Processing user file(s) '
2016 config_load "$packageName"
2017 config_foreach load_validate_include 'include' user_file_process
2018 output 1 '\n'
2019 resolver 'init_end'
2020 resolver 'compare_hash' && resolver 'restart'
2021 else
2022 resolver 'init_end'
2023 resolver 'compare_hash' && resolver 'restart'
2024 traffic_killswitch 'remove'
2025 fi
2026 ;;
2027 on_start|*)
2028 traffic_killswitch 'insert'
2029 resolver 'store_hash'
2030 resolver 'cleanup_all'
2031 resolver 'configure'
2032 resolver 'init'
2033 cleanup_main_chains
2034 cleanup_sets
2035 cleanup_marking_chains
2036 if ! is_nft; then
2037 for i in $chainsList; do
2038 i="$(str_to_upper "$i")"
2039 ipt -t mangle -N "${iptPrefix}_${i}"
2040 ipt -t mangle "$rule_create_option" "$i" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}"
2041 done
2042 fi
2043 output 1 'Processing interfaces '
2044 json_add_array 'gateways'
2045 interface_process 'all' 'prepare'
2046 config_foreach interface_process 'interface' 'create'
2047 interface_process_tor 'tor' 'destroy'
2048 is_tor_running && interface_process_tor 'tor' 'create'
2049 json_close_array
2050 ip route flush cache
2051 output 1 '\n'
2052 if is_config_enabled 'policy'; then
2053 output 1 'Processing policies '
2054 config_load "$packageName"
2055 config_foreach load_validate_policy 'policy' policy_process
2056 output 1 '\n'
2057 fi
2058 if is_config_enabled 'include'; then
2059 traffic_killswitch 'remove'
2060 output 1 'Processing user file(s) '
2061 config_load "$packageName"
2062 config_foreach load_validate_include 'include' user_file_process
2063 output 1 '\n'
2064 resolver 'init_end'
2065 resolver 'compare_hash' && resolver 'restart'
2066 else
2067 resolver 'init_end'
2068 resolver 'compare_hash' && resolver 'restart'
2069 traffic_killswitch 'remove'
2070 fi
2071 ;;
2072 esac
2073
2074 if [ -z "$gatewaySummary" ]; then
2075 state add 'errorSummary' 'errorNoGateways'
2076 fi
2077 json_add_object 'status'
2078 [ -n "$gatewaySummary" ] && json_add_string 'gateways' "$gatewaySummary"
2079 [ -n "$errorSummary" ] && json_add_string 'errors' "$errorSummary"
2080 [ -n "$warningSummary" ] && json_add_string 'warnings' "$warningSummary"
2081 if [ "$strict_enforcement" -ne 0 ] && str_contains "$gatewaySummary" '0.0.0.0'; then
2082 json_add_string 'mode' "strict"
2083 fi
2084 json_close_object
2085 procd_close_data
2086 procd_close_instance
2087 }
2088
2089 service_started() {
2090 if is_nft; then
2091 [ -n "$gatewaySummary" ] && output "$serviceName (nft) started with gateways:\\n${gatewaySummary}"
2092 else
2093 [ -n "$gatewaySummary" ] && output "$serviceName (iptables) started with gateways:\\n${gatewaySummary}"
2094 fi
2095 state print 'errorSummary'
2096 state print 'warningSummary'
2097 if [ -n "$errorSummary" ]; then
2098 return 2
2099 elif [ -n "$warningSummary" ]; then
2100 return 1
2101 else
2102 return 0
2103 fi
2104 }
2105
2106 service_triggers() {
2107 local n
2108 load_environment 'on_triggers'
2109 # shellcheck disable=SC2034
2110 PROCD_RELOAD_DELAY=$(( procd_reload_delay * 1000 ))
2111 procd_open_validate
2112 load_validate_config
2113 load_validate_policy
2114 load_validate_include
2115 procd_close_validate
2116 procd_open_trigger
2117 procd_add_reload_trigger 'openvpn'
2118 procd_add_config_trigger "config.change" "${packageName}" /etc/init.d/${packageName} reload
2119 for n in $ifacesSupported; do
2120 procd_add_interface_trigger "interface.*" "$n" /etc/init.d/${packageName} on_interface_reload "$n"
2121 done
2122 procd_close_trigger
2123 if [ "$serviceStartTrigger" = 'on_start' ]; then
2124 output 3 "$serviceName monitoring interfaces: ${ifacesSupported}\\n"
2125 fi
2126 }
2127
2128 stop_service() {
2129 local i
2130 load_environment 'on_stop'
2131 is_service_running || return 0
2132 traffic_killswitch 'insert'
2133 cleanup_main_chains
2134 cleanup_sets
2135 cleanup_marking_chains
2136 output 1 'Resetting interfaces '
2137 config_load 'network'
2138 config_foreach interface_process 'interface' 'destroy'
2139 interface_process_tor 'tor' 'destroy'
2140 output 1 "\\n"
2141 ip route flush cache
2142 unset ifaceMark
2143 unset ifaceTableID
2144 resolver 'store_hash'
2145 resolver 'cleanup_all'
2146 resolver 'compare_hash' && resolver 'restart'
2147 traffic_killswitch 'remove'
2148 if [ "$enabled" -ne 0 ]; then
2149 if is_nft; then
2150 output "$serviceName (nft) stopped "; output_okn;
2151 else
2152 output "$serviceName (iptables) stopped "; output_okn;
2153 fi
2154 fi
2155 }
2156
2157 status_service() {
2158 local _SEPARATOR_='============================================================'
2159 load_environment 'on_status'
2160 if is_nft; then
2161 status_service_nft "$@"
2162 else
2163 status_service_iptables "$@"
2164 fi
2165 }
2166
2167 status_service_nft() {
2168 local i dev dev6 wan_tid
2169
2170 json_load "$(ubus call system board)"; json_select release; json_get_var dist distribution; json_get_var vers version
2171 if [ -n "$wanIface4" ]; then
2172 network_get_gateway wanGW4 "$wanIface4"
2173 network_get_device dev "$wanIface4"
2174 fi
2175 if [ -n "$wanIface6" ]; then
2176 network_get_device dev6 "$wanIface6"
2177 wanGW6=$($ip_full -6 route show | grep -m1 " dev $dev6 " | awk '{print $1}')
2178 [ "$wanGW6" = "default" ] && wanGW6=$($ip_full -6 route show | grep -m1 " dev $dev6 " | awk '{print $3}')
2179 fi
2180 while [ "${1:0:1}" = "-" ]; do param="${1//-/}"; eval "set_$param=1"; shift; done
2181 [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support"
2182 status="$serviceName running on $dist $vers."
2183 [ -n "$wanIface4" ] && status="$status WAN (IPv4): ${wanIface4}/${dev}/${wanGW4:-0.0.0.0}."
2184 [ -n "$wanIface6" ] && status="$status WAN (IPv6): ${wanIface6}/${dev6}/${wanGW6:-::/0}."
2185
2186 echo "$_SEPARATOR_"
2187 echo "$packageName - environment"
2188 echo "$status"
2189 echo "$_SEPARATOR_"
2190 dnsmasq --version 2>/dev/null | sed '/^$/,$d'
2191 echo "$_SEPARATOR_"
2192 echo "$packageName chains - policies"
2193 for i in forward input output prerouting postrouting; do
2194 "$nft" list table inet "$nftTable" | sed -n "/chain ${nftPrefix}_${i} {/,/\t}/p"
2195 done
2196 echo "$_SEPARATOR_"
2197 echo "$packageName chains - marking"
2198 for i in $(get_mark_nft_chains); do
2199 "$nft" list table inet "$nftTable" | sed -n "/chain ${i} {/,/\t}/p"
2200 done
2201 echo "$_SEPARATOR_"
2202 echo "$packageName nft sets"
2203 for i in $(get_nft_sets); do
2204 "$nft" list table inet "$nftTable" | sed -n "/set ${i} {/,/\t}/p"
2205 done
2206 if [ -s "$dnsmasqFile" ]; then
2207 echo "$_SEPARATOR_"
2208 echo "dnsmasq sets"
2209 cat "$dnsmasqFile"
2210 fi
2211 # echo "$_SEPARATOR_"
2212 # ip rule list | grep "${packageName}_"
2213 echo "$_SEPARATOR_"
2214 tableCount="$(grep -c "${packageName}_" /etc/iproute2/rt_tables)" || tableCount=0
2215 wan_tid=$(($(get_rt_tables_next_id)-tableCount))
2216 i=0; while [ $i -lt $tableCount ]; do
2217 echo "IPv4 table $((wan_tid + i)) route: $($ip_full -4 route show table $((wan_tid + i)) | grep default)"
2218 echo "IPv4 table $((wan_tid + i)) rule(s):"
2219 $ip_full -4 rule list table "$((wan_tid + i))"
2220 i=$((i + 1))
2221 done
2222 }
2223
2224 status_service_iptables() {
2225 local dist vers out id s param status set_d set_p tableCount i=0 dev dev6 j wan_tid
2226
2227 json_load "$(ubus call system board)"; json_select release; json_get_var dist distribution; json_get_var vers version
2228 if [ -n "$wanIface4" ]; then
2229 network_get_gateway wanGW4 "$wanIface4"
2230 network_get_device dev "$wanIface4"
2231 fi
2232 if [ -n "$wanIface6" ]; then
2233 network_get_device dev6 "$wanIface6"
2234 wanGW6=$($ip_full -6 route show | grep -m1 " dev $dev6 " | awk '{print $1}')
2235 [ "$wanGW6" = "default" ] && wanGW6=$($ip_full -6 route show | grep -m1 " dev $dev6 " | awk '{print $3}')
2236 fi
2237 while [ "${1:0:1}" = "-" ]; do param="${1//-/}"; eval "set_$param=1"; shift; done
2238 [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support"
2239 status="$serviceName running on $dist $vers."
2240 [ -n "$wanIface4" ] && status="$status WAN (IPv4): ${wanIface4}/${dev}/${wanGW4:-0.0.0.0}."
2241 [ -n "$wanIface6" ] && status="$status WAN (IPv6): ${wanIface6}/${dev6}/${wanGW6:-::/0}."
2242 {
2243 echo "$status"
2244 echo "$_SEPARATOR_"
2245 dnsmasq --version 2>/dev/null | sed '/^$/,$d'
2246 if [ -n "$1" ]; then
2247 echo "$_SEPARATOR_"
2248 echo "Resolving domains"
2249 for i in $1; do
2250 echo "$i: $(resolveip "$i" | tr '\n' ' ')"
2251 done
2252 fi
2253
2254 echo "$_SEPARATOR_"
2255 echo "Routes/IP Rules"
2256 tableCount="$(grep -c "${packageName}_" /etc/iproute2/rt_tables)" || tableCount=0
2257 if [ -n "$set_d" ]; then route; else route | grep '^default'; fi
2258 if [ -n "$set_d" ]; then ip rule list; fi
2259 wan_tid=$(($(get_rt_tables_next_id)-tableCount))
2260 i=0; while [ $i -lt $tableCount ]; do
2261 echo "IPv4 table $((wan_tid + i)) route: $($ip_full -4 route show table $((wan_tid + i)) | grep default)"
2262 echo "IPv4 table $((wan_tid + i)) rule(s):"
2263 $ip_full -4 rule list table "$((wan_tid + i))"
2264 i=$((i + 1))
2265 done
2266
2267 if [ -n "$ipv6_enabled" ]; then
2268 i=0; while [ $i -lt $tableCount ]; do
2269 $ip_full -6 route show table $((wan_tid + i)) | while read -r param; do
2270 echo "IPv6 Table $((wan_tid + i)): $param"
2271 done
2272 i=$((i + 1))
2273 done
2274 fi
2275
2276 for j in Mangle NAT; do
2277 if [ -z "$set_d" ]; then
2278 for i in $chainsList; do
2279 i="$(str_to_upper "$i")"
2280 if iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}" >/dev/null 2>&1; then
2281 echo "$_SEPARATOR_"
2282 echo "$j IP Table: $i"
2283 iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}"
2284 if [ -n "$ipv6_enabled" ]; then
2285 echo "$_SEPARATOR_"
2286 echo "$j IPv6 Table: $i"
2287 iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}"
2288 fi
2289 fi
2290 done
2291 else
2292 echo "$_SEPARATOR_"
2293 echo "$j IP Table"
2294 iptables -L -t "$(str_to_lower $j)"
2295 if [ -n "$ipv6_enabled" ]; then
2296 echo "$_SEPARATOR_"
2297 echo "$j IPv6 Table"
2298 iptables -L -t "$(str_to_lower $j)"
2299 fi
2300 fi
2301 i=0; ifaceMark="$wan_mark";
2302 while [ $i -lt $tableCount ]; do
2303 if iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_MARK_${ifaceMark}" >/dev/null 2>&1; then
2304 echo "$_SEPARATOR_"
2305 echo "$j IP Table MARK Chain: ${iptPrefix}_MARK_${ifaceMark}"
2306 iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_MARK_${ifaceMark}"
2307 ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))";
2308 fi
2309 i=$((i + 1))
2310 done
2311 done
2312
2313 echo "$_SEPARATOR_"
2314 echo "Current ipsets"
2315 ipset save
2316 if [ -s "$dnsmasqFile" ]; then
2317 echo "$_SEPARATOR_"
2318 echo "DNSMASQ sets"
2319 cat "$dnsmasqFile"
2320 fi
2321 if [ -s "$aghIpsetFile" ]; then
2322 echo "$_SEPARATOR_"
2323 echo "AdGuardHome sets"
2324 cat "$aghIpsetFile"
2325 fi
2326 echo "$_SEPARATOR_"
2327 } | tee -a /var/${packageName}-support
2328 if [ -n "$set_p" ]; then
2329 printf "%b" "Pasting to paste.ee... "
2330 if is_present 'curl' && is_variant_installed 'libopenssl' && is_installed 'ca-bundle'; then
2331 json_init; json_add_string "description" "${packageName}-support"
2332 json_add_array "sections"; json_add_object '0'
2333 json_add_string "name" "$(uci -q get system.@system[0].hostname)"
2334 json_add_string "contents" "$(cat /var/${packageName}-support)"
2335 json_close_object; json_close_array; payload=$(json_dump)
2336 out=$(curl -s -k "https://api.paste.ee/v1/pastes" -X "POST" -H "Content-Type: application/json" -H "X-Auth-Token:uVOJt6pNqjcEWu7qiuUuuxWQafpHhwMvNEBviRV2B" -d "$payload")
2337 json_load "$out"; json_get_var id id; json_get_var s success
2338 [ "$s" = "1" ] && printf "%b" "https://paste.ee/p/$id $__OK__\\n" || printf "%b" "$__FAIL__\\n"
2339 [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support"
2340 else
2341 printf "%b" "${__FAIL__}\\n"
2342 printf "%b" "${_ERROR_}: The curl, libopenssl or ca-bundle packages were not found!\\nRun 'opkg update; opkg install curl libopenssl ca-bundle' to install them.\\n"
2343 fi
2344 else
2345 printf "%b" "Your support details have been logged to '/var/${packageName}-support'. $__OK__\\n"
2346 fi
2347 }
2348
2349 # shellcheck disable=SC2120
2350 load_validate_config() {
2351 uci_load_validate "$packageName" "$packageName" "$1" "${2}${3:+ $3}" \
2352 'enabled:bool:0' \
2353 'procd_boot_delay:integer:0' \
2354 'strict_enforcement:bool:1' \
2355 'secure_reload:bool:0' \
2356 'ipv6_enabled:bool:0' \
2357 'resolver_set:or("", "none", "dnsmasq.ipset", "dnsmasq.nftset")' \
2358 'verbosity:range(0,2):1' \
2359 "wan_mark:regex('0x[A-Fa-f0-9]{8}'):0x010000" \
2360 "fw_mask:regex('0x[A-Fa-f0-9]{8}'):0xff0000" \
2361 'icmp_interface:or("","ignore", uci("network", "@interface"))' \
2362 'ignored_interface:list(uci("network", "@interface"))' \
2363 'supported_interface:list(uci("network", "@interface"))' \
2364 'boot_timeout:integer:30' \
2365 'wan_ip_rules_priority:uinteger:30000' \
2366 'rule_create_option:or("", "add", "insert"):add' \
2367 'procd_reload_delay:integer:0' \
2368 'webui_supported_protocol:list(string)'
2369 }
2370
2371 # shellcheck disable=SC2120
2372 load_validate_policy() {
2373 local name
2374 local enabled
2375 local interface
2376 local proto
2377 local chain
2378 local src_addr
2379 local src_port
2380 local dest_addr
2381 local dest_port
2382 uci_load_validate "$packageName" 'policy' "$1" "${2}${3:+ $3}" \
2383 'name:string:Untitled' \
2384 'enabled:bool:1' \
2385 'interface:or(uci("network", "@interface"),"ignore"):wan' \
2386 'proto:or(string)' \
2387 'chain:or("", "forward", "input", "output", "prerouting", "postrouting", "FORWARD", "INPUT", "OUTPUT", "PREROUTING", "POSTROUTING"):prerouting' \
2388 'src_addr:list(neg(or(host,network,macaddr,string)))' \
2389 'src_port:list(neg(or(portrange,string)))' \
2390 'dest_addr:list(neg(or(host,network,string)))' \
2391 'dest_port:list(neg(or(portrange,string)))'
2392 }
2393
2394 # shellcheck disable=SC2120
2395 load_validate_include() {
2396 local path=
2397 local enabled=
2398 uci_load_validate "$packageName" 'include' "$1" "${2}${3:+ $3}" \
2399 'path:file' \
2400 'enabled:bool:0'
2401 }