Linux CLI · integration · Qeli 0.8.1

External TUN with dev_attach

A mode for Keenetic OpkgTun and other controllers that create the interface, assign its address, install routes and own its lifecycle.

Core rule

Qeli transports packets; the external controller owns the interface

With dev_attach=true, the Linux client opens an existing named TUN/TAP and connects it to the encrypted channel. Normal automatic L3 and route setup does not run in this mode.

OperationQeliExternal owner
Create and delete the interface
MTU, link up, address and prefix
Routes, full/split policy and NAT/firewall
Packet encryption and transport
Report the server-assigned IPv4Reads the file
Qeli will not repair incomplete owner setup. The connection may succeed, but traffic will not flow until the external manager assigns the address/prefix and installs the required routes.
client.conf

Minimal Linux client configuration

/etc/qeli/client.conf · [qeli]
dev = ext0
device_type = tun
dev_attach = true
gateway = false
dns = off

dev must exactly match the created interface name, and device_type must match its TUN/TAP type. dns=off is recommended when the external manager also owns DNS policy.

example owner preparation before Qeli starts
sudo ip tuntap add dev ext0 mode tun user qeli
sudo ip link set dev ext0 mtu 1200 up
Do not confuse this with QELI_PLATFORM_TUN_FD. dev_attach is a user-facing Linux CLI mode for an existing named interface. Platform TUN FD is an internal transport-core contract with mobile/platform adapters, not a client.conf key.
Startup order

The interface must exist before the Qeli client

#ActorAction
1External ownerCreates ext0, sets its type and MTU, and brings the link up
2QeliConnects to the server and opens the existing interface through TUNSETIFF
3QeliAfter authentication, atomically writes the assigned IPv4 to QELI_TUNIP_FILE
4External ownerReads the IP and applies its configured prefix, routes and firewall
5External ownerAfter Qeli stops, removes the interface and its network policy itself
Interface not present yet? The client reports that it is waiting for the owner, and the reconnect loop retries. Systemd dependencies are still useful, but a short startup race does not require a manual restart.

Qeli borrows the file descriptor: on a clean stop it closes it but does not remove the external owner's interface, addresses or routes.

QELI_TUNIP_FILE

Passing the assigned address to the controller

The path is set as an environment variable for the Qeli process, not an INI key. After AUTH, the file contains only the IPv4 address without a prefix length. The external controller must know the prefix from coordinated server configuration.

systemd · Environment
Environment=QELI_TUNIP_FILE=/run/qeli/ext0.ip
external hook logic after the file appears
TUN_IP=$(cat /run/qeli/ext0.ip)
TUN_PREFIX=24  # must match the server tunnel-pool prefix
sudo ip addr replace "$TUN_IP/$TUN_PREFIX" dev ext0
Do not copy /24 blindly. It is only an example owner variable. QELI_TUNIP_FILE does not contain a mask, so the controller must obtain the actual prefix from its own configuration.
Keenetic · OpkgTun

The release's supported integration pattern

On Keenetic, ndm creates the interface, the init script starts Qeli and exports the address-file path, and the wan.d hook applies L3 and routes. The client stays in split-tunnel mode because the router owns policy.

release/keenetic/opkgtun/client.conf.example
dev = opkgtun0
dev_attach = true
gateway = false
dns = off
release/keenetic/opkgtun/S99qeli
export QELI_TUNIP_FILE="$OPKGTUN_TUNIP"
By symptom

Common dev_attach failures

SymptomWhat to check
“interface … does not exist yet”Startup order and exact dev name; reconnect will retry attach
Permission denied on /dev/net/tunUser, CAP_NET_ADMIN and device permissions
Attach failsTUN/TAP type, owner compatibility and multi-queue/busy interface state
could not write tun IPThe directory exists and is writable by Qeli, and the path is not read-only
Connected, but no traffic flowsAddress with the correct prefix, link up, routes, forwarding and owner firewall
Qeli changes DNSSet dns=off when DNS must be controlled externally
ip -details link show dev ext0interface type, state and MTU
ip address show dev ext0address and actual prefix
ip route showroutes created by the external owner
journalctl -u qeli-client -bexpect Attached …; L3 left to its owner
Trust boundary

The TUN owner sees packets before encryption

The external manager controls the interface and can access raw IP packets before they reach Qeli. Run it with least privilege and protect the assigned-address file. Qeli uses CLOEXEC duplicates to avoid passing the TUN descriptor to child hooks, but this does not restrict the interface owner itself.

Primary sources

v0.8.1 code and ready integration