summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2022-05-31 15:14:36 +0100
committerEmīls <emils@mullvad.net>2022-05-31 15:14:36 +0100
commitc5ee2bc87d0bb42808fa0542ed00fe6257932ec1 (patch)
treeefd68ff5ac573c4185c0abcf8b3b4c1f325881e7
parent083d294309978a8cb96a4afc8abc0b4854289213 (diff)
parent3c1d2fcbcdbbf6414ffb8dee1283b9e883aef8ce (diff)
downloadmullvadvpn-c5ee2bc87d0bb42808fa0542ed00fe6257932ec1.tar.xz
mullvadvpn-c5ee2bc87d0bb42808fa0542ed00fe6257932ec1.zip
Merge branch 'add-docs'
-rw-r--r--docs/architecture.md58
-rw-r--r--docs/diagrams/daemon-components.pngbin0 -> 443114 bytes
-rw-r--r--docs/diagrams/daemon-components.puml66
-rw-r--r--docs/diagrams/readme.md6
-rw-r--r--docs/diagrams/set-allow-lan.pngbin0 -> 119487 bytes
-rw-r--r--docs/diagrams/set-allow-lan.puml21
-rw-r--r--docs/diagrams/tsm-connecting-enter.pngbin0 -> 233576 bytes
-rw-r--r--docs/diagrams/tsm-connecting-enter.puml26
-rw-r--r--docs/diagrams/update-relay-constraints.pngbin0 -> 240478 bytes
-rw-r--r--docs/diagrams/update-relay-constraints.puml28
10 files changed, 198 insertions, 7 deletions
diff --git a/docs/architecture.md b/docs/architecture.md
index c0186f76c9..3c61dcfba1 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -1,3 +1,6 @@
+
+
+
# Mullvad VPN app architecture
This document describes the code architecture and how everything fits together.
@@ -15,12 +18,48 @@ My thought was that after this section every aspect of the app is explained
under either the Mullvad or the Talpid header. So it's clear which part they
belong to. I yet don't know if this makes sense though.
+## The daemon
+The client consists of two main parts - the daemon and the GUI, but there's also a CLI. The daemon
+is the process that's responsible for upholding the security guarantees of the client, it consists
+of an actor system so that it can drive many processes asynchronously, allowing for a multiplicity
+of clients.
+
+<img src="diagrams/daemon-components.png">
+
+The daemon receives commands from the [front-ends](#frontends) (GUI and CLI) via the management
+interface and these are serviced asynchronously via the daemon, often interacting via various other
+components during and after the RPC has been finished. There are various dependencies between the
+different components and it's important to ensure no deadlocks occur, and some executions flows that
+provide essential behavior can be hard to trace.
+
+<img src="diagrams/update-relay-constraints.png">
+
## Mullvad part of daemon
### Frontend <-> system service communication
+This is done via GRPC ([here's](../mullvad-management-interface/proto/management_interface.proto)
+the relevant proto file) over a Unix domain socket on desktop platforms and via a JNI on Android. In
+both cases, the frontends end up sending a message to the daemon that it then services. The
+servicing of any message must never block any other message. Frontends can also subscribe to
+messages from the daemon, to receive updates about the tunnel state, new settings, new relay lists,
+version information and device events.
+
-### Talking to api.mullvad.net
+### Talking to api.mullvad.net.
+Reaching the API is done via a direct TLS connection to the API host or via a shadowsocks bridge, to
+increase censorship resistance. There are multiple components that interact with the API in an
+asynchronous fashion, so to manage them all, there's an actor that specifically deals with sending
+REST requests to the API.
+
+The API must be reachable in secured states even if a tunnel is not up, so the API runtime interacts
+with the [tunnel state machine](#tunnel-state-machine) to send over the currently used API endpoint.
+This can be a source of deadlocks, so no actor should ever be blocked by an API request if the TSM
+relies on it to change states.
+
+All API requests can be dropped in flight to allow for resetting the connection whenever a tunnel is
+established. The API requests can also be blocked when in the offline state or when it's assumed
+that the user hasn't used our client for a period of time.
### Selecting relay and bridge servers
See [this document](relay-selector.md).
@@ -92,7 +131,14 @@ A high-level overview of the tunnel state machine can be seen in the diagram bel
#### State machine inputs
There are two types of inputs that the tunnel state machine react to. The first one is commands sent
-to the state machine, and the second is external events that the state machine listens to.
+to the state machine, and the second is external events that the state machine listens to. Reacting
+to any event can result in the state machine transitioning away to a different state.
+
+<img src="diagrams/tsm-connecting-enter.png">
+
+
+
+
##### Tunnel commands
@@ -176,11 +222,9 @@ Linux.
#### macOS
-On macOS, the offline monitor uses [`SCNetworkReachability`] callbacks to detect changes in
-connectivity and then enumerates network interfaces via [`SCDynamicStore`] and assumes connectivity
-if an active physical interface exists. The interfaces are enumerated because sometimes
-`SCNetworkReachability` can trigger a callback signalling full connectivity even when there exists
-no default route.
+On macOS, the offline monitor uses `route -n monitor -` to listen for changes in the routing table,
+reasserting that a default route exists any time a change is detected. It's only assumed that the
+host is offline if a default route doesn't exist.
##### Issues
diff --git a/docs/diagrams/daemon-components.png b/docs/diagrams/daemon-components.png
new file mode 100644
index 0000000000..cfa7c9b2ba
--- /dev/null
+++ b/docs/diagrams/daemon-components.png
Binary files differ
diff --git a/docs/diagrams/daemon-components.puml b/docs/diagrams/daemon-components.puml
new file mode 100644
index 0000000000..42eed5aa19
--- /dev/null
+++ b/docs/diagrams/daemon-components.puml
@@ -0,0 +1,66 @@
+@startuml
+hide empty description
+scale 10000
+
+left to right direction
+!pragma layout elk
+
+
+component "Mullvad daemon" as mullvad_daemon {
+ () "Management interface" as management_interface
+ () "Mullvad API" as mullvad_api
+
+ node "Daemon" as daemon {
+ [Settings] as settings #yellow
+ [Account history] as account_history #yellow
+ [Various state around tunnels and relays] #yellow
+ }
+
+ node "Tunnel state machine" as tsm {
+ [Firewall] as firewall #yellow
+ [DNS] as dns #yellow
+ [Routing] as routing
+ [Tunnel] as tunnel
+ [Offline monitor] as offline_monitor
+ }
+
+ [Account manager] as account_manager
+ [Mullvad API client] as rest_service
+ [Relay list updater] as relay_list_updater
+ [Version updater] as version_updater
+ [Relay selector] as relay_selector #yellow
+}
+
+legend
+ Yellow components are shared synchronously (via a mutex).
+end legend
+
+
+management_interface -> daemon : Incoming RPCs
+
+daemon -> tsm : Sets target tunnel state
+tsm -> daemon : "Notifies of changes to tunnel state, gets tunnel connection config"
+tsm -> daemon : Get tunnel connection config
+daemon -> relay_selector : Select a relay for a connection
+daemon -> rest_service : Change API availability
+daemon -> relay_list_updater : Force relay list update
+daemon -> version_updater : Fetch current version
+daemon -> account_manager : Fetch account data
+daemon -> account_manager : Fetch device data and WG key
+
+relay_list_updater -> relay_selector : Update relay list
+account_manager -> daemon : Account/device events
+
+
+rest_service -> relay_selector : Select bridge relay for API connection
+rest_service -> tsm : Unblock API endpoint
+rest_service -> mullvad_api : Send requests to our web service
+
+relay_list_updater -> rest_service : Fetch relay list from API
+version_updater -> rest_service : Fetch latest app versions
+account_manager -> rest_service : Fetch account data
+account_manager -> rest_service : Fetch device data, rotate keys
+
+
+@enduml
+
diff --git a/docs/diagrams/readme.md b/docs/diagrams/readme.md
new file mode 100644
index 0000000000..50441c46d0
--- /dev/null
+++ b/docs/diagrams/readme.md
@@ -0,0 +1,6 @@
+# Diagrams
+The diagrams are written for [PlantUML](https://plantuml.com/). The SVG files can be produced via `plantuml -tsvg *.puml`.
+
+The more complex diagrams require a version of PlantUML that uses [eclipses diagramming library](https://plantuml.com/elk),
+this is indicated by the line `!pragma layout elk`.
+
diff --git a/docs/diagrams/set-allow-lan.png b/docs/diagrams/set-allow-lan.png
new file mode 100644
index 0000000000..b34fc78452
--- /dev/null
+++ b/docs/diagrams/set-allow-lan.png
Binary files differ
diff --git a/docs/diagrams/set-allow-lan.puml b/docs/diagrams/set-allow-lan.puml
new file mode 100644
index 0000000000..c4a6ad96bc
--- /dev/null
+++ b/docs/diagrams/set-allow-lan.puml
@@ -0,0 +1,21 @@
+@startuml
+hide empty description
+scale 800
+
+title Execution of ""set_allow_lan"" RPC
+
+participant "Management interface" as management_interface
+participant "Daemon" as daemon
+participant "Settings" as settings
+participant "Tunnel state machine" as tsm
+participant "Daemon event subscribers" as subscribers
+
+management_interface -> daemon : Incoming RPC
+daemon -> settings : Save settings
+daemon -> management_interface : Return save result to RPC
+daemon -> subscribers : Publish new settings to all subscribers
+daemon -> tsm : Send new __allow lan__ setting
+
+
+@enduml
+
diff --git a/docs/diagrams/tsm-connecting-enter.png b/docs/diagrams/tsm-connecting-enter.png
new file mode 100644
index 0000000000..19101cf69c
--- /dev/null
+++ b/docs/diagrams/tsm-connecting-enter.png
Binary files differ
diff --git a/docs/diagrams/tsm-connecting-enter.puml b/docs/diagrams/tsm-connecting-enter.puml
new file mode 100644
index 0000000000..e0964229f6
--- /dev/null
+++ b/docs/diagrams/tsm-connecting-enter.puml
@@ -0,0 +1,26 @@
+@startuml
+hide empty description
+scale 800
+
+state "Entering connecting state" as enter_connecting
+state "Check offline state" as offline
+state "Generate tunnel parameters" as ask_gen_parameters
+state "Set firewall policy" as set_firewall
+state "Spawn tunnel" as spawn_tunnel
+state "Connecting state" as connecting_state
+state "Enter error state" as enter_error
+
+[*] --> enter_connecting
+enter_connecting --> offline : Check offline state
+offline --> ask_gen_parameters : Host is not offline
+offline --> enter_error : Host is offline
+ask_gen_parameters --> set_firewall : Successfully generated parameters
+ask_gen_parameters --> enter_error : Failed to generate tunnel parameters
+set_firewall --> spawn_tunnel : Successfully set firewall policy
+set_firewall --> enter_error : Failed to set firewall policy
+spawn_tunnel -> connecting_state : Start a tunnel monitor and enter connecting state
+
+
+@enduml
+
+state "Starting a tunnel"
diff --git a/docs/diagrams/update-relay-constraints.png b/docs/diagrams/update-relay-constraints.png
new file mode 100644
index 0000000000..25f02ca77d
--- /dev/null
+++ b/docs/diagrams/update-relay-constraints.png
Binary files differ
diff --git a/docs/diagrams/update-relay-constraints.puml b/docs/diagrams/update-relay-constraints.puml
new file mode 100644
index 0000000000..fa4087fe41
--- /dev/null
+++ b/docs/diagrams/update-relay-constraints.puml
@@ -0,0 +1,28 @@
+@startuml
+hide empty description
+scale 800
+
+title Execution of ""update_relay_settings"" RPC when relay settings have changed, but the key is invalid.
+
+participant "Management interface" as management_interface
+participant "Daemon" as daemon
+participant "Settings" as settings
+participant "Relay selector" as relay_selector
+participant "Tunnel state machine" as tsm
+participant "Account manager" as account_manager
+
+management_interface -> daemon : Incoming RPC
+daemon -> settings : Update relay settings
+daemon -> management_interface : Return save result to RPC
+daemon -> management_interface : Publish new settings to all subscribers
+daemon -> relay_selector : Update relay constraints
+daemon -> tsm : Reconnect tunnel
+tsm -> daemon : Request new tunnel parameters
+daemon -> tsm : Send tunnel parameters
+tsm -> daemon : Publish connecting state
+daemon -> management_interface : Publish connecting state
+daemon -> account_manager : Asynchronously verify account state
+account_manager -> daemon : Publish new device state
+daemon -> management_interface : Publish new device state
+
+@enduml