From bb5de23743b46864ba6992ed130b2d2452df72db Mon Sep 17 00:00:00 2001 From: Stan Grishin Date: Thu, 11 Apr 2024 16:21:28 +0000 Subject: [PATCH] pbr: update to 1.1.4-r15 * delete obsolete files/etc/init.d/pbr.init * add files/etc/uci-defaults/91-pbr-iptables to help update from older OpenWrt * add files/etc/uci-defaults/91-pbr-nft to help update from older OpenWrt * update files/etc/uci-defaults/91-pbr-netifd to only add tables to supported ifaces * re-organize variants in the Makefile so that they hopefull work this time * update prerm for all variants for better user experience * update the -netifd prerm to remove leftofver entries from network and rt_tables file In the init script: * add decorations for netifd-interfaces related operations (blue ticks) * add rtTablesFile variables instead of hard-coding the rt_tables file * add function to check if the table is netifd-derived * add error messages/hints for failed interface setup and failed WAN discovery * make cleanup_rt_tables the netifd-compatible * streamline interface_process function with a clearer case statement * rename the interface_process `pre-init` option to `pre_init` to conform to the other functions options naming style Signed-off-by: Stan Grishin --- net/pbr/Makefile | 77 +- net/pbr/files/etc/init.d/pbr | 236 +- net/pbr/files/etc/init.d/pbr.init | 2528 ----------------- .../files/etc/uci-defaults/91-pbr-iptables | 27 + net/pbr/files/etc/uci-defaults/91-pbr-netifd | 38 + net/pbr/files/etc/uci-defaults/91-pbr-nft | 30 + 6 files changed, 300 insertions(+), 2636 deletions(-) delete mode 100755 net/pbr/files/etc/init.d/pbr.init create mode 100644 net/pbr/files/etc/uci-defaults/91-pbr-iptables create mode 100644 net/pbr/files/etc/uci-defaults/91-pbr-netifd create mode 100644 net/pbr/files/etc/uci-defaults/91-pbr-nft diff --git a/net/pbr/Makefile b/net/pbr/Makefile index ddc8537a7e..bbf588b489 100644 --- a/net/pbr/Makefile +++ b/net/pbr/Makefile @@ -5,13 +5,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=pbr PKG_VERSION:=1.1.4 -PKG_RELEASE:=r7 +PKG_RELEASE:=r15 PKG_LICENSE:=GPL-3.0-or-later PKG_MAINTAINER:=Stan Grishin include $(INCLUDE_DIR)/package.mk -define Package/pbr-service/Default +define Package/pbr/default SECTION:=net CATEGORY:=Network SUBMENU:=Routing and Redirection @@ -21,60 +21,60 @@ define Package/pbr-service/Default DEPENDS+=+!BUSYBOX_DEFAULT_AWK:gawk DEPENDS+=+!BUSYBOX_DEFAULT_GREP:grep DEPENDS+=+!BUSYBOX_DEFAULT_SED:sed - PROVIDES:=pbr-service CONFLICTS:=vpnbypass vpn-policy-routing + PROVIDES:=pbr PKGARCH:=all endef define Package/pbr -$(call Package/pbr-service/Default) +$(call Package/pbr/default) TITLE+= with nft/nft set support DEPENDS+=+kmod-nft-core +kmod-nft-nat +nftables-json - DEFAULT_VARIANT:=1 VARIANT:=nftables - PROVIDES+=pbr vpnbypass vpn-policy-routing + DEFAULT_VARIANT:=1 + PROVIDES+=vpnbypass vpn-policy-routing endef define Package/pbr-iptables -$(call Package/pbr-service/Default) +$(call Package/pbr/default) TITLE+= with iptables/ipset support DEPENDS+=+ipset +iptables +kmod-ipt-ipset +iptables-mod-ipopt VARIANT:=iptables endef define Package/pbr-netifd -$(call Package/pbr-service/Default) +$(call Package/pbr/default) TITLE+= with netifd support VARIANT:=netifd endef -define Package/pbr-service/description +define Package/pbr/default/description This service enables policy-based routing for WAN interfaces and various VPN tunnels. endef define Package/pbr/description - $(call Package/pbr-service/description) + $(call Package/pbr/default/description) This version supports OpenWrt with both firewall3/ipset/iptables and firewall4/nft. endef define Package/pbr-iptables/description - $(call Package/pbr-service/description) + $(call Package/pbr/default/description) This version supports OpenWrt with firewall3/ipset/iptables. endef define Package/pbr-netifd/description - $(call Package/pbr-service/description) + $(call Package/pbr/default/description) This version supports OpenWrt with both firewall3/ipset/iptables and firewall4/nft. This version uses OpenWrt native netifd/tables to set up interfaces. This is WIP. endef -define Package/pbr-service/conffiles +define Package/pbr/default/conffiles /etc/config/pbr endef -Package/pbr/conffiles = $(Package/pbr-service/conffiles) -Package/pbr-iptables/conffiles = $(Package/pbr-service/conffiles) -Package/pbr-netifd/conffiles = $(Package/pbr-service/conffiles) +Package/pbr/conffiles = $(Package/pbr/default/conffiles) +Package/pbr-iptables/conffiles = $(Package/pbr/default/conffiles) +Package/pbr-netifd/conffiles = $(Package/pbr/default/conffiles) define Build/Configure endef @@ -82,7 +82,7 @@ endef define Build/Compile endef -define Package/pbr-service/install +define Package/pbr/default/install $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/etc/init.d/pbr $(1)/etc/init.d/pbr $(SED) "s|^\(readonly PKG_VERSION\).*|\1='$(PKG_VERSION)-$(PKG_RELEASE)'|" $(1)/etc/init.d/pbr @@ -98,29 +98,33 @@ endef # $(INSTALL_DATA) ./files/etc/hotplug.d/iface/70-pbr $(1)/etc/hotplug.d/iface/70-pbr define Package/pbr/install -$(call Package/pbr-service/install,$(1)) +$(call Package/pbr/default/install,$(1)) $(INSTALL_DIR) $(1)/etc/config $(INSTALL_CONF) ./files/etc/config/pbr $(1)/etc/config/pbr $(INSTALL_DIR) $(1)/usr/share/pbr $(INSTALL_DATA) ./files/usr/share/pbr/firewall.include $(1)/usr/share/pbr/firewall.include $(INSTALL_DIR) $(1)/usr/share/nftables.d $(CP) ./files/usr/share/nftables.d/* $(1)/usr/share/nftables.d/ + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) ./files/etc/uci-defaults/91-pbr-nft $(1)/etc/uci-defaults/91-pbr-nft endef define Package/pbr-iptables/install -$(call Package/pbr-service/install,$(1)) +$(call Package/pbr/default/install,$(1)) $(INSTALL_DIR) $(1)/etc/hotplug.d/firewall $(INSTALL_DATA) ./files/etc/hotplug.d/firewall/70-pbr $(1)/etc/hotplug.d/firewall/70-pbr $(INSTALL_DIR) $(1)/etc/config $(INSTALL_CONF) ./files/etc/config/pbr.iptables $(1)/etc/config/pbr + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) ./files/etc/uci-defaults/91-pbr-iptables $(1)/etc/uci-defaults/91-pbr-iptables endef define Package/pbr-netifd/install -$(call Package/pbr-service/install,$(1)) +$(call Package/pbr/default/install,$(1)) $(INSTALL_DIR) $(1)/etc/config $(INSTALL_CONF) ./files/etc/config/pbr $(1)/etc/config/pbr $(INSTALL_DIR) $(1)/etc/uci-defaults - $(INSTALL_BIN) ./files/etc/uci-defaults/91-pbr $(1)/etc/uci-defaults/91-pbr + $(INSTALL_BIN) ./files/etc/uci-defaults/91-pbr-netifd $(1)/etc/uci-defaults/91-pbr-netifd endef define Package/pbr/postinst @@ -141,8 +145,8 @@ define Package/pbr/prerm # check if we are on real system if [ -z "$${IPKG_INSTROOT}" ]; then uci -q delete firewall.pbr || true - echo "Stopping pbr service... " - /etc/init.d/pbr stop quiet && echo "OK" || echo "FAIL" + echo -n "Stopping pbr service... " + /etc/init.d/pbr stop quiet >/dev/null 2>&1 && echo "OK" || echo "FAIL" echo -n "Removing rc.d symlink for pbr... " /etc/init.d/pbr disable && echo "OK" || echo "FAIL" fi @@ -173,8 +177,8 @@ define Package/pbr-iptables/prerm # check if we are on real system if [ -z "$${IPKG_INSTROOT}" ]; then uci -q delete firewall.pbr || true - echo "Stopping pbr-iptables service... " - /etc/init.d/pbr stop quiet && echo "OK" || echo "FAIL" + echo -n "Stopping pbr-iptables service... " + /etc/init.d/pbr stop quiet >/dev/null 2>&1 && echo "OK" || echo "FAIL" echo -n "Removing rc.d symlink for pbr-iptables... " /etc/init.d/pbr disable && echo "OK" || echo "FAIL" fi @@ -196,10 +200,29 @@ define Package/pbr-netifd/prerm # check if we are on real system if [ -z "$${IPKG_INSTROOT}" ]; then uci -q delete firewall.pbr || true - echo "Stopping pbr-netifd service... " - /etc/init.d/pbr stop quiet && echo "OK" || echo "FAIL" + echo -n "Stopping pbr-netifd service... " + /etc/init.d/pbr stop quiet >/dev/null 2>&1 && echo "OK" || echo "FAIL" echo -n "Removing rc.d symlink for pbr... " /etc/init.d/pbr disable && echo "OK" || echo "FAIL" + echo -n "Cleaning up /etc/iproute2/rt_tables... " + if sed -i '/pbr_/d' /etc/iproute2/rt_tables; then + echo "OK" + else + echo "FAIL" + fi + echo -n "Cleaning up /etc/config/network... " + if sed -i '/ip.table.*pbr_/d' /etc/config/network; then + echo "OK" + else + echo "FAIL" + fi + echo -n "Restarting Network... " + if /etc/init.d/network restart >/dev/null 2>&1; then + echo "OK" + else + echo "FAIL" + fi + fi exit 0 endef diff --git a/net/pbr/files/etc/init.d/pbr b/net/pbr/files/etc/init.d/pbr index 067b45fe7a..84f6203ac2 100755 --- a/net/pbr/files/etc/init.d/pbr +++ b/net/pbr/files/etc/init.d/pbr @@ -22,8 +22,10 @@ readonly packageConfigFile="/etc/config/${packageName}" readonly packageLockFile="/var/run/${packageName}.lock" readonly dnsmasqFileDefault="/var/dnsmasq.d/${packageName}" readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m' -readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m' readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m' +readonly _OKB_='\033[1;34m\xe2\x9c\x93\033[0m' +readonly __OKB__='\033[1;34m[\xe2\x9c\x93]\033[0m' +readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m' readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m' readonly _ERROR_='\033[0;31mERROR\033[0m' readonly _WARNING_='\033[0;33mWARNING\033[0m' @@ -55,6 +57,7 @@ readonly chainsList='forward input output postrouting prerouting' readonly ssConfigFile='/etc/shadowsocks' readonly torConfigFile='/etc/tor/torrc' readonly xrayIfacePrefix='xray_' +readonly rtTablesFile='/etc/iproute2/rt_tables' # package config options procd_boot_timeout= @@ -124,6 +127,8 @@ torTrafficPort= output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; } output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; } +output_okb() { output 1 "$_OKB_"; output 2 "$__OKB__\\n"; } +output_okbn() { output 1 "$_OKB_\\n"; output 2 "$__OKB__\\n"; } output_fail() { output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; } output_failn() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; } # shellcheck disable=SC2317 @@ -236,7 +241,8 @@ is_ipv4_netmask() { local ip="${1%/*}"; [ "$ip" != "$1" ] && is_ipv4 "$ip"; } is_lan() { local d; network_get_device d "$1"; str_contains "$d" 'br-lan'; } is_l2tp() { local p; network_get_protocol p "$1"; [ "${p:0:4}" = "l2tp" ]; } 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; } -is_netifd_table() { local iface="$1"; [ "$(uci_get 'network' "$iface" 'ip4table')" = "${packageName}_${iface%6}" ]; } +is_netifd_table() { grep -q "ip.table.*$1" /etc/config/network; } +is_netifd_table_interface() { local iface="$1"; [ "$(uci_get 'network' "$iface" 'ip4table')" = "${packageName}_${iface%6}" ]; } is_oc() { local p; network_get_protocol p "$1"; [ "${p:0:11}" = "openconnect" ]; } is_ovpn() { local d; uci_get_device d "$1"; [ "${d:0:3}" = "tun" ] || [ "${d:0:3}" = "tap" ] || [ -f "/sys/devices/virtual/net/${d}/tun_flags" ]; } is_ovpn_valid() { local dev_net dev_ovpn; uci_get_device dev_net "$1"; dev_ovpn="$(uci_get 'openvpn' "$1" 'dev')"; [ -n "$dev_net" ] && [ -n "$dev_ovpn" ] && [ "$dev_net" = "$dev_ovpn" ]; } @@ -284,9 +290,9 @@ get_tor_dns_port() { local i="$(grep -m1 DNSPort "$torConfigFile" | awk -F: '{pr # shellcheck disable=SC2155 get_tor_traffic_port() { local i="$(grep -m1 TransPort "$torConfigFile" | awk -F: '{print $2}')"; echo "${i:-9040}"; } get_xray_traffic_port() { local i="${1//$xrayIfacePrefix}"; [ "$i" = "$1" ] && unset i; echo "$i"; } -get_rt_tables_id() { local iface="$1"; grep "${ipTablePrefix}_${iface}\$" '/etc/iproute2/rt_tables' | awk '{print $1;}'; } -get_rt_tables_next_id() { echo "$(($(sort -r -n '/etc/iproute2/rt_tables' | grep -o -E -m 1 "^[0-9]+")+1))"; } -get_rt_tables_non_pbr_next_id() { echo "$(($(grep -v "${ipTablePrefix}_" '/etc/iproute2/rt_tables' | sort -r -n | grep -o -E -m 1 "^[0-9]+")+1))"; } +get_rt_tables_id() { local iface="$1"; grep "${ipTablePrefix}_${iface}\$" "$rtTablesFile" | awk '{print $1;}'; } +get_rt_tables_next_id() { echo "$(($(sort -r -n "$rtTablesFile" | grep -o -E -m 1 "^[0-9]+")+1))"; } +get_rt_tables_non_pbr_next_id() { echo "$(($(grep -v "${ipTablePrefix}_" "$rtTablesFile" | sort -r -n | grep -o -E -m 1 "^[0-9]+")+1))"; } # shellcheck disable=SC2016 resolveip_to_ipt() { resolveip "$@" | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d'; } resolveip_to_ipt4() { resolveip_to_ipt -4 "$@"; } @@ -386,6 +392,8 @@ get_text() { errorResolverNotSupported) r="Resolver set (${resolver_set}) is not supported on this system!";; errorServiceDisabled) r="The ${packageName} service is currently disabled!";; errorNoWanGateway) r="The ${serviceName} service failed to discover WAN gateway!";; + errorNoWanInterface) r="The %s inteface not found, you need to set the 'pbr.config.procd_wan_interface' option!";; + errorNoWanInterfaceHint) r="Refer to https://docs.openwrt.melmac.net/pbr/#procd_wan_interface.";; errorIpsetNameTooLong) r="The ipset name '%s' is longer than allowed 31 characters!";; errorNftsetNameTooLong) r="The nft set name '%s' is longer than allowed 255 characters!";; errorUnexpectedExit) r="Unexpected exit or service termination: '%s'!";; @@ -409,6 +417,7 @@ get_text() { errorPolicyProcessInsertionFailedIpv4) r="Insertion failed for IPv4 for policy '%s'!";; errorInterfaceRoutingEmptyValues) r="Received empty tid/mark or interface name when setting up routing!";; errorFailedToResolve) r="Failed to resolve '%s'!";; + errorTryFailed) r="Command failed: %s";; errorNftFileInstall) r="Failed to install fw4 nft file '%s'!";; errorDownloadUrlNoHttps) r="Failed to download '%s', HTTPS is not supported!";; errorDownloadUrl) r="Failed to download '%s'!";; @@ -630,6 +639,11 @@ is_wan_up() { load_network "$param" [ "$procd_wan_ignore_status" -eq '0' ] || return 0 [ "$param" = 'on_boot' ] || procd_boot_timeout='1' + if [ -z "$(uci_get network "$procd_wan_interface")" ]; then + state add 'errorSummary' 'errorNoWanInterface' "$procd_wan_interface" + state add 'errorSummary' 'errorNoWanInterfaceHint' + return 1 + fi while [ -z "$wanGW" ] ; do load_network "$param" if [ $((sleepCount)) -gt $((procd_boot_timeout)) ] || [ -n "$wanGW" ]; then break; fi @@ -959,7 +973,14 @@ nftset() { fi } -cleanup_rt_tables() { sed -i "/${ipTablePrefix}_/d" '/etc/iproute2/rt_tables'; sync; } +cleanup_rt_tables() { + local i +# shellcheck disable=SC2013 + for i in $(grep -oh "${ipTablePrefix}_.*" $rtTablesFile); do + ! is_netifd_table "$i" && sed -i "/${i}/d" "$rtTablesFile" + done + sync +} cleanup_main_chains() { local i @@ -1962,6 +1983,13 @@ policy_process() { fi } +try() { + if ! "$@"; then + state add 'errorSummary' 'errorTryFailed' "$*" + return 1 + fi +} + interface_routing() { local action="$1" tid="$2" mark="$3" iface="$4" gw4="$5" dev="$6" gw6="$7" dev6="$8" priority="$9" local dscp s=0 i ipv4_error=1 ipv6_error=1 @@ -1971,14 +1999,14 @@ interface_routing() { fi case "$action" in create) - if is_netifd_table "$iface"; then + if is_netifd_table_interface "$iface"; then ipv4_error=0 $ip_bin rule del table "$tid" >/dev/null 2>&1 - $ip_bin -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 + try "$ip_bin" -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 if is_nft_mode; then - nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1 - nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1 - nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1 + try nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1 + try nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1 + try nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1 else ipt -t mangle -N "${iptPrefix}_MARK_${mark}" || ipv4_error=1 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j MARK --set-xmark "${mark}/${fw_mask}" || ipv4_error=1 @@ -1986,13 +2014,13 @@ interface_routing() { fi if [ -n "$ipv6_enabled" ]; then ipv6_error=0 - $ip_bin -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1 + try "$ip_bin" -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1 fi else - if ! grep -q "$tid ${ipTablePrefix}_${iface}" '/etc/iproute2/rt_tables'; then - sed -i "/${ipTablePrefix}_${iface}/d" '/etc/iproute2/rt_tables' + if ! grep -q "$tid ${ipTablePrefix}_${iface}" "$rtTablesFile"; then + sed -i "/${ipTablePrefix}_${iface}/d" "$rtTablesFile" sync - echo "$tid ${ipTablePrefix}_${iface}" >> '/etc/iproute2/rt_tables' + echo "$tid ${ipTablePrefix}_${iface}" >> "$rtTablesFile" sync fi $ip_bin rule del table "$tid" >/dev/null 2>&1 @@ -2000,9 +2028,9 @@ interface_routing() { if [ -n "$gw4" ] || [ "$strict_enforcement" -ne 0 ]; then ipv4_error=0 if [ -z "$gw4" ]; then - $ip_bin -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1 + try "$ip_bin" -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1 else - $ip_bin -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1 + try "$ip_bin" -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1 fi # shellcheck disable=SC2086 while read -r i; do @@ -2010,16 +2038,16 @@ interface_routing() { i="$(echo "$i" | sed 's/ onlink$//')" idev="$(echo "$i" | grep -Eso 'dev [^ ]*' | awk '{print $2}')" if ! is_supported_iface_dev "$idev"; then - $ip_bin -4 route add $i table "$tid" >/dev/null 2>&1 || ipv4_error=1 + try "$ip_bin" -4 route add $i table "$tid" >/dev/null 2>&1 || ipv4_error=1 fi done << EOF $($ip_bin -4 route list table main) EOF - $ip_bin -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 + try "$ip_bin" -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 if is_nft_mode; then - nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1 - nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1 - nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1 + try nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1 + try nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1 + try nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1 else ipt -t mangle -N "${iptPrefix}_MARK_${mark}" || ipv4_error=1 ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j MARK --set-xmark "${mark}/${fw_mask}" || ipv4_error=1 @@ -2030,38 +2058,38 @@ EOF ipv6_error=0 if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strict_enforcement" -ne 0 ]; then if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then - $ip_bin -6 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv6_error=1 - elif $ip_bin -6 route list table main | grep -q " dev $dev6 "; then - $ip_bin -6 route add default via "$gw6" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 + try "$ip_bin" -6 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv6_error=1 + elif try "$ip_bin" -6 route list table main | grep -q " dev $dev6 "; then + try "$ip_bin" -6 route add default via "$gw6" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 while read -r i; do i="$(echo "$i" | sed 's/ linkdown$//')" i="$(echo "$i" | sed 's/ onlink$//')" # shellcheck disable=SC2086 - $ip_bin -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1 + try "$ip_bin" -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1 done << EOF $($ip_bin -6 route list table main | grep " dev $dev6 ") EOF else - $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 - $ip_bin -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 + try "$ip_bin" -6 route add "$($ip_bin -6 -o a show "$dev6" | awk '{print $4}')" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 + try "$ip_bin" -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 fi fi - $ip_bin -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" >/dev/null 2>&1 || ipv6_error=1 + try "$ip_bin" -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" >/dev/null 2>&1 || ipv6_error=1 fi fi if [ "$ipv4_error" -eq 0 ] || [ "$ipv6_error" -eq 0 ]; then dscp="$(uci_get "$packageName" 'config' "${iface}_dscp")" if is_nft_mode; then if [ "${dscp:-0}" -ge 1 ] && [ "${dscp:-0}" -le 63 ]; then - nft add rule inet "$nftTable" "${nftPrefix}_prerouting ${nftIPv4Flag} dscp ${dscp} goto ${nftPrefix}_mark_${mark}" || s=1 + try nft add rule inet "$nftTable" "${nftPrefix}_prerouting ${nftIPv4Flag} dscp ${dscp} goto ${nftPrefix}_mark_${mark}" || s=1 if [ -n "$ipv6_enabled" ]; then - nft add rule inet "$nftTable" "${nftPrefix}_prerouting ${nftIPv6Flag} dscp ${dscp} goto ${nftPrefix}_mark_${mark}" || s=1 + try nft add rule inet "$nftTable" "${nftPrefix}_prerouting ${nftIPv6Flag} dscp ${dscp} goto ${nftPrefix}_mark_${mark}" || s=1 fi fi if [ "$iface" = "$icmp_interface" ]; then - nft add rule inet "$nftTable" "${nftPrefix}_output ${nftIPv4Flag} protocol icmp goto ${nftPrefix}_mark_${mark}" || s=1 + try nft add rule inet "$nftTable" "${nftPrefix}_output ${nftIPv4Flag} protocol icmp goto ${nftPrefix}_mark_${mark}" || s=1 if [ -n "$ipv6_enabled" ]; then - nft add rule inet "$nftTable" "${nftPrefix}_output ${nftIPv6Flag} protocol icmp goto ${nftPrefix}_mark_${mark}" || s=1 + try nft add rule inet "$nftTable" "${nftPrefix}_output ${nftIPv6Flag} protocol icmp goto ${nftPrefix}_mark_${mark}" || s=1 fi fi else @@ -2093,46 +2121,46 @@ EOF ;; delete|destroy) $ip_bin rule del table "$tid" >/dev/null 2>&1 - if ! is_netifd_table "$iface"; then + if ! is_netifd_table_interface "$iface"; then $ip_bin route flush table "$tid" >/dev/null 2>&1 - sed -i "/${ipTablePrefix}_${iface}\$/d" '/etc/iproute2/rt_tables' + sed -i "/${ipTablePrefix}_${iface}\$/d" "$rtTablesFile" sync fi return "$s" ;; reload_interface) - is_netifd_table "$iface" && return 0; + is_netifd_table_interface "$iface" && return 0; ipv4_error=0 $ip_bin rule del table "$tid" >/dev/null 2>&1 - if ! is_netifd_table "$iface"; then + if ! is_netifd_table_interface "$iface"; then $ip_bin route flush table "$tid" >/dev/null 2>&1 fi if [ -n "$gw4" ] || [ "$strict_enforcement" -ne 0 ]; then if [ -z "$gw4" ]; then - $ip_bin -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1 + try "$ip_bin" -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1 else - $ip_bin -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1 + try "$ip_bin" -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1 fi - $ip_bin rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 + try "$ip_bin" rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 fi if [ -n "$ipv6_enabled" ]; then ipv6_error=0 if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strict_enforcement" -ne 0 ]; then if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then - $ip_bin -6 route add unreachable default table "$tid" || ipv6_error=1 + try "$ip_bin" -6 route add unreachable default table "$tid" || ipv6_error=1 elif $ip_bin -6 route list table main | grep -q " dev $dev6 "; then while read -r i; do # shellcheck disable=SC2086 - $ip_bin -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1 + try "$ip_bin" -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1 done << EOF $($ip_bin -6 route list table main | grep " dev $dev6 ") EOF else - $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 - $ip_bin -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 + try "$ip_bin" -6 route add "$($ip_bin -6 -o a show "$dev6" | awk '{print $4}')" dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 + try "$ip_bin" -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 fi fi - $ip_bin -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1 + try "$ip_bin" -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1 fi if [ "$ipv4_error" -eq 0 ] || [ "$ipv6_error" -eq 0 ]; then s=0 @@ -2209,66 +2237,112 @@ interface_process() { [ -z "$ifaceMark" ] && ifaceMark="$(printf '0x%06x' "$wan_mark")" [ -z "$ifacePriority" ] && ifacePriority="$wan_ip_rules_priority" - if [ "$action" = 'pre-init' ]; then - pbr_get_gateway6 gw6 "$iface" "$dev6" - [ -n "$gw6" ] && ipv6_enabled=1 - [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_non_pbr_next_id)" - eval "pre_init_mark_${iface//-/_}"='$ifaceMark' - eval "pre_init_priority_${iface//-/_}"='$ifacePriority' - eval "pre_init_tid_${iface//-/_}"='$ifaceTableID' - ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))" - ifacePriority="$((ifacePriority + 1))" - ifaceTableID="$((ifaceTableID + 1))" - return 0 - fi - -# TODO: if interfaces are started out of order the rt_tables ID may be incorrect -# use the expected_tid_${iface} ??? - ifaceTableID="$(get_rt_tables_id "$iface")" - [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)" - eval "mark_${iface//-/_}"='$ifaceMark' - eval "tid_${iface//-/_}"='$ifaceTableID' - pbr_get_gateway gw4 "$iface" "$dev" - pbr_get_gateway6 gw6 "$iface" "$dev6" - dispGw4="${gw4:-0.0.0.0}" - dispGw6="${gw6:-::/0}" - [ "$iface" != "$dev" ] && dispDev="$dev" - if is_default_dev "$dev"; then - [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__" - fi - displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" - case "$action" in + pre_init) + [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_non_pbr_next_id)" + eval "pre_init_mark_${iface//-/_}"='$ifaceMark' + eval "pre_init_priority_${iface//-/_}"='$ifacePriority' + eval "pre_init_tid_${iface//-/_}"='$ifaceTableID' + ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))" + ifacePriority="$((ifacePriority - 1))" + ifaceTableID="$((ifaceTableID + 1))" + return 0 + ;; create) + ifaceTableID="$(get_rt_tables_id "$iface")" + [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)" + eval "mark_${iface//-/_}"='$ifaceMark' + eval "tid_${iface//-/_}"='$ifaceTableID' + pbr_get_gateway gw4 "$iface" "$dev" + pbr_get_gateway6 gw6 "$iface" "$dev6" + dispGw4="${gw4:-0.0.0.0}" + dispGw6="${gw6:-::/0}" + [ "$iface" != "$dev" ] && dispDev="$dev" + if is_default_dev "$dev"; then + [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__" + fi + displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" output 2 "Setting up routing for '$displayText' " if interface_routing 'create' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"; then json_add_gateway 'create' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" "$dispStatus" gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n" - output_ok + if is_netifd_table_interface "$iface"; then output_okb; else output_ok; fi else state add 'errorSummary' 'errorFailedSetup' "$displayText" output_fail fi ;; create_user_set) + ifaceTableID="$(get_rt_tables_id "$iface")" + [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)" + eval "mark_${iface//-/_}"='$ifaceMark' + eval "tid_${iface//-/_}"='$ifaceTableID' + pbr_get_gateway gw4 "$iface" "$dev" + pbr_get_gateway6 gw6 "$iface" "$dev6" + dispGw4="${gw4:-0.0.0.0}" + dispGw6="${gw6:-::/0}" + [ "$iface" != "$dev" ] && dispDev="$dev" + if is_default_dev "$dev"; then + [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__" + fi + displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" interface_routing 'create_user_set' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" ;; destroy) + ifaceTableID="$(get_rt_tables_id "$iface")" + [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)" + eval "mark_${iface//-/_}"='$ifaceMark' + eval "tid_${iface//-/_}"='$ifaceTableID' + pbr_get_gateway gw4 "$iface" "$dev" + pbr_get_gateway6 gw6 "$iface" "$dev6" + dispGw4="${gw4:-0.0.0.0}" + dispGw6="${gw6:-::/0}" + [ "$iface" != "$dev" ] && dispDev="$dev" + if is_default_dev "$dev"; then + [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__" + fi + displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" output 2 "Removing routing for '$displayText' " interface_routing 'destroy' "${ifaceTableID}" "${ifaceMark}" "${iface}" - output_ok + if is_netifd_table_interface "$iface"; then output_okb; else output_ok; fi ;; reload) + ifaceTableID="$(get_rt_tables_id "$iface")" + [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)" + eval "mark_${iface//-/_}"='$ifaceMark' + eval "tid_${iface//-/_}"='$ifaceTableID' + pbr_get_gateway gw4 "$iface" "$dev" + pbr_get_gateway6 gw6 "$iface" "$dev6" + dispGw4="${gw4:-0.0.0.0}" + dispGw6="${gw6:-::/0}" + [ "$iface" != "$dev" ] && dispDev="$dev" + if is_default_dev "$dev"; then + [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__" + fi + displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n" ;; reload_interface) + ifaceTableID="$(get_rt_tables_id "$iface")" + [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)" + eval "mark_${iface//-/_}"='$ifaceMark' + eval "tid_${iface//-/_}"='$ifaceTableID' + pbr_get_gateway gw4 "$iface" "$dev" + pbr_get_gateway6 gw6 "$iface" "$dev6" + dispGw4="${gw4:-0.0.0.0}" + dispGw6="${gw6:-::/0}" + [ "$iface" != "$dev" ] && dispDev="$dev" + if is_default_dev "$dev"; then + [ "$verbosity" = '1' ] && dispStatus="$_OK_" || dispStatus="$__OK__" + fi + displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" if [ "$iface" = "$reloadedIface" ]; then output 2 "Reloading routing for '$displayText' " if interface_routing 'reload_interface' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"; then json_add_gateway 'reload_interface' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" "$dispStatus" gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n" - output_ok + if is_netifd_table_interface "$iface"; then output_okb; else output_ok; fi else state add 'errorSummary' 'errorFailedReload' "$displayText" output_fail @@ -2280,7 +2354,7 @@ interface_process() { esac # ifaceTableID="$((ifaceTableID + 1))" ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))" - ifacePriority="$((ifacePriority + 1))" + ifacePriority="$((ifacePriority - 1))" return $s } @@ -2351,7 +2425,7 @@ start_service() { is_wan_up "$param" || return 1 interface_process 'all' 'prepare' - config_foreach interface_process 'interface' 'pre-init' + config_foreach interface_process 'interface' 'pre_init' case "$param" in on_boot) @@ -2682,7 +2756,7 @@ status_service_nft() { # echo "$_SEPARATOR_" # ip rule list | grep "${packageName}_" echo "$_SEPARATOR_" - tableCount="$(grep -c "${packageName}_" /etc/iproute2/rt_tables)" || tableCount=0 + tableCount="$(grep -c "${packageName}_" $rtTablesFile)" || tableCount=0 wan_tid=$(($(get_rt_tables_next_id)-tableCount)) i=0; while [ $i -lt "$tableCount" ]; do echo "IPv4 table $((wan_tid + i)) route: $($ip_bin -4 route show table $((wan_tid + i)) | grep default)" @@ -2729,7 +2803,7 @@ status_service_iptables() { echo "$_SEPARATOR_" echo "Routes/IP Rules" - tableCount="$(grep -c "${packageName}_" /etc/iproute2/rt_tables)" || tableCount=0 + tableCount="$(grep -c "${packageName}_" $rtTablesFile)" || tableCount=0 if [ -n "$set_d" ]; then route; else route | grep '^default'; fi if [ -n "$set_d" ]; then ip rule list; fi wan_tid=$(($(get_rt_tables_next_id)-tableCount)) diff --git a/net/pbr/files/etc/init.d/pbr.init b/net/pbr/files/etc/init.d/pbr.init deleted file mode 100755 index b8c9c3d823..0000000000 --- a/net/pbr/files/etc/init.d/pbr.init +++ /dev/null @@ -1,2528 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright 2020-2022 Stan Grishin (stangri@melmac.ca) -# shellcheck disable=SC1091,SC2018,SC2019,SC3043,SC3057,SC3060 - -# sysctl net.ipv4.conf.default.rp_filter=1 -# sysctl net.ipv4.conf.all.rp_filter=1 - -# shellcheck disable=SC2034 -START=94 -# shellcheck disable=SC2034 -USE_PROCD=1 - -if type extra_command >/dev/null 2>&1; then - extra_command 'status' "Generates output required to troubleshoot routing issues - Use '-d' option for more detailed output - Use '-p' option to automatically upload data under VPR paste.ee account - WARNING: while paste.ee uploads are unlisted, they are still publicly available - List domain names after options to include their lookup in report" - extra_command 'version' 'Show version information' - extra_command 'on_firewall_reload' ' Run service on firewall reload' - extra_command 'on_interface_reload' ' Run service on indicated interface reload' -else -# shellcheck disable=SC2034 - EXTRA_COMMANDS='on_firewall_reload on_interface_reload status version' -# shellcheck disable=SC2034 - EXTRA_HELP=" status Generates output required to troubleshoot routing issues - Use '-d' option for more detailed output - Use '-p' option to automatically upload data under VPR paste.ee account - WARNING: while paste.ee uploads are unlisted, they are still publicly available - List domain names after options to include their lookup in report" -fi - -readonly PKG_VERSION='dev-test' -readonly packageName='pbr' -readonly serviceName="$packageName $PKG_VERSION" -readonly serviceTrapSignals='exit SIGHUP SIGQUIT SIGKILL' -readonly packageConfigFile="/etc/config/${packageName}" -readonly packageLockFile="/var/run/${packageName}.lock" -readonly nftTempFile="/var/run/${packageName}.nft" -#readonly nftPermFile="/etc/nftables.d/table-post/30-pbr.nft" -readonly dnsmasqFile="/var/dnsmasq.d/${packageName}" -readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m' -readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m' -readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m' -readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m' -readonly _ERROR_='\033[0;31mERROR\033[0m' -readonly _WARNING_='\033[0;33mWARNING\033[0m' -readonly ip_full='/usr/libexec/ip-full' -# shellcheck disable=SC2155 -readonly ip_bin="$(command -v ip)" -readonly ipTablePrefix='pbr' -# shellcheck disable=SC2155 -readonly iptables="$(command -v iptables)" -# shellcheck disable=SC2155 -readonly ip6tables="$(command -v ip6tables)" -# shellcheck disable=SC2155 -readonly ipset="$(command -v ipset)" -readonly ipsPrefix='pbr' -readonly iptPrefix='PBR' -# shellcheck disable=SC2155 -readonly agh="$(command -v AdGuardHome)" -readonly aghConfigFile='/etc/adguardhome.yaml' -readonly aghIpsetFile="/var/run/${packageName}.adguardhome.ipsets" -# shellcheck disable=SC2155 -readonly nft="$(command -v nft)" -readonly nftTable="fw4" -readonly nftPrefix='pbr' -readonly chainsList='forward input output postrouting prerouting' - -# package config options -boot_timeout= -enabled= -fw_mask= -icmp_interface= -ignored_interface= -ipv6_enabled= -nft_user_set_policy= -nft_user_set_counter= -procd_boot_delay= -procd_reload_delay= -resolver_set= -rule_create_option= -secure_reload= -strict_enforcement= -supported_interface= -verbosity= -wan_ip_rules_priority= -wan_mark= - -# run-time -gatewaySummary= -errorSummary= -warningSummary= -wanIface4= -wanIface6= -ifaceMark= -ifaceTableID= -ifacePriority= -ifacesAll= -ifacesSupported= -firewallWanZone= -wanGW4= -wanGW6= -serviceStartTrigger= -processPolicyError= -processPolicyWarning= -resolver_set_supported= -nftPrevParam4= -nftPrevParam6= - -get_text() { - local r - case "$1" in - errorConfigValidation) r="Config ($packageConfigFile) validation failure!";; - errorNoIpFull) r="ip-full binary cannot be found!";; - errorNoIptables) r="iptables binary cannot be found!";; - errorNoIpset) r="Resolver set support (${resolver_set}) requires ipset, but ipset binary cannot be found!";; - errorNoNft) r="Resolver set support (${resolver_set}) requires nftables, but nft binary cannot be found!";; - errorResolverNotSupported) r="Resolver set (${resolver_set}) is not supported on this system!";; - errorServiceDisabled) r="The ${packageName} service is currently disabled!";; - errorNoWanGateway) r="The ${serviceName} service failed to discover WAN gateway!";; - errorIpsetNameTooLong) r="The ipset name '%s' is longer than allowed 31 characters!";; - errorNftsetNameTooLong) r="The nft set name '%s' is longer than allowed 31 characters!";; - errorUnexpectedExit) r="Unexpected exit or service termination: '%s'!";; - errorPolicyNoSrcDest) r="Policy '%s' has no source/destination parameters!";; - errorPolicyNoInterface) r="Policy '%s' has no assigned interface!";; - errorPolicyUnknownInterface) r="Policy '%s' has an unknown interface!";; - errorPolicyProcessCMD) r="'%s'!";; - errorFailedSetup) r="Failed to set up '%s'!";; - errorFailedReload) r="Failed to reload '%s'!";; - errorUserFileNotFound) r="Custom user file '%s' not found or empty!";; - errorUserFileSyntax) r="Syntax error in custom user file '%s'!";; - errorUserFileRunning) r="Error running custom user file '%s'!";; - errorUserFileNoCurl) r="Use of 'curl' is detected in custom user file '%s', but 'curl' isn't installed!";; - errorNoGateways) r="Failed to set up any gateway!";; - errorResolver) r="Resolver '%s'!";; - errorPolicyProcessNoIpv6) r="Skipping IPv6 policy '%s' as IPv6 support is disabled!";; - errorPolicyProcessUnknownFwmark) r="Unknown packet mark for interface '%s'!";; - errorPolicyProcessMismatchFamily) r="Mismatched IP family between in policy '%s'!";; - errorPolicyProcessUnknownProtocol) r="Unknown protocol in policy '%s'!";; - errorPolicyProcessInsertionFailed) r="Insertion failed for both IPv4 and IPv6 for policy '%s'!";; - errorPolicyProcessInsertionFailedIpv4) r="Insertion failed for IPv4 for policy '%s'!";; - errorInterfaceRoutingEmptyValues) r="Received empty tid/mark or interface name when setting up routing!";; - errorFailedToResolve) r="Failed to resolve '%s'!";; - warningInvalidOVPNConfig) r="Invalid OpenVPN config for '%s' interface.";; - warningResolverNotSupported) r="Resolver set (${resolver_set}) is not supported on this system.";; - warningAGHVersionTooLow) r="Installed AdGuardHome ('%s') doesn't support 'ipset_file' option.";; - warningPolicyProcessCMD) r="'%s'";; - warningTorUnsetParams) r="Please unset 'src_addr', 'src_port' and 'dest_port' for policy '%s'.";; - warningTorUnsetProto) r="Please unset 'proto' or set 'proto' to 'all' for policy '%s'.";; - warningTorUnsetChainIpt) r="Please unset 'chain' or set 'chain' to 'PREROUTING' for policy '%s'.";; - warningTorUnsetChainNft) r="Please unset 'chain' or set 'chain' to 'prerouting' for policy '%s'.";; - warningOutdatedWebUIApp) r="The WebUI application is outdated (version %s), please update it.";; - esac - echo "$r" -} - -version() { echo "$PKG_VERSION"; } -output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; } -output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; } -output_fail() { s=1; output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; } -output_failn() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; } -# shellcheck disable=SC2317 -str_replace() { printf "%b" "$1" | sed -e "s/$(printf "%b" "$2")/$(printf "%b" "$3")/g"; } -str_replace() { echo "${1//$2/$3}"; } -str_contains() { [ -n "$1" ] && [ -n "$2" ] && [ "${1//$2}" != "$1" ]; } -is_greater() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } -is_greater_or_equal() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" = "$2"; } -str_contains_word() { echo "$1" | grep -q -w "$2"; } -str_to_lower() { echo "$1" | tr 'A-Z' 'a-z'; } -str_to_upper() { echo "$1" | tr 'a-z' 'A-Z'; } -str_extras_to_underscore() { echo "$1" | tr '[\. ~`!@#$%^&*()\+/,<>?//;:]' '_'; } -str_extras_to_space() { echo "$1" | tr ';{}' ' '; } -debug() { local i j; for i in "$@"; do eval "j=\$$i"; echo "${i}: ${j} "; done; } -output() { -# Can take a single parameter (text) to be output at any verbosity -# Or target verbosity level and text to be output at specifc verbosity - local msg memmsg logmsg - local sharedMemoryOutput="/dev/shm/$packageName-output" - verbosity="${verbosity:-2}" - if [ "$#" -ne 1 ]; then - if [ $((verbosity & $1)) -gt 0 ] || [ "$verbosity" = "$1" ]; then shift; else return 0; fi - fi - [ -t 1 ] && printf "%b" "$1" - msg="${1//$serviceName /service }"; - if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then - [ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")" - logmsg="$(printf "%b" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')" - logger -t "${packageName:-service}" "$(printf "%b" "$logmsg")" - rm -f "$sharedMemoryOutput" - else - printf "%b" "$msg" >> "$sharedMemoryOutput" - fi -} -is_present() { command -v "$1" >/dev/null 2>&1; } -is_installed() { [ -s "/usr/lib/opkg/info/${1}.control" ]; } -is_variant_installed() { [ "$(echo /usr/lib/opkg/info/"${1}"*.control)" != "/usr/lib/opkg/info/${1}*.control" ]; } -is_nft() { [ -x "$nft" ] && ! str_contains "$resolver_set" 'ipset' && "$nft" list chains inet | grep -q "${nftPrefix}_prerouting"; } -_find_firewall_wan_zone() { [ "$(uci -q get "firewall.${1}.name")" = "wan" ] && firewallWanZone="$1"; } -_build_ifaces_all() { ifacesAll="${ifacesAll}${1} "; } -_build_ifaces_supported() { is_supported_interface "$1" && ! str_contains "$ifacesSupported" "$1" && ifacesSupported="${ifacesSupported}${1} "; } -pbr_find_iface() { - local iface i param="$2" - [ "$param" = 'wan6' ] || param='wan' - "network_find_${param}" iface - is_tunnel "$iface" && unset iface - if [ -z "$iface" ]; then - for i in $ifacesAll; do - if "is_${param}" "$i"; then break; else unset i; fi - done - fi - eval "$1"='${iface:-$i}' -} -pbr_get_gateway() { - local iface="$2" dev="$3" gw - network_get_gateway gw "$iface" true - if [ -z "$gw" ] || [ "$gw" = '0.0.0.0' ]; then -# gw="$(ubus call "network.interface.${iface}" status | jsonfilter -e "@.route[0].nexthop")" - gw="$($ip_bin -4 a list dev "$dev" 2>/dev/null | grep inet | awk '{print $2}' | awk -F "/" '{print $1}')" - fi - eval "$1"='$gw' -} -pbr_get_gateway6() { - local iface="$2" dev="$3" gw - network_get_gateway6 gw "$iface" true - if [ -z "$gw" ] || [ "$gw" = '::/0' ] || [ "$gw" = '::0/0' ] || [ "$gw" = '::' ]; then - gw="$($ip_bin -6 a list dev "$dev" 2>/dev/null | grep inet6 | grep 'scope global' | awk '{print $2}')" - fi - eval "$1"='$gw' -} -is_dslite() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:6}" = "dslite" ]; } -is_l2tp() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:4}" = "l2tp" ]; } -is_oc() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:11}" = "openconnect" ]; } -# 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" ]; } -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" ]; } -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" ]; } -is_pptp() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:4}" = "pptp" ]; } -is_softether() { local dev; network_get_device dev "$1"; [ "${dev:0:4}" = "vpn_" ]; } -is_tor() { [ "$(str_to_lower "$1")" = "tor" ]; } -is_tor_running() { - local ret=0 - if [ -s "/etc/tor/torrc" ]; then - json_load "$(ubus call service list "{ 'name': 'tor' }")" - json_select 'tor'; json_select 'instances'; json_select 'instance1'; - json_get_var ret 'running'; json_cleanup - fi - if [ "$ret" = "0" ]; then return 1; else return 0; fi -} -is_wg() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:9}" = "wireguard" ]; } -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"; } -is_wan() { [ "$1" = "$wanIface4" ] || { [ "${1##wan}" != "$1" ] && [ "${1##wan6}" = "$1" ]; } || [ "${1%%wan}" != "$1" ]; } -is_wan6() { [ -n "$wanIface6" ] && [ "$1" = "$wanIface6" ] || [ "${1/#wan6}" != "$1" ] || [ "${1/%wan6}" != "$1" ]; } -is_ignored_interface() { str_contains_word "$ignored_interface" "$1"; } -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"; } -is_ignore_target() { [ "$(str_to_lower "$1")" = 'ignore' ]; } -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; } -is_ipv4() { expr "$1" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null; } -is_ipv6() { ! is_mac_address "$1" && str_contains "$1" ":"; } -is_family_mismatch() { ( is_netmask "${1//!}" && is_ipv6 "${2//!}" ) || ( is_ipv6 "${1//!}" && is_netmask "${2//!}" ); } -is_ipv6_link_local() { [ "${1:0:4}" = "fe80" ]; } -is_ipv6_unique_local() { [ "${1:0:2}" = "fc" ] || [ "${1:0:2}" = "fd" ]; } -is_ipv6_global() { [ "${1:0:4}" = "2001" ]; } -# is_ipv6_global() { is_ipv6 "$1" && ! is_ipv6_link_local "$1" && ! is_ipv6_link_local "$1"; } -is_list() { str_contains "$1" "," || str_contains "$1" " "; } -is_netmask() { local ip="${1%/*}"; [ "$ip" != "$1" ] && is_ipv4 "$ip"; } -is_domain() { ! is_ipv6 "$1" && str_contains "$1" '[a-zA-Z]'; } -is_phys_dev() { [ "${1:0:1}" = "@" ] && ip l show | grep -E -q "^\\d+\\W+${1:1}"; } -dnsmasq_kill() { killall -q -s HUP dnsmasq; } -dnsmasq_restart() { output 3 'Restarting dnsmasq '; if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then output_okn; else output_failn; fi; } -is_default_dev() { [ "$1" = "$($ip_bin -4 r | grep -m1 'dev' | grep -Eso 'dev [^ ]*' | awk '{print $2}')" ]; } -is_supported_iface_dev() { local n dev; for n in $ifacesSupported; do network_get_device dev "$n"; [ "$1" = "$dev" ] && return 0; done; return 1; } -is_supported_protocol() { grep -o '^[^#]*' /etc/protocols | grep -w -v '0' | grep . | awk '{print $1}' | grep -q "$1"; } -is_service_running_iptables() { [ -x "$iptables" ] && "$iptables" -t mangle -L | grep -q "${iptPrefix}_PREROUTING" >/dev/null 2>&1; } -is_service_running_nft() { [ -x "$nft" ] && [ -n "$(get_mark_nft_chains)" ]; } -# atomic -# is_service_running_nft() { [ -x "$nft" ] && [ -s "$nftPermFile" ]; } -is_service_running() { if is_nft; then is_service_running_nft; else is_service_running_iptables; fi; } -is_netifd_table() { local iface="$1"; [ "$(uci -q get "network.${iface}.ip4table")" = "${packageName}_${iface%6}" ]; } -get_rt_tables_id() { local iface="$1"; grep "${ipTablePrefix}_${iface}\$" '/etc/iproute2/rt_tables' | awk '{print $1;}'; } -get_rt_tables_next_id() { echo "$(($(sort -r -n '/etc/iproute2/rt_tables' | grep -o -E -m 1 "^[0-9]+")+1))"; } -_check_config() { local en; config_get_bool en "$1" 'enabled' 1; [ "$en" -gt 0 ] && _cfg_enabled=0; } -is_config_enabled() { - local cfg="$1" _cfg_enabled=1 - [ -n "$1" ] || return 1 - config_load "$packageName" - config_foreach _check_config "$cfg" - return "$_cfg_enabled" -} -# shellcheck disable=SC2016 -resolveip_to_ipt() { resolveip "$@" | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d'; } -resolveip_to_ipt4() { resolveip_to_ipt -4 "$@"; } -resolveip_to_ipt6() { [ -n "$ipv6_enabled" ] && resolveip_to_ipt -6 "$@"; } -# shellcheck disable=SC2016 -resolveip_to_nftset() { resolveip "$@" | sed -n 'H;${x;s/\n/,/g;s/^,//;p;};d' | tr '\n' ' '; } -resolveip_to_nftset4() { resolveip_to_nftset -4 "$@"; } -resolveip_to_nftset6() { [ -n "$ipv6_enabled" ] && resolveip_to_nftset -6 "$@"; } -# shellcheck disable=SC2016 -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' ' '; } -# shellcheck disable=SC2016 -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' ' '; } -# shellcheck disable=SC3037 -ports_to_nftset() { echo -ne "$value"; } -get_mark_ipt_chains() { [ -n "$(command -v iptables-save)" ] && iptables-save | grep ":${iptPrefix}_MARK_" | awk '{ print $1 }' | sed 's/://'; } -get_mark_nft_chains() { [ -x "$nft" ] && "$nft" list table inet "$nftTable" 2>/dev/null | grep chain | grep "${nftPrefix}_mark_" | awk '{ print $2 }'; } -get_ipsets() { [ -x "$(command -v ipset)" ] && ipset list | grep "${ipsPrefix}_" | awk '{ print $2 }'; } -get_nft_sets() { [ -x "$nft" ] && "$nft" list table inet "$nftTable" 2>/dev/null | grep 'set' | grep "${nftPrefix}_" | awk '{ print $2 }'; } -is_ipset_type_supported() { ipset help hash:"$1" >/dev/null 2>&1; } -ubus_get_status() { ubus call service list "{ 'name': '$packageName' }" | jsonfilter -e "@.${packageName}.instances.main.data.status.${1}"; } -ubus_get_iface() { ubus call service list "{ 'name': '$packageName' }" | jsonfilter -e "@.${packageName}.instances.main.data.interfaces[@.name='${1}']${2:+.$2}"; } -opkg_get_version() { grep -m1 -A1 "Package: $1$" '/usr/lib/opkg/status' | grep -m1 'Version: ' | sed 's|Version: \(.*\)|\1|'; } - -load_package_config() { - config_load "$packageName" - config_get boot_timeout 'config' 'boot_timeout' '30' - config_get_bool enabled 'config' 'enabled' '0' - config_get fw_mask 'config' 'fw_mask' 'ff0000' - config_get icmp_interface 'config' 'icmp_interface' - config_get ignored_interface 'config' 'ignored_interface' - config_get_bool ipv6_enabled 'config' 'ipv6_enabled' '0' - config_get nft_user_set_policy 'config' 'nft_user_set_policy' 'memory' - config_get_bool nft_user_set_counter 'config' 'nft_user_set_counter' '0' - config_get procd_boot_delay 'config' 'procd_boot_delay' '0' - config_get resolver_set 'config' 'resolver_set' - config_get rule_create_option 'config' 'rule_create_option' 'add' - config_get_bool secure_reload 'config' 'secure_reload' '1' - config_get_bool strict_enforcement 'config' 'strict_enforcement' '0' - config_get supported_interface 'config' 'supported_interface' - config_get verbosity 'config' 'verbosity' '2' - config_get wan_ip_rules_priority 'config' 'wan_ip_rules_priority' '30000' - config_get wan_mark 'config' 'wan_mark' '010000' - fw_mask="0x${fw_mask}" - wan_mark="0x${wan_mark}" - [ -n "$ipv6_enabled" ] && [ "$ipv6_enabled" -eq 0 ] && unset ipv6_enabled - . /lib/functions/network.sh - . /usr/share/libubox/jshn.sh - mkdir -p "${dnsmasqFile%/*}" - if is_nft; then - fw_maskXor="$(printf '%#x' "$((fw_mask ^ 0xffffffff))")" - fw_maskXor="${fw_maskXor:-0xff00ffff}" - if [ "$nft_user_set_counter" -eq '0' ]; then - unset nft_user_set_counter - fi - else - case $rule_create_option in - insert|-i|-I) rule_create_option='-I';; - add|-a|-A|*) rule_create_option='-A';; - esac - fi -} - -load_environment() { - local param="$1" validation_result="$2" - load_package_config - case "$param" in - on_start) - if [ -n "$validation_result" ] && [ "$validation_result" != '0' ]; then - output "${_ERROR_}: The $packageName config validation failed!\\n" - output "Please check if the '$packageConfigFile' contains correct values for config options.\\n" - state add 'errorSummary' 'errorConfigValidation' - return 1 - fi - if [ "$enabled" -eq 0 ]; then - state add 'errorSummary' 'errorServiceDisabled' - return 1 - fi - if [ ! -x "$ip_bin" ]; then - state add 'errorSummary' 'errorNoIpFull' - return 1 - fi - if ! is_nft; then - if [ -z "$iptables" ] || [ ! -x "$iptables" ]; then - state add 'errorSummary' 'errorNoIptables' - return 1 - fi - fi - rm -f "$packageLockFile" - resolver 'check_support' - ;; - on_stop) - touch "$packageLockFile" - ;; - esac - load_network "$param" -} - -load_network() { - local i - config_load 'network' - [ -z "$ifacesAll" ] && config_foreach _build_ifaces_all 'interface' - if [ -z "$ifacesSupported" ]; then - config_load 'firewall' - config_foreach _find_firewall_wan_zone 'zone' - for i in $(uci -q get "firewall.${firewallWanZone}.network"); do - is_supported_interface "$i" && ! str_contains "$ifacesSupported" "$1" && ifacesSupported="${ifacesSupported}${i} " - done - config_load 'network' - config_foreach _build_ifaces_supported 'interface' - fi - pbr_find_iface wanIface4 'wan' - [ -n "$ipv6_enabled" ] && pbr_find_iface wanIface6 'wan6' - [ -n "$wanIface4" ] && network_get_gateway wanGW4 "$wanIface4" - [ -n "$wanIface6" ] && network_get_gateway6 wanGW6 "$wanIface6" - wanGW="${wanGW4:-$wanGW6}" -} - -is_wan_up() { - local sleepCount='1' - load_network - while [ -z "$wanGW" ] ; do - load_network - if [ $((sleepCount)) -gt $((boot_timeout)) ] || [ -n "$wanGW" ]; then break; fi - output "$serviceName waiting for wan gateway...\\n" - sleep 1 - network_flush_cache - sleepCount=$((sleepCount+1)) - done - if [ -n "$wanGW" ]; then - return 0 - else - state add 'errorSummary' 'errorNoWanGateway' - return 1 - fi -} - -# shellcheck disable=SC2086 -ipt4() { - local d - [ -x "$iptables" ] || return 1 - for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do - [ "$d" != "$*" ] && "$iptables" $d >/dev/null 2>&1 - done - d="$*"; "$iptables" $d >/dev/null 2>&1 -} - -# shellcheck disable=SC2086 -ipt6() { - local d - [ -n "$ipv6_enabled" ] || return 0 - [ -x "$ip6tables" ] || return 1 - for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do - [ "$d" != "$*" ] && "$ip6tables" $d >/dev/null 2>&1 - done - d="$*" - "$ip6tables" $d >/dev/null 2>&1 -} - -# shellcheck disable=SC2086 -ipt() { - local d failFlagIpv4=1 failFlagIpv6=1 - [ -x "$iptables" ] || return 1 - for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do - if [ "$d" != "$*" ]; then - "$iptables" $d >/dev/null 2>&1 - [ -x "$ip6tables" ] && "$ip6tables" $d >/dev/null 2>&1 - fi - done - d="$*"; "$iptables" $d >/dev/null 2>&1 && failFlagIpv4=0; - if [ -n "$ipv6_enabled" ] && [ -x "$ip6tables" ]; then - "$ip6tables" $d >/dev/null 2>&1 && failFlagIpv6=0 - fi - [ "$failFlagIpv4" -eq 0 ] || [ "$failFlagIpv6" -eq 0 ] -} - -# shellcheck disable=SC2086 -ips4() { [ -x "$ipset" ] && "$ipset" "$@" >/dev/null 2>&1; } -ips6() { [ -x "$ipset" ] && { if [ -n "$ipv6_enabled" ] && [ -n "$*" ]; then "$ipset" "$@" >/dev/null 2>&1; else return 1; fi; }; } -ips() { - local command="$1" iface="$2" target="${3:-dst}" type="${4:-ip}" uid="$5" comment="$6" param="$7" mark="$7" - local ipset4 ipset6 i - local ipv4_error=1 ipv6_error=1 - ipset4="${ipsPrefix}${iface:+_$iface}_4${target:+_$target}${type:+_$type}${uid:+_$uid}" - ipset6="${ipsPrefix}${iface:+_$iface}_6${target:+_$target}${type:+_$type}${uid:+_$uid}" - - [ -x "$ipset" ] || return 1 - - if [ "${#ipset4}" -gt 31 ]; then - state add 'errorSummary' 'errorIpsetNameTooLong' "$ipset4" - return 1 - fi - - case "$command" in - add) - ips4 -q -! add "$ipset4" ["$param"] comment "$comment" && ipv4_error=0 - ips6 -q -! add "$ipset6" ["$param"] comment "$comment" && ipv6_error=0 - ;; - add_agh_element) - [ -n "$ipv6_enabled" ] || unset ipset6 - echo "${param}/${ipset4}${ipset6:+,$ipset6}" >> "$aghIpsetFile" && ipv4_error=0 - ;; - add_dnsmasq_element) - [ -n "$ipv6_enabled" ] || unset ipset6 - echo "ipset=/${param}/${ipset4}${ipset6:+,$ipset6} # $comment" >> "$dnsmasqFile" && ipv4_error=0 - ;; - create) - ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0 - ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0 - ;; - create_agh_set) - ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0 - ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0 - ;; - create_dnsmasq_set) - ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0 - ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0 - ;; - create_user_set) - case "$type" in - ip|net) - ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0 - ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv6_error=0 - case "$target" in - dst) - ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" dst -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0 - ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" dst -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0 - ;; - src) - ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0 - ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0 - ;; - esac - ;; - mac) - ips4 -q -! create "$ipset4" "hash:$type" comment && ipv4_error=0 - ips6 -q -! create "$ipset6" "hash:$type" comment family inet6 && ipv4_error=0 - ipt4 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0 - ipt6 -t mangle -A "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0 - ;; - esac - ;; - delete|destroy) - ips4 -q -! destroy "$ipset4" && ipv4_error=0 - ips6 -q -! destroy "$ipset6" && ipv6_error=0 - ;; - delete_user_set) - ips4 -q -! destroy "$ipset4" && ipv4_error=0 - ips6 -q -! destroy "$ipset6" family inet6 && ipv6_error=0 - case "$type" in - ip|net) - case "$target" in - dst) - ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" dst -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0 - ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" dst -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0 - ;; - src) - ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0 - ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0 - ;; - esac - ;; - mac) - ipt4 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset4" src -g "${iptPrefix}_MARK_${mark}" && ipv4_error=0 - ipt6 -t mangle -D "${iptPrefix}_PREROUTING" -m set --match-set "$ipset6" src -g "${iptPrefix}_MARK_${mark}" && ipv6_error=0 - ;; - esac - ;; - flush|flush_user_set) - ips4 -q -! flush "$ipset4" && ipv4_error=0 - ips6 -q -! flush "$ipset6" && ipv6_error=0 - ;; - esac - if [ "$ipv4_error" -eq '0' ] || [ "$ipv6_error" -eq '0' ]; then - return 0 - else - return 1 - fi -} - -# atomic -#nfta() { echo "$@" >> "$nftTempFile"; } -#nfta4() { echo "$@" >> "$nftTempFile"; } -#nfta6() { [ -z "$ipv6_enabled" ] || echo "$@" >> "$nftTempFile"; } -#nft() { nfta "$@"; [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; } -#nft4() { nfta "$@"; [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; } -#nft6() { nfta "$@"; [ -n "$ipv6_enabled" ] || return 0; [ -x "$nft" ] && [ -n "$*" ] && "$nft" "$@" >/dev/null 2>&1; } -nft() { [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; } -nft4() { [ -x "$nft" ] && "$nft" "$@" >/dev/null 2>&1; } -nft6() { [ -n "$ipv6_enabled" ] || return 0; [ -x "$nft" ] && [ -n "$*" ] && "$nft" "$@" >/dev/null 2>&1; } -nftset() { - local command="$1" iface="$2" target="${3:-dst}" type="${4:-ip}" uid="$5" comment="$6" param="$7" mark="$7" - local nftset4 nftset6 i param4 param6 - local ipv4_error=1 ipv6_error=1 - nftset4="${nftPrefix}${iface:+_$iface}_4${target:+_$target}${type:+_$type}${uid:+_$uid}" - nftset6="${nftPrefix}${iface:+_$iface}_6${target:+_$target}${type:+_$type}${uid:+_$uid}" - - [ -x "$nft" ] || return 1 - - if [ "${#nftset4}" -gt 255 ]; then - state add 'errorSummary' 'errorNftsetNameTooLong' "$nftset4" - return 1 - fi - - case "$command" in - add) - if is_netmask "$param" || is_ipv4 "$param" || is_ipv6 "$param" \ - || is_mac_address "$param" || is_list "$param"; then - nft4 add element inet "$nftTable" "$nftset4" "{ $param }" && ipv4_error=0 - nft6 add element inet "$nftTable" "$nftset6" "{ $param }" && ipv6_error=0 - else - if [ "$target" = 'src' ]; then - param4="$(ipv4_leases_to_nftset "$param")" - param6="$(ipv6_leases_to_nftset "$param")" - fi - [ -z "$param4" ] && param4="$(resolveip_to_nftset4 "$param")" - [ -z "$param6" ] && param6="$(resolveip_to_nftset6 "$param")" - if [ -z "$param4" ] && [ -z "$param6" ]; then - state add 'errorSummary' 'errorFailedToResolve' "$param" - else - nft4 add element inet "$nftTable" "$nftset4" "{ $param4 }" && ipv4_error=0 - nft6 add element inet "$nftTable" "$nftset6" "{ $param6 }" && ipv6_error=0 - fi - fi - ;; - add_dnsmasq_element) - [ -n "$ipv6_enabled" ] || unset nftset6 - echo "nftset=/${param}/4#inet#${nftTable}#${nftset4}${nftset6:+,6#inet#${nftTable}#$nftset6} # $comment" >> "$dnsmasqFile" && ipv4_error=0 - ;; - create) - case "$type" in - ip|net) - nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; counter; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0 - nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; counter; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0 - ;; - mac) - nft4 add set inet "$nftTable" "$nftset4" "{ type ether_addr; counter; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0 - nft6 add set inet "$nftTable" "$nftset6" "{ type ether_addr; counter; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0 - ;; - esac - ;; - create_dnsmasq_set) - nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; counter; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0 - nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; counter; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0 - ;; - create_user_set) - case "$type" in - ip|net) - 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 - 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 - case "$target" in - dst) - nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ip daddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0 - nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ip daddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0 - ;; - src) - nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ip saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0 - nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ip saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0 - ;; - esac - ;; - mac) - 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 - 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 - nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0 - nft add rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0 - ;; - esac - ;; - delete|destroy) - nft delete set inet "$nftTable" "$nftset4" && ipv4_error=0 - nft delete set inet "$nftTable" "$nftset6" && ipv6_error=0 - ;; - delete_user_set) - nft delete set inet "$nftTable" "$nftset4" && ipv4_error=0 - nft delete set inet "$nftTable" "$nftset6" && ipv6_error=0 - case "$type" in - ip|net) - case "$target" in - dst) - nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ip daddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0 - nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ip daddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0 - ;; - src) - nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ip saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0 - nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ip saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0 - ;; - esac - ;; - mac) - nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset4}" goto "${nftPrefix}_mark_${mark}" && ipv4_error=0 - nft delete rule inet "$nftTable" "${nftPrefix}_prerouting" ether saddr "@${nftset6}" goto "${nftPrefix}_mark_${mark}" && ipv6_error=0 - ;; - esac - ;; - flush|flush_user_set) - nft flush set inet "$nftTable" "$nftset4" && ipv4_error=0 - nft flush set inet "$nftTable" "$nftset6" && ipv6_error=0 - ;; - esac -# nft6 returns true if IPv6 support is not enabled - [ -z "$ipv6_enabled" ] && ipv6_error='1' - if [ "$ipv4_error" -eq '0' ] || [ "$ipv6_error" -eq '0' ]; then - return 0 - else - return 1 - fi -} - -cleanup_rt_tables() { sed -i '/pbr_/d' '/etc/iproute2/rt_tables'; sync; } -cleanup_dnsmasq() { [ -s "$dnsmasqFile" ] && resolverStoredHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')" && rm "$dnsmasqFile" >/dev/null 2>&1; } - -cleanup_main_chains() { - local i - for i in $chainsList; do - i="$(str_to_lower "$i")" - nft flush chain inet "$nftTable" "${nftPrefix}_${i}" - done - for i in $chainsList; do - i="$(str_to_upper "$i")" - ipt -t mangle -D "${i}" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}" - ipt -t mangle -F "${iptPrefix}_${i}" - ipt -t mangle -X "${iptPrefix}_${i}" - done -} - -cleanup_marking_chains() { - local i - for i in $(get_mark_nft_chains); do - nft flush chain inet "$nftTable" "$i" - nft delete chain inet "$nftTable" "$i" - done - for i in $(get_mark_ipt_chains); do - ipt -t mangle -F "$i" - ipt -t mangle -X "$i" - done -} - -cleanup_sets() { - local i - for i in $(get_nft_sets); do - nft flush set inet "$nftTable" "$i" - nft delete set inet "$nftTable" "$i" - done - for i in $(get_ipsets); do - ipset -q -! flush "$i" >/dev/null 2>&1 - ipset -q -! destroy "$i" >/dev/null 2>&1 - done -} - -state() { - local action="$1" param="$2" value="${3//#/_}" - shift 3 -# shellcheck disable=SC2124 - local extras="$@" - local line error_id error_extra label - case "$action" in - add) - line="$(eval echo "\$$param")" - eval "$param"='${line:+$line#}${value}${extras:+ $extras}' - ;; - json) - json_init - json_add_object "$packageName" - case "$param" in - errorSummary) - json_add_array 'errors';; - warningSummary) - json_add_array 'warnings';; - esac - if [ -n "$(eval echo "\$$param")" ]; then - while read -r line; do - if str_contains "$line" ' '; then - error_id="${line% *}" - error_extra="${line#* }" - else - error_id="$line" - fi - json_add_object - json_add_string 'id' "$error_id" - json_add_string 'extra' "$error_extra" - json_close_object - done </dev/null 2>&1 - rm -f "$aghIpsetFile" - rm -f "$dnsmasqFile" - return 0 - fi - - case "$resolver_set" in - ''|none) - case "$param" in - add_resolver_element) return 1;; - create_resolver_set) return 1;; - check_support) return 0;; - cleanup) return 0;; - configure) return 0;; - init) return 0;; - init_end) return 0;; - kill) return 0;; - reload) return 0;; - restart) return 0;; - compare_hash) return 0;; - store_hash) return 0;; - esac - ;; - adguardhome.ipset) - case "$param" in - add_resolver_element) - [ -n "$resolver_set_supported" ] && ips 'add_agh_element' "$@";; - create_resolver_set) - [ -n "$resolver_set_supported" ] && ips 'create_agh_set' "$@";; - check_support) - if [ ! -x "$ipset" ]; then - state add 'errorSummary' 'errorNoIpset' - return 1 - fi - if [ -n "$agh" ] && [ -s "$aghConfigFile" ]; then - agh_version="$($agh --version | sed 's|AdGuard Home, version v\(.*\)|\1|' | sed 's|-.*||')" - if is_greater_or_equal "$agh_version" '0.107.13'; then - resolver_set_supported='true' - return 0 - else - state add 'warningSummary' 'warningAGHVersionTooLow' "$agh_version" - return 1 - fi - else - state add 'warningSummary' 'warningResolverNotSupported' - return 1 - fi - ;; - cleanup) - [ -z "$resolver_set_supported" ] && return 0 - rm -f "$aghIpsetFile" - sed -i "/ipset_file: ${aghIpsetFile}/d" "$aghConfigFile" >/dev/null 2>&1 - ;; - configure) - [ -z "$resolver_set_supported" ] && return 1 - mkdir -p "${aghIpsetFile%/*}" - touch "$aghIpsetFile" - sed -i '/ipset_file/d' "$aghConfigFile" >/dev/null 2>&1 - sed -i "/ ipset:/a \ \ ipset_file: $aghIpsetFile" "$aghConfigFile" - ;; - init) :;; - init_end) :;; - kill) - [ -n "$resolver_set_supported" ] && [ -n "$agh" ] && killall -q -s HUP "$agh";; - reload) - [ -z "$resolver_set_supported" ] && return 1 - output 3 'Reloading adguardhome ' - if /etc/init.d/adguardhome reload >/dev/null 2>&1; then - output_okn - return 0 - else - output_failn - return 1 - fi - ;; - restart) - [ -z "$resolver_set_supported" ] && return 1 - output 3 'Restarting adguardhome ' - if /etc/init.d/adguardhome restart >/dev/null 2>&1; then - output_okn - return 0 - else - output_failn - return 1 - fi - ;; - compare_hash) - [ -z "$resolver_set_supported" ] && return 1 - local resolverNewHash - if [ -s "$aghIpsetFile" ]; then - resolverNewHash="$(md5sum $aghIpsetFile | awk '{ print $1; }')" - fi - [ "$resolverNewHash" != "$resolverStoredHash" ] - ;; - store_hash) - [ -s "$aghIpsetFile" ] && resolverStoredHash="$(md5sum $aghIpsetFile | awk '{ print $1; }')";; - esac - ;; - dnsmasq.ipset) - case "$param" in - add_resolver_element) - [ -n "$resolver_set_supported" ] && ips 'add_dnsmasq_element' "$@";; - create_resolver_set) - [ -n "$resolver_set_supported" ] && ips 'create_dnsmasq_set' "$@";; - check_support) - if [ ! -x "$ipset" ]; then - state add 'errorSummary' 'errorNoIpset' - return 1 - fi - if ! dnsmasq -v 2>/dev/null | grep -q 'no-ipset' && dnsmasq -v 2>/dev/null | grep -q 'ipset'; then - resolver_set_supported='true' - return 0 - else - state add 'warningSummary' 'warningResolverNotSupported' - return 1 - fi - ;; - cleanup) - [ -n "$resolver_set_supported" ] && rm -f "$dnsmasqFile";; - configure) - [ -n "$resolver_set_supported" ] && mkdir -p "${dnsmasqFile%/*}";; - init) :;; - init_end) :;; - kill) - [ -n "$resolver_set_supported" ] && killall -q -s HUP dnsmasq;; - reload) - [ -z "$resolver_set_supported" ] && return 1 - output 3 'Reloading dnsmasq ' - if /etc/init.d/dnsmasq reload >/dev/null 2>&1; then - output_okn - return 0 - else - output_failn - return 1 - fi - ;; - restart) - [ -z "$resolver_set_supported" ] && return 1 - output 3 'Restarting dnsmasq ' - if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then - output_okn - return 0 - else - output_failn - return 1 - fi - ;; - compare_hash) - [ -z "$resolver_set_supported" ] && return 1 - local resolverNewHash - if [ -s "$dnsmasqFile" ]; then - resolverNewHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')" - fi - [ "$resolverNewHash" != "$resolverStoredHash" ] - ;; - store_hash) - [ -s "$dnsmasqFile" ] && resolverStoredHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')";; - esac - ;; - dnsmasq.nftset) - case "$param" in - add_resolver_element) - [ -n "$resolver_set_supported" ] && nftset 'add_dnsmasq_element' "$@";; - create_resolver_set) - [ -n "$resolver_set_supported" ] && nftset 'create_dnsmasq_set' "$@";; - check_support) - if [ ! -x "$nft" ]; then - state add 'errorSummary' 'errorNoNft' - return 1 - fi - if ! dnsmasq -v 2>/dev/null | grep -q 'no-nftset' && dnsmasq -v 2>/dev/null | grep -q 'nftset'; then - resolver_set_supported='true' - return 0 - else - state add 'warningSummary' 'warningResolverNotSupported' - return 1 - fi - ;; - cleanup) - [ -n "$resolver_set_supported" ] && rm -f "$dnsmasqFile";; - configure) - [ -n "$resolver_set_supported" ] && mkdir -p "${dnsmasqFile%/*}";; - init) :;; - init_end) :;; - kill) - [ -n "$resolver_set_supported" ] && killall -q -s HUP dnsmasq;; - reload) - [ -z "$resolver_set_supported" ] && return 1 - output 3 'Reloading dnsmasq ' - if /etc/init.d/dnsmasq reload >/dev/null 2>&1; then - output_okn - return 0 - else - output_failn - return 1 - fi - ;; - restart) - [ -z "$resolver_set_supported" ] && return 1 - output 3 'Restarting dnsmasq ' - if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then - output_okn - return 0 - else - output_failn - return 1 - fi - ;; - compare_hash) - [ -z "$resolver_set_supported" ] && return 1 - local resolverNewHash - if [ -s "$dnsmasqFile" ]; then - resolverNewHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')" - fi - [ "$resolverNewHash" != "$resolverStoredHash" ] - ;; - store_hash) - [ -s "$dnsmasqFile" ] && resolverStoredHash="$(md5sum $dnsmasqFile | awk '{ print $1; }')";; - esac - ;; - unbound.ipset) - case "$param" in - add_resolver_element) :;; - create_resolver_set) :;; - check_support) :;; - cleanup) :;; - configure) :;; - init) :;; - init_end) :;; - kill) :;; - reload) :;; - restart) :;; - compare_hash) :;; - store_hash) :;; - esac - ;; - unbound.nftset) - case "$param" in - add_resolver_element) :;; - create_resolver_set) :;; - check_support) :;; - cleanup) :;; - configure) :;; - init) :;; - init_end) :;; - kill) :;; - reload) :;; - restart) :;; - compare_hash) :;; - store_hash) :;; - esac - ;; - esac -} - -trap_process() { - output "\\n" - output "Unexpected exit or service termination: '${1}'!\\n" - state add 'errorSummary' 'errorUnexpectedExit' "$1" - traffic_killswitch 'remove' -} - -traffic_killswitch() { - local s=0 - case "$1" in - insert) - local lan_subnet wan_device - [ "$secure_reload" -ne 0 ] || return 0 - for i in $serviceTrapSignals; do -# shellcheck disable=SC2064 - trap "trap_process $i" "$i" - done - output 3 'Activating traffic killswitch ' - network_get_subnet lan_subnet 'lan' - network_get_physdev wan_device 'wan' - if is_nft; then - nft add chain inet "$nftTable" "${nftPrefix}_killswitch" '{ type filter hook forward priority 0; policy accept; }' || s=1 - nft add rule inet "$nftTable" "${nftPrefix}_killswitch" oifname "$wan_device" ip saddr "$lan_subnet" counter reject || s=1 - else - ipt -N "${iptPrefix}_KILLSWITCH" || s=1 - ipt -A "${iptPrefix}_KILLSWITCH" -s "$lan_subnet" -o "$wan_device" -j REJECT || s=1 - ipt -I FORWARD -j "${iptPrefix}_KILLSWITCH" || s=1 - fi - if [ "$s" -eq 0 ]; then - output_okn - else - output_failn - fi - ;; - remove) - if [ "$secure_reload" -ne 0 ]; then - output 3 'Deactivating traffic killswitch ' - fi - if is_nft; then - nft flush chain inet "$nftTable" "${nftPrefix}_killswitch" || s=1 - nft delete chain inet "$nftTable" "${nftPrefix}_killswitch" || s=1 - else - ipt -D FORWARD -j "${iptPrefix}_KILLSWITCH" || s=1 - ipt -F "${iptPrefix}_KILLSWITCH" || s=1 - ipt -X "${iptPrefix}_KILLSWITCH" || s=1 - fi - if [ "$secure_reload" -ne 0 ]; then - if [ "$s" -eq 0 ]; then - output_okn - else - output_failn - fi - fi -# shellcheck disable=SC2086 - trap - $serviceTrapSignals - ;; - esac -} - -policy_routing_tor() { if is_nft; then policy_routing_tor_nft "$@"; else policy_routing_tor_iptables "$@"; fi; } -policy_routing_tor_iptables() { - local comment="$1" iface="$2" src_addr="$3" src_port="$4" dest_addr="$5" dest_port="$6" proto chain uid="$9" - proto="$(str_to_lower "$7")" - chain="$(str_to_upper "$8")" - chain="${chain:-PREROUTING}" - if [ -n "${src_addr}${src_port}${dest_port}" ]; then - state add 'warningSummary' 'warningTorUnsetParams' "$comment" - fi - if [ -n "$proto" ] && [ "$proto" != "all" ]; then - state add 'warningSummary' 'warningTorUnsetProto' "$comment" - fi - if [ "$chain" != "PREROUTING" ]; then - state add 'warningSummary' 'warningTorUnsetChainIpt' "$comment" - fi - if ! resolver 'add_resolver_element' "$iface" 'dst' 'ip' '' "${comment}: $dest_addr" "$dest_addr"; then - processPolicyError='true' - state add 'errorSummary' 'errorResolver' "'add_resolver_element' '$iface' 'dst' 'ip' '${comment}: $dest_addr' '$dest_addr'" - return 1 - fi - return 0 -} -policy_routing_tor_nft() { - local comment="$1" iface="$2" src_addr="$3" src_port="$4" dest_addr="$5" dest_port="$6" proto chain uid="$9" - proto="$(str_to_lower "$7")" - chain="$(str_to_lower "$8")" - chain="${chain:-prerouting}" - if [ -n "${src_addr}${src_port}${dest_port}" ]; then - state add 'warningSummary' 'warningTorUnsetParams' "$comment" - fi - if [ -n "$proto" ] && [ "$proto" != "all" ]; then - state add 'warningSummary' 'warningTorUnsetProto' "$comment" - fi - if [ "$chain" != "prerouting" ]; then - state add 'warningSummary' 'warningTorUnsetChainNft' "$comment" - fi - if ! resolver 'add_resolver_element' "$iface" 'dst' 'ip' '' "${comment}: $dest_addr" "$dest_addr"; then - processPolicyError='true' - state add 'errorSummary' 'errorResolver' "'add_resolver_element' '$iface' 'dst' 'ip' '${comment}: $dest_addr' '$dest_addr'" - return 1 - fi - return 0 -} - -policy_routing() { if is_nft; then policy_routing_nft "$@"; else policy_routing_iptables "$@"; fi; } -policy_routing_iptables() { - local mark param4 param6 i negation value dest ipInsertOption="-A" - local ip4error='1' ip6error='1' - local name="$1" iface="$2" laddr="$3" lport="$4" raddr="$5" rport="$6" proto chain uid="$9" - proto="$(str_to_lower "$7")" - chain="$(str_to_upper "$8")" - chain="${chain:-PREROUTING}" - mark=$(eval echo "\$mark_${iface//-/_}") - - if [ -n "$ipv6_enabled" ] && { is_ipv6 "$laddr" || is_ipv6 "$raddr"; }; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessNoIpv6' "$name" - return 1 - fi - - if [ -n "$mark" ]; then - dest="-g ${iptPrefix}_MARK_${mark}" - elif [ "$iface" = "ignore" ]; then - dest="-j RETURN" - else - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessUnknownFwmark' "$iface" - return 1 - fi - - if is_family_mismatch "$laddr" "$raddr"; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessMismatchFamily' "${name}: '$laddr' '$raddr'" - return 1 - fi - - if [ -z "$proto" ]; then - if [ -n "${lport}${rport}" ]; then - proto='tcp udp' - else - proto='all' - fi - fi - - for i in $proto; do - if [ "$i" = 'all' ]; then - param4="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest" - param6="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest" - elif ! is_supported_protocol "$i"; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessUnknownProtocol' "${name}: '$i'" - return 1 - else - param4="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest -p $i" - param6="-t mangle ${ipInsertOption} ${iptPrefix}_${chain} $dest -p $i" - fi - - if [ -n "$laddr" ]; then - if [ "${laddr:0:1}" = "!" ]; then - negation='!'; value="${laddr:1}" - else - unset negation; value="$laddr"; - fi - if is_phys_dev "$value"; then - param4="$param4 $negation -m physdev --physdev-in ${value:1}" - param6="$param6 $negation -m physdev --physdev-in ${value:1}" - elif is_netmask "$value"; then - local target='src' type='net' - if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \ - ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then - param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target" - param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target" - else - param4="$param4 $negation -s $value" - param6="$param6 $negation -s $value" - fi - elif is_mac_address "$value"; then - local target='src' type='mac' - if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \ - ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then - param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target" - param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target" - else - param4="$param4 -m mac $negation --mac-source $value" - param6="$param6 -m mac $negation --mac-source $value" - fi - else - local target='src' type='ip' - if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $laddr" && \ - ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $laddr" "$value"; then - param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target" - param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target" - else - local resolvedIP4 resolvedIP6 - resolvedIP4="$(resolveip_to_ipt4 "$value")" - resolvedIP6="$(resolveip_to_ipt6 "$value")" - if [ -z "$resolvedIP4" ] && [ -z "$resolvedIP6" ]; then - state add 'errorSummary' 'errorFailedToResolve' "$value" - fi - param4="$param4 $negation -s $resolvedIP4" - param6="$param6 $negation -s $resolvedIP6" - fi - fi - fi - - if [ -n "$lport" ]; then - if [ "${lport:0:1}" = "!" ]; then - negation='!'; value="${lport:1}" - else - unset negation; value="$lport"; - fi - param4="$param4 -m multiport $negation --sport ${value//-/:}" - param6="$param6 -m multiport $negation --sport ${value//-/:}" - fi - - if [ -n "$raddr" ]; then - if [ "${raddr:0:1}" = "!" ]; then - negation='!'; value="${raddr:1}" - else - unset negation; value="$raddr"; - fi - if is_netmask "$value"; then - local target='dst' type='net' - if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \ - ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then - param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target" - param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target" - else - param4="$param4 $negation -d $value" - param6="$param6 $negation -d $value" - fi - elif is_domain "$value"; then - local target='dst' type='ip' - if resolver 'create_resolver_set' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \ - resolver 'add_resolver_element' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then - param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target" - param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target" - elif ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \ - ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then - param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target" - param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target" - else - local resolvedIP4 resolvedIP6 - resolvedIP4="$(resolveip_to_ipt4 "$value")" - resolvedIP6="$(resolveip_to_ipt6 "$value")" - if [ -z "$resolvedIP4" ] && [ -z "$resolvedIP6" ]; then - state add 'errorSummary' 'errorFailedToResolve' "$value" - fi - param4="$param4 $negation -d $resolvedIP4" - param6="$param6 $negation -d $resolvedIP6" - fi - else - local target='dst' type='ip' - if ips 'create' "$iface" "$target" "$type" "$uid" "${name}: $raddr" && \ - ips 'add' "$iface" "$target" "$type" "$uid" "${name}: $raddr" "$value"; then - param4="$param4 -m set $negation --match-set ${ipsPrefix}_${iface}_4_${target}_${type}_${uid} $target" - param6="$param6 -m set $negation --match-set ${ipsPrefix}_${iface}_6_${target}_${type}_${uid} $target" - else - param4="$param4 $negation -d $value" - param6="$param6 $negation -d $value" - fi - fi - fi - - if [ -n "$rport" ]; then - if [ "${rport:0:1}" = "!" ]; then - negation='!'; value="${rport:1}" - else - unset negation; value="$rport"; - fi - param4="$param4 -m multiport $negation --dport ${value//-/:}" - param6="$param6 -m multiport $negation --dport ${value//-/:}" - fi - - if [ -n "$name" ]; then - param4="$param4 -m comment --comment $(str_extras_to_underscore "$name")" - param6="$param6 -m comment --comment $(str_extras_to_underscore "$name")" - fi - - local ipv4_error='0' ipv6_error='0' - if [ "$param4" = "$param6" ]; then - ipt4 "$param4" || ipv4_error='1' - else - ipt4 "$param4" || ipv4_error='1' - ipt6 "$param6" || ipv6_error='1' - fi - - if [ -n "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ] && [ "$ipv6_error" -eq '1' ]; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessInsertionFailed' "$name" - state add 'errorSummary' 'errorPolicyProcessCMD' "iptables $param4" - state add 'errorSummary' 'errorPolicyProcessCMD' "iptables $param6" - logger -t "$packageName" "ERROR: iptables $param4" - logger -t "$packageName" "ERROR: iptables $param6" - elif [ -z "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ]; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessInsertionFailedIpv4' "$name" - state add 'errorSummary' 'errorPolicyProcessCMD' "iptables $param4" - logger -t "$packageName" "ERROR: iptables $param4" - fi - - done -} -policy_routing_nft() { - local mark i nftInsertOption='add' - local param4 param6 proto_i negation value dest - local ip4Flag='ip' ip6Flag='ip6' - local name="$1" iface="$2" laddr="$3" lport="$4" raddr="$5" rport="$6" proto chain uid="$9" - proto="$(str_to_lower "$7")" - chain="$(str_to_lower "$8")" - chain="${chain:-prerouting}" - mark=$(eval echo "\$mark_${iface//-/_}") - - if [ -z "$ipv6_enabled" ] && { is_ipv6 "$src_addr" || is_ipv6 "$dest_addr"; }; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessNoIpv6' "$name" - return 1 - fi - - if [ -n "$mark" ]; then - dest="goto ${nftPrefix}_mark_${mark}" - elif [ "$iface" = "ignore" ]; then - dest="return" - else - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessUnknownFwmark' "$iface" - return 1 - fi - - if is_family_mismatch "$src_addr" "$dest_addr"; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessMismatchFamily' "${name}: '$laddr' '$raddr'" - return 1 - fi - - if [ -z "$proto" ]; then - if [ -n "${src_port}${dest_port}" ]; then - proto='tcp udp' - else - proto='all' - fi - fi - - for proto_i in $proto; do - unset param4 - unset param6 - if [ "$proto_i" = 'all' ]; then - unset proto_i - elif ! is_supported_protocol "$proto_i"; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessUnknownProtocol' "${name}: '$proto_i'" - return 1 - fi - - if [ -n "$src_addr" ]; then - if [ "${src_addr:0:1}" = "!" ]; then - negation='!='; value="${src_addr:1}" - else - unset negation; value="$src_addr"; - fi - if is_phys_dev "$value"; then - param4="$param4 iifname $negation ${value:1}" - param6="$param6 iifname $negation ${value:1}" - elif is_mac_address "$value"; then - local target='src' type='mac' - if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \ - nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then - param4="$param4 ether saddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}" - param6="$param6 ether saddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}" - else - param4="$param4 ether saddr $negation $value" - param6="$param6 ether saddr $negation $value" - fi - else - local target='src' type='ip' - if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \ - nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then - param4="$param4 $ip4Flag saddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}" - param6="$param6 $ip6Flag saddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}" - else - param4="$param4 $ip4Flag saddr $negation $value" - param6="$param6 $ip6Flag saddr $negation $value" - fi - fi - fi - - if [ -n "$dest_addr" ]; then - if [ "${dest_addr:0:1}" = "!" ]; then - negation='!='; value="${dest_addr:1}" - else - unset negation; value="$dest_addr"; - fi - if is_phys_dev "$value"; then - param4="$param4 oifname $negation ${value:1}" - param6="$param6 oifname $negation ${value:1}" - elif is_domain "$value"; then - local target='dst' type='ip' - if resolver 'create_resolver_set' "$iface" "$target" "$type" "$uid" "$name" && \ - resolver 'add_resolver_element' "$iface" "$target" "$type" "$uid" "$name" "$value"; then - param4="$param4 $ip4Flag daddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}" - param6="$param6 $ip6Flag daddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}" - elif nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \ - nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then - param4="$param4 $ip4Flag daddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}" - param6="$param6 $ip6Flag daddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}" - else - local resolvedIP4 resolvedIP6 - resolvedIP4="$(resolveip_to_nftset4 "$value")" - resolvedIP6="$(resolveip_to_nftset6 "$value")" - if [ -z "$resolvedIP4" ] && [ -z "$resolvedIP6" ]; then - state add 'errorSummary' 'errorFailedToResolve' "$value" - fi - param4="$param4 $ip4Flag daddr $negation { $resolvedIP4 }" - param6="$param6 $ip6Flag daddr $negation { $resolvedIP6 }" - fi - else - local target='dst' type='ip' - if nftset 'create' "$iface" "$target" "$type" "$uid" "$name" && \ - nftset 'add' "$iface" "$target" "$type" "$uid" "$name" "$value"; then - param4="$param4 $ip4Flag daddr $negation @${nftPrefix}_${iface}_4_${target}_${type}_${uid}" - param6="$param6 $ip6Flag daddr $negation @${nftPrefix}_${iface}_6_${target}_${type}_${uid}" - else - param4="$param4 $ip4Flag daddr $negation $value" - param6="$param6 $ip6Flag daddr $negation $value" - fi - fi - fi - - if [ -n "$src_port" ]; then - if [ "${src_port:0:1}" = "!" ]; then - negation='!='; value="${src_port:1}" - else - unset negation; value="$src_port"; - fi - param4="$param4 ${proto_i:+$proto_i }sport $negation {$(ports_to_nftset "$value")}" - param6="$param6 ${proto_i:+$proto_i }sport $negation {$(ports_to_nftset "$value")}" - fi - - if [ -n "$dest_port" ]; then - if [ "${dest_port:0:1}" = "!" ]; then - negation='!='; value="${dest_port:1}" - else - unset negation; value="$dest_port"; - fi - param4="$param4 ${proto_i:+$proto_i }dport $negation {$(ports_to_nftset "$value")}" - param6="$param6 ${proto_i:+$proto_i }dport $negation {$(ports_to_nftset "$value")}" - fi - - param4="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} $param4 $dest comment \"$name\"" - param6="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} $param6 $dest comment \"$name\"" - - local ipv4_error='0' ipv6_error='0' - if [ "$nftPrevParam4" != "$param4" ]; then - nft4 "$param4" || ipv4_error='1' - nftPrevParam4="$param4" - fi - if [ "$nftPrevParam6" != "$param6" ]; then - nft6 "$param6" || ipv6_error='1' - nftPrevParam6="$param6" - fi - - if [ -n "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ] && [ "$ipv6_error" -eq '1' ]; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessInsertionFailed' "$name" - state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param4" - state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param6" - logger -t "$packageName" "ERROR: nft $param4" - logger -t "$packageName" "ERROR: nft $param6" - elif [ -z "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ]; then - processPolicyError='true' - state add 'errorSummary' 'errorPolicyProcessInsertionFailedIpv4' "$name" - state add 'errorSummary' 'errorPolicyProcessCMD' "nft $param4" - logger -t "$packageName" "ERROR: nft $param4" - fi - - done -} - -policy_process() { - local i j uid="$9" - if [ -z "$uid" ]; then # first non-recursive call - [ "$enabled" -gt 0 ] || return 0 - unset processPolicyError - uid="$1" - if is_nft; then - chain="$(str_to_lower "$chain")" - else - chain="$(str_to_upper "$chain")" - fi - proto="$(str_to_lower "$proto")" - [ "$proto" = 'auto' ] && unset proto - [ "$proto" = 'all' ] && unset proto - output 2 "Routing '$name' via $interface " - if [ -z "${src_addr}${src_port}${dest_addr}${dest_port}" ]; then - state add 'errorSummary' 'errorPolicyNoSrcDest' "$name" - output_fail; return 1; - fi - if [ -z "$interface" ]; then - state add 'errorSummary' 'errorPolicyNoInterface' "$name" - output_fail; return 1; - fi - if ! is_supported_interface "$interface"; then - state add 'errorSummary' 'errorPolicyUnknownInterface' "$name" - output_fail; return 1; - fi - src_port="${src_port// / }"; src_port="${src_port// /,}"; src_port="${src_port//,\!/ !}"; - dest_port="${dest_port// / }"; dest_port="${dest_port// /,}"; dest_port="${dest_port//,\!/ !}"; -# if is_nft; then -# nftset 'flush' "$interface" "dst" "ip" "$uid" -# nftset 'flush' "$interface" "src" "ip" "$uid" -# nftset 'flush' "$interface" "src" "mac" "$uid" -# else -# ips 'flush' "$interface" "dst" "ip" "$uid" -# ips 'flush' "$interface" "src" "ip" "$uid" -# ips 'flush' "$interface" "src" "mac" "$uid" -# fi - policy_process "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid" - if [ -n "$processPolicyError" ]; then - output_fail - else - output_ok - fi - else # recursive call, get options from passed variables - local name="$1" interface="$2" src_addr="$3" src_port="$4" dest_addr="$5" dest_port="$6" proto="$7" chain="$8" - if str_contains "$src_addr" '[ ;\{\}]'; then - 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 - elif str_contains "$src_port" '[ ;\{\}]'; then - 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 - elif str_contains "$dest_addr" '[ ;\{\}]'; then - 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 - elif str_contains "$dest_port" '[ ;\{\}]'; then - 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 - elif str_contains "$proto" '[ ;\{\}]'; then - 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 - else - if is_tor "$interface"; then - policy_routing_tor "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid" - else - policy_routing "$name" "$interface" "$src_addr" "$src_port" "$dest_addr" "$dest_port" "$proto" "$chain" "$uid" - fi - fi - fi -} - -interface_process_tor() { if is_nft; then interface_process_tor_nft "$@"; else interface_process_tor_iptables "$@"; fi; } -interface_process_tor_iptables() { - local s=0 iface="$1" action="$2" - local displayText set_name4 set_name6 - local dnsPort trafficPort - case "$action" in - reload) - displayText="${iface}/53->${dnsPort}/80,443->${trafficPort}" - gatewaySummary="${gatewaySummary}${displayText}\\n" - ;; - destroy) - for i in $chainsList; do - i="$(str_to_upper "$i")" - ipt -t nat -D "${i}" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}" - ipt -t nat -F "${iptPrefix}_${i}"; ipt -t nat -X "${iptPrefix}_${i}"; - done - ;; - create) - output 2 "Creating TOR redirects " - dnsPort="$(grep -m1 DNSPort /etc/tor/torrc | awk -F: '{print $2}')" - trafficPort="$(grep -m1 TransPort /etc/tor/torrc | awk -F: '{print $2}')" - dnsPort="${dnsPort:-9053}"; trafficPort="${trafficPort:-9040}"; - for i in $chainsList; do - i="$(str_to_upper "$i")" - ipt -t nat -N "${iptPrefix}_${i}" - ipt -t nat -A "$i" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}" - done - if resolver 'create_resolver_set' "$iface" 'dst' 'ip' && ips 'flush' "$iface" 'dst' 'ip'; then - set_name4="${ipsPrefix}_${iface}_4_dst_ip" - for i in $chainsList; do - i="$(str_to_upper "$i")" - 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 - 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 - 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 - 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 - 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 - done - else - s=1 - fi - displayText="${iface}/53->${dnsPort}/80,443->${trafficPort}" - if [ "$s" -eq 0 ]; then - gatewaySummary="${gatewaySummary}${displayText}\\n" - output_ok - else - state add 'errorSummary' 'errorFailedSetup' "$displayText" - output_fail - fi - ;; - esac - return $s -} -interface_process_tor_nft() { - local s=0 iface="$1" action="$2" - local displayText set_name4 set_name6 - local dnsPort trafficPort - case "$action" in - reload) - displayText="${iface}/53->${dnsPort}/80,443->${trafficPort}" - gatewaySummary="${gatewaySummary}${displayText}\\n" - ;; - destroy) - ;; - create) - output 2 "Creating TOR redirects " - dnsPort="$(grep -m1 DNSPort /etc/tor/torrc | awk -F: '{print $2}')" - trafficPort="$(grep -m1 TransPort /etc/tor/torrc | awk -F: '{print $2}')" - dnsPort="${dnsPort:-9053}"; trafficPort="${trafficPort:-9040}"; - if resolver 'create_resolver_set' "$iface" 'dst' 'ip' && nftset 'flush' "$iface" 'dst' 'ip'; then - set_name4="${nftPrefix}_${iface}_4_dst_ip" - set_name6="${nftPrefix}_${iface}_6_dst_ip" - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - else - s=1 - fi - displayText="${iface}/53->${dnsPort}/80,443->${trafficPort}" - if [ "$s" -eq 0 ]; then - gatewaySummary="${gatewaySummary}${displayText}\\n" - output_ok - else - state add 'errorSummary' 'errorFailedSetup' "$displayText" - output_fail - fi - ;; - esac - return $s -} - -interface_routing() { - local action="$1" tid="$2" mark="$3" iface="$4" gw4="$5" dev="$6" gw6="$7" dev6="$8" priority="$9" - local dscp s=0 i ipv4_error=1 ipv6_error=1 - if [ -z "$tid" ] || [ -z "$mark" ] || [ -z "$iface" ]; then - state add 'errorSummary' 'errorInterfaceRoutingEmptyValues' - return 1 - fi - case "$action" in - create) - if is_netifd_table "$iface"; then - ipv4_error=0 - $ip_bin rule del table "$tid" >/dev/null 2>&1 - $ip_bin -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 - if is_nft; then - nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1 - nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1 - nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1 - else - ipt -t mangle -N "${iptPrefix}_MARK_${mark}" || ipv4_error=1 - ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j MARK --set-xmark "${mark}/${fw_mask}" || ipv4_error=1 - ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j RETURN || ipv4_error=1 - fi - if [ -n "$ipv6_enabled" ]; then - ipv6_error=0 - $ip_bin -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1 - fi - else - if ! grep -q "$tid ${ipTablePrefix}_${iface}" '/etc/iproute2/rt_tables'; then - sed -i "/${ipTablePrefix}_${iface}/d" '/etc/iproute2/rt_tables' - sync - echo "$tid ${ipTablePrefix}_${iface}" >> '/etc/iproute2/rt_tables' - sync - fi - $ip_bin rule del table "$tid" >/dev/null 2>&1 - $ip_bin route flush table "$tid" >/dev/null 2>&1 - if [ -n "$gw4" ] || [ "$strict_enforcement" -ne 0 ]; then - ipv4_error=0 - if [ -z "$gw4" ]; then - $ip_bin -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1 - else - $ip_bin -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1 - fi -# shellcheck disable=SC2086 - while read -r i; do - i="$(echo "$i" | sed 's/ linkdown$//')" - i="$(echo "$i" | sed 's/ onlink$//')" - idev="$(echo "$i" | grep -Eso 'dev [^ ]*' | awk '{print $2}')" - if ! is_supported_iface_dev "$idev"; then - $ip_bin -4 route add $i table "$tid" >/dev/null 2>&1 || ipv4_error=1 - fi - done << EOF - $($ip_bin -4 route list table main) -EOF - $ip_bin -4 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 - if is_nft; then - nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}" || ipv4_error=1 - nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} counter mark set mark and ${fw_maskXor} xor ${mark}" || ipv4_error=1 - nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return" || ipv4_error=1 - else - ipt -t mangle -N "${iptPrefix}_MARK_${mark}" || ipv4_error=1 - ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j MARK --set-xmark "${mark}/${fw_mask}" || ipv4_error=1 - ipt -t mangle -A "${iptPrefix}_MARK_${mark}" -j RETURN || ipv4_error=1 - fi - fi - if [ -n "$ipv6_enabled" ]; then - ipv6_error=0 - if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strict_enforcement" -ne 0 ]; then - if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then - $ip_bin -6 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv6_error=1 - elif $ip_bin -6 route list table main | grep -q " dev $dev6 "; then - while read -r i; do - i="$(echo "$i" | sed 's/ linkdown$//')" - i="$(echo "$i" | sed 's/ onlink$//')" - # shellcheck disable=SC2086 - $ip_bin -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1 - done << EOF - $($ip_bin -6 route list table main | grep " dev $dev6 ") -EOF - else - $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 - $ip_bin -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 - fi - fi - $ip_bin -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" >/dev/null 2>&1 || ipv6_error=1 - fi - fi - if [ "$ipv4_error" -eq 0 ] || [ "$ipv6_error" -eq 0 ]; then - dscp="$(uci -q get "${packageName}".config."${iface}"_dscp)" - if is_nft; then - if [ "${dscp:-0}" -ge 1 ] && [ "${dscp:-0}" -le 63 ]; then - nft add rule inet "$nftTable" "${nftPrefix}_prerouting ip dscp ${dscp} goto ${nftPrefix}_mark_${mark}" || s=1 - fi - if [ "$iface" = "$icmp_interface" ]; then - nft add rule inet "$nftTable" "${nftPrefix}_output ip protocol icmp goto ${nftPrefix}_mark_${mark}" || s=1 - fi - else - if [ "${dscp:-0}" -ge 1 ] && [ "${dscp:-0}" -le 63 ]; then - ipt -t mangle -I "${iptPrefix}_PREROUTING" -m dscp --dscp "${dscp}" -g "${iptPrefix}_MARK_${mark}" || s=1 - fi - if [ "$iface" = "$icmp_interface" ]; then - ipt -t mangle -I "${iptPrefix}_OUTPUT" -p icmp -g "${iptPrefix}_MARK_${mark}" || s=1 - fi - fi - else - s=1 - fi - return "$s" - ;; - create_user_set) - if is_nft; then - nftset 'create_user_set' "$iface" 'dst' 'ip' 'user' '' "$mark" || s=1 - nftset 'create_user_set' "$iface" 'src' 'ip' 'user' '' "$mark" || s=1 - nftset 'create_user_set' "$iface" 'src' 'mac' 'user' '' "$mark" || s=1 - else - ips 'create_user_set' "$iface" 'dst' 'ip' 'user' '' "$mark" || s=1 - ips 'create_user_set' "$iface" 'src' 'ip' 'user' '' "$mark" || s=1 - ips 'create_user_set' "$iface" 'dst' 'net' 'user' '' "$mark" || s=1 - ips 'create_user_set' "$iface" 'src' 'net' 'user' '' "$mark" || s=1 - ips 'create_user_set' "$iface" 'src' 'mac' 'user' '' "$mark" || s=1 - fi - return "$s" - ;; - delete|destroy) - $ip_bin rule del table "$tid" >/dev/null 2>&1 - if ! is_netifd_table "$iface"; then - $ip_bin route flush table "$tid" >/dev/null 2>&1 - sed -i "/${ipTablePrefix}_${iface}\$/d" '/etc/iproute2/rt_tables' - sync - fi - return "$s" - ;; - reload_interface) - is_netifd_table "$iface" && return 0; - ipv4_error=0 - $ip_bin rule del table "$tid" >/dev/null 2>&1 - if ! is_netifd_table "$iface"; then - $ip_bin route flush table "$tid" >/dev/null 2>&1 - fi - if [ -n "$gw4" ] || [ "$strict_enforcement" -ne 0 ]; then - if [ -z "$gw4" ]; then - $ip_bin -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1 - else - $ip_bin -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1 - fi - $ip_bin rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1 - fi - if [ -n "$ipv6_enabled" ]; then - ipv6_error=0 - if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strict_enforcement" -ne 0 ]; then - if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then - $ip_bin -6 route add unreachable default table "$tid" || ipv6_error=1 - elif $ip_bin -6 route list table main | grep -q " dev $dev6 "; then - while read -r i; do - # shellcheck disable=SC2086 - $ip_bin -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1 - done << EOF - $($ip_bin -6 route list table main | grep " dev $dev6 ") -EOF - else - $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 - $ip_bin -6 route add default dev "$dev6" table "$tid" >/dev/null 2>&1 || ipv6_error=1 - fi - fi - $ip_bin -6 rule add fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1 - fi - if [ "$ipv4_error" -eq 0 ] || [ "$ipv6_error" -eq 0 ]; then - s=0 - else - s=1 - fi - return "$s" - ;; - esac -} - -json_add_gateway() { - local action="$1" tid="$2" mark="$3" iface="$4" gw4="$5" dev4="$6" gw6="$7" dev6="$8" priority="$9" default="${10}" - json_add_object '' - json_add_string name "$iface" - json_add_string device_ipv4 "$dev4" - json_add_string gateway_ipv4 "$gw4" - json_add_string device_ipv6 "$dev6" - json_add_string gateway_ipv6 "$gw6" - if [ -n "$default" ]; then - json_add_boolean default true - else - json_add_boolean default false - fi - json_add_string action "$action" - json_add_string table_id "$tid" - json_add_string mark "$mark" - json_add_string priority "$priority" - json_close_object -} - -interface_process() { - local gw4 gw6 dev dev6 s=0 dscp iface="$1" action="$2" reloadedIface="$3" - local displayText dispDev dispGw4 dispGw6 dispStatus - - if [ "$iface" = 'all' ] && [ "$action" = 'prepare' ]; then - config_load 'network' - ifaceMark="$(printf '0x%06x' "$wan_mark")" - ifacePriority="$wan_ip_rules_priority" - return 0 - fi - - is_supported_interface "$iface" || return 0 - is_wan6 "$iface" && return 0 - [ $((ifaceMark)) -gt $((fw_mask)) ] && return 1 - - if is_ovpn "$iface" && ! is_valid_ovpn "$iface"; then - : || state add 'warningSummary' 'warningInvalidOVPNConfig' "$iface" - fi - - network_get_device dev "$iface" - [ -z "$dev" ] && network_get_physdev dev "$iface" - if is_wan "$iface" && [ -n "$wanIface6" ] && str_contains "$wanIface6" "$iface"; then - network_get_device dev6 "$wanIface6" - [ -z "$dev6" ] && network_get_physdev dev6 "$wanIface6" - fi - - [ -z "$dev6" ] && dev6="$dev" - [ -z "$ifaceMark" ] && ifaceMark="$(printf '0x%06x' "$wan_mark")" - [ -z "$ifacePriority" ] && ifacePriority="$wan_ip_rules_priority" - - ifaceTableID="$(get_rt_tables_id "$iface")" - [ -z "$ifaceTableID" ] && ifaceTableID="$(get_rt_tables_next_id)" - eval "mark_${iface//-/_}"='$ifaceMark' - eval "tid_${iface//-/_}"='$ifaceTableID' - pbr_get_gateway gw4 "$iface" "$dev" - pbr_get_gateway6 gw6 "$iface" "$dev6" - dispGw4="${gw4:-0.0.0.0}" - dispGw6="${gw6:-::/0}" - [ "$iface" != "$dev" ] && dispDev="$dev" - is_default_dev "$dev" && dispStatus="${__OK__}" - displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" - - case "$action" in - create) - output 2 "Setting up routing for '$displayText' " - if interface_routing 'create' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"; then - json_add_gateway 'create' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" "$dispStatus" - gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n" - output_ok - else - state add 'errorSummary' 'errorFailedSetup' "$displayText" - output_fail - fi - ;; - create_user_set) - interface_routing 'create_user_set' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" - ;; - destroy) - displayText="${iface}/${dispDev:+$dispDev/}${dispGw4}${ipv6_enabled:+/$dispGw6}" - output 2 "Removing routing for '$displayText' " - interface_routing 'destroy' "${ifaceTableID}" "${ifaceMark}" "${iface}" - output_ok - ;; - reload) - gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n" - ;; - reload_interface) - if [ "$iface" = "$reloadedIface" ]; then - output 2 "Reloading routing for '$displayText' " - if interface_routing 'reload_interface' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority"; then - json_add_gateway 'reload_interface' "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6" "$ifacePriority" "$dispStatus" - gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n" - output_ok - else - state add 'errorSummary' 'errorFailedReload' "$displayText" - output_fail - fi - else - gatewaySummary="${gatewaySummary}${displayText}${dispStatus:+ $dispStatus}\\n" - fi - ;; - esac -# ifaceTableID="$((ifaceTableID + 1))" - ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))" - ifacePriority="$((ifacePriority + 1))" - return $s -} - -user_file_process() { - local shellBin="${SHELL:-/bin/ash}" - [ "$enabled" -gt 0 ] || return 0 - if [ ! -s "$path" ]; then - state add 'errorSummary' 'errorUserFileNotFound' "$path" - output_fail - return 1 - fi - if ! $shellBin -n "$path"; then - state add 'errorSummary' 'errorUserFileSyntax' "$path" - output_fail - return 1 - fi - output 2 "Running $path " -# shellcheck disable=SC1090 - if ! . "$path"; then - state add 'errorSummary' 'errorUserFileRunning' "$path" - if grep -q -w 'curl' "$path" && ! is_present 'curl'; then - state add 'errorSummary' 'errorUserFileNoCurl' "$path" - fi - output_fail - return 1 - else - output_ok - return 0 - fi -} - -boot() { - ubus -t 30 wait_for network.interface 2>/dev/null - rc_procd start_service 'on_boot' -} - -on_firewall_reload() { - if [ -e "$packageLockFile" ]; then # service is stopped, do not start it on firewall reload - logger -t "$packageName" "Reload on firewall action aborted: service is stopped." - return 0 - else - rc_procd start_service 'on_firewall_reload' "$1" - fi -} -on_interface_reload() { - if [ -e "$packageLockFile" ]; then # service is stopped, do not start it on interface change - logger -t "$packageName" "Reload on interface change aborted: service is stopped." - return 0 - else - rc_procd start_service 'on_interface_reload' "$1" - fi -} - -start_service() { - local resolverStoredHash resolverNewHash i param="$1" reloadedIface - - load_environment 'on_start' "$(load_validate_config)" || return 1 - is_wan_up || return 1 - rm -f "$nftTempFile" - - case "$param" in - on_boot) - serviceStartTrigger='on_start' - ;; - on_firewall_reload) - serviceStartTrigger='on_start' - ;; - on_interface_reload) - reloadedIface="$2" - if is_ovpn "$reloadedIface"; then - logger -t "$packageName" "Updated interface is an OpenVPN tunnel, restarting." - serviceStartTrigger='on_start' - unset reloadedIface - else - serviceStartTrigger='on_interface_reload' - fi - ;; - on_reload) - serviceStartTrigger='on_reload' - ;; - on_restart) - serviceStartTrigger='on_start' - ;; - esac - - if [ -n "$reloadedIface" ] && ! is_supported_interface "$reloadedIface"; then - return 0 - fi - - if [ -n "$(ubus_get_status error)" ] || [ -n "$(ubus_get_status warning)" ]; then - serviceStartTrigger='on_start' - unset reloadedIface - elif ! is_service_running; then - serviceStartTrigger='on_start' - unset reloadedIface - elif [ -z "$(ubus_get_status gateway)" ]; then - serviceStartTrigger='on_start' - unset reloadedIface - elif [ "$serviceStartTrigger" = 'on_interface_reload' ] && \ - [ -z "$(ubus_get_interface "$reloadedIface" 'gateway_4')" ] && \ - [ -z "$(ubus_get_interface "$reloadedIface" 'gateway_6')" ]; then - serviceStartTrigger='on_start' - unset reloadedIface - else - serviceStartTrigger="${serviceStartTrigger:-on_start}" - fi - - procd_open_instance "main" - procd_set_param command /bin/true - procd_set_param stdout 1 - procd_set_param stderr 1 - procd_open_data - - case $serviceStartTrigger in - on_interface_reload) - output 1 "Reloading Interface: $reloadedIface " - json_add_array 'gateways' - interface_process 'all' 'prepare' - config_foreach interface_process 'interface' 'reload_interface' "$reloadedIface" - json_close_array - output 1 '\n' - ;; - on_reload) - traffic_killswitch 'insert' - resolver 'store_hash' - resolver 'cleanup_all' - resolver 'configure' - resolver 'init' - cleanup_main_chains - cleanup_sets - if ! is_nft; then - for i in $chainsList; do - i="$(str_to_upper "$i")" - ipt -t mangle -N "${iptPrefix}_${i}" - ipt -t mangle "$rule_create_option" "$i" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}" - done - fi - json_add_array 'gateways' - interface_process 'all' 'prepare' - config_foreach interface_process 'interface' 'reload' - interface_process_tor 'tor' 'destroy' - is_tor_running && interface_process_tor 'tor' 'reload' - json_close_array - if is_config_enabled 'policy'; then - output 1 'Processing policies ' - config_load "$packageName" - config_foreach load_validate_policy 'policy' policy_process - output 1 '\n' - fi - if is_config_enabled 'include'; then - interface_process 'all' 'prepare' - config_foreach interface_process 'interface' 'create_user_set' - output 1 'Processing user file(s) ' - config_load "$packageName" - config_foreach load_validate_include 'include' user_file_process - output 1 '\n' - fi - resolver 'init_end' - resolver 'compare_hash' && resolver 'restart' - traffic_killswitch 'remove' - ;; - on_start|*) - traffic_killswitch 'insert' - resolver 'store_hash' - resolver 'cleanup_all' - resolver 'configure' - resolver 'init' - cleanup_main_chains - cleanup_sets - cleanup_marking_chains - cleanup_rt_tables - if ! is_nft; then - for i in $chainsList; do - i="$(str_to_upper "$i")" - ipt -t mangle -N "${iptPrefix}_${i}" - ipt -t mangle "$rule_create_option" "$i" -m mark --mark "0x0/${fw_mask}" -j "${iptPrefix}_${i}" - done - fi - output 1 'Processing interfaces ' - json_add_array 'gateways' - interface_process 'all' 'prepare' - config_foreach interface_process 'interface' 'create' - interface_process_tor 'tor' 'destroy' - is_tor_running && interface_process_tor 'tor' 'create' - json_close_array - ip route flush cache - output 1 '\n' - if is_config_enabled 'policy'; then - output 1 'Processing policies ' - config_load "$packageName" - config_foreach load_validate_policy 'policy' policy_process - output 1 '\n' - fi - if is_config_enabled 'include'; then - interface_process 'all' 'prepare' - config_foreach interface_process 'interface' 'create_user_set' - output 1 'Processing user file(s) ' - config_load "$packageName" - config_foreach load_validate_include 'include' user_file_process - output 1 '\n' - fi - resolver 'init_end' - resolver 'compare_hash' && resolver 'restart' - traffic_killswitch 'remove' - ;; - esac - - if [ -z "$gatewaySummary" ]; then - state add 'errorSummary' 'errorNoGateways' - fi - json_add_object 'status' - [ -n "$gatewaySummary" ] && json_add_string 'gateways' "$gatewaySummary" - [ -n "$errorSummary" ] && json_add_string 'errors' "$errorSummary" - [ -n "$warningSummary" ] && json_add_string 'warnings' "$warningSummary" - if [ "$strict_enforcement" -ne 0 ] && str_contains "$gatewaySummary" '0.0.0.0'; then - json_add_string 'mode' "strict" - fi - json_close_object - procd_close_data - procd_close_instance -} - -service_started() { - if is_nft; then - [ -n "$gatewaySummary" ] && output "$serviceName (nft) started with gateways:\\n${gatewaySummary}" - else - [ -n "$gatewaySummary" ] && output "$serviceName (iptables) started with gateways:\\n${gatewaySummary}" - fi - state print 'errorSummary' - state print 'warningSummary' - if [ -n "$errorSummary" ]; then - return 2 - elif [ -n "$warningSummary" ]; then - return 1 - else - return 0 - fi -} - -service_triggers() { - local n - load_environment 'on_triggers' -# shellcheck disable=SC2034 - PROCD_RELOAD_DELAY=$(( procd_reload_delay * 1000 )) - procd_open_validate - load_validate_config - load_validate_policy - load_validate_include - procd_close_validate - procd_open_trigger - procd_add_reload_trigger 'openvpn' - procd_add_config_trigger "config.change" "${packageName}" /etc/init.d/${packageName} reload - for n in $ifacesSupported; do - procd_add_interface_trigger "interface.*" "$n" /etc/init.d/${packageName} on_interface_reload "$n" - done - procd_close_trigger - if [ "$serviceStartTrigger" = 'on_start' ]; then - output 3 "$serviceName monitoring interfaces: ${ifacesSupported}\\n" - fi -} - -stop_service() { - local i - load_environment 'on_stop' - is_service_running || return 0 - traffic_killswitch 'insert' - cleanup_main_chains - cleanup_sets - cleanup_marking_chains - output 1 'Resetting interfaces ' - config_load 'network' - config_foreach interface_process 'interface' 'destroy' - interface_process_tor 'tor' 'destroy' - cleanup_rt_tables - output 1 "\\n" - ip route flush cache - unset ifaceMark - unset ifaceTableID - resolver 'store_hash' - resolver 'cleanup_all' - resolver 'compare_hash' && resolver 'restart' - traffic_killswitch 'remove' - if [ "$enabled" -ne 0 ]; then - if is_nft; then - output "$serviceName (nft) stopped "; output_okn; - else - output "$serviceName (iptables) stopped "; output_okn; - fi - fi -} - -status_service() { - local _SEPARATOR_='============================================================' - load_environment 'on_status' - if is_nft; then - status_service_nft "$@" - else - status_service_iptables "$@" - fi -} - -status_service_nft() { - local i dev dev6 wan_tid - - json_load "$(ubus call system board)"; json_select release; json_get_var dist distribution; json_get_var vers version - if [ -n "$wanIface4" ]; then - network_get_gateway wanGW4 "$wanIface4" - network_get_device dev "$wanIface4" - fi - if [ -n "$wanIface6" ]; then - network_get_device dev6 "$wanIface6" - wanGW6=$($ip_bin -6 route show | grep -m1 " dev $dev6 " | awk '{print $1}') - [ "$wanGW6" = "default" ] && wanGW6=$($ip_bin -6 route show | grep -m1 " dev $dev6 " | awk '{print $3}') - fi - while [ "${1:0:1}" = "-" ]; do param="${1//-/}"; eval "set_$param=1"; shift; done - [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support" - status="$serviceName running on $dist $vers." - [ -n "$wanIface4" ] && status="$status WAN (IPv4): ${wanIface4}/${dev}/${wanGW4:-0.0.0.0}." - [ -n "$wanIface6" ] && status="$status WAN (IPv6): ${wanIface6}/${dev6}/${wanGW6:-::/0}." - - echo "$_SEPARATOR_" - echo "$packageName - environment" - echo "$status" - echo "$_SEPARATOR_" - dnsmasq --version 2>/dev/null | sed '/^$/,$d' - echo "$_SEPARATOR_" - echo "$packageName chains - policies" - for i in forward input output prerouting postrouting; do - "$nft" -a list table inet "$nftTable" | sed -n "/chain ${nftPrefix}_${i} {/,/\t}/p" - done - echo "$_SEPARATOR_" - echo "$packageName chains - marking" - for i in $(get_mark_nft_chains); do - "$nft" -a list table inet "$nftTable" | sed -n "/chain ${i} {/,/\t}/p" - done - echo "$_SEPARATOR_" - echo "$packageName nft sets" - for i in $(get_nft_sets); do - "$nft" -a list table inet "$nftTable" | sed -n "/set ${i} {/,/\t}/p" - done - if [ -s "$dnsmasqFile" ]; then - echo "$_SEPARATOR_" - echo "dnsmasq sets" - cat "$dnsmasqFile" - fi -# echo "$_SEPARATOR_" -# ip rule list | grep "${packageName}_" - echo "$_SEPARATOR_" - tableCount="$(grep -c "${packageName}_" /etc/iproute2/rt_tables)" || tableCount=0 - wan_tid=$(($(get_rt_tables_next_id)-tableCount)) - i=0; while [ $i -lt "$tableCount" ]; do - echo "IPv4 table $((wan_tid + i)) route: $($ip_bin -4 route show table $((wan_tid + i)) | grep default)" - echo "IPv4 table $((wan_tid + i)) rule(s):" - $ip_bin -4 rule list table "$((wan_tid + i))" - if [ -n "$ipv6_enabled" ]; then - echo "IPv6 table $((wan_tid + i)) route: $($ip_bin -6 route show table $((wan_tid + i)) | grep default)" - echo "IPv6 table $((wan_tid + i)) rule(s):" - $ip_bin -6 route show table $((wan_tid + i)) - fi - i=$((i + 1)) - done -} - -status_service_iptables() { - local dist vers out id s param status set_d set_p tableCount i=0 dev dev6 j wan_tid - - json_load "$(ubus call system board)"; json_select release; json_get_var dist distribution; json_get_var vers version - if [ -n "$wanIface4" ]; then - network_get_gateway wanGW4 "$wanIface4" - network_get_device dev "$wanIface4" - fi - if [ -n "$wanIface6" ]; then - network_get_device dev6 "$wanIface6" - wanGW6=$($ip_bin -6 route show | grep -m1 " dev $dev6 " | awk '{print $1}') - [ "$wanGW6" = "default" ] && wanGW6=$($ip_bin -6 route show | grep -m1 " dev $dev6 " | awk '{print $3}') - fi - while [ "${1:0:1}" = "-" ]; do param="${1//-/}"; eval "set_$param=1"; shift; done - [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support" - status="$serviceName running on $dist $vers." - [ -n "$wanIface4" ] && status="$status WAN (IPv4): ${wanIface4}/${dev}/${wanGW4:-0.0.0.0}." - [ -n "$wanIface6" ] && status="$status WAN (IPv6): ${wanIface6}/${dev6}/${wanGW6:-::/0}." - { - echo "$status" - echo "$_SEPARATOR_" - dnsmasq --version 2>/dev/null | sed '/^$/,$d' - if [ -n "$1" ]; then - echo "$_SEPARATOR_" - echo "Resolving domains" - for i in $1; do - echo "$i: $(resolveip "$i" | tr '\n' ' ')" - done - fi - - echo "$_SEPARATOR_" - echo "Routes/IP Rules" - tableCount="$(grep -c "${packageName}_" /etc/iproute2/rt_tables)" || tableCount=0 - if [ -n "$set_d" ]; then route; else route | grep '^default'; fi - if [ -n "$set_d" ]; then ip rule list; fi - wan_tid=$(($(get_rt_tables_next_id)-tableCount)) - i=0; while [ $i -lt "$tableCount" ]; do - echo "IPv4 table $((wan_tid + i)) route: $($ip_bin -4 route show table $((wan_tid + i)) | grep default)" - echo "IPv4 table $((wan_tid + i)) rule(s):" - $ip_bin -4 rule list table "$((wan_tid + i))" - i=$((i + 1)) - done - - if [ -n "$ipv6_enabled" ]; then - i=0; while [ $i -lt "$tableCount" ]; do - $ip_bin -6 route show table $((wan_tid + i)) | while read -r param; do - echo "IPv6 Table $((wan_tid + i)): $param" - done - i=$((i + 1)) - done - fi - - for j in Mangle NAT; do - if [ -z "$set_d" ]; then - for i in $chainsList; do - i="$(str_to_upper "$i")" - if iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}" >/dev/null 2>&1; then - echo "$_SEPARATOR_" - echo "$j IP Table: $i" - iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}" - if [ -n "$ipv6_enabled" ]; then - echo "$_SEPARATOR_" - echo "$j IPv6 Table: $i" - iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_${i}" - fi - fi - done - else - echo "$_SEPARATOR_" - echo "$j IP Table" - iptables -L -t "$(str_to_lower $j)" - if [ -n "$ipv6_enabled" ]; then - echo "$_SEPARATOR_" - echo "$j IPv6 Table" - iptables -L -t "$(str_to_lower $j)" - fi - fi - i=0; ifaceMark="$wan_mark"; - while [ $i -lt "$tableCount" ]; do - if iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_MARK_${ifaceMark}" >/dev/null 2>&1; then - echo "$_SEPARATOR_" - echo "$j IP Table MARK Chain: ${iptPrefix}_MARK_${ifaceMark}" - iptables -v -t "$(str_to_lower $j)" -S "${iptPrefix}_MARK_${ifaceMark}" - ifaceMark="$(printf '0x%06x' $((ifaceMark + wan_mark)))"; - fi - i=$((i + 1)) - done - done - - echo "$_SEPARATOR_" - echo "Current ipsets" - ipset save - if [ -s "$dnsmasqFile" ]; then - echo "$_SEPARATOR_" - echo "DNSMASQ sets" - cat "$dnsmasqFile" - fi - if [ -s "$aghIpsetFile" ]; then - echo "$_SEPARATOR_" - echo "AdGuardHome sets" - cat "$aghIpsetFile" - fi - echo "$_SEPARATOR_" - } | tee -a /var/${packageName}-support - if [ -n "$set_p" ]; then - printf "%b" "Pasting to paste.ee... " - if is_present 'curl' && is_variant_installed 'libopenssl' && is_installed 'ca-bundle'; then - json_init; json_add_string "description" "${packageName}-support" - json_add_array "sections"; json_add_object '0' - json_add_string "name" "$(uci -q get system.@system[0].hostname)" - json_add_string "contents" "$(cat /var/${packageName}-support)" - json_close_object; json_close_array; payload=$(json_dump) - out=$(curl -s -k "https://api.paste.ee/v1/pastes" -X "POST" -H "Content-Type: application/json" -H "X-Auth-Token:uVOJt6pNqjcEWu7qiuUuuxWQafpHhwMvNEBviRV2B" -d "$payload") - json_load "$out"; json_get_var id id; json_get_var s success - [ "$s" = "1" ] && printf "%b" "https://paste.ee/p/$id $__OK__\\n" || printf "%b" "$__FAIL__\\n" - [ -e "/var/${packageName}-support" ] && rm -f "/var/${packageName}-support" - else - printf "%b" "${__FAIL__}\\n" - 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" - fi - else - printf "%b" "Your support details have been logged to '/var/${packageName}-support'. $__OK__\\n" - fi -} - -# shellcheck disable=SC2120 -load_validate_config() { - uci_load_validate "$packageName" "$packageName" "$1" "${2}${3:+ $3}" \ - 'enabled:bool:0' \ - 'procd_boot_delay:integer:0' \ - 'strict_enforcement:bool:1' \ - 'secure_reload:bool:0' \ - 'ipv6_enabled:bool:0' \ - 'resolver_set:or("", "none", "dnsmasq.ipset", "dnsmasq.nftset")' \ - 'verbosity:range(0,2):1' \ - "wan_mark:regex('0x[A-Fa-f0-9]{8}'):0x010000" \ - "fw_mask:regex('0x[A-Fa-f0-9]{8}'):0xff0000" \ - 'icmp_interface:or("", "tor", uci("network", "@interface"))' \ - 'ignored_interface:list(or("tor", uci("network", "@interface")))' \ - 'supported_interface:list(or("tor", uci("network", "@interface")))' \ - 'boot_timeout:integer:30' \ - 'wan_ip_rules_priority:uinteger:30000' \ - 'rule_create_option:or("", "add", "insert"):add' \ - 'procd_reload_delay:integer:0' \ - 'webui_supported_protocol:list(string)' \ - 'nft_user_set_policy:or("", "memory", "performance")'\ - 'nft_user_set_counter:bool:0' -} - -# shellcheck disable=SC2120 -load_validate_policy() { - local name - local enabled - local interface - local proto - local chain - local src_addr - local src_port - local dest_addr - local dest_port - uci_load_validate "$packageName" 'policy' "$1" "${2}${3:+ $3}" \ - 'name:string:Untitled' \ - 'enabled:bool:1' \ - 'interface:or("ignore", "tor", uci("network", "@interface")):wan' \ - 'proto:or(string)' \ - 'chain:or("", "forward", "input", "output", "prerouting", "postrouting", "FORWARD", "INPUT", "OUTPUT", "PREROUTING", "POSTROUTING"):prerouting' \ - 'src_addr:list(neg(or(host,network,macaddr,string)))' \ - 'src_port:list(neg(or(portrange,string)))' \ - 'dest_addr:list(neg(or(host,network,string)))' \ - 'dest_port:list(neg(or(portrange,string)))' -} - -# shellcheck disable=SC2120 -load_validate_include() { - local path= - local enabled= - uci_load_validate "$packageName" 'include' "$1" "${2}${3:+ $3}" \ - 'path:file' \ - 'enabled:bool:0' -} diff --git a/net/pbr/files/etc/uci-defaults/91-pbr-iptables b/net/pbr/files/etc/uci-defaults/91-pbr-iptables new file mode 100644 index 0000000000..3fa08e53d9 --- /dev/null +++ b/net/pbr/files/etc/uci-defaults/91-pbr-iptables @@ -0,0 +1,27 @@ +#!/bin/sh +# shellcheck disable=SC2015,SC3037,SC3043 + +readonly pbrFunctionsFile='/etc/init.d/pbr' +if [ -s "$pbrFunctionsFile" ]; then +# shellcheck source=../../etc/init.d/pbr + . "$pbrFunctionsFile" +else + printf "%b: pbr init.d file (%s) not found! \n" '\033[0;31mERROR\033[0m' "$pbrFunctionsFile" +fi + +# Transition resolver_set depending on dnsmasq support +if [ "$(uci_get pbr config resolver_set)" != 'dnsmasq.ipset' ] && [ "$(uci_get pbr config resolver_set)" != 'adguardhome.ipset' ]; then + if check_agh_ipset; then + output "Setting resolver_set to 'adguardhome.ipset'... " + uci_set pbr config resolver_set 'adguardhome.ipset' && output_okn || output_failn + elif check_dnsmasq_ipset; then + output "Setting resolver_set to 'dnsmasq.ipset'... " + uci_set pbr config resolver_set 'dnsmasq.ipset' && output_okn || output_failn + else + output "Setting resolver_set to 'none'... " + uci_set pbr config resolver_set 'none' && output_okn || output_failn + fi + uci_commit pbr +fi + +exit 0 diff --git a/net/pbr/files/etc/uci-defaults/91-pbr-netifd b/net/pbr/files/etc/uci-defaults/91-pbr-netifd new file mode 100644 index 0000000000..bea4a353d5 --- /dev/null +++ b/net/pbr/files/etc/uci-defaults/91-pbr-netifd @@ -0,0 +1,38 @@ +#!/bin/sh +# shellcheck disable=SC3037,SC3043 + +readonly pbrFunctionsFile='/etc/init.d/pbr' +if [ -s "$pbrFunctionsFile" ]; then +# shellcheck source=../../etc/init.d/pbr + . "$pbrFunctionsFile" +else + printf "%b: pbr init.d file (%s) not found! \n" '\033[0;31mERROR\033[0m' "$pbrFunctionsFile" +fi + +# shellcheck disable=SC2317 +pbr_iface_setup() { + local iface="${1}" + local proto + if is_supported_interface "${iface}"; then + output "Setting up ${packageName} routing tables for ${iface}... " + uci_set 'network' "${iface}" 'ip4table' "${ipTablePrefix}_${iface%6}" + uci_set 'network' "${iface}" 'ip6table' "${ipTablePrefix}_${iface%6}" + if ! grep -q -E -e "^[0-9]+\s+${ipTablePrefix}_${iface%6}$" "$rtTablesFile"; then + sed -i -e "\$a $(($(sort -r -n "$rtTablesFile" | grep -o -E -m 1 "^[0-9]+")+1))\t${ipTablePrefix}_${iface%6}" \ + "$rtTablesFile" + fi + output_okbn + fi +} + +sed -i "/${ipTablePrefix}_/d" "$rtTablesFile" +sync +config_load network +config_foreach pbr_iface_setup interface +uci_commit network +sync +output "Restarting network... " +/etc/init.d/network restart +output_okn + +exit 0 diff --git a/net/pbr/files/etc/uci-defaults/91-pbr-nft b/net/pbr/files/etc/uci-defaults/91-pbr-nft new file mode 100644 index 0000000000..0406e2a435 --- /dev/null +++ b/net/pbr/files/etc/uci-defaults/91-pbr-nft @@ -0,0 +1,30 @@ +#!/bin/sh +# shellcheck disable=SC2015,SC3037,SC3043 + +readonly pbrFunctionsFile='/etc/init.d/pbr' +if [ -s "$pbrFunctionsFile" ]; then +# shellcheck source=../../etc/init.d/pbr + . "$pbrFunctionsFile" +else + printf "%b: pbr init.d file (%s) not found! \n" '\033[0;31mERROR\033[0m' "$pbrFunctionsFile" +fi + +# Transition resolver_set depending on dnsmasq support +if [ "$(uci_get pbr config resolver_set)" != 'dnsmasq.nftset' ]; then + if check_dnsmasq_nftset; then + output "Setting resolver_set to 'dnsmasq.nftset'... " + uci_set pbr config resolver_set 'dnsmasq.nftset' && output_okn || output_failn + elif check_agh_ipset; then + output "Setting resolver_set to 'adguardhome.ipset'... " + uci_set pbr config resolver_set 'adguardhome.ipset' && output_okn || output_failn + elif check_dnsmasq_ipset; then + output "Setting resolver_set to 'dnsmasq.ipset'... " + uci_set pbr config resolver_set 'dnsmasq.ipset' && output_okn || output_failn + else + output "Setting resolver_set to 'none'... " + uci_set pbr config resolver_set 'none' && output_okn || output_failn + fi + uci_commit pbr +fi + +exit 0