Skip to content

transport server: bind to the address family enabled on the host - #1832

Draft
Narasimha-sc wants to merge 1 commit into
simplex-chat:masterfrom
Narasimha-sc:nd/rc-listener-ipv4-fallback
Draft

transport server: bind to the address family enabled on the host#1832
Narasimha-sc wants to merge 1 commit into
simplex-chat:masterfrom
Narasimha-sc:nd/rc-listener-ipv4-fallback

Conversation

@Narasimha-sc

@Narasimha-sc Narasimha-sc commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Connecting a mobile to the desktop fails when IPv6 is disabled in the kernel (ipv6.disable=1) — simplex-chat/simplex-chat#5515, simplex-chat/simplex-chat#3531.

startTCPServer resolves the wildcard address with AI_PASSIVE only, and then select picks the IPv6 address whenever one is returned:

let hints = defaultHints {addrFlags = [AI_PASSIVE], addrSocketType = Stream}
 in select <$> getAddrInfo (Just hints) host (Just port)
select as = fromJust $ family AF_INET6 <|> family AF_INET

getaddrinfo returns :: even when the host has no IPv6 at all, so the filter selects it and socket AF_INET6 throws EAFNOSUPPORT.

AI_ADDRCONFIG is the missing part of the filter: it excludes the address families that have no address configured on any interface. This adds startTCPServerConfigured, which passes it, and uses it for the remote control TLS server — the only listener that has to accept connections on an IPv6-less host, as its address is advertised as IPv4 in the invitation.

startTCPServer itself is unchanged: SMP/XFTP/ntf servers and the local TCP server keep requiring IPv6, and still fail if it is disabled.

Measured

Calling the two functions from this branch with host = Nothing:

host state startTCPServer startTCPServerConfigured
IPv6 enabled [::] [::]
ipv6.disable=1 (no IPv6 addresses, socket(AF_INET6) → EAFNOSUPPORT) Network.Socket.socket: unsupported operation (Address family not supported by protocol) 0.0.0.0
net.ipv6.conf.all.disable_ipv6=1 [::] 0.0.0.0

Verified in a network namespace — the third row with the real sysctl, the second with an LD_PRELOAD shim making socket(AF_INET6) return EAFNOSUPPORT on top of a namespace with no IPv6 addresses. Also checked that AI_ADDRCONFIG never empties the result: on a host with no addresses configured at all glibc falls back to returning both families, so fromJust in select stays safe.

Supersedes the earlier catchAny-on-bind version of this PR, which worked around the selection instead of fixing it.

startTCPServer resolves the wildcard address with AI_PASSIVE only and then
selects IPv6 address when it is present. On the hosts where IPv6 is disabled
in the kernel (ipv6.disable=1) getaddrinfo still returns `::`, creating the
socket fails with EAFNOSUPPORT, and the desktop app cannot be connected from
the mobile app (simplex-chat/simplex-chat#5515).

Add startTCPServerConfigured that also passes AI_ADDRCONFIG, so that the
address families without any configured address are excluded - IPv6 wildcard
address is only chosen when IPv6 is enabled, and IPv4 wildcard address is used
otherwise. Use it for the remote control TLS server, as its address is
advertised as IPv4 in the invitation.

startTCPServer is unchanged and is still used for SMP/XFTP/ntf servers and for
the local TCP server, so they keep failing when IPv6 is disabled.
@Narasimha-sc
Narasimha-sc force-pushed the nd/rc-listener-ipv4-fallback branch from d340e19 to bc8f91e Compare August 18, 2026 14:35
@Narasimha-sc Narasimha-sc changed the title remote control: fall back to IPv4 when IPv6 bind fails transport server: bind to the address family enabled on the host Aug 18, 2026
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.

1 participant