VPN-PBR actually worked out better for me in the end - it allows me to give a fixed IP address to the computer I don't want to be on the VPN, and everything else stays on the VPN.
When I connect from a computer with an IP address of 192.168.1.(say110) it connects via VPN.
When I connect from a .98 or .99 computer, it does not use the VPN.
I (wrongly) assumed a WiFi connection would work the same way (the WiFi is on the same subnet). When I connect via WiFi, regardless of the computer IP address, the VPN is always used.
And you are right, there is no VPN visible in the service gateways. I guess it needs to be for correct functionality.
Any thoughts as to how to get my VPN to show up in the service gateways?
I am using the OpenVPN configuration in luci. I am not sure what interface name to add? I tried tun0, but it does not then show up in the policies interface drop down.
uci export network; uci export wireless
config interface 'loopback'
option ifname 'lo'
option proto 'static'
option ipaddr '127.0.0.1'
option netmask '255.0.0.0'
config globals 'globals'
option ula_prefix 'fdb8:dd48:fbae::/48'
config interface 'lan'
option type 'bridge'
option ifname 'eth0.1'
option proto 'static'
option ipaddr '192.168.1.1'
option netmask '255.255.255.0'
option ip6assign '60'
list dns '8.8.8.8'
list dns '8.8.4.4'
list dns '1.1.1.1'
config device 'lan_eth0_1_dev'
option name 'eth0.1'
option macaddr 'ec:ad:e0:20:a5:10'
config interface 'wan'
option ifname 'eth0.2'
option proto 'dhcp'
config device 'wan_eth0_2_dev'
option name 'eth0.2'
option macaddr 'ec:ad:e0:20:a5:0f'
config interface 'wan6'
option ifname 'eth0.2'
option proto 'dhcpv6'
config switch
option name 'switch0'
option reset '1'
option enable_vlan '1'
config switch_vlan
option device 'switch0'
option vlan '1'
option ports '0 1 2 3 6t'
config switch_vlan
option device 'switch0'
option vlan '2'
option ports '4 6t'
config interface 'wwan'
option proto 'qmi'
option device '/dev/cdc-wdm0'
option apn 'wapaccess.co.nz'
list dns '8.8.8.8'
list dns '8.8.4.4'
list dns '1.1.1.1'
package wireless
config wifi-device 'radio0'
option type 'mac80211'
option channel '11'
option hwmode '11g'
option path 'platform/10180000.wmac'
option htmode 'HT20'
config wifi-iface 'default_radio0'
option device 'radio0'
option network 'lan'
option mode 'ap'
option ssid 'OpenWrt'
option encryption 'none'
It's a tun interface so it must be detected from VPN-PBR. Could you try to connect the VPN and paste the output of /etc/init.d/vpn-policy-routing restart ?
I stopped and then started the VPN (luci, VPN, OpenVPN.
I then looked at /etc/init.d/vpn-policy-routing and I could not really see much under restart. I cant paste the full text from vpn-policy-routing because it is over the character limit - so I will spread it over two posts.....
Part 1
#!/bin/sh /etc/rc.common
# Copyright 2017-2020 Stan Grishin (stangri@melmac.net)
# shellcheck disable=SC2039,SC1091,SC2018,SC2019
PKG_VERSION='0.2.1-13'
export START=94
export USE_PROCD=1
readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m'
readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m'
readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m'
readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m'
readonly __PASS__='\033[0;33m[-]\033[0m'
readonly _ERROR_='\033[0;31mERROR\033[0m'
readonly _WARNING_='\033[0;33mWARNING\033[0m'
readonly readmeURL="https://github.com/openwrt/packages/tree/master/net/vpn-policy-routing/files/README.md"
export EXTRA_COMMANDS='support'
export EXTRA_HELP=" support Generates output required to troubleshoot routing issues
Use '-d' option for more detailed output
Use '-p' option to automatically upload data under VPR paste.ee account
WARNING: while paste.ee uploads are unlisted, they are still publicly available
List domain names after options to include their lookup in report"
readonly packageName='vpn-policy-routing'
readonly serviceName="$packageName $PKG_VERSION"
readonly PID="/var/run/${packageName}.pid"
readonly dnsmasqFile="/var/dnsmasq.d/${packageName}"
readonly userFile="/etc/${packageName}.user"
readonly sharedMemoryOutput="/dev/shm/$packageName-output"
create_lock() { [ -e "$PID" ] && return 1; touch "$PID"; }
remove_lock() { [ -e "$PID" ] && rm -f "$PID"; }
trap remove_lock EXIT
output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; }
output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; }
output_fail() { s=1; output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; }
output_failn() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; }
# str_replace() { printf "%b" "$1" | sed -e "s/$(printf "%b" "$2")/$(printf "%b" "$3")/g"; }
# str_contains() { [ "$1" != "$(str_replace "$1" "$2" "")" ]; }
# shellcheck disable=SC2018,SC2019
str_to_lower() { echo "$1" | tr 'A-Z' 'a-z'; }
str_extras_to_underscore() { echo "$1" | tr '[\. ~`!@#$%^&*()\+/,<>?//;:]' '_'; }
str_extras_to_space() { echo "$1" | tr ';{}' ' '; }
output() {
# Can take a single parameter (text) to be output at any verbosity
# Or target verbosity level and text to be output at specifc verbosity
local msg memmsg logmsg
if [ $# -ne 1 ]; then
if [ $((verbosity & $1)) -gt 0 ] || [ "$verbosity" = "$1" ]; then shift; else return 0; fi
fi
[ -t 1 ] && printf "%b" "$1"
msg="${1//$serviceName /service }";
if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then
[ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")"
logmsg="$(printf "%b" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')"
logger -t "${packageName:-service} [$$]" "$(printf "%b" "$logmsg")"
rm -f "$sharedMemoryOutput"
else
printf "%b" "$msg" >> "$sharedMemoryOutput"
fi
}
is_installed() { [ -s "/usr/lib/opkg/info/${1}.control" ]; }
export serviceEnabled verbosity strictMode wanTableID wanMark fwMask
export ipv6Enabled localIpset remoteIpset ipruleEnabled icmpIface
export ignoredIfaces="" supportedIfaces=""
export appendLocalPolicy="" appendRemotePolicy=""
export wanIface4 wanIface6 ifaceMark ifaceTableID ifAll ifSupported wanGW4 wanGW6
export bootTimeout insertOption
list_iface() { ifAll="${ifAll}${1} "; }
list_supported_iface() { is_supported_interface "$1" && ifSupported="${ifSupported}${1} "; }
vpr_find_true() {
local iface i param="$2"
[ "$param" = 'wan6' ] || param='wan'
"network_find_${param}" iface
is_tunnel "$iface" && unset iface
if [ -z "$iface" ]; then
unset ifAll; config_load 'network';
config_foreach list_iface 'interface'
for i in $ifAll; do
if "is_${param}" "$i"; then break; else unset i; fi
done
fi
export "$1=${iface:-$i}"
}
vpr_get_gateway() {
local iface="$2" dev="$3" gw
network_get_gateway gw "$iface"
if [ -z "$gw" ] || [ "$gw" = '0.0.0.0' ]; then
gw="$(ip -4 a list dev "$dev" 2>/dev/null | grep inet | awk '{print $2}' | awk -F "/" '{print $1}')"
fi
export "$1=$gw"
}
vpr_get_gateway6() {
local iface="$2" dev="$3" gw
network_get_gateway6 gw "$iface"
if [ -z "$gw" ] || [ "$gw" = '::/0' ] || [ "$gw" = '::0/0' ] || [ "$gw" = '::' ]; then
gw="$(ip -6 a list dev "$dev" 2>/dev/null | grep inet6 | awk '{print $2}')"
fi
export "$1=$gw"
}
is_l2tp() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:4}" = "l2tp" ]; }
is_oc() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:11}" = "openconnect" ]; }
is_ovpn() { local dev; dev=$(uci -q get network."$1".ifname); [ "${dev:0:3}" = "tun" ] || [ "${dev:0:3}" = "tap" ] || [ -f "/sys/devices/virtual/net/${dev}/tun_flags" ]; }
is_pptp() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:4}" = "pptp" ]; }
is_tor() { local dev; dev=$(uci -q get network."$1".ifname); [ "${dev:0:3}" = "tor" ]; }
is_wg() { local proto; proto=$(uci -q get network."$1".proto); [ "${proto:0:9}" = "wireguard" ]; }
is_tunnel() { is_l2tp "$1" || is_oc "$1" || is_ovpn "$1" || is_pptp "$1" || is_tor "$1" || is_wg "$1"; }
is_wan() { [ "$1" = "$wanIface4" ] || { [ "${1##wan}" != "$1" ] && [ "${1##wan6}" = "$1" ]; } || [ "${1%%wan}" != "$1" ]; }
is_wan6() { [ -n "$wanIface6" ] && [ "$1" = "$wanIface6" ] || [ "${1/#wan6}" != "$1" ] || [ "${1/%wan6}" != "$1" ]; }
string_match_word() { echo "$1" | grep -q -w "$2"; }
is_ignored_interface() { string_match_word "$ignoredIfaces" "$1"; }
is_supported_interface() { string_match_word "$supportedIfaces" "$1" || { ! is_ignored_interface "$1" && { is_wan "$1" || is_wan6 "$1" || is_tunnel "$1"; }; }; }
is_mac_address() { expr "$1" : '[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]$' >/dev/null; }
is_ipv4() { expr "$1" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null; }
is_ipv6() { ! is_mac_address "$1" && [ "${1//:}" != "$1" ]; }
is_ipv6_link_local() { [ "${1:0:4}" = "fe80" ]; }
is_ipv6_unique_local() { [ "${1:0:2}" = "fc" ] || [ "${1:0:2}" = "fd" ]; }
is_ipv6_global() { [ "${1:0:4}" = "2001" ]; }
# is_ipv6_global() { is_ipv6 "$1" && ! is_ipv6_link_local "$1" && ! is_ipv6_link_local "$1"; }
is_netmask() { local ip="${1%/*}"; [ "$ip" != "$1" ] && is_ipv4 "$ip"; }
is_domain() { [ "${1//[a-zA-Z-]}" != "$1" ]; }
is_phys_dev() { [ "${1:0:1}" = "@" ] && ip l show | grep -E -q "^\\d+\\W+${1:1}"; }
is_turris() { /bin/ubus -S call system board | /bin/grep 'Turris' | /bin/grep -q '15.05'; }
is_chaos_calmer() { ubus -S call system board | grep -q 'Chaos Calmer'; }
dnsmasq_kill() { killall -q -HUP dnsmasq; }
dnsmasq_restart() { output 1 'Restarting DNSMASQ '; if /etc/init.d/dnsmasq restart >/dev/null 2>&1; then output_okn; else output_failn; fi; }
is_default_dev() { [ "$1" = "$(ip -4 r | grep -m1 'dev' | grep -Eso 'dev [^ ]*' | awk '{print $2}')" ]; }
is_supported_iface_dev() {
for n in $ifSupported; do
if [ "$1" = "$(uci -q get "network.${n}.ifname" || echo "$n")" ] || [ "$1" = "$(uci -q get "network.${n}.proto")-${n}" ] ; then return 0; fi
done
return 1
}
is_supported_protocol () { grep -o '^[^#]*' /etc/protocols | grep -w -v '0' | grep . | awk '{print $1}' | grep -q "$1"; }
load_package_config() {
config_load "$packageName"
config_get_bool serviceEnabled 'config' 'enabled' 0
config_get_bool strictMode 'config' 'strict_enforcement' 1
config_get_bool ipv6Enabled 'config' 'ipv6_enabled' 0
config_get_bool localIpset 'config' 'src_ipset' 0
config_get_bool ipruleEnabled 'config' 'iprule_enabled' 0
config_get remoteIpset 'config' 'dest_ipset'
config_get appendLocalPolicy 'config' 'append_src_rules'
config_get appendRemotePolicy 'config' 'append_dest_rules'
config_get verbosity 'config' 'verbosity' '2'
config_get wanTableID 'config' 'wan_tid' '201'
config_get wanMark 'config' 'wan_mark' '0x010000'
config_get fwMask 'config' 'fw_mask' '0xff0000'
config_get icmpIface 'config' 'icmp_interface'
config_get ignoredIfaces 'config' 'ignored_interface'
config_get supportedIfaces 'config' 'supported_interface'
config_get bootTimeout 'config' 'boot_timeout' '30'
config_get insertOption 'config' 'iptables_rule_option' 'append'
if [ -z "${verbosity##*[!0-9]*}" ] || [ "$verbosity" -lt 0 ] || [ "$verbosity" -gt 2 ]; then
verbosity=1
fi
. /lib/functions/network.sh
. /usr/share/libubox/jshn.sh
vpr_find_true wanIface4 'wan'
[ "$ipv6Enabled" -ne 0 ] && vpr_find_true wanIface6 'wan6'
[ -n "$wanIface4" ] && network_get_gateway wanGW4 "$wanIface4"
[ -n "$wanIface6" ] && network_get_gateway6 wanGW6 "$wanIface6"
wanGW="${wanGW4:-$wanGW6}"
}
is_enabled() {
load_package_config
if [ "$serviceEnabled" -eq 0 ]; then
if [ "$1" = 'on_start' ]; then
output "$packageName is currently disabled.\\n"
output "Run the following commands before starting service again:\\n"
output "uci set $packageName.config.enabled='1'; uci commit;\\n"
fi
return 1
fi
case $insertOption in
insert|-i|-I) insertOption='-I';;
append|-a|-A|*) insertOption='-A';;
esac
case $remoteIpset in
ipset)
if ! ipset help hash:net >/dev/null 2>&1; then
output "$_ERROR_: ipset support is enabled in $packageName, but ipset is either not installed or installed ipset does not support 'hash:net' type!\\n"
unset remoteIpset
fi
;;
dnsmasq.ipset)
if dnsmasq -v 2>/dev/null | grep -q 'no-ipset' || ! dnsmasq -v 2>/dev/null | grep -q -w 'ipset'; then
output "$_ERROR_: DNSMASQ ipset support is enabled in $packageName, but DNSMASQ is either not installed or installed DNSMASQ does not support ipsets!\\n"
unset remoteIpset
fi
if ! ipset help hash:net >/dev/null 2>&1; then
output "$_ERROR_: DNSMASQ ipset support is enabled in $packageName, but ipset is either not installed or installed ipset does not support 'hash:net' type!\\n"
unset remoteIpset
fi
;;
*) unset remoteIpset;;
esac
if [ "$localIpset" -ne 0 ]; then
if ! ipset help hash:net >/dev/null 2>&1; then
output "$_ERROR_: Local ipset support is enabled in $packageName, but ipset is either not installed or installed ipset does not support 'hash:net' type!\\n"
unset localIpset
fi
if ! ipset help hash:mac >/dev/null 2>&1; then
output "$_ERROR_: Local ipset support is enabled in $packageName, but ipset is either not installed or installed ipset does not support 'hash:mac' type!\\n"
unset localIpset
fi
fi
}
is_wan_up() {
local sleepCount=1
while [ -z "$wanGW" ] ; do
vpr_find_true wanIface4 'wan'
[ "$ipv6Enabled" -ne 0 ] && vpr_find_true wanIface6 'wan6'
[ -n "$wanIface4" ] && network_get_gateway wanGW4 "$wanIface4"
[ -n "$wanIface6" ] && network_get_gateway6 wanGW6 "$wanIface6"
wanGW="${wanGW4:-$wanGW6}"
if [ $((sleepCount)) -gt $((bootTimeout)) ] || [ -n "$wanGW" ]; then break; fi
output "$serviceName waiting for wan gateway...\\n"; sleep 1; network_flush_cache; sleepCount=$((sleepCount+1));
done
mkdir -p "${PID%/*}"; mkdir -p "${dnsmasqFile%/*}";
unset ifSupported
config_load 'network'
config_foreach list_supported_iface 'interface'
if [ -n "$wanGW" ]; then
return 0
else
output "$_ERROR_: $serviceName failed to discover WAN gateway!\\n"
return 1
fi
}
ipt_cleanup() {
local i
for i in PREROUTING FORWARD INPUT OUTPUT; do
while iptables -t mangle -D $i -m mark --mark 0x0/0xff0000 -j VPR_${i} >/dev/null 2>&1; do : ; done
done
for i in PREROUTING FORWARD INPUT OUTPUT; do
while iptables -t mangle -D $i -j VPR_${i} >/dev/null 2>&1; do : ; done
done
}
# shellcheck disable=SC2086
ipt() {
local d failFlagIpv4=1 failFlagIpv6=1
for d in "${*//-A/-D}" "${*//-I/-D}" "${*//-N/-F}" "${*//-N/-X}"; do
[ "$d" != "$*" ] && { iptables $d >/dev/null 2>&1; ip6tables $d >/dev/null 2>&1; }
done
d="$*"; iptables $d >/dev/null 2>&1 && failFlagIpv4=0;
if [ "$ipv6Enabled" -gt 0 ]; then ip6tables $d >/dev/null 2>&1 && failFlagIpv6=0; fi
[ "$failFlagIpv4" -eq 0 ] || [ "$failFlagIpv6" -eq 0 ]
}
# shellcheck disable=SC2086
ips() {
local command="$1" ipset="${2//-/_}" param="$3" comment="$4" appendix failFlag=0
if [ "${ipset//_ip}" != "${ipset}" ]; then
ipset="${ipset//_ip}"; appendix='_ip';
elif [ "${ipset//_mac}" != "${ipset}" ]; then
ipset="${ipset//_mac}"; appendix='_mac';
fi
if [ "$command" = "add_dnsmasq" ]; then
[ "$remoteIpset" != 'dnsmasq.ipset' ] && return 1
# elif [ "$command" = "add_unbound" ]; then
# [ "$remoteIpset" != 'unbound.ipset' ] && return 1
else
if [[ -z "$appendix" && -z "$remoteIpset" ]] || \
[[ -n "$appendix" && "$localIpset" -eq 0 ]]; then
return 1
fi
fi
case "$command" in
add_dnsmasq)
echo "ipset=/${param}/${ipset} # $comment" >> "$dnsmasqFile" || failFlag=1
;;
add)
ipset -q -! $command "${ipset}${appendix}" $param comment "$comment" || failFlag=1
;;
create)
ipset -q -! "$command" "${ipset}${appendix}" $param || failFlag=1
;;
destroy|flush)
ipset -q -! "$command" "${ipset}${appendix}" 2>/dev/null || failFlag=1
return 0
;;
esac
return $failFlag
}
ipr()
{
[ "$ipruleEnabled" -ne 0 ] || return 1
local comment="$1" tid=$(eval echo "\$tid_${2//-/_}") laddr="$3" failFlagIpv4=0 failFlagIpv6=1
ip -4 rule del from "$laddr" table "$tid" >/dev/null 2>&1
ip -4 rule add from "$laddr" table "$tid" >/dev/null 2>&1 || failFlagIpv4=1
if [ "$ipv6Enabled" -ne 0 ]; then
ip -6 rule del from "$laddr" table "$tid" >/dev/null 2>&1
ip -6 rule add from "$laddr" table "$tid" >/dev/null 2>&1 && failFlagIpv6=0
fi
if [ "$failFlagIpv4" -eq 0 ] || [ "$failFlagIpv6" -eq 0 ]; then return 0; else return 1; fi
}
insert_tor_policy() {
local comment="$1" iface="$2" laddr="$3" lport="$4" raddr="$5" rport="$6" proto="$7" chain="${8:-PREROUTING}"
local mark=$(eval echo "\$mark_${iface//-/_}")
[ -z "$mark" ] && processPolicyError="${processPolicyError}${_ERROR_}: Unknown fw_mark for ${iface}##"
param="-t mangle $insertOption VPR_${chain} -j MARK --set-xmark ${mark}/${fwMask}"
[ -n "$laddr" ] && param="$param -s $laddr"
[ -n "$lport" ] && param="$param -p tcp -m multiport --sport ${lport//-/:}"
[ -n "$raddr" ] && param="$param -d $raddr"
[ -n "$rport" ] && param="$param -p $proto -m multiport --dport ${rport//-/:}"
[ -n "$comment" ] && param="$param -m comment --comment $(str_extras_to_underscore "$comment")"
# Here be dragons
return 0
}
insert_policy() {
local comment="$1" iface="$2" laddr="$3" lport="$4" raddr="$5" rport="$6" proto="$(str_to_lower "$7")" chain="${8:-PREROUTING}"
local mark=$(eval echo "\$mark_${iface//-/_}") param i valueNeg value
if [ "$ipv6Enabled" -eq 0 ]; then
is_ipv6 "$laddr" && return 0
is_ipv6 "$raddr" && return 0
fi
if is_ipv4 "$laddr" && is_ipv6 "$raddr"; then return 0; fi
if is_ipv6 "$laddr" && is_ipv4 "$raddr"; then return 0; fi
if [ -z "$mark" ]; then
processPolicyError="${processPolicyError}${_ERROR_}: Unknown fw_mark for ${iface}##"
return 0
fi
if [ -z "$proto" ]; then
if [ -n "$lport" ] || [ -n "$rport" ]; then
proto='tcp udp'
else
proto='all'
fi
fi
for i in $proto; do
if [ "$i" = 'all' ]; then
param="-t mangle -I VPR_${chain} -j MARK --set-xmark ${mark}/${fwMask}"
elif ! is_supported_protocol "$i"; then
processPolicyError="${processPolicyError}${_ERROR_}: Unknown protocol '$i' in policy '$comment'##"
return 0
else
param="-t mangle -I VPR_${chain} -j MARK --set-xmark ${mark}/${fwMask} -p $i"
fi
if [ -n "$laddr" ]; then
if [ "${laddr:0:1}" = "!" ]; then
valueNeg='!'; value="${laddr:1}"
else
unset valueNeg; value="$laddr";
fi
if is_phys_dev "$value"; then
param="$param $valueNeg -m physdev --physdev-in ${value:1}"
elif is_mac_address "$value"; then
param="$param -m mac $valueNeg --mac-source $value"
elif [ "${appendLocalPolicy//-d}" != "$appendLocalPolicy" ] && [ -n "$raddr" ]; then
param="$param $valueNeg -s $value"
processPolicyError="${processPolicyError}${_ERROR_}: Cannot append '$comment' policy with '$appendLocalPolicy' as destination is already set to '$raddr'##"
else
param="$param $valueNeg -s $value $appendLocalPolicy"
fi
fi
if [ -n "$lport" ]; then
if [ "${lport:0:1}" = "!" ]; then
valueNeg='!'; value="${lport:1}"
else
unset valueNeg; value="$lport";
fi
param="$param -m multiport $valueNeg --sport ${value//-/:}"
fi
if [ -n "$raddr" ]; then
if [ "${raddr:0:1}" = "!" ]; then
valueNeg='!'; value="${raddr:1}"
else
unset valueNeg; value="$raddr";
fi
if [ "${appendRemotePolicy//-s}" != "$appendRemotePolicy" ] && [ -n "$laddr" ]; then
param="$param $valueNeg -d $value"
processPolicyError="${processPolicyError}${_ERROR_}: Cannot append '$comment' policy with '$appendRemotePolicy' as source is already set to '$laddr'\\n"
else
param="$param $valueNeg -d $value $appendRemotePolicy"
fi
fi
if [ -n "$rport" ]; then
if [ "${rport:0:1}" = "!" ]; then
valueNeg='!'; value="${rport:1}"
else
unset valueNeg; value="$rport";
fi
param="$param -m multiport $valueNeg --dport ${value//-/:}"
fi
[ -n "$comment" ] && param="$param -m comment --comment $(str_extras_to_underscore "$comment")"
ipt "$param" || processPolicyError="${processPolicyError}${_ERROR_}: iptables $param\\n"
done
return 0
}
r_process_policy(){
local comment="$1" iface="$2" laddr="$3" lport="$4" raddr="$5" rport="$6" proto="$7" chain="$8" resolved_laddr resolved_raddr i ipsFailFlag
if [ "${laddr//[ ;\{\}]/}" != "$laddr" ]; then
for i in $(str_extras_to_space "$laddr"); do [ -n "$i" ] && r_process_policy "$comment" "$iface" "$i" "$lport" "$raddr" "$rport" "$proto" "$chain"; done
return 0
elif [ "${lport//[ ;\{\}]/}" != "$lport" ]; then
for i in $(str_extras_to_space "$lport"); do [ -n "$i" ] && r_process_policy "$comment" "$iface" "$laddr" "$i" "$raddr" "$rport" "$proto" "$chain"; done
return 0
elif [ "${raddr//[ ;\{\}]/}" != "$raddr" ]; then
for i in $(str_extras_to_space "$raddr"); do [ -n "$i" ] && r_process_policy "$comment" "$iface" "$laddr" "$lport" "$i" "$rport" "$proto" "$chain"; done
return 0
elif [ "${rport//[ ;\{\}]/}" != "$rport" ]; then
for i in $(str_extras_to_space "$rport"); do [ -n "$i" ] && r_process_policy "$comment" "$iface" "$laddr" "$lport" "$raddr" "$i" "$proto" "$chain"; done
return 0
fi
# start non-recursive processing
# process TOR, netmask, physical device and mac-address separately, so we don't send them to resolveip
if is_tor "$iface"; then
insert_tor_policy "$comment" "$iface" "$laddr" "$lport" "$raddr" "$rport" "$proto" "$chain"
elif is_phys_dev "$laddr"; then
insert_policy "$comment" "$iface" "$laddr" "$lport" "$raddr" "$rport" "$proto" "$chain"
elif [ -n "$laddr" ] && [ -z "${lport}${raddr}${rport}" ] && [ "$chain" = 'PREROUTING' ]; then
if is_mac_address "$laddr"; then
if [ -n "$proto" ] && [ "$proto" != 'all' ] && [ "$localIpset" -ne 0 ]; then
processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'proto' or set 'proto' to 'all' for policy '$comment', mac-address '$laddr'\\n"
fi
ips 'add' "${iface}_mac" "$laddr" "${comment}: $laddr" || ipsFailFlag=1
else
if [ -n "$proto" ] && [ "$proto" != "all" ] && [ "$localIpset" -ne 0 ]; then
processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'proto' or set 'proto' to 'all' for policy '$comment', address '$laddr'\\n"
fi
if ! ips 'add' "${iface}_ip" "$laddr" "${comment}: $laddr"; then
ipr "$comment" "$iface" "$i" || ipsFailFlag=1
fi
fi
elif [ -n "$raddr" ] && [ -z "${laddr}${lport}${rport}" ] && [ "$chain" = 'PREROUTING' ] && [ -n "$remoteIpset" ]; then
if [ -n "$proto" ] && [ "$proto" != 'all' ]; then
processPolicyWarning="${processPolicyWarning}${_WARNING_}: Please unset 'proto' or set 'proto' to 'all' for policy '$comment', domain '$raddr'\\n"
fi
case "$remoteIpset" in
ipset)
ips 'add' "${iface}" "$raddr" "${comment}: $raddr" || ipsFailFlag=1;;
dnsmasq.ipset)
if is_domain "$raddr"; then ips 'add_dnsmasq' "${iface}" "$raddr" "${comment}" || ipsFailFlag=1
else ips 'add' "${iface}" "$raddr" "${comment}: $raddr" || ipsFailFlag=1; fi;;
esac
else
ipsFailFlag=1
fi
if [ -n "$ipsFailFlag" ]; then
if is_mac_address "$laddr"; then
insert_policy "$comment" "$iface" "$laddr" "$lport" "$raddr" "$rport" "$proto" "$chain"
elif is_netmask "$laddr" || is_netmask "$raddr"; then
insert_policy "$comment" "$iface" "$laddr" "$lport" "$raddr" "$rport" "$proto" "$chain"
else
[ -n "$laddr" ] && resolved_laddr="$(resolveip "$laddr")"
[ -n "$raddr" ] && resolved_raddr="$(resolveip "$raddr")"
if [ -n "$resolved_laddr" ] && [ "$resolved_laddr" != "$laddr" ]; then
for i in $resolved_laddr; do [ -n "$i" ] && r_process_policy "$comment $laddr" "$iface" "$i" "$lport" "$raddr" "$rport" "$proto" "$chain"; done
elif [ -n "$resolved_raddr" ] && [ "$resolved_raddr" != "$raddr" ]; then
for i in $resolved_raddr; do [ -n "$i" ] && r_process_policy "$comment $raddr" "$iface" "$laddr" "$lport" "$i" "$rport" "$proto" "$chain"; done
else
insert_policy "$comment" "$iface" "$laddr" "$lport" "$raddr" "$rport" "$proto" "$chain"
fi
fi
fi
}
process_policy(){
local name comment iface laddr lport raddr rport param mark processPolicyError processPolicyWarning proto chain enabled
config_get comment "$1" 'comment'
config_get name "$1" 'name' 'blank'
config_get iface "$1" 'interface'
config_get laddr "$1" 'src_addr'
config_get lport "$1" 'src_port'
config_get raddr "$1" 'dest_addr'
config_get rport "$1" 'dest_port'
config_get proto "$1" 'proto'
config_get chain "$1" 'chain' 'PREROUTING'
config_get_bool enabled "$1" 'enabled' 1
[ "$enabled" -gt 0 ] || return 0
proto="$(str_to_lower "$proto")"
[ "$proto" = 'auto' ] && unset proto
comment="${comment:-$name}"
output 2 "Routing '$comment' via $iface "
if [ -z "$comment" ]; then
errorSummary="${errorSummary}${_ERROR_}: Policy name is empty\\n"
output_fail; return 1;
fi
if [ -z "${laddr}${lport}${raddr}${rport}" ]; then
errorSummary="${errorSummary}${_ERROR_}: Policy '$comment' missing all IPs/ports\\n"
output_fail; return 1;
fi
if [ -z "$iface" ]; then
errorSummary="${errorSummary}${_ERROR_}: Policy '$comment' has no assigned interface\\n"
output_fail; return 1;
fi
if ! is_supported_interface "$iface"; then
errorSummary="${errorSummary}${_ERROR_}: Policy '$comment' has unknown interface: '${iface}'\\n"
output_fail; return 1;
fi
lport="${lport// / }"; lport="${lport// /,}"; lport="${lport//,\!/ !}";
rport="${rport// / }"; rport="${rport// /,}"; rport="${rport//,\!/ !}";
r_process_policy "$comment" "$iface" "$laddr" "$lport" "$raddr" "$rport" "$proto" "$chain"
if [ -n "$processPolicyWarning" ]; then
warningSummary="${warningSummary}${processPolicyWarning}\\n"
fi
if [ -n "$processPolicyError" ]; then
output_fail
errorSummary="${errorSummary}${processPolicyError}\\n"
else
output_ok
fi
}
table_destroy(){
local tid="$1" iface="$2" mark="$3"
if [ -n "$tid" ] && [ -n "$iface" ] && [ -n "$mark" ]; then
ip -4 rule del fwmark "$mark" table "$tid" >/dev/null 2>&1
ip -6 rule del fwmark "$mark" table "$tid" >/dev/null 2>&1
ip -4 rule del table "$tid" >/dev/null 2>&1
ip -6 rule del table "$tid" >/dev/null 2>&1
ip -4 route flush table "$tid";
ip -6 route flush table "$tid";
ips 'flush' "${iface}"; ips 'destroy' "${iface}";
ips 'flush' "${iface}_ip"; ips 'destroy' "${iface}_ip";
ips 'flush' "${iface}_mac"; ips 'destroy' "${iface}_mac";
ip -4 route flush cache
ip -6 route flush cache
return 0
else
return 1
fi
}
# shellcheck disable=SC2086
table_create(){
local tid="$1" mark="$2" iface="$3" gw4="$4" dev="$5" gw6="$6" dev6="$7" dscp s=0 i ipv4_error=0 ipv6_error=0
if [ -z "$tid" ] || [ -z "$mark" ] || [ -z "$iface" ]; then
return 1
fi
table_destroy "$tid" "$iface" "$mark"
if [ -n "$gw4" ] || [ "$strictMode" -ne 0 ]; then
if [ -z "$gw4" ]; then
ip -4 route add unreachable default table "$tid" >/dev/null 2>&1 || ipv4_error=1
else
ip -4 route add default via "$gw4" dev "$dev" table "$tid" >/dev/null 2>&1 || ipv4_error=1
fi
ip -4 route ls table main | grep -v 'br-lan' | while read -r i; do
idev="$(echo "$i" | grep -Eso 'dev [^ ]*' | awk '{print $2}')"
if ! is_supported_iface_dev "$idev"; then
ip -4 route add $i table "$tid" >/dev/null 2>&1 || ipv4_error=1
fi
done
ip -4 route flush cache || ipv4_error=1
ip -4 rule add fwmark "${mark}/${fwMask}" table "$tid" || ipv4_error=1
fi
if [ "$ipv6Enabled" -ne 0 ]; then
if { [ -n "$gw6" ] && [ "$gw6" != "::/0" ]; } || [ "$strictMode" -ne 0 ]; then
if [ -z "$gw6" ] || [ "$gw6" = "::/0" ]; then
ip -6 route add unreachable default table "$tid" || ipv6_error=1
else
ip -6 route ls table main | grep " dev $dev6 " | while read -r i; do
ip -6 route add $i table "$tid" >/dev/null 2>&1 || ipv6_error=1
done
fi
ip -6 route flush cache || ipv6_error=1
ip -6 rule add fwmark "${mark}/${fwMask}" table "$tid" || ipv6_error=1
fi
fi
if [ $ipv4_error -eq 0 ] || [ $ipv6_error -eq 0 ]; then
dscp="$(uci -q get "${packageName}".config."${iface}"_dscp)"
if [ "${dscp:-0}" -ge 1 ] && [ "${dscp:-0}" -le 63 ]; then
ipt -t mangle -I VPR_PREROUTING -m dscp --dscp "${dscp}" -j MARK --set-xmark "${mark}/${fwMask}" || s=1
fi
if [ -n "$remoteIpset" ]; then
if ips 'create' "${iface}" 'hash:net comment' && ips 'flush' "${iface}"; then
for i in PREROUTING FORWARD INPUT OUTPUT; do
ipt -t mangle -I VPR_${i} -m set --match-set "${iface}" dst -j MARK --set-xmark "${mark}/${fwMask}" || s=1
done
else
s=1
fi
fi
if [ "$localIpset" -ne 0 ]; then
if ips 'create' "${iface}_ip" 'hash:net comment' && ips 'flush' "${iface}_ip"; then
ipt -t mangle -I VPR_PREROUTING -m set --match-set "${iface}_ip" src -j MARK --set-mark "${mark}/${fwMask}" || s=1
else
s=1
fi
if ips 'create' "${iface}_mac" 'hash:mac comment' && ips 'flush' "${iface}_mac"; then
ipt -t mangle -I VPR_PREROUTING -m set --match-set "${iface}_mac" src -j MARK --set-mark "${mark}/${fwMask}" || s=1
else
s=1
fi
fi
if [ "$iface" = "$icmpIface" ]; then
ipt -t mangle -I VPR_OUTPUT -p icmp -j MARK --set-xmark "${mark}/${fwMask}" || s=1
fi
else
s=1
fi
return $s
}
process_interface(){
local gw4 gw6 dev dev6 s=0 dscp iface="$1" action="$2" displayText
is_supported_interface "$iface" || return 0
is_wan6 "$iface" && return 0
[ $((ifaceMark)) -gt $((fwMask)) ] && return 1
network_get_device dev "$iface"
[ -z "$dev" ] && config_get dev "$iface" 'ifname'
if is_wan "$iface" && [ -n "$wanIface6" ]; then
network_get_device dev6 "$wanIface6"
[ -z "$dev6" ] && config_get dev6 "$wanIface6" 'ifname'
fi
[ -z "$dev6" ] && dev6="$dev"
[ -z "$ifaceTableID" ] && ifaceTableID="$wanTableID"; [ -z "$ifaceMark" ] && ifaceMark="$wanMark";
case "$action" in
destroy)
table_destroy "${ifaceTableID}" "${iface}" "${ifaceMark}"
ifaceTableID="$((ifaceTableID + 1))"; ifaceMark="$(printf '0x%06x' $((ifaceMark + wanMark)))";
;;
create)
export "mark_${iface//-/_}=$ifaceMark"; export "tid_${iface//-/_}=$ifaceTableID";
table_destroy "${ifaceTableID}" "${iface}"
vpr_get_gateway gw4 "$iface" "$dev"
vpr_get_gateway6 gw6 "$iface" "$dev6"
if [ "$iface" = "$dev" ]; then
displayText="${iface}/${gw4:-0.0.0.0}"
else
displayText="${iface}/${dev}/${gw4:-0.0.0.0}"
fi
[ "$ipv6Enabled" -ne 0 ] && displayText="${displayText}/${gw6:-::/0}"
output 2 "Creating table '$displayText' "
is_default_dev "$dev" && displayText="${displayText} ${__OK__}"
if table_create "$ifaceTableID" "$ifaceMark" "$iface" "$gw4" "$dev" "$gw6" "$dev6"; then
gatewaySummary="${gatewaySummary}${displayText}\\n"
output_ok
else
errorSummary="${errorSummary}${_ERROR_}: Failed to set up '$displayText'\\n"
output_fail
fi
ifaceTableID="$((ifaceTableID + 1))"; ifaceMark="$(printf '0x%06x' $((ifaceMark + wanMark)))";
;;
esac
return $s
}
convert_config(){
local i
[ -s "/etc/config/${packageName}" ] || return 0
sed -i 's/ignored_interfaces/ignored_interface/g' "/etc/config/${packageName}"
sed -i 's/supported_interfaces/supported_interface/g' "/etc/config/${packageName}"
sed -i 's/local_addresses/local_address/g' "/etc/config/${packageName}"
sed -i 's/local_ports/local_port/g' "/etc/config/${packageName}"
sed -i 's/remote_addresses/remote_address/g' "/etc/config/${packageName}"
sed -i 's/remote_ports/remote_port/g' "/etc/config/${packageName}"
sed -i 's/ipset_enabled/remote_ipset/g' "/etc/config/${packageName}"
sed -i 's/dnsmasq_enabled/dnsmasq_ipset/g' "/etc/config/${packageName}"
sed -i 's/enable_control/webui_enable_column/g' "/etc/config/${packageName}"
sed -i 's/proto_control/webui_protocol_column/g' "/etc/config/${packageName}"
sed -i 's/chain_control/webui_chain_column/g' "/etc/config/${packageName}"
sed -i 's/sort_control/webui_sorting/g' "/etc/config/${packageName}"
sed -i 's/local_address/src_addr/g' "/etc/config/${packageName}"
sed -i 's/local_port/src_port/g' "/etc/config/${packageName}"
sed -i 's/remote_address/dest_addr/g' "/etc/config/${packageName}"
sed -i 's/remote_port/dest_port/g' "/etc/config/${packageName}"
sed -i 's/append_local_rules/append_src_rules/g' "/etc/config/${packageName}"
sed -i 's/append_remote_rules/append_dest_rules/g' "/etc/config/${packageName}"
sync
config_load "$packageName"
config_get_bool dnsmasqIpset 'config' 'dnsmasq_ipset' 0
config_get remoteIpset 'config' 'remote_ipset'
config_get webuiProtocol 'config' 'webui_supported_protocol'
# shellcheck disable=SC2154
if [ "$dnsmasqIpset" = "1" ]; then
remoteIpset="dnsmasq.ipset";
elif [ "$remoteIpset" = "1" ]; then
remoteIpset="ipset";
elif [ "$remoteIpset" = "0" ]; then
remoteIpset=""
fi
uci -q del "$packageName.config.dnsmasq_ipset"
uci -q set "$packageName".config.remote_ipset="$remoteIpset"
# shellcheck disable=SC2154
if [ -z "$webuiProtocol" ]; then
uci add_list "$packageName".config.webui_supported_protocol='tcp'
uci add_list "$packageName".config.webui_supported_protocol='udp'
uci add_list "$packageName".config.webui_supported_protocol='tcp udp'
uci add_list "$packageName".config.webui_supported_protocol='icmp'
uci add_list "$packageName".config.webui_supported_protocol='all'
fi
uci commit "$packageName"
sed -i 's/local_ipset/src_ipset/g' "/etc/config/${packageName}"
sed -i 's/remote_ipset/dest_ipset/g' "/etc/config/${packageName}"
for i in udp_proto_enabled forward_chain_enabled input_chain_enabled output_chain_enabled; do
grep -q "$i" "/etc/config/${packageName}" && output "${_WARNING_}: $i setting is not supported in ${serviceName}.\\n"
done
}
check_config(){ local en; config_get_bool en "$1" 'enabled' 1; [ "$en" -gt 0 ] && _cfg_enabled=0; }
is_config_enabled(){
local cfg="$1" _cfg_enabled=1
[ -n "$1" ] || return 1
config_load "$packageName"
config_foreach check_config "$cfg"
return "$_cfg_enabled"
}
process_user_file(){
local path enabled shellBin="${SHELL:-/bin/ash}"
config_get_bool enabled "$1" 'enabled' 1
config_get path "$1" 'path'
[ "$enabled" -gt 0 ] || return 0
if [ ! -s "$path" ]; then
errorSummary="${errorSummary}${_ERROR_}: Custom user file '$path' not found or empty\\n"
output_fail
return 1
fi
if ! $shellBin -n "$path"; then
errorSummary="${errorSummary}${_ERROR_}: Syntax error in custom user file '$path'\\n"
output_fail
return 1
fi
Hi. This time. The 'test' and test2' are policies I tried - Which worked when I as plugged into the router by ethernet cable, but not when I am connected by WiFi.
Thank you!
root@OpenWrt:~# /etc/init.d/vpn-policy-routing restart
Creating table 'wan/eth0.2/0.0.0.0' [✓]
Creating table 'wwan/wwan0/100.107.xxx.xxx' [✓]
Routing 'test' via wwan [✓]
Routing 'test2' via wwan [✓]
vpn-policy-routing 0.2.1-13 started with gateways:
wan/eth0.2/0.0.0.0
wwan/wwan0/100.107.xxx.xxx
vpn-policy-routing 0.2.1-13 monitoring interfaces: wan wwan .
root@OpenWrt:~#
yes - the VPN interface is definitely up - no errors on the OpenVPN page, and IP address is from my VPN provider. If I check my IP address ('whatismyip'), I see it change from my local IP to a different country as OpenVPN starts. And it remains connected to this address, and internet working, etc.
The system log seems to show tun0 being created?
Sat Jul 4 18:44:06 2020 daemon.notice openvpn(StrongVPN)[1220]: TUN/TAP device tun0 opened
Sat Jul 4 18:44:06 2020 daemon.notice openvpn(StrongVPN)[1220]: TUN/TAP TX queue length set to 100
Sat Jul 4 18:44:06 2020 daemon.notice openvpn(StrongVPN)[1220]: /sbin/ifconfig tun0 10.8.0.14 pointopoint 10.8.0.13 mtu 1500
root@OpenWrt:~# ip -4 ro; /etc/init.d/vpn-policy-routing support
0.0.0.0/1 via 10.8.0.13 dev tun0
default via 100.87.xx.xxx dev wwan0 proto static src 100.87.xx.xxx
10.8.0.9 via 10.8.0.13 dev tun0 metric 1
10.8.0.13 dev tun0 proto kernel scope link src 10.8.0.14
100.87.xx.xxx/29 dev wwan0 proto kernel scope link src 100.87.xx.xxx
128.0.0.0/1 via 10.8.0.13 dev tun0
173.xxx.xxx.x via 100.87.xx.xxx dev wwan0
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1
vpn-policy-routing 0.2.1-13 running on OpenWrt 19.07.3. WAN (IPv4): wwan_4/dev/100.87.xx.xxx.
============================================================
Dnsmasq version 2.80 Copyright (c) 2000-2018 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset auth DNSSEC no-ID loop-detect inotify dumpfile
============================================================
Routes/IP Rules
default 10.8.0.13 128.0.0.0 UG 0 0 0 tun0
default 100.87.xx.xxx 0.0.0.0 UG 0 0 0 wwan0
IPv4 Table 201: unreachable default
100.87.xx.xxx/29 dev wwan0 proto kernel scope link src 100.87.xx.xxx
IPv4 Table 201 Rules:
32765: from all fwmark 0x10000/0xff0000 lookup 201
IPv4 Table 202: default via 100.87.96.155 dev wwan0
100.87.xx.xxx/29 dev wwan0 proto kernel scope link src 100.87.xx.xxx
IPv4 Table 202 Rules:
32764: from all fwmark 0x20000/0xff0000 lookup 202
============================================================
IP Tables PREROUTING
-N VPR_PREROUTING
-A VPR_PREROUTING -s 192.168.1.98/32 -m comment --comment test2 -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -s 192.168.1.99/32 -m comment --comment test -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -m set --match-set wwan dst -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -m set --match-set wan dst -c 0 0 -j MARK --set-xmark 0x10000/0xff0000
============================================================
IP Tables FORWARD
-N VPR_FORWARD
-A VPR_FORWARD -m set --match-set wwan dst -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_FORWARD -m set --match-set wan dst -c 0 0 -j MARK --set-xmark 0x10000/0xff0000
============================================================
IP Tables INPUT
-N VPR_INPUT
-A VPR_INPUT -m set --match-set wwan dst -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_INPUT -m set --match-set wan dst -c 0 0 -j MARK --set-xmark 0x10000/0xff0000
============================================================
IP Tables OUTPUT
-N VPR_OUTPUT
-A VPR_OUTPUT -m set --match-set wwan dst -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_OUTPUT -m set --match-set wan dst -c 0 0 -j MARK --set-xmark 0x10000/0xff0000
============================================================
Current ipsets
create wan hash:net family inet hashsize 1024 maxelem 65536 comment
create wwan hash:net family inet hashsize 1024 maxelem 65536 comment
============================================================
Your support details have been logged to '/var/vpn-policy-routing-support'. [✓]
root@OpenWrt:~#