pbr: update to 1.1.7-21
authorStan Grishin <stangri@melmac.ca>
Sun, 6 Oct 2024 22:59:17 +0000 (22:59 +0000)
committerStan Grishin <stangri@melmac.ca>
Mon, 7 Oct 2024 18:21:02 +0000 (11:21 -0700)
* switch to dstnat chain from dstnat_lan chain for dns & tor policies (thanks @egc112)
* re-introduce procd_lan_interface for better LAN detection
* improve is_domain function
* introduce health-check for requried fw4 chains
* bugfix: avoid double counters for dns policies
* bugfix: remove faulty counters for tor policies
* rename interface_process to process_interface for better code readability
* overhaul pbr.user.aws script for a much better performance and more compact
  (gzipped) storage of the ranges json locally (thanks @bigsmile74)

Signed-off-by: Stan Grishin <stangri@melmac.ca>
net/pbr/Makefile
net/pbr/files/etc/init.d/pbr
net/pbr/files/usr/share/nftables.d/chain-post/dstnat/30-pbr.nft [new file with mode: 0644]
net/pbr/files/usr/share/nftables.d/chain-post/dstnat_lan/30-pbr.nft [deleted file]
net/pbr/files/usr/share/nftables.d/table-post/30-pbr.nft
net/pbr/files/usr/share/pbr/pbr.user.aws

index 0603c37ea7f984870547ba6e5f98a819a194d7ac..4bccd55a63d5a5eeff8ba9ccda5ce1ba9c053056 100644 (file)
@@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=pbr
 PKG_VERSION:=1.1.7
-PKG_RELEASE:=15
+PKG_RELEASE:=21
 PKG_LICENSE:=AGPL-3.0-or-later
 PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>
 
index aaf2e97bea786558f805122fb8f70ea9ce369ecb..053e6b3544a681c2825f07aa958ce65d99c96b25 100755 (executable)
@@ -57,6 +57,7 @@ nft_user_set_policy=
 nft_user_set_counter=
 procd_boot_delay=
 procd_reload_delay=
+procd_lan_interface=
 procd_wan_ignore_status=
 procd_wan_interface=
 procd_wan6_interface=
