Skip to content

OpenVPN DCO instance fails to start after unclean stop: orphaned kernel socket, bind fails with "Address already in use" #10784

Description

@sudosadek

Important notices

Before you add a new report, we ask you kindly to acknowledge the following:

If AI was used, please disclose:

  • Model used: Claude (Opus 5)
  • Extent of AI involvement: log analysis, review of ovpn_service_control.php and drafting of this report. All facts, logs and command output come from my production system and were verified by me.

Describe the bug

After an unclean stop of an OpenVPN instance of type DCO, the kernel side of the instance survives the process. The openvpn process is gone, but the UDP listening socket stays bound with no owning process, so every following start attempt fails with:

TCP/UDP: Socket bind failed on local address [AF_INET6][undef]:7777: Address already in use (errno=48)

The instance stays in "failed" state and cannot be recovered from the GUI (service restart, disable and enable again). Only a manual ifconfig ovpns5 destroy from the shell brings it back.

I cannot name a last known working version, since I switched these instances from TUN to DCO one day before the incident, so I have no earlier DCO history to compare with. On the same system the identical instance ran fine on DCO for about 14 hours before the failing restart.

To Reproduce

Steps as they happened on my system:

Go to VPN > OpenVPN > Instances, edit a running server instance with Type = DCO (UDP, port 7777)
Change a parameter (in my case keepalive from 60/120 to 10/60), Save, and apply
The in place restart ends with the openvpn process gone, but the socket still held by the kernel
Any further start of this instance logs "Socket bind failed ... Address already in use (errno=48)" and the instance shows as "failed"

The failure is not deterministic; earlier edits of the same instance restarted cleanly.

State on the shell while the instance was down, no process, but the socket is still there:

# ps auxww | grep instance-3106bb83
(no result besides grep itself)

# sockstat -l | grep 7777
??       ??              ?? ?? udp46   *:7777                *:*

Expected behavior

Starting an instance should not fail because of leftovers of its own previous run. I would expect the service control script to make sure the interface is in a clean state before start, for example by destroying an existing ovpnsX/ovpncX interface before creating and starting it, or by destroying it on stop.

Describe alternatives you considered

  • Workaround that solves it: ifconfig ovpns5 destroy, then configctl openvpn restart . Takes a minute, but needs shell access, which is awkward when the broken instance is the remote access VPN itself.
  • Restart or disable and enable from the GUI: does not help, the kernel socket survives both.
  • Going back to Type = TUN: works, but gives up the performance benefit of DCO (in my case a single stream went from around 260 Mbit/s to over 600 Mbit/s after switching to DCO).
  • A monit check on the process and port with automatic restart: does not help either, since a restart is exactly what fails here.

Screenshots

Not applicable, the relevant output is in the log and command output above.

Relevant log files

VPN > OpenVPN > Log File, three start attempts, all rejected:

2026-08-23T08:03:21 Error openvpn_server5 TCP/UDP: Socket bind failed on local address [AF_INET6][undef]:7777: Address already in use (errno=48)
2026-08-23T08:21:55 Error openvpn_server5 TCP/UDP: Socket bind failed on local address [AF_INET6][undef]:7777: Address already in use (errno=48)
2026-08-23T08:28:04 Error openvpn_server5 TCP/UDP: Socket bind failed on local address [AF_INET6][undef]:7777: Address already in use (errno=48)

Additional context

Reading src/opnsense/scripts/openvpn/ovpn_service_control.php, legacy_interface_destroy() seems to be called only when the dev_type of an instance changes, when the device name changes, or when an instance is removed. On a normal start, setup_interface() reuses an already existing interface and only runs ifconfig ... down, which does not release the socket held by the kernel. If that reading is correct, the orphaned interface case is not covered.

pfSense had what looks like the same class of problem with DCO and fixed it by destroying the interface right before starting OpenVPN: https://redmine.pfsense.org/issues/13602

Impact in my case: the remote access VPN of the site was down for about 30 minutes and I could only reach the firewall through the site to site tunnel from our second location.

Environment

Software version used and hardware type if relevant, e.g.:

OPNsense 26.7.2_2 (amd64), FreeBSD 15.1-RELEASE-p2, OpenSSL 3.5.7 OpenVPN 2.7.6 (log banner reports: DCO version: FreeBSD 15.1-RELEASE-p2) Instance: role server, UDP port 7777, Type DCO, tls-crypt, AES-128-GCM, topology subnet Intel Pentium Gold G6405 (2 cores, 4 threads) Network: Intel igb

Metadata

Metadata

Assignees

No one assigned

    Labels

    supportCommunity support or awaiting triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions