The client authenticates, the log says connected, and no packet crosses the tunnel. The server ends the attempt with write to TUN/TAP: Invalid argument (code=22), which reads like a driver fault and usually is not. On routers and small Linux servers that line most often means the two peers disagree about how data packets are framed, so the kernel rejects the decrypted buffer it was handed. Routing has not been tested at that point.

A correct route table and a broken framing agreement look the same from the client: connected, and nothing works.

The Tunnel Comes Up and Nothing Crosses It

Write errors on the tunnel device happen after decryption and before routing. The daemon decrypts a packet, hands it to the interface, and the interface refuses it because the buffer does not match what that device expects. Code 22 is the generic invalid-argument answer, so the useful information is the layer: this is the data path rather than the handshake. If traffic carried yesterday and stopped today with no configuration change, suspect a package or firmware upgrade that moved a default before you suspect the network.

Read the log around the data-channel setup instead of the first error. The negotiated compression mode, the dev type and the pushed options all appear at higher verbosity, and they tell you which of the three mismatches you have.

Compression Is Framing, Not Bandwidth

With compression enabled, every data packet carries a header describing how it was encoded, and both ends must agree on that header. A server still carrying comp-lzo from an old sample configuration, paired with a client that has no compression line, produces exactly this error: the server expects a header the client never wrote. Mixing comp-lzo with compress lz4-v2 fails the same way, since the algorithms differ even though both are called compression. The option is a framing contract rather than a bandwidth feature on modern links.

Version behaviour adds a trap. The 2.5 series started issuing deprecation warnings for compression options, and 2.6 draws a line between refusing compressed packets and merely leaving data uncompressed. A router firmware update can therefore change the effective agreement with nobody editing the tunnel.

Align Both Ends or Remove It from Both

Enumerate every compression directive: the server file, any pushed options, client-specific files and the client profile. comp-lzo on the server needs the same word on the client, and adaptive is the legacy default that the bare option usually means on older builds. A router's GUI switch labelled LZO or compression writes that same option, so set it to match rather than mixing algorithms. Do not assume a similar-looking name is compatible.

If compression is not wanted, remove it deliberately from both ends. allow-compression no on the server refuses compressed packets, but only once clients have stopped offering them; applying it while a client still pushes compression recreates the mismatch in the other direction.

Check the Push and the Device Type

A server can push a compression directive from its main file or from a client-specific one, and a client can drop pushed options with pull-filter. Connect one client at verbosity 4, read what the server announced against what the client accepted, then confirm no filter removed it. If both sides now agree and the error remains, look at the device type: dev tap on one end and dev tun on the other cannot exchange frames, and the kernel rejects the write in the same way.

A bridged TAP deployment needs an actual bridge on the server, not just a different device name. Renaming an interface to tap0 without adding it to a bridge produces a device that accepts the write and goes nowhere.

Then verify with one client and one destination: ping the server's tunnel address, then a host on its LAN. The first proves the data channel and the second proves forwarding.

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