fuzz: adopt fuzzing (wave 1) + alkcall 0.8.1 bump

Bump the substrate dependency to alkcall 0.8.1 — the bug-fix release
whose fix (duplicate adopt/open no longer destroying the live channel)
is directly relevant to this crate's reverse-path adopt flow.

Adopt fuzzing per docs/research/fuzzing.md, scoped smaller than
alkcall's (the envelope/chunk/demux/manager surfaces are upstream and
now fuzzed there; this crate fuzzes its own named downstream target —
the ADR-003 datagram codec — plus the params/reply parsers):

- fuzz/ workspace per the alkcall pattern: nightly-pinned subtree
  (rust-toolchain.toml), thin fuzz_target! binaries, and a
  stable-toolchain shared crate carrying the invariant logic so the
  committed corpus replays as plain `cargo test` (the fuzz gate in
  the release checklist — no hosted CI, alkcall §7.9 posture).
- Targets (both over already-pub APIs; no #[cfg(fuzzing)] exposure):
  - datagram_codec — DatagramReader::feed + frame_datagram: no-panic,
    infallible decode, size bound, F-2 sentinel layering (empty
    datagram only from a length-0 header at a frame boundary),
    3-byte-slice splitting transparency, re-frame round-trip,
    oversize rejection at the bound, is_mid_datagram framing state,
    and the decoder-state retained-bytes bound.
  - params_parse — serde params/reply parsers + establishment_reason:
    no-panic on raw bytes and bounded structured Values, clean typed
    failure, round-trips, listen: 0 pin, loud/lenient projection-pair
    agreement, pass-through reason extraction model.
- New public diagnostic: DatagramReader::retained_bytes() (decoder-
  state byte count; the fuzz bound asserts against it).
- 96 committed seeds (gen_fuzz_seeds.py) + the campaign-found crash
  input promoted as datagram_codec/seed-900; grown corpora gitignored.
- run-detached.sh: setsid+nohup runner so campaigns never share fate
  with the agent session process tree (fuzzing.md §5).

Campaign findings this session were harness-model defects, not crate
bugs (both invisible to example-based review; the alkcall
"fuzzer as harness-checker" pattern confirmed):

- the F-2 empty-datagram invariant first counted [00 00] pairs in the
  raw stream — a pair inside a payload region is payload, not a
  header; corrected to walk the framing (crash artifact saved).
- establishment_reason is a pass-through extractor of details.reason,
  not a validated table (harness first asserted a closed set).
- is_mid_datagram means a partial datagram, not buffered header bytes
  (a 1-byte header fragment is buffered, not in flight).

Verification: cargo test 135 passed; clippy -D warnings and fmt clean
(main + fuzz/shared); corpus replay green; cargo fuzz build clean;
wasm32-unknown-unknown check clean. Wave-1 campaigns (10-min detached,
fork mode): params_parse 3.14M execs / datagram_codec 827k execs,
0 crashes/OOMs/timeouts; coverage saturated on the codec state space.
This commit is contained in:
glm-5.3-flash committed 2026-09-28 08:09:11 +00:00
1 parent d789031863
commit 57285d23bd
116 files changed
+2662 -4

No files matched your search

Generated
+2 -2
View File
@@ -27,9 +27,9 @@ dependencies = [
[[package]]
name = "alkcall"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8695d47cee5b5a5fe68471f04a505bc257a7e7ed9e64d827de33ff83adf4db12"
checksum = "bf6af1e4af1460480849adf959c972d65deeafc36f4101064ced1ce6d1adfd5b"
dependencies = [
"async-trait",
"bytes",
+6 -2
View File
@@ -9,7 +9,11 @@ repository = "https://git.alk.dev/alkdev/alktunnels"
readme = "README.md"
keywords = ["tunnel", "proxy", "channels", "alkcall", "network"]
categories = ["network-programming", "asynchronous"]
exclude = [".opencode/", "AGENTS.md", "docs/reviews/", "docs/research/", "docs/plans/", "tasks/", "docs/sdd_process.md"]
exclude = [".opencode/", "AGENTS.md", "docs/reviews/", "docs/research/", "docs/plans/", "tasks/", "docs/sdd_process.md", "fuzz/"]
[workspace]
members = ["."]
exclude = ["fuzz"]
[lib]
name = "alktunnels"
@@ -19,7 +23,7 @@ default = []
local = ["tokio/net"]
[dependencies]
alkcall = "0.8.0"
alkcall = "0.8.1"
tokio = { version = "1", default-features = false, features = ["rt", "sync", "io-util", "macros", "time"] }
bytes = "1"
futures = "0.3"
+415
View File
@@ -0,0 +1,415 @@
# Fuzzing alktunnels: Proposal and Plan
**Status:** adopted — wave-1 complete (`datagram_codec` +
`params_parse` implemented, seeds committed, two 10-min campaigns
clean, two harness-model findings fixed — see §7); wave-2 (stateful
two-pump target) deferred, see §4. Campaigns run via the detached
runner (§6) — **never as a foreground child of an agent session** (§5).
**Date:** 2026-09-28
**Upstream precedent:** `/workspace/@alkdev/alkcall/docs/research/fuzzing.md`
(0.8.0 — 0.8.1 campaign; one real finding: duplicate adopt/open destroying
the live channel, fixed in 0.8.1). Tooling, corpus policy, runner, and the
no-hosted-CI posture are inherited from that doc wholesale — this doc does
not re-litigate them; it scopes them to this crate.
---
## 1. Should this crate be fuzzed?
**Yes — but scoped smaller than alkcall's.** The decision follows from
three lines, all pointing the same way:
1. **alkcall's fuzz doc already assigned this to us.** Its §5
"non-surfaces (deliberately)" note ends: *the channels layer carries
opaque `Bytes` and the handler owns sub-stream framing (ADR-035) —
those downstream parsers are downstream crates' fuzz targets.* Our
`wire.rs` datagram codec IS that named downstream target. Fuzzing it
completes alkcall's fuzz scope rather than duplicating it.
2. **We own one hand-rolled parse surface of exactly the covered class.**
`DatagramReader::feed` (`src/wire.rs:100`) is an incremental
length-prefix state machine reassembling `[len: u16 BE][payload]`
frames across arbitrary chunk boundaries — length arithmetic and
boundary handling, the dominant rust-fuzz trophy-case classes. It is
sync, pure, allocation-light, and infallible **by contract** (the
decode direction cannot fail; oversize is rejected at frame time) —
a fuzz target is how that contract is *demonstrated* rather than
believed.
3. **The stateful DoS class applies to us directly.** One pre-fuzz
code-review candidate, the analog of alkcall §6.2-1 (the
early-arrival key-space): `DatagramHalves.pending`
(`src/consumer.rs:78`) queues every datagram decoded from a chunk
beyond the one returned to the caller. A single 16 MiB chunk of
`[00 00]` pairs = ~8.4 M empty datagrams → ~8.4 M `VecDeque`
entries (≈ 400+ MiB) from ONE peer chunk — a ~25–50× memory
amplification riding a bounded channel buffer. Example-based tests
structurally cannot find this; a byte-sequence target with a
pending-bytes assertion will.
**The honest caveat** (mirroring alkcall §1): the highest-value alkcall
targets — envelope framing, chunk header, demux, manager — are upstream
and now fuzzed (0.8.1). Our params parsing is serde + registry-side
jsonschema (upstream's `spec_parse` target covers attacker-shaped
schemas compiling at registration). Expected yield here: datagram-codec
pathologies, the pending-queue bound (§1.3), serde/untagged-enum edge
cases in params, and lifecycle invariants in the two-pump shape. That
is worthwhile, not five-targets-worth of new machinery on day one —
hence the two-wave scope in §4. If the first campaigns find nothing,
that is the successful-negative-result posture alkcall's §1 codified:
"we think the codec is robust" becomes a demonstrated property, and the
targets become regression protection for a wire-stable format
(ADR-003).
## 2. Toolchain (inherited, not re-decided)
Identical to alkcall §4: **cargo-fuzz 0.13.2 + `arbitrary` 1.4.x**,
nightly confined to the `fuzz/` subtree via `fuzz/rust-toolchain.toml`,
the crate itself stays stable at MSRV 1.88. AFL optional/deferred;
bolero deferred (same async-friction argument); libafl/honggfuzz/OSS-Fuzz
not adopted. Sanitizer: `--sanitizer=address` with debug assertions
(cargo-fuzz defaults) — no MSAN (no `unsafe` in this crate).
**Layout (the alkcall pattern, load-bearing):**
```
fuzz/
├── Cargo.toml alktunnels-fuzz (nightly-only bins; own [workspace])
├── rust-toolchain.toml pins nightly for this subtree only
├── fuzz_targets/ thin fuzz_target! wrappers (3-line each)
│ ├── datagram_codec.rs
│ └── params_parse.rs
├── shared/ alktunnels-fuzz-shared — STABLE-toolchain library
│ └── src/… invariant logic + corpus replay (§3)
├── corpus/<target>/ committed hand-made seeds (§3)
├── gen_fuzz_seeds.py deterministic seed generator (quiche pattern)
├── run-detached.sh §6 detached runner (CWD-independent)
└── README.md
```
- **Invariant logic lives in `fuzz/shared/`**, not inline in the target
binaries — the stable-toolchain corpus replay
(`cargo test --manifest-path fuzz/shared/Cargo.toml`) runs the SAME
invariant functions the fuzzer runs, on stable, in the release
verification checklist. This is CI tier-3's deliverable (alkcall
§7.2) minus automation; per alkcall §7.9 this repo has no hosted CI
and will not get one (same gitea posture) — corpus replay as plain
`cargo test` is the fuzz gate.
- **Root `Cargo.toml` needs the explicit `[workspace]` table**
(`members = ["."]`, `exclude = ["fuzz"]`) and `"fuzz/"` on the
publish exclude list — without it cargo auto-discovers `fuzz/shared/`
into the main workspace and the MSRV toolchain tries to build the
nightly-consumed dev-deps (the exact failure alkcall hit).
- **Corpus policy:** commit hand-made seeds, gitignore grown corpora
(quinn/h2 model). Seeds per target: valid frames, truncation at every
short prefix length, `len = 0` / `len = MAX` / `len = MAX+1`, empty
datagrams, batching (two frames per chunk), splitting (one frame per
many chunks), and for params: every substrate value, unknown
substrate, unknown/missing fields, `listen: 0`, malformed reply
shapes, untagged cross-shape targets, deep/invalid JSON.
## 3. Invariants by target
### 3.1 `datagram_codec` (wave 1)
Input: raw `&[u8]` (and in the shared logic, chunk-slice parameter
arbitrary). Drives `DatagramReader::feed` + `frame_datagram`
(`src/wire.rs`). Invariants:
- **no-panic on any byte sequence** (the baseline; the one
`unreachable!` in `feed` is a structural invariant of the state
machine — the target is how it stays true).
- **infallibility**: `feed` never errors (contract — oversize is
rejected at frame time; the decode direction is infallible by
design, `src/wire.rs` docs).
- **datagram-size bound**: every yielded datagram is
`<= MAX_DATAGRAM_LEN` (u16 frame field makes this structural — the
target pins it against future refactors).
- **no partial yields**: a datagram completes only when exactly
`declared` payload bytes are buffered (`is_mid_datagram` observable
consistency); `feed(&[])` never yields anything and never clears
mid-datagram state.
- **round-trip**: `feed(frame_datagram(x)) == [x]` for any x; the
reverse direction `write(feed-parse(x))` re-frames to the same
frame for any well-framed input.
- **F-2 sentinel layering**: `len == 0` is a legal empty datagram,
never EOF; the codec never emits zero-length datagrams for non-empty
frames and never treats an empty datagram as stream end.
- **consumption accounting**: re-framing all consumed bytes and
feeding the byte-level remainder yields the same datagram stream
(splitting a feed at any boundary is transparent).
- **oversize frame rejection**: `frame_datagram` errors iff payload >
`MAX_DATAGRAM_LEN`, echoing the sizes.
- **pending-queue bound (the §1.3 finding-class assertion)**: total
bytes retained across `buf` + `current` + `pending` after a feed is
bounded by the fed chunk size plus the one in-flight frame —
an adversarial peer chunk cannot force unbounded queue growth in
the decoder state. (NOTE: this is the *decoder-state* bound; the
consumer-side `DatagramHalves.pending` backlog between chunk-read
and `recv_datagram` pulls is a session-shape question tracked in
§4/§8 — the wave-2 stateful target, or a code fix if the bound is
judged unacceptable. The fuzzer documents the amplification factor;
the remediation decision is ours.)
### 3.2 `params_parse` (wave 1)
Input: raw bytes → `serde_json` (with alkcall's bounded
`arbitrary_value` approach — depth/width-capped `Value` generation) →
`TunnelParams` / `TunnelDirectParams` / `TunnelForwardedParams` /
`SubstrateAddr` deserialization + `parse_listen_reply` /
`listen_reply_fields` (`src/params.rs`). Invariants:
- **no-panic on any JSON-shaped input** (untagged-enum serde dispatch,
`deny_unknown_fields`, the `positive_u32` pin).
- **clean failure only**: parse failures are `Err`, never panics;
`parse_listen_reply` returns `TunnelError::MalformedReply` on
malformed shapes.
- **round-trip for valid params**: `from_json(to_json(p)) == p` for
constructed params of every substrate.
- **deny-unknown posture**: unknown top-level fields reject;
untagged-variant leniency (extra fields inside a `SubstrateAddr`
variant) is the documented asymmetry — asserted, not "fixed".
- **the `listen: 0` pin**: zero rejects at serde level.
- **projection agreement**: `listen_reply_fields` yields both-`Some`
iff `parse_listen_reply` is `Ok`; it never panics and never refuses
construction (the lenient view projects malformed to both-`None`).
- **establishment-reason surface**: `establishment_reason` never
panics on arbitrary `ChannelOpenError` shapes.
## 4. Scope: two waves
**Wave 1 (this session):** the two targets above. Both drive already-
`pub` APIs — no `#[cfg(fuzzing)]` exposure needed (matching alkcall's
experience where none of five targets needed it).
**Wave 2 (deferred):** a stateful op-sequence target over the two-pump
tunnel shape in the alkcall `manager_routing` style (`#[derive(Arbitrary)]`
op enum; live mux runner; the alkcall harness lessons apply: per-
receiver EOF-sentinel latching, odd/even id ranges on adopt/open).
Drives: `TunnelSession` pump lifecycle + the producer open handlers —
the two-pump shutdown-on-completion contract (AGENTS.md convention 8)
and the EOF-sentinel teardown semantics, with byte-accounting
invariants across `pump_bidi`. Also: a `forwarded_routing` correlation
target if the assembly-side correlation registry (ADR-008 §3, assembly
bookkeeping) grows into this crate. Highest harness cost of anything
here — the wave-1 targets will be saturated long before this one pays
its setup cost, which is exactly why it is deferred, not dropped.
Sequencing mirrors alkcall §7.4: init + wave-1 targets → 10–30 min
campaigns per target via the detached runner → fix anything found →
wave 2 when justified.
## 5. Operational isolation: campaigns never share fate with the agent session
**This is an environment constraint, not a nice-to-have** (upstream
doc §7.6, adopted verbatim as policy here). Agent sessions (opencode)
run fuzzer builds/campaigns through a bash tool that spawns the fuzzer
as a **child of the session's own process tree and cgroup**. A fuzz
run is precisely the workload shape that kills its own host:
- **OOM-killer shared fate**: the target's worst case IS unbounded
allocation. If libFuzzer's soft RSS guard loses the race with the
kernel, the OOM killer fires — and it picks the largest-RSS process
in the cgroup, which can be the opencode server hosting the session.
That is *recoverable* (sessions are recorded in a DB) but hugely
derailing — the session's live environment access dies mid-task.
An OOM in a fuzz target must cost the fuzzer, never the session.
- **Fork bombs / CPU saturation**: `-fork=N` workers; a runaway
campaign starves the session host.
- **Wedged targets**: a deadlock in an async harness would hang a
foreground bash call forever.
Three layers of defense, cheapest first — **all mandatory**:
1. **libFuzzer soft limits (always on)**: `-rss_limit_mb=2048`
`-malloc_limit_mb=2048` make libFuzzer exit cleanly (artifact
recorded) before the kernel gets involved. Note the RSS limit is
*soft* (polls `/proc/self/statm`); a fast huge allocation can beat
it — that is what layers 2–3 are for. Never `ulimit -v` with ASAN
(it reserves terabytes of virtual address space); the ASAN-safe
hard-limit recipe is `-fork=1`.
2. **Fork mode as blast-radius containment (default)**: `-fork=1`
(or a small number) runs each input in a short-lived child — a
crash/timeout/OOM/leak kills only that child; the harness survives,
records the artifact, keeps fuzzing. Also the deadlock answer: the
per-input timeout kills the child, not the session's bash call.
3. **Process detachment from the session tree (MANDATORY for agent-run
campaigns)**: never run fuzzing as a foreground child of the
session. The runner script wraps `cargo fuzz run` in `setsid` +
`nohup` + full redirection to a log file: (a) removes the fuzzer
from the session's controlling terminal and signal relation, (b)
survives the session ending, (c) gives the agent a pollable log +
artifact directory instead of a blocking call. Combined with fork
mode, an OOM-class finding costs one child process.
**The runner** (`fuzz/run-detached.sh`, CWD-independent — resolves its
own repo root):
```bash
#!/usr/bin/env bash
# Detached fuzzing runner for agent sessions: the campaign never runs
# as a foreground child of the session (an OOM in a target must cost
# the fuzzer, never the agent host), and survives the session ending.
set -euo pipefail
target="${1:?usage: run-detached.sh <target> [extra libfuzzer args...]}"
shift
runtime="${FUZZ_RUNTIME_SECS:-600}"
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
log_dir="$root/fuzz/artifacts"
mkdir -p "$log_dir"
log="$log_dir/${target}-$(date -u +%Y%m%d-%H%M%S).log"
cd "$root"
setsid nohup cargo fuzz run "$target" -- \
-fork=1 -rss_limit_mb=2048 -malloc_limit_mb=2048 -timeout=25 \
-max_total_time="$runtime" "$@" \
>"$log" 2>&1 < /dev/null &
echo "pid=$! log=$log"
```
**Agent polling protocol** (never `wait` on the detached process from a
tool call — poll instead):
- `tail -n 50 fuzz/artifacts/<target>-*.log` — campaign progress.
- `ls fuzz/artifacts/` — `crash-*` / `oom-*` / `timeout-*` / `leak-*`
artifacts are the findings.
- `pgrep -f "cargo fuzz run <target>"` — still running?
- One detached campaign per target at a time; log filenames carry the
UTC timestamp.
**Flags worth pinning beyond the runner defaults**: `-max_len=65536`
on the codec target; `-use_value_profile=1`; a JSON token `-dict` for
the params target (alkcall's `json.dict` transfers as-is).
## 6. No hosted CI
Per alkcall §7.9 — the standing policy applies to this repo identically:
no hosted CI will exist; do not add Actions/Gitea-Actions workflow
files. **Corpus replay is the fuzz gate as plain `cargo test`**:
`cargo test --manifest-path fuzz/shared/Cargo.toml` replays every
committed seed through the invariant functions — add it to the release
verification checklist (AGENTS.md). Campaigns run manually via the
detached runner (§6) — e.g. before a release, or after touching
`src/wire.rs`, the consumer data planes, or `src/params.rs`.
## 7. Implementation log
- **2026-09-28 — proposal adopted** (this doc). Wave-1 targets
`datagram_codec` + `params_parse`; wave-2 deferred (§4).
- **2026-09-28 — `alkcall` bumped 0.8.0 → 0.8.1.** Bug-fix release, no
API/wire change; the fix (duplicate adopt/open no longer destroying
the live channel) is directly relevant to this crate's
`TunnelSession::adopt` path — the changelog's "open-op response
replayed / id re-announced" scenario is our reverse path. Verification:
full suite (135 passed), clippy, fmt, wasm check (§8 commands).
- **2026-09-28 — wave-1 implemented.** `fuzz/` workspace laid out per
§2 (nightly-pinned subtree, stable `fuzz/shared` library, runner,
dict, generator); `datagram_codec` + `params_parse` targets over
already-`pub` APIs — no `#[cfg(fuzzing)]` exposure needed. One new
public diagnostic: `DatagramReader::retained_bytes()` (the
decoder-state byte count the §3.1 bound asserts against, in the
`is_mid_datagram` diagnostic style). Seeds committed: 27 +
69 generated (fuzz/gen_fuzz_seeds.py) + 1 campaign-found crash
input promoted to `datagram_codec/seed-900` (see the finding below).
Stable side: corpus replay green, shared crate clippy/fmt clean;
main suite untouched and green; `cargo fuzz build` clean.
- **2026-09-28 — first campaign finding: a HARNESS-model bug, not a
crate bug.** The `datagram_codec` campaign crashed in its first
minute on input `00 2b 01 00 00 05` (`fuzz/artifacts/datagram_codec/
crash-e9ba284e…`, exit 77, fork-mode containment worked as
designed — the harness parent survived and persisted the artifact).
Analysis: the codec is CORRECT — `00 2b` declares a 43-byte
datagram; `01 00 00 05` is its in-flight payload; nothing is
yielded. The invariant that tripped ("an empty datagram must come
only from a [00 00] length header") was mis-modeled: it counted
`00 00` byte pairs anywhere in the RAW stream, but a `00 00` pair
sitting INSIDE a frame's payload region is payload, not a length
header — exactly the same class as alkcall §7.7's probe (the
harness claimed `4 + len` when the prefix counts only the body).
Fix: the count now walks the framing as the decoder does (complete
frames from the start; the walk stops where the decoder would be
stuck mid-frame). The crash input is committed as seed-900 and
replays clean; the campaign relaunched clean.
- **2026-09-28 — second harness finding (caught by corpus replay,
pre-campaign): `establishment_reason` is a pass-through extractor,
not a validated table.** The params.rs doc names the pinned reason
strings, but the upstream implementation (alkcall
`channels/client.rs` `establishment_reason`) extracts
`details.reason` AS-IS whenever the code is `channel:open_failed` —
a made-up reason is surfaced as-is by design, and validation is the
consumer's job. The harness first asserted a closed set of reason
strings and corpus replay tripped it on `made_up_reason` before any
campaign ran. Invariant corrected to assert the extraction shape
(Some iff code == `channel:open_failed` and reason is a string).
- **2026-09-28 — second harness finding (same replay pass):
`is_mid_datagram` means a partial DATAGRAM, not buffered header
bytes.** A dangling 1-byte length prefix at input end is buffered
header state (no frame in flight, `is_mid_datagram == false`);
the harness first asserted `true` for that case. Corrected:
mid-datagram iff the framing walk leaves a remainder ≥ 2 bytes
(a parsed-but-unfinished payload), not `!= 0`.
- **2026-09-28 — wave-1 campaigns run (10-min detached runs, §6 runner;
`-fork=1 -rss_limit_mb=2048 -malloc_limit_mb=2048 -timeout=25`;
codec with `-max_len=65536`, params with `-dict=json.dict
-use_value_profile=1`). Both exited 0.**
- `params_parse` — 3.14M execs (~5.3k exec/s), 33 fork jobs,
`oom/timeout/crash: 0/0/0` throughout. Coverage 2049 edges /
15.6k features; in-memory corpus 69 committed seeds → 3018
entries — the serde/untagged-enum shape space was still expanding
at budget end, so longer campaigns keep paying here.
- `datagram_codec` (post-harness-fix) — 827k execs, 33 fork jobs,
`oom/timeout/crash: 0/0/0` throughout. Coverage saturated at 221
edges (ft 1198) — the 2-byte-header state machine is fully
enumerated, matching alkcall §7.7's `chunk_header` saturation
profile. Exec/s reads low (~400) because each exec replays the
input through a ~35-feed 3-byte-sliced sequence alongside the
whole-input feed; the state space is small and exhausted early.
- The pre-fix `datagram_codec` run (the §7 finding above) crashed at
job 4 and exited 77; fork-mode containment behaved as designed —
the harness survived, persisted the artifact, and the run wrapped
up. That artifact is the promoted seed-900.
- Grown corpora (3018 params entries) were **not** merged into the
committed seeds — per the §2 policy, grown corpora stay
gitignored.
- Operational note for future sessions: `cargo fuzz run` returns
before its last fork-mode children fully exit; a `pkill -f
"cargo fuzz run <target>"` followed immediately by another
`pgrep` of the same pattern can wedge a bash tool call on its own
process match — prefer `pgrep -af` to LIST, kill by explicit pid
from the runner's echoed `pid=`, and never pattern-kill-and-recheck
in one call.
- **NO crate bugs found by wave 1.** The two findings this session
were both harness-model defects (§7 above), each invisible to
example-based review and caught by fuzzing/replay — the alkcall §7.7
"fuzzer as a harness-checker" pattern, confirmed. The §1.3
decoder-state bound held everywhere: `retained_bytes()` never
exceeded fed + one frame on any adversarial input. The session-shape
`DatagramHalves.pending` amplification remains a documented
§1.3/§4 note (wave-2's motivation), not a campaign finding — the
wave-1 targets assert the decoder, not the session pump.
- (progress appended as implementation proceeds — see git log)
## 8. Verification commands
```bash
cargo test # main suite (stable)
cargo test --manifest-path fuzz/shared/Cargo.toml # corpus replay (fuzz gate)
cargo fuzz build # in fuzz/ (nightly, ASAN)
fuzz/run-detached.sh <target> # campaigns (never foreground)
cargo clippy --all-targets -- -D warnings
cargo fmt --check
cargo clippy --manifest-path fuzz/shared/Cargo.toml --all-targets -- -D warnings
cargo fmt --manifest-path fuzz/shared/Cargo.toml --check
cargo check --target wasm32-unknown-unknown # default crate stays wasm-clean
```
## 9. References
- Upstream campaign + operational model (authoritative for tooling,
runner, corpus policy, no-CI posture):
`/workspace/@alkdev/alkcall/docs/research/fuzzing.md`
- alkcall 0.8.1 changelog — the finding our adopt path is exposed to
- This crate: ADR-003 (codec framing), ADR-002 (ALPN), ADR-007/008
(direct/forwarded ops), `docs/architecture/wire.md`
- External: RUSTSEC-2026-0037 (quinn-proto — the maintainers'
fuzzing-coverage statement), rust-fuzz trophy case, cargo-fuzz Rust
Fuzz Book (all linked from the upstream doc's §9)
+9
View File
@@ -0,0 +1,9 @@
target
corpus/*
!corpus/datagram_codec
!corpus/params_parse
# Grown corpus entries (libFuzzer hash-named) are gitignored; only the
# hand-made seed-* files are committed (the quinn/h2 policy).
corpus/*/[0-9a-f]*
artifacts
coverage
+1296
View File
File diff suppressed because it is too large. Load diff
+31
View File
@@ -0,0 +1,31 @@
[package]
name = "alktunnels-fuzz"
version = "0.0.0"
publish = false
edition = "2021"
[package.metadata]
cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.4"
alktunnels-fuzz-shared = { path = "shared" }
[dependencies.alktunnels]
path = ".."
[[bin]]
name = "datagram_codec"
path = "fuzz_targets/datagram_codec.rs"
test = false
doc = false
bench = false
[[bin]]
name = "params_parse"
path = "fuzz_targets/params_parse.rs"
test = false
doc = false
bench = false
[workspace]
+56
View File
@@ -0,0 +1,56 @@
# alktunnels fuzzing
libFuzzer targets for alktunnels' untrusted-input surfaces (see
`docs/research/fuzzing.md` for the full rationale, scope decision, and
campaign plan; the tooling/corpus/runner/no-CI posture is inherited
from alkcall's `docs/research/fuzzing.md`).
## Layout
- `fuzz_targets/` — one binary per target; thin `fuzz_target!` wrappers.
- `shared/` — the invariant logic, as a plain library so normal
`cargo test` (stable toolchain) can replay the committed corpora
through the same invariants (`fuzz/shared/src/*.rs` `#[cfg(test)]`
modules; quinn's CI pattern). The fuzz binaries are nightly-only;
the shared crate is stable-clean.
- `corpus/<target>/` — committed hand-made seeds (regenerate with
`python3 fuzz/gen_fuzz_seeds.py` from the repo root). Grown corpora
and artifacts are gitignored.
- `run-detached.sh` — mandatory runner for agent sessions: wraps
`cargo fuzz run` in `setsid` + `nohup` + log redirection so an OOM
in a target can never take down the agent host (fuzzing.md §5).
- `json.dict` — JSON token dictionary for the params target
(transferred from alkcall).
## Targets
| Target | Drives | Invariants |
|---|---|---|
| `datagram_codec` | `DatagramReader::feed` / `frame_datagram` (`src/wire.rs`) | no-panic; infallible decode; yielded datagrams ≤ `MAX_DATAGRAM_LEN`; F-2 sentinel layering (empty datagram ≠ EOF, only from `[00 00]` headers); splitting transparency (3-byte slices == whole-input feed); re-frame round-trip; oversize rejection exactly at the bound; `is_mid_datagram` tracks framing; decoder-state retained-bytes bound |
| `params_parse` | `TunnelParams` / `TunnelDirectParams` / `TunnelForwardedParams` / `SubstrateAddr` serde parses + `parse_listen_reply` / `listen_reply_fields` / `establishment_reason` (`src/params.rs`) | no-panic on raw bytes and structured Values; clean typed failure only; round-trip for valid params; `listen: 0` pin; loud/lenient projection-pair agreement; pinned establishment-reason table |
## Commands
`cargo fuzz build` and `cargo fuzz run` must be executed with `fuzz/`
(or deeper) as the working directory so rustup selects the pinned
nightly toolchain — the detached runner handles that itself.
```sh
# build (nightly, pinned by rust-toolchain.toml inside fuzz/; run from fuzz/)
cargo fuzz build
# agent sessions: detached campaign (never foreground; CWD-independent)
FUZZ_RUNTIME_SECS=600 fuzz/run-detached.sh datagram_codec -max_len=65536
FUZZ_RUNTIME_SECS=600 fuzz/run-detached.sh params_parse -dict=json.dict -use_value_profile=1
# corpus replay through the invariants (stable toolchain, no nightly)
cargo test --manifest-path fuzz/shared/Cargo.toml
# coverage
cargo fuzz coverage <target>
```
The fuzz workspace is excluded from the main workspace and from the
published package (`exclude` in the root `Cargo.toml`); it pins its own
nightly toolchain via `rust-toolchain.toml` and does not affect the
crate's stable MSRV.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
��bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLine truncated
View File
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@

+1
View File
@@ -0,0 +1 @@
��
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
��
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
4
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
{}
+1
View File
@@ -0,0 +1 @@
{"resource": "postgres-primary", "substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"resource": "postgres-primary", "substrate": "udp"}
+1
View File
@@ -0,0 +1 @@
{"resource": "sock", "substrate": "unix"}
+1
View File
@@ -0,0 +1 @@
{"resource": "r", "substrate": "tcp", "extra": true}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"resource": "r"}
+1
View File
@@ -0,0 +1 @@
{"resource": "", "substrate": ""}
+1
View File
@@ -0,0 +1 @@
{"resource": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"resource": null, "substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"resource": 1, "substrate": 2}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp", "target": {"host": "db.internal", "port": 5432}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "udp", "target": {"host": "10.0.0.7", "port": 53}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "unix", "target": {"path": "/run/x.sock"}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp", "target": {"port": 1}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp", "target": {"host": "h"}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "unix", "target": {"path": "/p", "host": "h"}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp", "target": {"host": "h", "port": 65536}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp", "target": {"host": "h", "port": -1}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp", "target": [1, 2]}
+1
View File
@@ -0,0 +1 @@
{"substrate": "unix", "target": {"host": "h", "port": 1}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp", "target": {}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"target": {"host": "h", "port": 1}}
+1
View File
@@ -0,0 +1 @@
{"listen": 918273, "substrate": "tcp", "peer": {"host": "198.51.100.4", "port": 55231}}
+1
View File
@@ -0,0 +1 @@
{"listen": 918273, "substrate": "unix", "peer": {"path": "/run/x.sock"}}
+1
View File
@@ -0,0 +1 @@
{"listen": 0, "substrate": "tcp", "peer": {"host": "h", "port": 1}}
+1
View File
@@ -0,0 +1 @@
{"listen": -1, "substrate": "tcp", "peer": {"host": "h", "port": 1}}
+1
View File
@@ -0,0 +1 @@
{"listen": 1, "substrate": "tcp", "peer": {"host": "h", "port": 1}, "channel": 7}
+1
View File
@@ -0,0 +1 @@
{"listen": 4294967296, "substrate": "tcp", "peer": {"host": "h", "port": 1}}
+1
View File
@@ -0,0 +1 @@
{"listen": "token", "substrate": "tcp", "peer": {"host": "h", "port": 1}}
+1
View File
@@ -0,0 +1 @@
{"substrate": "tcp", "peer": {"host": "h", "port": 1}}
+1
View File
@@ -0,0 +1 @@
{"listen": 1, "substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"listen": 1, "substrate": "unix", "peer": {"path": "/p", "host": "h"}}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7, "bound": {"host": "203.0.113.9", "port": 42113}, "listen": 918273}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 0}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7, "bound": {"path": "/run/x.sock"}, "listen": 5, "future_field": {"n": true}}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7, "bound": {"port": 1}}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7, "listen": 0}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7, "listen": "token"}
+1
View File
@@ -0,0 +1 @@
{"bound": {"path": "/p"}}
+1
View File
@@ -0,0 +1 @@
{"channel_id": -7}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7.5}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7, "bound": 5}
+1
View File
@@ -0,0 +1 @@
{"channel_id": 7, "listen": 4294967296}
+1
View File
@@ -0,0 +1 @@
{}
+1
View File
@@ -0,0 +1 @@
{"code": "channel:open_failed", "message": "establishment failed", "details": {"reason": "dial_failed"}}
+1
View File
@@ -0,0 +1 @@
{"code": "channel:open_failed", "details": {"reason": "unknown_resource"}}
+1
View File
@@ -0,0 +1 @@
{"code": "channel:open_failed", "details": {"reason": "resource_shortage"}}
+1
View File
@@ -0,0 +1 @@
{"code": "channel:open_failed", "details": {"reason": "handler_error"}}
+1
View File
@@ -0,0 +1 @@
{"code": "channel:open_failed", "details": {"reason": "timeout"}}
+1
View File
@@ -0,0 +1 @@
{"code": "channel:open_failed", "details": {"reason": "made_up_reason"}}
+1
View File
@@ -0,0 +1 @@
{"code": "forbidden"}
+1
View File
@@ -0,0 +1 @@
{"code": "channel:too_many_channels", "details": {"reason": "dial_failed"}}
+1
View File
@@ -0,0 +1 @@
{"details": null}
+1
View File
@@ -0,0 +1 @@
{"resource": ["a" * 1], "substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"resource": {"nested": {"deep": [1, 2, {"x": [1, [2, [3]]]}]}}, "substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"resource": "ÿþ", "substrate": "tcp"}
+1
View File
@@ -0,0 +1 @@
{"resource": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxLine truncated
+1
View File
@@ -0,0 +1 @@
{"substrate": {"enum": "tcp"}}
+1
View File
@@ -0,0 +1 @@
[{"resource": "r", "substrate": "tcp"}]
+1
View File
@@ -0,0 +1 @@
"just a string"
+1
View File
@@ -0,0 +1 @@
12345
+1
View File
@@ -0,0 +1 @@
null
Loaded 100 of 116 files, more files were not shown because too many files have changed in this diff. Show more