pbr: update to 1.0.1-10
authorStan Grishin <stangri@melmac.ca>
Tue, 3 Jan 2023 19:46:20 +0000 (19:46 +0000)
committerStan Grishin <stangri@melmac.ca>
Mon, 16 Jan 2023 22:58:49 +0000 (22:58 +0000)
Bugfixes:
* better error information for empty tid/mark and failure to resolve domains
* better handling of entries in /etc/iproute2/rt_tables
* update packages definitions and descriptions
* remove firewall4 from dependencies to prevent dependency recursion

Updates:
* introduce nft_user_set_policy and nft_user_set_counter to control options for
  user nft sets this service creares
* use counters in internal nft sets

Signed-off-by: Stan Grishin <stangri@melmac.ca>
net/pbr/Makefile
net/pbr/files/etc/init.d/pbr.init

index ddcd9e1235b51957843daca7035224d10d29f627..6348c9bab756aec608e776c7cf6fc00aefbb8afc 100644 (file)
@@ -5,57 +5,60 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=pbr
 PKG_VERSION:=1.0.1
-PKG_RELEASE:=4
+PKG_RELEASE:=10
 PKG_LICENSE:=GPL-3.0-or-later
 PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>
 
 include $(INCLUDE_DIR)/package.mk
 
-define Package/pbr/default
+define Package/pbr/Default
   SECTION:=net
   CATEGORY:=Network
-  SUBMENU:=VPN
-  PROVIDES:=pbr
+  SUBMENU:=Routing and Redirection
   TITLE:=Policy Based Routing Service
   URL:=https://docs.openwrt.melmac.net/pbr/
-  DEPENDS:=+ip-full +jshn +jsonfilter +resolveip
+  DEPENDS:=+ip-full +jshn +jsonfilter +libubus +resolveip
   CONFLICTS:=vpnbypass vpn-policy-routing
   PKGARCH:=all
 endef
 
 define Package/pbr
-$(call Package/pbr/default)
+$(call Package/pbr/Default)
   TITLE+= with nft/nft set support
-  DEPENDS+=+firewall4 +kmod-nft-core +kmod-nft-nat +nftables-json
+  DEPENDS+=+kmod-nft-core +kmod-nft-nat +nftables-json
+  VARIANT:=nftables
   PROVIDES:=vpnbypass vpn-policy-routing
+  DEFAULT_VARIANT:=1
 endef
 
 define Package/pbr-iptables
-$(call Package/pbr/default)
+$(call Package/pbr/Default)
   TITLE+= with iptables/ipset support
   DEPENDS+=+ipset +iptables +kmod-ipt-ipset +iptables-mod-ipopt
-  PROVIDES:=pbr vpnbypass vpn-policy-routing
+  VARIANT:=iptables
+  PROVIDES:=pbr
 endef
 
 define Package/pbr-netifd
-$(call Package/pbr/default)
+$(call Package/pbr/Default)
   TITLE+= with netifd support
-  PROVIDES:=pbr vpnbypass vpn-policy-routing
+  VARIANT:=netifd
+  PROVIDES:=pbr
 endef
 
 define Package/pbr/description
 This service enables policy-based routing for WAN interfaces and various VPN tunnels.
-This version supports OpenWrt with both fw3/ipset/iptables and fw4/nft.
+This version supports OpenWrt with both firewall3/ipset/iptables and firewall4/nft.
 endef
 
 define Package/pbr-iptables/description
 This service enables policy-based routing for WAN interfaces and various VPN tunnels.
-This version supports OpenWrt with fw3/ipset/iptables.
+This version supports OpenWrt with firewall3/ipset/iptables.
 endef
 
 define Package/pbr-netifd/description
 This service enables policy-based routing for WAN interfaces and various VPN tunnels.
-This version supports OpenWrt with both fw3/ipset/iptables and fw4/nft.
+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
 
index 16aae0596f6c3cfabce2aeae1a90dee940b949ba..481b1d94861b7c2c43228e7e11a4eacb6237ed49 100755 (executable)
@@ -72,6 +72,8 @@ fw_mask=
 icmp_interface=
 ignored_interface=
 ipv6_enabled=
+nft_user_set_policy=
+nft_user_set_counter=
 procd_boot_delay=
 procd_reload_delay=
 resolver_set=
@@ -103,7 +105,6 @@ resolver_set_supported=
 nftPrevParam4=
 nftPrevParam6=
 
