pfSense IKEv2 for iOS/macOS – Part 4

In this article, we’ll configure On Demand VPN for iOS and macOS devices to connect to the VPN we created.

Articles in This Series:
Part 1 – Certificate Configuration
Part 2 – VPN Configuration
Part 3 – Mobile Profile Configuration
Part 4 (Current Article)

Part 4 – On Demand VPN

Advertisement

So you want to get your hands dirty and force your VPN to connect based on network states? You’ve come to the right place! First and foremost, you’ll need an editor that handles XML. I recommend Atom.

Inspired by a Reddit post1, I began to look into Apple’s options for forcing VPN connections through the use of Mobile Configuration Profiles2. One resource I found that was helpful was this post from derman.com. So open up your Mobile Configuration file and let’s get to work!

Here’s the gist of it:
– You force connections through the use of conditions defined in the XML of the Mobile Configuration Profile.

  • The matchine criteria can include any of the following:
    • DNS Domain or DNS Server Settings (with Wildcard Matching)
    • SSID
    • Interface Type
    • Reachable Server Detection

The type of matching you want to do is really up to personal preference. Below is an example of the very simple rules I use and where you want to place your own rules:

  <key>IKEv2</key>
  <dict>
    ***IKEv2 Configuration Info***
    <key>OnDemandEnabled</key>
        <integer>1</integer>
    <key>OnDemandRules</key>
        <array>
           <dict>
               <key>Action</key>
               <string>Disconnect</string>
               <key>URLStringProbe</key>
               <string>https://vpncheckint.domain.com</string>
           </dict>
           <dict>
               <key>Action</key>
               <string>Connect</string>
           </dict>
        </array>
    ***Remainder of IKEv2 Config***
</dict>  

The most important part is the section that enables On Demand VPN:

    <key>OnDemandEnabled</key>
        <integer>1</integer>

The section that follows defines the rules you want to use. In my example, I only use two rules. Each <dict></dict> section defines one rule. Within each rule is an Action and at least one criteria. In my first rule, the action is to Disconnect when a URLStringProbe can contact a server of mine that is only accessible within my network. The final rule is the default action. This is very important. Per the Apple Developer Library, “Dictionaries are checked sequentially, beginning with the first dictionary in the array.” Therefore, if none of your rules match, you need a default to fall back on. In my case, if it can’t reach my internal server (is on the local network), then it should connect the VPN.

Below are some more examples of rules to give you a better idea of how they’re used.:

Disconnect when I have a specific DNS server and am connected to one of two specific wireless networks, otherwise connect (default):

    <key>OnDemandRules</key>
        <array>
        <dict>
            <key>Action</key>
                <string>Disconnect</string>
            <key>DNSServerAddressMatch</key>
                <array>
                    <string>123.123.123.123</string>
                </array>
            <key>InterfaceTypeMatch</key>
                <string>WiFi</string>
            <key>SSIDMatch</key>
                <array>
                    <string>WiFi_SSID1</string>
                    <string>WiFi_SSID2</string>
                </array>
        </dict>
        <dict>
            <key>Action</key>
                <string>Connect</string>
        </dict>
        </array>

Disconnect when I have a specific DNS server and am connected to any Ethernet connection, otherwise connect (default):

    <key>OnDemandRules</key>
        <array>
        <dict>
            <key>Action</key>
                <string>Disconnect</string>
            <key>DNSServerAddressMatch</key>
                <array>
                    <string>10.10.10.18</string>
                </array>
            <key>InterfaceTypeMatch</key>
                <string>Ethernet</string>
        </dict>
        <dict>
            <key>Action</key>
                <string>Connect</string>
        </dict>
        </array>

Disconnect when I am connected to any cellular connection, otherwise connect (default):

    <key>OnDemandRules</key>
        <array>
        <dict>
            <key>Action</key>
                <string>Disconnect</string>
            <key>InterfaceTypeMatch</key>
                <string>Cellular</string>
        </dict>
        <dict>
            <key>Action</key>
                <string>Connect</string>
        </dict>
        </array>

Connect when I am connected to any cellular connection and I can reach Google.com, otherwise disconnect (default):

    <key>OnDemandRules</key>
        <array>
        <dict>
            <key>Action</key>
                <string>Connect</string>
            <key>InterfaceTypeMatch</key>
                <string>Cellular</string>
            <key>URLStringProbe</key>
                <string>https://google.com</string>
        </dict>
        <dict>
            <key>Action</key>
                <string>Disconnect</string>
        </dict>
        </array>

