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