-
Notifications
You must be signed in to change notification settings - Fork 113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
VPN-6252: Add Daemon Documentation #9741
Merged
Merged
Changes from 5 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
0cfe956
Add documentation for the Daemon
oskirby f2b1f90
Document the behaviour upon a crash of the daemon
oskirby 1e921e8
Massage some grammar and spelling
oskirby c745f67
A bit more spelling
oskirby c78407e
Last bit of spellchecking, I hope
oskirby a893756
Add details for Android
oskirby b834158
Spelling
oskirby File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
# Mozilla VPN Daemon | ||
|
||
On most platforms, the VPN software requires privileged access to the operating system in order to create and manage | ||
network interfaces. This level of privilege is unsuitable for a GUI program, so the duties of the VPN software are | ||
split into a graphical client, and a privileged daemon program. This document describes the behavior of the daemon | ||
and how it interacts with the system. | ||
|
||
## Communication Protocol | ||
|
||
Every platform has unique service management and interprocess communication mechanisms which dictate how to start the | ||
daemon and communicate with it, but the format of the message sent and received by the daemon follow a common format | ||
and describe a common set of commands: | ||
- `activate`: Method called to create a VPN connection to a specific Wireguard peer. This method takes a JSON | ||
configuration object describing the connection to establish, and returns a boolean value indicating if the | ||
connection has been started. If the returned value is `true` then the connection will be completed asynchronously | ||
by the emission of either a `connected` or `disconnected` signal. | ||
|
||
- `deactivate`: Method called to stop all VPN connections to all Wireguard peers. | ||
|
||
- `status`: Method called to fetch the current state of the VPN. Returns a JSON object describing the primary | ||
VPN connection (the one that routes to the internet). | ||
|
||
- `getLogs`: Method called to fetch log messages from the daemon. This is typically joined to the logs from the | ||
GUI client when exporting logs for debug and analysis purposes. This returns the contents of the logs concatenated | ||
together into a multi-line string. | ||
|
||
- `cleanupLogs`: Method called to delete logs messages from the daemon. | ||
|
||
- `connected`: An asynchronous signal sent from the daemon to inform the GUI client that a VPN connection to a Wireguard | ||
peer has been successfully established. The public key of the Wireguard peer is provided as an argument to this | ||
signal. | ||
|
||
- `disconnected`: An asynchronous signal sent from the daemon to inform the GUI client that the VPN has been terminated | ||
and the connection to all Wireguard peers has been stopped. | ||
|
||
## Platform Implementations | ||
|
||
### Linux systemd service | ||
|
||
The Linux daemon is launched as a systemd service named `mozillavpn`. You can manage this service using the `systemctl` | ||
command. For example: | ||
|
||
``` | ||
[user@hostname ~] systemctl status mozillavpn | ||
o mozillavpn.service - MozillaVPN D-Bus service | ||
Loaded: loaded (/usr/lib/systemd/system/mozillavpn.service; enabled; preset: disabled) | ||
Drop-In: /usr/lib/systemd/system/service.d | ||
10-timeout-abort.conf | ||
Active: active (running) since Mon 2024-07-22 14:22:34 PDT; 1s ago | ||
Main PID: 40698 (mozillavpn) | ||
Tasks: 9 (limit: 17683) | ||
Memory: 21.9M | ||
CPU: 492ms | ||
CGroup: /system.slice/mozillavpn.service | ||
40698 /usr/bin/mozillavpn linuxdaemon | ||
``` | ||
|
||
Other commands include: | ||
- `systemctl enable mozillavpn`: Enable the daemon to start when the system boots. | ||
- `systemctl disable mozillavpn`: Disable startup of them daemon when the system boots. | ||
- `systemctl start mozillavpn`: Request startup of the daemon. | ||
- `systemctl stop mozillavpn`: Request shutdown of the daemon. | ||
- `systemctl restart mozillavpn`: Stop and restart the daemon. | ||
|
||
Communication with the Linux daemon is achieved using the D-Bus protocol, described by the FreeDesktop | ||
[D-Bus](http://dbus.freedesktop.org/doc/dbus-specification.html) specification. The daemon will be available on the | ||
system bus, and takes ownership of the name `org.mozilla.vpn.dbus`. | ||
|
||
The Linux kernel includes support for the Wireguard protocol, so this daemon only needs to respond to the communication | ||
protocol and retain the necessary capabilities to orchestrate interface creation, configuration and management. | ||
|
||
### MacOS launchd | ||
|
||
The MacOS daemon is launched using [launchd](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html) | ||
by installing a daemon plist at `/Library/LaunchDaemons/org.mozilla.macos.FirefoxVPN.daemon.plist` and registering the | ||
daemon for automatic startup with `launchctl load -w $DAEMON_PLIST_PATH`. | ||
|
||
Communication with the daemon is achieved via a named UNIX socket, which the daemon will create at | ||
`/var/run/mozillavpn/daemon.socket`. The API methods are invoked by formatting the arguments as a JSON object, and | ||
inserting a value of `type` set to the name of the method being invoked. | ||
|
||
MacOS does not include native support for the Wireguard protocol, so in order to establish a Wireguard tunnel, the | ||
daemon will create and manage other processes to perform this function. The | ||
[wireguard-go](https://git.zx2c4.com/wireguard-go) project provides a packet tunnel for Wireguard connectivity and | ||
connects to the kernel using the `/dev/net/tun` interface. | ||
|
||
To manage the DNS resolver changes required for this interface, we also include another tool, the `macosdnsmanager`, | ||
whose purpose is to reconfigure MacOS to use the DNS resolver provided by the VPN network, and to restore the previous | ||
DNS configuration upon shutdown of the VPN tunnel. | ||
|
||
### Windows Service | ||
|
||
The MSI Installer package creates a Windows service, named the `Mozilla VPN (broker)`, to gain administrator privileges | ||
for creating and managing the network interfaces and configuration. This service is set to launch automatically on boot, | ||
and can be inspected via the Windows Service Manager. | ||
|
||
Communication with the daemon is achieved via a named pipe, which the daemon will create at `\\.\pipe\mozillavpn`. | ||
The API methods are invoked by formatting the arguments as a JSON object, and inserting a value of `type` set to the | ||
name of the method being invoked. | ||
|
||
Windows does not include native support for the Wireguard protocol, so in order provide this capability the | ||
[Wireguard NT](https://github.com/WireGuard/wireguard-nt) kernel driver is installed by the windows service. This driver | ||
is instantiated when bringing up the VPN tunnel to handle the connection. | ||
|
||
Additionally, a [split-tunneling](https://github.com/mullvad/win-split-tunnel) driver may also be provided, which can be used | ||
by the VPN to allow some applications to access the network directly and bypass the VPN. The daemon will check for this driver | ||
at startup, and register it for split tunneling if possible. | ||
|
||
### Android daemon??? | ||
|
||
TODO: How does Android work, exactly? | ||
|
||
### iOS Network Extension | ||
|
||
In order to provide custom VPN protocols on iOS, it is required to implement an iOS Network Extension. The Mozilla VPN | ||
makes use of the [wireguard-apple](https://github.com/WireGuard/wireguard-apple) project to provide a network extension | ||
implementing the [NEPacketTunnelProvider](https://developer.apple.com/documentation/networkextension/nepackettunnelprovider) | ||
class. | ||
|
||
## Crashes and Recovery | ||
|
||
Because the VPN is designed to intercept all network traffic originating from the user's device and encrypt it, a crash | ||
or failure of this software can be especially severe, and has the potential to permanently break the user's internet | ||
connectivity if handled incorrectly. Therefore additional steps are taken to ensure that a crash of this software can be | ||
recovered from. | ||
|
||
In the GUI client, software communication with the daemon is guarded by a timeout mechanism and communication errors | ||
must be handled gracefully. These errors are detected by the `Controller` class, and reported as an | ||
`ErrorHandler::ControllerError`. Such failures typically result in a re-initialization of the controller class which | ||
will bring the client back to the deactivated state. Detection of these errors will trigger an error banner in the GUI | ||
client, as well as a system tray notification in case the GUI client is not visible in the foreground. | ||
|
||
Where possible the services are configured to automatically restart daemon processes which exit abnormally (crash): | ||
- Linux: The `mozillavpn.service` file sets `Restart=on-failure` | ||
- MacOS: The `org.mozilla.macos.FirefoxVPN.daemon.plist` set `KeepAlive` to `true` | ||
- Windows: The service config is set with `FirstFailureActionType` and `SecondFailureActionType` to `restart` | ||
|
||
When starting, the daemon processes MUST check for the existence of any VPN interfaces, firewalls, kill-switches and | ||
drivers which were created by a previous instance of the daemon and stop them as necessary to return to a known state | ||
and to ensure that the host network connectivity is restored. | ||
|
||
If the VPN connection was active at the time of the crash, the daemon SHOULD NOT attempt to re-activate the connection. | ||
The context of such a connection is likely to have been lost in the crash and it is desired that the daemon should | ||
remain stateless. An attempt to re-activate the connection may lead to the same condition which triggered the crash, | ||
therefore we feel it is safer to leave the VPN inactive after recovery. | ||
|
||
Because the daemon runs as a privileged process, has no UI, and is outside of direct user control, it does not currently | ||
support crash reporting via Sentry. However, we can still get telemetry about the frequency of crashes and controller | ||
communication errors through analysis of the `error_alert_shown` ping. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Daemon is an Android Service communicating using Bindings with the Client (or widgets). Unlike "standard" android guidelines, it's explicitly a 2nd process.
The protocol is similar to the desktop daemons as we exchange json blobs but the format on the wire is
{requestType:int,data:json}
(...we could actually think about using the desktop protocol at some point)To activate the daemon will request a raw handle of a TUN device using Android's VPN API. It load's wireguard-go into it's process and calls into wg-go with the handle and the config, which will then spawn a goroutine handling traffic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!