-
 get_text() {
        local r
        case "$1" in
@@ -136,6 +137,8 @@ get_text() {
                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";;
                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";;
@@ -264,7 +267,7 @@ is_service_running_nft() { [ -x "$nft" ] && [ -n "$(get_mark_nft_chains)" ]; }
 # 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 "${packageName}_${iface}" '/etc/iproute2/rt_tables' | awk '{print $1;}'; }
+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() {
@@ -276,6 +279,8 @@ is_config_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 "$@"; }
@@ -302,6 +307,8 @@ load_package_config() {
        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'
@@ -320,6 +327,9 @@ load_package_config() {
        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';;
@@ -569,8 +579,12 @@ nftset() {
                                fi
                                [ -z "$param4" ] &&     param4="$(resolveip_to_nftset4 "$param")"
                                [ -z "$param6" ] &&     param6="$(resolveip_to_nftset6 "$param")"
-                               nft4 add element inet "$nftTable" "$nftset4" "{ $param4 }" && ipv4_error=0
-                               nft6 add element inet "$nftTable" "$nftset6" "{ $param6 }" && ipv6_error=0
+                               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)
@@ -580,24 +594,24 @@ nftset() {
                create)
                        case "$type" in
                                ip|net)
-                                       nft4 add set inet "$nftTable" "$nftset4" "{ type ipv4_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0
-                                       nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0
+                                       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; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0
-                                       nft6 add set inet "$nftTable" "$nftset6" "{ type ether_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0
+                                       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; flags interval; auto-merge; comment \"$comment\"; }" && ipv4_error=0
-                       nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; flags interval; auto-merge; comment \"$comment\"; }" && ipv6_error=0
+                       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; flags interval; auto-merge; policy memory; comment \"$comment\"; }" && ipv4_error=0
-                                       nft6 add set inet "$nftTable" "$nftset6" "{ type ipv6_addr; flags interval; auto-merge; policy memory; comment \"$comment\"; }" && ipv6_error=0
+                                       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
@@ -610,8 +624,8 @@ nftset() {
                                        esac
                                        ;;
                                mac)
-                                       nft4 add set inet "$nftTable" "$nftset4" "{ type ether_addr; flags interval; auto-merge; policy memory; comment \"$comment\"; }" && ipv4_error=0
-                                       nft6 add set inet "$nftTable" "$nftset6" "{ type ether_addr; flags interval; auto-merge; policy memory; comment \"$comment\"; }" && ipv6_error=0
+                                       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
                                        ;;
@@ -657,7 +671,9 @@ nftset() {
        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
@@ -1212,8 +1228,14 @@ policy_routing_iptables() {
                                        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 $(resolveip_to_ipt -4 "$value")"
-                                       param6="$param6 $negation -s $(resolveip_to_ipt -6 "$value")"
+                                       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
@@ -1255,8 +1277,14 @@ policy_routing_iptables() {
                                        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 $(resolveip_to_ipt -4 "$value")"
-                                       param6="$param6 $negation -d $(resolveip_to_ipt -6 "$value")"
+                                       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'
@@ -1400,8 +1428,14 @@ policy_routing_nft() {
                                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 {$(resolveip_to_nftset4 "$value")}"
-                               param6="$param6 $ip6Flag daddr $negation {$(resolveip_to_nftset6 "$value")}"
+                               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'
@@ -1635,6 +1669,7 @@ 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
@@ -1758,7 +1793,7 @@ EOF
                        $ip_full rule del fwmark "${mark}/${fw_mask}" table "$tid" >/dev/null 2>&1
                        if ! is_netifd_table "$iface"; then
                                $ip_full route flush table "$tid" >/dev/null 2>&1
-                               sed -i "/${ipTablePrefix}_${iface}/d" '/etc/iproute2/rt_tables'
+                               sed -i "/${ipTablePrefix}_${iface}\$/d" '/etc/iproute2/rt_tables'
                                sync
                        fi
                        return "$s"
@@ -2057,6 +2092,7 @@ start_service() {
                        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")"
@@ -2159,6 +2195,7 @@ stop_service() {
        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
@@ -2387,7 +2424,9 @@ load_validate_config() {
                'wan_ip_rules_priority:uinteger:30000' \
                'rule_create_option:or("", "add", "insert"):add' \
                'procd_reload_delay:integer:0' \
-               'webui_supported_protocol:list(string)'
+               'webui_supported_protocol:list(string)' \
+               'nft_user_set_policy:or("", "memory", "performance")'\
+               'nft_user_set_counter:bool:0'
 }
 
 # shellcheck disable=SC2120