OpenVPN Bridge

From ArchWiki
Revision as of 18:11, 12 June 2010 by Crabmeat (Talk | contribs)

Jump to: navigation, search

OpenVPN is a full-featured SSL VPN solution which can accommodate a wide range of configurations and is particularly useful for "road warriors" :).

This wiki page will discuss how to configure OpenVPN (1.6) in Bridge mode with a linux server and either a linux or a windows client. http://openvpn.sourceforge.net/howto.html discusses how to setup OpenVPN routing and explains the pros and cons of each. The article does not go into depth about iptables or how to allow traffic through your firewall to reach your OpenVPN machine. This page describes the "quick n dirty" setup using a secret ssh key for authentication. See the OpenVPN website for more information about SSL setups.

TODO: This document seems out of date. I noticed there is a /etc/conf.d/bridges now, probably the bridging part should be taken out of the vpn configuration.

Server Config

First thing you want to do is install OpenVPN

pacman -Sy openvpn bridge-utils

Next install this script as /etc/rc.d/openvpn

TODO: this script doesn't always correctly report "FAILED" or "DONE" so output can't be relied upon and may be confusing. Check /var/log/daemons if things don't seem to work.

#!/bin/bash

# /etc/rc.d/openvpn
#
# An init script to start and stop OpenVPN daemons

. /etc/rc.conf
. /etc/rc.d/functions

openvpn_config_dir=/etc/openvpn

make_bridge ()
{
	#echo "# mkbr $1"
	# for example $1 = "br0" and
	# $br0 = ("br0 192.168.2.1 netmask 255.255.255.0 broadcast 192.168.2.255" eth1)	
	eval brvar="(\"\${${1}[@]}\")"
	brdev=$1

	brctl addbr $brdev
	add_to_bridge ${brvar[1]} $brdev

        ifconfig ${brvar[0]}
	return $?
}

add_to_bridge ()
{
	#echo "# addbr $1 $2"
	# for example $1=tap0 and $2=br0
	ifconfig $1 down >/dev/null 2>&1
	brctl addif $2 $1
	ifconfig $1 0.0.0.0 promisc up
}

destroy_bridge ()
{
	eval brvar="(\"\${${1}[@]}\")"
	brdev=$1
	
	ifconfig $brdev down
	brctl delbr $brdev
}

make_vpn ()
{
	#echo  "# mkvpn $1"
	# for example $1 = vpn0 and
	# $vpn0 = ("default.conf" tap0 br0)
	eval vpnvar="(\"\${${1}[@]}\")"
	
	openvpn --mktun --dev ${vpnvar[1]} > /dev/null
	if [ "${vpnvar[2]}" != "" ]; then
		add_to_bridge ${vpnvar[1]} ${vpnvar[2]}
	fi

	openvpn --cd $openvpn_config_dir --daemon --config ${vpnvar[0]}
	return $?
}

destroy_vpn ()
{
	eval vpnvar="(\"\${${1}[@]}\")"
	openvpn --rmtun --dev ${vpnvar[1]} > /dev/null
	return $?
}

case "$1" in
        start)
        stat_busy "Starting OpenVPN daemons"

        # enable IP forwarding
        echo 1 > /proc/sys/net/ipv4/ip_forward

	# create bridge(s)
	error=0
       	for brconf in ${BRIDGES[@]}; do
               	if echo $brconf | grep '^[^\!]' >/dev/null 2>&1; then
                       	make_bridge $brconf || error=1
               	fi
       	done

	# create vpn(s)
       	for vpnconf in ${VPNS[@]}; do
               	if echo $vpnconf | grep '^[^\!]' >/dev/null 2>&1; then
                       	make_vpn $vpnconf || error=1
               	fi
       	done

	if [ $error -eq 0 ]; then
		stat_done
	else
		stat_fail
	fi
	;;
        stop)
        stat_busy "Stopping OpenVPN daemons"

        killall `which openvpn` 2> /dev/null

	# destroy bridge(s)
	error=0
       	for brconf in ${BRIDGES[@]}; do
               	if echo $brconf | grep '^[^\!]' >/dev/null 2>&1; then
                       	destroy_bridge $brconf || error=1
               	fi
       	done

	# destroy vpn(s)
       	for vpnconf in ${VPNS[@]}; do
               	if echo $vpnconf | grep '^[^\!]' >/dev/null 2>&1; then
                       	destroy_vpn $vpnconf || error=1
               	fi
       	done

	if [ $error -eq 0 ]; then
		stat_done
	else
		stat_fail
	fi
	;;
        restart)
                $0 stop
		sleep 1
                $0 start
                ;;
        *)
                echo $"Usage: $0 {start|stop|restart}"
                RETVAL=1
