Skip to content

Fall back to a second host, then a TCP handshake, where the internet probe fails - #9069

Closed
AronBakes wants to merge 1 commit into
omacom:quattrofrom
AronBakes:network-icmp-tcp-fallback
Closed

AronBakes wants to merge 1 commit into
omacom:quattrofrom
AronBakes:network-icmp-tcp-fallback

Conversation

@AronBakes

@AronBakes AronBakes commented Aug 30, 2026 •

Copy link
Copy Markdown

Fixes #9068. Fixes #9261.

omarchy-network-status measures the internet hop with a single ICMP echo to
one hardcoded host. Anything that filters either the host (an ISP or router
that blackholes 1.1.1.1 — #9261) or the protocol (a university or corporate
WLAN with a default-deny egress ACL, a captive-portal appliance, CGNAT — #9068)
makes every sample come back empty, so the panel reads Timeout and climbs to
100% packet loss on a link that is working fine.

Two layers, each only reached when the one before it gets nothing:

  1. Second host. 1.1.1.1 and 8.8.8.8 are pinged together and the first reply
    in list order wins. Pinging in parallel rather than in sequence means a blocked
    host costs no time, and nothing changes on a network where 1.1.1.1 answers.
  2. TCP handshake. Only when no echo returns from either, a handshake to
    each host's port 443 is timed and reported as a separate field.

Why the handshake time is comparable

"You substituted a different measurement into the same row" is the fair
objection, so, measured on one machine:

probe result
/dev/tcp handshake 3.8 – 5.7 ms
curl time_connect 4.1 – 4.4 ms
ICMP RTT (ping avg) 4.24 ms

Both cross the network exactly once — SYN/SYN-ACK is a round trip like
echo/reply — which is why they agree. The row is still labelled Ping (TCP)
rather than passing one off as the other, because a handshake can additionally
carry server-side accept latency.

Why it is a separate field

internet_ping_ms keeps meaning "an echo returned in this long", because that
is what the packet loss row counts. Folding the handshake into it would report a
link shedding half its packets as perfectly healthy — the fallback would quietly
fill the gap left by every lost echo. A sample the handshake rescued is still a
lost echo.

Where no echo returns all window but the handshake keeps landing, loss is not
measurable from here at all, so the row holds at -- rather than claiming a
clean link nobody measured.

scenario Ping Packet Loss
healthy 20 ms 0%
1.1.1.1 blocked, 8.8.8.8 answers 20 ms 0%
real 50% loss, handshake rescues each miss 20 ms 50%
ICMP filtered, link healthy 10 ms (Ping (TCP)) --
link dead Timeout 100%
status script without the new field 20 ms unchanged

Each is a test in test/shell.d/network-test.sh. The script-side cases run
print_ping_samples for real against a stubbed ping, rather than grepping the
source, and were checked to fail when the second host or the per-host handshake
is removed.

Notes

  • Uses bash's /dev/tcp under a timeout rather than curl, which no script in
    bin/ currently needs. Verified bounded on all four outcomes: reachable,
    refused, blackholed (returns at 2.001s), unresolvable.
  • The router row deliberately stays ICMP-only. The gateway is inside the network,
    answers echo even where the border filters it, and need not have the port open.
  • On a network where 1.1.1.1 answers, output is identical to today: no extra line
    is emitted and no socket opened. The one added cost everywhere is a second ICMP
    packet per poll, in parallel with the first.
  • Other designs are reasonable and I have no attachment to this one — reading
    NetworkManager's existing connectivity state, or simply rendering -- when
    every sample is empty while rx_bytes is still climbing, would both be smaller
    than this. Happy to redo it either way.

🤖 Generated with Claude Code

…probe fails

omarchy-network-status measures the internet hop with a single ICMP echo to one
hardcoded host. Anything that filters either the host or the protocol -- an ISP
that blackholes 1.1.1.1, a university or corporate WLAN with a default-deny
egress ACL, a captive-portal appliance, CGNAT -- makes every sample come back
empty, so the panel reads Timeout and climbs to 100% packet loss on a link that
is working fine.

Probe 1.1.1.1 and 8.8.8.8 together and take the first reply in list order, so a
blocked host costs no time and nothing changes for a network where 1.1.1.1
answers. Only when no echo returns from either, time a TCP handshake to each in
turn and report it as internet_tcp_ms. It crosses the network the same single
round trip, so the number is comparable, and the panel labels the row Ping (TCP)
rather than passing a handshake off as an echo reply.

internet_ping_ms keeps meaning "an echo returned in this long", because that is
what the packet loss row counts: a sample the handshake rescued is still a lost
echo, and folding the two together would report a link shedding half its packets
as healthy. Where no echo returns all window but the handshake keeps landing,
loss is not measurable from here, so the row holds at -- instead of claiming 0%.

Uses bash's /dev/tcp under a timeout rather than curl, which no script in bin/
currently needs.

Fixes omacom#9068
Fixes omacom#9261

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AFuwaBrZB6VbYVHy7oUU64
@AronBakes
AronBakes force-pushed the network-icmp-tcp-fallback branch from 467179b to 42537de Compare August 31, 2026 09:05
@AronBakes AronBakes changed the title Fall back to a TCP handshake where ICMP is filtered Fall back to a second host, then a TCP handshake, where the internet probe fails Aug 31, 2026
@bjarneo

bjarneo commented Sep 21, 2026

Copy link
Copy Markdown
Member

Automated duplication check: this pull request looks similar to #7932, which covers the same network status second probe. I keep that one open and close this one to consolidate review.

If you feel this is the wrong decision, please open the PR again with a note on the difference.

@bjarneo bjarneo closed this Sep 21, 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

2 participants