10

The forticlient VPN software is borked, when using split horizon, since OSX El Capitan. The problem is that DNS requests are sent out on the normal primary interface to the DNS of the VPN tunnel.

How do we get the DNS requests to be sent out over the correct interface (i.e. VPN tunnel)

hbogert
  • 411
  • 1
  • 4
  • 18

8 Answers8

11

Edited Answer

(Re)improved on just about everybody else's improved answer (@elmart, @user26312,myself). Edits should not be needed in the script:

#!/bin/bash
default_line=$(netstat -rn |grep default)
gateway=$(echo $default_line | awk '{print $2}')
interface=$(echo $default_line | awk '{print $6}')
echo $gateway
echo $interface

scutil <<EOF
d.init
get State:/Network/Service/forticlientsslvpn/IPv4
d.add InterfaceName ppp0
set State:/Network/Service/forticlientsslvpn/IPv4
EOF

route delete default
route delete -ifscope $interface default
route add -ifscope $interface default $gateway
route add -net 0.0.0.0 -interface $interface

Make the file you put this in, executable and execute (after connecting with the VPN) with sudo. Before the script does any changes, it looks at your current default route and therefore knows your current gateway and interface.


Old answer

Not a complete solution, you'll have to do the following two high-level things after each VPN connection setup:

  1. We'll have to set the tunnel's interface to ppp0
  2. Redo default routes (because 1. implicitly sets the wrong default gateway, split tunnel should still work correctly hereafter)

Create a file with the name scutil-forti for example

d.init
get State:/Network/Service/forticlientsslvpn/IPv4
d.add InterfaceName ppp0
set State:/Network/Service/forticlientsslvpn/IPv4

Redo gateway routes, so make another file, routes-forti, with (mind the lines with specific settings for your network):

sudo route delete default
sudo route delete  -ifscope en0 default # This line depends on your interface
sudo route add -ifscope en0 default 192.168.2.252  # This depends on your normal local gateway.
sudo route add -net 0.0.0.0 -interface en0

now, execute,

$ cat scutil-forti |sudo scutil ; bash routes-forti
hbogert
  • 411
  • 1
  • 4
  • 18
  • But, these steps should need to be reverted after disconnecting, shouldn't they? – elmart Oct 14 '15 at 18:01
  • 1
    TL;DR no reverting is needed. No, the `State:/Network/Service/forticlientsslvpn/IPv4` key is there to start with once the VPN tunnel is running and is deleted when the VPN tunnel is deleted disconnects. The routes aren't actually different than what they should be. – hbogert Oct 14 '15 at 20:17
8

I've reworked @hbogert's solution into a more manageable single script:

#!/bin/bash

scutil <<EOF
d.init
get State:/Network/Service/forticlientsslvpn/IPv4
d.add InterfaceName ppp0
set State:/Network/Service/forticlientsslvpn/IPv4
EOF

route delete default
route delete -ifscope en0 default
route add -ifscope en0 default 192.168.1.1
route add -net 0.0.0.0 -interface en0

That is assuming you're using en0 interface and 192.168.1.1 default gateway. If not, replace those with your corresponding values. If you don't know them, type route get www.google.com to get them. Then:

  • Place that into a file (e.g. 'fix-vpn') somewhere in your path.
  • Give it execute permissions (chmod u+x fix-vpn).
  • Run it with sudo (sudo fix-vpn) just after connecting to vpn.

I've tried it and it works. As I said, this is just a rework of a previous solution. I just posted it as a separate answer because I didn't have space enough in a comment.

BTW, I also thought this could be included in a /etc/ppp/ip-up script so that it gets automatically executed when connecting. But for some reason, it doesn't work that way. If somebody can explain/improve on that, please do.

elmart
  • 181
  • 2
4

I was able to use an older version of Forticlient and confirmed that it works!

Here's the link to it on my dropbox:

https://www.dropbox.com/s/p43ssvp0gusmzeq/forticlientsslvpn_macosx_4.0.2297.dmg?dl=0

mr. brody
  • 41
  • 2
1

UPDATE: Downloading and installing the newest and official version 5.4.1 for Mac OS X fixes all the problems on Mac OS X El Capitan.

As described in the fortinet forum one should download the newest (yet unpublished) version of the FortiClient to fix the problems on Mac OS X El Capitan:

https://www.dropbox.com/sh/cb0j4pxw1f8nq84/AABHzZW1bpx1VjzYAmiK00S9a?dl=0

This was the easiest solution for me.

asmaier
  • 131
  • 1
  • 5
0

Improving on @elmart's answer a little bit (I think).

#!/bin/bash
scutil <<EOF
d.init
get State:/Network/Service/forticlientsslvpn/IPv4
d.add InterfaceName ppp0
set State:/Network/Service/forticlientsslvpn/IPv4
EOF
ROUTE_OUT=$(route get www.google.com)
GATEWAY=$(echo "${ROUTE_OUT}"|grep gateway|cut -d':' -f2|xargs)
INTERFACE=$(echo "${ROUTE_OUT}"|grep interface|cut -d':' -f2|xargs)

echo "Fixing $INTERFACE with gateway $GATEWAY"

route delete default
route delete -ifscope $INTEFACE default
route add -ifscope $INTERFACE default $GATEWAY
route add -net 0.0.0.0 -interface $INTERFACE

That way the script doesn't need to be edited (and changing interfaces shouldn't be a problem). xargs is used to strip the whitespace.

I've also added (though I don't know if this is an improvement):

rootcheck () {
  if [ $(id -u) != "0" ]
    then
      echo "We need sudo permissions to run this script"
      sudo "$0" "$@"  # Modified as suggested below.
      exit $?
  fi
}

rootcheck "$@"

To the very beginning of the script to remind people to use sudo.

  • It would be better to use an IP address in the `route get` command to eliminate the dependency on DNS. – kasperd Oct 27 '15 at 08:48
  • As this Question's issue is with split brain, even after the VPN is connected your default route is likely your gateway. You can just scrape `$ netstat -rn` to get the gateway and interface. – hbogert Oct 27 '15 at 10:22
0

I took hbogert's script and wrapped it in Applescript for myself and another employee, it's available here: https://www.dropbox.com/s/lh0hsqdesk3i0n7/Execute-Post-VPN-Connection.app.zip?dl=0

Simply connect to VPN, then execute the app and type in your admin password (required for sudo). NOTE: MUST BE SAVED IN /Applications/

0

I solved the problem for me by re-configuring the DNS settings to use Google DNS servers before the ones provided by FortiClient. Unfortunately, this has to be done after each re-connect.

#!/bin/bash
scutil <<EOF
d.init
d.add ServerAddresses 8.8.8.8 8.8.4.4 <IP ADDRESSES FOR DNS FROM FORTICLIENT>
set State:/Network/Service/forticlientsslvpn/DNS
quit
EOF

Details on this can be found here.

  • So what happens if I need my company's DNS for resolving hostnames in the company network? – hbogert May 16 '16 at 14:55
  • This depends on how the VPN is configured. Normally, the "internal" DNS servers are passed through to your machine. These are the ones I called "". If your machine can't resolve an address with 8.8.8.8 or 8.8.4.4 it uses the DNS servers defined by the IP addresses in "". – Christoph Hermann May 21 '16 at 14:28
0

On my current OS X version (Sierra 10.12.6) & FortiClient 5.6.1 it seems like if ServerAddresses has more than 2 addresses, then the "set" call doesn't persist anything (if you "get", nothing will have been updated). To workaround this, I decided to only keep first FortiClient DNS address and merge it with my public DNS address (8.8.8.8).

Moreover, I would suggest to automatically run the bash script on FortiClient connect : this can be done by exporting FortiClient configuration script then re-importing it

Full guide below :

1/ Create following bash script and store it somewhere (in my case, it was into ~/bashscripts/update-forticlient-dns.sh) and don't forget to replace the <FIRST IP ADDRESS FOR FORTICLIENT DNS> by the result of scutil --dns | grep "nameserver\[0\]" while your FortiClient connection is up

#!/bin/bash

ROOT_PASSWORD=$1

# Uncomment this if you want to log everything happening during this script execution into a dedicated log file
# exec >/tmp/forticlient-log 2>&1

# Ensuring we did a sudo correctly once
# Because we cannot both use a pipe and an stdin redirection at the same time
# (or at least, my bash knowledge is not wide enough for that :-))
echo "$ROOT_PASSWORD" | sudo -S ls /dev/null
sudo scutil <<EOF
get State:/Network/Service/forticlientsslvpn/DNS
d.add ServerAddresses 8.8.8.8 <FIRST IP ADDRESS FOR FORTICLIENT DNS>
set State:/Network/Service/forticlientsslvpn/DNS
quit
EOF

2/ Run FortiClient, then go into Preferences > General and click the Backup button which will export your FortiClient configuration into a file

3/ In this file, locate & edit the /forticlient_configuration/vpn/sslvpn/connections/connection[name="YOUR CONNECTION"]/on_connect/script/script node and call your script inside it :

<on_connect>
   <script>
      <os>mac</os>
      <script>/Users/fcamblor/bashscripts/update-forticlient-dns.sh "your_secret_root_password_here"</script>
    </script>
</on_connect>

4/ Go back to FortiClient console, click the lock in the bottom left corner, then go to Preferences > General and click the Restore button : locate your updated configuration file and that's it, your DNS configuration will be updated on the fly each time you connect to the VPN.