PBR with netifd

  • This how-to describes the method for setting up PBR on OpenWrt.
  • It relies on netifd utilizing custom routing tables and rules.
  • Utilize multiple upstream interfaces with their own gateways.
  • Route different subnets/clients to a different gateway.
  • Prioritize routing for local subnets and tunnel endpoints.

Automatically set up PBR with netifd:

  • Provide the PBR protocol for netifd.
  • Set up named routing tables for each interface.
  • Assign each interface to its own routing table.
  • Use the PBR protocol for unmanaged interfaces.
  • Add default routing rules after subnets/endpoints.

Add custom routing rules before the default ones.

# Configure profile
mkdir -p /etc/profile.d
cat << "EOF" > /etc/profile.d/pbr.sh
setup_pbr() {
. /lib/functions.sh
. /lib/config/uci.sh
. /lib/functions/network.sh
setup_proto
config_load network
config_foreach setup_iface interface
setup_rules
uci_commit network
/etc/init.d/network restart
}
 
setup_proto() {
cat << "EOI" > /lib/netifd/proto/pbr.sh
#!/bin/sh
 
proto_pbr_setup() {
local NET_CONF="${1}"
local NET_DEV
local NET_RT
local NET_RT6
config_load network
config_get NET_DEV "${NET_CONF}" device
config_get NET_RT "${NET_CONF}" ip4table
config_get NET_RT6 "${NET_CONF}" ip6table
if [ -n "${NET_RT}" ]
then ip route add default dev "${NET_DEV}" table "${NET_RT}"
fi
if [ -n "${NET_RT6}" ]
then ip -6 route add default dev "${NET_DEV}" table "${NET_RT6}"
fi
proto_init_update "${NET_DEV}" 1
proto_send_update "${NET_CONF}"
}
 
proto_pbr_teardown() {
local NET_CONF="${1}"
}
 
if [ -z "${INCLUDE_ONLY}" ]
then
. /lib/functions.sh
. /lib/functions/network.sh
. ../netifd-proto.sh
init_proto "${@}"
add_protocol pbr
fi
EOI
chmod +x /lib/netifd/proto/pbr.sh
cat << "EOI" >> /etc/sysupgrade.conf
/lib/netifd/proto/pbr.sh
EOI
}
 
setup_iface() {
local NET_CONF="${1}"
local NET_PROTO
local NET_RT
local NET_RT6
local NET_RTCONF="/etc/iproute2/rt_tables"
local NET_RT0="$(sort -r -n "${NET_RTCONF}" \
| grep -o -E -m 1 "^[0-9]+")"
config_get NET_PROTO "${NET_CONF}" proto
config_get NET_RT "${NET_CONF}" ip4table "${NET_CONF}"
config_get NET_RT6 "${NET_CONF}" ip6table "${NET_CONF}"
case "${NET_CONF}" in
(loopback) return 0 ;;
esac
case "${NET_PROTO}" in
(gre*|vti*|vxlan|xfrm|relay) return 0 ;;
(none) NET_PROTO="pbr" ;;
(dhcp) NET_RT6= ;;
(dhcpv6) NET_RT=
NET_RT6="${NET_RT6%6}" ;;
esac
uci_set network "${NET_CONF}" proto "${NET_PROTO}"
uci_set network "${NET_CONF}" ip4table "${NET_RT}"
uci_set network "${NET_CONF}" ip6table "${NET_RT6}"
if ! grep -q -E -e "^[0-9]+\s+${NET_CONF}$" "${NET_RTCONF}"
then sed -i -e "\$a $((NET_RT0+1))\t${NET_CONF}" "${NET_RTCONF}"
fi
}
 
setup_rules() {
local NET_IF
local NET_IF6
local NET_RT
local NET_RT6
network_flush_cache
network_find_wan NET_IF
network_find_wan6 NET_IF6
NET_RT="${NET_IF}"
NET_RT6="${NET_IF6%6}"
uci_remove network default
uci_add network rule default
uci_set network default lookup "${NET_RT}"
uci_set network default priority "40000"
uci_remove network default6
uci_add network rule6 default6
uci_set network default6 lookup "${NET_RT6}"
uci_set network default6 priority "40000"
}
 
unset_pbr() {
. /lib/functions.sh
. /lib/config/uci.sh
unset_proto
config_load network
config_foreach unset_iface interface
unset_rules
uci_commit network
/etc/init.d/network restart
}
 
unset_proto() {
rm -f /lib/netifd/proto/pbr.sh
}
 
unset_iface() {
local NET_CONF="${1}"
local NET_PROTO
config_get NET_PROTO "${NET_CONF}" proto
case "${NET_CONF}" in
(loopback) return 0 ;;
esac
case "${NET_PROTO}" in
(gre*|vti*|vxlan|xfrm|relay) return 0 ;;
(pbr) NET_PROTO="none" ;;
esac
uci_set network "${NET_CONF}" proto "${NET_PROTO}"
uci_remove network "${NET_CONF}" ip4table
uci_remove network "${NET_CONF}" ip6table
}
 
unset_rules() {
uci_remove network default
uci_remove network default6
}
EOF
. /etc/profile.d/pbr.sh
 
# Set up PBR
setup_pbr

Use traceroute and traceroute6 to verify your traffic is routed via the proper gateway.

traceroute openwrt.org
traceroute6 openwrt.org

Check your public IP addresses.

Make sure there is no DNS leak.

Collect and analyze the following information.

# Restart services
/etc/init.d/log restart; /etc/init.d/network restart; sleep 10
 
# Log and status
logread; ifstatus wan; ifstatus wan6
 
# Runtime configuration
ip address show; ip route show table all
ip rule show; iptables-save -c
ip -6 rule show; ip6tables-save -c
 
# Persistent configuration
uci show network; uci show dhcp; uci show firewall
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2021/09/13 12:44
  • by vgaetera