Merge pull request #23908 from qosmio/ngtcp2-fix-release-number
[feed/packages.git] / net / pbr / files / etc / init.d / pbr
1 #!/bin/sh /etc/rc.common
2 # Copyright 2020-2023 MOSSDeF, Stan Grishin (stangri@melmac.ca)
3 # shellcheck disable=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 #!/bin/sh
14 # Copyright 2023 MOSSDeF, Stan Grishin (stangri@melmac.ca)
15 # shellcheck disable=SC2018,SC2019,SC2034,SC3043,SC3057,SC3060
16
17 readonly packageName='pbr'
18 readonly PKG_VERSION='dev-test'
19 readonly serviceName="$packageName $PKG_VERSION"
20 readonly serviceTrapSignals='exit SIGHUP SIGQUIT SIGKILL'
21 readonly packageConfigFile="/etc/config/${packageName}"
22 readonly packageLockFile="/var/run/${packageName}.lock"
23 readonly dnsmasqFileDefault="/var/dnsmasq.d/${packageName}"
24 readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m'
25 readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m'
26 readonly _OKB_='\033[1;34m\xe2\x9c\x93\033[0m'
27 readonly __OKB__='\033[1;34m[\xe2\x9c\x93]\033[0m'
28 readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m'
29 readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m'
30 readonly _ERROR_='\033[0;31mERROR\033[0m'
31 readonly _WARNING_='\033[0;33mWARNING\033[0m'
32 readonly ip_full='/usr/libexec/ip-full'
33 # shellcheck disable=SC2155
34 readonly ip_bin="$(command -v ip)"
35 readonly ipTablePrefix='pbr'
36 # shellcheck disable=SC2155
37 readonly iptables="$(command -v iptables)"
38 # shellcheck disable=SC2155
39 readonly ip6tables="$(command -v ip6tables)"
40 # shellcheck disable=SC2155
41 readonly ipset="$(command -v ipset)"
42 readonly ipsPrefix='pbr'
43 readonly iptPrefix='PBR'
44 # shellcheck disable=SC2155
45 readonly agh="$(command -v AdGuardHome)"
46 readonly aghConfigFile='/etc/adguardhome.yaml'
47 readonly aghIpsetFile="/var/run/${packageName}.adguardhome.ipsets"
48 # shellcheck disable=SC2155
49 readonly nft="$(command -v nft)"
50 readonly nftIPv4Flag='ip'
51 readonly nftIPv6Flag='ip6'
52 readonly nftTempFile="/var/run/${packageName}.nft"
53 readonly nftPermFile="/usr/share/nftables.d/ruleset-post/30-${packageName}.nft"
54 readonly nftPrefix='pbr'
55 readonly nftTable='fw4'
56 readonly chainsList='forward input output postrouting prerouting'
57 readonly ssConfigFile='/etc/shadowsocks'
58 readonly torConfigFile='/etc/tor/torrc'
59 readonly xrayIfacePrefix='xray_'
60 readonly rtTablesFile='/etc/iproute2/rt_tables'
61
62 # package config options
63 procd_boot_timeout=
64 enabled=
65 fw_mask=
66 icmp_interface=
67 ignored_interface=
68 ipv6_enabled=
69 nft_file_support=
70 nft_user_set_policy=
71 nft_user_set_counter=
72 procd_boot_delay=
73 procd_reload_delay=
74 procd_lan_interface=
75 procd_wan_ignore_status=
76 procd_wan_interface=
77 procd_wan6_interface=
78 resolver_set=
79 resolver_instance=
80 rule_create_option=
81 secure_reload=
82 strict_enforcement=
83 supported_interface=
84 verbosity=
85 wan_ip_rules_priority=
86 wan_mark=
87 nft_set_auto_merge=
88 nft_set_counter=
89 nft_set_flags_interval=
90 nft_set_flags_timeout=
91 nft_set_flags_gc_interval=
92 nft_set_policy=
93 nft_set_timeout=
94
95 # run-time
96 gatewaySummary=
97 errorSummary=
98 warningSummary=
99 wanIface4=
100 wanIface6=
101 dnsmasqFile=
102 dnsmasqFileList=
103 ifaceMark=
104 ifaceTableID=
105 ifacePriority=
106 ifacesAll=
107 ifacesSupported=
108 firewallWanZone=
109 wanGW4=
110 wanGW6=
111 serviceStartTrigger=
112 processPolicyError=
113 processPolicyWarning=
114 resolver_set_supported=
115 policy_routing_nft_prev_param4=
116 policy_routing_nft_prev_param6=
117 nft_set_params=
118 torDnsPort=
119 torTrafficPort=
120
121 # shellcheck disable=SC1091
122 . /lib/functions.sh
123 # shellcheck disable=SC1091
124 . /lib/functions/network.sh
125 # shellcheck disable=SC1091
126 . /usr/share/libubox/jshn.sh
127
128 output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; }
129 output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; }
130 output_okb() { output 1 "$_OKB_"; output 2 "$__OKB__\\n"; }
131 output_okbn() { output 1 "$_OKB_\\n"; output 2 "$__OKB__\\n"; }
132 output_fail() { output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; }
133 output_failn() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; }
134 # shellcheck disable=SC2317
135 str_replace() { printf "%b" "$1" | sed -e "s/$(printf "%b" "$2")/$(printf "%b" "$3")/g"; }
136 str_replace() { echo "${1//$2/$3}"; }
137 str_contains() { [ -n "$1" ] && [ -n "$2" ] && [ "${1//$2}" != "$1" ]; }
138 str_contains_word() { echo "$1" | grep -q -w "$2"; }
139 str_to_lower() { echo "$1" | tr 'A-Z' 'a-z'; }
140 str_to_upper() { echo "$1" | tr 'a-z' 'A-Z'; }
141 str_extras_to_underscore() { echo "$1" | tr '[\. ~`!@#$%^&*()\+/,<>?//;:]' '_'; }
142 str_extras_to_space() { echo "$1" | tr ';{}' ' '; }
143 debug() { local i j; for i in "$@"; do eval "j=\$$i"; echo "${i}: ${j} "; done; }
144 quiet_mode() {
145 case "$1" in
146 on) verbosity=0;;
147 off) verbosity="$(uci_get "$packageName" 'config' 'verbosity' '2')";;
148 esac
149 }
150 output() {
151 # Target verbosity level with the first parameter being an integer
152 is_integer() {
153 case "$1" in
154 (*[!0123456789]*) return 1;;
155 ('') return 1;;
156 (*) return 0;;
157 esac
158 }
159 local msg memmsg logmsg text
160 local sharedMemoryOutput="/dev/shm/$packageName-output"
161 if [ -z "$verbosity" ] && [ -n "$packageName" ]; then
162 verbosity="$(uci_get "$packageName" 'config' 'verbosity' '2')"
163 fi
164 if [ $# -ne 1 ] && is_integer "$1"; then
165 if [ $((verbosity & $1)) -gt 0 ] || [ "$verbosity" = "$1" ]; then shift; text="$*"; else return 0; fi
166 fi
167 text="${text:-$*}";
168 [ -t 1 ] && printf "%b" "$text"
169 msg="${text//$serviceName /service }";
170 if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then
171 [ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")"
172 logmsg="$(printf "%b" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')"
173 logger -t "${packageName:-service} [$$]" "$(printf "%b" "$logmsg")"
174 rm -f "$sharedMemoryOutput"
175 else
176 printf "%b" "$msg" >> "$sharedMemoryOutput"
177 fi
178 }
179 pbr_find_iface() {
180 local iface i param="$2"
181 case "$param" in
182 wan6) iface="$procd_wan6_interface";;
183 wan|*) iface="$procd_wan_interface";;
184 esac
185 eval "$1"='${iface}'
186 }
187 pbr_get_gateway4() {
188 local iface="$2" dev="$3" gw
189 network_get_gateway gw "$iface" true
190 if [ -z "$gw" ] || [ "$gw" = '0.0.0.0' ]; then
191 # gw="$(ubus call "network.interface.${iface}" status | jsonfilter -e "@.route[0].nexthop")"
192 gw="$($ip_bin -4 a list dev "$dev" 2>/dev/null | grep inet | awk '{print $2}' | awk -F "/" '{print $1}')"
193 fi
194 eval "$1"='$gw'
195 }
196 pbr_get_gateway6() {
197 local iface="$2" dev="$3" gw
198 network_get_gateway6 gw "$iface" true
199 if [ -z "$gw" ] || [ "$gw" = '::/0' ] || [ "$gw" = '::0/0' ] || [ "$gw" = '::' ]; then
200 gw="$($ip_bin -6 a list dev "$dev" 2>/dev/null | grep inet6 | grep 'scope global' | awk '{print $2}')"
201 fi
202 eval "$1"='$gw'
203 }
204
205 # shellcheck disable=SC2016
206 is_bad_user_file_nft_call() { grep -q '"\$nft" list' "$1" || grep '"\$nft" -f' "$1";}
207 is_config_enabled() {
208 _check_config() { local en; config_get_bool en "$1" 'enabled' 1; [ "$en" -gt 0 ] && _cfg_enabled=0; }
209 local cfg="$1" _cfg_enabled=1
210 [ -n "$1" ] || return 1
211 config_load "$packageName"
212 config_foreach _check_config "$cfg"
213 return "$_cfg_enabled"
214 }
215 uci_get_device() { uci_get 'network' "$1" 'device' || uci_get 'network' "$1" 'dev'; }
216 uci_get_protocol() { uci_get 'network' "$1" 'proto'; }
217 is_default_dev() { [ "$1" = "$($ip_bin -4 r | grep -m1 'dev' | grep -Eso 'dev [^ ]*' | awk '{print $2}')" ]; }
218 is_domain() { ! is_ipv6 "$1" && str_contains "$1" '[a-zA-Z]'; }
219 is_dslite() { local p; network_get_protocol p "$1"; [ "${p:0:6}" = "dslite" ]; }
220 is_family_mismatch() { ( is_ipv4_netmask "${1//!}" && is_ipv6 "${2//!}" ) || ( is_ipv6 "${1//!}" && is_ipv4_netmask "${2//!}" ); }
221 is_greater() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
222 is_greater_or_equal() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" = "$2"; }
223 is_ignored_interface() { str_contains_word "$ignored_interface" "$1"; }
224 is_ignore_target() { [ "$(str_to_lower "$1")" = 'ignore' ]; }
225 is_integer() {
226 case "$1" in
227 (*[!0123456789]*) return 1;;
228 ('') return 1;;
229 (*) return 0;;
230 esac
231 }
232 is_ipset_type_supported() { ipset help hash:"$1" >/dev/null 2>&1; }
233 is_nft_mode() { [ -x "$nft" ] && ! str_contains "$resolver_set" 'ipset' && "$nft" list chains inet | grep -q "${nftPrefix}_prerouting"; }
234 is_ipv4() { expr "$1" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null; }
235 is_ipv6() { ! is_mac_address "$1" && str_contains "$1" ':'; }
236 is_ipv6_global() { [ "${1:0:4}" = '2001' ]; }
237 is_ipv6_link_local() { [ "${1:0:4}" = 'fe80' ]; }
238 is_ipv6_unique_local() { [ "${1:0:2}" = 'fc' ] || [ "${1:0:2}" = 'fd' ]; }
239 is_list() { str_contains "$1" ',' || str_contains "$1" ' '; }
240 is_ipv4_netmask() { local ip="${1%/*}"; [ "$ip" != "$1" ] && is_ipv4 "$ip"; }
241 is_lan() { local d; network_get_device d "$1"; str_contains "$d" 'br-lan'; }
242 is_l2tp() { local p; network_get_protocol p "$1"; [ "${p:0:4}" = "l2tp" ]; }
243 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; }
244 is_netifd_table() { grep -q "ip.table.*$1" /etc/config/network; }
245 is_netifd_table_interface() { local iface="$1"; [ "$(uci_get 'network' "$iface" 'ip4table')" = "${packageName}_${iface%6}" ]; }
246 is_oc() { local p; network_get_protocol p "$1"; [ "${p:0:11}" = "openconnect" ]; }
247 is_ovpn() { local d; uci_get_device d "$1"; [ "${d:0:3}" = "tun" ] || [ "${d:0:3}" = "tap" ] || [ -f "/sys/devices/virtual/net/${d}/tun_flags" ]; }
248 is_ovpn_valid() { local dev_net dev_ovpn; uci_get_device dev_net "$1"; dev_ovpn="$(uci_get 'openvpn' "$1" 'dev')"; [ -n "$dev_net" ] && [ -n "$dev_ovpn" ] && [ "$dev_net" = "$dev_ovpn" ]; }
249 is_phys_dev() { [ "${1:0:1}" = "@" ] && ip l show | grep -E -q "^\\d+\\W+${1:1}"; }
250 is_present() { command -v "$1" >/dev/null 2>&1; }
251 is_service_running() { if is_nft_mode; then is_service_running_nft; else is_service_running_iptables; fi; }
252 is_service_running_iptables() { [ -x "$iptables" ] && "$iptables" -t mangle -L | grep -q "${iptPrefix}_PREROUTING" >/dev/null 2>&1; }
253 is_service_running_nft() { [ -x "$nft" ] && [ -n "$(get_mark_nft_chains)" ]; }
254 is_supported_iface_dev() { local n dev; for n in $ifacesSupported; do network_get_device dev "$n"; [ "$1" = "$dev" ] && return 0; done; return 1; }
255 is_supported_protocol() { grep -o '^[^#]*' /etc/protocols | grep -w -v '0' | grep . | awk '{print $1}' | grep -q "$1"; }
256 is_pptp() { local p; network_get_protocol p "$1"; [ "${p:0:4}" = "pptp" ]; }
257 is_softether() { local d; network_get_device d "$1"; [ "${d:0:4}" = "vpn_" ]; }
258 is_supported_interface() { is_lan "$1" && return 1; str_contains_word "$supported_interface" "$1" || { ! is_ignored_interface "$1" && { is_wan "$1" || is_wan6 "$1" || is_tunnel "$1"; }; } || is_ignore_target "$1" || is_xray "$1"; }
259 is_tailscale() { local d; network_get_device d "$1"; [ "${d:0:9}" = "tailscale" ]; }
260 is_tor() { [ "$(str_to_lower "$1")" = "tor" ]; }
261 is_tor_running() {
262 local ret=0
263 is_ignored_interface 'tor' && return 1
264 [ -s "$torConfigFile" ] || return 1
265 json_load "$(ubus call service list "{ 'name': 'tor' }")" >/dev/null || return 1
266 json_select 'tor' >/dev/null || return 1
267 json_select 'instances' >/dev/null || return 1
268 json_select 'instance1' >/dev/null || return 1
269 json_get_var ret 'running' >/dev/null || return 1
270 json_cleanup
271 if [ "$ret" = "0" ]; then return 1; else return 0; fi
272 }
273 is_tunnel() { is_dslite "$1" || is_l2tp "$1" || is_oc "$1" || is_ovpn "$1" || is_pptp "$1" || is_softether "$1" || is_tailscale "$1" || is_tor "$1" || is_wg "$1"; }
274 is_url() { is_url_file "$1" || is_url_dl "$1"; }
275 is_url_dl() { is_url_ftp "$1" || is_url_http "$1" || is_url_https "$1"; }
276 is_url_file() { [ "$1" != "${1#file://}" ];}
277 is_url_ftp() { [ "$1" != "${1#ftp://}" ];}
278 is_url_http() { [ "$1" != "${1#http://}" ];}
279 is_url_https() { [ "$1" != "${1#https://}" ];}
280 is_wan() { [ "$1" = "$wanIface4" ] || { [ "${1##wan}" != "$1" ] && [ "${1##wan6}" = "$1" ]; } || [ "${1%%wan}" != "$1" ]; }
281 is_wan6() { [ -n "$wanIface6" ] && [ "$1" = "$wanIface6" ] || [ "${1/#wan6}" != "$1" ] || [ "${1/%wan6}" != "$1" ]; }
282 is_wg() { local p lp; network_get_protocol p "$1"; uci_get_listen_port lp "$1"; [ -z "$lp" ] && [ "${p:0:9}" = "wireguard" ]; }
283 is_xray() { [ -n "$(get_xray_traffic_port "$1")" ]; }
284 dnsmasq_kill() { killall -q -s HUP dnsmasq; }
285 dnsmasq_restart() { output 3 'Restarting dnsmasq '; if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then output_okn; else output_failn; fi; }
286 # shellcheck disable=SC2155
287 get_ss_traffic_ports() { local i="$(jsonfilter -i "$ssConfigFile" -q -e "@.inbounds[*].port")"; echo "${i:-443}"; }
288 # shellcheck disable=SC2155
289 get_tor_dns_port() { local i="$(grep -m1 DNSPort "$torConfigFile" | awk -F: '{print $2}')"; echo "${i:-9053}"; }
290 # shellcheck disable=SC2155
291 get_tor_traffic_port() { local i="$(grep -m1 TransPort "$torConfigFile" | awk -F: '{print $2}')"; echo "${i:-9040}"; }
292 get_xray_traffic_port() { local i="${1//$xrayIfacePrefix}"; [ "$i" = "$1" ] && unset i; echo "$i"; }
293 get_rt_tables_id() { local iface="$1"; grep "${ipTablePrefix}_${iface}\$" "$rtTablesFile" | awk '{print $1;}'; }
294 get_rt_tables_next_id() { echo "$(($(sort -r -n "$rtTablesFile" | grep -o -E -m 1 "^[0-9]+")+1))"; }
295 get_rt_tables_non_pbr_next_id() { echo "$(($(grep -v "${ipTablePrefix}_" "$rtTablesFile" | sort -r -n | grep -o -E -m 1 "^[0-9]+")+1))"; }
296 # shellcheck disable=SC2016
297 resolveip_to_ipt() { resolveip "$@" | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d'; }
298 resolveip_to_ipt4() { resolveip_to_ipt -4 "$@"; }
299 resolveip_to_ipt6() { [ -n "$ipv6_enabled" ] && resolveip_to_ipt -6 "$@"; }
300 # shellcheck disable=SC2016
301 resolveip_to_nftset() { resolveip "$@" | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d' | tr '\n' ' '; }
302 resolveip_to_nftset4() { resolveip_to_nftset -4 "$@"; }
303 resolveip_to_nftset6() { [ -n "$ipv6_enabled" ] && resolveip_to_nftset -6 "$@"; }
304 # shellcheck disable=SC2016
305 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' ' '; }
306 # shellcheck disable=SC2016
307 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' ' '; }
308 # shellcheck disable=SC3037
309 ports_to_nftset() { echo -ne "$1"; }
310 get_mark_ipt_chains() { [ -n "$(command -v iptables-save)" ] && iptables-save | grep ":${iptPrefix}_MARK_" | awk '{ print $1 }' | sed 's/://'; }
311 get_mark_nft_chains() { [ -x "$nft" ] && "$nft" list table inet "$nftTable" 2>/dev/null | grep chain | grep "${nftPrefix}_mark_" | awk '{ print $2 }'; }
312 get_ipsets() { [ -x "$(command -v ipset)" ] && ipset list | grep "${ipsPrefix}_" | awk '{ print $2 }'; }
313 get_nft_sets() { [ -x "$nft" ] && "$nft" list table inet "$nftTable" 2>/dev/null | grep 'set' | grep "${nftPrefix}_" | awk '{ print $2 }'; }
314 __ubus_get() { ubus call service list "{ 'name': '$packageName' }" | jsonfilter -e "$1"; }
315 ubus_get_status() { __ubus_get "@.${packageName}.instances.main.data.status.${1}"; }
316 ubus_get_interface() { __ubus_get "@.${packageName}.instances.main.data.gateways[@.name='${1}']${2:+.$2}"; }
317 ubus_get_gateways() { __ubus_get "@.${packageName}.instances.main.data.gateways"; }
318 uci_get_device() {
319 local __tmp
320 __tmp="$(uci_get 'network' "$2" 'device')"
321 [ -z "$__tmp" ] && unset "$1" && return 1
322 eval "$1=$__tmp"
323 }
324 uci_get_listen_port() {
325 local __tmp
326 __tmp="$(uci_get 'network' "$2" 'listen_port')"
327 [ -z "$__tmp" ] && unset "$1" && return 1
328 eval "$1=$__tmp"
329 }
330
331 # luci app specific
332 is_enabled() { uci_get "$1" 'config' 'enabled'; }
333 is_running_iptables() { iptables -t mangle -L | grep -q PBR_PREROUTING >/dev/null 2>&1; }
334 is_running_nft_file() { [ -s "$nftPermFile" ]; }
335 is_running_nft() { "$nft" list table inet fw4 | grep chain | grep -q pbr_mark_ >/dev/null 2>&1; }
336 is_running() { is_running_iptables || is_running_nft; }
337 check_ipset() { { [ -n "$ipset" ] && "$ipset" help hash:net; } >/dev/null 2>&1; }
338 check_nft() { [ -n "$nft" ]; }
339 check_agh() { [ -n "$agh" ] && [ -s "$aghConfigFile" ]; }
340 check_dnsmasq() { command -v dnsmasq >/dev/null 2>&1; }
341 check_unbound() { command -v unbound >/dev/null 2>&1; }
342 check_agh_ipset() {
343 check_ipset || return 1
344 check_agh || return 1
345 is_greater_or_equal "$($agh --version | sed 's|AdGuard Home, version v\(.*\)|\1|' | sed 's|-.*||')" '0.107.13'
346 }
347 check_dnsmasq_ipset() {
348 local o;
349 check_ipset || return 1
350 check_dnsmasq || return 1
351 o="$(dnsmasq -v 2>/dev/null)"
352 ! echo "$o" | grep -q 'no-ipset' && echo "$o" | grep -q 'ipset'
353 }
354 check_dnsmasq_nftset() {
355 local o;
356 check_nft || return 1
357 check_dnsmasq || return 1
358 o="$(dnsmasq -v 2>/dev/null)"
359 ! echo "$o" | grep -q 'no-nftset' && echo "$o" | grep -q 'nftset'
360 }
361 print_json_bool() { json_init; json_add_boolean "$1" "$2"; json_dump; json_cleanup; }
362 print_json_string() { json_init; json_add_string "$1" "$2"; json_dump; json_cleanup; }
363
364 if type extra_command >/dev/null 2>&1; then
365 extra_command 'status' "Generates output required to troubleshoot routing issues
366 Use '-d' option for more detailed output
367 Use '-p' option to automatically upload data under VPR paste.ee account
368 WARNING: while paste.ee uploads are unlisted, they are still publicly available
369 List domain names after options to include their lookup in report"
370 extra_command 'version' 'Show version information'
371 extra_command 'on_firewall_reload' ' Run service on firewall reload'
372 extra_command 'on_interface_reload' ' Run service on indicated interface reload'
373 else
374 # shellcheck disable=SC2034
375 EXTRA_COMMANDS='on_firewall_reload on_interface_reload status version'
376 # shellcheck disable=SC2034
377 EXTRA_HELP=" status Generates output required to troubleshoot routing issues
378 Use '-d' option for more detailed output
379 Use '-p' option to automatically upload data under VPR paste.ee account
380 WARNING: while paste.ee uploads are unlisted, they are still publicly available
381 List domain names after options to include their lookup in report"
382 fi
383
384 get_text() {
385 local r
386 case "$1" in
387 errorConfigValidation) r="Config ($packageConfigFile) validation failure!";;
388 errorNoIpFull) r="ip-full binary cannot be found!";;
389 errorNoIptables) r="iptables binary cannot be found!";;
390 errorNoIpset) r="Resolver set support (${resolver_set}) requires ipset, but ipset binary cannot be found!";;
391 errorNoNft) r="Resolver set support (${resolver_set}) requires nftables, but nft binary cannot be found!";;
392 errorResolverNotSupported) r="Resolver set (${resolver_set}) is not supported on this system!";;
393 errorServiceDisabled) r="The ${packageName} service is currently disabled!";;
394 errorNoWanGateway) r="The ${serviceName} service failed to discover WAN gateway!";;
395 errorNoWanInterface) r="The %s inteface not found, you need to set the 'pbr.config.procd_wan_interface' option!";;
396 errorNoWanInterfaceHint) r="Refer to https://docs.openwrt.melmac.net/pbr/#procd_wan_interface.";;
397 errorIpsetNameTooLong) r="The ipset name '%s' is longer than allowed 31 characters!";;
398 errorNftsetNameTooLong) r="The nft set name '%s' is longer than allowed 255 characters!";;
399 errorUnexpectedExit) r="Unexpected exit or service termination: '%s'!";;
400 errorPolicyNoSrcDest) r="Policy '%s' has no source/destination parameters!";;
401 errorPolicyNoInterface) r="Policy '%s' has no assigned interface!";;
402 errorPolicyUnknownInterface) r="Policy '%s' has an unknown interface!";;
403 errorPolicyProcessCMD) r="'%s'!";;
404 errorFailedSetup) r="Failed to set up '%s'!";;
405 errorFailedReload) r="Failed to reload '%s'!";;
406 errorUserFileNotFound) r="Custom user file '%s' not found or empty!";;
407 errorUserFileSyntax) r="Syntax error in custom user file '%s'!";;
408 errorUserFileRunning) r="Error running custom user file '%s'!";;
409 errorUserFileNoCurl) r="Use of 'curl' is detected in custom user file '%s', but 'curl' isn't installed!";;
410 errorNoGateways) r="Failed to set up any gateway!";;
411 errorResolver) r="Resolver '%s'!";;
412 errorPolicyProcessNoIpv6) r="Skipping IPv6 policy '%s' as IPv6 support is disabled!";;
413 errorPolicyProcessUnknownFwmark) r="Unknown packet mark for interface '%s'!";;
414 errorPolicyProcessMismatchFamily) r="Mismatched IP family between in policy '%s'!";;
415 errorPolicyProcessUnknownProtocol) r="Unknown protocol in policy '%s'!";;
416 errorPolicyProcessInsertionFailed) r="Insertion failed for both IPv4 and IPv6 for policy '%s'!";;
417 errorPolicyProcessInsertionFailedIpv4) r="Insertion failed for IPv4 for policy '%s'!";;
418 errorInterfaceRoutingEmptyValues) r="Received empty tid/mark or interface name when setting up routing!";;
419 errorFailedToResolve) r="Failed to resolve '%s'!";;
420 errorTryFailed) r="Command failed: %s";;
421 errorNftFileInstall) r="Failed to install fw4 nft file '%s'!";;
422 errorDownloadUrlNoHttps) r="Failed to download '%s', HTTPS is not supported!";;
423 errorDownloadUrl) r="Failed to download '%s'!";;
424 errorNoDownloadWithSecureReload) r="Policy '%s' refers to URL which can't be downloaded in 'secure_reload' mode!";;
425 errorFileSchemaRequiresCurl) r="The file:// schema requires curl, but it's not detected on this system!";;
426 warningInvalidOVPNConfig) r="Invalid OpenVPN config for '%s' interface.";;
427 warningResolverNotSupported) r="Resolver set (${resolver_set}) is not supported on this system.";;
428 warningAGHVersionTooLow) r="Installed AdGuardHome ('%s') doesn't support 'ipset_file' option.";;
429 warningPolicyProcessCMD) r="'%s'";;
430 warningTorUnsetParams) r="Please unset 'src_addr', 'src_port' and 'dest_port' for policy '%s'.";;
431 warningTorUnsetProto) r="Please unset 'proto' or set 'proto' to 'all' for policy '%s'.";;
432 warningTorUnsetChainIpt) r="Please unset 'chain' or set 'chain' to 'PREROUTING' for policy '%s'.";;
433 warningTorUnsetChainNft) r="Please unset 'chain' or set 'chain' to 'prerouting' for policy '%s'.";;
434 warningOutdatedWebUIApp) r="The WebUI application is outdated (version %s), please update it.";;
435 warningBadNftCallsInUserFile) r="Incompatible nft calls detected in user include file, disabling fw4 nft file support.";;
436 warningDnsmasqInstanceNoConfdir) r="Dnsmasq instance (%s) targeted in settings, but it doesn't have its own confdir.";;
437 esac
438 echo "$r"
439 }
440
441 process_url() {
442 local url="$1"
443 local dl_command dl_https_supported dl_temp_file
444 # TODO: check for FILE schema and missing curl
445 if is_present 'curl'; then
446 dl_command="curl --silent --insecure"
447 dl_flag="-o"
448 elif is_present '/usr/libexec/wget-ssl'; then
449 dl_command="/usr/libexec/wget-ssl --no-check-certificate -q"
450 dl_flag="-O"
451 elif is_present wget && wget --version 2>/dev/null | grep -q "+https"; then
452 dl_command="wget --no-check-certificate -q"
453 dl_flag="-O"
454 else
455 dl_command="uclient-fetch --no-check-certificate -q"
456 dl_flag="-O"
457 fi
458 if curl --version 2>/dev/null | grep -q "Protocols: .*https.*" \
459 || wget --version 2>/dev/null | grep -q "+ssl"; then
460 dl_https_supported=1
461 else
462 unset dl_https_supported
463 fi
464 while [ -z "$dl_temp_file" ] || [ -e "$dl_temp_file" ]; do
465 dl_temp_file="$(mktemp -u -q -t ${packageName}_tmp.XXXXXXXX)"
466 done
467 if is_url_file "$url" && ! is_present 'curl'; then
468 state add 'errorSummary' 'errorFileSchemaRequiresCurl' "$url"
469 elif is_url_https "$url" && [ -z "$dl_https_supported" ]; then
470 state add 'errorSummary' 'errorDownloadUrlNoHttps' "$url"
471 elif $dl_command "$url" "$dl_flag" "$dl_temp_file" 2>/dev/null; then
472 sed 'N;s/\n/ /;s/\s\+/ /g;' "$dl_temp_file"
473 else
474 state add 'errorSummary' 'errorDownloadUrl' "$url"
475 fi
476 rm -f "$dl_temp_file"
477 }
478
479 load_package_config() {
480 _check_user_files_for_bad_nft_calls() {
481 local cfg="$1"
482 local en path
483 config_get_bool en "$cfg" 'enabled' 1
484 config_get path "$cfg" 'path'
485 [ "$en" -eq 0 ] && return 0
486 [ -z "$path" ] && return 0
487 [ -s "$path" ] || return 0
488 is_bad_user_file_nft_call "$path" && user_file_check_result='bad'
489 }
490 local param="$1"
491 local user_file_check_result i
492 config_load "$packageName"
493 config_get_bool enabled 'config' 'enabled' '0'
494 config_get fw_mask 'config' 'fw_mask' 'ff0000'
495 config_get icmp_interface 'config' 'icmp_interface'
496 config_get ignored_interface 'config' 'ignored_interface'
497 config_get_bool ipv6_enabled 'config' 'ipv6_enabled' '0'
498 config_get_bool nft_file_support 'config' 'nft_file_support' '1'
499 config_get_bool nft_set_auto_merge 'config' 'nft_set_auto_merge' '1'
500 config_get_bool nft_set_counter 'config' 'nft_set_counter' '1'
501 config_get_bool nft_set_flags_interval 'config' 'nft_set_flags_interval' '1'
502 config_get_bool nft_set_flags_timeout 'config' 'nft_set_flags_timeout' '0'
503 config_get nft_set_gc_interval 'config' 'nft_set_gc_interval'
504 config_get nft_set_policy 'config' 'nft_set_policy' 'performance'
505 config_get nft_set_timeout 'config' 'nft_set_timeout'
506 config_get resolver_set 'config' 'resolver_set'
507 config_get resolver_instance 'config' 'resolver_instance' '*'
508 config_get rule_create_option 'config' 'rule_create_option' 'add'
509 config_get_bool secure_reload 'config' 'secure_reload' '0'
510 config_get_bool strict_enforcement 'config' 'strict_enforcement' '1'
511 config_get supported_interface 'config' 'supported_interface'
512 config_get verbosity 'config' 'verbosity' '2'
513 config_get procd_boot_delay 'config' 'procd_boot_delay' '0'
514 config_get procd_boot_timeout 'config' 'procd_boot_timeout' '30'
515 config_get procd_lan_interface 'config' 'procd_lan_interface'
516 config_get procd_wan_ignore_status 'config' 'procd_wan_ignore_status' '0'
517 config_get procd_wan_interface 'config' 'procd_wan_interface' 'wan'
518 config_get procd_wan6_interface 'config' 'procd_wan6_interface' 'wan6'
519 config_get wan_ip_rules_priority 'config' 'wan_ip_rules_priority' '30000'
520 config_get wan_mark 'config' 'wan_mark' '010000'
521 fw_mask="0x${fw_mask}"
522 wan_mark="0x${wan_mark}"
523 [ -n "$ipv6_enabled" ] && [ "$ipv6_enabled" -eq 0 ] && unset ipv6_enabled
524 [ -n "$nft_file_support" ] && [ "$nft_file_support" -eq 0 ] && unset nft_file_support
525 [ -n "$nft_user_set_counter" ] && [ "$nft_user_set_counter" -eq 0 ] && unset nft_user_set_counter
526 [ -n "$secure_reload" ] && [ "$secure_reload" -eq 0 ] && unset secure_reload
527 config_foreach _check_user_files_for_bad_nft_calls 'include'
528 [ -n "$user_file_check_result" ] && unset nft_file_support
529 [ -n "$nft_file_support" ] && unset secure_reload
530 is_config_enabled 'include' && unset secure_reload
531 if is_nft_mode; then
532 fw_maskXor="$(printf '%#x' "$((fw_mask ^ 0xffffffff))")"
533 fw_maskXor="${fw_maskXor:-0xff00ffff}"
534 else
535 case $rule_create_option in
536 insert|-i|-I) rule_create_option='-I';;
537 add|-a|-A|*) rule_create_option='-A';;
538 esac
539 fi
540
541 [ "$nft_set_auto_merge" != '1' ] && unset nft_set_auto_merge
542 [ "$nft_set_counter" != '1' ] && unset nft_set_counter
543 [ "$nft_set_flags_interval" != '1' ] && unset nft_set_flags_interval
544 [ "$nft_set_flags_timeout" != '1' ] && unset nft_set_flags_timeout
545 [ -z "${nft_set_flags_timeout}${nft_set_timeout}" ] && unset nft_set_gc_interval
546 local nft_set_flags
547 if [ -n "${nft_set_flags_interval}${nft_set_flags_timeout}" ]; then
548 [ -n "$nft_set_flags_interval" ] && nft_set_flags='flags interval'
549 if [ -n "$nft_set_flags_timeout" ]; then
550 if [ -n "$nft_set_flags" ]; then
551 nft_set_flags="${nft_set_flags}, timeout"
552 else
553 nft_set_flags='flags timeout'
554 fi
555 fi
556 fi
557 nft_set_params=" \
558 ${nft_set_auto_merge:+ auto-merge;} \
559 ${nft_set_counter:+ counter;} \
560 ${nft_set_flags:+ $nft_set_flags;} \
561 ${nft_set_gc_interval:+ gc_interval "$nft_set_gc_interval";} \
562 ${nft_set_policy:+ policy "$nft_set_policy";} \
563 ${nft_set_timeout:+ timeout "$nft_set_timeout";} \
564 "
565
566 resolver 'check_support' && resolver 'configure_instances'
567 }
568
569 load_environment() {
570 local param="$1" validation_result="$2"
571 load_package_config "$param"
572 case "$param" in
573 on_start)
574 if [ "$enabled" -eq 0 ]; then
575 state add 'errorSummary' 'errorServiceDisabled'
576 return 1
577 fi
578 if [ -n "$validation_result" ] && [ "$validation_result" != '0' ]; then
579 output "${_ERROR_}: The $packageName config validation failed!\\n"
580 output "Please check if the '$packageConfigFile' contains correct values for config options.\\n"
581 state add 'errorSummary' 'errorConfigValidation'
582 return 1
583 fi
584 if [ ! -x "$ip_bin" ]; then
585 state add 'errorSummary' 'errorNoIpFull'
586 return 1
587 fi
588 if is_nft_mode; then
589 if [ "$(uci_get 'firewall' 'defaults' 'auto_includes')" = '0' ]; then
590 uci_remove 'firewall' 'defaults' 'auto_includes'
591 uci_commit firewall
592 fi
593 else
594 if [ -z "$iptables" ] || [ ! -x "$iptables" ]; then
595 state add 'errorSummary' 'errorNoIptables'
596 return 1
597 fi
598 fi
599 ;;
600 on_stop)
601 :
602 ;;
603 esac
604 load_network "$param"
605 }
606
607 load_network() {
608 _build_ifaces_supported() { is_supported_interface "$1" && ! str_contains "$ifacesSupported" "$1" && ifacesSupported="${ifacesSupported}${1} "; }
609 _find_firewall_wan_zone() { [ "$(uci_get 'firewall' "$1" 'name')" = "wan" ] && firewallWanZone="$1"; }
610 local i param="$1"
611 local dev4 dev6
612 if [ -z "$ifacesSupported" ]; then
613 config_load 'firewall'
614 config_foreach _find_firewall_wan_zone 'zone'
615 for i in $(uci_get 'firewall' "$firewallWanZone" 'network'); do
616 is_supported_interface "$i" && ! str_contains "$ifacesSupported" "$1" && ifacesSupported="${ifacesSupported}${i} "
617 done
618 config_load 'network'
619 config_foreach _build_ifaces_supported 'interface'
620 fi
621 wanIface4="$procd_wan_interface"
622 network_get_device dev4 "$wanIface4"
623 [ -z "$dev4" ] && network_get_physdev dev4 "$wanIface4"
624 [ -z "$wanGW4" ] && pbr_get_gateway4 wanGW4 "$wanIface4" "$dev4"
625 if [ -n "$ipv6_enabled" ]; then
626 wanIface6="$procd_wan6_interface"
627 network_get_device dev6 "$wanIface6"
628 [ -z "$dev6" ] && network_get_physdev dev6 "$wanIface6"
629 [ -z "$wanGW6" ] && pbr_get_gateway6 wanGW6 "$wanIface6" "$dev6"
630 fi
631
632 case "$param" in
633 on_boot|on_start)
634 [ -n "$wanIface4" ] && output 2 "Using wan interface (${param}): $wanIface4 \\n"
635 [ -n "$wanGW4" ] && output 2 "Found wan gateway (${param}): $wanGW4 \\n"
636 [ -n "$wanIface6" ] && output 2 "Using wan6 interface (${param}): $wanIface6 \\n"
637 [ -n "$wanGW6" ] && output 2 "Found wan6 gateway (${param}): $wanGW6 \\n"
638 ;;
639 esac
640 wanGW="${wanGW4:-$wanGW6}"
641 }
642
643 is_wan_up() {
644 local sleepCount='1' param="$1"
645 load_network "$param"
646 [ "$procd_wan_ignore_status" -eq '0' ] || return 0
647 [ "$param" = 'on_boot' ] || procd_boot_timeout='1'
648 if [ -z "$(uci_get network "$procd_wan_interface")" ]; then
649 state add 'errorSummary' 'errorNoWanInterface' "$procd_wan_interface"
650 state add 'errorSummary' 'errorNoWanInterfaceHint'
651 return 1
652 fi
653 while [ -z "$wanGW" ] ; do
654 load_network "$param"
655 if [ $((sleepCount)) -gt $((procd_boot_timeout)) ] || [ -n "$wanGW" ]; then break; fi
656 output "$serviceName waiting for $procd_wan_interface gateway...\\n"
657 sleep 1
658 network_flush_cache
659 sleepCount=$((sleepCount+1))
660 done
661 if [ -n "$wanGW" ]; then
662 return 0
663 else
664 state add 'errorSummary' 'errorNoWanGateway'
665 return 1
666 fi
667 }
668
669 # shellcheck disable=SC2086
670 ipt4() {
671 local d
672 [ -x "$iptables" ] || return 1
673 for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do
674 [ "$d" != "$*" ] && "$iptables" $d >/dev/null 2>&1
675 done
676 d="$*"; "$iptables" $d >/dev/null 2>&1
677 }
678
679 # shellcheck disable=SC2086
680 ipt6() {
681 local d
682 [ -n "$ipv6_enabled" ] || return 0
683 [ -x "$ip6tables" ] || return 1
684 for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do
685 [ "$d" != "$*" ] && "$ip6tables" $d >/dev/null 2>&1
686 done
687 d="$*"
688 "$ip6tables" $d >/dev/null 2>&1
689 }
690
691 # shellcheck disable=SC2086
692 ipt() {
693 local d failFlagIpv4=1 failFlagIpv6=1
694 [ -x "$iptables" ] || return 1
695 for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do
696 if [ "$d" != "$*" ]; then
697 "$iptables" $d >/dev/null 2>&1
698 if [ -x "$ip6tables" ]; then
699 "$ip6tables" $d >/dev/null 2>&1
700 fi
701 fi
702 done
703 d="$*"; "$iptables" $d >/dev/null 2>&1 && failFlagIpv4=0;
704 if [ -n "$ipv6_enabled" ] && [ -x "$ip6tables" ]; then
705 "$ip6tables" $d >/dev/null 2>&1 && failFlagIpv6=0
706 fi
707 [ "$failFlagIpv4" -eq 0 ] || [ "$failFlagIpv6" -eq 0 ]
708 }
709
710 # shellcheck disable=SC2086
711 ips4() { [ -x "$ipset" ] && "$ipset" "$@" >/dev/null 2>&1; }
712 ips6() { [ -x "$ipset" ] && { if [ -n "$ipv6_enabled" ] && [ -n "$*" ]; then "$ipset" "$@" >/dev/null 2>&1; else return 1; fi; }; }
713 ips() {
714 local command="$1" iface="$2" target="${3:-dst}" type="${4:-ip}" uid="$5" comment="$6" param="$7" mark="$7"
715 local ipset4 ipset6 i
716 local ipv4_error=1 ipv6_error=1
717 ipset4="${ipsPrefix}${iface:+_$iface}_4${target:+_$target}${type:+_$type}${uid:+_$uid}"
718 ipset6="${ipsPrefix}${iface:+_$iface}_6${target:+_$target}${type:+_$type}${uid:+_$uid}"
719
720 [ -x "$ipset" ] || return 1
721
722 if [ "${#ipset4}" -gt 31 ]; then
723 state add 'errorSummary' 'errorIpsetNameTooLong' "$ipset4"
724 return 1
725 fi
726
727 case "$command" in
728 add)
729 ips4 -q -! add "$ipset4" ["$param"] comment "$comment" && ipv4_error=0
730 ips6 -q -! add "$ipset6" ["$param"] comment "$comment" && ipv6_error=0
731 ;;
732 add_agh_element)
733 [ -n "$ipv6_enabled" ] || unset ipset6
734 echo "${param}/${ipset4}${ipset6:+,$ipset6}" >> "$aghIpsetFile" && ipv4_error=0
735 ;;
736 add_dnsmasq_element)
737 [ -n "$ipv6_enabled" ] || unset ipset6
738 # shellcheck disable=SC2086
739 echo "ipset=/${param}/${ipset4}${ipset6:+,$ipset6} # $comment" | tee -a $dnsmasqFileList >/dev/null 2>&1 && ipv4_error=0
740 ;;
741 create)
742 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
743 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0
744 ;;
745 create_agh_set)
746 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
747 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0
748 ;;
749 create_dnsmasq_set)
750 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
751 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0
752 ;;
753 create_user_set)
754 case "$type" in
755 ip|net)
756 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
757 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0
758 case "$target" in
759 dst)
760 ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" dst -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
761 ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" dst -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
762 ;;
763 src)
764 ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
765 ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
766 ;;
767 esac
768 ;;
769 mac)
770 ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0
771 ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv4_error=0
772 ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
773 ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
774 ;;
775 esac
776 ;;
777 delete|destroy)
778 ips4 -q -! destroy "$ipset4" && ipv4_error=0
779 ips6 -q -! destroy "$ipset6" && ipv6_error=0
780 ;;
781 delete_user_set)
782 ips4 -q -! destroy "$ipset4" && ipv4_error=0
783 ips6 -q -! destroy "$ipset6" family inet6 && ipv6_error=0
784 case "$type" in
785 ip|net)
786 case "$target" in
787 dst)
788 ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" dst -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
789 ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" dst -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
790 ;;
791 src)
792 ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
793 ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
794 ;;
795 esac
796 ;;
797 mac)
798 ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0
799 ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0
800 ;;
801 esac
802 ;;
803 flush|flush_user_set)
804 ips4 -q -! flush "$ipset4" && ipv4_error=0
805 ips6 -q -! flush "$ipset6" && ipv6_error=0
806 ;;
807 esac
808 if [ "$ipv4_error" -eq '0' ] || [ "$ipv6_error" -eq '0' ]; then
809 return 0
810 else
811 return 1
812 fi
813 }
814
815 nft_call() { [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; }
816 nft_file() {
817 local i
818 [ -x "$nft" ] || return 1
819 case "$1" in
820 add|add_command)
821 [ -n "$nft_file_support" ] || return 1
822 shift
823 grep -q "$*" "$nftTempFile" || echo "$*" >> "$nftTempFile"
824 ;;
825 create)
826 rm -f "$nftTempFile" "$nftPermFile"
827 for i in "$nftTempFile" "$nftPermFile"; do
828 mkdir -p "${i%/*}"
829 done
830 [ -n "$nft_file_support" ] || return 1
831 { echo '#!/usr/sbin/nft -f'; echo ''; } > "$nftTempFile"
832 ;;
833 delete|rm|remove)
834 rm -f "$nftTempFile" "$nftPermFile"
835 ;;
836 enabled)
837 [ -n "$nft_file_support" ] && return 0 || return 1
838 ;;
839 exists)
840 [ -s "$nftPermFile" ] && return 0 || return 1
841 ;;
842 install)
843 [ -n "$nft_file_support" ] || return 1
844 [ -s "$nftTempFile" ] || return 1
845 output "Installing fw4 nft file "
846 if nft_call -c -f "$nftTempFile" && \
847 cp -f "$nftTempFile" "$nftPermFile"; then
848 output_okn
849 else
850 state add 'errorSummary' 'errorNftFileInstall' "$nftTempFile"
851 output_failn
852 fi
853 ;;
854 esac
855 }
856 nft() { [ -x "$nft" ] && [ -n "$*" ] && { nft_file 'add_command' "$@" || "$nft" "$@" >/dev/null 2>&1;} }
857 nft4() { nft "$@"; }
858 nft6() { [ -n "$ipv6_enabled" ] || return 0; nft "$@"; }
859 nftset() {
860 local command="$1" iface="$2" target="${3:-dst}" type="${4:-ip}" uid="$5" comment="$6" param="$7" mark="$7"
861 local nftset4 nftset6 i param4 param6
862 local ipv4_error=1 ipv6_error=1
863 nftset4="${nftPrefix}${iface:+_$iface}_4${target:+_$target}${type:+_$type}${uid:+_$uid}"
864 nftset6="${nftPrefix}${iface:+_$iface}_6${target:+_$target}${type:+_$type}${uid:+_$uid}"
865
866 [ -x "$nft" ] || return 1
867
868 if [ "${#nftset4}" -gt 255 ]; then
869 state add 'errorSummary' 'errorNftsetNameTooLong' "$nftset4"
870 return 1
871 fi
872
873 case "$command" in
874 add)
875 if is_mac_address "$param" || is_list "$param"; then
876 nft4 add element inet "$nftTable" "$nftset4" "{ $param }" && ipv4_error=0
877 nft6 add element inet "$nftTable" "$nftset6" "{ $param }" && ipv6_error=0
878 elif is_ipv4_netmask "$param" || is_ipv4 "$param"; then
879 nft4 add element inet "$nftTable" "$nftset4" "{ $param }" && ipv4_error=0
880 elif is_ipv6 "$param"; then
881 nft6 add element inet "$nftTable" "$nftset6" "{ $param }" && ipv6_error=0
882 else
883 if [ "$target" = 'src' ]; then
884 param4="$(ipv4_leases_to_nftset "$param")"
885 param6="$(ipv6_leases_to_nftset "$param")"
886 fi
887 [ -z "$param4" ] && param4="$(resolveip_to_nftset4 "$param")"
888 [ -z "$param6" ] && param6="$(resolveip_to_nftset6 "$param")"
889 if [ -z "$param4" ] && [ -z "$param6" ]; then
890 state add 'errorSummary' 'errorFailedToResolve' "$param"
891 else
892 [ -n "$param4" ] && nft4 add element inet "$nftTable" "$nftset4" "{ $param4 }" && ipv4_error=0
893 [ -n "$param6" ] && nft6 add element inet "$nftTable" "$nftset6" "{ $param6 }" && ipv6_error=0
894 fi
895 fi
896 ;;
897 add_dnsmasq_element)
898 [ -n "$ipv6_enabled" ] || unset nftset6
899 # shellcheck disable=SC2086
900 echo "nftset=/${param}/4#inet#${nftTable}#${nftset4}${nftset6:+,6#inet#${nftTable}#$nftset6} # $comment" | tee -a $dnsmasqFileList >/dev/null 2>&1 && ipv4_error=0
901 ;;
902 create)
903 case "$type" in
904 ip|net)
905 nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; $nft_set_params comment \"$comment\";}" && ipv4_error=0
906 nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; $nft_set_params comment \"$comment\"; }" && ipv6_error=0
907 ;;
908 mac)
909 nft4 add set inet "$nftTable" "$nftset4" "{ type ether_addr; $nft_set_params comment \"$comment\"; }" && ipv4_error=0
910 nft6 add set inet "$nftTable" "$nftset6" "{ type ether_addr; $nft_set_params comment \"$comment\"; }" && ipv6_error=0
911 ;;
912 esac
913 ;;
914 create_dnsmasq_set)
915 nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; $nft_set_params comment \"$comment\"; }" && ipv4_error=0
916 nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; $nft_set_params comment \"$comment\"; }" && ipv6_error=0
917 ;;
918 create_user_set)
919 case "$type" in
920 ip|net)
921 nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; $nft_set_params comment \"$comment\"; }" && ipv4_error=0
922 nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; $nft_set_params comment \"$comment\"; }" && ipv6_error=0
923 case "$target" in
924 dst)
925 nft4 add rule inet "$nftTable" "${nftPrefix}_prerouting" "$nftIPv4Flag" daddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
926 nft6 add rule inet "$nftTable" "${nftPrefix}_prerouting" "$nftIPv6Flag" daddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
927 ;;
928 src)
929 nft4 add rule inet "$nftTable" "${nftPrefix}_prerouting" "$nftIPv4Flag" saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
930 nft6 add rule inet "$nftTable" "${nftPrefix}_prerouting" "$nftIPv6Flag" saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
931 ;;
932 esac
933 ;;
934 mac)
935 nft4 add set inet "$nftTable" "$nftset4" "{ type ether_addr; $nft_set_params comment \"$comment\"; }" && ipv4_error=0
936 nft6 add set inet "$nftTable" "$nftset6" "{ type ether_addr; $nft_set_params comment \"$comment\"; }" && ipv6_error=0
937 nft4 add rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
938 nft6 add rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
939 ;;
940 esac
941 ;;
942 delete|destroy)
943 nft_call delete set inet "$nftTable" "$nftset4" && ipv4_error=0
944 nft_call delete set inet "$nftTable" "$nftset6" && ipv6_error=0
945 ;;
946 delete_user_set)
947 nft_call delete set inet "$nftTable" "$nftset4" && ipv4_error=0
948 nft_call delete set inet "$nftTable" "$nftset6" && ipv6_error=0
949 case "$type" in
950 ip|net)
951 case "$target" in
952 dst)
953 nft_call delete rule inet "$nftTable" "${nftPrefix}_prerouting" "$nftIPv4Flag" daddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
954 nft_call delete rule inet "$nftTable" "${nftPrefix}_prerouting" "$nftIPv6Flag" daddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
955 ;;
956 src)
957 nft_call delete rule inet "$nftTable" "${nftPrefix}_prerouting" "$nftIPv4Flag" saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
958 nft_call delete rule inet "$nftTable" "${nftPrefix}_prerouting" "$nftIPv6Flag" saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
959 ;;
960 esac
961 ;;
962 mac)
963 nft_call delete rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0
964 nft_call delete rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0
965 ;;
966 esac
967 ;;
968 flush|flush_user_set)
969 nft_call flush set inet "$nftTable" "$nftset4" && ipv4_error=0
970 nft_call flush set inet "$nftTable" "$nftset6" && ipv6_error=0
971 ;;
972 esac
973 # nft6 returns true if IPv6 support is not enabled
974 [ -z "$ipv6_enabled" ] && ipv6_error='1'
975 if [ "$ipv4_error" -eq '0' ] || [ "$ipv6_error" -eq '0' ]; then
976 return 0
977 else
978 return 1
979 fi
980 }
981
982 cleanup_rt_tables() {
983 local i
984 # shellcheck disable=SC2013
985 for i in $(grep -oh "${ipTablePrefix}_.*" $rtTablesFile); do
986 ! is_netifd_table "$i" && sed -i "/${i}/d" "$rtTablesFile"
987 done
988 sync
989 }
990
991 cleanup_main_chains() {
992 local i
993 for i in $chainsList; do
994 i="$(str_to_lower "$i")"
995 nft_call flush chain inet "$nftTable" "${nftPrefix}_${i}"
996 done
997 for i in $chainsList; do
998 i="$(str_to_upper "$i")"
999 ipt -t mangle -D "${i}" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}"
1000 ipt -t mangle -F "${iptPrefix}_${i}"
1001 ipt -t mangle -X "${iptPrefix}_${i}"
1002 done
1003 }
1004
1005 cleanup_marking_chains() {
1006 local i
1007 for i in $(get_mark_nft_chains); do
1008 nft_call flush chain inet "$nftTable" "$i"
1009 nft_call delete chain inet "$nftTable" "$i"
1010 done
1011 for i in $(get_mark_ipt_chains); do
1012 ipt -t mangle -F "$i"
1013 ipt -t mangle -X "$i"
1014 done
1015 }
1016
1017 cleanup_sets() {
1018 local i
1019 for i in $(get_nft_sets); do
1020 nft_call flush set inet "$nftTable" "$i"
1021 nft_call delete set inet "$nftTable" "$i"
1022 done
1023 for i in $(get_ipsets); do
1024 ipset -q -! flush "$i" >/dev/null 2>&1
1025 ipset -q -! destroy "$i" >/dev/null 2>&1
1026 done
1027 }
1028
1029 state() {
1030 local action="$1" param="$2" value="${3//#/_}"
1031 shift 3
1032 # shellcheck disable=SC2124
1033 local extras="$@"
1034 local line error_id error_extra label
1035 case "$action" in
1036 add)
1037 line="$(eval echo "\$$param")"
1038 eval "$param"='${line:+$line#}${value}${extras:+ $extras}'
1039 ;;
1040 json)
1041 json_init
1042 json_add_object "$packageName"
1043 case "$param" in
1044 errorSummary)
1045 json_add_array 'errors';;
1046 warningSummary)
1047 json_add_array 'warnings';;
1048 esac
1049 if [ -n "$(eval echo "\$$param")" ]; then
1050 while read -r line; do
1051 if str_contains "$line" ' '; then
1052 error_id="${line% *}"
1053 error_extra="${line#* }"
1054 else
1055 error_id="$line"
1056 fi
1057 json_add_object
1058 json_add_string 'id' "$error_id"
1059 json_add_string 'extra' "$error_extra"
1060 json_close_object
1061 done <<EOF
1062 $(eval echo "\$$param" | tr \# \\n)
1063 EOF
1064 fi
1065 json_close_array
1066 json_close_object
1067 json_dump
1068 ;;
1069 print)
1070 [ -z "$(eval echo "\$$param")" ] && return 0
1071 case "$param" in
1072 errorSummary)
1073 label="${_ERROR_}:";;
1074 warningSummary)
1075 label="${_WARNING_}:";;
1076 esac
1077 while read -r line; do
1078 if str_contains "$line" ' '; then
1079 error_id="${line% *}"
1080 error_extra="${line#* }"
1081 printf "%b $(get_text "$error_id")\\n" "$label" "$error_extra"
1082 else
1083 error_id="$line"
1084 printf "%b $(get_text "$error_id")\\n" "$label"
1085 fi
1086 done <<EOF
1087 $(eval echo "\$$param" | tr \# \\n)
1088 EOF
1089 ;;
1090 set)
1091 eval "$param"='${value}${extras:+ $extras}'
1092 ;;
1093 esac
1094 }
1095
1096 _resolver_dnsmasq_confdir() {
1097 local cfg="$1"
1098 local confdir
1099 [ -z "$(uci_get 'dhcp' "$cfg")" ] && return 1;
1100 config_get confdir "$1" 'confdir'
1101 if [ -z "$confdir" ] && [ "$resolver_instance" != "*" ]; then
1102 state add 'warningSummary' 'warningDnsmasqInstanceNoConfdir' "$cfg"
1103 fi
1104 if [ -n "$confdir" ] && ! str_contains "$dnsmasqFileList" "$confdir"; then
1105 dnsmasqFile="${confdir}/${packageName}"
1106 dnsmasqFileList="${dnsmasqFileList:+$dnsmasqFileList }${dnsmasqFile}"
1107 fi
1108 }
1109
1110 resolver() {
1111 local agh_version
1112 local param="$1"
1113 shift
1114
1115 if [ "$param" = 'cleanup_all' ]; then
1116 sed -i "/ipset_file: ${aghIpsetFile}/d" "$aghConfigFile" >/dev/null 2>&1
1117 rm -f "$aghIpsetFile"
1118 local dfl
1119 for dfl in $dnsmasqFileList; do
1120 rm -f "$dfl"
1121 done
1122 return 0
1123 fi
1124
1125 case "$resolver_set" in
1126 ''|none)
1127 case "$param" in
1128 add_resolver_element) return 1;;
1129 create_resolver_set) return 1;;
1130 check_support) return 0;;
1131 cleanup) return 0;;
1132 configure) return 0;;
1133 init) return 0;;
1134 init_end) return 0;;
1135 kill) return 0;;
1136 reload) return 0;;
1137 restart) return 0;;
1138 compare_hash) return 0;;
1139 store_hash) return 0;;
1140 esac
1141 ;;
1142 adguardhome.ipset)
1143 case "$param" in
1144 add_resolver_element)
1145 [ -n "$resolver_set_supported" ] && ips 'add_agh_element' "$@";;
1146 create_resolver_set)
1147 [ -n "$resolver_set_supported" ] && ips 'create_agh_set' "$@";;
1148 check_support)
1149 if [ ! -x "$ipset" ]; then
1150 state add 'errorSummary' 'errorNoIpset'
1151 return 1
1152 fi
1153 if [ -n "$agh" ] && [ -s "$aghConfigFile" ]; then
1154 agh_version="$($agh --version | sed 's|AdGuard Home, version v\(.*\)|\1|' | sed 's|-.*||')"
1155 if is_greater_or_equal "$agh_version" '0.107.13'; then
1156 resolver_set_supported='true'
1157 return 0
1158 else
1159 state add 'warningSummary' 'warningAGHVersionTooLow' "$agh_version"
1160 return 1
1161 fi
1162 else
1163 state add 'warningSummary' 'warningResolverNotSupported'
1164 return 1
1165 fi
1166 ;;
1167 cleanup)
1168 [ -z "$resolver_set_supported" ] && return 0
1169 rm -f "$aghIpsetFile"
1170 sed -i "/ipset_file: ${aghIpsetFile}/d" "$aghConfigFile" >/dev/null 2>&1
1171 ;;
1172 configure)
1173 [ -z "$resolver_set_supported" ] && return 1
1174 mkdir -p "${aghIpsetFile%/*}"
1175 touch "$aghIpsetFile"
1176 sed -i '/ipset_file/d' "$aghConfigFile" >/dev/null 2>&1
1177 sed -i "/ ipset:/a \ \ ipset_file: $aghIpsetFile" "$aghConfigFile"
1178 ;;
1179 init) :;;
1180 init_end) :;;
1181 kill)
1182 [ -n "$resolver_set_supported" ] && [ -n "$agh" ] && killall -q -s HUP "$agh";;
1183 reload)
1184 [ -z "$resolver_set_supported" ] && return 1
1185 output 3 'Reloading adguardhome '
1186 if /etc/init.d/adguardhome reload >/dev/null 2>&1; then
1187 output_okn
1188 return 0
1189 else
1190 output_failn
1191 return 1
1192 fi
1193 ;;
1194 restart)
1195 [ -z "$resolver_set_supported" ] && return 1
1196 output 3 'Restarting adguardhome '
1197 if /etc/init.d/adguardhome restart >/dev/null 2>&1; then
1198 output_okn
1199 return 0
1200 else
1201 output_failn
1202 return 1
1203 fi
1204 ;;
1205 compare_hash)
1206 [ -z "$resolver_set_supported" ] && return 1
1207 local resolverNewHash
1208 if [ -s "$aghIpsetFile" ]; then
1209 resolverNewHash="$(md5sum "$aghIpsetFile" | awk '{ print $1; }')"
1210 fi
1211 [ "$resolverNewHash" != "$resolverStoredHash" ]
1212 ;;
1213 store_hash)
1214 [ -s "$aghIpsetFile" ] && resolverStoredHash="$(md5sum "$aghIpsetFile" | awk '{ print $1; }')";;
1215 esac
1216 ;;
1217 dnsmasq.ipset)
1218 case "$param" in
1219 add_resolver_element)
1220 [ -n "$resolver_set_supported" ] && ips 'add_dnsmasq_element' "$@";;
1221 create_resolver_set)
1222 [ -n "$resolver_set_supported" ] && ips 'create_dnsmasq_set' "$@";;
1223 check_support)
1224 if [ ! -x "$ipset" ]; then
1225 state add 'errorSummary' 'errorNoIpset'
1226 return 1
1227 fi
1228 if ! dnsmasq -v 2>/dev/null | grep -q 'no-ipset' && dnsmasq -v 2>/dev/null | grep -q 'ipset'; then
1229 resolver_set_supported='true'
1230 return 0
1231 else
1232 state add 'warningSummary' 'warningResolverNotSupported'
1233 return 1
1234 fi
1235 ;;
1236 cleanup)
1237 if [ -n "$resolver_set_supported" ]; then
1238 local dfl
1239 for dfl in $dnsmasqFileList; do
1240 rm -f "$dfl"
1241 done
1242 fi
1243 ;;
1244 configure)
1245 if [ -n "$resolver_set_supported" ]; then
1246 local dfl
1247 for dfl in $dnsmasqFileList; do
1248 mkdir -p "${dfl%/*}"
1249 chmod -R 660 "${dfl%/*}"
1250 chown -R root:dnsmasq "${dfl%/*}"
1251 touch "$dfl"
1252 chmod 660 "$dfl"
1253 chown root:dnsmasq "$dfl"
1254 done
1255 fi
1256 ;;
1257 configure_instances)
1258 config_load 'dhcp'
1259 if [ "$resolver_instance" = "*" ]; then
1260 config_foreach _resolver_dnsmasq_confdir 'dnsmasq'
1261 dnsmasqFile="${dnsmasqFile:-$dnsmasqFileDefault}"
1262 str_contains "$dnsmasqFileList" "$dnsmasqFileDefault" || \
1263 dnsmasqFileList="${dnsmasqFileList:+$dnsmasqFileList }${dnsmasqFileDefault}"
1264 else
1265 for i in $resolver_instance; do
1266 _resolver_dnsmasq_confdir "@dnsmasq[$i]" \
1267 || _resolver_dnsmasq_confdir "$i"
1268 done
1269 dnsmasqFile="${dnsmasqFile:-$dnsmasqFileDefault}"
1270 str_contains "$dnsmasqFileList" "$dnsmasqFileDefault" || \
1271 dnsmasqFileList="${dnsmasqFileList:-$dnsmasqFileDefault}"
1272 fi
1273 ;;
1274 init) :;;
1275 init_end) :;;
1276 kill)
1277 [ -n "$resolver_set_supported" ] && killall -q -s HUP dnsmasq;;
1278 reload)
1279 [ -z "$resolver_set_supported" ] && return 1
1280 output 3 'Reloading dnsmasq '
1281 if /etc/init.d/dnsmasq reload >/dev/null 2>&1; then
1282 output_okn
1283 return 0
1284 else
1285 output_failn
1286 return 1
1287 fi
1288 ;;
1289 restart)
1290 [ -z "$resolver_set_supported" ] && return 1
1291 output 3 'Restarting dnsmasq '
1292 if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then
1293 output_okn
1294 return 0
1295 else
1296 output_failn
1297 return 1
1298 fi
1299 ;;
1300 compare_hash)
1301 [ -z "$resolver_set_supported" ] && return 1
1302 local resolverNewHash
1303 if [ -s "$dnsmasqFile" ]; then
1304 resolverNewHash="$(md5sum "$dnsmasqFile" | awk '{ print $1; }')"
1305 fi
1306 [ "$resolverNewHash" != "$resolverStoredHash" ]
1307 ;;
1308 store_hash)
1309 [ -s "$dnsmasqFile" ] && resolverStoredHash="$(md5sum "$dnsmasqFile" | awk '{ print $1; }')";;
1310 esac
1311 ;;
1312 dnsmasq.nftset)
1313 case "$param" in
1314 add_resolver_element)
1315 [ -n "$resolver_set_supported" ] && nftset 'add_dnsmasq_element' "$@";;
1316 create_resolver_set)
1317 [ -n "$resolver_set_supported" ] && nftset 'create_dnsmasq_set' "$@";;
1318 check_support)
1319 if [ ! -x "$nft" ]; then
1320 state add 'errorSummary' 'errorNoNft'
1321 return 1
1322 fi
1323 if ! dnsmasq -v 2>/dev/null | grep -q 'no-nftset' && dnsmasq -v 2>/dev/null | grep -q 'nftset'; then
1324 resolver_set_supported='true'
1325 return 0
1326 else
1327 state add 'warningSummary' 'warningResolverNotSupported'
1328 return 1
1329 fi
1330 ;;
1331 cleanup)
1332 if [ -n "$resolver_set_supported" ]; then
1333 local dfl
1334 for dfl in $dnsmasqFileList; do
1335 rm -f "$dfl"
1336 done
1337 fi
1338 ;;
1339 configure)
1340 if [ -n "$resolver_set_supported" ]; then
1341 local dfl
1342 for dfl in $dnsmasqFileList; do
1343 mkdir -p "${dfl%/*}"
1344 chmod -R 660 "${dfl%/*}"
1345 chown -R root:dnsmasq "${dfl%/*}"
1346 touch "$dfl"
1347 chmod 660 "$dfl"
1348 chown root:dnsmasq "$dfl"
1349 done
1350 fi
1351 ;;
1352 configure_instances)
1353 config_load 'dhcp'
1354 if [ "$resolver_instance" = "*" ]; then
1355 config_foreach _resolver_dnsmasq_confdir 'dnsmasq'
1356 dnsmasqFile="${dnsmasqFile:-$dnsmasqFileDefault}"
1357 str_contains "$dnsmasqFileList" "$dnsmasqFileDefault" || \
1358 dnsmasqFileList="${dnsmasqFileList:+$dnsmasqFileList }${dnsmasqFileDefault}"
1359 else
1360 for i in $resolver_instance; do
1361 _resolver_dnsmasq_confdir "@dnsmasq[$i]" \
1362 || _resolver_dnsmasq_confdir "$i"
1363 done
1364 dnsmasqFile="${dnsmasqFile:-$dnsmasqFileDefault}"
1365 str_contains "$dnsmasqFileList" "$dnsmasqFileDefault" || \
1366 dnsmasqFileList="${dnsmasqFileList:-$dnsmasqFileDefault}"
1367 fi
1368 ;;
1369 init) :;;
1370 init_end) :;;
1371 kill)
1372 [ -n "$resolver_set_supported" ] && killall -q -s HUP dnsmasq;;
1373 reload)
1374 [ -z "$resolver_set_supported" ] && return 1
1375 output 3 'Reloading dnsmasq '
1376 if /etc/init.d/dnsmasq reload >/dev/null 2>&1; then
1377 output_okn
1378 return 0
1379 else
1380 output_failn
1381 return 1
1382 fi
1383 ;;
1384 restart)
1385 [ -z "$resolver_set_supported" ] && return 1
1386 output 3 'Restarting dnsmasq '
1387 if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then
1388 output_okn
1389 return 0
1390 else
1391 output_failn
1392 return 1
1393 fi
1394 ;;
1395 compare_hash)
1396 [ -z "$resolver_set_supported" ] && return 1
1397 local resolverNewHash
1398 if [ -s "$dnsmasqFile" ]; then
1399 resolverNewHash="$(md5sum "$dnsmasqFile" | awk '{ print $1; }')"
1400 fi
1401 [ "$resolverNewHash" != "$resolverStoredHash" ]
1402 ;;
1403 store_hash)
1404 [ -s "$dnsmasqFile" ] && resolverStoredHash="$(md5sum "$dnsmasqFile" | awk '{ print $1; }')";;
1405 esac
1406 ;;
1407 unbound.ipset)
1408 case "$param" in
1409 add_resolver_element) :;;
1410 create_resolver_set) :;;
1411 check_support) :;;
1412 cleanup) :;;
1413 configure) :;;
1414 init) :;;
1415 init_end) :;;
1416 kill) :;;
1417 reload) :;;
1418 restart) :;;
1419 compare_hash) :;;
1420 store_hash) :;;
1421 esac
1422 ;;
1423 unbound.nftset)
1424 case "$param" in
1425 add_resolver_element) :;;
1426 create_resolver_set) :;;
1427 check_support) :;;
1428 cleanup) :;;
1429 configure) :;;
1430 init) :;;
1431 init_end) :;;
1432 kill) :;;
1433 reload) :;;
1434 restart) :;;
1435 compare_hash) :;;
1436 store_hash) :;;
1437 esac
1438 ;;
1439 esac
1440 }
1441
1442 trap_process() {
1443 output "\\n"
1444 output "Unexpected exit or service termination: '${1}'!\\n"
1445 state add 'errorSummary' 'errorUnexpectedExit' "$1"
1446 traffic_killswitch 'remove'
1447 }
1448
1449 traffic_killswitch() {
1450 local s=0
1451 case "$1" in
1452 insert)
1453 local lan_subnet wan_device wan6_device
1454 [ -n "$secure_reload" ] || return 0
1455 nft_file 'enabled' && return 0
1456 for i in $serviceTrapSignals; do
1457 # shellcheck disable=SC2064
1458 trap "trap_process $i" "$i"
1459 done
1460 output 3 'Activating traffic killswitch '
1461 network_get_subnet lan_subnet "${procd_lan_interface:-lan}"
1462 network_get_physdev wan_device "${wanIface4:-wan}"
1463 network_get_physdev wan6_device "${wanIface6:-wan6}"
1464 if is_nft_mode; then
1465 nft_call add chain inet "$nftTable" "${nftPrefix}_killswitch" '{ type filter hook forward priority 0; policy accept; }' || s=1
1466 nft_call add rule inet "$nftTable" "${nftPrefix}_killswitch" oifname "$wan_device" "$nftIPv4Flag" saddr "$lan_subnet" counter reject || s=1
1467 nft_call add rule inet "$nftTable" "${nftPrefix}_killswitch" oifname "$wan6_device" "$nftIPv6Flag" saddr "$lan_subnet" counter reject
1468 else
1469 ipt -N "${iptPrefix}_KILLSWITCH" || s=1
1470 ipt -A "${iptPrefix}_KILLSWITCH" -s "$lan_subnet" -o "$wan_device" -j REJECT || s=1
1471 ipt -A "${iptPrefix}_KILLSWITCH" -s "$lan_subnet" -o "$wan6_device" -j REJECT
1472 ipt -I FORWARD -j "${iptPrefix}_KILLSWITCH" || s=1
1473 fi
1474 if [ "$s" -eq 0 ]; then
1475 output_okn
1476 else
1477 output_failn
1478 fi
1479 ;;
1480 remove)
1481 if [ -n "$secure_reload" ] && ! nft_file 'enabled'; then
1482 output 3 'Deactivating traffic killswitch '
1483 fi
1484 if is_nft_mode; then
1485 nft_call flush chain inet "$nftTable" "${nftPrefix}_killswitch" || s=1
1486 nft_call delete chain inet "$nftTable" "${nftPrefix}_killswitch" || s=1
1487 else
1488 ipt -D FORWARD -j "${iptPrefix}_KILLSWITCH" || s=1
1489 ipt -F "${iptPrefix}_KILLSWITCH" || s=1
1490 ipt -X "${iptPrefix}_KILLSWITCH" || s=1
1491 fi
1492 if [ -n "$secure_reload" ] && ! nft_file 'enabled'; then
1493 if [ "$s" -eq 0 ]; then
1494 output_okn
1495 else
1496 output_failn
1497 fi
1498 fi
1499 # shellcheck disable=SC2086
1500 trap - $serviceTrapSignals
1501 ;;
1502 esac
1503 }
1504
1505 policy_routing() { if is_nft_mode; then policy_routing_nft "$@"; else policy_routing_iptables "$@"; fi; }
1506 policy_routing_iptables() {
1507 local mark param4 param6 i negation value dest4 dest6 ipInsertOption="-A"
1508 local ip4error='1' ip6error='1'
1509 local name="$1" iface="$2" laddr="$3" lport="$4" raddr="$5" rport="$6" proto chain uid="$9"
1510 proto="$(str_to_lower "$7")"
1511 chain="$(str_to_upper "$8")"
1512 chain="${chain:-PREROUTING}"
1513 mark=$(eval echo "\$mark_${iface//-/_}")
1514
1515 if [ -n "$ipv6_enabled" ] && { is_ipv6 "$laddr" || is_ipv6 "$raddr"; }; then
1516 processPolicyError='true'
1517 state add 'errorSummary' 'errorPolicyProcessNoIpv6' "$name"
1518 return 1
1519 fi
1520
1521 if is_tor "$iface"; then
1522 return 1
1523 elif is_xray "$iface"; then
1524 unset rport
1525 [ -z "$lport" ] && lport='0-52,54-65535'
1526 proto='tcp udp'
1527 dest4="-j TPROXY --on-ip 0.0.0.0 --on-port $(get_xray_traffic_port "$iface")"
1528 dest6="-j TPROXY --on-ip :: --on-port $(get_xray_traffic_port "$iface")"
1529 elif [ -n "$mark" ]; then
1530 dest4="-g ${iptPrefix}_MARK_${mark}"
1531 dest6="-g ${iptPrefix}_MARK_${mark}"
1532 elif [ "$iface" = "ignore" ]; then
1533 dest4="-j RETURN"
1534 dest6="-j RETURN"
1535 else
1536 processPolicyError='true'
1537 state add 'errorSummary' 'errorPolicyProcessUnknownFwmark' "$iface"
1538 return 1
1539 fi
1540
1541 if is_family_mismatch "$laddr" "$raddr"; then
1542 processPolicyError='true'
1543 state add 'errorSummary' 'errorPolicyProcessMismatchFamily' "${name}: '$laddr' '$raddr'"
1544 return 1
1545 fi
1546
1547 if [ -z "$proto" ]; then
1548 if [ -n "${lport}${rport}" ]; then
1549 proto='tcp udp'
1550 else
1551 proto='all'
1552 fi
1553 fi
1554
1555 for i in $proto; do
1556 if [ "$i" = 'all' ]; then
1557 param4="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest4"
1558 param6="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest6"
1559 elif ! is_supported_protocol "$i"; then
1560 processPolicyError='true'
1561 state add 'errorSummary' 'errorPolicyProcessUnknownProtocol' "${name}: '$i'"
1562 return 1
1563 else
1564 param4="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest4 -p $i"
1565 param6="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest6 -p $i"
1566 fi
1567
1568 if [ -n "$laddr" ]; then
1569 if [ "${laddr:0:1}" = "!" ]; then
1570 negation='!'; value="${laddr:1}"
1571 else
1572 unset negation; value="$laddr";
1573 fi
1574 if is_phys_dev "$value"; then
1575 param4="$param4 ${negation:+$negation }-m physdev --physdev-in ${value:1}"
1576 param6="$param6 ${negation:+$negation }-m physdev --physdev-in ${value:1}"
1577 elif is_ipv4_netmask "$value"; then
1578 local target='src' type='net'
1579 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \
1580 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then
1581 param4="$param4 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1582 param6="$param6 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1583 else
1584 param4="$param4 ${negation:+$negation }-s $value"
1585 param6="$param6 ${negation:+$negation }-s $value"
1586 fi
1587 elif is_mac_address "$value"; then
1588 local target='src' type='mac'
1589 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \
1590 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then
1591 param4="$param4 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1592 param6="$param6 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1593 else
1594 param4="$param4 -m mac ${negation:+$negation }--mac-source $value"
1595 param6="$param6 -m mac ${negation:+$negation }--mac-source $value"
1596 fi
1597 else
1598 local target='src' type='ip'
1599 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \
1600 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then
1601 param4="$param4 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1602 param6="$param6 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1603 else
1604 local resolvedIP4 resolvedIP6
1605 resolvedIP4="$(resolveip_to_ipt4 "$value")"
1606 resolvedIP6="$(resolveip_to_ipt6 "$value")"
1607 if [ -z "$resolvedIP4" ] && [ -z "$resolvedIP6" ]; then
1608 state add 'errorSummary' 'errorFailedToResolve' "$value"
1609 fi
1610 param4="$param4 ${negation:+$negation }-s $resolvedIP4"
1611 param6="$param6 ${negation:+$negation }-s $resolvedIP6"
1612 fi
1613 fi
1614 fi
1615
1616 if [ -n "$lport" ]; then
1617 if [ "${lport:0:1}" = "!" ]; then
1618 negation='!'; value="${lport:1}"
1619 else
1620 unset negation; value="$lport";
1621 fi
1622 param4="$param4 -m multiport ${negation:+$negation }--sport ${value//-/:}"
1623 param6="$param6 -m multiport ${negation:+$negation }--sport ${value//-/:}"
1624 fi
1625
1626 if [ -n "$raddr" ]; then
1627 if [ "${raddr:0:1}" = "!" ]; then
1628 negation='!'; value="${raddr:1}"
1629 else
1630 unset negation; value="$raddr";
1631 fi
1632 if is_ipv4_netmask "$value"; then
1633 local target='dst' type='net'
1634 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \
1635 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then
1636 param4="$param4 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1637 param6="$param6 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1638 else
1639 param4="$param4 ${negation:+$negation }-d ${value}"
1640 param6="$param6 ${negation:+$negation }-d ${value}"
1641 fi
1642 elif is_domain "$value"; then
1643 local target='dst' type='ip'
1644 if resolver 'create_resolver_set' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \
1645 resolver 'add_resolver_element' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then
1646 param4="$param4 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1647 param6="$param6 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1648 elif ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \
1649 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then
1650 param4="$param4 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1651 param6="$param6 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1652 else
1653 local resolvedIP4 resolvedIP6
1654 resolvedIP4="$(resolveip_to_ipt4 "$value")"
1655 resolvedIP6="$(resolveip_to_ipt6 "$value")"
1656 if [ -z "$resolvedIP4" ] && [ -z "$resolvedIP6" ]; then
1657 state add 'errorSummary' 'errorFailedToResolve' "$value"
1658 fi
1659 param4="$param4 ${negation:+$negation }-d $resolvedIP4"
1660 param6="$param6 ${negation:+$negation }-d $resolvedIP6"
1661 fi
1662 else
1663 local target='dst' type='ip'
1664 if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \
1665 ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then
1666 param4="$param4 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target"
1667 param6="$param6 -m set ${negation:+$negation }--match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target"
1668 else
1669 param4="$param4 ${negation:+$negation }-d ${value}"
1670 param6="$param6 ${negation:+$negation }-d ${value}"
1671 fi
1672 fi
1673 fi
1674
1675 if [ -n "$rport" ]; then
1676 if [ "${rport:0:1}" = "!" ]; then
1677 negation='!'; value="${rport:1}"
1678 else
1679 unset negation; value="$rport";
1680 fi
1681 param4="$param4 -m multiport ${negation:+$negation }--dport ${value//-/:}"
1682 param6="$param6 -m multiport ${negation:+$negation }--dport ${value//-/:}"
1683 fi
1684
1685 if [ -n "$name" ]; then
1686 param4="$param4 -m comment --comment $(str_extras_to_underscore "$name")"
1687 param6="$param6 -m comment --comment $(str_extras_to_underscore "$name")"
1688 fi
1689
1690 local ipv4_error='0' ipv6_error='0'
1691 if [ "$param4" = "$param6" ]; then
1692 ipt4 "$param4" || ipv4_error='1'
1693 else
1694 ipt4 "$param4" || ipv4_error='1'
1695 ipt6 "$param6" || ipv6_error='1'
1696 fi
1697
1698 if [ -n "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ] && [ "$ipv6_error" -eq '1' ]; then
1699 processPolicyError='true'
1700 state add 'errorSummary' 'errorPolicyProcessInsertionFailed' "$name"
1701 state add 'errorSummary' 'errorPolicyProcessCMD' "iptables $param4"
1702 state add 'errorSummary' 'errorPolicyProcessCMD' "iptables $param6"
1703 logger -t "$packageName" "ERROR: iptables $param4"
1704 logger -t "$packageName" "ERROR: iptables $param6"
1705 elif [ -z "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ]; then
1706 processPolicyError='true'
1707 state add 'errorSummary' 'errorPolicyProcessInsertionFailedIpv4' "$name"
1708 state add 'errorSummary' 'errorPolicyProcessCMD' "iptables $param4"
1709 logger -t "$packageName" "ERROR: iptables $param4"
1710 fi
1711
1712 done
1713 }
1714 policy_routing_nft() {
1715 local mark i nftInsertOption='add'
1716 local param4 param6 proto_i negation value dest4 dest6
1717 local name="$1" iface="$2" src_addr="$3" src_port="$4" dest_addr="$5" dest_port="$6" proto chain uid="$9"
1718 proto="$(str_to_lower "$7")"
1719 chain="$(str_to_lower "$8")"
1720 chain="${chain:-prerouting}"
1721 mark=$(eval echo "\$mark_${iface//-/_}")
1722
1723 if [ -z "$ipv6_enabled" ] && { is_ipv6 "$src_addr" || is_ipv6 "$dest_addr"; }; then
1724 processPolicyError='true'
1725 state add 'errorSummary' 'errorPolicyProcessNoIpv6' "$name"
1726 return 1
1727 fi
1728
1729 if is_tor "$iface"; then
1730 unset dest_port
1731 unset proto
1732 elif is_xray "$iface"; then
1733 unset dest_port
1734 [ -z "$src_port" ] && src_port='0-65535'
1735 dest4="tproxy $nftIPv4Flag to: $(get_xray_traffic_port "$iface") accept"
1736 dest6="tproxy $nftIPv6Flag to: $(get_xray_traffic_port "$iface") accept"
1737 elif [ -n "$mark" ]; then
1738 dest4="goto ${nftPrefix}_mark_${mark}"
1739 dest6="goto ${nftPrefix}_mark_${mark}"
1740 elif [ "$iface" = "ignore" ]; then
1741 dest4="return"
1742 dest6="return"
1743 else
1744 processPolicyError='true'
1745 state add 'errorSummary' 'errorPolicyProcessUnknownFwmark' "$iface"
1746 return 1
1747 fi
1748
1749 if is_family_mismatch "$src_addr" "$dest_addr"; then
1750 processPolicyError='true'
1751 state add 'errorSummary' 'errorPolicyProcessMismatchFamily' "${name}: '$src_addr' '$dest_addr'"
1752 return 1
1753 fi
1754
1755 if [ -z "$proto" ]; then
1756 if [ -n "${src_port}${dest_port}" ]; then
1757 proto='tcp udp'
1758 else
1759 proto='all'
1760 fi
1761 fi
1762
1763 for proto_i in $proto; do
1764 unset param4
1765 unset param6
1766 if [ "$proto_i" = 'all' ]; then
1767 unset proto_i
1768 elif ! is_supported_protocol "$proto_i"; then
1769 processPolicyError='true'
1770 state add 'errorSummary' 'errorPolicyProcessUnknownProtocol' "${name}: '$proto_i'"
1771 return 1
1772 fi
1773
1774 if [ -n "$src_addr" ]; then
1775 if [ "${src_addr:0:1}" = "!" ]; then
1776 negation='!='; value="${src_addr:1}"
1777 else
1778 unset negation; value="$src_addr";
1779 fi
1780 if is_phys_dev "$value"; then
1781 param4="${param4:+$param4 }iifname ${negation:+$negation }${value:1}"
1782 param6="${param6:+$param6 }iifname ${negation:+$negation }${value:1}"
1783 elif is_mac_address "$value"; then
1784 local target='src' type='mac'
1785 if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \
1786 nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1787 param4="${param4:+$param4 }ether saddr ${negation:+$negation }@${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1788 param6="${param6:+$param6 }ether saddr ${negation:+$negation }@${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1789 else
1790 param4="${param4:+$param4 }ether saddr ${negation:+$negation }${value}"
1791 param6="${param6:+$param6 }ether saddr ${negation:+$negation }${value}"
1792 fi
1793 else
1794 local target='src' type='ip'
1795 if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \
1796 nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1797 param4="${param4:+$param4 }${nftIPv4Flag} saddr ${negation:+$negation }@${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1798 param6="${param6:+$param6 }${nftIPv6Flag} saddr ${negation:+$negation }@${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1799 else
1800 param4="${param4:+$param4 }${nftIPv4Flag} saddr ${negation:+$negation }${value}"
1801 param6="${param6:+$param6 }${nftIPv6Flag} saddr ${negation:+$negation }${value}"
1802 fi
1803 fi
1804 fi
1805
1806 if [ -n "$dest_addr" ]; then
1807 if [ "${dest_addr:0:1}" = "!" ]; then
1808 negation='!='; value="${dest_addr:1}"
1809 else
1810 unset negation; value="$dest_addr";
1811 fi
1812 if is_phys_dev "$value"; then
1813 param4="${param4:+$param4 }oifname ${negation:+$negation }${value:1}"
1814 param6="${param6:+$param6 }oifname ${negation:+$negation }${value:1}"
1815 elif is_domain "$value"; then
1816 local target='dst' type='ip'
1817 if resolver 'create_resolver_set' "$iface" "$target" "$type" "$uid" "$name" && \
1818 resolver 'add_resolver_element' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1819 param4="${param4:+$param4 }${nftIPv4Flag} daddr ${negation:+$negation }@${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1820 param6="${param6:+$param6 }${nftIPv6Flag} daddr ${negation:+$negation }@${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1821 elif nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \
1822 nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1823 param4="${param4:+$param4 }${nftIPv4Flag} daddr ${negation:+$negation }@${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1824 param6="${param6:+$param6 }${nftIPv6Flag} daddr ${negation:+$negation }@${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1825 else
1826 local resolvedIP4 resolvedIP6
1827 resolvedIP4="$(resolveip_to_nftset4 "$value")"
1828 resolvedIP6="$(resolveip_to_nftset6 "$value")"
1829 if [ -z "$resolvedIP4" ] && [ -z "$resolvedIP6" ]; then
1830 state add 'errorSummary' 'errorFailedToResolve' "$value"
1831 fi
1832 param4="${param4:+$param4 }${nftIPv4Flag} daddr ${negation:+$negation }{ $resolvedIP4 }"
1833 param6="${param6:+$param6 }${nftIPv6Flag} daddr ${negation:+$negation }{ $resolvedIP6 }"
1834 fi
1835 else
1836 local target='dst' type='ip'
1837 if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \
1838 nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then
1839 param4="${param4:+$param4 }${nftIPv4Flag} daddr ${negation:+$negation }@${nftPrefix}_${iface}_4_${target}_${type}_${uid}"
1840 param6="${param6:+$param6 }${nftIPv6Flag} daddr ${negation:+$negation }@${nftPrefix}_${iface}_6_${target}_${type}_${uid}"
1841 else
1842 param4="${param4:+$param4 }${nftIPv4Flag} daddr ${negation:+$negation }${value}"
1843 param6="${param6:+$param6 }${nftIPv6Flag} daddr ${negation:+$negation }${value}"
1844 fi
1845 fi
1846 fi
1847
1848 if [ -n "$src_port" ]; then
1849 if [ "${src_port:0:1}" = "!" ]; then
1850 negation='!='; value="${src_port:1}"
1851 else
1852 unset negation; value="$src_port";
1853 fi
1854 param4="${param4:+$param4 }${proto_i:+$proto_i }sport ${negation:+$negation }{$(ports_to_nftset "$value")}"
1855 param6="${param6:+$param6 }${proto_i:+$proto_i }sport ${negation:+$negation }{$(ports_to_nftset "$value")}"
1856 fi
1857
1858 if [ -n "$dest_port" ]; then
1859 if [ "${dest_port:0:1}" = "!" ]; then
1860 negation='!='; value="${dest_port:1}"
1861 else
1862 unset negation; value="$dest_port";
1863 fi
1864 param4="${param4:+$param4 }${proto_i:+$proto_i }dport ${negation:+$negation }{$(ports_to_nftset "$value")}"
1865 param6="${param6:+$param6 }${proto_i:+$proto_i }dport ${negation:+$negation }{$(ports_to_nftset "$value")}"
1866 fi
1867
1868 if is_tor "$iface"; then
1869 local dest_udp_53 dest_tcp_80 dest_udp_80 dest_tcp_443 dest_udp_443
1870 local ipv4_error='0' ipv6_error='0'
1871 local dest_i dest4 dest6
1872 param4="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} dstnat meta nfproto ipv4 $param4"
1873 param6="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} dstnat meta nfproto ipv6 $param6"
1874 dest_udp_53="udp dport 53 counter redirect to :${torDnsPort} comment 'Tor-DNS-UDP'"
1875 dest_tcp_80="tcp dport 80 counter redirect to :${torTrafficPort} comment 'Tor-HTTP-TCP'"
1876 dest_udp_80="udp dport 80 counter redirect to :${torTrafficPort} comment 'Tor-HTTP-UDP'"
1877 dest_tcp_443="tcp dport 443 counter redirect to :${torTrafficPort} comment 'Tor-HTTPS-TCP'"
1878 dest_udp_443="udp dport 443 counter redirect to :${torTrafficPort} comment 'Tor-HTTPS-UDP'"
1879 for dest_i in dest_udp_53 dest_tcp_80 dest_udp_80 dest_tcp_443 dest_udp_443; do
1880 eval "dest4=\$$dest_i"
1881 eval "dest6=\$$dest_i"
1882 nft4 "$param4" "$dest4" || ipv4_error='1'
1883 nft6 "$param6" "$dest6" || ipv6_error='1'
1884 if [ -n "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ] && [ "$ipv6_error" -eq '1' ]; then
1885 processPolicyError='true'
1886 state add 'errorSummary' 'errorPolicyProcessInsertionFailed' "$name"
1887 state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param4 $dest4"
1888 state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param6 $dest6"
1889 logger -t "$packageName" "ERROR: nft $param4 $dest4"
1890 logger -t "$packageName" "ERROR: nft $param6 $dest6"
1891 elif [ -z "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ]; then
1892 processPolicyError='true'
1893 state add 'errorSummary' 'errorPolicyProcessInsertionFailedIpv4' "$name"
1894 state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param4 $dest4"
1895 logger -t "$packageName" "ERROR: nft $param4 $dest4"
1896 fi
1897 done
1898 else
1899 param4="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} $param4 $dest4 comment \"$name\""
1900 param6="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} $param6 $dest6 comment \"$name\""
1901 local ipv4_error='0' ipv6_error='0'
1902 if [ "$policy_routing_nft_prev_param4" != "$param4" ]; then
1903 nft4 "$param4" || ipv4_error='1'
1904 policy_routing_nft_prev_param4="$param4"
1905 fi
1906 if [ "$policy_routing_nft_prev_param6" != "$param6" ] && \
1907 [ "$param4" != "$param6" ]; then
1908 nft6 "$param6" || ipv6_error='1'
1909 policy_routing_nft_prev_param6="$param6"
1910 fi
1911
1912 if [ -n "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ] && [ "$ipv6_error" -eq '1' ]; then
1913 processPolicyError='true'
1914 state add 'errorSummary' 'errorPolicyProcessInsertionFailed' "$name"
1915 state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param4"
1916 state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param6"
1917 logger -t "$packageName" "ERROR: nft $param4"
1918 logger -t "$packageName" "ERROR: nft $param6"
1919 elif [ -z "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ]; then
1920 processPolicyError='true'
1921 state add 'errorSummary' 'errorPolicyProcessInsertionFailedIpv4' "$name"
1922 state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param4"
1923 logger -t "$packageName" "ERROR: nft $param4"
1924 fi
1925 fi
1926 done
1927 }
1928
1929 policy_process() {
1930 local i j uid="$9"
1931 if [ -z "$uid" ]; then # first non-recursive call
1932 [ "$enabled" -gt 0 ] || return 0
1933 unset processPolicyError
1934 uid="$1"
1935 if is_nft_mode; then
1936 chain="$(str_to_lower "$chain")"
1937 else
1938 chain="$(str_to_upper "$chain")"
1939 fi
1940 proto="$(str_to_lower "$proto")"
1941 [ "$proto" = 'auto' ] && unset proto
1942 [ "$proto" = 'all' ] && unset proto
1943 output 2 "Routing '$name' via $interface "
1944 if [ -z "${src_addr}${src_port}${dest_addr}${dest_port}" ]; then
1945 state add 'errorSummary' 'errorPolicyNoSrcDest' "$name"
1946 output_fail; return 1;
1947 fi
1948 if [ -z "$interface" ]; then
1949 state add 'errorSummary' 'errorPolicyNoInterface' "$name"
1950 output_fail; return 1;
1951 fi
1952 if ! is_supported_interface "$interface"; then
1953 state add 'errorSummary' 'errorPolicyUnknownInterface' "$name"
1954 output_fail; return 1;
1955 fi
1956 src_port="${src_port// / }"; src_port="${src_port// /,}"; src_port="${src_port//,\!/ !}";
1957 dest_port="${dest_port// / }"; dest_port="${dest_port// /,}"; dest_port="${dest_port//,\!/ !}";
1958 policy_process "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"
1959 if [ -n "$processPolicyError" ]; then
1960 output_fail
1961 else
1962 output_ok
1963 fi
1964 else # recursive call, get options from passed variables
1965 local name="$1" interface="$2" src_addr="$3" src_port="$4" dest_addr="$5" dest_port="$6" proto="$7" chain="$8"
1966 if str_contains "$src_addr" '[ ;\{\}]'; then
1967 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
1968 elif str_contains "$src_port" '[ ;\{\}]'; then
1969 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
1970 elif str_contains "$dest_addr" '[ ;\{\}]'; then
1971 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
1972 elif str_contains "$dest_port" '[ ;\{\}]'; then
1973 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
1974 elif str_contains "$proto" '[ ;\{\}]'; then
1975 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
1976 else
1977 if [ -n "$secure_reload" ] && { is_url_dl "$src_addr" || is_url_dl "$dest_addr"; }; then
1978 state add 'errorSummary' 'errorNoDownloadWithSecureReload' "$name"
1979 elif is_url "$src_addr"; then
1980 src_addr="$(process_url "$src_addr")"
1981 [ -n "$src_addr" ] && policy_process "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"
1982 elif is_url "$dest_addr"; then
1983 dest_addr="$(process_url "$dest_addr")"
1984 [ -n "$dest_addr" ] && policy_process "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"
1985 else
1986 policy_routing "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid"
1987 fi
1988 fi
1989 fi
1990 }
1991
1992 try() {
1993 if ! "$@"; then
1994 state add 'errorSummary' 'errorTryFailed' "$*"
1995 return 1
1996 fi
1997 }
1998
1999 interface_routing() {
2000 local action="$1" tid="$2" mark="$3" iface="$4" gw4="$5" dev="$6" gw6="$7" dev6="$8" priority="$9"
2001 local dscp s=0 i ipv4_error=1 ipv6_error=1
2002 if [ -z "$tid" ] || [ -z "$mark" ] || [ -z "$iface" ]; then
2003 state add 'errorSummary' 'errorInterfaceRoutingEmptyValues'
2004 return 1
2005 fi
2006 case "$action" in
2007 create)
2008 if is_netifd_table_interface "$iface"; then
2009 ipv4_error=0
2010 $ip_bin -4 rule del table "$tid" >/dev/null 2>&1
2011 try "$ip_bin" -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
2012 if is_nft_mode; then
2013 try nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1
2014 try nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1
2015 try nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1
2016 else
2017 ipt -t mangle -N "${iptPrefix}_MARK_${mark}" || ipv4_error=1
2018 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j MARK --set-xmark "${mark}/${fw_mask}" || ipv4_error=1
2019 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j RETURN || ipv4_error=1
2020 fi
2021 if [ -n "$ipv6_enabled" ]; then
2022 ipv6_error=0
2023 $ip_bin -6 rule del table "$tid" >/dev/null 2>&1
2024 try "$ip_bin" -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$((priority-1))" || ipv6_error=1
2025 fi
2026 else
2027 if ! grep -q "$tid ${ipTablePrefix}_${iface}" "$rtTablesFile"; then
2028 sed -i "/${ipTablePrefix}_${iface}/d" "$rtTablesFile"
2029 sync
2030 echo "$tid ${ipTablePrefix}_${iface}" >> "$rtTablesFile"
2031 sync
2032 fi
2033 $ip_bin -4 rule del table "$tid" >/dev/null 2>&1
2034 $ip_bin -4 route flush table "$tid" >/dev/null 2>&1
2035 if [ -n "$gw4" ] || [ "$strict_enforcement" -ne 0 ]; then
2036 ipv4_error=0
2037 if [ -z "$gw4" ]; then
2038 try "$ip_bin" -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1
2039 else
2040 try "$ip_bin" -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1
2041 fi
2042 # shellcheck disable=SC2086
2043 while read -r i; do
2044 i="$(echo "$i" | sed 's/ linkdown$//')"
2045 i="$(echo "$i" | sed 's/ onlink$//')"
2046 idev="$(echo "$i" | grep -Eso 'dev [^ ]*' | awk '{print $2}')"
2047 if ! is_supported_iface_dev "$idev"; then
2048 try "$ip_bin" -4 route add $i table "$tid" >/dev/null 2>&1 || ipv4_error=1
2049 fi
2050 done << EOF
2051 $($ip_bin -4 route list table main)
2052 EOF
2053 try "$ip_bin" -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
2054 if is_nft_mode; then
2055 try nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1
2056 try nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1
2057 try nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1
2058 else
2059 ipt -t mangle -N "${iptPrefix}_MARK_${mark}" || ipv4_error=1
2060 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j MARK --set-xmark "${mark}/${fw_mask}" || ipv4_error=1
2061 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j RETURN || ipv4_error=1
2062 fi
2063 fi
2064 if [ -n "$ipv6_enabled" ]; then
2065 ipv6_error=0
2066 $ip_bin -6 rule del table "$tid" >/dev/null 2>&1
2067 $ip_bin -6 route flush table "$tid" >/dev/null 2>&1
2068 if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strict_enforcement" -ne 0 ]; then
2069 if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then
2070 try "$ip_bin" -6 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv6_error=1
2071 elif "$ip_bin" -6 route list table main | grep -q " dev $dev6 "; then
2072 "$ip_bin" -6 route add default via "$gw6" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
2073 while read -r i; do
2074 i="$(echo "$i" | sed 's/ linkdown$//')"
2075 i="$(echo "$i" | sed 's/ onlink$//')"
2076 # shellcheck disable=SC2086
2077 try "$ip_bin" -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1
2078 done << EOF
2079 $($ip_bin -6 route list table main | grep " dev $dev6 ")
2080 EOF
2081 else
2082 try "$ip_bin" -6 route add "$($ip_bin -6 -o a show "$dev6" | awk '{print $4}')" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
2083 try "$ip_bin" -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
2084 fi
2085 fi
2086 try "$ip_bin" -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$((priority-1))" >/dev/null 2>&1 || ipv6_error=1
2087 fi
2088 fi
2089 if [ "$ipv4_error" -eq 0 ] || [ "$ipv6_error" -eq 0 ]; then
2090 dscp="$(uci_get "$packageName" 'config' "${iface}_dscp")"
2091 if is_nft_mode; then
2092 if [ "${dscp:-0}" -ge 1 ] && [ "${dscp:-0}" -le 63 ]; then
2093 try nft add rule inet "$nftTable" "${nftPrefix}_prerouting ${nftIPv4Flag} dscp ${dscp} goto ${nftPrefix}_mark_${mark}" || s=1
2094 if [ -n "$ipv6_enabled" ]; then
2095 try nft add rule inet "$nftTable" "${nftPrefix}_prerouting ${nftIPv6Flag} dscp ${dscp} goto ${nftPrefix}_mark_${mark}" || s=1
2096 fi
2097 fi
2098 if [ "$iface" = "$icmp_interface" ]; then
2099 try nft add rule inet "$nftTable" "${nftPrefix}_output ${nftIPv4Flag} protocol icmp goto ${nftPrefix}_mark_${mark}" || s=1
2100 if [ -n "$ipv6_enabled" ]; then
2101 try nft add rule inet "$nftTable" "${nftPrefix}_output ${nftIPv6Flag} protocol icmp goto ${nftPrefix}_mark_${mark}" || s=1
2102 fi
2103 fi
2104 else
2105 if [ "${dscp:-0}" -ge 1 ] && [ "${dscp:-0}" -le 63 ]; then
2106 ipt -t mangle -I "${iptPrefix}_PREROUTING" -m dscp --dscp "${dscp}" -g "${iptPrefix}_MARK_${mark}" || s=1
2107 fi
2108 if [ "$iface" = "$icmp_interface" ]; then
2109 ipt -t mangle -I "${iptPrefix}_OUTPUT" -p icmp -g "${iptPrefix}_MARK_${mark}" || s=1
2110 fi
2111 fi
2112 else
2113 s=1
2114 fi
2115 return "$s"
2116 ;;
2117 create_user_set)
2118 if is_nft_mode; then
2119 nftset 'create_user_set' "$iface" 'dst' 'ip' 'user' '' "$mark" || s=1
2120 nftset 'create_user_set' "$iface" 'src' 'ip' 'user' '' "$mark" || s=1
2121 nftset 'create_user_set' "$iface" 'src' 'mac' 'user' '' "$mark" || s=1
2122 else
2123 ips 'create_user_set' "$iface" 'dst' 'ip' 'user' '' "$mark" || s=1
2124 ips 'create_user_set' "$iface" 'dst' 'net' 'user' '' "$mark" || s=1
2125 ips 'create_user_set' "$iface" 'src' 'ip' 'user' '' "$mark" || s=1
2126 ips 'create_user_set' "$iface" 'src' 'net' 'user' '' "$mark" || s=1
2127 ips 'create_user_set' "$iface" 'src' 'mac' 'user' '' "$mark" || s=1
2128 fi
2129 return "$s"
2130 ;;
2131 delete|destroy)
2132 $ip_bin rule del table "$tid" >/dev/null 2>&1
2133 if ! is_netifd_table_interface "$iface"; then
2134 $ip_bin route flush table "$tid" >/dev/null 2>&1
2135 sed -i "/${ipTablePrefix}_${iface}\$/d" "$rtTablesFile"
2136 sync
2137 fi
2138 return "$s"
2139 ;;
2140 reload_interface)
2141 is_netifd_table_interface "$iface" && return 0;
2142 ipv4_error=0
2143 $ip_bin rule del table "$tid" >/dev/null 2>&1
2144 if ! is_netifd_table_interface "$iface"; then
2145 $ip_bin route flush table "$tid" >/dev/null 2>&1
2146 fi
2147 if [ -n "$gw4" ] || [ "$strict_enforcement" -ne 0 ]; then
2148 if [ -z "$gw4" ]; then
2149 try "$ip_bin" -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1
2150 else
2151 try "$ip_bin" -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1
2152 fi
2153 try "$ip_bin" rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
2154 fi
2155 if [ -n "$ipv6_enabled" ]; then
2156 ipv6_error=0
2157 if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strict_enforcement" -ne 0 ]; then
2158 if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then
2159 try "$ip_bin" -6 route add unreachable default table "$tid" || ipv6_error=1
2160 elif $ip_bin -6 route list table main | grep -q " dev $dev6 "; then
2161 while read -r i; do
2162 # shellcheck disable=SC2086
2163 try "$ip_bin" -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1
2164 done << EOF
2165 $($ip_bin -6 route list table main | grep " dev $dev6 ")
2166 EOF
2167 else
2168 try "$ip_bin" -6 route add "$($ip_bin -6 -o a show "$dev6" | awk '{print $4}')" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
2169 try "$ip_bin" -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1
2170 fi
2171 fi
2172 try "$ip_bin" -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1
2173 fi
2174 if [ "$ipv4_error" -eq 0 ] || [ "$ipv6_error" -eq 0 ]; then
2175 s=0
2176 else
2177 s=1
2178 fi
2179 return "$s"
2180 ;;
2181 esac
2182 }
2183
2184 json_add_gateway() {
2185 local action="$1" tid="$2" mark="$3" iface="$4" gw4="$5" dev4="$6" gw6="$7" dev6="$8" priority="$9" default="${10}"
2186 json_add_object ''
2187 json_add_string 'name' "$iface"
2188 json_add_string 'device_ipv4' "$dev4"
2189 json_add_string 'gateway_ipv4' "$gw4"
2190 json_add_string 'device_ipv6' "$dev6"
2191 json_add_string 'gateway_ipv6' "$gw6"
2192 if [ -n "$default" ]; then
2193 json_add_boolean 'default' '1'
2194 else
2195 json_add_boolean 'default' '0'
2196 fi
2197 json_add_string 'action' "$action"
2198 json_add_string 'table_id' "$tid"
2199 json_add_string 'mark' "$mark"
2200 json_add_string 'priority' "$priority"
2201 json_close_object
2202 }
2203
2204 interface_process() {
2205 local gw4 gw6 dev dev6 s=0 dscp iface="$1" action="$2" reloadedIface="$3"
2206 local displayText dispDev dispGw4 dispGw6 dispStatus
2207
2208 if [ "$iface" = 'all' ] && [ "$action" = 'prepare' ]; then
2209 config_load 'network'
2210 ifaceMark="$(printf '0x%06x' "$wan_mark")"
2211 ifacePriority="$wan_ip_rules_priority"
2212 unset ifaceTableID
2213 return 0
2214 fi
2215
2216 if [ "$iface" = 'tor' ]; then
2217 case "$action" in
2218 create|reload)
2219 torDnsPort="$(get_tor_dns_port)"
2220 torTrafficPort="$(get_tor_traffic_port)"
2221 displayText="${iface}/53->${torDnsPort}/80,443->${torTrafficPort}"
2222 gatewaySummary="${gatewaySummary}${displayText}\\n"
2223 ;;
2224 destroy)
2225 ;;
2226 esac
2227 return 0
2228 fi
2229
2230 is_supported_interface "$iface" || return 0
2231 is_wan6 "$iface" && return 0
2232 [ $((ifaceMark)) -gt $((fw_mask)) ] && return 1
2233
2234 if is_ovpn "$iface" && ! is_ovpn_valid "$iface"; then
2235 : || state add 'warningSummary' 'warningInvalidOVPNConfig' "$iface"
2236 fi
2237
2238 network_get_device dev "$iface"
2239 [ -z "$dev" ] && network_get_physdev dev "$iface"
2240 if is_wan "$iface" && [ -n "$wanIface6" ] && str_contains "$wanIface6" "$iface"; then
2241 network_get_device dev6 "$wanIface6"
2242 [ -z "$dev6" ] && network_get_physdev dev6 "$wanIface6"
2243 fi
2244
2245 [ -z "$dev6" ] && dev6="$dev"
2246 [ -z "$ifaceMark" ] && ifaceMark="$(printf '0x%06x' "$wan_mark")"
2247 [ -z "$ifacePriority" ] && ifacePriority="$wan_ip_rules_priority"
2248
2249 case "$action" in
2250 pre_init)
2251 [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_non_pbr_next_id)"
2252 eval "pre_init_mark_${iface//-/_}"='$ifaceMark'
2253 eval "pre_init_priority_${iface//-/_}"='$ifacePriority'
2254 eval "pre_init_tid_${iface//-/_}"='$ifaceTableID'
2255 ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))"
2256 ifacePriority="$((ifacePriority - 1))"
2257 ifaceTableID="$((ifaceTableID + 1))"
2258 return 0
2259 ;;
2260 create)
2261 ifaceTableID="$(get_rt_tables_id "$iface")"
2262 [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)"
2263 eval "mark_${iface//-/_}"='$ifaceMark'
2264 eval "tid_${iface//-/_}"='$ifaceTableID'
2265 pbr_get_gateway4 gw4 "$iface" "$dev"
2266 pbr_get_gateway6 gw6 "$iface" "$dev6"
2267 dispGw4="${gw4:-0.0.0.0}"
2268 dispGw6="${gw6:-::/0}"
2269 [ "$iface" != "$dev" ] && dispDev="$dev"
2270 if is_default_dev "$dev"; then
2271 [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__"
2272 fi
2273 displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}"
2274 output 2 "Setting up routing for '$displayText' "
2275 if interface_routing 'create' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"; then
2276 json_add_gateway 'create' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" "$dispStatus"
2277 gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n"
2278 if is_netifd_table_interface "$iface"; then output_okb; else output_ok; fi
2279 else
2280 state add 'errorSummary' 'errorFailedSetup' "$displayText"
2281 output_fail
2282 fi
2283 ;;
2284 create_user_set)
2285 ifaceTableID="$(get_rt_tables_id "$iface")"
2286 [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)"
2287 eval "mark_${iface//-/_}"='$ifaceMark'
2288 eval "tid_${iface//-/_}"='$ifaceTableID'
2289 pbr_get_gateway4 gw4 "$iface" "$dev"
2290 pbr_get_gateway6 gw6 "$iface" "$dev6"
2291 dispGw4="${gw4:-0.0.0.0}"
2292 dispGw6="${gw6:-::/0}"
2293 [ "$iface" != "$dev" ] && dispDev="$dev"
2294 if is_default_dev "$dev"; then
2295 [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__"
2296 fi
2297 displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}"
2298 interface_routing 'create_user_set' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"
2299 ;;
2300 destroy)
2301 ifaceTableID="$(get_rt_tables_id "$iface")"
2302 [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)"
2303 eval "mark_${iface//-/_}"='$ifaceMark'
2304 eval "tid_${iface//-/_}"='$ifaceTableID'
2305 pbr_get_gateway4 gw4 "$iface" "$dev"
2306 pbr_get_gateway6 gw6 "$iface" "$dev6"
2307 dispGw4="${gw4:-0.0.0.0}"
2308 dispGw6="${gw6:-::/0}"
2309 [ "$iface" != "$dev" ] && dispDev="$dev"
2310 if is_default_dev "$dev"; then
2311 [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__"
2312 fi
2313 displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}"
2314 displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}"
2315 output 2 "Removing routing for '$displayText' "
2316 interface_routing 'destroy' "${ifaceTableID}" "${ifaceMark}" "${iface}"
2317 if is_netifd_table_interface "$iface"; then output_okb; else output_ok; fi
2318 ;;
2319 reload)
2320 ifaceTableID="$(get_rt_tables_id "$iface")"
2321 [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)"
2322 eval "mark_${iface//-/_}"='$ifaceMark'
2323 eval "tid_${iface//-/_}"='$ifaceTableID'
2324 pbr_get_gateway4 gw4 "$iface" "$dev"
2325 pbr_get_gateway6 gw6 "$iface" "$dev6"
2326 dispGw4="${gw4:-0.0.0.0}"
2327 dispGw6="${gw6:-::/0}"
2328 [ "$iface" != "$dev" ] && dispDev="$dev"
2329 if is_default_dev "$dev"; then
2330 [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__"
2331 fi
2332 displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}"
2333 gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n"
2334 ;;
2335 reload_interface)
2336 ifaceTableID="$(get_rt_tables_id "$iface")"
2337 [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)"
2338 eval "mark_${iface//-/_}"='$ifaceMark'
2339 eval "tid_${iface//-/_}"='$ifaceTableID'
2340 pbr_get_gateway4 gw4 "$iface" "$dev"
2341 pbr_get_gateway6 gw6 "$iface" "$dev6"
2342 dispGw4="${gw4:-0.0.0.0}"
2343 dispGw6="${gw6:-::/0}"
2344 [ "$iface" != "$dev" ] && dispDev="$dev"
2345 if is_default_dev "$dev"; then
2346 [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__"
2347 fi
2348 displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}"
2349 if [ "$iface" = "$reloadedIface" ]; then
2350 output 2 "Reloading routing for '$displayText' "
2351 if interface_routing 'reload_interface' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"; then
2352 json_add_gateway 'reload_interface' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" "$dispStatus"
2353 gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n"
2354 if is_netifd_table_interface "$iface"; then output_okb; else output_ok; fi
2355 else
2356 state add 'errorSummary' 'errorFailedReload' "$displayText"
2357 output_fail
2358 fi
2359 else
2360 gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n"
2361 fi
2362 ;;
2363 esac
2364 # ifaceTableID="$((ifaceTableID + 1))"
2365 ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))"
2366 ifacePriority="$((ifacePriority - 2))"
2367 return $s
2368 }
2369
2370 user_file_process() {
2371 local shellBin="${SHELL:-/bin/ash}"
2372 [ "$enabled" -gt 0 ] || return 0
2373 if [ ! -s "$path" ]; then
2374 state add 'errorSummary' 'errorUserFileNotFound' "$path"
2375 output_fail
2376 return 1
2377 fi
2378 if ! $shellBin -n "$path"; then
2379 state add 'errorSummary' 'errorUserFileSyntax' "$path"
2380 output_fail
2381 return 1
2382 fi
2383 output 2 "Running $path "
2384 # shellcheck disable=SC1090
2385 if ! . "$path"; then
2386 state add 'errorSummary' 'errorUserFileRunning' "$path"
2387 if grep -q -w 'curl' "$path" && ! is_present 'curl'; then
2388 state add 'errorSummary' 'errorUserFileNoCurl' "$path"
2389 fi
2390 output_fail
2391 return 1
2392 else
2393 output_ok
2394 return 0
2395 fi
2396 }
2397
2398 boot() {
2399 local procd_boot_delay
2400 config_load "$packageName"
2401 config_get procd_boot_delay 'config' 'procd_boot_delay' '0'
2402 nft_file 'delete'
2403 ubus -t 30 wait_for network.interface 2>/dev/null
2404 { is_integer "$procd_boot_delay" && sleep "$procd_boot_delay"; \
2405 rc_procd start_service 'on_boot' && service_started 'on_boot'; } &
2406 }
2407
2408 on_firewall_reload() {
2409 if [ ! -e "$packageLockFile" ]; then
2410 logger -t "$packageName" "Reload on firewall action aborted: service is stopped."
2411 return 0
2412 else
2413 if nft_file 'exists'; then
2414 logger -t "$packageName" "Reusing the fw4 nft file."
2415 else
2416 rc_procd start_service 'on_firewall_reload' "$1"
2417 fi
2418 fi
2419 }
2420
2421 on_interface_reload() {
2422 if [ ! -e "$packageLockFile" ]; then
2423 logger -t "$packageName" "Reload on interface change aborted: service is stopped."
2424 return 0
2425 else
2426 rc_procd start_service 'on_interface_reload' "$1"
2427 fi
2428 }
2429
2430 start_service() {
2431 local resolverStoredHash resolverNewHash i param="$1" reloadedIface
2432
2433 load_environment "${param:-on_start}" "$(load_validate_config)" || return 1
2434 is_wan_up "$param" || return 1
2435
2436 interface_process 'all' 'prepare'
2437 config_foreach interface_process 'interface' 'pre_init'
2438
2439 case "$param" in
2440 on_boot)
2441 serviceStartTrigger='on_start'
2442 ;;
2443 on_firewall_reload)
2444 serviceStartTrigger='on_start'
2445 ;;
2446 on_interface_reload)
2447 reloadedIface="$2"
2448 local tid pre_init_tid
2449 tid="$(get_rt_tables_id "$reloadedIface")"
2450 pre_init_tid="$(eval echo "\$pre_init_tid_${reloadedIface//-/_}")"
2451 if [ "$tid" = "$pre_init_tid" ]; then
2452 # logger -t "$packageName" "Updated interface $reloadedIface TID: ${tid}; Pre-Init TID: ${pre_init_tid}. Reloading..."
2453 serviceStartTrigger='on_interface_reload'
2454 else
2455 # logger -t "$packageName" "Updated interface $reloadedIface TID: ${tid}; Pre-Init TID: ${pre_init_tid}. Restarting..."
2456 serviceStartTrigger='on_start'
2457 unset reloadedIface
2458 fi
2459 # if is_ovpn "$reloadedIface"; then
2460 # logger -t "$packageName" "Updated interface is an OpenVPN tunnel, restarting."
2461 # serviceStartTrigger='on_start'
2462 # unset reloadedIface
2463 # else
2464 # serviceStartTrigger='on_interface_reload'
2465 # fi
2466 ;;
2467 on_reload)
2468 serviceStartTrigger='on_reload'
2469 ;;
2470 on_restart)
2471 serviceStartTrigger='on_start'
2472 ;;
2473 esac
2474
2475 if [ -n "$reloadedIface" ] && ! is_supported_interface "$reloadedIface"; then
2476 return 0
2477 fi
2478
2479 if [ -n "$(ubus_get_status error)" ] || [ -n "$(ubus_get_status warning)" ]; then
2480 serviceStartTrigger='on_start'
2481 unset reloadedIface
2482 elif ! is_service_running; then
2483 serviceStartTrigger='on_start'
2484 unset reloadedIface
2485 elif [ -z "$(ubus_get_status gateways)" ]; then
2486 serviceStartTrigger='on_start'
2487 unset reloadedIface
2488 # elif [ "$serviceStartTrigger" = 'on_interface_reload' ] && \
2489 # [ -z "$(ubus_get_interface "$reloadedIface" 'gateway_ipv4')" ] && \
2490 # [ -z "$(ubus_get_interface "$reloadedIface" 'gateway_ipv6')" ]; then
2491 # serviceStartTrigger='on_start'
2492 # unset reloadedIface
2493 else
2494 serviceStartTrigger="${serviceStartTrigger:-on_start}"
2495 fi
2496
2497 procd_open_instance 'main'
2498 procd_set_param command /bin/true
2499 procd_set_param stdout 1
2500 procd_set_param stderr 1
2501 procd_open_data
2502
2503 case $serviceStartTrigger in
2504 on_interface_reload)
2505 output 1 "Reloading Interface: $reloadedIface "
2506 json_add_array 'gateways'
2507 interface_process 'all' 'prepare'
2508 config_foreach interface_process 'interface' 'reload_interface' "$reloadedIface"
2509 json_close_array
2510 output 1 '\n'
2511 ;;
2512 on_reload)
2513 traffic_killswitch 'insert'
2514 resolver 'store_hash'
2515 resolver 'cleanup_all'
2516 resolver 'configure'
2517 resolver 'init'
2518 cleanup_main_chains
2519 cleanup_sets
2520 nft_file 'create'
2521 if ! is_nft_mode; then
2522 for i in $chainsList; do
2523 i="$(str_to_upper "$i")"
2524 ipt -t mangle -N "${iptPrefix}_${i}"
2525 ipt -t mangle "$rule_create_option" "$i" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}"
2526 done
2527 fi
2528 json_add_array 'gateways'
2529 interface_process 'all' 'prepare'
2530 config_foreach interface_process 'interface' 'reload'
2531 interface_process 'tor' 'destroy'
2532 is_tor_running && interface_process 'tor' 'reload'
2533 json_close_array
2534 if is_config_enabled 'policy'; then
2535 output 1 'Processing policies '
2536 config_load "$packageName"
2537 config_foreach load_validate_policy 'policy' policy_process
2538 output 1 '\n'
2539 fi
2540 if is_config_enabled 'include'; then
2541 interface_process 'all' 'prepare'
2542 config_foreach interface_process 'interface' 'create_user_set'
2543 output 1 'Processing user file(s) '
2544 config_load "$packageName"
2545 config_foreach load_validate_include 'include' user_file_process
2546 output 1 '\n'
2547 fi
2548 nft_file 'install'
2549 resolver 'init_end'
2550 ! nft_file 'exists' && resolver 'compare_hash' && resolver 'restart'
2551 traffic_killswitch 'remove'
2552 ;;
2553 on_start|*)
2554 traffic_killswitch 'insert'
2555 resolver 'store_hash'
2556 resolver 'cleanup_all'
2557 resolver 'configure'
2558 resolver 'init'
2559 cleanup_main_chains
2560 cleanup_sets
2561 cleanup_marking_chains
2562 cleanup_rt_tables
2563 nft_file 'create'
2564 if ! is_nft_mode; then
2565 for i in $chainsList; do
2566 i="$(str_to_upper "$i")"
2567 ipt -t mangle -N "${iptPrefix}_${i}"
2568 ipt -t mangle "$rule_create_option" "$i" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}"
2569 done
2570 fi
2571 output 1 'Processing interfaces '
2572 json_add_array 'gateways'
2573 interface_process 'all' 'prepare'
2574 config_foreach interface_process 'interface' 'create'
2575 interface_process 'tor' 'destroy'
2576 is_tor_running && interface_process 'tor' 'create'
2577 json_close_array
2578 ip route flush cache
2579 output 1 '\n'
2580 if is_config_enabled 'policy'; then
2581 output 1 'Processing policies '
2582 config_load "$packageName"
2583 config_foreach load_validate_policy 'policy' policy_process
2584 output 1 '\n'
2585 fi
2586 if is_config_enabled 'include'; then
2587 interface_process 'all' 'prepare'
2588 config_foreach interface_process 'interface' 'create_user_set'
2589 output 1 'Processing user file(s) '
2590 config_load "$packageName"
2591 config_foreach load_validate_include 'include' user_file_process
2592 output 1 '\n'
2593 fi
2594 nft_file 'install'
2595 resolver 'init_end'
2596 ! nft_file 'exists' && resolver 'compare_hash' && resolver 'restart'
2597 traffic_killswitch 'remove'
2598 ;;
2599 esac
2600
2601 if [ -z "$gatewaySummary" ]; then
2602 state add 'errorSummary' 'errorNoGateways'
2603 fi
2604 json_add_object 'status'
2605 [ -n "$gatewaySummary" ] && json_add_string 'gateways' "$gatewaySummary"
2606 [ -n "$errorSummary" ] && json_add_string 'errors' "$errorSummary"
2607 [ -n "$warningSummary" ] && json_add_string 'warnings' "$warningSummary"
2608 if [ "$strict_enforcement" -ne 0 ] && str_contains "$gatewaySummary" '0.0.0.0'; then
2609 json_add_string 'mode' 'strict'
2610 fi
2611 json_close_object
2612 procd_close_data
2613 procd_close_instance
2614 }
2615
2616 service_started() {
2617 if nft_file 'exists'; then
2618 procd_set_config_changed firewall
2619 if nft_file 'exists'; then
2620 resolver 'compare_hash' && resolver 'restart'
2621 [ -n "$gatewaySummary" ] && output "$serviceName (fw4 nft file mode) started with gateways:\\n${gatewaySummary}"
2622 else
2623 output "$serviceName FAILED TO START in fw4 nft file mode!!!"
2624 output "Check the output of nft -c -f $nftTempFile"
2625 fi
2626 elif is_nft_mode; then
2627 [ -n "$gatewaySummary" ] && output "$serviceName (nft mode) started with gateways:\\n${gatewaySummary}"
2628 else
2629 [ -n "$gatewaySummary" ] && output "$serviceName (iptables mode) started with gateways:\\n${gatewaySummary}"
2630 fi
2631 state print 'errorSummary'
2632 state print 'warningSummary'
2633 touch "$packageLockFile"
2634 if [ -n "$errorSummary" ]; then
2635 return 2
2636 elif [ -n "$warningSummary" ]; then
2637 return 1
2638 else
2639 return 0
2640 fi
2641 }
2642
2643 service_triggers() {
2644 local n
2645 load_environment 'on_triggers'
2646 # shellcheck disable=SC2034
2647 PROCD_RELOAD_DELAY=$(( procd_reload_delay * 1000 ))
2648 procd_open_validate
2649 load_validate_config
2650 load_validate_policy
2651 load_validate_include
2652 procd_close_validate
2653 procd_open_trigger
2654 procd_add_config_trigger "config.change" 'openvpn' "/etc/init.d/${packageName}" reload 'on_openvpn_change'
2655 procd_add_config_trigger "config.change" "${packageName}" /etc/init.d/${packageName} reload
2656 for n in $ifacesSupported; do
2657 procd_add_interface_trigger "interface.*" "$n" /etc/init.d/${packageName} on_interface_reload "$n"
2658 done
2659 procd_close_trigger
2660 # procd_add_raw_trigger "interface.*.up" 4000 "/etc/init.d/${packageName}" restart 'on_interface_up'
2661 if [ "$serviceStartTrigger" = 'on_start' ]; then
2662 output 3 "$serviceName monitoring interfaces: ${ifacesSupported}\\n"
2663 fi
2664 }
2665
2666 stop_service() {
2667 local i nft_file_mode
2668 load_environment 'on_stop'
2669 ! is_service_running && [ "$(get_rt_tables_next_id)" = "$(get_rt_tables_non_pbr_next_id)" ] && return 0
2670 [ "$1" = 'quiet' ] && quiet_mode 'on'
2671 traffic_killswitch 'insert'
2672 if nft_file 'exists'; then
2673 nft_file_mode=1
2674 fi
2675 nft_file 'delete'
2676 cleanup_main_chains
2677 cleanup_sets
2678 cleanup_marking_chains
2679 output 1 'Resetting interfaces '
2680 config_load 'network'
2681 config_foreach interface_process 'interface' 'destroy'
2682 interface_process 'tor' 'destroy'
2683 cleanup_rt_tables
2684 output 1 "\\n"
2685 ip route flush cache
2686 unset ifaceMark
2687 unset ifaceTableID
2688 resolver 'store_hash'
2689 resolver 'cleanup_all'
2690 resolver 'compare_hash' && resolver 'restart'
2691 traffic_killswitch 'remove'
2692 if [ "$enabled" -ne 0 ]; then
2693 if [ -n "$nft_file_mode" ]; then
2694 output "$serviceName (fw4 nft file mode) stopped "; output_okn;
2695 elif is_nft_mode; then
2696 output "$serviceName (nft mode) stopped "; output_okn;
2697 else
2698 output "$serviceName (iptables mode) stopped "; output_okn;
2699 fi
2700 fi
2701 rm -f "$packageLockFile"
2702 }
2703
2704 version() { echo "$PKG_VERSION"; }
2705
2706 status_service() {
2707 local _SEPARATOR_='============================================================'
2708 load_environment 'on_status'
2709 if is_nft_mode; then
2710 status_service_nft "$@"
2711 else
2712 status_service_iptables "$@"
2713 fi
2714 }
2715
2716 status_service_nft() {
2717 local i dev dev6 wan_tid
2718
2719 json_load "$(ubus call system board)"; json_select release; json_get_var dist distribution; json_get_var vers version
2720 if [ -n "$wanIface4" ]; then
2721 network_get_gateway wanGW4 "$wanIface4"
2722 network_get_device dev "$wanIface4"
2723 fi
2724 if [ -n "$wanIface6" ]; then
2725 network_get_device dev6 "$wanIface6"
2726 wanGW6=$($ip_bin -6 route show | grep -m1 " dev $dev6 " | awk '{print $1}')
2727 [ "$wanGW6" = "default" ] && wanGW6=$($ip_bin -6 route show | grep -m1 " dev $dev6 " | awk '{print $3}')
2728 fi
2729 while [ "${1:0:1}" = "-" ]; do param="${1//-/}"; eval "set_$param=1"; shift; done
2730 [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support"
2731 status="$serviceName running on $dist $vers."
2732 [ -n "$wanIface4" ] && status="$status WAN (IPv4): ${wanIface4}/${dev}/${wanGW4:-0.0.0.0}."
2733 [ -n "$wanIface6" ] && status="$status WAN (IPv6): ${wanIface6}/${dev6}/${wanGW6:-::/0}."
2734
2735 echo "$_SEPARATOR_"
2736 echo "$packageName - environment"
2737 echo "$status"
2738 echo "$_SEPARATOR_"
2739 dnsmasq --version 2>/dev/null | sed '/^$/,$d'
2740 if nft_file 'exists'; then
2741 echo "$_SEPARATOR_"
2742 echo "$packageName fw4 nft file: $nftPermFile"
2743 sed '1d;2d;' "$nftPermFile"
2744 fi
2745 echo "$_SEPARATOR_"
2746 echo "$packageName chains - policies"
2747 for i in forward input output prerouting postrouting; do
2748 "$nft" -a list table inet "$nftTable" | sed -n "/chain ${nftPrefix}_${i} {/,/\t}/p"
2749 done
2750 echo "$_SEPARATOR_"
2751 echo "$packageName chains - marking"
2752 for i in $(get_mark_nft_chains); do
2753 "$nft" -a list table inet "$nftTable" | sed -n "/chain ${i} {/,/\t}/p"
2754 done
2755 echo "$_SEPARATOR_"
2756 echo "$packageName nft sets"
2757 for i in $(get_nft_sets); do
2758 "$nft" -a list table inet "$nftTable" | sed -n "/set ${i} {/,/\t}/p"
2759 done
2760 if [ -s "$dnsmasqFile" ]; then
2761 echo "$_SEPARATOR_"
2762 echo "dnsmasq sets"
2763 cat "$dnsmasqFile"
2764 fi
2765 # echo "$_SEPARATOR_"
2766 # ip rule list | grep "${packageName}_"
2767 echo "$_SEPARATOR_"
2768 tableCount="$(grep -c "${packageName}_" $rtTablesFile)" || tableCount=0
2769 wan_tid=$(($(get_rt_tables_next_id)-tableCount))
2770 i=0; while [ $i -lt "$tableCount" ]; do
2771 echo "IPv4 table $((wan_tid + i)) route: $($ip_bin -4 route show table $((wan_tid + i)) | grep default)"
2772 echo "IPv4 table $((wan_tid + i)) rule(s):"
2773 $ip_bin -4 rule list table "$((wan_tid + i))"
2774 if [ -n "$ipv6_enabled" ]; then
2775 echo "IPv6 table $((wan_tid + i)) route: $($ip_bin -6 route show table $((wan_tid + i)) | grep default)"
2776 echo "IPv6 table $((wan_tid + i)) rule(s):"
2777 $ip_bin -6 route show table $((wan_tid + i))
2778 fi
2779 i=$((i + 1))
2780 done
2781 }
2782
2783 status_service_iptables() {
2784 local dist vers out id s param status set_d set_p tableCount i=0 dev dev6 j wan_tid
2785
2786 json_load "$(ubus call system board)"; json_select release; json_get_var dist distribution; json_get_var vers version
2787 if [ -n "$wanIface4" ]; then
2788 network_get_gateway wanGW4 "$wanIface4"
2789 network_get_device dev "$wanIface4"
2790 fi
2791 if [ -n "$wanIface6" ]; then
2792 network_get_device dev6 "$wanIface6"
2793 wanGW6=$($ip_bin -6 route show | grep -m1 " dev $dev6 " | awk '{print $1}')
2794 [ "$wanGW6" = "default" ] && wanGW6=$($ip_bin -6 route show | grep -m1 " dev $dev6 " | awk '{print $3}')
2795 fi
2796 while [ "${1:0:1}" = "-" ]; do param="${1//-/}"; eval "set_$param=1"; shift; done
2797 [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support"
2798 status="$serviceName running on $dist $vers."
2799 [ -n "$wanIface4" ] && status="$status WAN (IPv4): ${wanIface4}/${dev}/${wanGW4:-0.0.0.0}."
2800 [ -n "$wanIface6" ] && status="$status WAN (IPv6): ${wanIface6}/${dev6}/${wanGW6:-::/0}."
2801 {
2802 echo "$status"
2803 echo "$_SEPARATOR_"
2804 dnsmasq --version 2>/dev/null | sed '/^$/,$d'
2805 if [ -n "$1" ]; then
2806 echo "$_SEPARATOR_"
2807 echo "Resolving domains"
2808 for i in $1; do
2809 echo "$i: $(resolveip "$i" | tr '\n' ' ')"
2810 done
2811 fi
2812
2813 echo "$_SEPARATOR_"
2814 echo "Routes/IP Rules"
2815 tableCount="$(grep -c "${packageName}_" $rtTablesFile)" || tableCount=0
2816 if [ -n "$set_d" ]; then route; else route | grep '^default'; fi
2817 if [ -n "$set_d" ]; then ip rule list; fi
2818 wan_tid=$(($(get_rt_tables_next_id)-tableCount))
2819 i=0; while [ $i -lt "$tableCount" ]; do
2820 echo "IPv4 table $((wan_tid + i)) route: $($ip_bin -4 route show table $((wan_tid + i)) | grep default)"
2821 echo "IPv4 table $((wan_tid + i)) rule(s):"
2822 $ip_bin -4 rule list table "$((wan_tid + i))"
2823 i=$((i + 1))
2824 done
2825
2826 if [ -n "$ipv6_enabled" ]; then
2827 i=0; while [ $i -lt "$tableCount" ]; do
2828 $ip_bin -6 route show table $((wan_tid + i)) | while read -r param; do
2829 echo "IPv6 Table $((wan_tid + i)): $param"
2830 done
2831 i=$((i + 1))
2832 done
2833 fi
2834
2835 for j in Mangle NAT; do
2836 if [ -z "$set_d" ]; then
2837 for i in $chainsList; do
2838 i="$(str_to_upper "$i")"
2839 if iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}" >/dev/null 2>&1; then
2840 echo "$_SEPARATOR_"
2841 echo "$j IP Table: $i"
2842 iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}"
2843 if [ -n "$ipv6_enabled" ]; then
2844 echo "$_SEPARATOR_"
2845 echo "$j IPv6 Table: $i"
2846 iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}"
2847 fi
2848 fi
2849 done
2850 else
2851 echo "$_SEPARATOR_"
2852 echo "$j IP Table"
2853 iptables -L -t "$(str_to_lower $j)"
2854 if [ -n "$ipv6_enabled" ]; then
2855 echo "$_SEPARATOR_"
2856 echo "$j IPv6 Table"
2857 iptables -L -t "$(str_to_lower $j)"
2858 fi
2859 fi
2860 i=0; ifaceMark="$wan_mark";
2861 while [ $i -lt "$tableCount" ]; do
2862 if iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_MARK_${ifaceMark}" >/dev/null 2>&1; then
2863 echo "$_SEPARATOR_"
2864 echo "$j IP Table MARK Chain: ${iptPrefix}_MARK_${ifaceMark}"
2865 iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_MARK_${ifaceMark}"
2866 ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))";
2867 fi
2868 i=$((i + 1))
2869 done
2870 done
2871
2872 echo "$_SEPARATOR_"
2873 echo "Current ipsets"
2874 ipset save
2875 if [ -s "$dnsmasqFile" ]; then
2876 echo "$_SEPARATOR_"
2877 echo "DNSMASQ sets"
2878 cat "$dnsmasqFile"
2879 fi
2880 if [ -s "$aghIpsetFile" ]; then
2881 echo "$_SEPARATOR_"
2882 echo "AdGuardHome sets"
2883 cat "$aghIpsetFile"
2884 fi
2885 echo "$_SEPARATOR_"
2886 } | tee -a /var/${packageName}-support
2887 if [ -n "$set_p" ]; then
2888 printf "%b" "Pasting to paste.ee... "
2889 if curl --version 2>/dev/null | grep -q "Protocols: .*https.*"; then
2890 json_init; json_add_string 'description' "${packageName}-support"
2891 json_add_array 'sections'; json_add_object '0'
2892 json_add_string 'name' "$(uci_get 'system' '@system[0]' 'hostname')"
2893 json_add_string 'contents' "$(cat /var/${packageName}-support)"
2894 json_close_object; json_close_array; payload=$(json_dump)
2895 out=$(curl -s -k "https://api.paste.ee/v1/pastes" -X "POST" -H "Content-Type: application/json" -H "X-Auth-Token:uVOJt6pNqjcEWu7qiuUuuxWQafpHhwMvNEBviRV2B" -d "$payload")
2896 json_load "$out"; json_get_var id id; json_get_var s success
2897 [ "$s" = "1" ] && printf "%b" "https://paste.ee/p/$id $__OK__\\n" || printf "%b" "$__FAIL__\\n"
2898 [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support"
2899 else
2900 printf "%b" "${__FAIL__}\\n"
2901 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"
2902 fi
2903 else
2904 printf "%b" "Your support details have been logged to '/var/${packageName}-support'. $__OK__\\n"
2905 fi
2906 }
2907
2908 # shellcheck disable=SC2120
2909 load_validate_config() {
2910 uci_load_validate "$packageName" "$packageName" "$1" "${2}${3:+ $3}" \
2911 'enabled:bool:0' \
2912 'strict_enforcement:bool:1' \
2913 'secure_reload:bool:0' \
2914 'ipv6_enabled:bool:0' \
2915 'resolver_set:or("", "none", "dnsmasq.ipset", "dnsmasq.nftset")' \
2916 'resolver_instance:list(or(integer, string)):*' \
2917 'verbosity:range(0,2):2' \
2918 'wan_mark:regex("[A-Fa-f0-9]{8}"):010000' \
2919 'fw_mask:regex("[A-Fa-f0-9]{8}"):ff0000' \
2920 'icmp_interface:or("", tor, uci("network", "@interface"))' \
2921 'ignored_interface:list(or(tor, uci("network", "@interface")))' \
2922 'supported_interface:list(or(ignore, tor, regex("xray_.*"), uci("network", "@interface")))' \
2923 'procd_boot_delay:integer:0' \
2924 'procd_boot_timeout:integer:30' \
2925 'procd_lan_interface:string' \
2926 'procd_reload_delay:integer:0' \
2927 'procd_wan_ignore_status:bool:0' \
2928 'procd_wan_interface:network:wan' \
2929 'procd_wan6_interface:network:wan6' \
2930 'wan_ip_rules_priority:uinteger:30000' \
2931 'rule_create_option:or("", add, insert):add' \
2932 'webui_supported_protocol:list(string)' \
2933 'nft_file_support:bool:1'\
2934 'nft_set_auto_merge:bool:1'\
2935 'nft_set_counter:bool:1'\
2936 'nft_set_flags_interval:bool:1'\
2937 'nft_set_flags_timeout:bool:0'\
2938 'nft_set_gc_interval:or("", string)'\
2939 'nft_set_policy:or("", memory, performance):performance'\
2940 'nft_set_timeout:or("", string)'
2941 }
2942
2943 # shellcheck disable=SC2120
2944 load_validate_policy() {
2945 local name
2946 local enabled
2947 local interface
2948 local proto
2949 local chain
2950 local src_addr
2951 local src_port
2952 local dest_addr
2953 local dest_port
2954 uci_load_validate "$packageName" 'policy' "$1" "${2}${3:+ $3}" \
2955 'name:string:Untitled' \
2956 'enabled:bool:1' \
2957 'interface:or("ignore", "tor", regex("xray_.*"), uci("network", "@interface")):wan' \
2958 'proto:or(string)' \
2959 'chain:or("", "forward", "input", "output", "prerouting", "postrouting", "FORWARD", "INPUT", "OUTPUT", "PREROUTING", "POSTROUTING"):prerouting' \
2960 'src_addr:list(neg(or(host,network,macaddr,string)))' \
2961 'src_port:list(neg(or(portrange,string)))' \
2962 'dest_addr:list(neg(or(host,network,string)))' \
2963 'dest_port:list(neg(or(portrange,string)))'
2964 }
2965
2966 # shellcheck disable=SC2120
2967 load_validate_include() {
2968 local path=
2969 local enabled=
2970 uci_load_validate "$packageName" 'include' "$1" "${2}${3:+ $3}" \
2971 'path:file' \
2972 'enabled:bool:0'
2973 }