Split tunneling usually fails in one of two ways. Either traffic that should be inside the tunnel goes around it, or traffic that should stay out gets pulled in. The stale-rule failure is the first kind, and it is the more confusing one, because the rule is being enforced exactly as written. What changed is the destination: the service now answers on an address the rule never named, and nothing in the tunnel is wrong.

What the rule pins and what DNS returns

A split-tunnel rule is a static statement about destinations, usually expressed as a prefix, a route or an address list. It is evaluated against the packet's destination at send time. A hostname is a lookup that returns a set of addresses with a lifetime and a cache, and the answer can differ by resolver, by query type and by minute.

Those two objects never negotiate with each other. The rule keeps matching the prefix it was given, the service keeps changing the address it hands out, and the gap between them widens silently. This is why the symptom appears after a provider migration or a certificate renewal rather than after a configuration change. Nobody edited the tunnel, so nobody looks at the tunnel, and the diagnosis drifts toward the application instead of the policy.

Three ways the match breaks

The obvious case is a moved service: the operator re-addressed it, DNS followed, and the exception did not. The second is an address family the rule never covered, which happens when a name starts returning AAAA records that a v4-only exception ignores. The third is a resolver difference: an internal view and a public view can return different addresses for the same name, so the address your app uses is not the one you tested with.

A cached connection is a fourth variant and it is easy to miss. The application may still be talking to an address it resolved an hour ago, which means your fresh lookup and its open socket disagree about where the service lives.

Read the destination the app actually uses

Ask the operating system and the socket table, not a browser tab. The lookup answers what the name resolves to right now, and the socket table shows the address the process is connected to, which may be older. Run both before you form a theory, because the difference between them is itself the answer in roughly half the cases.

getent ahosts api.example.com
dig +short api.example.com A
dig +short api.example.com AAAA
ss -tnp | grep -F api
ip route get 203.0.113.40

Then compare with what the rule covers. If the current address falls outside the exception and the request still fails, you have found the cause without touching the tunnel configuration. If the app is connected to an address that matches the rule and the request still fails, the problem is somewhere past the tunnel and this is the wrong investigation.

Repair the mechanism, not the symptom

If the product supports maintained domain-based steering, use it and follow its documented refresh and scope behaviour. That replaces a static guess with a maintained answer, at the cost of depending on the feature working as documented.

If the design relies on a static list, give it an owner and an update plan. That plan should say how the address is discovered, who approves the change and how quickly the list is expected to follow a provider migration. A list with no owner is a future outage with a known cause.

Do not widen the exception to a large neighbouring network just to catch every address you saw during a short test. That is not a fix; it is a permanent change to the security boundary, and it will quietly let unrelated services bypass the tunnel for as long as the rule exists.

Verify both halves of the intent

A split-tunnel design has two intentions, and a fix should preserve both. The protected service must go through the tunnel, and the excluded categories must keep going around it. Test a fresh connection to the repaired destination, then test one thing that is supposed to stay outside.

curl -sv --max-time 5 https://api.example.com/ -o /dev/null 2>&1 | grep -E 'Trying|Connected to'
curl -sS --max-time 5 https://public.example/ -o /dev/null -w '%{http_code}\n'

Record the new address, the mechanism you chose and the date. That note is what stops the next person from concluding that the VPN randomly ignored its own configuration.

ସମ୍ପର୍କିତ ପ୍ରବନ୍ଧ