Joe's Linux Blog Linux Admin tips and tricks

March 5, 2014

OpenVPN Linux clients with VPN-based DNS services

Filed under: Centos,Configuration,Installation — jfreivald @ 6:45 am

Openvpn is a really nice, relatively simple VPN service.

There are lots of tutorials on how to get things rolling. This post deals with the specific issue of DNS services made available through the VPN.

Most of my users connect to our VPN using Windows clients, which is great because OpenVPN’s Windows client has the ability to override the existing DNS services that the client is using and replace them with DNS services pushed by the VPN server.  This means that the users have access to all of our internal network using the same names as if they were connected locally.  Just what you would expect.

Under Linux this is a bit more complicated because Linux (and most of the *nix world) uses the /etc/resolv.conf file to resolve name information and the Linux Openvpn client doesn’t change the information stored thereon it’s own. This makes things painful if Linux users don’t have access to the internal DNS.

The Openvpn solution is to use the openvpn scripting feature to pass the information to a script which will process it. After a few false starts with other people’s scripts I came up with the following configuration. OpenVPN will provide warnings in syslog that scripting is enabled because almost anything can be done with scripts, even very bad things.

I hope that you find these scripts helpful.

 

Linux Client Configuration: /etc/openvpn/client.conf

client
dev tun
proto udp
script-security 2
up ./up.sh
down ./down.sh
remote <remote_server_ip_address> 1194
remote <remote_server_ip_address #2> 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca /etc/pki/tls/certs/my_cert_authority.pem
cert /etc/pki/tls/certs/my_client_certificate.pem
key /etc/pki/tls/private/my_client_key.key
ns-cert-type server
verb 1
mute 5

The up script: /etc/openvpn/up.sh:

#!/bin/bash
log="openvpn.log"
modified="0"
echo "Initialization: $0 $1 $2 $3 $4 $5 $6" >> $log
echo ";; created by openvpn" > ./resolv.conf.new 
echo ";; Initialization: $0 $1 $2 $3 $4 $5 $6" > ./resolv.conf.new
for opt in ${!foreign_option_*}; do
    optval=${!opt} 
    optiontype="`echo $optval | awk -F ' ' '{ print $1; }';`"
    if [ "$optiontype" == "dhcp-option" ]; then 
        dhcptype=`echo $optval | awk -F ' ' '{ print $2;}';` 
        dhcpval=`echo $optval | awk -F ' ' '{ print $3;}';` 
        if [ "$dhcptype" == "DNS" ]; then 
            modified="1" 
            echo "Adding DNS Server $dhcpval" >> $log 
            echo "nameserver $dhcpval" >>./resolv.conf.new 
        fi 
        if [ "$dhcptype" == "DOMAIN" ]; then 
            modified="1" 
            echo "Adding domain $dhcpval" >> $log 
            echo "domain $dhcpval" >> ./resolv.conf.new 
            echo "search $dhcpval" >> ./resolv.conf.new 
        fi 
        #Note that the DOMAIN must come first for the sed command do match properly.
        if [ "$dhcptype" == "DOMAIN-SEARCH" ]; then 
            modified="1"
            echo "Adding domain search $dhcpval" >> $log
            sed -i "s/^search \(.*\)/search \\1 $dhcpval/" ./resolv.conf.new
        fi
        dhcptype=
        dhcpval=
    else
        echo "Ignore non-dhcp option: $optval" >> $log
    fi
done
if [ "$modified" != "0" ]; then
    if [ -f /etc/resolv.conf ] && [ -f ./resolv.conf.new ]; then
        cp -f /etc/resolv.conf ./resolv.conf.saved
        if [ $? != 0 ]; then
            echo "Failed to copy existing /etc/resolv.conf." >> $log
        fi
    fi
 if [ -f ./resolv.conf.new ]; then
    echo "Replacing existing name services with VPN settings" >> $log
    cp -f ./resolv.conf.new /etc/resolv.conf
        if [ $? != 0 ]; then
            echo "Replacement resolv.conf failed." >> $log
            exit 1;
        else
            rm ./resolv.conf.new
        fi
    fi
else
    echo "/etc/resolv.conf not replaced" >> $log
fi

VPN Down script: /etc/openvpn/down.sh

#!/bin/bash
log="openvpn.log"
if [ -f ./resolv.conf.saved ]; then
    echo "Reverting to original name services." >> $log
    cp -f ./resolv.conf.saved /etc/resolv.conf
    if [ $? == 0 ]; then
        rm -f resolv.conf.saved
    else
        echo "Failed to recover /etc/resolv.conf." >> $log
    fi
else
    echo "No stored name service information available." >> $log
fi

Server configuration file: /etc/openvpn/server.conf

port 1194
dev tun
# TLS parms
tls-server
#Notice that the server uses a Diffie-Hellman file. This is to make session key generation less resource intensive.
ca /etc/pki/tls/certs/<my_certificate_authority>.pem
cert /etc/pki/tls/certs/<my_server_certificate>.pem
key /etc/pki/tls/private/<my_server_key>.key
dh /etc/pki/tls/private/<my_server_diffe_hellman_file>.pem
# Tell OpenVPN to be a multi-client udp server
mode server
# The server's virtual endpoints
ifconfig 192.168.200.1 192.168.200.2
# Require all clients to have a ccd file. This provides clients with a static IP address, and no client that isn't assigned a static IP address will be permitted to join the network.
# It is a little more overhead to keep track of clients, and probably isn't necessary in most cases.
ccd-exclusive
# Use individual client configs based on SSL CN
client-config-dir /etc/openvpn/ccd
# Pool of /30 subnets to be allocated to clients.
# When a client connects, an --ifconfig command
# will be automatically generated and pushed back to
# the client.
# ifconfig-pool 10.2.0.4 10.2.0.255
# Push route to client to bind it to our local virtual endpoint.
# These are the only routes that will be delivered to the client over the VPN. All other internet traffic will route based on their current routing tables.
push "route 192.168.200.0 255.255.255.0"
push "route 10.1.0.0 255.255.0.0"
push "route 10.2.0.0 255.255.0.0"
push "route 10.128.0.0 255.255.0.0"
# Push DHCP options to clients. Windows clients use these automatically, Linux clients need our up/down scripts to help them.
push "dhcp-option DNS 192.168.200.12"
push "dhcp-option DOMAIN work"
push "dhcp-option DOMAIN-SEARCH intranet.work"
# Client should attempt reconnection on link
# failure.
keepalive 10 60
# Delete client instances after some period
# of inactivity.
inactive 600
# Route the --ifconfig pool range into the
# OpenVPN server.
route 192.168.201.0 255.255.255.0
# The server doesn't need privileges
user openvpn
group openvpn
# Keep TUN devices and keys open across restarts.
persist-tun
persist-key
verb 2

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment

You must be logged in to post a comment.

Powered by WordPress