Skip to content

Instantly share code, notes, and snippets.

@dreamcat4
Forked from bluewalk/vpn.sh
Created November 8, 2023 21:55
Show Gist options
  • Save dreamcat4/2ff8c6a3747d11a42d7819d1295aa698 to your computer and use it in GitHub Desktop.
Save dreamcat4/2ff8c6a3747d11a42d7819d1295aa698 to your computer and use it in GitHub Desktop.
VPN.SH script to tunnel specific VLAN through a WireGuard tunnel on an UDM Pro
#!/bin/sh
INTERFACE="vpn0"
MARK=100
TABLE="vpn"
SCRIPT_NAME="/etc/wireguard/scripts/vpn.sh"
# set this to the interface(s) on which you want WAN traffic to
# be routed through vpn. separate interfaces with spaces.
# e.g. "br0" or "br0 br1" etc.
INTERFACES="br100 wg0" # Proxied wifi and WireGuard tunnel from phone to use pihole etc.
# set this to the ASN networks which you want to exlude traffic from
# being routed through vpn. separate networks with spaces.
EXCLUDED_ASN="AS2906" # AS2906 = Netflix
EXCLUDED_DOMAINS="www.netflix.com netflix.com nflxext.com nflximg.net nflxso.net nflxvideo.net ichnaea-web.netflix.com"
################################# DO NOT EDIT #################################
MANGLE_CHAIN=$(echo ${TABLE} | tr a-z A-Z)
### ASN LIST ###
function setup_asn_lists() {
for asn in ${EXCLUDED_ASN}; do
ipset create ${asn} hash:net -exist
PREFIXES=`curl -s https://api.bgpview.io/asn/${asn}/prefixes | jq -r '.data.ipv4_prefixes[].prefix'`
for prefix in ${PREFIXES}; do
ipset add ${asn} ${prefix} -exist
done
done
}
function remove_asn_lists() {
for asn in ${EXCLUDED_ASN}; do
ipset destroy ${asn}
done;
}
### DMOAIN LIST ###
function setup_domain_list() {
ipset create VPN_EXCLUDED hash:ip -exist
ipset flush VPN_EXCLUDED
for domain in ${EXCLUDED_DOMAINS}; do
IPS=`nslookup -type=a ${domain} | grep "Address" | awk '{print $2}' | sed '1d'`
for ip in ${IPS}; do
ipset add VPN_EXCLUDED ${ip} -exist
done
done
}
function remove_domain_list() {
ipset destroy VPN_EXCLUDED
}
### IP4TABLES MANGLE ###
function add_ip4tables_mangle() {
iptables -w -t mangle -C ${1} || iptables -w -t mangle -A ${1}
}
function remove_ip4tables_mangle() {
iptables -w -t mangle -D ${1}
}
### IP RULE ###
function add_ip_rule() {
# Apply policy on mangle mark
if [[ $(ip rule show fwmark ${MARK} | wc -l) -eq 0 ]]; then
ip rule add fwmark ${MARK} table ${TABLE}
fi
}
function remove_ip_rule() {
# Remove policy on mangle mark
if [[ $(ip rule show fwmark ${MARK} | wc -l) -gt 0 ]]; then
ip rule delete fwmark ${MARK} table ${TABLE}
fi
}
### IP ROUTE ###
function add_ip_route() {
# Create routing table
if [[ $(cat /etc/iproute2/rt_tables | grep "${MARK} ${TABLE}" | wc -l) -eq 0 ]]; then
echo "${MARK} ${TABLE}" >> /etc/iproute2/rt_tables
fi
# Add default route to table
if [[ $(ip route show table ${TABLE} | wc -l) -eq 0 ]]; then
ip route add default dev ${INTERFACE} table ${TABLE}
fi
}
function remove_ip_route() {
# Remove default route to table
if [[ $(ip route show table ${TABLE} | wc -l) -gt 0 ]]; then
ip route delete default dev ${INTERFACE} table ${TABLE}
fi
}
### RULE WATCHER ###
# Kill the rule watcher (previously running up/down script for the tunnel device).
kill_rule_watcher() {
for p in $(pgrep -f "/bin/sh.*$(basename "$0") monitor"); do
if [ $p != $$ ]; then
kill -9 $p
fi
done
# ip rule del $ip_rule &> /dev/null || true
# ip -6 rule del $ip_rule &> /dev/null || true
}
# Run the rule watcher which will be used to re-add the policy-based ip rules
# if removed. Rule watcher keeps this script running in the background.
run_rule_watcher() {
kill_rule_watcher
(while :; do
add_ip_rule
sleep 5
done) &
}
### IP TABLES ###
function setup_iptables() {
# Add chain
iptables -t mangle -F ${MANGLE_CHAIN} || iptables -t mangle -N ${MANGLE_CHAIN}
# Exclude private networks
add_ip4tables_mangle "${MANGLE_CHAIN} -d 192.168.0.0/16 -j RETURN"
add_ip4tables_mangle "${MANGLE_CHAIN} -d 172.16.0.0/12 -j RETURN"
add_ip4tables_mangle "${MANGLE_CHAIN} -d 10.0.0.0/8 -j RETURN"
# Exclude defined ASN
for asn in ${EXCLUDED_ASN}; do
add_ip4tables_mangle "${MANGLE_CHAIN} -m set --match-set ${asn} dst -j RETURN"
done
# Exclude domains
add_ip4tables_mangle "${MANGLE_CHAIN} -m set --match-set VPN_EXCLUDED dst -j RETURN"
# Mark unmatched traffic
add_ip4tables_mangle "${MANGLE_CHAIN} -j MARK --set-mark ${MARK}"
# Apply PREROUTING
for intfc in ${INTERFACES}; do
add_ip4tables_mangle "PREROUTING -i ${intfc} -j ${MANGLE_CHAIN}"
done
# Add Masquerade
iptables -w -t nat -A POSTROUTING -o ${INTERFACE} -j MASQUERADE
# Add firewall rules - Block VPN from coming in
iptables -w -I FORWARD -i ${INTERFACE} -j DROP
iptables -w -I FORWARD -i ${INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -w -I FORWARD -o ${INTERFACE} -j ACCEPT
}
function remove_iptables() {
# Remove PREROUTING
for intfc in ${INTERFACES}; do
remove_ip4tables_mangle "PREROUTING -i ${intfc} -j ${MANGLE_CHAIN}"
done
# Remove chain
iptables -w -t mangle -F ${MANGLE_CHAIN}
iptables -w -t mangle -X ${MANGLE_CHAIN}
# Remove Masquerade
iptables -w -t nat -D POSTROUTING -o ${INTERFACE} -j MASQUERADE
# Remove firewall rules - Block VPN from coming in
iptables -w -D FORWARD -i ${INTERFACE} -j DROP
iptables -w -D FORWARD -i ${INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -w -D FORWARD -o ${INTERFACE} -j ACCEPT
}
if [[ $# -lt 1 ]]; then
echo "Uncorrect usage, use {up|down|monitor}"
exit 1
fi
case $1 in
monitor)
run_rule_watcher
;;
up)
# Apply rules and routes
setup_asn_lists
setup_domain_list
setup_iptables
add_ip_rule
add_ip_route
${SCRIPT_NAME} monitor
;;
down)
# Remove rules and routes
kill_rule_watcher
remove_ip_route
remove_ip_rule
remove_iptables
remove_domain_list
remove_asn_lists
;;
*)
echo "Uncorrect usage, use {up|down|monitor}"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment