Skip to content

listen: set IP_FREEBIND so binding to a not-yet-present address works#27

Open
DevenDucommun wants to merge 1 commit into
openwrt:masterfrom
DevenDucommun:listen-freebind
Open

listen: set IP_FREEBIND so binding to a not-yet-present address works#27
DevenDucommun wants to merge 1 commit into
openwrt:masterfrom
DevenDucommun:listen-freebind

Conversation

@DevenDucommun

Copy link
Copy Markdown

Fixes openwrt/openwrt#18551

When uhttpd listens on a specific address instead of the 0.0.0.0/[::] wildcard, and it starts before the network is fully up, bind() fails with EADDRNOTAVAIL and the listener is dropped. If that was the only configured address, uhttpd prints "bind(): Address not available" followed by "No sockets bound, unable to continue" and the web UI never comes back without a manual restart. People have been hitting this on 23.05 through 25.12, especially with VLAN/management interfaces where the init script's interface-up trigger does not map the listen IP to an interface.

This sets IP_FREEBIND / IPV6_FREEBIND before bind() so the kernel lets us bind to an address that is not assigned yet. The socket starts serving the moment the address appears, so the startup race goes away without depending on the trigger heuristic. The options are best effort and #ifdef guarded, and a failed setsockopt is logged but not fatal.

Tested by building uhttpd from this branch and reproducing the issue in a Linux container:

  • unpatched: binding 192.168.x.y before the address exists prints "bind(): Address not available" and exits with no sockets bound
  • patched: uhttpd stays up on the absent address and serves a real HTTP GET as soon as the address is added to the interface

Verified both IPv4 (IP_FREEBIND) and IPv6 (IPV6_FREEBIND) paths, and confirmed both constants are defined under glibc and musl.

This patch was developed with AI assistance. I have reviewed, understood, and tested the change.

When uhttpd is configured to listen on a specific address (instead of
the 0.0.0.0/[::] wildcard) and starts before the network is fully
configured, bind() fails with EADDRNOTAVAIL ("Address not available")
and that listener is dropped. If it was the only configured address,
uhttpd exits with "No sockets bound, unable to continue" and the admin
interface stays unreachable until a manual restart.

Set IP_FREEBIND / IPV6_FREEBIND on the socket before bind() so the
kernel allows binding to an address that is not assigned to a local
interface yet. The socket starts serving as soon as the address is
configured, which removes the startup race without relying on the
init script's interface-up trigger (which misses DHCP, alias and VLAN
addresses that are not statically mapped to an interface).

The options are best effort and guarded with #ifdef; a failed
setsockopt is logged but not fatal, so kernels without FREEBIND keep
the previous behaviour.

Signed-off-by: Deven Ducommun <deven.ducommun@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

uhttpd fails to listen on specific IP address when network is slow to configure

1 participant