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.
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.
| Operation | Qeli | External 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 IPv4 | ✓ | Reads the file |
Minimal Linux client configuration
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.
sudo ip tuntap add dev ext0 mode tun user qeli
sudo ip link set dev ext0 mtu 1200 up
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.The interface must exist before the Qeli client
| # | Actor | Action |
|---|---|---|
| 1 | External owner | Creates ext0, sets its type and MTU, and brings the link up |
| 2 | Qeli | Connects to the server and opens the existing interface through TUNSETIFF |
| 3 | Qeli | After authentication, atomically writes the assigned IPv4 to QELI_TUNIP_FILE |
| 4 | External owner | Reads the IP and applies its configured prefix, routes and firewall |
| 5 | External owner | After Qeli stops, removes the interface and its network policy itself |
Qeli borrows the file descriptor: on a clean stop it closes it but does not remove the external owner's interface, addresses or routes.
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.
Environment=QELI_TUNIP_FILE=/run/qeli/ext0.ip
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
QELI_TUNIP_FILE does not contain a mask, so the controller must obtain the actual prefix from its own configuration.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.
dev = opkgtun0
dev_attach = true
gateway = false
dns = off
export QELI_TUNIP_FILE="$OPKGTUN_TUNIP"
Common dev_attach failures
| Symptom | What to check |
|---|---|
| “interface … does not exist yet” | Startup order and exact dev name; reconnect will retry attach |
| Permission denied on /dev/net/tun | User, CAP_NET_ADMIN and device permissions |
| Attach fails | TUN/TAP type, owner compatibility and multi-queue/busy interface state |
| could not write tun IP | The directory exists and is writable by Qeli, and the path is not read-only |
| Connected, but no traffic flows | Address with the correct prefix, link up, routes, forwarding and owner firewall |
| Qeli changes DNS | Set dns=off when DNS must be controlled externally |
ip -details link show dev ext0interface type, state and MTUip address show dev ext0address and actual prefixip route showroutes created by the external ownerjournalctl -u qeli-client -bexpect Attached …; L3 left to its ownerThe 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.