@@ -305,7 +306,7 @@ uci_get_device() { uci_get 'network' "$1" 'device' || uci_get 'network' "$1" 'de
 uci_get_protocol() { uci_get 'network' "$1" 'proto'; }
 is_default_dev() { [ "$1" = "$(ip -4 r | grep -m1 'dev' | grep -Eso 'dev [^ ]*' | awk '{print $2}')" ]; }
 is_disabled_interface() { [ "$(uci_get 'network' "$1" 'disabled')" = '1' ]; }
-is_domain() { ! is_ipv6 "$1" && str_contains "$1" '[a-zA-Z]'; }
+is_domain() { ! is_ipv6 "$1" && ! is_mac_address "$1" && ! is_phys_dev "$1" && str_contains "$1" '[a-zA-Z]'; }
 is_dslite() { local p; network_get_protocol p "$1"; [ "${p:0:6}" = "dslite" ]; }
 is_family_mismatch() { ( is_ipv4_netmask "${1//!}" && is_ipv6 "${2//!}" ) || ( is_ipv6 "${1//!}" && is_ipv4_netmask "${2//!}" ); }
 is_greater() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
@@ -326,7 +327,7 @@ is_ipv6_link_local() { [ "${1:0:4}" = 'fe80' ]; }
 is_ipv6_unique_local() { [ "${1:0:2}" = 'fc' ] || [ "${1:0:2}" = 'fd' ]; }
 is_list() { str_contains "$1" ',' || str_contains "$1" ' '; }
 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_lan() { local d; network_get_device d "$1"; str_contains "$procd_lan_interface" "$d"; }
 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_negation() { [ "${1:0:1}" = '!' ]; }
@@ -575,6 +576,7 @@ load_package_config() {
        config_get      verbosity                 'config' 'verbosity' '2'
        config_get      procd_boot_delay          'config' 'procd_boot_delay' '0'
        config_get      procd_boot_timeout        'config' 'procd_boot_timeout' '30'
+       config_get      procd_lan_interface       'config' 'procd_lan_interface'  'br-lan'
        config_get      procd_wan_ignore_status   'config' 'procd_wan_ignore_status' '0'
        config_get      procd_wan_interface       'config' 'procd_wan_interface'  'wan'
        config_get      procd_wan6_interface      'config' 'procd_wan6_interface' 'wan6'
@@ -630,9 +632,9 @@ load_environment() {
                        state add 'errorSummary' 'errorDefaultFw4TableMissing' 'fw4'
                        return 1
                fi
-               if is_config_enabled 'dns_policy'; then
-                       if ! nft_call list chain inet fw4 dstnat_lan; then
-                               state add 'errorSummary' 'errorDefaultFw4ChainMissing' 'dstnat_lan'
+               if is_config_enabled 'dns_policy' || is_tor_running; then
+                       if ! nft_call list chain inet fw4 dstnat; then
+                               state add 'errorSummary' 'errorDefaultFw4ChainMissing' 'dstnat'
                                return 1
                        fi
                fi
@@ -910,7 +912,7 @@ cleanup_rt_tables() {
 
 cleanup_main_chains() {
        local i j
-       for i in $chainsList dstnat_lan; do
+       for i in $chainsList dstnat; do
                i="$(str_to_lower "$i")"
                nft_call flush chain inet "$nftTable" "${nftPrefix}_${i}"
        done
@@ -1172,7 +1174,7 @@ dns_policy_routing() {
        local negation value dest4 dest6 first_value
        local inline_set_ipv4_empty_flag inline_set_ipv6_empty_flag
        local name="$1" src_addr="$2" dest_dns="$3" uid="$4"
-       local chain='dstnat_lan' iface='dns'
+       local chain='dstnat' iface='dns'
 
        if [ -z "${dest_dns_ipv4}${dest_dns_ipv6}" ]; then
                processPolicyError='true'
@@ -1197,8 +1199,8 @@ dns_policy_routing() {
                unset param4
                unset param6
 
-               dest4="dport 53 counter dnat ip to ${dest_dns_ipv4}:53"
-               dest6="dport 53 counter dnat ip6 to ${dest_dns_ipv6}:53"
+               dest4="dport 53 dnat ip to ${dest_dns_ipv4}:53"
+               dest6="dport 53 dnat ip6 to ${dest_dns_ipv6}:53"
 
                if [ -n "$src_addr" ]; then
                        if [ "${src_addr:0:1}" = "!" ]; then
@@ -1237,8 +1239,8 @@ dns_policy_routing() {
                        fi
                fi
 
-               param4="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param4} ${proto_i} ${nft_rule_params} ${dest4} comment \"$name\""
-               param6="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param6} ${proto_i} ${nft_rule_params} ${dest6} comment \"$name\""
+               param4="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param4} ${nft_rule_params} meta nfproto ipv4 ${proto_i} ${dest4} comment \"$name\""
+               param6="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param6} ${nft_rule_params} meta nfproto ipv6 ${proto_i} ${dest6} comment \"$name\""
 
                local ipv4_error='0' ipv6_error='0'
                if [ "$policy_routing_nft_prev_param4" != "$param4" ] && \
@@ -1439,13 +1441,14 @@ policy_routing() {
                        local dest_udp_53 dest_tcp_80 dest_udp_80 dest_tcp_443 dest_udp_443
                        local ipv4_error='0' ipv6_error='0'
                        local dest_i dest4 dest6
-                       param4="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} dstnat meta nfproto ipv4 $param4"
-                       param6="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} dstnat meta nfproto ipv6 $param6"
-                       dest_udp_53="udp dport 53 counter redirect to :${torDnsPort} comment 'Tor-DNS-UDP'"
-                       dest_tcp_80="tcp dport 80 counter redirect to :${torTrafficPort} comment 'Tor-HTTP-TCP'"
-                       dest_udp_80="udp dport 80 counter redirect to :${torTrafficPort} comment 'Tor-HTTP-UDP'"
-                       dest_tcp_443="tcp dport 443 counter redirect to :${torTrafficPort} comment 'Tor-HTTPS-TCP'"
-                       dest_udp_443="udp dport 443 counter redirect to :${torTrafficPort} comment 'Tor-HTTPS-UDP'"
+                       chain='dstnat'
+                       param4="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} ${nft_rule_params} meta nfproto ipv4 $param4"
+                       param6="$nftInsertOption rule inet $nftTable ${nftPrefix}_${chain} ${nft_rule_params} meta nfproto ipv6 $param6"
+                       dest_udp_53="udp dport 53 redirect to :${torDnsPort} comment 'Tor-DNS-UDP'"
+                       dest_tcp_80="tcp dport 80 redirect to :${torTrafficPort} comment 'Tor-HTTP-TCP'"
+                       dest_udp_80="udp dport 80 redirect to :${torTrafficPort} comment 'Tor-HTTP-UDP'"
+                       dest_tcp_443="tcp dport 443 redirect to :${torTrafficPort} comment 'Tor-HTTPS-TCP'"
+                       dest_udp_443="udp dport 443 redirect to :${torTrafficPort} comment 'Tor-HTTPS-UDP'"
                        for dest_i in dest_udp_53 dest_tcp_80 dest_udp_80 dest_tcp_443 dest_udp_443; do
                                eval "dest4=\$$dest_i"
                                eval "dest6=\$$dest_i"
@@ -1483,7 +1486,6 @@ policy_routing() {
                                        nft6 "$param6" || ipv6_error='1'
                                        policy_routing_nft_prev_param6="$param6"
                        fi
-
                        if [ -n "$ipv6_enabled" ] && [ "$ipv4_error" -eq '1' ] && [ "$ipv6_error" -eq '1' ]; then
                                processPolicyError='true'
                                state add 'errorSummary' 'errorPolicyProcessInsertionFailed' "$name"
@@ -1816,7 +1818,7 @@ json_add_gateway() {
        json_close_object
 }
 
-interface_process() {
+process_interface() {
        local gw4 gw6 dev dev6 s=0 dscp iface="$1" action="$2" reloadedIface="$3"
        local displayText dispDev dispGw4 dispGw6 dispStatus
 
@@ -2080,8 +2082,8 @@ start_service() {
        load_environment "${param:-on_start}" "$(load_validate_config)" || return 1
        is_wan_up "$param" || return 1
 
-       interface_process 'all' 'prepare'
-       config_foreach interface_process 'interface' 'pre_init'
+       process_interface 'all' 'prepare'
+       config_foreach process_interface 'interface' 'pre_init'
 
        case "$param" in
                on_boot)
@@ -2137,8 +2139,8 @@ start_service() {
                on_interface_reload)
                        output 1 "Reloading Interface: $reloadedIface "
                        json_add_array 'gateways'
-                       interface_process 'all' 'prepare'
-                       config_foreach interface_process 'interface' 'reload_interface' "$reloadedIface"
+                       process_interface 'all' 'prepare'
+                       config_foreach process_interface 'interface' 'reload_interface' "$reloadedIface"
                        json_close_array
                        output 1 '\n'
                ;;
@@ -2154,10 +2156,10 @@ start_service() {
                        nft_file 'create'
                        output 1 'Processing interfaces '
                        json_add_array 'gateways'
-                       interface_process 'all' 'prepare'
-                       config_foreach interface_process 'interface' 'create'
-                       interface_process 'tor' 'destroy'
-                       is_tor_running && interface_process 'tor' 'create'
+                       process_interface 'all' 'prepare'
+                       config_foreach process_interface 'interface' 'create'
+                       process_interface 'tor' 'destroy'
+                       is_tor_running && process_interface 'tor' 'create'
                        json_close_array
                        ip route flush cache
                        output 1 '\n'
@@ -2174,8 +2176,8 @@ start_service() {
                                output 1 '\n'
                        fi
                        if is_config_enabled 'include' || [ -d "/etc/${packageName}.d/" ]; then
-                               interface_process 'all' 'prepare'
-                               config_foreach interface_process 'interface' 'create_user_set'
+                               process_interface 'all' 'prepare'
+                               config_foreach process_interface 'interface' 'create_user_set'
                                output 1 'Processing user file(s) '
                                config_load "$packageName"
                                config_foreach load_validate_include 'include' user_file_process
@@ -2270,8 +2272,8 @@ stop_service() {
        cleanup_marking_chains
        output 1 'Resetting interfaces '
        config_load 'network'
-       config_foreach interface_process 'interface' 'destroy'
-       interface_process 'tor' 'destroy'
+       config_foreach process_interface 'interface' 'destroy'
+       process_interface 'tor' 'destroy'
        cleanup_rt_tables
        output 1 "\\n"
        ip route flush cache
@@ -2324,7 +2326,7 @@ status_service() {
        fi
        echo "$_SEPARATOR_"
        echo "$packageName chains - policies"
-       for i in $chainsList dstnat_lan; do
+       for i in $chainsList dstnat; do
                "$nft" -a list table inet "$nftTable" | sed -n "/chain ${nftPrefix}_${i} {/,/\t}/p"
        done
        echo "$_SEPARATOR_"
@@ -2377,6 +2379,7 @@ load_validate_config() {
                'procd_boot_delay:integer:0' \
                'procd_boot_timeout:integer:30' \
                'procd_reload_delay:integer:0' \
+               'procd_lan_interface:list(or(network)):br-lan' \
                'procd_wan_ignore_status:bool:0' \
                'procd_wan_interface:network:wan' \
                'procd_wan6_interface:network:wan6' \
diff --git a/net/pbr/files/usr/share/nftables.d/chain-post/dstnat/30-pbr.nft b/net/pbr/files/usr/share/nftables.d/chain-post/dstnat/30-pbr.nft
new file mode 100644 (file)
index 0000000..987eece
--- /dev/null
@@ -0,0 +1 @@
+jump pbr_dstnat comment "Jump into pbr dstnat chain";
diff --git a/net/pbr/files/usr/share/nftables.d/chain-post/dstnat_lan/30-pbr.nft b/net/pbr/files/usr/share/nftables.d/chain-post/dstnat_lan/30-pbr.nft
deleted file mode 100644 (file)
index 2434649..0000000
+++ /dev/null
@@ -1 +0,0 @@
-jump pbr_dstnat_lan comment "Jump into pbr dstnat_lan chain";
index 0a9118d834d84f1a531d31786b53dfae78228ff7..637ed9270f8021442444314b6f76bd578023d261 100644 (file)
@@ -1,4 +1,4 @@
-chain pbr_dstnat_lan {}
+chain pbr_dstnat {}
 chain pbr_forward {}
 chain pbr_input {}
 chain pbr_output {}
index 46cd4b3f1a1e621c1870d46505219546b8e86b69..8efcc0dea1d23df436341f589bc77bdaed2a0ecf 100644 (file)
@@ -1,34 +1,29 @@
 #!/bin/sh
-# This file is heavily based on code from https://github.com/Xentrk/netflix-vpn-bypass/blob/master/IPSET_Netflix.sh
-
-TARGET_INTERFACE='wan'
-TARGET_NFTSET_4="pbr_${TARGET_INTERFACE}_4_dst_ip_user"
-TARGET_NFTSET_6="pbr_${TARGET_INTERFACE}_6_dst_ip_user"
+# shellcheck disable=SC2015,SC3003,SC3060
+TARGET_URL='https://ip-ranges.amazonaws.com/ip-ranges.json'
+TARGET_DL_FILE='/var/pbr_tmp_aws_ip_ranges.gz'
 TARGET_TABLE='inet fw4'
-TARGET_URL="https://ip-ranges.amazonaws.com/ip-ranges.json"
-TARGET_DL_FILE_4="/var/pbr_tmp_aws_ip_ranges.ipv4"
-# Uncomment the following line if you enabled ipv6 for pbr and want IPv6 entries added to the IPv6 set
-# TARGET_DL_FILE_6="/var/pbr_tmp_aws_ip_ranges.ipv6"
-_ret=0
+TARGET_INTERFACE='wan'
+
+_ret=1
 
-if [ ! -s "$TARGET_DL_FILE_4" ]; then
-       uclient-fetch --no-check-certificate -qO- "$TARGET_URL" 2>/dev/null | grep "ip_prefix" | sed 's/^.*\"ip_prefix\": \"//; s/\",//' > "$TARGET_DL_FILE_4"
-fi
+mkdir -p "${TARGET_DL_FILE%/*}"
 
-if [ -s "$TARGET_DL_FILE_4" ]; then
-       params=
-       while read -r p; do params="${params:+$params, }${p}"; done < "$TARGET_DL_FILE_4"
-       [ -n "$params" ] && nft "add element $TARGET_TABLE $TARGET_NFTSET_4 { $params }" || _ret=1
-fi
+[ -s "$TARGET_DL_FILE" ] || \
+       uclient-fetch --no-check-certificate -qO- "$TARGET_URL" | \
+               gzip > "$TARGET_DL_FILE"
 
-if [ -n "$TARGET_DL_FILE_6" ] && [ ! -s "$TARGET_DL_FILE_6" ]; then
-       uclient-fetch --no-check-certificate -qO- "$TARGET_URL" 2>/dev/null | grep "ipv6_prefix" | sed 's/^.*\"ipv6_prefix\": \"//; s/\",//' > "$TARGET_DL_FILE_6"
-fi
+[ "$(uci get pbr.config.ipv6_enabled)" = "1" ] && vers="4 6" || vers="4"
 
-if [ -s "$TARGET_DL_FILE_6" ]; then
-       params=
-       while read -r p; do params="${params:+$params, }${p}"; done < "$TARGET_DL_FILE_6"
-       [ -n "$params" ] && nft "add element $TARGET_TABLE $TARGET_NFTSET_6 { $params }" || _ret=1
-fi
+for ver in $vers;do
+       case "$ver" in
+               4) search='@.prefixes[*].ip_prefix';;
+               6) search='@.ipv6_prefixes[*].ipv6_prefix';;
+       esac
+       params="$(zcat "$TARGET_DL_FILE" | jsonfilter -e "$search")"
+       [ -n "$params" ] && _ret=0 || continue
+       nftset="pbr_${TARGET_INTERFACE}_${ver}_dst_ip_user"
+       nft "add element $TARGET_TABLE $nftset { ${params//$'\n'/, } }" || _ret=1
+done
 
 return $_ret