This will be achieved by restricting network access for the user running rTorrent to the VPN interface only. OpenVPN will be configured not to add default routing and instead we will only route the VPN traffic needed. rTorrent will be bound to the VPN interface. We will also add tools to restart OpenVPN if down and automatic update rTorrents bind settings if VPN IP changes.
There are probably better ways to achieve this but this works for me. Note that all script are made for my setup and will probably need to be modified to work for your setup. Maybe you will find some useful information here.
Tested on Ubuntu Server 14.04 connected to a local network.
Pre-Requirements:
* Working OpenVPN interface (tap0 in this tutorial)
* Dedicated user running rTorrent (named torrent in this tutorial)
First we are going to lock down network access for the torrent user to tap0, lannet and local. This script should be run at startup or when your network interface is up. I've chosen to place it in /etc/network/if-up.d/vpn-lockdown.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #!/bin/bash ## vpn-lockdown - v1.0 ## Function: Limit a user's network access to VPN and LAN only ## Installation: ## Place this script in /etc/network/if-up.d/vpn-lockdown #Settings export LANIF="eth0" export LANNET="192.168.0.0/24" export VPNIF="tap0" export VPNUSER="torrent" export TORRENTPORT="57225" export ENABLEDHT="1" #/Settings # only run when triggered from $LANIF (use -f parameter to force run) if [[ "$IFACE" != "$LANIF" ]]; then if [[ "$1" != "-f" ]]; then exit 0 fi fi # only run from ifup if [[ "$MODE" != start ]]; then if [[ "$1" != "-f" ]]; then exit 0 fi fi sysctl -w net.ipv4.ip_forward=1 sysctl -w net.ipv4.conf.all.rp_filter=0 sysctl -w net.ipv4.conf.default.rp_filter=0 sysctl -w net.ipv4.conf.lo.rp_filter=0 sysctl -w net.ipv4.conf.eth0.rp_filter=0 # clear iptables iptables -F -t nat iptables -X -t nat iptables -F -t mangle iptables -X -t mangle iptables -F -t filter iptables -X -t filter iptables -F -t raw iptables -X -t raw # allow responses iptables -A INPUT -i $VPNIF -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # allow incoming $TORRENTPORT iptables -A INPUT -i $VPNIF -p tcp --dport $TORRENTPORT -j ACCEPT iptables -A INPUT -i $VPNIF -p udp --dport $TORRENTPORT -j ACCEPT # allow incoming DHT if [[ "$ENABLEDHT" = "1" ]]; then iptables -A INPUT -i $VPNIF -p udp --dport 6881 -j ACCEPT iptables -t raw -I PREROUTING -i $VPNIF -p udp --dport 6881 -j NOTRACK iptables -t raw -I OUTPUT -o $VPNIF -p udp --sport 6881 -j NOTRACK fi # block everything else incoming on $VPNIF iptables -A INPUT -i $VPNIF -j DROP # all packets on $VPNIF needs to be masqueraded iptables -t nat -A POSTROUTING -o $VPNIF -j MASQUERADE # allow $VPNUSER outgoing on lo, to $LANNET and on $VPNIF iptables -A OUTPUT -o lo -m owner --uid-owner $VPNUSER -j ACCEPT iptables -A OUTPUT -d $LANNET -m owner --uid-owner $VPNUSER -j ACCEPT iptables -A OUTPUT -o $VPNIF -m owner --uid-owner $VPNUSER -j ACCEPT # reject everything else outgoing for $VPNUSER that is not going over $VPNIF iptables -A OUTPUT ! -o $VPNIF -m owner --uid-owner $VPNUSER -j DROP |
When this script i executed the torrent user should only be able to access your LAN and internet via VPN (not yet).
Verify this by trying to connect to the internet as the torrent user. For example executing curl -s "icanhazip.com" should time out.
Next step is to configure OpenVPN not to add the default routing since we don't want the whole system to use the VPN. We also need to supply a script that adds the necessary routing for when the VPN is used.
First add a new table ($IPTABLE) in /etc/iproute2/rt_tables (e.g. echo "200 torrent" >> /etc/iproute2/rt_tables)
Then add the following settings to your OpenVPN config:
route-noexec
route-up /etc/openvpn/vpn-route
Place this script in /etc/openvpn/vpn-route
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | #!/bin/bash ## vpn-route - v1.0 ## Function: Set routing for OpenVPN network ## Installation: ## Add a new table ($IPTABLE) in /etc/iproute2/rt_tables (e.g. echo "200 torrent" >> /etc/iproute2/rt_tables) ## Add settings to OpenVPN config: ## route-noexec ## route-up /path/to/this-script #echo "$dev: $ifconfig_local mask: $ifconfig_netmask gw: $route_vpn_gateway" #Settings VPNIF=$dev MASK=$ifconfig_netmask VPNGW=$route_vpn_gateway IPTABLE="torrent" LANGW="192.168.0.1" LANNET="192.168.0.0/24" #/Settings if [[ -z "$VPNIF" ]]; then echo "Error: No VPN interface" exit 1 fi if [[ -z "$MASK" ]]; then echo "Error: No VPN mask" exit 1 fi if [[ -z "$VPNGW" ]]; then echo "Error: No VPN gateway" exit 1 fi if [[ `ip rule list | grep -c $VPNGW` == 0 ]]; then #Add ip rule for VPN traffic to use $IPTABLE table ip rule add from $VPNGW/$MASK table $IPTABLE fi #Set default route to $VPNGW in $IPTABLE table ip route replace default via $VPNGW dev $VPNIF table $IPTABLE #Add routing for lo ip route append default via 127.0.0.1 dev lo table $IPTABLE #Add routing for $LANNET via $LANGW ip route add $LANNET via $LANGW table $IPTABLE #Commit changes ip route flush cache |
Restarting OpenVPN will execute the script. The torrent user is now able to access to the internet via the tap0 interface, and your LAN via eth0, but not access internet via eth0. Verify this by running curl --interface "tap0" -s "icanhazip.com". Running curl -s "icanhazip.com" should not work as it uses eth0.
From here you can run rTorrent with the -b 1.2.3.4 parameter or bind = 1.2.3.4 setting in .rtorrent.rc, replacing 1.2.3.4 with the IP of tap0, and you are good to go!
Since there is a possibility that tap0 will change IP and we want rTorrent to rebind the new IP if this happens we will use the schedule setting in .rtorrent.rc.
First we need to add an entry in the hosts file that will resolve the tap0 IP (e.g. echo "10.0.0.1 vpniphost" >> /etc/hosts).
Add the script below to root crontab (*/5 * * * * /root/vpn-check-hostname). The script will update to host entry with the tap0 IP if it has changed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #!/bin/bash ## vpn-check-hostname - v1.0 ## Function: Set hostname entry to VPN IP ## Installation: ## Add a new hostname ($HOST) in your hosts file ($HOSTFILE) (e.g. echo "10.0.0.1 vpniphost" >> /etc/hosts) ## Add this to script to root crontab (*/5 * * * * /path/to/this-script) ## Add bind settings to .rtorrent.rc: ## bind = vpniphost ## schedule = bind_tick,30,30,bind=vpniphost #Settings VPNIF="tap0" HOSTFILE="/etc/hosts" HOST="vpniphost" #/Settings # get VPN IP VPNIP=$(ifconfig $VPNIF 2>/dev/null | awk '/inet addr/{print substr($2,6)}') if [[ -z "$VPNIP" ]]; then if [[ "$1" = "-v" ]]; then echo "Cannot find IP for $VPNIF. Terminating." fi exit fi # get current hostname IP FINDLINE=$(cat $HOSTFILE | egrep -n "\ $HOST$" | tail -n 1) FINDLINENR=$(echo $FINDLINE | egrep -o "[0-9]+:" | egrep -o "[0-9]+") FINDOLDIP=$(echo $FINDLINE | egrep -o "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}") if [[ -z "$FINDLINENR" ]] || [[ -z "$FINDOLDIP" ]]; then if [[ "$1" = "-v" ]]; then echo "Couldn't find '$HOST' host in $HOSTFILE. Terminating." fi exit fi # check if IP has changed if [[ "$VPNIP" = "$FINDOLDIP" ]]; then if [[ "$1" = "-v" ]]; then echo "Update not required" fi else echo "Setting '$HOST' to $VPNIP (old: $FINDOLDIP)" sed -i.bak -e "$FINDLINENR s/$FINDOLDIP/$VPNIP/" $HOSTFILE fi |
Executing ping vpniphost should get a response from the tap0 IP.
We now tell rTorrent to bind to whatever interface 'vpniphost' is pointing to, and check every 30 seconds if it has changed. Add the following settings to .rtorrent.rc:
bind = vpniphost
schedule = bind_tick,30,30,bind=vpniphost
Thats it!
Finally I use these optional scripts to restart OpenVPN and rTorrent if they go down.
OpenVPN.
Add this script to root crontab (*/10 * * * * /root/vpn-check-interface).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #!/bin/bash ## vpn-check-interface - v1.0 ## Function: Make sure OpenVPN is running ## Installation: ## Add this script to root crontab (*/10 * * * * /path/to/this-script) #Settings VPNIF="tap0" #/Settings PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin UPTIME=$(cat /proc/uptime | cut -d . -f 1) UPTIMEM=$(expr $UPTIME / 60) # wait a couple of minutes if recently booted if [ $UPTIMEM -lt 5 ]; then if [ "$1" = "-v" ]; then echo "Uptime only $UPTIMEM m. Terminating." fi exit 0 fi if [ -f /sys/class/net/$VPNIF/operstate ]; then if [ "$1" = "-v" ]; then echo "OpenVPN seems to be running. Terminating." fi exit 0 fi echo "OpenVPN is down. Restarting service." /etc/init.d/openvpn restart |
rTorrent.
Add this script to torrent users crontab (*/10 * * * * /home/torrent/rtorrent-check).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #!/bin/bash ## rtorrent-check - v1.0 ## Function: Make sure rTorrent is running ## Installation: ## Add this script to crontab (*/10 * * * * /path/to/this-script) #Settings #Home folder LOC="/home/torrent" #Conf file in home folder CONFFILE=".rtorrent.rc" #rTorrent working folder WORKINGFOLDER="$LOC/download" #Name the screen session SCREENNAME="torrent" #rTorrent incoming folder mount check (OPTIONAL) #MOUNTCHECK="$WORKINGFOLDER/incoming" #/Settings if [[ ! -z "$MOUNTCHECK" ]]; then testmount=$(/bin/mount | grep "on $MOUNTCHECK") if [[ -z "$testmount" ]]; then if [[ "$1" = "-v" ]]; then echo "$MOUNTCHECK is not mounted. Terminating." fi exit fi fi if [[ ! -f $LOC/$CONFFILE ]]; then echo "Conf file not found. Terminating." exit fi if [[ ! -s $LOC/$CONFFILE ]]; then echo "Conf file empty. Terminating." exit fi TESTSCREEN=$(screen -ls | egrep "[0-9]+.$SCREENNAME") if [[ -n "$TESTSCREEN" ]]; then if [[ "$1" = "-v" ]]; then echo "rTorrent is already running. Terminating." fi exit fi echo "Starting rTorrent" cd "$WORKINGFOLDER" sleep 1 stty stop undef 2>/dev/null stty start undef 2>/dev/null screen -A -m -d -S $SCREENNAME -t $SCREENNAME /usr/bin/rtorrent -o http_capath=/etc/ssl/certs |
Nice work :-D
ReplyDeleteBut for some reason vpn-check-hostname dont work in hostname.
i just run the script it works. but in crontab it dont
Maybe cron can't find all utils? Try adding full path to the utils. For example replace: "VPNIP=$(ifconfig $VPNIF ..." with "VPNIP=$(/path/to/ifconfig $VPNIF ..."
DeleteOr you could try adding PATH to the script like this:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
This comment has been removed by the author.
ReplyDeleteUsed this to make a continuis running script add it to rc.local (/home/ubuntu/vpn.sh > /dev/null 2>&1 &)
Deletehttp://pastebin.com/YF4gRyVA