Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/sh
- #DEBUG= # uncomment/comment to enable/disable debug mode
- # name: merlin-ovpn-lan2wan-by-domain.sh
- # version: 3.1.0, 19-aug-2022, by eibgrad
- # purpose: route specific domains away from vpn and back to wan
- # type(s): dnsmasq.postconf, firewall-start, openvpn-event
- # href: https://tinyurl.com/yrarw2m9 (original version)
- # href: https://tinyurl.com/bdesfa32 (version 3.x.x)
- # installation:
- # 1. enable jffs custom scripts and configs (administration->system)
- # 2. ssh to router and copy/paste the following command:
- # curl -kLs bit.ly/merlin-installer|tr -d '\r'|sh -s 9jHRA6DG
- # 3. modify script w/ your preferred options using nano editor:
- # nano /jffs/configs/merlin-ovpn-lan2wan-by-domain.options
- # 4. reboot
- # limitations and known issues:
- # - 100% reliability can only be achieved by using either exclusive or
- # disabled for "accept dns configuration" on the openvpn client(s);
- # anything else risks dnsmasq choosing a dns server bound to the vpn
- CONFIGS_DIR='/jffs/configs'
- CONFIG="$CONFIGS_DIR/merlin-ovpn-lan2wan-by-domain.options"
- SCRIPTS_DIR='/jffs/scripts'
- SCRIPT1="$SCRIPTS_DIR/merlin-ovpn-lan2wan-by-domain.dnsmasq"
- SCRIPT2="$SCRIPTS_DIR/merlin-ovpn-lan2wan-by-domain.firewall"
- SCRIPT3="$SCRIPTS_DIR/merlin-ovpn-lan2wan-by-domain.openvpn"
- SCRIPT4="$SCRIPTS_DIR/dnsmasq.postconf"
- SCRIPT5="$SCRIPTS_DIR/firewall-start"
- SCRIPT6="$SCRIPTS_DIR/openvpn-event"
- mkdir -p $CONFIGS_DIR $SCRIPTS_DIR
- # --------------- begin merlin-ovpn-lan2wan-by-domain.options ---------------- #
- cat << 'EOF' > $CONFIG
- # ------------------------------ BEGIN OPTIONS ------------------------------- #
- # destination domains to be routed through wan
- DOMAINS='
- netflix.com
- nflxext.com
- nflximg.net
- nflxso.net
- nflxvideo.net
- '
- # specific source ip(s)/network(s) to be routed to destination domains
- SOURCES='
- 192.168.1.7
- 192.168.1.10
- 192.168.1.128/27
- '
- # uncomment/comment to route all/specific sources to destination domains
- SOURCES='0.0.0.0/0'
- # uncomment/comment to enable/disable logging of dns queries
- #LOG_QUERIES=
- # ------------------------------- END OPTIONS -------------------------------- #
- # ---------------------- DO NOT CHANGE BELOW THIS LINE ----------------------- #
- # resolved domains hash table
- RESOLVED_DOMAINS='ovpnc_resolved_domains'
- # verification/control domain (should *always* report wan public ip)
- VERIFY_DOMAIN='ipchicken.com'
- # firewall mark and chain for vpn bypass
- FW_MARK=0x10000/0x10000
- FW_CHAIN='ovpnc_dns2wan'
- EOF
- echo "installed: $CONFIG"
- # ---------------- end merlin-ovpn-lan2wan-by-domain.options ----------------- #
- # --------------- begin merlin-ovpn-lan2wan-by-domain.dnsmasq ---------------- #
- cat << 'EOF' > $SCRIPT1
- #!/bin/sh
- #set -x # comment/uncomment to disable/enable debug mode
- {
- . $CONFIG
- . /usr/sbin/helper.sh
- # optional: include diagnostic information
- [ ${LOG_QUERIES+x} ] && pc_append 'log-queries=extra' "$1"
- # initialize resolved domains hash table
- ipset -N $RESOLVED_DOMAINS iphash -q
- # for each domain, configure ipset directive (max five (5) per line)
- for dom in $VERIFY_DOMAIN $DOMAINS; do
- if [ $((n++ % 5)) -eq 0 ]; then
- [ "$str" ] && pc_append "$str/$RESOLVED_DOMAINS" "$1"
- str='ipset='
- fi
- str="$str/$dom"
- done
- [ "$str" ] && pc_append "$str/$RESOLVED_DOMAINS" "$1"
- exit 0
- } 2>&1 | logger -t $(basename $0)[$$]
- EOF
- [ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT1
- sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT1
- chmod +x $SCRIPT1
- echo "installed: $SCRIPT1"
- # ---------------- end merlin-ovpn-lan2wan-by-domain.dnsmasq ----------------- #
- # --------------- begin merlin-ovpn-lan2wan-by-domain.firewall --------------- #
- cat << 'EOF' > $SCRIPT2
- #!/bin/sh
- #set -x # comment/uncomment to disable/enable debug mode
- {
- . $CONFIG
- for src in $SOURCES; do
- # mark matching domains for the purposes of bypassing vpn
- iptables -t mangle -I PREROUTING -s $src \
- -m set --match-set $RESOLVED_DOMAINS dst -j RETURN
- iptables -t mangle -I PREROUTING -s $src \
- -m set --match-set $RESOLVED_DOMAINS dst -j MARK --set-mark $FW_MARK
- done
- # add to rpdb (routing policy database) w/ highest priority
- ip rule del fwmark $FW_MARK prio 10 table main 2>/dev/null
- ip rule add fwmark $FW_MARK prio 10 table main
- # disable reverse path filtering for the wan
- echo 2 > /proc/sys/net/ipv4/conf/$1/rp_filter
- # force routing system to recognize changes
- ip route flush cache
- # create user-defined chain for vpn bypass (dns only)
- iptables -t nat -N $FW_CHAIN
- for dom in $VERIFY_DOMAIN $DOMAINS; do
- # bypass vpn for dns purposes (tcp, port 53)
- iptables -t nat -A $FW_CHAIN -p tcp -m webstr --url "$dom" -j ACCEPT
- str=''
- for d in ${dom//./ }; do str="$str|$(printf '%.2x' ${#d})|$d"; done
- # bypass vpn for dns purposes (udp, port 53)
- iptables -t nat -A $FW_CHAIN -p udp -m string --icase \
- --hex-string "$str" --algo bm -j ACCEPT
- done
- # openvpn clients may need updating to bypass vpn for dns purposes
- for i in 1 2 3 4 5; do $SCRIPT3 $i; done
- exit 0
- } 2>&1 | logger -t $(basename $0)[$$]
- EOF
- [ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT2
- sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT2
- sed -i "s:\$SCRIPT3:$SCRIPT3:g" $SCRIPT2
- chmod +x $SCRIPT2
- echo "installed: $SCRIPT2"
- # ---------------- end merlin-ovpn-lan2wan-by-domain.firewall ---------------- #
- # --------------- begin merlin-ovpn-lan2wan-by-domain.openvpn ---------------- #
- cat << 'EOF' > $SCRIPT3
- #!/bin/sh
- #set -x # comment/uncomment to disable/enable debug mode
- {
- . $CONFIG
- # continue only if legitimate invocation
- [ $dev ] && { [[ ${dev:0:4} == 'tun1' && $script_type == 'route-up' ]] || exit 0; }
- [ $dev ] && CID=${dev:4:1} || CID=$1
- # continue only if dns is being rerouted over vpn (typical w/ exclusive)
- iptables -t nat -vnL | grep -q DNSVPN${CID} || exit 0
- iptables -t nat -vnL DNSVPN${CID} | grep -q $FW_CHAIN && exit 0
- for src in $SOURCES; do
- # bypass vpn for dns purposes w/ resolved domains
- iptables -t nat -I DNSVPN${CID} -s $src -j $FW_CHAIN
- done
- exit 0
- } 2>&1 | logger -t $(basename $0)[$$]
- EOF
- [ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT3
- sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT3
- chmod +x $SCRIPT3
- echo "installed: $SCRIPT3"
- # ---------------- end merlin-ovpn-lan2wan-by-domain.openvpn ----------------- #
- # -------------------------- begin dnsmasq.postconf -------------------------- #
- create_script() {
- cat << 'EOF' > $SCRIPT4
- #!/bin/sh
- #set -x # comment/uncomment to disable/enable debug mode
- {
- $SCRIPT1 "$1"
- } 2>&1 | logger -t $(basename $0)[$$]
- EOF
- [ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT4
- sed "s:\$SCRIPT1:$SCRIPT1:g" -i $SCRIPT4
- chmod +x $SCRIPT4
- }
- if [ -f $SCRIPT4 ]; then
- echo "error: $SCRIPT4 already exists; requires manual installation"
- else
- create_script
- echo "installed: $SCRIPT4"
- fi
- # --------------------------- end dnsmasq.postconf --------------------------- #
- # --------------------------- begin firewall-start --------------------------- #
- create_script() {
- cat << 'EOF' > $SCRIPT5
- #!/bin/sh
- #set -x # comment/uncomment to disable/enable debug mode
- {
- $SCRIPT2 "$1"
- } 2>&1 | logger -t $(basename $0)[$$]
- EOF
- [ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT5
- sed "s:\$SCRIPT2:$SCRIPT2:g" -i $SCRIPT5
- chmod +x $SCRIPT5
- }
- if [ -f $SCRIPT5 ]; then
- echo "error: $SCRIPT5 already exists; requires manual installation"
- else
- create_script
- echo "installed: $SCRIPT5"
- fi
- # ---------------------------- end firewall-start ---------------------------- #
- # --------------------------- begin openvpn-event ---------------------------- #
- create_script() {
- cat << 'EOF' > $SCRIPT6
- #!/bin/sh
- #set -x # comment/uncomment to disable/enable debug mode
- {
- $SCRIPT3
- } 2>&1 | logger -t $(basename $0)[$$]
- EOF
- [ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT6
- sed "s:\$SCRIPT3:$SCRIPT3:g" -i $SCRIPT6
- chmod +x $SCRIPT6
- }
- if [ -f $SCRIPT6 ]; then
- echo "error: $SCRIPT6 already exists; requires manual installation"
- else
- create_script
- echo "installed: $SCRIPT6"
- fi
- # ---------------------------- end openvpn-event ----------------------------- #
Add Comment
Please, Sign In to add comment