OpenVPN - Bridged connection without NAT using LAN DHCP

This is a note about using OpenVPN.

OpenVPN is far from simple to setup, because there are a lot of things working together with it to create connections and there are lots of ways to use it. The configuration is also quite hard to get right.

Therefore there may be a lot of invalid information here, it is based on the trial-and-error-method.


Note for VirtualBox setups

For VirtualBox setups - ensure that the virtual machine network adapters do not have Promiscuous mode NOT set to Deny. Deny results in that the OpenVPN client is unable to get responses nor contact other hosts on the LAN. On each virtual box machine settings go to -> Network -> Adapter -> Advanced -> Promiscuous mode -> Change Deny to Allow all.


Note using ping from client to hosts on the VPN LAN

Do NOT give up too fast when trying to ping a LAN host from the client through the VPN. The first ping gave "Destination Host Unreachable" 8 times before it started replying.


Creating keys for the server

The following creates certificate files for the client and server.
The > lines show what the expected response is.

Reference: https://www.golinuxcloud.com/install-openvpn-server-easy-rsa-3-centos-7/

# install required files
apt update
apt install bridge-utils easy-rsa openvpn

# make a ca dir for easy-rsa
cd /etc/openvpn
make-cadir easy-rsa
cd easy-rsa

# init pki and build certificate
./easyrsa init-pki
./easyrsa build-ca

# > Your new CA certificate file for publishing is at:
# > /etc/openvpn/easy-rsa/pki/ca.crt

# make diffie-hellman parameters
./easyrsa gen-dh
# > DH parameters of size <...> created at /etc/openvpn/easy-rsa/pki/dh.pem

# make keypair and certificate request
./easyrsa gen-req <server> nopass
# > Keypair and certificate request completed. Your files are:
# >  req: /etc/openvpn/easy-rsa/pki/reqs/<server>.req
# >  key: /etc/openvpn/easy-rsa/pki/private/<server>.key

./easyrsa sign server <server name>
# > Certificate created at: /etc/openvpn/easy-rsa/pki/issued/<server>.crt

mkdir /etc/openvpn/keys/
chmod 750 /etc/openvpn/keys
cp -a /etc/openvpn/easy-rsa/pki/ca.crt /etc/openvpn/keys/
cp -a /etc/openvpn/easy-rsa/pki/dh.pem /etc/openvpn/keys/dh.pem
cp -a /etc/openvpn/easy-rsa/pki/issued/<server>.crt /etc/openvpn/keys/
cp -a /etc/openvpn/easy-rsa/pki/private/<server>.key /etc/openvpn/keys/


To use them in /etc/openvpn/server.conf:
  tls-server
  persist-key
  ...
  ca /etc/openvpn/keys/ca.crt
  cert /etc/openvpn/keys/<server>.crt
  key /etc/openvpn/keys/<server>.key # this file should be kept secret
  dh /etc/openvpn/keys/dh.pem


Creating keys for the client on the server

Keys for the clients are made on the server or somewhere else, then each client gets it's own  key to login with.

./easyrsa gen-req <client> nopass
./easyrsa sign client <client>

cp -a /etc/openvpn/easy-rsa/pki/issued/<client>.crt /etc/openvpn/keys/
cp -a /etc/openvpn/easy-rsa/pki/private/<client>.key /etc/openvpn/keys/

copy the client certificates to the client node under /etc/openvpn
  scp /etc/openvpn/keys/<client>.* <client-hostname>:/etc/openvpn/

Note, only ca.crt is shared, <client>.crt and <client>.key belong to the client.

To use this in the configuration in the client at /etc/openvpn/client.conf:
  client
  ...
  ca ca.crt
  cert <client>.crt
  key <client>.key
  ns-cert-type server
  ...


Bridged setup without LAN using DHCP server on the LAN

The following configuration creates a bridged connection without NAT using the DHCP server on the LAN, resulting in that the clients get real IP:s from the LAN.

Note, the client adds gateway DNS:es to /etc/resolv.conf after some seconds WITHOUT a push command from the server when connecting. But it does not add the default gateway.

The configuration setting "redirect-gateway local def1" is suggested in some setup examples, but seems to be to quick, it tries to add routes before tap0 has received an ip, which makes the system complain with "Nexthop has an invalid gateway". Without this configuration setting it cannot add the default gateway in the client routing automatically.

Therefore a workaround has been supplied here, to set the tap0 interface in /etc/network/interfaces, then it will manage this when ready on its own. This will also route all traffic through the LAN (using the the 0.0.0.0 and 128... lines).

The downside of this workaround is that you can only connect to 1 VPN since it will do the same for all connections using the tap0 interface.

12.345.678.9 is here the external WAN IP and 192.168.2.* is the internal LAN that should be reachable using the OpenVPN connection.


server : /etc/openvpn/server.conf

