Subscribe via Email

Subscribe via RSS/JSON


Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan


MacOS VPN doesn’t use the VPN DNS

Continuing with my previous post … as part of configuring it I went to “Advanced” > “DNS” in the VPN connection and put in my remote end DNS server and domain name to search. On Windows 10 I didn’t even have to do this – remote DNS and domains were automatically configured as part of connecting. Anyways, once I put these in though I thought it should just work out of the box but it didn’t.

So turns out many others have noticed and complained about this. I couldn’t find a solution as such to this but learnt about scutil --dns in the process. Even though the Mac OS has a /etc/resolv.conf file it does not seem to be used; rather, the OS has its own way of DNS resolution and scutil --dns lets you see what is configured. (I am very very sketchy on the details and to be honest I didn’t make much of an effort to figure out the details either). In my case the output of this command showed that the VPN provided resolver for my custom domain was being seen by scutil and yet it wasn’t being used – no idea why.

I would like to point out this post though that shows how one can use scutil to override the DHCP or VPN assigned DNS servers with another. Good to know the kind of things scutil can do.

And while on this confusing topic it is worth pointing out that tools like nslookup and dig use the resolver provided in /etc/resolv.conf so these are not good tools if you want to test what an average Mac OS program might be resolving a particular name to. Best to just ping and see what IP a name resolves to.

Anyways, I didn’t want to go down a scripting route like in that nice blog post so I tried to find an alternative.

Oh, almost forgot! Scoped queries. If you check out this SuperUser post you can see the output of scutil --dns and come across the concept of scoped queries. The idea (I think) is that you can say domain should be resolved using a particular name server, domain should be resolved via another, and so on. From that post I also got the impression you can scope it per interface … so the idea would be that you can scope the name server for my VPN interface to be one, while the name server for my other interfaces to be another. But this wasn’t working in my case (or I had configured something wrong – I dunno. I am a new Mac OS user). Here was my output btw so you can see my Azure hosted domain has its own name server, while my home domain rakhesh.local has its own (and don’t ask me where the name server for general Internet queries is picked up from … I have no idea!).

Anyways, here’s a link to scutil for my future reference. And story 1 and story 2 on mDNSResponder, which seems to be the DNS resolver in Mac OS. And while on mDNSResponder, if you want to flush you local DNS cache you can do the following (thanks to this help page):

What a mouthful! :)

Also, not related to all this, but something I had to Google on as I didn’t know how to view the routing table in Mac OS. If you want to do the same then netstat -nr is your friend.

Ok, so going back to my problem. I was reading the resolver(5) man page and came across the following:

Mac OS X supports a DNS search strategy that may involve multiple DNS resolver clients.

Each DNS client is configured using the contents of a single configuration file of the format described below, or from a property list supplied from some other system configuration database. Note that the /etc/resolv.conf file, which contains configuration for the default (or “primary”) DNS resolver client, is maintained automatically by Mac OS X and should not be edited manually. Changes to the DNS configuration should be made by using the Network Preferences panel.

Mac OS X uses a DNS search strategy that supports multiple DNS client configurations. Each DNS client has its own set of nameserver addresses and its own set of operational parameters. Each client can perform DNS queries and searches independent of other clients. Each client has a symbolic name which is of the same format as a domain name, e.g. “”. A special meta-client, known as the “Super” DNS client acts as a router for DNS queries. The Super client chooses among all available clients by finding a best match between the domain name given in a query and the names of all known clients.

Queries for qualified names are sent using a client configuration that best matches the domain name given in the query. For example, if there is a client named “”, a search for “” would use the resolver configuration specified for that client. The matching algorithm chooses the client with the maximum number of matching domain components. For example, if there are clients named “a.b.c”, and “b.c”, a search for “x.a.b.c” would use the “a.b.c” resolver configuration, while a search for “x.y.b.c” would use the “b.c” client. If there are no matches, the configuration settings in the default client, generally corresponding to the /etc/resolv.conf file or to the “primary” DNS configuration on the system are used for the query.

If multiple clients are available for the same domain name, the clients ordered according to a search_order value (see above). Queries are sent to these resolvers in sequence by ascending value of search_order.

