Skip to content

Instantly share code, notes, and snippets.

@NerdyProjects
Created April 9, 2023 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NerdyProjects/059759af292887b93690fee852a36bf0 to your computer and use it in GitHub Desktop.
Save NerdyProjects/059759af292887b93690fee852a36bf0 to your computer and use it in GitHub Desktop.
OpenWRT VPN policy routing setup script
#!/bin/sh
# VPN policy routing setup generator for OpenWRT 22 & 23 (Snapshot as of 2023-04-09)
# Creates network devices / bridge for "WAN" and "LAN" and sets up policy routing so traffic from "LAN" only exits via VPN.
# Can be used simultaneously for multiple VPNs as long as their IP space is separate.
# Based on https://kiljan.org/2020/03/27/vpn-as-wan-for-guest-network-on-openwrt/
# interface name for lan interface (e.g. what clients will connect to).
# also used for bridge interface and firewall ruleset as well as routing table
LAN_IFNAME=guest
# IP address of this router on the lan interface. Will have DHCP enabled.
LAN_IP=192.168.42.1
# routing table ID
ROUTE_TABLE_ID=42
# interface name for wan interface to be created and linked to the OpenVPN instance
WAN_VPN_IFNAME=wan_pvpn
# OpenVPN tun interface name. Use explicit numbering also in OpenVPN config.
TUN=tun1
# Optionally, add route up/down scripts to OpenVPN config.
# alternatively, do the changes from the following lines manually:
#OVPN_CONF=/etc/openvpn/projekt.ovpn
#
#
#cat << EOI >> $OVPN_CONF
#route-noexec
#script-security 2
#route-up /etc/openvpn/routes-$LAN_IFNAME.sh
#route-pre-down /etc/openvpn/routes-$LAN_IFNAME.sh
#EOI
grep ^$ROUTE_TABLE_ID /etc/iproute2/rt_tables
if [ 0 -eq "$?" ]; then
echo routing table ID $ROUTE_TABLE_ID already exists, aborting
exit 1
fi
cat << EOF >> /etc/iproute2/rt_tables
$ROUTE_TABLE_ID $LAN_IFNAME
EOF
uci batch << EOI
set dhcp.$LAN_IFNAME=dhcp
set dhcp.$LAN_IFNAME.interface='$LAN_IFNAME'
set dhcp.$LAN_IFNAME.start='100'
set dhcp.$LAN_IFNAME.limit='150'
set dhcp.$LAN_IFNAME.leasetime='12h'
set dhcp.$LAN_IFNAME.dhcp_option='6,9.9.9.9,149.112.112.112'
EOI
DEVICE=$(uci add network device)
uci batch << EOI
set network.$DEVICE.type='bridge'
set network.$DEVICE.name='br-$LAN_IFNAME'
set network.$DEVICE.bridge_empty='1'
set network.$LAN_IFNAME=interface
set network.$LAN_IFNAME.proto='static'
set network.$LAN_IFNAME.device='br-$LAN_IFNAME'
set network.$LAN_IFNAME.ipaddr='$LAN_IP'
set network.$LAN_IFNAME.netmask='255.255.255.0'
set network.$LAN_IFNAME.delegate='0'
set network.$WAN_VPN_IFNAME=interface
set network.$WAN_VPN_IFNAME.proto='none'
set network.$WAN_VPN_IFNAME.device='$TUN'
EOI
RULE=$(uci add firewall rule)
uci batch << EOI
set firewall.$RULE.name='Allow $LAN_IFNAME dhcp'
set firewall.$RULE.proto='udp'
set firewall.$RULE.src='$LAN_IFNAME'
set firewall.$RULE.src_port='68'
set firewall.$RULE.dest_port='67'
set firewall.$RULE.target='ACCEPT'
set firewall.$RULE.family='ipv4'
EOI
ZONE_WAN_VPN=$(uci add firewall zone)
ZONE_LAN=$(uci add firewall zone)
FORWARDING=$(uci add firewall forwarding)
uci batch << EOI
set firewall.$ZONE_WAN_VPN.name='$WAN_VPN_IFNAME'
set firewall.$ZONE_WAN_VPN.input='REJECT'
set firewall.$ZONE_WAN_VPN.output='ACCEPT'
set firewall.$ZONE_WAN_VPN.forward='REJECT'
set firewall.$ZONE_WAN_VPN.masq='1'
set firewall.$ZONE_WAN_VPN.mtu_fix='1'
set firewall.$ZONE_WAN_VPN.network='$WAN_VPN_IFNAME'
set firewall.$ZONE_LAN.name='$LAN_IFNAME'
set firewall.$ZONE_LAN.input='REJECT'
set firewall.$ZONE_LAN.output='ACCEPT'
set firewall.$ZONE_LAN.forward='REJECT'
set firewall.$ZONE_LAN.network='$LAN_IFNAME'
set firewall.$FORWARDING.src='$LAN_IFNAME'
set firewall.$FORWARDING.dest='$WAN_VPN_IFNAME'
EOI
cat << EOF > /etc/openvpn/routes-$LAN_IFNAME.sh
#!/usr/bin/env sh
table=$LAN_IFNAME
if [ "\$script_type" == "route-up" ]; then
ip route add default via \$route_vpn_gateway dev \$dev table \$table proto static
elif [ "\$script_type" == "route-pre-down" ]; then
ip route del default via \$route_vpn_gateway dev \$dev table \$table proto static
fi
EOF
chmod +x /etc/openvpn/routes-$LAN_IFNAME.sh
cat << EOF >> /etc/sysupgrade.conf
/etc/hotplug.d/iface/99-$LAN_IFNAME
EOF
cat << EOF > /etc/hotplug.d/iface/99-$LAN_IFNAME
#!/usr/bin/env sh
if=$LAN_IFNAME
dev=\$DEVICE
table=\$INTERFACE
if2dev() {
dev=\$(uci get network.\$1.ifname)
[ \$(echo \$dev | wc -w) -gt 1 ] && dev=br-\$1
echo \$dev
}
if [ "\$INTERFACE" == "\$if" ]; then
if [ "\$ACTION" == "ifup" ]; then
ip rule add iif \$dev lookup \$table
elif [ "\$ACTION" == "ifdown" ]; then
# Workaround for missing \$DEVICE when interface is going down
dev=\$(if2dev \$if)
ip rule del iif \$dev lookup \$table
fi
fi
EOF
echo "Done. Please check and run uci commit, afterwards restart interfaces or router."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment