When starting openvpn with a pre-existing Linux DCO interface, userspace appears to enter the intended "existing DCO device" path, but the interface is not actually adopted correctly.
Reproducer:
modprobe ovpn
ip link add tun0 type ovpn
openvpn --dev tun0 ...
The program seems to correctly detect the underlying interface:
open_tun_dco: tun0
net_iface_new: add tun0 type ovpn
sitnl_send: rtnl: generic error (-17): File exists
Cannot create DCO interface tun0: -17
DCO device tun0 already exists, won't be destroyed at shutdown
ovpn-dco device [tun0] opened
But when a client connects, DCO netlink operations fail:
dco_new_peer: peer-id 0 ...
kernel error: ovpn: ifindex does not match any interface
dco_new_peer: netlink reports device not found
Exiting due to fatal error
And despite the earlier "won't be destroyed at shutdown" message, shutdown deletes the interface:
Closing ovpn-dco interface
net_iface_del: delete tun0
So there seem to be two userspace bugs in this path:
- The
-EEXIST branch in net_iface_new() marks the interface persistent, but does not set tt->dco.ifindex from the existing device. Later generic netlink messages are sent with an invalid ifindex.
close_tun_dco() deletes the interface unconditionally and does not honor tt->persistent_if.
Note that there is also a mode wrinkle: ovpn interfaces need to be created with the correct mode (as a netlink parameter): MP for server and P2P for p2p/client. Userspace will likely need to verify that mode too when adopting a pre-existing ovpn interface.
When starting openvpn with a pre-existing Linux DCO interface, userspace appears to enter the intended "existing DCO device" path, but the interface is not actually adopted correctly.
Reproducer:
The program seems to correctly detect the underlying interface:
But when a client connects, DCO netlink operations fail:
And despite the earlier "won't be destroyed at shutdown" message, shutdown deletes the interface:
So there seem to be two userspace bugs in this path:
-EEXISTbranch innet_iface_new()marks the interface persistent, but does not settt->dco.ifindexfrom the existing device. Later generic netlink messages are sent with an invalid ifindex.close_tun_dco()deletes the interface unconditionally and does not honortt->persistent_if.Note that there is also a mode wrinkle: ovpn interfaces need to be created with the correct mode (as a netlink parameter): MP for server and P2P for p2p/client. Userspace will likely need to verify that mode too when adopting a pre-existing ovpn interface.