From 4f038ecad87777bc1d74f8f93f267da8cd396446 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 17 Jul 2026 19:45:13 +0200 Subject: net: unbreak ping against hosts that intermittently drop ICMP Pinging sl0p.foo through gbhub looked hung: DNS resolved, then nothing. Packet-tracing showed the echo request leaving the hub's TUN and eth0 correctly NATed every time - but 80.78.19.56 blackholes ICMP for all ids in windows of tens of seconds (provider rate limiting). One lost reply wedged ping for minutes because net_recv's pump-counted timeout is effectively unbounded at native emulation speed. Two fixes: - NET_RECVNB (op 8): non-blocking recv - one RX pump, $FE if nothing buffered, same delivery/EOF semantics as NET_RECV otherwise. ping now waits <=~2s per seq (net_recv_nb + msleep loop), prints 'seq=N timeout' and moves on, like real ping. - ICMP echo id was hardcoded $1234 for every GB, every boot, so all sessions produced byte-identical flows - hostile to NAT conntrack (keyed on icmp id). wNetEchoId is now our host octet + rDIV timing noise sampled at DHCP lease, distinct per GB and per boot. Verified: 8 back-to-back native-speed gbhub runs, zero hangs; a run that hit a blackhole window printed seq=1 timeout then recovered to 3/4 received. GB<->GB ping and DNS/DHCP unaffected. --- c/ping.c | 15 ++++++++++++++- c/sock.h | 6 ++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'c') diff --git a/c/ping.c b/c/ping.c index f8d5bf7..8671318 100644 --- a/c/ping.c +++ b/c/ping.c @@ -14,6 +14,19 @@ static void put_ip(unsigned char *ip) { for (i = 0; i < 4; i++) { putu(ip[i]); if (i < 3) putc('.'); } } +/* wait up to ~2s for an echo reply without blocking in the kernel: a lost + reply (some hosts rate-limit ICMP) must cost one "timeout" line, not + minutes wedged inside net_recv's pump-counted wait. */ +static unsigned char wait_reply(unsigned char s) { + unsigned char t, r; + for (t = 0; t < 40; t++) { + r = net_recv_nb(s, rbuf, (unsigned char)sizeof(rbuf)); + if (r != 0xFE) return r; /* reply (or error) */ + msleep(50); + } + return 0xFF; /* ~2s with no reply */ +} + void main(void) { char *arg; unsigned char s, seq, got = 0, i; @@ -35,7 +48,7 @@ void main(void) { puts("PING "); put_ip(dst); nl(); for (seq = 1; seq <= 4; seq++) { net_send(s, payload, 4); - if (net_recv(s, rbuf, (unsigned char)sizeof(rbuf)) != 0xFF) { + if (wait_reply(s) != 0xFF) { got++; puts(" reply from "); put_ip(dst); puts(" seq="); putu(seq); nl(); } else { diff --git a/c/sock.h b/c/sock.h index 9e4dd40..876e85c 100644 --- a/c/sock.h +++ b/c/sock.h @@ -42,6 +42,12 @@ static unsigned char net_recv(unsigned char s, void *buf, unsigned char max) { _nr.op = 3; _nr.sock = s; _nr.buf = (unsigned char *)buf; _nr.len = max; return sys_net(&_nr); } +/* non-blocking recv: one RX pump -> length, 0xFE if nothing buffered yet, + 0 on TCP EOF. Loop it with msleep() to own your timeout (see ping). */ +static unsigned char net_recv_nb(unsigned char s, void *buf, unsigned char max) { + _nr.op = 8; _nr.sock = s; _nr.buf = (unsigned char *)buf; _nr.len = max; + return sys_net(&_nr); +} /* set the local (source) port - needed so UDP replies demux back to us */ static unsigned char net_bind(unsigned char s, unsigned int port) { _nr.op = 5; _nr.sock = s; -- cgit v1.3.1-sl0p