Files
firezone/rust/Cargo.toml
Thomas Eizinger 1a5c40bd75 refactor(connlib): extract l4-udp-dns-client (#10854)
In order to bootstrap DoH servers, we need a way of reliably resolving
the domain of the DoH server to an IP address. Initially, I thought that
this would be tricky to do if we have to integrate this into the
Client's state machine.

Whilst implementing DoH however, I realised that we can instead put this
responsibility onto the IO layer of connlib. Similar to other cases, we
can reuse external triggers as our retry mechanism in case of failure.
In particular, we can simply issue UDP DNS queries for the DoH domain to
all system-defined DNS resolvers every time we are told to send a DNS
query over DoH but the corresponding client isn't initialized yet.

In other words, instead of building a retry mechanism ourselves, we
attempt to repair any kind of broken state once per DNS query that we
receive.

Performing this DNS resolution does require a bit of code. We already
started to do something similar in #10817. In order to reuse that code,
we extract it into a `l4-udp-dns-client` crate and slightly refactor its
semantics. In particular, we now wait for the response of all upstream
servers (but at most 2s) and combine the result.

The resulting `UdpDnsClient` can now be used inside the Client's
event-loop to re-resolve the portal URL and will also be used as part of
our DoH implementation to bootstrap the connection to the DoH server.

Related: #4668
2025-11-13 13:19:22 +00:00

282 lines
9.1 KiB
TOML

[workspace]
members = [
"bin-shared",
"cli",
"client-ffi",
"client-shared",
"connlib/bufferpool",
"connlib/dns-over-tcp",
"connlib/dns-types",
"connlib/etherparse-ext",
"connlib/http-client",
"connlib/ip-packet",
"connlib/l3-tcp",
"connlib/l3-udp-dns-client",
"connlib/l4-tcp-dns-server",
"connlib/l4-udp-dns-client",
"connlib/l4-udp-dns-server",
"connlib/model",
"connlib/phoenix-channel",
"connlib/snownet",
"connlib/socket-factory",
"connlib/tun",
"connlib/tunnel",
"gateway",
"gui-client/src-admx-macro",
"gui-client/src-tauri",
"headless-client",
"logging",
"relay/ebpf-shared",
"relay/ebpf-turn-router",
"relay/server",
"telemetry",
"tests/fuzz",
"tests/gui-smoke-test",
"tests/http-test-server",
"tools/uniffi-bindgen",
]
resolver = "2"
[workspace.package]
license = "Apache-2.0"
edition = "2024"
[workspace.dependencies]
admx-macro = { path = "gui-client/src-admx-macro" }
anyhow = "1.0.99"
arbitrary = "1.4.2"
arboard = { version = "3.6.1", default-features = false }
async-trait = { version = "0.1", default-features = false }
atomicwrites = "0.4.4"
axum = { version = "0.8.5", default-features = false }
aya = { git = "https://github.com/aya-rs/aya" }
aya-build = { git = "https://github.com/aya-rs/aya" }
aya-ebpf = { git = "https://github.com/aya-rs/aya" }
aya-log = { git = "https://github.com/aya-rs/aya" }
aya-log-ebpf = { git = "https://github.com/aya-rs/aya" }
backoff = { version = "0.4", features = ["tokio"] }
base64 = { version = "0.22.1", default-features = false }
bimap = "0.6"
bnum = "0.13.0"
boringtun = { version = "0.6", default-features = false }
bufferpool = { path = "connlib/bufferpool" }
bytecodec = "0.5.0"
bytes = { version = "1.9.0", default-features = false }
caps = "0.5.5"
chrono = { version = "0.4", default-features = false, features = ["std", "clock", "oldtime", "serde"] }
clap = "4.5.47"
client-shared = { path = "client-shared" }
connlib-model = { path = "connlib/model" }
crossbeam-queue = "0.3.12"
dashmap = "6.1.0"
derive_more = { version = "2.0.1", default-features = false }
difference = "2.0.0"
dirs = "6.0.0"
divan = "0.1.21"
dns-lookup = "3.0"
dns-over-tcp = { path = "connlib/dns-over-tcp" }
dns-types = { path = "connlib/dns-types" }
ebpf-shared = { path = "relay/ebpf-shared" }
either = "1"
etherparse = { version = "0.19", default-features = false }
etherparse-ext = { path = "connlib/etherparse-ext" }
firezone-bin-shared = { path = "bin-shared" }
firezone-headless-client = { path = "headless-client" }
firezone-logging = { path = "logging" }
firezone-relay = { path = "relay/server" }
firezone-telemetry = { path = "telemetry" }
firezone-tunnel = { path = "connlib/tunnel" }
flume = { version = "0.11.1", features = ["async"] }
futures = { version = "0.3.31" }
futures-bounded = "0.3.0"
gat-lending-iterator = "0.1.7"
glob = "0.3.3"
hex = "0.4.3"
hex-display = "0.3.0"
hex-literal = "1.0.0"
hickory-resolver = "0.25.2"
hmac = "0.12.1"
http = "1.3.1"
http-body-util = "0.1.3"
http-client = { path = "connlib/http-client" }
humantime = "2.3"
hyper = "1.7.0"
hyper-util = "0.1.17"
ip-packet = { path = "connlib/ip-packet" }
ip_network = { version = "0.4", default-features = false }
ip_network_table = { version = "0.2", default-features = false }
itertools = "0.14"
jni = "0.21.1"
keyring = "3.6.3"
known-folders = "1.4.0"
l3-tcp = { path = "connlib/l3-tcp" }
l3-udp-dns-client = { path = "connlib/l3-udp-dns-client" }
l4-tcp-dns-server = { path = "connlib/l4-tcp-dns-server" }
l4-udp-dns-client = { path = "connlib/l4-udp-dns-client" }
l4-udp-dns-server = { path = "connlib/l4-udp-dns-server" }
libc = "0.2.176"
libfuzzer-sys = "0.4"
log = "0.4"
lru = "0.16.1"
mio = "1.1.0"
moka = "0.12.11"
native-dialog = "0.7.0"
netlink-packet-core = "0.8"
netlink-packet-route = "0.25"
network-types = "0.1.0"
nix = "0.30.1"
nu-ansi-term = "0.50"
num_cpus = "1.17.0"
once_cell = "1.21.3"
opentelemetry = "0.30.0"
opentelemetry-otlp = "0.30.0"
opentelemetry-stdout = "0.30.0"
opentelemetry_sdk = "0.30.0"
os_info = { version = "3", default-features = false }
output_vt100 = "0.1"
parking_lot = "0.12.5"
phoenix-channel = { path = "connlib/phoenix-channel" }
png = "0.17.16"
proc-macro2 = "1.0"
proptest = "1.9.0"
proptest-state-machine = "0.6.0"
quinn-udp = { version = "0.5.12", features = ["fast-apple-datapath"] }
quote = "1.0"
rand = "0.8.5"
rand_core = "0.6.4"
rangemap = "1.6.0"
reqwest = { version = "0.12.23", default-features = false }
resolv-conf = "0.7.5"
ringbuffer = "0.16.0"
roxmltree = "0.20"
rpassword = "7.4.0"
rtnetlink = { version = "0.18.1", default-features = false, features = ["tokio_socket"] }
rustls = { version = "0.23.31", default-features = false, features = ["ring"] }
rustls-pki-types = "1.13.0"
sadness-generator = "0.6.0"
sd-notify = "0.4.5" # This is a pure Rust re-implementation, so it isn't vulnerable to CVE-2024-3094
secrecy = "0.10"
semver = "1.0.27"
sentry = { version = "0.43.0", default-features = false }
sentry-tracing = "0.43.0"
serde = "1.0.228"
serde_json = "1.0.145"
serde_variant = "0.1.3"
serde_with = "3.15.0"
sha2 = "0.10.9"
smallvec = "1.15.1"
smbios-lib = "0.9.2"
smoltcp = { version = "0.12", default-features = false }
snownet = { path = "connlib/snownet" }
socket-factory = { path = "connlib/socket-factory" }
socket2 = { version = "0.6" }
specta = "=2.0.0-rc.22"
specta-typescript = "0.0.9"
static_assertions = "1.1.0"
str0m = { version = "0.9.0", default-features = false, features = ["sha1"] }
strum = { version = "0.27.2", features = ["derive"] }
stun_codec = "0.4.0"
subprocess = "0.2.9"
subtle = "2.5.0"
supports-color = "3.0.2"
swift-bridge = "0.1.57"
swift-bridge-build = "0.1.57"
syn = "2.0"
tauri = "2.8.4"
tauri-build = "2.4.0"
tauri-plugin-dialog = "2.4.0"
tauri-plugin-notification = "2.3.1"
tauri-plugin-opener = "2.5.0"
tauri-plugin-shell = "2.3.1"
tauri-runtime = "2.7.1"
tauri-specta = { version = "=2.0.0-rc.21", features = ["derive", "typescript"] }
tauri-utils = "2.2.0"
tempfile = "3.23.0"
test-case = "3.3.1"
test-strategy = "0.4.3"
thiserror = "2.0.17"
time = "0.3.43"
tokio = "1.48.0"
tokio-rustls = { version = "0.26.4", default-features = false }
tokio-stream = "0.1.17"
tokio-tungstenite = "0.28.0"
tokio-util = "0.7.16"
tracing = { version = "0.1.40" }
tracing-appender = "0.2.3"
tracing-core = "0.1.34"
tracing-journald = "0.3.1"
tracing-log = "0.2.0"
tracing-macros = { git = "https://github.com/tokio-rs/tracing", branch = "v0.1.x" } # Contains `dbg!` but for `tracing`.
tracing-opentelemetry = "0.31.0"
tracing-stackdriver = "0.12.0"
tracing-subscriber = { version = "0.3.20", features = ["parking_lot"] }
trackable = "1.3.0"
tun = { path = "connlib/tun" }
uniffi = "0.29.4"
url = "2.5.2"
uuid = "1.18.1"
webpki-roots = "1.0.4"
which = "4.4.2"
windows = "0.61.3"
windows-core = "0.61.1"
windows-implement = "0.60.0"
windows-service = "0.8.0"
winreg = "0.55.0"
zbus = "5.11.0"
zip = { version = "5", default-features = false }
[workspace.lints.clippy]
dbg_macro = "warn"
print_stdout = "warn"
print_stderr = "warn"
unnecessary_wraps = "warn"
unused_async = "warn"
wildcard_enum_match_arm = "warn" # Ensures we match on all combinations of `Poll`, preventing erroneous suspensions.
redundant_else = "warn"
redundant_clone = "warn"
unwrap_in_result = "warn"
unwrap_used = "warn"
too_many_arguments = "allow" # Don't care.
large_enum_variant = "allow" # Don't care.
[workspace.lints.rustdoc]
private-intra-doc-links = "allow" # We don't publish any of our docs but want to catch dead links.
[patch.crates-io]
boringtun = { git = "https://github.com/firezone/boringtun", branch = "master" }
ip_network = { git = "https://github.com/JakubOnderka/ip_network", branch = "master" } # Waiting for release.
ip_network_table = { git = "https://github.com/edmonds/ip_network_table", branch = "some-useful-traits" } # For `Debug` and `Clone`
tracing-stackdriver = { git = "https://github.com/thomaseizinger/tracing-stackdriver", branch = "bump-otel-0.30" } # Waiting for release.
softbuffer = { git = "https://github.com/rust-windowing/softbuffer" } # Waiting for release.
str0m = { git = "https://github.com/algesten/str0m", branch = "main" }
moka = { git = "https://github.com/moka-rs/moka", branch = "main" } # Waiting for release.
quinn-udp = { git = "https://github.com/quinn-rs/quinn", branch = "main" } # Waiting for release.
proptest = { git = "https://github.com/firezone/proptest", branch = "feat/state-machine-closure" }
proptest-state-machine = { git = "https://github.com/firezone/proptest", branch = "feat/state-machine-closure" }
# Enforce `tracing-macros` to have released `tracing` version.
[patch.'https://github.com/tokio-rs/tracing']
tracing = "0.1.41"
[profile.release]
# Full link-time optimization. Reduces binaries by up to 3x on some platforms.
lto = "fat"
# Increases the compiler's ability to produce smaller, optimized code
# at the expense of compilation time
codegen-units = 1
[profile.release.package.firezone-gui-client]
debug = "full"
split-debuginfo = "packed"
[profile.release.package.ebpf-turn-router]
debug = 2
# Override build settings just for the GUI client, so we get a pdb/dwp
# Cargo ignores profile settings if they're not in the workspace's Cargo.toml
[profile.dev.package.firezone-gui-client]
debug = "full"
split-debuginfo = "packed"