Disconnect when I am connected to Ethernet and I can reach an internal URL, connect if I am on cellular, otherwise disconnect (default):

Advertisement
    <key>OnDemandRules</key>
        <array>
        <dict>
            <key>Action</key>
                <string>Disconnect</string>
            <key>InterfaceTypeMatch</key>
                <string>Ethernet</string>
            <key>URLStringProbe</key>
                <string>https://vpncheck.domain.com</string>
        </dict>
        <dict>
            <key>Action</key>
                <string>Connect</string>
            <key>InterfaceTypeMatch</key>
                <string>Cellular</string>
        </dict>
        <dict>
            <key>Action</key>
                <string>Disconnect</string>
        </dict>
        </array>

This should give you a decent idea of what is possible with manual editing of the Mobile Configuration Profile. Once you’ve set the parameters you want, save the file and follow Step 4 or 5 in Part 3 – Mobile Profile Configuration to add the profile to your mobile device.


References

Advertisement

10 thoughts to “pfSense IKEv2 for iOS/macOS – Part 4”

    1. Sorry for the delay in responding. I have been testing Windows 10 off and on and I haven’t yet gotten a combination of Powershell commands that will connect to this configuration. It’s still on my to-do list.

  1. Here you go…

    Phase 1: AES 256 bits | SHA256 | 20 (nist ecp384)
    Phase 2: AES 256 bits | SHA256 | 20 (nist ecp384)

    Note: If you have a mix of Win10 PCs and Macs, enable AES256-GCM 128 bits for Macs.

    —> Add-VpnConnection -Name “VPN Connection” -ServerAddress 192.168.1.1 -TunnelType “Ikev2”
    —> Set-VpnConnectionIPsecConfiguration -ConnectionName “VPN Connection” -AuthenticationTransformConstants SHA256128 -CipherTransformConstants AES256 -EncryptionMethod AES256 -IntegrityCheckMethod SHA256 -DHGroup ECP384 -PfsGroup ECP384 -PassThru -Force

    1. @FATSLAV is it possible to use stronger encryption for phase one and two? like AES with GCM for the encryption algorithm and and e.g. SHA384 for the hash algorithm? Same goes for key echange/SA in phase two.

      1. What I ended up having to do to get it to work with Windows 10 was set the encryption algorithm in Phase 1 to AES256. I left everything else as configured in the guide (Hash=SHA384,DH=20) for Phase 1 and 2. This obviously required a minor tweak to the mobile config profiles for Apple devices, so I’m working on an addition section of the guide to address all of that.

        I believe this is what I ended up using to configure the Windows VPN (will verify):
        Set-VpnConnectionIPsecConfiguration -ConnectionName “VPN Connection” -AuthenticationTransformConstants GCMAES256 -CipherTransformConstants GCMAES256 -EncryptionMethod AES256 -IntegrityCheckMethod SHA384 -DHGroup ECP384 -PfsGroup ECP384 -PassThru -Force

        1. That`s nice. Thank you. The only worry here is the downside of decreasing the encryption strength in Phase 1, because you probably need to push apple devices (back) to use AES_CBC (with HMAC_SHA2_384_192) instead of the previous AES_GCM_16 (which is a next generation encryption that provides built-in authentication). Having said that, I did not found a way to enable AES_GCM_16 (= Phase 1 encryption algorithm/method “AES 256 GCM with 128bit”) for windows 10 myself yet with leaving every thing else as configured in the guide.

          PS: If AES-GCM is configured as ESP encryption, ESP integrity must be null on some devices.

          1. Update: While it seems possible to set “-EncryptionMethod GCMAES256”, it seems not possible to set -IntegrityCheckMethod to “Null” in Windows 10. At least I did not find a way to do it.

          2. UPDATE: Things are getting more interesting. Pfsense update 2.4.3 now allows configuration of multiple IKE encryption algorithms, key lengths, hashes, and DH groups (see: https://redmine.pfsense.org/issues/8186). As long as the Windows 10 clients can not allow Integrity Check Method “null” or another way is found to make AGES256GCM work, you can instead generate a separate IKE configuration for Windows 10 clients without having the downside of “decreasing” at the same time the encryption strength in Phase 1 for Apple Clients.

  2. Kudos! This is a great step-by-step instruction with a high level of security in mind. Any downside of “just” using the certificate on clients end without additional identification (user/password)? Very much looking forward to the Windows 10 Power Shell instructions for AES256-GCM1 128.

Leave a Reply

Your email address will not be published. Required fields are marked *