The configuration for a particular client may be read from a file having the format described in this man page. These are at present located by the system in the /etc/resolv.conf file and in the files found in the /etc/resolver directory. However, client configurations are not limited to file storage. The implementation of the DNS multi-client search strategy may also locate client configurations in other data sources, such as the System Configuration Database. Users of the DNS system should make no assumptions about the source of the configuration data.

If I understand this correctly, what it is saying is that:

  1. The settings defined in /etc/resolv.conf is kind of like the fall-back/ default?
  2. Each domain (confusingly referred to as “client”) in the man-page can have its own settings. You define these as files in /etc/resolver/. So I could have a file called /etc/resolver/ that defines how I want the “” domain to be resolved – what name servers to use etc. (these are the typical options one finds in /etc/resolv.conf).
  3. The system combines all these individual definitions, along with dynamically created definitions such as when a VPN is established (or any DHCP provided definitions I’d say, including wired and wireless) into a configuration database. This is what scutil can query and manipulate.

What this means for me though is that I can create a file called /etc/resolvers/ (my Azure domain is with something like these:

Thus any requests for will go via this name server. When I am not connected to VPN these requests will fail as the DNS server is not reachable, but when connected it will work fine.

What if I want to take this one step further though? As in I want DNS requests for to go to its proper external DNS server when I am not on VPN but go via the internal DNS server when I am on VPN? That too is possible. All I have to do is have multiple files – since I can’t call all of them /etc/resolvers/ – and within each specify the domain name via the domain parameter and also define the preference via a search_order parameter. The one with the lower number gets tried first.

So I now have two files. For internal queries I have /etc/resolvers/ (the name doesn’t matter):

For external queries I have /etc/resolvers/

The internal file has higher priority. I also added a timeout of 5 seconds so it doens’t spend too much time trying to contact the name server if the VPN is not connected. Easy peasy. This way my queries work via the internal DNS servers if I am connected to VPN, and via external DNS servers if I am not on VPN.

If I now look at the output of scutil --dns I see all this info captured:

So that’s it. Hope this helps someone!


Azure stuff I’ve been up to

Past few days I’ve been writing this PowerShell script to set up an Azure lab environment automatically. In the time that I spent writing this script I am sure I could have set up numerous labs by hand, so it’s probably a waste of time! It’s also been a waste of time in the sense that instead of actually doing stuff in this lab I have spent that time scripting. I had to scale back a lot of what I originally set out to do because I realized they are not practical and I was aiming for too much. I have a tendency to jump into what I want to do rather than take a moment to plan out I want, how the interfaces will be etc, so that’s led to more waste of time as I coded something, realized it won’t work, then had to backtrack or split things up etc. 

The script is at GitHub. It’s not fully tested as of date as I am still working on it. I don’t think I’ll be making too much changes to it except wrap it up so it works somewhat. I really don’t want to spend too much time down this road. (And if you check out the script be aware it’s not very complex and “neat” either. If I had more time I would have made the interfaces better for one). 

Two cool things the script does though:

  1. You define your network via an XML file. And if this XML file mentions gateways, it will automatically create and turn them on. My use case here was that I wanted to create a bunch of VNets in Azure and hook them up – thanks to this script I could get that done in one step. That’s probably an edge case, so I don’t know how the script will work in real life scenarios involving gateways. 
  2. I wanted to set up a domain easily. For this I do some behind the scenes work like automatically get the Azure VM certificates, add them to the local store, connect via WMI, and install the AD DS role and create a domain. That’s pretty cool! It’s not fully tested yet as initially I was thinking of creating all VMs in one fell swoop, but yesterday I decided to split this up and create per VM. So I have this JSON file now that contains VM definitions (name, IP address, role, etc) and based on this the VM is created and if it has a role I am aware of I can set it up (currently only DC+DNS is supported). 

Some links of reference to future me. I had thought of writing blog posts on these topics but these links cover them all much better:

I am interested in Point-to-Site VPN because I don’t want to expose my VMs to the Internet. By default I disable Remote Desktop on the VMs I create and have this script which automatically creates an RDP end point and connects to the VM when needed (it doesn’t remove the end point once I disconnect, so don’t forget to do that manually). Once I get a Point-to-Site VPN up and running I can leave RDP on and simply VPN into the VNet when required. 

Some more:

PowerShell: Add a line to multiple files

Trivial stuff, but I don’t get to use PowerShell as much as I would like to so I end up forgetting elementary things that should just be second nature to me. Case in hand, I wanted to a add a line to a bunch of text files. Here’s what I came up with – just posting it here as a reference to my future selef.

For the background behind this, I use Private Internet Access for my VPN needs and since last month or so my ISP’s been blocking traffic to it. Private Internet Access offers a client that lets me connects to their servers via UDP or TCP. The UDP option began failing but the TCP option surprisingly worked. Of course I don’t want to use TCP as that’s slow and so I went to Private Internet Access’s website where they give a bunch of OpenVPN config files we can use. These are cool in the sense that some of them connect via IP (instead of server name) while others connect to well-known ports or use a well-known local port and so there’s less chance of being blocked by the ISP. In my case turned out just connecting via IP was more than enough so it looks like the ISP isn’t blocking OpenVPN UDP ports, it’s just blocking UDP traffic to these server names.

Anyhow, next step was to stop the client from prompting for an username/ password. OpenVPN has an option auth-user-pass which lets you specify a file-name where the usrname and password are on separate lines. So all I had to do was create this file and add a line such as auth-user-pass pia.txt to all the configuration files. That’s what the code snippet above does.

OpenVPN “pausing” bug in iOS 7


If you are using iOS 7 and the OpenVPN app you might notice it “pauses” when on 3G and the phone goes to sleep.

This only happens on 3G and when you switch from Wi-Fi to 3G and is a known bug.

Private Internet Access OpenVPN on iOS

I use Private Internet Access for my VPN needs. They have servers in many countries and provide OpenVPN, L2TP, and PPTP access. Been using them for a year now and no complaints so far. For Android and Windows they provide apps that use OpenVPN, but for iDevices you are stuck with L2TP and PPTP and while that’s fine I prefer OpenVPN (see here and here; also worth reading this on why TCP isn’t a good idea for tunneling). Thankfully iOS has an OpenVPN client so this is something one can setup manually.

Private Internet Access provides a zip file containing all the certificates and config files for OpenVPN. You can’t use these config files directly in the client though. Will have to use iTunes and copy over the files to the OpenVPN app (with a modification to the config files which I’ll come to in a minute). Or you can make two changes to these config files (one of which you have to make even in the iTunes case) and skip iTunes. That’s what I am going to do here. I avoid iTunes if I can (not coz I hate it but generally, I don’t like to be tied to it).

The zip file provided by Private Internet Access contain files with an ovpn extension – which are the configuration files for their server at each location – as well as a ca.crt file which is the certificate for the Private Internet Access servers. The first thing we have to do is combine this ca.crt file into each of the ovpn files. This way we don’t have to worry about how to have both files in the same location as the contents are now merged into one.

The second thing we have to do is added a line like this to each of the ovpn files:

This line tells the OpenVPN client there is no client certificate. By default the iOS OpenVPN client expects a client certificate so unless make this change to the config files the client will not let us connect.

To combine the ca.crt file into each of the config files copy paste the contents of file into each of the config files, surrounding the contents with <ca> and </ca> tags. Alternatively, you could be a geek and use something like PowerShell to automate the process. Copy paste the snippet below and run it in the folder where you extracted the zip file from Private Internet Access.

Pretty straightforward. Replace the line with the contents of the file, add an extra line.

I did this for the files from Private Internet Access and uploaded the resulting files to a zip file you can download from here.

You can download the zip file on your computer, extract the contents, and email the config files you want to an email account you have on the iDevice. Opening the config file from the email will launch OpenVPN and let you add the profile to it.

Alternatively you could visit the above link in a browser such as iCab Mobile on your iDevice. Or even in a browser such as Safari, but download and open with an app like File Explorer (or any other app really which lets you open a zip file and pass the contents to another app).