You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e81721e
Browse filesBrowse the repository at this point in the historyBrowse files
Stop one refused flow from killing every flow beside it
Two Mux defects, both found by repairing a harness that had been reporting
success while measuring nothing, and both invisible to any test that opens one
flow at a time.
The first is a poll interval used as a protocol deadline. `readStream` answers
three things with three values, and 0 means "nothing arrived in the last 250 ms"
— not a verdict. `open` read it as one, so a Portal that answered a SYN slower
than a quarter of a second was reported as "the Portal did not answer on this
stream — authentication most likely failed", which is both wrong and the most
misleading sentence available. A dedicated lane gives the identical protocol
step fifteen seconds. The carrier now gives it the same, because how long a
Portal takes to dial a target is a property of the target rather than of the
carrier the request arrived over.
The second is worse and is a conformance matter. A rejected flow was reset. But
the rejection *is* the teardown — the Portal answers and forgets the stream in
the same breath — and section 3 says STREAM data for an unknown flow is a
*carrier* error. So the RST did not tidy up one flow, it closed the connection
and failed every other flow multiplexed onto it. The dedicated lane has always
simply closed a rejected lane, so this is also the two carriers agreeing again.
The trigger is ordinary and permanent: Android's Private DNS probes port 853 the
moment a tunnel comes up, the Portal answers DIAL_FAILED, and whichever shard
that probe landed on lost its other flows half a second later. Measured at one
to four of sixteen concurrent fetches coming back empty, intermittently. After
both fixes, fourteen further runs produced one short response rather than three
in two runs of three — better, and not yet zero, which is recorded rather than
rounded down.
`reset` had no other caller and is gone. This client now sends no RST at all,
which is a decision: every other way a flow ends here is a half-close, and FIN
is what that is. Reading one stays implemented and tested, because the Portal
may send one.
The harness half is the reason any of this was visible. e2e-fakeip.sh drove
three instrumentation classes that had been disabled two runs earlier for
proving nothing — so it ran, skipped everything, and its shard arithmetic
compared 0 connections against 0 flows and passed. It now drives the fetch from
the shell, where the traffic actually enters the TUN, over both address
families; the concurrency measurement opens sixteen `nc` processes at once and
counts what the Portal saw; and zero flows now fails loudly instead of
satisfying every comparison. e2e-tunnel-fetch.sh gained a family switch, which
is what proves the v6 half of the fake-IP layer with nothing but the device: the
name is resolved through the tunnel's own resolver into fc00::/96, the packet
takes the ::/0 route, and the Portal still dials the name.
Measured on the emulator: 20,971,762 bytes over a synthetic IPv6 address, the
Portal's counters moving by the same amount, digest matching; and sixteen
concurrent flows over four connections at mux=1, sixteen over sixteen at mux=0.
Copy file name to clipboardExpand all lines: conformance/scripts/device-acceptance.sh
+29-9Lines changed: 29 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -145,17 +145,37 @@ else
145
145
fi
146
146
fi
147
147
148
-
head2 "3c. An IPv6 destination through the tunnel"
149
-
# Needs an origin the Portal can reach over IPv6. The docker origin
150
-
# e2e-fakeip.sh starts is v4-only, so this is supplied or it is a note --
151
-
# never a silent pass.
152
-
if [ -z"${NOWHERE_E2E_TARGET6:-}" ];then
153
-
note "no NOWHERE_E2E_TARGET6 given, so nothing checked that a v6 destination is carried. Set it to [addr]:port of an HTTP origin reachable over IPv6 from the Portal, serving /blob.bin with X-Content-Sha256."
# The v6 half of the fake-IP layer, proved with nothing but this device: the
150
+
# name is resolved through the tunnel's own resolver, which answers AAAA with an
151
+
# address out of fc00::/96; the packet takes the ::/0 route into the TUN;
152
+
# lwIP's IPv6 side carries it; the address is resolved back to the name; and the
153
+
# Portal dials that name over whichever family its own network prefers. No
154
+
# IPv6 connectivity is needed anywhere outside this device.
155
+
#
156
+
# It needs a NAME rather than an address, because a synthetic address exists
157
+
# only as the answer to a query. NOWHERE_E2E_ORIGIN is that name; without one
158
+
# this says so rather than passing.
159
+
if [ -z"${NOWHERE_E2E_ORIGIN:-}" ];then
160
+
note "no NOWHERE_E2E_ORIGIN given, so the v6 half of the fake-IP layer was not exercised. Set it to name:port of an origin only the Portal can resolve — e2e-fakeip.sh starts one at origin.somewhere.test:8080."
miss "synthetic IPv6: $(tail -3 /tmp/somewhere-fetch-v6.log | tr '\n''')"
167
+
fi
168
+
169
+
head2 "3d. A real IPv6 destination through the tunnel"
170
+
# The other half, which this device cannot supply: an origin the Portal reaches
171
+
# over IPv6. Supplied or a note, never a silent pass.
172
+
if [ -z"${NOWHERE_E2E_TARGET6:-}" ];then
173
+
note "no NOWHERE_E2E_TARGET6 given, so nothing checked that a genuinely IPv6 destination is carried. Set it to [addr]:port of an HTTP origin reachable over IPv6 from the Portal, serving /blob.bin with X-Content-Sha256."
0 commit comments