pfSense, as of 2016-03-01, does not support OpenConnect out of the box. However, it’s in the FreeBSD repository, and relatively easy to add:
# pkg # pkg update -f # pkg install openconnect # rehash
You can now play around with the openconnect command and test your connection.
Next step: Autostart, and adding the tun interface to the pfSense GUI. The GUI will, by default, ignore any interface named “tun*”, while openconnect will refuse to work with any interface not named “tun*”. Brilliant. The easiest workaround for this special case seems to be renaming the VPN interface after creation.
I made a script that automates checking if the connection is up, and (re-)starting it if it is not.
Replace the options in the “settings” section with appropriate values for your setup, and you should be good to go.
The “test” field should be a command that returns 0 when the connection is up, and anything else when it’s broken. I used netcat’s port testing feature on the remote desktop port of a server I needed to be able to connect to, but you can just as easily use things like ping with a limited count or similar.
#!/bin/sh # settings user="vpnuser" pass="P4ssw0rd" host="vpn.server.here.com" test="nc -v -w 10 -z 172.16.0.4 3389" tmpif="tun69" iface="ocvpnc1" pidfile="/tmp/${iface}.pid" script="/usr/local/sbin/vpnc-script" # env openconnect="/usr/local/sbin/openconnect" ifconfig="/sbin/ifconfig" # func ifkill() { $ifconfig "$1" down 2>/dev/null || : $ifconfig "$1" destroy 2>/dev/null || : } # check if we're already running if [ -n "$test" ] && $test; then echo "Connection is already up" exit 0 fi # clean up previous instance, if any if [ -e "$pidfile" ]; then read pid <"$pidfile" echo "Killing previous pid: $pid" kill -TERM "$pid" rm "$pidfile" fi ifkill "$tmpif" ifkill "$iface" # open vpn connection echo "$pass" |\ $openconnect \ --background \ --pid-file="$pidfile" \ --interface="$tmpif" \ --user="$user" \ --passwd-on-stdin \ --script="$script" \ "$host" # rename the interface if [ "$iface" != "$tmpif" ]; then echo "Renaming $tmpif to $iface" $ifconfig "$tmpif" name "$iface" fi
Next, use crontab -e and add an entry to run the script regularly.
*/5 * * * * /root/openconnect-vpn >/dev/null 2>&1
Again, replace the path and timing with your own preferred values.
With the connection established, you can now go ahead and add the interface in the “assignment” tab of the GUI and set up appropriate rules for it.
CAUTION: Adding an interface that’s not available at boot time to the GUI will cause pfSense to think something is wrong on subsequent reboots and ask you to configure interfaces. I am not currently aware of a workaround for this, other than to not add the interface, controlling rules directly from the script instead. Please use the workaround below to avoid this issue, and make sure to verify that it works before leaving a pfSense box at a remote site unattended.
Interface boot workaround
The following workaround was offered by “DJC” in the comments section:
- Install “Shellcmd” in PfSense WebConfigurator:
System => Package Manager => Available Packages
Find Shellcmd and INSTALL - Navigate to Shellcmd:
Services => Shellcmd - Add the following item in Shellcmd:
Command: /sbin/ifconfig tun create; /sbin/ifconfig tun0 name ocvpnc1
Shellcmd Type: earlyshellcmd
Description: Create tunnel interface for OVPNC1 at boot
28 Comments
I’ve just tried that, but somehow it doesn’t work. I’m located in China and currently use a patched openvpn with pfsense.
When I run your script it connects fine and the pfsense can ping the server.
On the gui I just changed the openvpn interface from ovpnc1 to ocvpnc1 so all the rules should just carry over, but somehow the LAN can’t connect anywhere. What am I doing wrong?
Thanks a lot
Without knowing how all your rules are set up, that would be very hard for me to diagnose.
I suggest taking a look at your firewall logs to see which rule is blocking the communication.
I got it working. Was a problem with the server. Thanks a lot. That has really helped me.
Glad it worked for you. Keep in mind the “CAUTION” section above. The GUI will rebel on boot if the interface you add doesn’t exist at boot time.
You could probably hack that by adding it in a script before that check is made, but I’m uncertain of where that would be.
Hello!
I would like to set this up to allow my house (and tablet) to have access to my university’s resources.
Would you be able to tell me where you’ve placed the autostart script? My experience with bsd is limited.
Also, could you clarify about the CAUTION section?
Like after I’ve added the connection using the script and added the interface to the GUI and added the routes, will it detonate on reboots or can I remove it from the “assign” interface tab for it to survive reboots and still preserve routes?
I generally add my scripts in cron (crontab -e) using the @reboot timing option. This keeps all my stuff generally out of the way of pfSense, and is very robust when upgrading. It’s also easy to find all my modifications by doing “crontab -l”.
About the CAUTION: pfSense will indeed detonate, as you say, on reboot. There will be a missing interface, as the VPN software hasn’t created it yet. This will kick pfSense into the interface assignment part of the setup, which you’ll have to skip out of to continue booting. Since this requires access to the console, I could not use this at the remote site I was deploying it at, since accessing the console, even over the network, would of course require the network to be there in the first place.
Instead, I ended up installing a minimal virtual machine with Linux, installing the VPN client on there and adding a few simple iptables rules, using shorewall as I often do, to tunnel all traffic from LAN through the VPN. Then I added this linux VM as an additional router in pfSense and I control which traffic is routed through it using the pfSense interface. It’s less intrusive, and has worked quite well. If this option interests you, let me know, and I can provide more details.
Hey, can you provide more details about your minimal vm?
Hey, please see my post here: https://blog.dhampir.no/content/making-a-minimal-vpn-routing-virtual-machine-to-isolate-obnoxious-clients
Here’s the workaround to allow PfSense to boot/reboot and avoid the interface issue. Please update your notes:
——- Interface boot workaround ——-
1. Install “Shellcmd” in PfSense WebConfigurator:
System => Package Manager => Available Packages
Find Shellcmd and INSTALL
2. Navigate to Shellcmd:
Services => Shellcmd
3. Add the following item in Shellcmd:
Command:
/sbin/ifconfig tun create; /sbin/ifconfig tun0 name ocvpnc1
Shellcmd Type:
earlyshellcmd
Description:
Create tunnel interface for OVPNC1 at boot
——-
This will create the missing interface at boot; early enough to avoid the interface mismatch, and you won’t have to reconfigure interfaces or hang at boot.
I used the same setup for VPNC and works great.
Thanks,
DJC
Awesome! I’ll put it into the main article.
this solution is not working on pfsense 2.4.3 anymore. do you hava any alternative?
This post helped me greatly getting started with openconnect! Thank you very much.
One question: I am trying to connect to a larger VPN server, which assigns a different IP address to the client every time it is connected to. This essentially renders the gateway I had specified for the interface as kaput. Any advice on how that can be fixed?
OK, answering my own question here… with a named gateway, the following addition at the end of the script works for me:
# grab our new IP address, edit the config file, and reload the filters
ip=`$ifconfig $iface | grep ‘inet ‘ | awk ‘{ print $2 }’`
xml ed -L -u ‘//gateway_item[name=”VPN_Gateway”]/gateway’ -v $ip /cf/conf/config.xml
/etc/rc.filter_configure
this required the xmlstarlet package to be installed.
Hey. Glad you figured it out. And thanks for sharing!
The install does not work in pfSense 2.3.2+:
You will get this error: “pkg: No packages available to install matching ‘openconnect’ have been found in the repositories”
To fix:
1. Make sure “enabled” key is set to “yes” in /etc/pkg/FreeBSD.conf
2. Change “enabled: no” to “enabled: yes” in /usr/local/etc/pkg/repos/FreeBSD.conf
3. Change “enabled: no” to “enabled: yes” in /usr/local/etc/pkg/repos/pfSense.conf for FreeBSD repo
4. Now you’re able to install packages from FreeBSD official repo
https://forum.pfsense.org/index.php?PHPSESSID=7gohk3pvkochgitq2bf5r2d4b6&topic=109827.msg644067#msg644067
One other thing… before doing the “pkg update” and “pkg install”, you may need to *temporarily* rename /usr/local/etc/pkg/repos. Once openconnect is installed, then rename it back.
Hi Bolt,
intrestet in your minimal vm solution … which iptabels parameters will you use ?
regards Gerhard
Hey, please see my post here: https://blog.dhampir.no/content/making-a-minimal-vpn-routing-virtual-machine-to-isolate-obnoxious-clients
Is it possible to make pfSense be a VPN Server for AnyConnect clients? I already have AnyConnect installed on many PC’s for work. A formal package would be wonderful!
I was only able to get this partially working. The connection is made and pfsense sees the connection and a valid IP address. However, the gateway never gets assigned. And my subnet is wrong (255.255.255.255 instead of 255.255.255.0) so pfsense doesn’t let me manually assign a gateway. Without that, I haven’t been able to create any routes. Any ideas why that would happen or how to troubleshoot?
thank you!
nice article!
also i would like to add how to create NAT, cause GUI doesn’t know what is tun69.
so, first you need to save all NAT rules:
pfctl -sn > nat.pf
than edit nat.pf and add needed rule. in my case that would be:
nat on tun69 inet from 192.168.0.0/22 to any -> 10.12.43.180 port 1024:65535
and i’ve put it before
“no rdr proto carp all”
after that you can reload NAT rules:
pfctl -N -f nat.pf
and it should work.
I’m banging my head against the wall on this one. I’ve got it to the point where the connection is established and the routes are created. I can ping servers on the remote network from the pfSense command-line. But nothing is getting routed from the outside network to the VPN.
Any suggestions for where to look? I’ve got ocvpnc1 assigned to OPT2 and I’ve setup the firewall with allow everything for IPv4 and IPv6 – not other rules. IPv4 – allow all protocols, all sources, all destinations. Save for IPv6.
Not sure how to diagnose this.
Thanks in advance.
Never mind, I didn’t add NAT entries for the OPT2 interface. that fixed it.
I have set up everything as it was described and VPN was working very well for 2 months. Now there was some update on a server side and now when I log in the server prompts me the same password twice:
First, it prompts for a username, then password and then: second password.
After this second password was introduced I’m getting the below error:
Connected to 194.xxx.xxx.xxx:443
SSL negotiation with vpn.xxx.net
Server certificate verify failed: unable to get local issuer certificate
Connected to HTTPS on vpn.xxx.net
XML POST enabled
Please enter your username.
POST https://vpn.xxx.net/auth
Please enter your password.
POST https://vpn.xxx.net/auth
Please enter your password.
Password1:
fgets (stdin): Inappropriate ioctl for device
Renaming tun69 to ocvpnc1
ifconfig: interface tun69 does not exist
Do you know how I should edit the script to support this second password, which is static and exactly the same as the first one?
Thanks
Hey. Unfortunately, I no longer have a need for this kind of setup.
Since it grabs the password from stdin, it may be enough to do something like echo -e “$pass\n$pass” instead of the single one?
If you figure it out, feel free to leave a follow-up comment so others can benefit 🙂
It looks like your AnyConnect provider is requiring 2 factor auth and the client is parsing a form. You can double check this by running the anyconnect client from the command line with a dump of the responses. For example:
openconnect –protocol=anyconnect vpn.server.com –dump-http-traffic -v
You’ll probably see an HTML response in there with form field names like “username”, “password”, and “secondary_password”. Also, look for the form name, usually in a container tag like
You can provide values for these form elements by passing them on the command line to the client:
openconnect –protocol=anyconnect vpn.server.com –form-entry=main:username=myuser –form-entry=main:password=mypass –form-entry=main:secondary_password=push
In my case “push” is the secondary password requirement that indicates the server should push a request to my mobile device for me to authorize the connection request (2 factor). It could also be a code provided by a key generator that has to be input within a certain amount of time. So if you’re seeing this “secondary_password” then it means you need to input the correct 2 factor mechanism or code.
On the other hand it could be your provider gives you the option and there are multiple forms now–one that requires two factor and and another form that doesn’t. If that’s the case you can just pick the right form and pass the relevant values.
Hope this helps someone.
Dudeee, this did help me. Thank you sincerely
Policy route with openconnect client on pfsense 2.5.2 not working!
I followed the procedure from https://forum.netgate.com/topic/103215/pfsense-with-openconnect
The tunnel is up and I can ping the gateway on remote server. If I add a static route to send the traffic through tunnel, it work. But I can not send entire traffic from one IP in LAN through the tunnel. I have multiple openvpn connections which works perfectly with policy route in pfsense.
Any help in this regard is appreciated
John