IOS – Is it possible to bring up or tear down an iOS OnDemand tunnel based on a site accessed by mobile device

iosiphonevpn

Say, if accessing one.example.com should always bring up the tunnel, how can this be expressed with OnDemandRules? Or if two.example.com should always tear down the tunnel?

The Configuration Profile Key Reference states that the latter case could somewhat be handled by using a DomainAction with value NeverConnect that would "never trigger a VPN connection attempt". Which would be, although better than nothing, not exactly what I'm looking for – except that even this does not work as expected (if I've understood the documentation correctly):

<key>OnDemandRules</key>
<array>

  <dict>
    <key>Action</key>
    <string>EvaluateConnection</string>
    <key>ActionParameters</key>
    <array>
      <dict>
        <key>DomainAction</key>
        <string>NeverConnect</string>
        <key>Domains</key>
        <array>
          <string>two.example.com</string>
        </array>
      </dict>
    </array>
  </dict>

  <dict>
    <key>URLStringProbe</key>
    <string>http://a.url.that.returns.a.two.hundred.ok/</string>
    <key>Action</key>
    <string>Connect</string>
  </dict>

</array>

My understanding is that as the OnDemandRules array of dictionaries is evaluated at every connection attempt, and if the device is accessing two.example.com, the first dictionary would match and the tunnel would not be brought up. If the device is accessing another domain, for example one.example.com, the first dictionary would not match, the second dictionary would match, and the tunnel would be brought up. This does not work, however, and the tunnel is never brought up. If the order is switched and the Connect dictionary is on top then the tunnel is always brought up (including when accessing two.example.com).

Is my understanding of the whole thing way off, or is Apple documentation or/and implementation somehow broken? Has anyone come up with OnDemandRules that can be used to selectively bring up or tear down a VPN connection based on the sites the device is accessing?


Edit: The tunnel can be brought up "by-domain" by using the following rules (this assumes that there is no local resolver present):

<key>OnDemandRules</key>
<array>

  <dict>
    <key>Action</key>
    <string>EvaluateConnection</string>
    <key>ActionParameters</key>
    <array>
      <dict>
        <key>RequiredDNSServers</key>
        <array>
          <string>127.0.0.1</string>
        </array>
        <key>DomainAction</key>
        <string>ConnectIfNeeded</string>
        <key>Domains</key>
        <array>
          <string>one.example.com</string>
        </array>
      </dict>
    </array>
    <key>URLStringProbe</key>
    <string>http://a.url.that.returns.a.two.hundred.ok/</string>
  </dict>

  <dict>
    <key>Action</key>
    <string>Disconnect</string>
  </dict>
</array>

This however suffers from the fact that resolving the domain name first fails, causing the initial page load to fail in Safari. After a page reload the page is shown, and the tunnel is brought up. This happens even if instead of 127.0.0.1 a real, working behind-the-tunnel DNS server address is provided. Is there a way to not fail the initial lookup?

Also, the latter dictionary (Disconnect) is never reached, and the tunnel stays up for some time. How can I do the "opposite" of the above and tear down the tunnel for some domain names? The DomainAction of NeverConnect does not do this.

Best Answer

This however suffers from the fact that resolving the domain name first fails, causing the initial page load to fail in Safari. After a page reload the page is shown, and the tunnel is brought up. This happens even if instead of 127.0.0.1 a real, working behind-the-tunnel DNS server address is provided. Is there a way to not fail the initial lookup?

If you are using a real DNS server, the initial lookup will not fail on iOS 9.2. It is a bug introduced from iOS 9.3 and Apple haven't fixed it on iOS 9.3.2 release version.

iOS 9.3 beta VPN On Demand ignores useDNSServers