Four stages stack on each other in a working openfortivpn session. The client authenticates to the gateway and starts a TLS connection, then runs PPP inside that connection, then receives an address and DNS information, and finally applies host routes and resolver settings. Each stage can be alive while the next one is not, which is why "connected" is such a slippery word in support threads.

The decision that removes most of the confusion is who owns the last stage. Either the VPN client applies host changes itself, or another component does it, and mixing the two halfway is how routes and resolver files end up describing different sessions.

Four stages that look like one connection

The first stage is admission. The client posts credentials to the gateway, possibly through a named authentication domain or a one-time code, and receives the parameters it needs to continue. When the client prints that it is connected to the gateway, that means the TLS transport is up. It does not mean PPP has negotiated, and it certainly does not mean an internal application is reachable.

The second stage is the PPP link. The client starts a PPP process against the tunnel device, and the two sides negotiate link options and addresses. Only after that does the host know which local and remote addresses the session uses, and only then can a route pointing into the tunnel make sense.

The third stage is applying that information to the host, which is where ownership matters. The client can add the routes and rewrite resolver configuration, or it can be told to stand down and leave both to whatever else manages networking on that machine. The project's README describes these as separate responsibilities rather than one automatic behavior.

Who edits the routing table

By default the client is the owner. It adds a route toward the gateway through the physical interface, a route for the tunnel's peer, and routes for the networks the session is allowed to use, then removes them when the process exits. That default is convenient on a laptop with a single network manager and no other VPN software.

Choose the handover only when something else genuinely owns routing. A network manager integration, a container network namespace, or a site-wide routing agent may already know how to install and clean up the same prefixes. Passing the no-routes option then prevents two writers from fighting over the same table, which is a race that shows up as intermittent loss of one subnet rather than as a clean failure.

Overlap is the second reason to hand over. If the pushed routes include a prefix that the local network already uses, the client cannot resolve the conflict for you. Someone has to decide whether that prefix is reachable through the tunnel, through the physical link, or through a more specific route, and that decision belongs to whoever owns the topology.

Cleanup is the third. A client that crashes before removing its routes leaves a black hole that outlives the session, and the next connection may add a duplicate on top of it. Whatever owns routing also owns verifying that the old entries are gone. Make that check part of the startup path, not an optional cleanup step.

Who owns DNS and the resolver file

DNS is the same decision with sharper edges. The client can accept the DNS servers the gateway or PPP peer reports and write them into the host resolver configuration. On a simple machine that is exactly what you want, because internal names then resolve only while the tunnel is up.

On a modern Linux host the resolver may be managed by a local stub, and rewriting the resolver file behind that stub's back produces a configuration that looks correct and behaves inconsistently. If the host already runs a resolver manager, let it own DNS and feed it the tunnel's servers through its supported interface. The client's no-dns option is the correct choice there, not a workaround.

Split DNS is a separate question from who writes the file. Sending every query through the tunnel is simple and slow; sending only internal zones through it requires per-domain configuration that most simple clients do not provide. Decide which behavior the host needs before enabling the client's resolver changes. A wrong choice here looks like a name-resolution outage even when the tunnel itself is fine.

Privilege, readiness, and the handover

Creating the tunnel device and editing host routes or resolver state needs elevated network authority. The common mistake is to conclude that everything should therefore run as root, including the browser or the application that uses the tunnel. Keep the privileged part small: the client and its configuration file, owned by an administrator, while user applications keep their normal account.

Readiness should be defined per consumer. A supervisor can consider the service started when the client process is running and the tunnel device exists. A backup job should consider the VPN usable only when its storage endpoint answers through the tunnel. Those are different checks, and using the weaker one for the stronger purpose produces jobs that start too early and fail intermittently. Write the chosen definition down, because a supervisor and a job that disagree about readiness is a support ticket waiting to happen.

Test the contract with four observations: the gateway phase completes, PPP assigns addresses, the intended route is present, and a request to an internal host succeeds. Then stop the client and confirm every one of those is removed or restored. If the host still resolves internal names or still holds a route after the tunnel closes, the ownership handover is incomplete.

Ũhoro ũhĩtĩte