pbr: update to 1.2.2-r8

* bugfix: don't mask RFC1918 in the support output
* bugfix: proper processing of downed interfaces

Thanks to everyone who reported/tested and @egc112 for collecting feedback.

Signed-off-by: Stan Grishin <stangri@melmac.ca>
This commit is contained in:
Stan Grishin
2026-03-02 20:29:26 +00:00
parent 072f32fee3
commit 38313ec4b4
3 changed files with 133 additions and 17 deletions

View File

@@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=pbr
PKG_VERSION:=1.2.2
PKG_RELEASE:=6
PKG_RELEASE:=8
PKG_LICENSE:=AGPL-3.0-or-later
PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>

View File

@@ -2218,12 +2218,6 @@ interface_routing() {
try ip -4 rule replace fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
fi
if ! nft_file 'match' 'temp' "${nftPrefix}_mark_${mark}"; then
nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}"
nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} ${nftRuleParams} meta mark set (meta mark & ${fw_maskXor}) | ${mark}"
nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return"
fi
dscp="$(uci_get "$packageName" 'config' "${iface}_dscp" '0')"
if [ "$dscp" -ge '1' ] && [ "$dscp" -le '63' ]; then
nft add rule inet "$nftTable" "${nftPrefix}_prerouting ${nftIPv4Flag} dscp ${dscp} ${nftRuleParams} goto ${nftPrefix}_mark_${mark}"
@@ -2231,6 +2225,12 @@ interface_routing() {
if [ "$iface" = "$icmp_interface" ]; then
nft add rule inet "$nftTable" "${nftPrefix}_output ${nftIPv4Flag} protocol icmp ${nftRuleParams} goto ${nftPrefix}_mark_${mark}"
fi
elif [ -n "$strict_enforcement" ] && ! { is_split_uplink && [ "$iface" = "$uplink_interface6" ]; }; then
ipv4_error=0
ip -4 rule flush table "$tid" >/dev/null 2>&1
ip -4 route flush table "$tid" >/dev/null 2>&1
try ip -4 route replace unreachable default table "$tid" || ipv4_error=1
try ip -4 rule replace fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
fi
if [ -n "$ipv6_enabled" ] && [ -n "$dev6" ]; then
@@ -2256,12 +2256,6 @@ interface_routing() {
try ip -6 rule replace fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1
fi
if ! nft_file 'match' 'temp' "${nftPrefix}_mark_${mark}"; then
nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}"
nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} ${nftRuleParams} meta mark set (meta mark & ${fw_maskXor}) | ${mark}"
nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return"
fi
dscp="$(uci_get "$packageName" 'config' "${iface}_dscp" '0')"
if [ "$dscp" -ge '1' ] && [ "$dscp" -le '63' ]; then
nft add rule inet "$nftTable" "${nftPrefix}_prerouting ${nftIPv6Flag} dscp ${dscp} ${nftRuleParams} goto ${nftPrefix}_mark_${mark}"
@@ -2269,6 +2263,19 @@ interface_routing() {
if [ "$iface" = "$icmp_interface" ]; then
nft add rule inet "$nftTable" "${nftPrefix}_output ${nftIPv6Flag} protocol icmp ${nftRuleParams} goto ${nftPrefix}_mark_${mark}"
fi
elif [ -n "$ipv6_enabled" ] && [ -n "$strict_enforcement" ] && ! { is_split_uplink && [ "$iface" = "$uplink_interface4" ]; }; then
ipv6_error=0
ip -6 rule flush table "$tid" >/dev/null 2>&1
ip -6 route flush table "$tid" >/dev/null 2>&1
try ip -6 route replace unreachable default table "$tid" || ipv6_error=1
try ip -6 rule replace fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1
fi
# Always create the nft mark chain so policies can reference it
if ! nft_file 'match' 'temp' "${nftPrefix}_mark_${mark}"; then
nft add chain inet "$nftTable" "${nftPrefix}_mark_${mark}"
nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} ${nftRuleParams} meta mark set (meta mark & ${fw_maskXor}) | ${mark}"
nft add rule inet "$nftTable" "${nftPrefix}_mark_${mark} return"
fi
if [ "$ipv4_error" -eq '0' ] || [ "$ipv6_error" -eq '0' ]; then
@@ -2318,6 +2325,12 @@ interface_routing() {
fi
try ip -4 rule replace fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
fi
elif [ -n "$strict_enforcement" ] && ! { is_split_uplink && [ "$iface" = "$uplink_interface6" ]; }; then
ipv4_error=0
ip -4 rule flush table "$tid" >/dev/null 2>&1
ip -4 route flush table "$tid" >/dev/null 2>&1
try ip -4 route replace unreachable default table "$tid" || ipv4_error=1
try ip -4 rule replace fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv4_error=1
fi
if [ -n "$ipv6_enabled" ] && [ -n "$dev6" ]; then
@@ -2341,6 +2354,12 @@ interface_routing() {
fi
try ip -6 rule replace fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1
fi
elif [ -n "$ipv6_enabled" ] && [ -n "$strict_enforcement" ] && ! { is_split_uplink && [ "$iface" = "$uplink_interface4" ]; }; then
ipv6_error=0
ip -6 rule flush table "$tid" >/dev/null 2>&1
ip -6 route flush table "$tid" >/dev/null 2>&1
try ip -6 route replace unreachable default table "$tid" || ipv6_error=1
try ip -6 rule replace fwmark "${mark}/${fw_mask}" table "$tid" priority "$priority" || ipv6_error=1
fi
if [ "$ipv4_error" -eq '0' ] || [ "$ipv6_error" -eq '0' ]; then
@@ -3140,16 +3159,25 @@ print_config_masked() {
{
line = $0
result = ""
# Mask digits inside IPv4-looking tokens, keep dots
# RFC1918/loopback addresses are not sensitive — skip masking them
while (match(line, /([0-9]{1,3}\.){3}[0-9]{1,3}/)) {
ip = substr(line, RSTART, RLENGTH)
masked = ip
gsub(/[0-9]/, "*", masked)
line = substr(line, 1, RSTART-1) masked substr(line, RSTART+RLENGTH)
result = result substr(line, 1, RSTART-1)
line = substr(line, RSTART+RLENGTH)
if (ip ~ /^(10\.|127\.|192\.168\.)/ || ip ~ /^172\.(1[6-9]|2[0-9]|3[01])\./) {
result = result ip
} else {
masked = ip
gsub(/[0-9]/, "*", masked)
result = result masked
}
}
print line
print result line
}
' \
| sed -E 's/([a-fA-F0-9:]{2,}:){1,7}[a-fA-F0-9]{2,}/***/g'

View File

@@ -0,0 +1,88 @@
#!/bin/bash
# Test: print_config_masked - IP masking logic
. "$(dirname "$0")/../lib/setup.sh"
oneTimeTearDown() { rm -rf "${MOCK_ROOT:-}"; }
# Apply the IP-masking awk pass from print_config_masked to a single input line.
# Mirrors the second awk block in print_config_masked so we can test it in isolation
# without needing to write files to /etc/config/.
_mask_ips() {
printf '%s\n' "$1" | awk '
/^[ \t]*(option|list)[ \t]+allowed_ips[ \t]+/ { print; next }
{
line = $0; result = ""
while (match(line, /([0-9]{1,3}\.){3}[0-9]{1,3}/)) {
ip = substr(line, RSTART, RLENGTH)
result = result substr(line, 1, RSTART-1)
line = substr(line, RSTART+RLENGTH)
if (ip ~ /^(10\.|127\.|192\.168\.)/ || ip ~ /^172\.(1[6-9]|2[0-9]|3[01])\./)
result = result ip
else { masked = ip; gsub(/[0-9]/, "*", masked); result = result masked }
}
print result line
}
'
}
testPublicIPIsMasked() {
assertEquals "Public IP masked" \
" option gateway '*.*.*.*'" \
"$(_mask_ips " option gateway '1.2.3.4'")"
}
testRFC1918_10_preserved() {
assertEquals "10.x not masked" \
" option gateway '10.0.0.1'" \
"$(_mask_ips " option gateway '10.0.0.1'")"
}
testRFC1918_192_168_preserved() {
assertEquals "192.168.x not masked" \
" option gateway '192.168.1.254'" \
"$(_mask_ips " option gateway '192.168.1.254'")"
}
testRFC1918_172_16_preserved() {
assertEquals "172.16.x not masked" \
" option gateway '172.16.0.1'" \
"$(_mask_ips " option gateway '172.16.0.1'")"
}
testRFC1918_172_31_preserved() {
assertEquals "172.31.x not masked" \
" option gateway '172.31.255.254'" \
"$(_mask_ips " option gateway '172.31.255.254'")"
}
testBorderBelow_172_16_masked() {
assertEquals "172.15.x is not RFC1918 - masked" \
" option gateway '***.**.*.*'" \
"$(_mask_ips " option gateway '172.15.0.1'")"
}
testBorderAbove_172_31_masked() {
assertEquals "172.32.x is not RFC1918 - masked" \
" option gateway '***.**.*.*'" \
"$(_mask_ips " option gateway '172.32.0.1'")"
}
testLoopbackPreserved() {
assertEquals "127.x loopback not masked" \
" option dns '127.0.0.1'" \
"$(_mask_ips " option dns '127.0.0.1'")"
}
testAllowedIPsLineNotMasked() {
assertEquals "allowed_ips line bypasses IP masking" \
" option allowed_ips '8.8.8.8/32'" \
"$(_mask_ips " option allowed_ips '8.8.8.8/32'")"
}
testMixedLinePrivateAndPublic() {
assertEquals "Private preserved, public masked on same line" \
" option foo '192.168.1.1 *.*.*.*'" \
"$(_mask_ips " option foo '192.168.1.1 8.8.8.8'")"
}
. shunit2