qubes-mirage-firewall/dao.ml
Thomas Leonard 312627e078 Monitor set of client interfaces, not client domains
Qubes does not remove the client directory itself when the domain exits.
Combined with 63cbb4bed0, this prevented clients from reconnecting.

This may also make it possible to connect clients to the firewall via
multiple interfaces, although this doesn't seem useful.
2016-10-01 16:11:16 +01:00

99 lines
3.2 KiB
OCaml

(* Copyright (C) 2015, Thomas Leonard <thomas.leonard@unikernel.com>
See the README file for details. *)
open Lwt.Infix
open Utils
open Qubes
open Astring
let src = Logs.Src.create "dao" ~doc:"QubesDB data access"
module Log = (val Logs.src_log src : Logs.LOG)
module ClientVif = struct
type t = {
domid : int;
device_id : int;
}
let pp f { domid; device_id } = Fmt.pf f "{domid=%d;device_id=%d}" domid device_id
let compare = compare
end
module VifMap = struct
include Map.Make(ClientVif)
let rec of_list = function
| [] -> empty
| (k, v) :: rest -> add k v (of_list rest)
let find key t =
try Some (find key t)
with Not_found -> None
end
let directory ~handle dir =
OS.Xs.directory handle dir >|= function
| [""] -> [] (* XenStore client bug *)
| items -> items
let vifs ~handle domid =
match String.to_int domid with
| None -> Log.err (fun f -> f "Invalid domid %S" domid); Lwt.return []
| Some domid ->
let path = Printf.sprintf "backend/vif/%d" domid in
directory ~handle path >>=
Lwt_list.filter_map_p (fun device_id ->
match String.to_int device_id with
| None -> Log.err (fun f -> f "Invalid device ID %S for domid %d" device_id domid); Lwt.return_none
| Some device_id ->
let vif = { ClientVif.domid; device_id } in
Lwt.try_bind
(fun () -> OS.Xs.read handle (Printf.sprintf "%s/%d/ip" path device_id))
(fun client_ip ->
let client_ip = Ipaddr.V4.of_string_exn client_ip in
Lwt.return (Some (vif, client_ip))
)
(function
| Xs_protocol.Enoent _ -> Lwt.return None
| ex ->
Log.err (fun f -> f "Error getting IP address of %a: %s"
ClientVif.pp vif (Printexc.to_string ex));
Lwt.return None
)
)
let watch_clients fn =
OS.Xs.make () >>= fun xs ->
let backend_vifs = "backend/vif" in
Log.info (fun f -> f "Watching %s" backend_vifs);
OS.Xs.wait xs (fun handle ->
begin Lwt.catch
(fun () -> directory ~handle backend_vifs)
(function
| Xs_protocol.Enoent _ -> return []
| ex -> fail ex)
end >>= fun items ->
Lwt_list.map_p (vifs ~handle) items >>= fun items ->
fn (List.concat items |> VifMap.of_list);
(* Wait for further updates *)
fail Xs_protocol.Eagain
)
type network_config = {
uplink_netvm_ip : Ipaddr.V4.t; (* The IP address of NetVM (our gateway) *)
uplink_our_ip : Ipaddr.V4.t; (* The IP address of our interface to NetVM *)
clients_our_ip : Ipaddr.V4.t; (* The IP address of our interface to our client VMs (their gateway) *)
}
(* TODO: /qubes-secondary-dns *)
let read_network_config qubesDB =
let get name =
match DB.read qubesDB name with
| None -> raise (error "QubesDB key %S not present" name)
| Some value -> value in
let uplink_our_ip = get "/qubes-ip" |> Ipaddr.V4.of_string_exn in
let uplink_netvm_ip = get "/qubes-gateway" |> Ipaddr.V4.of_string_exn in
let clients_our_ip = get "/qubes-netvm-gateway" |> Ipaddr.V4.of_string_exn in
{ uplink_netvm_ip; uplink_our_ip; clients_our_ip }
let set_iptables_error db = Qubes.DB.write db "/qubes-iptables-error"