Problem
Similar to this case, I needed to maintain a (near) continuous VPN connection to a server (server 1) from my server (server 2) that was running a Tomcat web-app (on Ubuntu Server 16.04). Server 1 was part of a network that provided secured VPN access using a FortiNet VPN gateway.
The solution below uses a bash script (which creates an external expect script) to automate the connection, and re-connection (if VPN connection drops), of the VPN connection to server 1.
Solution
Installing Forticlient and dependencies
You'll need to install an appropriate Forticlient SSLVPN package. I don't know why, but FortiNet makes it unusually difficult to find the Linux client package with the forticlientsslvpn_cli script that is required. In any case, I found a package (used version 4.4.23330-1) appropriate for my Ubuntu server (running 16.04) here. Once downloaded you can install it with:
sudo apt-get install <DOWNLOAD_LOCATION>/forticlient-sslvpn_4.4.2333-1_amd64.deb
You'll also need the ppp
and expect
packages installed. If you're using Ubuntu, simply do:
sudo apt-get install ppp expect
Setup
Forticlient should be installed to /opt/forticlient-sslvpn/64bit/. Apparently you need to run the setup
script first:
sudo /opt/forticlient-sslvpn/64bit/helper/setup
Scroll through the legalese and then accept (type Y
). We should have everything we need to now automate connecting.
Bash script (with embedded expect script) to execute (and maintain FortiClient VPN connection)
Please note that the below approach stores a vpn password in clear text in the script file, and as such is a potential security risk. The script should be locked down to stop users without authorisation from viewing its contents. Hence, this approach may only be appropriate for a server/system that is strictly managed or not accessed by other users.
We'll now create a bash script to handle the connection (and automatic reconnection). The script below does several things, including creating and executing an external expect script. This expect script automates and emulates a bit of human interaction that forticlientsslvpn_cli
requires.
#!/bin/bash # init only CONNECT_PID="" RUNNING="" # Provide required parameters FORTICLIENT_PATH="/opt/forticlient-sslvpn/64bit/forticlientsslvpn_cli" VPN_HOST="<HOST:PORT>" VPN_USER="<USER_NAME>" VPN_PASS="<PASSWORD>" # Checks whether vpn is connected function checkConnect { ps -p $CONNECT_PID &> /dev/null RUNNING=$? } # Initiates connection function startConnect { # start vpn connection and grab its pid (expect script returns spawned vpn conn pid) CONNECT_PID="connect" eval $CONNECT_PID } # Creates an expect script to complete automated vpn connection function connect { # write expect script to tmp location cat <<-EOF > /tmp/expect #!/usr/bin/expect -f match_max 1000000 set timeout -1 spawn $FORTICLIENT_PATH --server $VPN_HOST --vpnuser $VPN_USER --keepalive puts [exp_pid] expect "Password for VPN:" send -- "$VPN_PASS" send -- "\r" expect "Would you like to connect to this server? (Y/N)" send -- "Y" send -- "\r" expect "Clean up..." close EOF #IMPORTANT!: the "EOF" just above must be preceded by a TAB character (not spaces) # lock down and execute expect script chmod 500 /tmp/expect /usr/bin/expect -f /tmp/expect # when expect script is finished (closes) clean up rm -f /tmp/expect } startConnect # note this will not continuously loop, it will only loop if the spawned vpn connection drops # i.e. will only hit this code when expect closes while true do # sleep a bit of time (why not, everyone needs sleep) sleep 1 checkConnect [ $RUNNING -ne 0 ] && startConnect done
NOTE: the "EOF" on line 47 MUST be preceded by a single TAB character (not spaces), otherwise the script will fail. If you are copy/pasting the script above into your favourite Linux text editor, please remove the preceding spaces and replace with a tab character.
Securing and executing
You'll note that the above script requires the entering of a username and password. At the very least, let's lock down this script to root
(only allow root
to read/write contents):
Assume our script is called forti-vpn.sh
and is located in our home folder
sudo chown root:root ~/forti-vpn.sh sudo chmod 600 ~/forti-vpn.sh sudo chmod +x ~/forti-vpn.sh
To execute the script, change to the folder where it resides and run
sudo ./forti-vpn.sh &
which will execute the script in the background.
Stopping the script (and killing the vpn connection)
To stop the script you'll need to find it's pid
's and kill them. If you named your script forti-vpn.sh
, then you can do this easily with pkill
. For example, executing
sudo pkill forti
will kill all processes with the name "forti" in it (which include the script and spawned forticlient processes).
Alternatively, you can use htop.
You should have this installed (if not, do sudo apt-get install htop
). With htop
you can then locate the sudo forti-vpn.sh
process and select them (with space-bar) and then hit F9 (kill) and then 9 (sigkill) and hit enter.
References
- https://hadler.me/linux/forticlient-sslvpn-deb-packages/
- https://gist.github.com/mgeeky/8afc0e32b8b97fd6f96fce6098615a93
Related articles