diff --git a/Cargo.lock b/Cargo.lock index 18f49bdf..8d8e0734 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + [[package]] name = "android_log-sys" version = "0.3.2" @@ -147,7 +156,7 @@ version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "libloading", + "libloading 0.8.9", ] [[package]] @@ -167,9 +176,9 @@ dependencies = [ [[package]] name = "asn1-rs" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -177,15 +186,15 @@ dependencies = [ "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror 1.0.69", + "thiserror 2.0.20", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", @@ -505,7 +514,7 @@ dependencies = [ "bitflags 2.13.1", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools", "log", "prettyplease", "proc-macro2", @@ -522,7 +531,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec", + "bit-vec 0.8.0", ] [[package]] @@ -531,6 +540,15 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -797,7 +815,7 @@ checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" dependencies = [ "glob", "libc", - "libloading", + "libloading 0.8.9", ] [[package]] @@ -951,23 +969,22 @@ dependencies = [ [[package]] name = "criterion" -version = "0.5.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" dependencies = [ + "alloca", "anes", "cast", "ciborium", "clap", "criterion-plot", - "is-terminal", - "itertools 0.10.5", + "itertools", "num-traits", - "once_cell", "oorandom", + "page_size", "regex", "serde", - "serde_derive", "serde_json", "tinytemplate", "walkdir", @@ -975,12 +992,12 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" dependencies = [ "cast", - "itertools 0.10.5", + "itertools", ] [[package]] @@ -1068,7 +1085,7 @@ version = "0.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17200eb07e7d85a243aa1bf4569a7aa998385ba98d14833973a817a63cc86e92" dependencies = [ - "libloading", + "libloading 0.8.9", ] [[package]] @@ -1161,9 +1178,9 @@ dependencies = [ [[package]] name = "der-parser" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" dependencies = [ "asn1-rs", "displaydoc", @@ -2144,16 +2161,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "if-addrs" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b2eeee38fef3aa9b4cc5f1beea8a2444fc00e7377cafae396de3f5c2065e24" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "if-addrs" version = "0.15.0" @@ -2203,32 +2210,12 @@ dependencies = [ "hybrid-array", ] -[[package]] -name = "is-terminal" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -2366,7 +2353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading", + "libloading 0.8.9", ] [[package]] @@ -2446,6 +2433,16 @@ dependencies = [ "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "libloading" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" +dependencies = [ + "cfg-if", + "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libm" version = "0.2.16" @@ -2560,13 +2557,13 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "mdns-sd" -version = "0.20.3" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86dbb9f00c8c367f75ed3a775d3eb31d0375a72f58275ef64a1bc53c255a2ce2" +checksum = "ba97b4c886eea3c2823388120d92063c011ac866919ffc4200a0e4b1642a54a5" dependencies = [ "fastrand", "flume", - "if-addrs 0.15.0", + "if-addrs", "log", "mio", "socket-pktinfo", @@ -2842,9 +2839,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" dependencies = [ "asn1-rs", ] @@ -2913,6 +2910,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "pango" version = "0.22.8" @@ -3039,7 +3046,7 @@ dependencies = [ "ash", "async-channel", "libc", - "libloading", + "libloading 0.9.0", "mdns-sd", "openh264", "opus", @@ -3124,7 +3131,7 @@ dependencies = [ "ash", "ffmpeg-next", "libc", - "libloading", + "libloading 0.9.0", "libvpl-sys", "nvidia-video-codec-sdk", "openh264", @@ -3237,7 +3244,7 @@ version = "0.27.0" dependencies = [ "anyhow", "aws-lc-rs", - "base64 0.22.1", + "base64 0.23.1", "serde", "serde_json", "ureq", @@ -3315,7 +3322,7 @@ dependencies = [ "ash", "khronos-egl", "libc", - "libloading", + "libloading 0.9.0", "serde", "serde_json", "tempfile", @@ -3507,7 +3514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set", - "bit-vec", + "bit-vec 0.8.0", "bitflags 2.13.1", "num-traits", "rand 0.9.5", @@ -3606,7 +3613,7 @@ dependencies = [ "criterion", "fec-rs", "hmac 0.13.0", - "if-addrs 0.13.4", + "if-addrs", "libc", "opus", "proptest", @@ -3648,7 +3655,7 @@ dependencies = [ "aws-lc-rs", "axum", "axum-server", - "base64 0.22.1", + "base64 0.23.1", "cbc", "futures-util", "hex", @@ -3656,9 +3663,9 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "if-addrs 0.13.4", + "if-addrs", "libc", - "libloading", + "libloading 0.9.0", "log", "mac_address", "mdns-sd", @@ -3679,7 +3686,7 @@ dependencies = [ "pipewire", "punktfunk-core", "quinn", - "rand 0.8.7", + "rand 0.9.5", "rcgen", "roxmltree", "rsa", @@ -3855,7 +3862,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ - "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -4001,14 +4007,15 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "091e7a8e7d86e6feb87a27ce8e2cba29d49eff9507afeebefab7eeb2ca667fb4" dependencies = [ "aws-lc-rs", "pem", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -6152,18 +6159,19 @@ checksum = "acf4d1bc32aa46eec18caa634ec3cf4c05bfa151f12b93b510b15190f69a1ca8" [[package]] name = "x509-parser" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", + "aws-lc-rs", "data-encoding", "der-parser", "lazy_static", "nom 7.1.3", "oid-registry", "rusticata-macros", - "thiserror 1.0.69", + "thiserror 2.0.20", "time", ] @@ -6196,10 +6204,11 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec 0.9.1", "time", ] diff --git a/clients/android/native/Cargo.toml b/clients/android/native/Cargo.toml index e6b629a6..d3e82609 100644 --- a/clients/android/native/Cargo.toml +++ b/clients/android/native/Cargo.toml @@ -37,7 +37,7 @@ log = "0.4" # `NsdManager` system daemon with one tested browse path. Pure Rust (socket2/if-addrs/mio), so it # cross-compiles to the Android targets AND builds on the host (the JNI seam links into # `cargo build --workspace`). Kotlin keeps only the Wi-Fi `MulticastLock` + permission UX. -mdns-sd = "0.20" +mdns-sd = "0.21" # Android-only deps. Gated so `cargo build --workspace` on the Linux/macOS dev boxes + CI still # compiles this crate (as a host cdylib) — the Android-framework glue (logging, AMediaCodec + AAudio diff --git a/clients/probe/Cargo.toml b/clients/probe/Cargo.toml index bd8b7a0e..7f14a802 100644 --- a/clients/probe/Cargo.toml +++ b/clients/probe/Cargo.toml @@ -24,7 +24,7 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } # LAN host discovery (`--discover`): browse the native `_punktfunk._udp` mDNS service the host # advertises (same crate/version the host advertises with). -mdns-sd = "0.20" +mdns-sd = "0.21" # Opus: multistream DECODE of the host's audio plane (the surround validator) + `--mic-test`'s # encoder. libopus is already in the graph via `punktfunk-core`'s quic feature; this exposes the # name directly. Cross-platform (cmake-vendored), so the probe builds + validates everywhere. diff --git a/clients/windows/Cargo.toml b/clients/windows/Cargo.toml index 55bf7f05..762ede90 100644 --- a/clients/windows/Cargo.toml +++ b/clients/windows/Cargo.toml @@ -89,7 +89,7 @@ windows = { git = "https://github.com/microsoft/windows-rs", rev = "acb5a1a74410 # (see the `gamepad` field in app/); the spawned punktfunk-session does the actual forwarding. SDL3 # itself (built from source via the bundled CMake on Windows) is pulled transitively by # pf-client-core with the same `build-from-source,hidapi` features, so it is not a direct dep here. -mdns-sd = "0.20" +mdns-sd = "0.21" async-channel = "2" serde_json = "1" tracing = "0.1" diff --git a/crates/pf-client-core/Cargo.toml b/crates/pf-client-core/Cargo.toml index 80640b7a..8df23866 100644 --- a/crates/pf-client-core/Cargo.toml +++ b/crates/pf-client-core/Cargo.toml @@ -89,7 +89,7 @@ libc = "0.2" # with libavcodec (`pf-encode`); nothing in this crate does. opus = "0.3" -mdns-sd = "0.20" +mdns-sd = "0.21" # PyroWave decode (the opt-in wired-LAN wavelet codec, design/pyrowave-codec-plan.md # §4.5) — pure Vulkan compute on the presenter's shared device, so it builds wherever the @@ -141,7 +141,7 @@ pf-vaadec = { path = "../pf-vaadec" } # libva itself is dlopen'd, never linked (see `video_vaapi_native`'s module docs): the # container can then compile and clippy the whole rung without `libva-dev`, and a machine # without a VAAPI runtime gets a clean refusal instead of a packaging dependency. -libloading = "0.8" +libloading = "0.9" # The gamescope overlay watcher (`overlay_focus`): read two CARDINAL properties off a # gamescope root window and block on PropertyNotify. `default-features = false` keeps the # pure-Rust `RustConnection` — no libxcb link, so no new C dependency on any client package diff --git a/crates/pf-encode/Cargo.toml b/crates/pf-encode/Cargo.toml index 4313fa1f..8c03a5f0 100644 --- a/crates/pf-encode/Cargo.toml +++ b/crates/pf-encode/Cargo.toml @@ -54,7 +54,7 @@ libc = "0.2" # the dep stays unconditional to mirror the host's Linux target — unused-but-declared is harmless). ash = "0.38" # `libnvidia-encode.so.1` is dlopen'd at runtime for the direct-SDK NVENC/CUDA backend. -libloading = "0.8" +libloading = "0.9" # Direct-SDK NVENC (raw `sys::nvEncodeAPI` types; entry points resolved at runtime). `ci-check` = # vendored bindings, no CUDA toolkit at build. nvidia-video-codec-sdk = { version = "0.4", features = ["ci-check"], optional = true } @@ -67,7 +67,7 @@ nvidia-video-codec-sdk = { version = "0.4", features = ["ci-check"], optional = # AMD (AMF) + Intel (QSV) hardware encode via libavcodec (behind `amf-qsv`; link-imports FFmpeg). ffmpeg-next = { version = "9", optional = true } # `libnvidia-encode`/`nvEncodeAPI64.dll` resolved at runtime; the NVENC status→cause table dlopen. -libloading = "0.8" +libloading = "0.9" # Native Intel QSV (VPL): vendored static MIT dispatcher + bindgen'd C API, only under `qsv`. libvpl-sys = { path = "../libvpl-sys", optional = true } # PyroWave (opt-in wired-LAN wavelet codec) — vendored codec + bindgen'd C API, only under diff --git a/crates/pf-update-check/Cargo.toml b/crates/pf-update-check/Cargo.toml index 90df57d7..525e2f34 100644 --- a/crates/pf-update-check/Cargo.toml +++ b/crates/pf-update-check/Cargo.toml @@ -33,7 +33,9 @@ serde_json = "1" # runner. Naming it here makes the crate build standalone instead of relying on who else is in # the selection. aws-lc-rs = { version = "1", features = ["prebuilt-nasm"] } -base64 = "0.22" +# Feature selection matched to ureq's (and punktfunk-host's) on purpose — 0.23's default-on +# `simd-unsafe` engine stays off, so a currency bump doesn't quietly add unsafe SIMD to the tree. +base64 = { version = "0.23", default-features = false, features = ["std"] } # Small, sync, bundles webpki roots — no system cert store dependency, which matters on the # Deck (Decky's embedded Python has no usable roots either; see clients/decky/main.py). # ⚠ `rustls-no-provider`, NEVER the default `rustls` feature — that one pulls `_ring`, which would diff --git a/crates/pf-zerocopy/Cargo.toml b/crates/pf-zerocopy/Cargo.toml index 16df1add..d9014114 100644 --- a/crates/pf-zerocopy/Cargo.toml +++ b/crates/pf-zerocopy/Cargo.toml @@ -20,7 +20,7 @@ tracing = "0.1" libc = "0.2" # `libcuda.so.1` is dlopen'd at runtime (NOT link-time) so one Linux binary runs on NVIDIA # (zero-copy via CUDA) AND on AMD/Intel (VAAPI, no NVIDIA driver present) — see `cuda::ffi`. -libloading = "0.8" +libloading = "0.9" # EGL imports the PipeWire dmabuf, CUDA maps it (`dynamic` = load the NVIDIA libEGL at runtime). khronos-egl = { version = "6", features = ["dynamic"] } # Vulkan bridge for LINEAR dmabufs (gamescope): VK_EXT_external_memory_dma_buf import, diff --git a/crates/punktfunk-core/Cargo.toml b/crates/punktfunk-core/Cargo.toml index f8e9cc6d..5d3805bc 100644 --- a/crates/punktfunk-core/Cargo.toml +++ b/crates/punktfunk-core/Cargo.toml @@ -55,7 +55,12 @@ zeroize = "1" # Interface enumeration for Wake-on-LAN: computes each NIC's subnet-directed broadcast so a # magic packet reaches the host's L2 segment on multi-homed clients (VPN/docker/multiple LANs), # not just the default route. Tiny, cross-platform (getifaddrs / GetAdaptersAddresses), no cmake. -if-addrs = "0.13" +# `link-local` is named EXPLICITLY, not inherited. mdns-sd declares if-addrs with it, so any build +# containing both (every host and every client) unifies it on regardless — and a crate whose +# enumeration silently changes depending on who else is in the selection is the worst of both. On +# means fe80::/169.254 interfaces are enumerated too, which for WoL is the behaviour we want: a NIC +# is wake-capable whether or not it currently holds a routable address. +if-addrs = { version = "0.15", features = ["link-local"] } # Crypto backend is aws-lc-rs, and rustls/quinn/rcgen must all name it: they each select a # backend independently, so one dissenter pulls a SECOND crypto stack in via feature unification. @@ -72,7 +77,7 @@ quinn = { version = "0.11", optional = true, default-features = false, features ] } rustls = { version = "0.23", optional = true, default-features = false, features = ["aws_lc_rs", "prefer-post-quantum", "std"] } # `generate_simple_self_signed` is backend-agnostic, so the swap is transparent here. -rcgen = { version = "0.13", optional = true, default-features = false, features = ["aws_lc_rs", "pem"] } +rcgen = { version = "0.14", optional = true, default-features = false, features = ["aws_lc_rs", "pem"] } rustls-pki-types = { version = "1", optional = true } # `rustls-no-provider`, NOT the default `rustls` feature — ureq's `rustls` feature body pulls # `_ring`, which would drag the whole ring backend back into a tree that has deliberately moved to @@ -121,7 +126,7 @@ windows-sys = { version = "0.59", features = [ proptest = "1" # Tier-1 microbenchmarks (benches/pipeline.rs). default-features off → no plotters/HTML (headless # CI just needs the measurement + target/criterion/**/estimates.json for the regression compare). -criterion = { version = "0.5", default-features = false, features = ["cargo_bench_support"] } +criterion = { version = "0.8", default-features = false, features = ["cargo_bench_support"] } [[bench]] name = "pipeline" diff --git a/crates/punktfunk-core/benches/pipeline.rs b/crates/punktfunk-core/benches/pipeline.rs index f875f61b..e4276fa7 100644 --- a/crates/punktfunk-core/benches/pipeline.rs +++ b/crates/punktfunk-core/benches/pipeline.rs @@ -10,11 +10,15 @@ //! The GPU capture/NVENC encode path is deliberately out of scope here (no GPU in CI) — that's the //! Tier-3 stream benchmark on a self-hosted GPU runner. Run locally with `cargo bench -p punktfunk-core`. -use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use punktfunk_core::config::{Config, FecConfig, FecScheme, ProtocolPhase, Role}; use punktfunk_core::crypto::{SessionCrypto, SessionKey}; use punktfunk_core::session::Session; use punktfunk_core::transport::loopback_pair; +// NOT `criterion::black_box`: it still exists in 0.8 but is deprecated, and now just forwards to +// this one. Benches compile under `--all-targets -D warnings`, so importing criterion's would fail +// the lint gate rather than merely warn. +use std::hint::black_box; const TAG_LEN: usize = 16; // AEAD authentication tag (GCM and Poly1305 share the size) const SHARD: usize = punktfunk_core::config::mtu1500_shard_payload(); // one MTU-safe data shard diff --git a/crates/punktfunk-core/src/quic/endpoint.rs b/crates/punktfunk-core/src/quic/endpoint.rs index def498e4..3f605abd 100644 --- a/crates/punktfunk-core/src/quic/endpoint.rs +++ b/crates/punktfunk-core/src/quic/endpoint.rs @@ -131,7 +131,7 @@ pub fn server(addr: std::net::SocketAddr) -> anyhow_result::Result anyhow_result::Result<(String, String)> { let cert = rcgen::generate_simple_self_signed(vec!["punktfunk-client".into()]) .map_err(|e| anyhow_result::Error::msg(format!("self-signed cert: {e}")))?; - Ok((cert.cert.pem(), cert.key_pair.serialize_pem())) + Ok((cert.cert.pem(), cert.signing_key.serialize_pem())) } /// Fingerprint of the client certificate a connection presented (host side), if any. diff --git a/crates/punktfunk-host/Cargo.toml b/crates/punktfunk-host/Cargo.toml index 0d142a08..bb0de840 100644 --- a/crates/punktfunk-host/Cargo.toml +++ b/crates/punktfunk-host/Cargo.toml @@ -68,36 +68,59 @@ tracing-log = "0.2" # tracing-log bridge with `ignore_crate("wasapi")`). Already in the tree transitively. log = "0.4" axum = "0.8" -mdns-sd = "0.20" +mdns-sd = "0.21" # Wake-on-LAN: report the host's wake-capable NIC MAC(s) to clients via the mDNS `mac` TXT record. # `mac_address` reads a NIC's hardware address; `if-addrs` maps the routed IP to its interface name. mac_address = "1" -if-addrs = "0.13" +# `link-local` named explicitly for the same reason as in punktfunk-core: mdns-sd (right above) +# turns it on by unification anyway, and `wake_macs` should not enumerate a different set of NICs +# depending on which other crates share the build. +if-addrs = { version = "0.15", features = ["link-local"] } tokio = { version = "1", features = ["full"] } # GameStream-only (behind the `gamestream` feature): the Moonlight RSA-2048 identity generator + # pairing signer (cert.rs, pairing.rs) and the legacy-client-cert leniency verifier (tls.rs). # The native planes use the P-256 identity (src/identity.rs) and never touch this crate — so a # native-only build also sheds the accepted Marvin advisory (RUSTSEC-2023-0071, .cargo/audit.toml). # -# `features = ["sha2"]` re-exports the `sha2` that `rsa`'s OWN trait generation speaks. `rsa` 0.9 -# is built on `digest 0.10`, and the rest of this crate is on the `digest 0.11` wave (sha2 0.11 / -# hmac 0.13) — so the digest types that appear as `rsa` TYPE PARAMETERS (`SigningKey` in -# cert.rs, `VerifyingKey<_>` in pairing.rs and tls.rs) must come from `rsa::sha2`, not from the -# `sha2` below. Everything else (plain hashing, HMAC) uses the 0.11 one. Collapsing the two needs -# `rsa` 0.10, which is still release-candidate only — not something the Moonlight pairing -# ceremony should ride. -rsa = { version = "0.9", optional = true, features = ["sha2"] } +# TWO independent `rsa` features, arriving from two different bumps in this wave — both are load- +# bearing, and taking either side alone breaks the build: +# +# `sha2` re-exports the `sha2` that `rsa`'s OWN trait generation speaks. `rsa` 0.9 is built on +# `digest 0.10`, and the rest of this crate is on the `digest 0.11` wave (sha2 0.11 / hmac 0.13) — +# so the digest types that appear as `rsa` TYPE PARAMETERS (`SigningKey` in cert.rs, +# `VerifyingKey<_>` in pairing.rs and tls.rs) must come from `rsa::sha2`, not from the `sha2` +# below. Everything else (plain hashing, HMAC) uses the 0.11 one. Collapsing the two needs `rsa` +# 0.10, which is still release-candidate only — not something the Moonlight pairing ceremony +# should ride. +# +# `getrandom` is NOT one of rsa's defaults; we ask for it because `RsaPrivateKey::new` wants an +# rng implementing rand_core **0.6**'s traits, and since our own `rand` moved to 0.9 no rng we +# hold satisfies that bound any more. The feature exposes `rsa::rand_core::OsRng`, which does — +# see the keygen in gamestream/cert.rs. Getting it from rsa's own re-export is what keeps the two +# rand_core majors from being something this crate has to name. +rsa = { version = "0.9", optional = true, features = ["sha2", "getrandom"] } # `oid` is default-on in sha2 0.11 and was only ever needed for the RSA signer, which now takes # its digest from `rsa::sha2` (above). sha2 = "0.11" aes = "0.9" aes-gcm = "0.11" cbc = { version = "0.2", features = ["alloc"] } -rand = "0.8" +# 0.9, matching punktfunk-core and pf-client-core — the host was the last 0.8 holdout, and that +# was drift, not a pin. NOTE this does NOT take rand 0.8 out of the gamestream build: `rsa` pulls +# it transitively through `num-bigint-dig`, so 0.8 only disappears from the native-only host +# (`--no-default-features`, where `rsa` is absent). What it does buy everywhere is that OUR calls +# all speak one rand major. +rand = "0.9" hex = "0.4" # Cover-art delivery in the game library: encode Lutris's local JPEGs into `data:` URLs and decode # the Epic launcher's base64 `catcache.bin`. Cross-platform (Linux Lutris art + Windows Epic art). -base64 = "0.22" +# `default-features = false` + `std` deliberately: 0.23 added a default-ON `simd-unsafe` feature +# (hand-written AVX2/NEON engines). ureq already declares base64 exactly this way, so taking the +# defaults here would unify the feature ON and pull that unsafe code into every build as a side +# effect of a version bump. Turning it on is a perf decision worth making on purpose, with a +# measurement — not one to inherit silently. `std` covers everything we call (`Engine::encode`, +# `decode` to a `Vec`). +base64 = { version = "0.23", default-features = false, features = ["std"] } # Blocking HTTP for the library cover-art warmer (no-auth GOG api.gog.com + Xbox displaycatalog), # run on a background thread off the hot path. `ureq` is small + sync (no tokio here) and bundles # webpki roots (no system cert dependency). Cross-platform so the fetch/parse code is compiled + @@ -109,8 +132,12 @@ ureq = { version = "3", default-features = false, features = [ "rustls-webpki-roots", "gzip", ] } -rcgen = { version = "0.13", default-features = false, features = ["aws_lc_rs", "pem"] } -x509-parser = "0.16" +rcgen = { version = "0.14", default-features = false, features = ["aws_lc_rs", "pem"] } +# ⚠ Do not float this back below 0.18. 0.16 was the LAST crate pulling `thiserror` 1.0 into the +# host graph (via asn1-rs 0.6 / der-parser 9 / oid-registry 0.7); 0.18 moves that chain to asn1-rs +# 0.7 + thiserror 2, so the host now links exactly one thiserror major. `cargo tree -p +# punktfunk-host -i thiserror@1` must keep reporting no match. +x509-parser = "0.18" # Only used for the plain-HTTP nvhttp listener (`bind().serve()`); HTTPS/mTLS is hand-rolled over # tokio-rustls (axum-server can't surface the peer cert), so we do NOT enable `tls-rustls` — that # feature is what pulled the unmaintained `rustls-pemfile` (security-review dep hygiene). @@ -198,7 +225,7 @@ pipewire = "0.9" rusqlite = { version = "0.40", features = ["bundled"] } # `libcuda.so.1` is dlopen'd at runtime (NOT link-time) so one Linux binary runs on NVIDIA # (zero-copy via CUDA) AND on AMD/Intel (VAAPI, no NVIDIA driver present) — see `zerocopy::cuda`. -libloading = "0.8" +libloading = "0.9" [target.'cfg(target_os = "windows")'.dependencies] # Windows host backends. `windows` covers the Win32/CCD APIs the SudoVDA virtual-display backend diff --git a/crates/punktfunk-host/src/gamestream/cert.rs b/crates/punktfunk-host/src/gamestream/cert.rs index 3ad65cb7..9204d331 100644 --- a/crates/punktfunk-host/src/gamestream/cert.rs +++ b/crates/punktfunk-host/src/gamestream/cert.rs @@ -88,8 +88,14 @@ fn generate() -> Result<(String, String)> { // // This path runs ONLY when no cert exists yet — a fresh install — so an upgraded box never // re-executes it. - let mut rng = rand::thread_rng(); - let priv_key = RsaPrivateKey::new(&mut rng, 2048).context("generate RSA-2048 host key")?; + // + // The rng comes from `rsa`'s OWN rand_core re-export, not from our `rand`. `RsaPrivateKey::new` + // is bounded on rand_core **0.6**'s `CryptoRngCore`, and since the host moved to rand 0.9 its + // `ThreadRng` implements rand_core 0.9's traits instead — a different trait of the same name, + // so it no longer satisfies the bound. `rsa::rand_core::OsRng` is the OS CSPRNG under the + // exact traits `rsa` compiled against, which keeps the two rand_core majors from meeting. + let priv_key = RsaPrivateKey::new(&mut rsa::rand_core::OsRng, 2048) + .context("generate RSA-2048 host key")?; let key_pem = priv_key .to_pkcs8_pem(LineEnding::LF) .context("encode host key as PKCS#8 PEM")? diff --git a/crates/punktfunk-host/src/gamestream/crypto.rs b/crates/punktfunk-host/src/gamestream/crypto.rs index d8e31446..5fc6a92d 100644 --- a/crates/punktfunk-host/src/gamestream/crypto.rs +++ b/crates/punktfunk-host/src/gamestream/crypto.rs @@ -11,7 +11,7 @@ use sha2::{Digest, Sha256}; /// `n` cryptographically-random bytes. pub fn random() -> [u8; N] { let mut b = [0u8; N]; - rand::thread_rng().fill_bytes(&mut b); + rand::rng().fill_bytes(&mut b); b } diff --git a/crates/punktfunk-host/src/mgmt_token.rs b/crates/punktfunk-host/src/mgmt_token.rs index ee1c6435..fdf2b098 100644 --- a/crates/punktfunk-host/src/mgmt_token.rs +++ b/crates/punktfunk-host/src/mgmt_token.rs @@ -59,7 +59,7 @@ fn load_or_generate_impl(env_var: &str, file: &str) -> Result { } } let mut buf = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut buf); + rand::rng().fill_bytes(&mut buf); let token = hex::encode(buf); write_token(&path, env_var, &token)?; tracing::info!(path = %path.display(), "generated and persisted API token (owner-only)"); diff --git a/crates/punktfunk-host/src/native/handshake.rs b/crates/punktfunk-host/src/native/handshake.rs index 60afb95b..afb53a78 100644 --- a/crates/punktfunk-host/src/native/handshake.rs +++ b/crates/punktfunk-host/src/native/handshake.rs @@ -502,14 +502,14 @@ pub(super) async fn negotiate( let shard_payload = wire_mtu::negotiated_shard_payload(conn, hello.max_shard_payload).await; let mut key = [0u8; 16]; - rand::thread_rng().fill_bytes(&mut key); + rand::rng().fill_bytes(&mut key); // Fresh per-session salt alongside the fresh key. GCM nonce uniqueness only *requires* one // of the two to be unique per session (the nonce is salt || sequence under the session // key), but a constant salt would make a key-reuse bug catastrophic instead of merely // wrong — this keeps the second line of defense real. Negotiated via Welcome, so clients // just follow. let mut salt = [0u8; 4]; - rand::thread_rng().fill_bytes(&mut salt); + rand::rng().fill_bytes(&mut salt); // Session AEAD: ChaCha20-Poly1305 when the client asked for it (VIDEO_CAP_CHACHA20 — the // soft-AES armv7 targets, whose GCM decrypt caps at ~100 Mbps) and the operator // kill-switch allows (PUNKTFUNK_CHACHA20, default on — pure rollout safety; perf-only, @@ -520,7 +520,7 @@ pub(super) async fn negotiate( let chacha = client_wants_chacha && pf_host_config::config().chacha20; let key_chacha = chacha.then(|| { let mut k = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut k); + rand::rng().fill_bytes(&mut k); k }); tracing::info!( diff --git a/crates/punktfunk-host/src/native_pairing/arming.rs b/crates/punktfunk-host/src/native_pairing/arming.rs index 8230bc9a..c628b099 100644 --- a/crates/punktfunk-host/src/native_pairing/arming.rs +++ b/crates/punktfunk-host/src/native_pairing/arming.rs @@ -35,7 +35,7 @@ pub enum PinAttempt { fn random_pin() -> String { use rand::Rng; - format!("{:04}", rand::thread_rng().gen_range(0..10_000u32)) + format!("{:04}", rand::rng().random_range(0..10_000u32)) } /// A snapshot of the arming window for the management API: `(armed, pin, expires_in_secs)`. diff --git a/crates/punktfunk-host/src/send_pacing.rs b/crates/punktfunk-host/src/send_pacing.rs index ae205e54..68e4b0c6 100644 --- a/crates/punktfunk-host/src/send_pacing.rs +++ b/crates/punktfunk-host/src/send_pacing.rs @@ -288,9 +288,9 @@ pub(crate) fn inject_video_drop(packets: &mut Vec) -> u64 { return 0; } use rand::Rng; - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let before = packets.len(); - packets.retain(|_| rng.gen_range(0..100) >= pct); + packets.retain(|_| rng.random_range(0..100) >= pct); (before - packets.len()) as u64 } diff --git a/crates/punktfunk-host/src/windows/install.rs b/crates/punktfunk-host/src/windows/install.rs index 931b9976..ab16acb7 100644 --- a/crates/punktfunk-host/src/windows/install.rs +++ b/crates/punktfunk-host/src/windows/install.rs @@ -801,7 +801,7 @@ fn random_password() -> String { use base64::Engine; use rand::RngCore; let mut b = [0u8; 24]; - rand::thread_rng().fill_bytes(&mut b); + rand::rng().fill_bytes(&mut b); base64::engine::general_purpose::STANDARD .encode(b) .chars()