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