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
icmp_interface=
ignored_interface=
ipv6_enabled=
+nft_user_set_policy=
+nft_user_set_counter=
procd_boot_delay=
procd_reload_delay=
resolver_set=
nftPrevParam4=
nftPrevParam6=
-
get_text() {
local r
case "$1" in
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";;
# 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() {
}
# 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 "$@"; }
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'
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';;
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)
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
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
;;
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
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
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'
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'
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
$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"
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")"
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
'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