Sometime it’s needed to selectively route specified IPs or networks via different interface – i.e. if you want to route private addresses over VPN (a.k.a split tunnel routing) or to route some public IPs over VPN to unblock some nationally restricted sites (Netflix). Here are simple scripts to achieve this.
PPP up script
This is PPP up script, it routes and NATs whole traffic of user polipo over PPP tunnel to public IP. Simply put it it /etc/ppp/ip-up.d and change config values.
To forward additional owners/ips/networks over tunnel simply create a appropriate rule in iptables mangle table that will mark packets with given $TABLE_MARK.
#!/bin/bash # ppp ip-up.d script # This script is called with the following arguments: # Arg Name # $1 Interface name # $2 The tty # $3 The link speed # $4 Local IP number # $5 Peer IP number # $6 Optional ``ipparam'' value foo # config COMMENT="polipo"; # used for identifying our rules TABLE="Tproxy"; # iproute2 table as define in /etc/iproute2/rt_tables TABLE_MARK="102"; # unique mark, using table id TAG="$6"; # tag for syslog entry MATCH_OWNER="polipo"; # restricted user ARG_DEV="$1"; ARG_LOCAL_IP="$4"; ARG_REMOTE_IP="$5"; logger -t "$TAG" "Setting up $COMMENT tunnel over $ARG_DEV"; # disable rp_filter sysctl -w net.ipv4.conf.$ARG_DEV.rp_filter=0; ip route flush table "$TABLE" ip route add default via "$ARG_REMOTE_IP" dev "$ARG_DEV" table "$TABLE" # delete existing entries iptables -t mangle -L OUTPUT --line-numbers | grep "$COMMENT" | awk '{print $1}' | sort -n -r | xargs -n 1 /sbin/iptables -t mangle -D OUTPUT; # forward only specified owner if [ -n "$MATCH_OWNER" ]; then iptables -t mangle -A OUTPUT -m owner --uid "$MATCH_OWNER" -j MARK --set-mark "$TABLE_MARK" -m comment --comment "$COMMENT"; fi # forward also this this SUBNET over tunnel #iptables -t mangle -A OUTPUT -d 173.194.0.0/16 -j MARK --set-mark "$TABLE_MARK" -m comment --comment "$COMMENT"; # NAT iptables -t nat -L POSTROUTING --line-numbers | grep "$COMMENT" | awk '{print $1}' | sort -n -r | xargs -r -n 1 /sbin/iptables -t nat -D POSTROUTING; iptables -t nat -A POSTROUTING -o "$ARG_DEV" -j SNAT --to-source "$ARG_LOCAL_IP" -m comment --comment "$COMMENT"; # flush rules and add new ip rule | grep "$TABLE" | sed -e 's/.*:/ip rule del/g' | bash; ip rule add fwmark "$TABLE_MARK" pri 100 lookup "$TABLE"; ip rule add from "$ARG_LOCAL_IP" pri 200 table "$TABLE"; ip route flush cache;
OpenVPN up script
This is OpenVPN up script, it routes and NATs traffic with tunnel source ip via VPN.
#!/bin/bash # openvpn up script, hook with 'up' directive in openvpn config # This script is called with the following arguments: # Arg Name ## $1 tun_dev ## $2 tun_mtu ## $3 link_mtu ## $4 ifconfig_local_ip ## $5 ifconfig_remote_ip ## $6 [ init | restart ]. COMMENT="vpn1"; # used for identifying our rules TABLE="Tvpn1"; # iproute2 table as define in /etc/iproute2/rt_tables TABLE_MARK="101"; # unique mark, using table id here TAG="$TABLE"; # tag for syslog entry ARG_DEV="$1"; ARG_LOCAL_IP="$4"; ARG_REMOTE_IP="$5"; logger -t "$TAG" "Setting up $COMMENT tunnel over $ARG_DEV"; # disable rp_filter sysctl -w net.ipv4.conf.$ARG_DEV.rp_filter=0; ip route flush table "$TABLE" ip route add default via "$ARG_REMOTE_IP" dev "$ARG_DEV" table "$TABLE"; # NAT iptables -t nat -L POSTROUTING --line-numbers | grep "$COMMENT" | awk '{print $1}' | sort -n -r | xargs -r -n 1 /sbin/iptables -t nat -D POSTROUTING; iptables -t nat -A POSTROUTING -o "$ARG_DEV" -j SNAT --to-source "$ARG_LOCAL_IP" -m comment --comment "$COMMENT"; # flush rules and add new ip rule | grep "$TABLE" | sed -e 's/.*:/ip rule del/g' | bash; ip rule add fwmark "$TABLE_MARK" pri 100 lookup "$TABLE"; ip rule add from "$ARG_LOCAL_IP" pri 200 table "$TABLE"; ip route flush cache;