esac

and make the script executable

chmod 755 /etc/rc.d/openvpn

In /etc/rc.conf add the following modules to the MODULES array

tun bridge

add the following configuration

# Bridges and VPN setup
br0=("br0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255" eth0)
BRIDGES=(br0)
vpn0=("vpn0.conf" tap0 br0)
VPNS=(vpn0)

and add the following daemons to the DAEMONS array

bridge_devices openvpn

So what does all of that mean up there? First we create a bridge called br0 which attaches itself to eth0 and has certain ip address etc. Then we create a vpn daemon with config file "vpn0.conf" (see below) which uses device tap0 and attaches to the bridge br0. The "BRIDGES" and "VPNS" arrays should allow you to define more then one of each (but I didn't test this).

Now onto creating the config files

Firstly create the secret key

openvpn --genkey --secret /etc/openvpn/vpn0.key

and then make the vpn0.conf and save it in /etc/openvpn/

#/etc/openvpn/vpn0.conf
#
# Sample OpenVPN server configuration file
# using a pre-shared static key.
#
# See man openvpn for more configuration options.
# (the config file options are the same as the commandline switches)
#
# '#' or ';' may be used to delimit comments.

# Define the virtual ethernet device.
dev tap0

# Our pre-shared static key
secret /etc/openvpn/vpn0.key

# OpenVPN uses UDP port 1194 by default.
# Each OpenVPN tunnel must use
# a different port number.
# lport or rport can be used
# to denote different ports
# for local and remote.
port 1194

# Protocol to use; udp is the default for good reason.
# Alternative is 'tcp-server' (with 'tcp-client' on the other side of the line)
# which can be useful in certain situations or behind certain firewalls.
; proto udp

# Downgrade UID and GID to
# "nobody" after initialization
# for extra security.
user nobody
group nobody

# If you built OpenVPN with
# LZO compression, uncomment
# out the following line.
comp-lzo

# Send a UDP ping to remote once
# every 15 seconds to keep
# stateful firewall connection
# alive.  Uncomment this
# out if you are using a stateful
# firewall.
; ping 15

# Uncomment this section for a more reliable detection when a system
# loses its connection.  For example, dial-ups or laptops that
# travel to other locations.
ping 15
ping-restart 45
ping-timer-rem
persist-tun
persist-key

# Verbosity level.
# 0 -- quiet except for fatal errors.
# 1 -- mostly quiet, but display non-fatal network errors.
# 3 -- medium output, good for normal operation.
# 9 -- verbose, good for troubleshooting
verb 3

If you have more then one vpn daemon you should not reuse devices or port numbers across .conf files.

Now we can start up our daemons scripts.

sudo modprobe tun
sudo modprobe bridge
sudo /etc/rc.d/openvpn start

Linux client config

Install openvpn on the client machine the same way as on the server. Copy /etc/rc.d/openvpn, /etc/openvpn/vpn0.key and /etc/openvpn/vpn0.conf to the client (preferably using sftp or scp).

Add the following lines to /etc/openvpn/vpn0.conf with the "real" address of the server and the virtual address of the client.

remote real_server_address
ifconfig vpn_client_ip vpn_netmask

(And set proto to 'tcp-client' if you used 'tcp-server' on the server)

Now edit /etc/rc.conf to include

# Bridges and VPN setup
BRIDGES=()
vpn0=("vpn0.conf" tap0)
VPNS=(vpn0)

Now start it up

modprobe tun
/etc/rc.d/openvpn start

You should now be able to ping across the tunnel to any of the hosts on the other end.

Windows client config

Install OpenVPN from openvpn-1.6.0-install.exe now copy the vpn0.key from the VPN server (preferably using sftp or scp) and the vpn0.conf below to "C:\Program Files\OpenVPN\config\". And delete the sample file in that folder (or at least move it to another folder).

# replace with the public ip address of the vpn server
remote remote.public.ip.address
port 1194
dev tap
ifconfig 192.168.0.200 255.255.255.0
ifconfig-nowarn
secret "C:\Program Files\OpenVPN\config\vpn0.key"
ping 10
comp-lzo
verb 5

Now open a command prompt and enter

net start openvpnservice

You should now be able to ping across the tunnel to any of the hosts on the other end.


Any additions, clarifications, reorganizations, feedback etc. etc. are more than appreciated.