Your laptop resolves intranet.corp through the tunnel while gitlab.com keeps going to the ISP resolver, and that is the arrangement working as designed. Two separate decisions produced it: a name-matching rule picked the resolver, and a route carried the answer back. Break either one and the browser shows a failure that looks the same from the outside. Most split-DNS reports describe the second failure while quoting evidence about the first.

The two halves live in different places and are usually edited by different people. One is DNS policy attached to the VPN profile, the other is a route the tunnel installs or withholds. Debugging stalls when nobody establishes which half actually moved.

Two decisions hiding in one request

The name half is a policy object rather than a route. On Windows it is a name-resolution policy on the VPN profile; on Apple platforms a set of match domains on a DNS settings object; on Linux a routing domain, a split resolver line or the name service switch order. The path half is ordinary routing, installed by the tunnel or by hand, and it has no idea what a hostname is. A profile that admits a suffix only decides who answers; it never makes the answer reachable.

A quick symptom test separates them: substitute an address for the name. If the address works, the path is fine and the rule is wrong. If the address fails too, the rule may be right and the path missing.

How each platform expresses the same name rule

The intent is identical and the field names are not. An example copied from one client to another parses cleanly and never matches. The three shapes look like this:

PlatformWhere the rule livesWhat usually breaks
Windowsname-resolution policy on the VPN profileprecedence against the interface suffix list
Apple platformsmatch domains on the DNS settings objectdomains attached to the wrong extension
Linuxrouting domain, split resolver, nsswitch orderthe suffix written the wrong way round

A match or routing domain is a suffix test, so intranet.corp covers git.intranet.corp and does not cover corp.intranet, and reversing it is the most common mistake in the whole setup. Windows carries the mapping as a name-resolution policy attached to the profile, with its own precedence order against whatever suffix list the interface already had. Apple platforms attach match domains to the DNS settings object of the network extension, and the system applies them per scoped resolver. None of these forms is a route, and none can make an unreachable address reachable. The Windows name-resolution policy reference lists the field names and the precedence rules for that platform, and they are not the ones the Apple or systemd documents use.

A correct answer still needs a path

A resolver answer is only an address, and the application still has to reach it. A split-tunnel design commonly pushes 10.20.0.0/16 and withholds the default route, so the internal name resolves and the connection then hangs. The opposite case is just as common: the route exists, a public resolver answers the private name with NXDOMAIN, and the failure gets filed as a routing problem. Testing the path first sends you staring at routes for a name that was never going to resolve.

There is also a third gate that neither half covers. An ACL on the gateway, a firewall rule or a client-side policy can drop the connection after both decisions went right. When the name resolves, the route exists and the connection still times out, stop testing DNS.

Testing names and paths in a fixed order

Pick an order and keep it, or you will chase whichever step failed most recently. Resolve the documented full internal name, confirm the answer is an address the route table can carry, then repeat with a public name to prove the tunnel did not capture everything. On a systemd host the query and the resolver routing domain are one command apart:

resolvectl query intranet.corp
resolvectl domain
ip route get 10.20.5.10

A Windows client asks the same two questions with different cmdlets. The second one reports the interface the system would actually use:

Resolve-DnsName intranet.corp -Type A
Find-NetRoute -RemoteIPAddress 10.20.5.10

If the lookup returns an address and the path check names the physical interface, the name rule worked and the route did not. If the short name fails while the full name resolves, the suffix list is wrong rather than the resolver.

Where the comparison usually goes wrong

The first mistake is asking an unrelated public resolver about a private name and reading the refusal as evidence about the VPN. The second is assuming that a working public lookup proves the tunnel's resolver path. The third is treating split tunneling and split DNS as one design decision, when a deployment can be correct in one and broken in the other. Each mistake produces confident conclusions from a test that never exercised the part being blamed.

A browser with its own secure DNS can also bypass the system rule, which is why one browser failing while another succeeds is not a contradiction. Compare the resolver that answered, not the browser that complained.

Once both halves are visible, the remaining question is a policy question rather than a technical one: which namespaces belong to the organization, who owns each answer, and which of them should leave the machine at all. Write that down next to the profile, because the next person to touch the rule will need it.

Makomi ya ndenge moko