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