(After GA)
This adds a unit test for the Unix domain sockets that I intend to use
for process splitting on Linux.
The length-prefixed encoding and decoding are copied from `subzone`, but
most of that code will not be re-used since it's Windows-specific and
also specific to a Chromium-like process model, which won't work for
Firezone.
Refs #3713
With this, the deb package for the Linux GUI Client contains a build of
the Linux CLI Client, at `/usr/bin/firezone-client-tunnel`. Future PRs
can add IPC to the code.
There is also a Windows stub, since Windows will eventually need a
tunnel process and a CLI Client.
In the future we might need to move or rename things, since the CLI
Clients and tunnel binaries for both Linux and Windows may all share
code or at least architecture. For now there is a slight duplication
with this being built as both "Firezone Client Tunnnel" and "Firezone
Linux Client"
These customizations were from before we used `cargo cross` for all
architectures in CI.
1.77.1 has been tested to work with the following clients:
- [x] Apple
- [x] Android
- [x] Windows
This catches two of the mutants, according to `cargo-mutants`.
~~Unfortunately since `cargo test` runs in one process, it's
all-or-nothing for sudo, this will run all unit tests as sudo.~~
(This explanation is not exactly correct, `cargo test` does run _a_
subprocess, but still, there is no way to request sudo or non-sudo
runners for specific tests, since it's just an environment variable, and
since many tests run in parallel in different threads of the same
process.)
Here it is passing in Linux:
https://github.com/firezone/firezone/actions/runs/8382799272/job/22957555987#step:5:3160
And Windows:
https://github.com/firezone/firezone/actions/runs/8382799272/job/22957558003#step:5:1006
```[tasklist]
### Before merging
- [x] Try `#[ignore]` attribute
- [x] Fail gracefully if `sudo` isn't available
```
Refs #3776
I think `Tun` could use some automated coverage, so here's the baseline
if this PR goes in:
For `cargo mutants -p firezone-tunnel -p firezone-gui-client --file
connlib/tunnel/src/client.rs --file
connlib/tunnel/src/device_channel/tun_windows.rs`, 113 mutants tested,
68 missed
For `tun_linux.rs`, 128 tested, 76 missed
This is only counting the unit tests, not integration tests or anything,
but it's nice if we can cover some I/O stuff like `wintun` in unit tests
locally.
Motivated by: #4340.
I also activated
[`clippy::unnnecessary_wraps`](https://rust-lang.github.io/rust-clippy/master/#/unnecessary_wraps)
which does create some false-positives for the platform-specific code
but is IMO overall a net-positive. With the amount of Rust code and
crates increasing, it is good to have tools point out simplifications
like these as they are otherwise hard to spot, especially across crate
boundaries.
* Move the resource changes to `ClientState` to unit test easier
* Add unit tests
* Set new config on update from portal
* Set parameters as told by portal on re-init
Fixes: #2728
Supersedes #4320, closes#4318
Updates the interface if effective dns have changed.
Fixes a bug where we could set upstream_dns to have sentinel dns
Adds corresponding unit tests.
---------
Signed-off-by: Gabi <gabrielalejandro7@gmail.com>
Co-authored-by: Reactor Scram <ReactorScram@users.noreply.github.com>
Tried to organize this PR into commits so that it's a bit easier to
review.
1. Involves simplifying the logic in Adapter.swift so that us mortals
can maintain it confidently:
- The `.stoppingTunnel`, `.stoppedTunnelTemporarily`, and
`.stoppingTunnelTemporarily` states have been removed.
- I also removed the `self.` prefix from local vars when it's not
necessary to use it, to be more consistent.
- `onTunnelReady` and `getSystemDefaultResolvers` has been removed, and
`onUpdateRoutes` wired up, along with cleanup necessary to support that.
2. Involves adding the `reconnect` and `set_dns` stubs in the FFI and
fixing the log filter so that we can log them (see #4182 )
3. Involves getting the path update handler working well on macOS using
`SystemConfiguration` to read DNS servers.
4. Involves getting the path update handler working well on iOS by
employing careful trickery to prevent path update cycles by detecting if
`path.gateways` has changed, and avoid setting new DNS if it hasn't.
Refs #4028Fixes#4297Fixes#3565Fixes#3429Fixes#4175Fixes#4176Fixes#4309
---------
Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Reactor Scram <ReactorScram@users.noreply.github.com>
- [x] Updated log level string for client and gateways to info or higher
- [x] Update logs to hide DNS information
I also removed `hickory_resolve` errors which could contain sensitive
info from our general error and hide the logs that specifically relates
to them.
@bmanifold double checking that the log levels in the gateway's `*.tf`
files are just used for our own gateways.
Also, the relays still have `debug`, since only we see that I think that
makes sense but double checking with @jamilbk
Fixes: #3618.
---------
Signed-off-by: Gabi <gabrielalejandro7@gmail.com>
Co-authored-by: Reactor Scram <ReactorScram@users.noreply.github.com>
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.11.27 to
0.12.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seanmonstar/reqwest/releases">reqwest's
releases</a>.</em></p>
<blockquote>
<h2>v0.12.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix <code>ClientBuilder::interface()</code> when no TLS is
enabled.</li>
<li>Fix <code>TlsInfo::peer_certificate()</code> being truncated with
rustls.</li>
<li>Fix panic if <code>http2</code> feature disabled but TLS negotiated
h2 in ALPN.</li>
<li>Fix <code>Display</code> for <code>Error</code> to not include its
source error.</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/atouchet"><code>@atouchet</code></a>
made their first contribution in <a
href="https://redirect.github.com/seanmonstar/reqwest/pull/2193">seanmonstar/reqwest#2193</a></li>
<li><a href="https://github.com/mbme"><code>@mbme</code></a> made their
first contribution in <a
href="https://redirect.github.com/seanmonstar/reqwest/pull/2195">seanmonstar/reqwest#2195</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seanmonstar/reqwest/compare/v0.12.0...v0.12.1">https://github.com/seanmonstar/reqwest/compare/v0.12.0...v0.12.1</a></p>
<h2>v0.12.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Upgrade to <code>hyper</code>, <code>http</code>, and
<code>http-body</code> v1.</li>
<li>Add better support for converting to and from
<code>http::Request</code> and <code>http::Response</code>.</li>
<li>Add <code>http2</code> optional cargo feature, default on.</li>
<li>Add <code>charset</code> optional cargo feature, default on.</li>
<li>Add <code>macos-system-configuration</code> cargo feature, default
on.</li>
<li>Change all optional dependencies to no longer be exposed as implicit
features.</li>
<li>Add <code>ClientBuilder::interface(str)</code> to specify the local
interface to bind to.</li>
<li>Experimental: disables the <code>http3</code> feature
temporarily.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seanmonstar/reqwest/compare/v0.11.27...v0.12.0">https://github.com/seanmonstar/reqwest/compare/v0.11.27...v0.12.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md">reqwest's
changelog</a>.</em></p>
<blockquote>
<h2>v0.12.1</h2>
<ul>
<li>Fix <code>ClientBuilder::interface()</code> when no TLS is
enabled.</li>
<li>Fix <code>TlsInfo::peer_certificate()</code> being truncated with
rustls.</li>
<li>Fix panic if <code>http2</code> feature disabled but TLS negotiated
h2 in ALPN.</li>
<li>Fix <code>Display</code> for <code>Error</code> to not include its
source error.</li>
</ul>
<h1>v0.12.0</h1>
<ul>
<li>Upgrade to <code>hyper</code>, <code>http</code>, and
<code>http-body</code> v1.</li>
<li>Add better support for converting to and from
<code>http::Request</code> and <code>http::Response</code>.</li>
<li>Add <code>http2</code> optional cargo feature, default on.</li>
<li>Add <code>charset</code> optional cargo feature, default on.</li>
<li>Add <code>macos-system-configuration</code> cargo feature, default
on.</li>
<li>Change all optional dependencies to no longer be exposed as implicit
features.</li>
<li>Add <code>ClientBuilder::interface(str)</code> to specify the local
interface to bind to.</li>
<li>Experimental: disables the <code>http3</code> feature
temporarily.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e0ea15bd65"><code>e0ea15b</code></a>
v0.12.1</li>
<li><a
href="3d78fcbbb5"><code>3d78fcb</code></a>
fix: Display for Error shouldn't include source (<a
href="https://redirect.github.com/seanmonstar/reqwest/issues/2199">#2199</a>)</li>
<li><a
href="c53572410d"><code>c535724</code></a>
Fix binding interface when no TLS is used (<a
href="https://redirect.github.com/seanmonstar/reqwest/issues/2200">#2200</a>)</li>
<li><a
href="d5adcba6a2"><code>d5adcba</code></a>
fix: rustls extraction of <code>TlsInfo::peer_certificate()</code> being
truncated (<a
href="https://redirect.github.com/seanmonstar/reqwest/issues/2195">#2195</a>)</li>
<li><a
href="7a5df21260"><code>7a5df21</code></a>
fix: could panic if http2 disabled but TLS negotiated h2 (<a
href="https://redirect.github.com/seanmonstar/reqwest/issues/2194">#2194</a>)</li>
<li><a
href="d5051f9bee"><code>d5051f9</code></a>
Update version number in Readme</li>
<li><a
href="92aa28caab"><code>92aa28c</code></a>
v0.12.0</li>
<li><a
href="6c6170b1a7"><code>6c6170b</code></a>
feat: Make encoding_rs an optional dependency called
<code>charset</code></li>
<li><a
href="d1022b3b9f"><code>d1022b3</code></a>
Support conversion to http::Response</li>
<li><a
href="a29c7f9011"><code>a29c7f9</code></a>
Add macos-system-configuration feature flag</li>
<li>Additional commits viewable in <a
href="https://github.com/seanmonstar/reqwest/compare/v0.11.27...v0.12.1">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Our sockets need to be initialized within a tokio runtime context. To
achieve this, we don't actually initialize anything on `Sockets::new`.
Instead, we call `rebind` within the constructor of `Tunnel` which
already runs in a tokio context.
Fixes: #4282
---------
Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
Co-authored-by: Reactor Scram <ReactorScram@users.noreply.github.com>
This updates connlib to follow the new guidelines described in #4262. I
only made the bare-minimum changes to the clients. With these changes
`reconnect` should only be called when the network interface actually
changed, meaning clients have to be updated to reflect that.
Currently, a failure during DNS resolution results in the client hanging
during the connection setup. Instead, we fall back to an empty list
which results in an empty DNS query result for the client.
That in turn will make most application consider the DNS request failed.
As far as I know, we don't currently retry these DNS requests, meaning a
user would have to sign-in and out again to fix this state.
Whilst not ideal, I think this is a better behaviour and what we
currently have where the initial connection just hangs.
Currently, we need to wait for the timeout of the current candidate pair
during `reconnect` before we nominate a new one. To speed this up, we
can preemptively invalidate candidates we have previously discovered via
our `Allocation`s, i.e. relay candidates and srflx candidates.
This is done to fix a bug where the file descriptor is unregistered from
the reactor after the new `Tun` struct is created if the old one is
dropped after.
Running as sudo / root causes a lot of problems for GUI programs, so
we're unwinding that. In this case we can go back to using Tauri's "open
URL" function, which is great.
Closes#4103
Refs #3713
Affects #3972 - I was finally able to debug it because it came up
constantly during this PR
Currently, an error returned by `Tunnel::poll_next_event` is only
logged. In other words, they are never fatal. This creates a tricky to
understand relationship on what kind of errors should be returned from
callbacks. Because connlib is used on multiple operating systems, it has
no idea how fatal a particular error is.
This PR removes all of these `Result` return values with the following
consequences:
- For Android, we now panic when a callback fails. This is a slight
change in behaviour. I believe that previously, any exception thrown by
a callback into Android was caught and returned as an error. Now, we
panic because in the FFI layer, we don't have any information on how
fatal the error is. For non-fatal errors, the Android app should simply
not throw an exception. The panics will cause the connlib task to be
shut down which triggers an `on_disconnect`.
- For Swift, there is no behaviour change. The FFI layer already did not
support `Result`s for those callbacks. I don't know how exceptions from
Swift are translated across the FFI layer but there is no change to what
we had before.
- For the Tauri client:
- I chose to log errors on ERROR level and continue gracefully for the
DNS resolvers.
- We panic in case the controller channel is full / closed. That should
really never happen in practice though unless we are currently shutting
down the app.
Resolves: #4064.
Previously, we used `SocketState::send` without wrapping it in
`UdpSocket::try_io`. This meant that tokio had no chance of clearing the
readiness flag on the socket when we actually failed to send a packet,
resulting in many log messages like this:
```
Tunnel error: Resource temporarily unavailable (os error 11)
```
This PR refactors how we send UDP packets and when we read IP packet
from the device. Instead of just polling for send-readiness, we flush
all buffered packets and _then_ check for send-readiness. That will only
succeed if we managed to send all buffered packets and the socket still
has space for more packets.
Typically, this buffer only has 1-2 packets. That is because we
currently only ever read a single packet from the device. See #4139 for
how this might change. It may have more packets when our `Allocation`s
emit some (like multiple channel bindings in a row). Because we enforce
further send-readiness before continuing, this buffer cannot grow
unbounded.
Resolves: #3931.
In the future we will want to refactor this to a builder pattern to
prevent the number of parameters from growing and have them clearer but
this works simply for now.
Found while discussing #4174
---------
Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
With the move to SANS-IO, we will be able to write deterministic unit
tests for the tunnel logic. To actually do that, `ClientState` and
`GatewayState` need to encapsulate all the logic that we want to test.
This PR does some minor refactoring on the functions on `ClientTunnel`
and moves several of them onto `ClientState`. It doesn't touch
`add_resources` and `remove_resource` because those depend on #4156.
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.80 to 1.0.81.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dtolnay/anyhow/releases">anyhow's
releases</a>.</em></p>
<blockquote>
<h2>1.0.81</h2>
<ul>
<li>Make backtrace support available when using -Dwarnings (<a
href="https://redirect.github.com/dtolnay/anyhow/issues/354">#354</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4aad4edebd"><code>4aad4ed</code></a>
Release 1.0.81</li>
<li><a
href="8be90917c6"><code>8be9091</code></a>
Merge pull request <a
href="https://redirect.github.com/dtolnay/anyhow/issues/354">#354</a>
from dtolnay/deadcode</li>
<li><a
href="a2eb7dd5e1"><code>a2eb7dd</code></a>
Make compatible with -Dwarnings</li>
<li>See full diff in <a
href="https://github.com/dtolnay/anyhow/compare/1.0.80...1.0.81">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This isn't really user-facing, so I marked it down from `feat` to
`chore`. Closes#3817
- If we exit gracefully, `/etc/resolv.conf` is reverted
- We always keep the `.before-firezone` backup in case we lose power and
the revert transaction is corrupted or rolled back
- We use a magic header to detect whether the last run was a crash or
not. If Firezone crashes and the user wants to modify their default DNS,
they need to delete that header so that Firezone won't accidentally
revert its backup and trash their change.
- All error variants for this module replaced with `anyhow::Error` since
they were never matched by callers.
I ran `cargo mutants` locally and it helped me validate the unit tests
and it picked up a `match` branch that I forgot to delete.
```[tasklist]
- [x] (Failed: Integration tests didn't like it) ~~Add the system default resolvers below Firezone's sentinels~~
- [x] `tracing::info` "Last run crashed" if we have to revert the file at startup
```
---------
Signed-off-by: Reactor Scram <ReactorScram@users.noreply.github.com>
This opens the door for unit testing `ClientState` with a
`GatewayState`, similarly as we have a test for a `ClientNode` and
`ServerNode` in `snownet`.
Before we can do that though, we need to move several functions from
`ClientTunnel` onto `ClientState`, i.e. essentially encapsulate
`ClientState` better. This is left to a future PR though to keep the
steps small.
Resolves: #3928.