[25.12] pbr: update to 1.2.2-r6#28642
Merged
stangri merged 1 commit intoopenwrt:openwrt-25.12from Feb 27, 2026
Merged
Conversation
Update pbr from 1.2.1-r87 to 1.2.2-r6. This release
adds mwan4 (Multi-WAN) integration, a diagnostic
`support` command, IPv6 lease-to-nftset handling,
improved split-uplink detection, stricter UCI
validation, shell variable quoting fixes across 30+
locations, and a comprehensive 126-case test suite
with a full mock OpenWrt sysroot.
Signed-off-by: Stan Grishin <stangri@melmac.ca>
---
- **31 files changed**, +1,745 / -227 lines
(net +1,518)
- **1 commit**: `61c8923` —
`pbr: update to 1.2.2-r6`
---
- Version bumped from `1.2.1-r87` to `1.2.2-r6`
- URL updated from `github.com/stangri/pbr/` to
`github.com/mossdef-org/pbr/`
- No dependency changes
---
Three options changed from scalar to list type:
| Option | Old Type | New Type |
|---------------------|----------|----------|
| `ignored_interface` | `option` | `list` |
| `lan_device` | `option` | `list` |
| `resolver_instance` | `option` | `list` |
Options reordered: scalars first, then lists,
matching UCI convention. No values changed.
---
The init script (`/etc/init.d/pbr`) received
significant additions and fixes across ~660 lines
(+443/-218).
Bumped from `24` to `25`.
**mwan4 (Multi-WAN) Integration (8 new functions):**
- `mwan4_is_installed()` — Detect mwan4 package
- `mwan4_is_running()` — Check service status
- `mwan4_get_iface_list()` — Get enabled interfaces
- `mwan4_get_strategy_list()` — Get strategies
- `mwan4_get_iface_mark_chain()` — Get nft mark
chain for interface
- `mwan4_get_iface_nft_sets()` — Get nftset names
- `mwan4_get_strategy_chain()` — Get strategy chain
- `mwan4_get_mmx_mask()` — Get Multi-WAN mark mask
Enables PBR to coordinate with mwan4 for combined
policy routing and multi-WAN failover.
**Diagnostic `support` Command:**
- New `support()` function generates masked
diagnostic output for troubleshooting
- `print_config_masked()` redacts sensitive data
(passwords, keys, tokens, PSKs, endpoints)
while preserving IP addresses and structure
**IPv6 Lease Handling:**
- New `ipv6_leases_to_nftset()` parses DHCPv6
leases from `/tmp/hosts/odhcpd`
- Complements existing `ipv4_leases_to_nftset()`
**Split Uplink Detection (3 new functions):**
- `is_uplink4()` — Check IPv4 uplink interface
- `is_uplink6()` — Check IPv6 uplink interface
- `is_uplink()` — Unified check (v4 or v6)
- New `ipv6_default_lookup` variable for split
IPv4/IPv6 uplink routing table assignment
**ubus Integration:**
- New `ubus_get_interface()` queries PBR gateway
data via ubus
**Shell Variable Quoting (30+ locations):**
Systematic conversion of bare variable references
to brace-quoted syntax throughout the script:
- `$2` to `${2}` in string replacements
- `$_ret` to `${_ret}` in conditional expansions
- `$_mark` to `${_mark}` in nft rule generation
- `$nftset6` to `${nftset6}` in dnsmasq rules
- `$nft_set_timeout` to `${nft_set_timeout}`
- `$xrayIfacePrefix` to `${xrayIfacePrefix}`
- And many more across rule generation, output
strings, and conditional expressions
**Specific Fixes:**
- `pbr_get_gateway6()`: Changed `is_wan` to
`is_uplink4` for correct IPv4 uplink detection
- `is_netifd_interface()`: Now checks both
`ip4table` and `ip6table` (was IPv4 only)
- `load_environment()`: Fixed inverted flag check
(`-z` changed to `-n` for `loadEnvironmentFlag`)
- Dnsmasq instance detection: Fixed UCI section
lookup with proper variable handling
- Help text URL: `#WarningMessagesDetails` changed
to `#warning-messages-details` (kebab-case)
- `uplink_ip_rules_priority`: Changed from
`uinteger` to `range(99,32765)` to enforce
valid Linux routing policy DB bounds
Three options now use `config_get_list` instead of
`config_get` to support multiple values:
- `ignored_interface`
- `lan_device`
- `resolver_instance`
**Rule Cleanup Refactored:**
- Replaced complex awk-based rule parsing with
priority-range approach
- Calculates `prio_min = priority - max_ifaces`
and `prio_max = priority`, iterates and deletes
rules within range
- Skips netifd-managed fwmark rules
- Added legacy rule cleanup for
`suppress_prefixlength` entries
**Firewall Sync:**
- Added `fw4 -q reload` after successful nft file
installation to ensure fw4 state synchronizes
with PBR's nftables changes
**Resolver Instance Handling:**
- Added robustness checks in
`_dnsmasq_instance_config()`: file existence
check and instance validity check
- Better section name resolution with UCI query
- Added missing `setup` parameter in resolver
instance setup calls
- `uci_get_device()` — Replaced with inline call
- `uci_get_protocol()` — Replaced with inline call
---
In `70-pbr`, fixed shell variable quoting:
```sh
${DEVICE:+ ($DEVICE)}
${DEVICE:+ (${DEVICE})}
```
---
In `pbr.user.netflix`, fixed two instances of
bare variable expansion in parameter substitution:
```sh
params="${params:+$params, }${p}"
params="${params:+${params}, }${p}"
```
---
A full test suite is added in `net/pbr/tests/`
(21 new files, ~1,300 lines) using the shunit2
framework with a complete mock OpenWrt sysroot.
**Runner (`run_tests.sh`):**
- Discovers test files via glob pattern
- Supports pattern-based filtering via CLI arg
- Executes each test in isolated bash subprocess
- Captures output, reports pass/fail with color
- Accumulates stats and lists failures at end
- Requires `shunit2` package
**Setup (`lib/setup.sh`):**
- Creates temporary mock sysroot (`$MOCK_ROOT`)
- Sets `IPKG_INSTROOT` for OpenWrt path resolution
- Installs mock libraries, configs, and binaries
- Stubs `rc.common`, procd, logger, resolveip,
jsonfilter, pidof, sync
- Sources pbr init script with `readonly` keyword
stripped (allows test overrides)
- Redirects all file paths to temp directories
**UCI Config API (`lib/mocks/functions.sh`):**
- Full `config_load` parser for UCI syntax
- `config_get`, `config_get_bool`,
`config_get_list`, `config_foreach`,
`config_list_foreach`
- `uci_set`, `uci_get`, `uci_add_list`,
`uci_remove`, `uci_remove_list`, `uci_commit`
- Stores state in associative arrays
**Network API (`lib/mocks/network.sh`):**
- `network_get_device`, `network_get_physdev`,
`network_get_gateway`, `network_get_gateway6`,
`network_get_protocol`, `network_get_ipaddr`,
`network_get_ip6addr`, `network_get_dnsserver`,
`network_flush_cache`
- Backed by `MOCK_NET_*` variables that tests
override to simulate different network states
- Pre-configured: wan (eth0/dhcp/192.168.1.1),
wan6 (eth0/dhcpv6/fd00::1), wg0 (wireguard),
lan (br-lan/static), loopback (lo/static)
**JSON Shell (`lib/mocks/jshn.sh`):**
- Minimal JSON-in-shell implementation
- `json_init`, `json_add_string/boolean/int`,
`json_add_object/array`, `json_close_*`,
`json_select`, `json_get_var`, `json_get_keys`,
`json_dump`, `json_load`
- Associative array backend with path tracking
**Mock Binaries:**
- `nft` — Returns fw4 table structure with
standard chains (input, forward, output,
dstnat, mangle_*); passes syntax checks
- `dnsmasq` — Reports version with nftset support
- `readlink` — Returns `/usr/libexec/ip-full`
for `*/sbin/ip` (simulates ip-full installed)
**Mock UCI Configs:**
- `pbr` — Full config: enabled, policies
(vpn_all, vpn_gaming, disabled_policy),
dns_policy, nft settings, interface lists
- `network` — Interfaces: loopback, lan, wan,
wan6, wg0 (wireguard)
- `firewall` — Zones: lan (accept all),
wan (reject input/forward)
- `dhcp` — DHCP server stub
- `system` — Hostname and timezone
**01_validation — Input Validation (67 cases):**
`01_ipv4_validation` (13 cases):
- Valid IPs: 192.168.1.1, 10.0.0.1, 172.16.0.1
- Valid CIDR: /8, /24, /32, /0
- Invalid: octets >255, wrong octet count,
CIDR >32, IPv6 addresses, domain names
`02_ipv6_validation` (21 cases):
- Valid: ::1, fe80::1, 2001:db8::1, fd00::1,
full addresses, ::/0
- Invalid: IPv4 addrs, plain strings, MACs
- Scope detection: global (2001:db8::/32),
link-local (fe80::/10), ULA (fd00::/8)
`03_domain_validation` (8 cases):
- Host: single labels (router, host123)
- Hostname: multi-label (example.com,
sub.example.com, deep.sub.example.com)
- Domain: FQDN or single-label
- Invalid: IPs, empty strings, MAC notation
`04_misc_validators` (25 cases):
- MAC addresses (colon notation, case variants)
- Integer validation (positive, not negative)
- Negation marker (! prefix detection)
- URL schemes (http, https, ftp, file://)
- Version comparison (is_greater,
is_greater_or_equal)
- Family mismatch (IPv4/IPv6 mixing detection)
**02_string_utils — String Functions (8 cases):**
`01_str_functions`:
- `str_contains` — Substring search
- `str_contains_word` — Word-boundary search
- `str_to_lower` / `str_to_upper` — Case convert
- `str_first_word` — Token extraction
- `str_replace` — String substitution
- `str_extras_to_underscore` — Normalize delims
- `str_extras_to_space` — Expand delimiters
**03_wan_detection — Interface Detection
(13 cases):**
`01_wan_types`:
- `is_wan4` — Detects wan/wanX, not wan6/lan/wg0
- `is_wan6` — Detects wan6/mwan6 (IPv6-aware)
- `is_wan6_disabled` — Disabled when ipv6 off
- `is_wan` — Unified v4+v6 detection
- `is_uplink4` / `is_uplink6` — Uplink detection
- `is_tor` — Case-insensitive tor detection
- `is_ignore_target` — Ignore target detection
- `is_list` — Comma/space list vs single value
**04_config — Configuration Loading (13 cases):**
`01_load_config` (7 cases):
- Default values from UCI config
- Hex value parsing (fw_mask, uplink_mark)
- XOR calculation (fw_maskXor = ~fw_mask)
- List parsing (ignored_interface, resolver)
- nft parameters (auto-merge, flags)
- Config-loaded flag tracking
`02_disabled_service` (2 cases):
- Disabled: enabled option becomes unset
- Enabled: enabled option is set
`03_config_ipv6` (4 cases):
- IPv6 enabled: config and uplink interface set
- IPv6 disabled: both unset
- Reload behavior verification
**05_nft — nftables Integration (14 cases):**
`01_nft_file_operations` (8 cases):
- File creation with nft shebang
- Chain creation (dstnat, forward, output,
prerouting)
- Jump rules and guard rules
- File append, content search, file deletion
`02_nft_check_element` (6 cases):
- fw4 table existence
- Chain existence (input, forward, output,
dstnat, mangle_*)
- Non-existent chain detection
**06_network — Network Functions (11 cases):**
`01_gateway_discovery` (4 cases):
- IPv4 gateway from mock (192.168.1.1)
- IPv4 gateway fallback (ip addr parsing)
- IPv6 gateway from mock (fd00::1)
- Interface finding for uplinks
`02_supported_interfaces` (7 cases):
- Ignored: loopback in ignored list
- LAN detection vs non-LAN
- Uplink support (wan is supported)
- LAN/loopback not supported
- Wireguard supported (wg0)
- Explicit custom interface support
---
```sh
cd net/pbr/tests && sh run_tests.sh
```
Requires: `bash`, `shunit2`.
Optional filter: `sh run_tests.sh 01_validation`
Signed-off-by: Stan Grishin <stangri@melmac.ca>
(cherry picked from commit cf1d277)
Signed-off-by: Stan Grishin <stangri@melmac.ca>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Maintainer: me
Compile tested: x86_64, Dell EMC Edge620, OpenWrt 25.12.0-rc4
Run tested: x86_64, Dell EMC Edge620, OpenWrt 25.12.0-rc4
Description:
Update pbr from 1.2.1-r87 to 1.2.2-r6. This release adds mwan4 (Multi-WAN) integration, a diagnostic
supportcommand, IPv6 lease-to-nftset handling,improved split-uplink detection, stricter UCI
validation, shell variable quoting fixes across 30+ locations, and a comprehensive 126-case test suite with a full mock OpenWrt sysroot.
61c8923—pbr: update to 1.2.2-r61.2.1-r87to1.2.2-r6github.com/stangri/pbr/togithub.com/mossdef-org/pbr/Three options changed from scalar to list type:
ignored_interfaceoptionlistlan_deviceoptionlistresolver_instanceoptionlistOptions reordered: scalars first, then lists,
matching UCI convention. No values changed.
The init script (
/etc/init.d/pbr) receivedsignificant additions and fixes across ~660 lines
(+443/-218).
Bumped from
24to25.mwan4 (Multi-WAN) Integration (8 new functions):
mwan4_is_installed()— Detect mwan4 packagemwan4_is_running()— Check service statusmwan4_get_iface_list()— Get enabled interfacesmwan4_get_strategy_list()— Get strategiesmwan4_get_iface_mark_chain()— Get nft mark chain for interfacemwan4_get_iface_nft_sets()— Get nftset namesmwan4_get_strategy_chain()— Get strategy chainmwan4_get_mmx_mask()— Get Multi-WAN mark maskEnables PBR to coordinate with mwan4 for combined
policy routing and multi-WAN failover.
Diagnostic
supportCommand:support()function generates masked diagnostic output for troubleshootingprint_config_masked()redacts sensitive data (passwords, keys, tokens, PSKs, endpoints) while preserving IP addresses and structureIPv6 Lease Handling:
ipv6_leases_to_nftset()parses DHCPv6 leases from/tmp/hosts/odhcpdipv4_leases_to_nftset()Split Uplink Detection (3 new functions):
is_uplink4()— Check IPv4 uplink interfaceis_uplink6()— Check IPv6 uplink interfaceis_uplink()— Unified check (v4 or v6)ipv6_default_lookupvariable for split IPv4/IPv6 uplink routing table assignmentubus Integration:
ubus_get_interface()queries PBR gateway data via ubusShell Variable Quoting (30+ locations):
Systematic conversion of bare variable references
to brace-quoted syntax throughout the script:
$2to${2}in string replacements$_retto${_ret}in conditional expansions$_markto${_mark}in nft rule generation$nftset6to${nftset6}in dnsmasq rules$nft_set_timeoutto${nft_set_timeout}$xrayIfacePrefixto${xrayIfacePrefix}Specific Fixes:
pbr_get_gateway6(): Changedis_wantois_uplink4for correct IPv4 uplink detectionis_netifd_interface(): Now checks bothip4tableandip6table(was IPv4 only)load_environment(): Fixed inverted flag check (-zchanged to-nforloadEnvironmentFlag)Dnsmasq instance detection: Fixed UCI section lookup with proper variable handling
Help text URL:
#WarningMessagesDetailschanged to#warning-messages-details(kebab-case)uplink_ip_rules_priority: Changed fromuintegertorange(99,32765)to enforce valid Linux routing policy DB boundsThree options now use
config_get_listinstead ofconfig_getto support multiple values:ignored_interfacelan_deviceresolver_instanceRule Cleanup Refactored:
prio_min = priority - max_ifacesandprio_max = priority, iterates and deletes rules within rangesuppress_prefixlengthentriesFirewall Sync:
fw4 -q reloadafter successful nft file installation to ensure fw4 state synchronizes with PBR's nftables changesResolver Instance Handling:
Added robustness checks in
_dnsmasq_instance_config(): file existence check and instance validity checkBetter section name resolution with UCI query
Added missing
setupparameter in resolver instance setup callsuci_get_device()— Replaced with inline calluci_get_protocol()— Replaced with inline callIn
70-pbr, fixed shell variable quoting:In
pbr.user.netflix, fixed two instances ofbare variable expansion in parameter substitution:
A full test suite is added in
net/pbr/tests/(21 new files, ~1,300 lines) using the shunit2
framework with a complete mock OpenWrt sysroot.
Runner (
run_tests.sh):shunit2packageSetup (
lib/setup.sh):$MOCK_ROOT)IPKG_INSTROOTfor OpenWrt path resolutionrc.common, procd, logger, resolveip, jsonfilter, pidof, syncreadonlykeyword stripped (allows test overrides)UCI Config API (
lib/mocks/functions.sh):config_loadparser for UCI syntaxconfig_get,config_get_bool,config_get_list,config_foreach,config_list_foreachuci_set,uci_get,uci_add_list,uci_remove,uci_remove_list,uci_commitNetwork API (
lib/mocks/network.sh):network_get_device,network_get_physdev,network_get_gateway,network_get_gateway6,network_get_protocol,network_get_ipaddr,network_get_ip6addr,network_get_dnsserver,network_flush_cacheMOCK_NET_*variables that tests override to simulate different network statesJSON Shell (
lib/mocks/jshn.sh):json_init,json_add_string/boolean/int,json_add_object/array,json_close_*,json_select,json_get_var,json_get_keys,json_dump,json_loadMock Binaries:
nft— Returns fw4 table structure with standard chains (input, forward, output, dstnat, mangle_*); passes syntax checksdnsmasq— Reports version with nftset supportreadlink— Returns/usr/libexec/ip-fullfor*/sbin/ip(simulates ip-full installed)Mock UCI Configs:
pbr— Full config: enabled, policies (vpn_all, vpn_gaming, disabled_policy), dns_policy, nft settings, interface listsnetwork— Interfaces: loopback, lan, wan, wan6, wg0 (wireguard)firewall— Zones: lan (accept all), wan (reject input/forward)dhcp— DHCP server stubsystem— Hostname and timezone01_validation — Input Validation (67 cases):
01_ipv4_validation(13 cases):02_ipv6_validation(21 cases):03_domain_validation(8 cases):04_misc_validators(25 cases):02_string_utils — String Functions (8 cases):
01_str_functions:str_contains— Substring searchstr_contains_word— Word-boundary searchstr_to_lower/str_to_upper— Case convertstr_first_word— Token extractionstr_replace— String substitutionstr_extras_to_underscore— Normalize delimsstr_extras_to_space— Expand delimiters03_wan_detection — Interface Detection
(13 cases):
01_wan_types:is_wan4— Detects wan/wanX, not wan6/lan/wg0is_wan6— Detects wan6/mwan6 (IPv6-aware)is_wan6_disabled— Disabled when ipv6 offis_wan— Unified v4+v6 detectionis_uplink4/is_uplink6— Uplink detectionis_tor— Case-insensitive tor detectionis_ignore_target— Ignore target detectionis_list— Comma/space list vs single value04_config — Configuration Loading (13 cases):
01_load_config(7 cases):02_disabled_service(2 cases):03_config_ipv6(4 cases):05_nft — nftables Integration (14 cases):
01_nft_file_operations(8 cases):02_nft_check_element(6 cases):06_network — Network Functions (11 cases):
01_gateway_discovery(4 cases):02_supported_interfaces(7 cases):Requires:
bash,shunit2.Optional filter:
sh run_tests.sh 01_validation(cherry picked from commit cf1d277)