A routing table dump is the least useful diagnostic in VPN troubleshooting and the most frequently pasted one. Forty lines of prefixes tell you what the machine could do, not what it did for the request that failed. The mechanism you actually want is the lookup: given this source and this destination, which rule matched, which table was consulted, and which interface and next hop came out. Start from one destination and one source, then read the table with that question in hand, and the same output becomes evidence instead of noise.

A table is a set of candidates, not a decision

Each entry describes a prefix and what to do with traffic that matches it: send it to an interface, hand it to a next hop, or drop it. Nothing in that list is ordered by intent, and the entry that looks most specific to a human is not always the one the kernel selects, because selection follows longest prefix match and, among equal prefixes, the metric.

So the first move is to ask the kernel rather than to read the list. The lookup command answers for a destination, and with a source argument it answers for the exact pair a forwarded or bound connection would use:

ip route get 198.51.100.10
ip route get 198.51.100.10 from 10.80.0.25
ip -6 route get 2001:db8:10::40

Every address above is a documentation example. The point is the shape of the answer: interface, source address chosen, gateway, and the table the entry came from. If that output does not match the interface you expected, you have localised the problem in one command, and no amount of reading the full table would have told you which candidate won.

The lookup walks rules, then tables

On Linux the decision is two stages. Policy rules are evaluated in priority order, and the first rule that matches names a table to consult; that table then does the longest-prefix match. A rule can match on source, destination, firewall mark, interface or a combination, which is why a main-table dump can be perfectly accurate and completely irrelevant to the packet you are investigating.

ip rule show
ip route show table all | head -40
ip route show table 100

If a rule sends traffic from your VPN pool to table 100, then table 100 is the one that matters, and the main table is a decoy. This is also the mechanism behind source-based routing on a router: the same destination can have two different answers depending on where the packet came from, and only the lookup with a source argument reveals which one applies.

IPv6 has its own rules and tables. A design that runs both families needs both lookups, and a working IPv4 answer says nothing about the v6 path a dual-stack client may prefer.

What the VPN client installs

Clients do not usually replace the default route, because doing so would break the tunnel's own outer path. They install something more specific that wins by prefix length: a pair of half-defaults covering 0.0.0.0/1 and 128.0.0.0/1 is the classic trick, since both are longer prefixes than 0.0.0.0/0 and together cover the whole space. Others install specific private prefixes plus a policy rule, and some add a mark so only selected traffic is captured.

That is why "the VPN did not change my default route" is not evidence of failure. Check what it did add, and check whether the destination in question falls inside those prefixes:

ip route show | grep -E 'tun|wg|ppp|ipsec'
ip route get 10.20.30.40 from 10.80.0.25

Two half-routes are easy to miss in a dump because they do not look like a default. A split-tunnel configuration that forgot to include a prefix produces exactly the symptom you are chasing: the application that should use the tunnel resolves and connects locally instead. Compare the installed prefixes against the destinations the user actually needs, not against the addresses you happened to test. A split-tunnel list that covers the file server but not its resolver produces a connection that resolves to a public address and then fails to authenticate, which looks like a password problem and is a route problem.

The outer route has to survive too

The tunnel is itself traffic. The packets carrying the encapsulated payload go to the peer's address over the physical interface, and that path must not be routed back into the tunnel. When it is, you get the distinctive failure where the tunnel establishes and then stops passing traffic, because the transport for the tunnel is now inside the tunnel.

Check the peer address the way you checked the inner destination, and confirm it resolves to the physical interface rather than the tunnel:

ip route get 203.0.113.10
traceroute -n -m 5 203.0.113.10

A recursive route, a policy rule that catches the peer, or a default that was replaced by a full-tunnel client are the three usual causes. All three are visible in the outer lookup, and none of them are visible in a dump of the main table taken after the fact.

What routing output cannot tell you

A correct lookup means the kernel would send the packet somewhere sensible. It does not mean the firewall permits it, the IPsec policy covers it, the NAT rule translates it, or the remote side has a return route. Each of those is a later stage, and the strongSwan forwarding notes describe the chain a packet has to pass on both ends.

It also does not account for application-level binding. A process can bind to an interface, set a mark, or use its own resolver and connect by a name that resolves differently from what you tested. When the lookup is right and the connection still fails, the next question is which process is making it and whether that process sees the same table you do.

So keep the diagnosis ordered: name the destination and source, run the lookup, read only the table and rule that the lookup named, then test the next stage. That sequence keeps a routing investigation to minutes and leaves a record someone else can follow, which a pasted table never does.

ХӀокхунах тера йаззамаш