port 1194
proto udp4
dev tap0
keepalive 100 1200
persist-key
persist-tun
tls-server
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/<server>.crt
key /etc/openvpn/keys/<server>.key
dh /etc/openvpn/keys/dh.pem
script-security 2
remote-cert-tls client
up "/etc/openvpn/up.sh br0"
down "/etc/openvpn/down.sh br0"
# to override network dhcp server with openvpn dhcp server
# server-bridge 192.168.2.200 255.255.255.0 192.168.2.100 192.168.2.150
push "redirect-gateway local def1"
cipher AES-256-CBC


server : /etc/openvpn/up.sh

#!/bin/sh
BR=$1
DEV=$2
MTU=$3

# to use the older ifconfig
# /sbin/ifconfig $DEV mtu $MTU promisc up
# /sbin/brctl addif $BR $DEV

# to use the newer ip
PATH=/sbin:/usr/sbin:/bin:/usr/bin
ip link set "$DEV" up promisc on mtu "$MTU"
if ! brctl show $BR | egrep -q "\W+$DEV$"; then
  brctl addif $BR $DEV
fi


server : /etc/openvpn/down.sh

#!/bin/sh
BR=$1
DEV=$2

# to use the older ifconfig
# /sbin/brctl delif $BR $DEV
# /sbin/ifconfig $DEV down

# to use the newer ip
PATH=/sbin:/usr/sbin:/bin:/usr/bin
brctl delif $BR $DEV
ip link set "$DEV" down


server : /etc/network/interfaces

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The WAN interface
auto eth0
iface eth0 inet static
  address 12.345.678.9
  netmask 255.255.255.0

# The VPN-tap0-br0-eth1-LAN bridge
auto br0
iface br0 inet static
  address 192.168.2.200
  netmask 255.255.255.0
  network 192.168.2.0
  broadcast 192.168.2.255
  gateway 192.168.2.1
  dns-nameservers 192.168.2.1
  bridge_ports eth1
  bridge_fd 0
  bridge_hello 2
  bridge_maxage 12
  bridge_stp on
  bridge_prio 1000

# The LAN interface
auto eth1
  iface eth1 inet manual
  up ifconfig $IFACE 0.0.0.0 up
  up ip link set $IFACE promisc on
  down ip link set $IFACE promisc off
  down ifconfig $IFACE down


client : /etc/network/interfaces

# ref: https://serverfault.com/questions/612868/openvpn-linux-client-does-not-bring-up-tap0-interface
# this works to add and remove gateway since openvpn
# assigns them before dhclient has assigned an IP to tap0

allow-hotplug tap0
iface tap0 inet dhcp
  # testing
  up route add default gw 192.168.2.1
  # extra to ensure all traffic is routed through it
  up route add -net 0.0.0.0 netmask 128.0.0.0 gw 192.168.2.1
  up route add -net 128.0.0.0 netmask 128.0.0.0 gw 192.168.2.1
  down route del default gw 192.168.2.1
  # extra to remove all traffic routing
  down route del -net 0.0.0.0 netmask 128.0.0.0 gw 192.168.2.1
  down route del -net 128.0.0.0 netmask 128.0.0.0 gw 192.168.2.1
  #up ip route add 0.0.0.0/1 via 192.168.2.1
  #up ip route add 128.0.0.0/1 via 192.168.2.1
  down dhclient wlan0


client : /etc/openvpn/client.conf

# the ip to the server
remote 12.345.678.9
port 1194
client
dev tap
proto udp4
nobind
persist-key
persist-tun
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/<client>.crt
key /etc/openvpn/keys/<client>.key
verb 3
float
remote-cert-tls server
auth-nocache
cipher AES-256-CBC


Start and stop commands

server start (runs automatically on boot):
  service openvpn start
server stop:
  service openvpn stop
client start:
  openvpn /etc/openvpn/client.conf
client stop:
  killall openvpn
  maybe also dhclient wlan0 (otherwise it won't reset the /etc/resolv.conf), but it is done in /etc/network/interfaces
  

About static IP addresses

Static MAC addresses for static IP assignment does not seem to exist in OpenVPN. Instead it is suggested is to use the internal OpenVPN DHCP and create a custom profile for each user based on the client certificate name at /etc/openvpn/ccd/<client certificate name>. Then the OpenVPN DHCP on the server will send static IP:s to the clients.

If using dnsmasq on the LAN as DHCP server, then it is possible in dnsmasq to assign static IP a based on the client hostname. To assign IP:s in dnsmasq on the server based on the client hostname, edit /etc/dnsmasq.conf or /etc/dnsmasq.d/<file> and add this line:

dhcp-host=<hostname>,<ip>

For Tomato routers running the dnsmasq server please note that there are no fields to fill in hostnames for client identification, only MAC addresses. The line above should therefore be added to the custom configuration for the dnsmasq server located at Advanced, DHCP/DNS, Dnsmasq Custom configuration.

dhclient client hostname is set at /etc/dhcp/dhclient.conf, send host-name. No change needed unless you want to send custom hostnames - like if you want different hostnames when connecting from LAN or VPN) if using dhclient.

This is a personal note. Last updated: 2020-05-27 20:08:07.



LinkedIn
Klebe.se

Don't forget to pay my friend a visit too. Joakim