Public bug reported:
Package: network-manager-config-connectivity-ubuntu
NetworkManager: 1.54.3-2ubuntu3
Ubuntu: 26.04 LTS
WHAT HAPPENS
NetworkManager's connectivity check always sends "Connection: close".
connectivity-check.ubuntu.com answers that with an abortive close: the 204
response, then FIN, then RST, sent back to back.
On a network path that reorders packets, that RST can arrive ahead of the
response body. An RST is not data - it holds no sequence space and never
enters the reassembly queue - so when the kernel accepts it, it tears down
the connection and discards whatever is buffered, including a complete and
valid 204 that had already arrived. libcurl then reports
(56) Recv failure: Connection reset by peer
and NetworkManager scores the interface as having limited connectivity.
The server is not doing anything invalid, and the response itself is
perfectly well-formed. But the abortive close leaves no margin: any
reordering between the body and the RST turns a successful request into a
failed one. Every other connectivity endpoint I tested closes gracefully
with FIN alone and is unaffected by the same reordering.
WHY IT MATTERS
A "limited" verdict adds +20000 to that device's default-route metric. On a
multi-homed host whose interface metrics differ by less than that - the
default wired 100 / WiFi 600 pairing, for instance - each failed probe moves
the default route to the backup interface and the next successful probe
moves it back. On my host this produced roughly 830 IPv4 and 740 IPv6
default-route changes per day, with no actual connectivity fault anywhere.
Changing only the probe endpoint took it to zero.
The reordering on my path comes from powerline ethernet adapters, which is
my environment's problem and not Ubuntu's. The point of this report is
narrower: the endpoint's abortive close is what converts a tolerable path
condition into a failed connectivity check, and it is the only endpoint
tested that does so.
HOW TO REPRODUCE
From a host on a path that reorders (or any lossy path), compare the same
request with and without the header NetworkManager sends:
# NM's actual request shape - fails
for i in $(seq 60); do
curl -4 -sS -m 5 -H 'Connection: close' -o /dev/null \
http://connectivity-check.ubuntu.com/ || echo FAIL
done
# identical but keepalive - never fails
for i in $(seq 60); do
curl -4 -sS -m 5 -o /dev/null \
http://connectivity-check.ubuntu.com/ || echo FAIL
done
Results on my host, wired interface:
with Connection: close 40 ok, 20 failed (all curl 56)
default keepalive 60 ok, 0 failed
Note that plain curl does NOT reproduce this by default, because curl uses
keepalive and NetworkManager does not. The explicit header is required.
ENDPOINT COMPARISON
40 requests each, same host, same wired interface, all carrying
"Connection: close":
connectivity-check.ubuntu.com 14 failed
nmcheck.gnome.org 0 failed
connectivitycheck.gstatic.com 0 failed
network-test.debian.org 0 failed
Same request over two different paths from the same host, run back to back,
counting both TCP streams delivered with FIN/RST ahead of the body and
outright failures:
wired (via powerline) 36 of 40 streams reordered, 19 failed
WiFi (direct to AP) 1 of 40 streams reordered, 1 failed
PACKET CAPTURE
A failing exchange. Note the three server packets share a capture timestamp
and their IP IDs are 0x7b (body), 0x7c (FIN), 0x7d (RST) - so the server
sent body-first, and they were delivered body-last:
10.0.0.63.49660 > 91.189.91.97.80: Flags [P.], seq 1:88, length 87
GET / HTTP/1.1
Host: connectivity-check.ubuntu.com
Accept: */*
Connection: close
91.189.91.97.80 > 10.0.0.63.49660: Flags [F.], seq 80, ack 88 <- IP ID 0x7c
91.189.91.97.80 > 10.0.0.63.49660: Flags [R.], seq 81, ack 88 <- IP ID 0x7d
91.189.91.97.80 > 10.0.0.63.49660: Flags [P.], seq 1:80, length 79 <- IP ID
0x7b
HTTP/1.1 204 No Content
x-networkmanager-status: online
connection: close
10.0.0.63.49660 > 91.189.91.97.80: Flags [.], ack 1, sack 1 {80:81}
91.189.91.97.80 > 10.0.0.63.49660: Flags [R], seq 701268504, win 0
The client's ack 1 with sack {80:81} shows the stack had not taken the
payload - it acknowledges nothing and selectively acknowledges only the FIN.
The connection then ends reset, with a valid 204 discarded.
EXPECTED
connectivity-check.ubuntu.com closes gracefully after its response - FIN,
without the trailing RST - as nmcheck.gnome.org, connectivitycheck.gstatic.com
and network-test.debian.org all do. That removes the race entirely and costs
nothing, since NetworkManager has already asked for the connection to close.
WORKAROUND
Override the endpoint in /etc/NetworkManager/conf.d/, at a name sorting after
20-connectivity-ubuntu.conf. nmcheck.gnome.org carries no
X-NetworkManager-Status header, so the verdict has to come from the body:
[connectivity]
uri=http://nmcheck.gnome.org/check_network_status.txt
response=NetworkManager is online
** Affects: network-manager (Ubuntu)
Importance: Undecided
Status: New
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2163449
Title:
connectivity-check.ubuntu.com sends RST immediately after FIN, so its
204 is discarded on any path that reorders packets
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/network-manager/+bug/2163449/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs