pbr2shunt.sh reads an existing pbr configuration and writes an equivalent shunt configuration. It is a one-shot helper for moving over, not part of the shunt package. pbr's config and a running shunt are never touched: the result goes to stdout or to a file of your choice, and everything that could not be carried over is reported on stderr.
The result needs shunt 0.2.0 or later: device selectors (src_dev) and policies that select by port alone do not exist in earlier versions.
pbr2shunt.sh [-c <confdir>] [-o <file>]| Option | Description |
|---|---|
-c |
UCI config directory to read pbr from, default /etc/config |
-o |
write the shunt config to <file> instead of stdout |
Typical run on the router:
sh pbr2shunt.sh -o /tmp/shunt.new
# read the report, review /tmp/shunt.new, then
cp /etc/config/shunt /etc/config/shunt.bak
cp /tmp/shunt.new /etc/config/shunt
service shunt restartExit codes: 0 everything migrated, 1 fatal error, 2 done, but sections or options were skipped - see the report.
The script needs /lib/functions.sh and /sbin/uci, so it runs on OpenWrt (busybox ash). Plain dash does not work, OpenWrt's functions.sh relies on export -n.
| pbr | shunt |
|---|---|
config.lan_device |
global.snoop_device |
config.strict_enforcement '1' (default) |
fallback 'block' on every routing policy, otherwise fallback 'main' |
policy name |
section name, reduced to [A-Za-z0-9_]{1,24} and made unique (_2, ...) |
policy enabled |
enabled '0' where pbr had it disabled |
interface 'ignore' |
action 'bypass' |
interface '<name>' (default wan) |
interface '<name>' |
src_addr addresses / CIDRs |
list src |
src_addr MAC addresses |
list src_mac, dash notation rewritten to colons |
src_addr devices (@br-guest) |
list src_dev; for a policy with domains the device is added to snoop_device as well, so shunt observes its clients' DNS answers |
dest_addr addresses / CIDRs |
list dst |
dest_addr domains |
list domain - with resolver_set 'dnsmasq.nftset' as name plus *.name, because dnsmasq includes subdomains; with none as name only, matching pbr's one-shot resolve |
dest_port |
list dport, also on its own - a policy with nothing but ports selects that traffic from every client |
proto tcp / udp |
list proto; auto / all are dropped |
Policy order is kept. Both pbr and shunt stop at the first matching policy, so precedence carries over unchanged. keep_local stays at its default: pbr already consults main with suppress_prefixlength ahead of its policy rules.
A policy containing any of the following is skipped as a whole, with the reason in the report - dropping just the offending part would silently widen or change what the policy matches:
src_port- shunt has no source port selector- negation (
!...) - shunt has none; express the exception as abypasspolicy above it protoother than tcp / udp (icmp, ...)- hostnames in
src_addr- use the client's address orsrc_mac - physical devices (
@dev) indest_addr- shunt has no output interface selector - URLs in
src_addrordest_addr- fetch the list outside shunt and usedst_fileordomain_file interface 'tor'andxray_*- for xray, write atproxypolicy by hand- policies without any source or destination selector - pbr rejects them
chain 'forward'orchain 'output'- shunt has no chain selector, the policy would match forwarded and router traffic alike- entries shunt would reject itself: malformed addresses, ports outside 1-65535, ranges that run backwards
Also reported, globally: enabled dns_policy and include sections, icmp_interface, and non-zero <iface>_dscp options. None of them has a shunt equivalent.
- shunt routes IPv4 and IPv6 alike. If pbr had
ipv6_enabled '0', policies selecting bysrc_mac,src_devor domain now steer IPv6 traffic as well - check that their interface carries IPv6, otherwise that traffic is lost in the tunnel. - pbr's default
preroutingchain never touched the router's own traffic. shunt applies address and domain policies inoutputtoo, so a policy without a client selector now also covers traffic the router itself generates. - Disabled pbr policies are migrated with
enabled '0'and marked(disabled)in the report. - pbr and shunt can run side by side during the move - their marks, rule priorities and tables do not overlap, and where both match pbr wins. Retire pbr once everything is verified, e.g. with
shunt check.