forked from talex5/qubes-mirage-firewall
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunikernel.ml
85 lines (79 loc) · 3.07 KB
/
unikernel.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
(* Copyright (C) 2015, Thomas Leonard <[email protected]>
See the README file for details. *)
open Lwt
open Qubes
let src = Logs.Src.create "unikernel" ~doc:"Main unikernel code"
module Log = (val Logs.src_log src : Logs.LOG)
module Main (Clock : Mirage_clock_lwt.MCLOCK) = struct
module Uplink = Uplink.Make(Clock)
(* Set up networking and listen for incoming packets. *)
let network ~clock nat qubesDB =
(* Read configuration from QubesDB *)
let config = Dao.read_network_config qubesDB in
(* Initialise connection to NetVM *)
Uplink.connect ~clock config >>= fun uplink ->
(* Report success *)
Dao.set_iptables_error qubesDB "" >>= fun () ->
(* Set up client-side networking *)
let client_eth = Client_eth.create
~client_gw:config.Dao.clients_our_ip in
(* Set up routing between networks and hosts *)
let router = Router.create
~client_eth
~uplink:(Uplink.interface uplink)
~nat
in
(* Handle packets from both networks *)
Lwt.choose [
Client_net.listen router;
Uplink.listen uplink router
]
(* We don't use the GUI, but it's interesting to keep an eye on it.
If the other end dies, don't let it take us with it (can happen on logout). *)
let watch_gui gui =
Lwt.async (fun () ->
Lwt.try_bind
(fun () ->
gui >>= fun gui ->
Log.info (fun f -> f "GUI agent connected");
GUI.listen gui
)
(fun `Cant_happen -> assert false)
(fun ex ->
Log.warn (fun f -> f "GUI thread failed: %s" (Printexc.to_string ex));
return ()
)
)
(* Main unikernel entry point (called from auto-generated main.ml). *)
let start clock =
let start_time = Clock.elapsed_ns clock in
(* Start qrexec agent, GUI agent and QubesDB agent in parallel *)
let qrexec = RExec.connect ~domid:0 () in
GUI.connect ~domid:0 () |> watch_gui;
let qubesDB = DB.connect ~domid:0 () in
(* Wait for clients to connect *)
qrexec >>= fun qrexec ->
let agent_listener = RExec.listen qrexec Command.handler in
qubesDB >>= fun qubesDB ->
let startup_time =
let (-) = Int64.sub in
let time_in_ns = Clock.elapsed_ns clock - start_time in
Int64.to_float time_in_ns /. 1e9
in
Log.info (fun f -> f "QubesDB and qrexec agents connected in %.3f s" startup_time);
(* Watch for shutdown requests from Qubes *)
let shutdown_rq =
OS.Lifecycle.await_shutdown_request () >>= fun (`Poweroff | `Reboot) ->
return () in
(* Set up networking *)
let get_time () = Clock.elapsed_ns clock in
let max_entries = Key_gen.nat_table_size () in
My_nat.create ~get_time ~max_entries >>= fun nat ->
let net_listener = network ~clock nat qubesDB in
(* Report memory usage to XenStore *)
Memory_pressure.init ();
(* Run until something fails or we get a shutdown request. *)
Lwt.choose [agent_listener; net_listener; shutdown_rq] >>= fun () ->
(* Give the console daemon time to show any final log messages. *)
OS.Time.sleep_ns (1.0 *. 1e9 |> Int64.of_float)
end