One application on the machine exits through the VPN and another does not, and both users swear they changed nothing. The difference is often a binding decision made by the application itself: a socket tied to a device, a source address chosen before the connection, or a namespace with its own routing table. Each one changes which path applies, and none of them shows up in a generic browser IP check.

Three different bindings, three different effects

Binding to a device and binding to a source address are related operations with different consequences. A device binding can force traffic out of one interface, bypassing the normal route lookup for that socket. A source-address binding still goes through route selection, but the chosen source can match a policy rule and send the packet somewhere else. The distinction sounds academic until a rule routes by source. Then it decides everything.

A network namespace is the third case. It has its own interfaces and routing table, so an application inside it is not affected by the host default at all. Treating all three as the same thing produces confident explanations that do not survive the first test.

Decide what the app actually sets

Read the application's networking configuration or its documented behavior before touching routes. If it exposes an interface choice, a source address field or a namespace option, that setting is the first thing to inspect. If it does not, the binding may be internal and only visible through tracing or its own diagnostics.

On Linux, socket options such as SO_BINDTODEVICE have documented scope and permission requirements, and an unprivileged process may not be able to set them at all. That constraint is a useful clue: if the option cannot be applied, the application is probably not the source of the difference.

Policy routing reads the source

When policy routing is configured, a rule can select a table based on the packet source. A socket that binds a source address can therefore follow a rule the default path never touches, even though no interface was named explicitly.

Reproduce the lookup with the same address family, source and namespace the application uses. A generic route lookup from a shell in the host namespace answers a different question, and that mismatch is the most common reason a working route looks broken.

Split tunneling and helper processes

Per-app split tunneling adds another layer. The client may match the application package or process, and a helper that opens its own socket is a separate subject. A launcher and its background service can produce different connections under the same visible name.

Check whether the split-tunnel rule covers the process that actually connects. If the app binds to a specific interface and the VPN client matches by package, the two decisions can disagree without either one being wrong.

Test the app's own path

Run a fresh request from the application after each change. A browser showing the exit you wanted is not equivalent evidence for a different program bound to a different interface, and cached connections can keep using the old path long after a setting changed. Close the old session before you judge the new rule. Otherwise the test measures the past.

The Linux socket reference documents SO_BINDTODEVICE and its requirements. Read the application's own configuration first, reproduce the lookup in the same context, and only then decide whether the route or the binding needs to change.

អត្ថបទពាក់ព័ន្ធ