You picture the VPN server reading your laptop address off the packet and writing it into a log. What it reads is whatever the last NAT hop put into the outer header, which on a tethered phone is often an address shared with hundreds of other subscribers. Your machine's own 192.168.x.x never crosses the internet in that header, and the tunnel address is handed out by the server after the connection is already up. So when a server log and ip addr on the laptop disagree, neither is wrong; they describe different layers of one session.

Three addresses, and only one is in the log

The confusion comes from collapsing three addresses into one. Each has a different owner, lives in a different header, and reaches the server by a different path.

AddressWho assigns itWhere it sitsVisible to the VPN server
Device address, e.g. 192.168.1.24Your router via DHCPOuter header, before translationNo, rewritten in place
Translated address and portRouter, ISP CGNAT, or bothOuter header, after translationYes, this is the tuple it logs
Tunnel address, e.g. 10.8.0.6The VPN server itselfInner header, after decapsulationYes, but it chose it

Only the middle row is unknown at connect time. The server writes it into its peer table, status file or flow log depending on the daemon: WireGuard calls it the endpoint, an OpenVPN status file labels it Real Address, strongSwan reports it as the remote host of the IKE_SA. That value is refreshed whenever a packet arrives from a different source, so it changes without anyone restarting anything.

The bottom row is what people misread as an identity claim. It marks a slot in the server configuration, not a person, because the server picked it from its own pool. Two users can receive the same tunnel address on different days, and one can hold two of them from two devices.

Why the logged tuple changes while the tunnel stays up

Address translation is a table with a timer, not a permanent binding. A home router keeps its UDP mapping for a while after the last packet, a carrier gateway recycles ports on its own schedule, and a phone that hops from Wi-Fi to LTE returns with a different source entirely. Linux conntrack defaults are a useful benchmark here: nf_conntrack_udp_timeout is 30 seconds and the streaming variant is 120, so a quiet tunnel can lose its mapping long before the user notices.

The tunnel survives because the protocol authenticates the peer, not the address. WireGuard is stateless after the handshake, so any authenticated packet updates the stored endpoint and a rebind heals on the next packet; that is why persistent-keepalive = 25 exists, to keep the mapping warm while idle. OpenVPN's --float does the same job, letting an authenticated client resume from a new address and port. On 2.4 and 2.5 builds where float is off by default, a rebind resets the session and the client reconnects.

IPsec gets there with more moving parts. IKEv2 notices translation by comparing the source and destination hashes in the NAT detection payloads, switches to UDP 4500 encapsulation, and follows keepalives to the new tuple. When keepalives are blocked the SA stays up on paper while traffic in one direction silently stops.

What the server can attribute, and what it cannot

The myth worth killing is that translation hides you from the operator. It changes the label, not the observation. A gateway behind carrier NAT sees 100.64.0.0/10 space or one public address shared by many subscribers, and can still tie the flow to a certificate subject, a WireGuard public key, an assigned tunnel address, byte counters and a time window. None of that needs your LAN address.

The limits run the other way too. A shared address in a log points at a gateway, not a household; two sessions from the same translated address on different ports are different devices; the same address on two different days can be two unrelated subscribers if the port was recycled. A server that records only peer keys cannot map one to a customer without the account database, and a server that records only addresses cannot tell a laptop from a phone behind the same router.

Compare both ends instead of guessing

To settle what happened, capture the same connection at both ends at the same moment and compare the tuple, not the address. On the client, before any translation:

ss -uapn 'dport = :51820'
ip -4 route get 203.0.113.10
wg show wg0 endpoints

Then read the translation entry on the router or CGNAT gateway, and what finally arrives on the server:

conntrack -L -p udp --dport 51820
tcpdump -ni eth0 udp port 51820

Three patterns explain most mismatches. The server source port differs from the local port while the destination matches: ordinary port translation. The server source address belongs to an ISP block that is not yours: at least one extra NAT layer. Packets stop after an idle period and resume with a new port: the mapping expired, not a routing fault. If the timestamps are more than a second or two apart, you are comparing two different attempts.

Where the difference breaks things

Outages that look like server faults usually start here. An access rule pinned to your home address fails after the ISP lease changes. A fail2ban rule matching a translated address bans every subscriber behind that gateway at once. A site-to-site peer with a fixed remote address stops rekeying after a mobile link changes. The tunnel protocol was fine; the assumption about the outer tuple was not.

The same confusion shows up at the server end. If the VPN box itself sits behind NAT you need a port forward and a working forwarding path; the strongSwan forwarding guide covers that case for IPsec. A server reachable only on a private address never sees the translated tuple its clients present, which is a different problem from clients being translated.

Work through these four checks in order and stop at the first one that fails:

  • Capture at both ends at the same time; confirm source port, destination port and timestamps line up.
  • Read the server peer listing for the address it currently holds, not the address you expected.
  • Check the conntrack or NAT table for the entry and its remaining lifetime.
  • Confirm the tunnel interface address on the client matches what the server assigned, not the LAN address.

If both captures agree on the tuple and the tunnel still fails, translation is not your problem; move on to the handshake and to the routing table inside the tunnel.

متعلقہ مضامین