pfSense: WFH VPN-connected LAN
Published: 2022-08-07 08:23:00



## Abstract
As an IT professional working from home you may have more than one physical or virtual clients that will need at some point need to access the internal company network using a VPN client.

Usually the VPN client is a program installed locally on the machine that kidnaps your network adapters, sets everything up for you, but more often than else is timing out, needing authorization or frequent confirmation of annoying banner pop-ups.

How about we get rid of those annoyances?

This guide will walk you through on how to establish this VPN connection on an interface on your pfSense router, gaining the full performance and security of a proper network appliance.
We will utilize policy based routing and network address translation to allow multiple clients to utilize a single VPN connection as their gateway.

## Disclaimer
This may be unwanted/non-compliant usage of the VPN service provided at your company. Please make sure you have proper permission from whoever is responsible for the VPN service at your company (usually the NOC/SOC).
It should be noted that if improperly configured, this can introduce security risks to your company network. Particularly if non-compliant devices are allowed to access the VPN connection.

**Prerequisites**

- pfSense v2.5.x release or later
- Preferred: Split tunneling enabled
- Your workplace uses a VPN service protocol that is supported by OpenConnect

**Below are the protocols supported by OpenConnect**

`Cisco AnyConnect ( - protocol=anyconnect)
Array Networks AG SSL VPN ( - protocol=array)
Juniper SSL VPN ( - protocol=nc)
Pulse Connect Secure ( - protocol=pulse
Palo Alto Networks GlobalProtect SSL VPN ( - protocol=gp)
F5 Big-IP SSL VPN ( - protocol=f5)
Fortinet Fortigate SSL VPN ( - protocol=fortinet)`

**Step 1: Install OpenConnect**
OpenConnect is unfortunately not (at the time of writing) available as a supported package in the pfSense package manager. Due to that, we have to go through some kinks to be able to install it.

Before going ahead please read the implications of running unsupported packages here: Using Software from FreeBSD | pfSense Documentation (netgate.com).
Ready to go? 
Enable the full set of FreeBSD packages by editing /usr/local/etc/pkg/repos/pfSense.conf and changing the first line to:

`FreeBSD: { enabled: yes }`

Save the file and now head into your favorite terminal and SSH into your pfSense box. Pick option 8) to enter Shell

`PS C:\Users\hugog> ssh pf -l root
Password for root@pfSense.localdomain:
pfSense - Serial: xxx - Netgate Device ID: xxx
*** Welcome to pfSense 2.5.2-RELEASE (amd64) on pfSense ***
WAN (wan)       -> em1        -> v4/DHCP4: 123.456.78.9/24
 LAN (lan)       -> em0        -> v4: 10.0.1.1/24
[... Interfaces omitted ...]
0) Logout (SSH only)                  9) pfTop
 1) Assign Interfaces                 10) Filter Logs
 2) Set interface(s) IP address       11) Restart webConfigurator
 3) Reset webConfigurator password    12) PHP shell + pfSense tools
 4) Reset to factory defaults         13) Update from console
 5) Reboot system                     14) Disable Secure Shell (sshd)
 6) Halt system                       15) Restore recent configuration
 7) Ping host                         16) Restart PHP-FPM
 8) Shell
Enter an option: 8
[2.5.2-RELEASE][root@pfSense.localdomain]/root:`

Now type
`pkg install openconnect`

Let it do its thing ;)

When it has completed, let's go back and disable the FreeBSD repo. We do this to prevent any accidental installs or upgrades of packages that could potentially mess with our pfSense installation.

Head back into
/usr/local/etc/pkg/repos/pfSense.conf and change back the first line to:

`FreeBSD: { enabled: no }`

**Step 2: The VPN profile - A shell script**
Now we will create a shell script that will contain all the logic needed to get OpenConnect to establish a connection.
It will also know if a connection is already running if we run the script twice. This is useful for the cronjob we will make later.
The full script example can be found over at my github repository here:
[VPN Profile Shell Script](https://github.com/hugil/pfSense-openconnect/blob/main/vpn-profile-example.sh)

**2.1 Credentials**
Replace the username, password and host details in the script.
Please note: It is strongly discouraged to save passwords in plaintext, we may only enter it in the shell script for testing purposes.

In the example script I've used the AnyConnect protocol, you will need to change this if your company uses another provider.

**2.2 Certificate**
Your VPN service will probably require a certificate to even allow authorization in the first place, this is common security practice.

The certificate type and requirement can vary depending on the setup your organization uses so it will not be in scope for this guide.

If your company doesn't require a certificate, they definitely should.

**2.3 Save & Upload**
Save the shell script and upload it to your pfSense router's /root/ directory.

**Step 3: Test it out!**
Got everything down in the shell file? Run it!
`[2.5.2-RELEASE][root@pfSense.localdomain]/root: sh vpn-profile.sh`
If you run into issues you can uncomment the verbose switch in the shell script to get a better idea of what's going on.
Step 4: Add the interface in pfSense
Log in to the pfSense web GUI
Go to Interfaces -> Assignments
Choose the "tun1001" interface and click add.
Click on the "tun1001" interface and select "enable".

**Step 5: Set up the Gateway**
Still in the pfSense web GUI
Go to System -> Routing
Click "Add"
Set the Interface to the same "tun1001" interface we created in Step 4.
Optional: Set a monitor IP
This should be the IP to a device on the internal company network that's always online).
Save!

**Step 6: Set up the Outbound NAT**
Go to Firewall -> NAT
Go to the Outbound tab.
Select Hybrid Outbound NAT 
(Power users may prefer Manual Outbound NAT)
Click on "Add"
Select the "tun1001" interface and put the Source as Network.
Enter the CIDR of the IP subnet/VLAN the devices you want to give access to the company network are in.

Example subnet:
v --------------------------------------v
| DEVICE    |   IP ADDR   |   CIDR      |
|                                       |
| LAPTOP       10.0.10.4                |
| DESKTOP      10.0.10.5                |
^------------------------- 10.0.10.4/31-^

**Step 7: Set up the Firewall Policy Routing**

Click on Firewall -> Rules
Click on the interface you will use for your clients ("LAN" by default)
Create a new rule at the top
Set the Source to Network and enter the same CIDR we used in Step 6.
Scroll down a bit and at Advanced Options click "Display Advanced"
Set "Gateway" to the same gateway we created in Step 5.
Hit Save!

**Step 9: Reload and fire!**
Due to the changes we performed previously the connection we established with the shell script may have gone down. Execute it again and verify everything comes up and is working.
The VPN interface and gateway should now be visible in the web GUI widgets. Once connected it should show the assigned IP in the "Interfaces" widget.

**Step 10: Persistence**
Since we're doing some non-supported stuff outside of pfSense itself, it will not persist through a reboot. This can easily be solved with a cronjob.
use crontab -e and add an entry to run the script regularly.
`*/5 * * * * /root/vpn-profile >/dev/null 2>&1`
Replace the path and timing with your own preferred values.

You're Done!