Merge pull request #163 from hannesm/next

Next release: 0.8.3
This commit is contained in:
Hannes Mehnert 2022-11-11 16:43:26 +01:00 committed by GitHub
commit ee45c7ba3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 104 additions and 85 deletions

View File

@ -1,3 +1,23 @@
### 0.8.3 (2022-11-11)
- Fix "DNS issues", a firewall ruleset with a domain name lead to 100% CPU usage
(reported by fiftyfourthparallel on
https://forum.qubes-os.org/t/mirage-firewall-0-8-2-broken-new-users-should-install-0-8-1/14566,
re-reported by @palainp in #158, fixed by @hannesm in mirage/mirage-nat#48
(release 3.0.1)) - underlying issue was a wrong definition of `is_port_free`
(since 3.0.0, used since mirage-qubes-firewall 0.8.2).
- Fix "crash on downstream vm start", after more than 64 client VMs have been
connected and disconnected with the qubes-mirage-firewall (reported by @xaki23
in #155, fixed by @hannesm in #161) - underlying issue was a leak of xenstore
watchers and a hard limit in xen on the amount of watchers
- Fix "detach netvm fails" (reported by @rootnoob in #157, fixed by @palainp
in mirage/mirage-net-xen#105 (release 2.1.2)) - underlying issue was that the
network interface state was never set to closed, but directly removed
- Fix potential DoS in handling DNS replies (#162 @hannesm)
- Avoid potential forever loop in My_nat.free_udp_port (#159 @hannesm)
- Assorted code removals (#161 @hannesm)
- Update to dns 6.4.0 changes (#154, @hannesm)
### 0.8.2 (2022-10-12) ### 0.8.2 (2022-10-12)
- Advise to use 32 MB memory, which is sufficient (#150, @palainp) - Advise to use 32 MB memory, which is sufficient (#150, @palainp)

View File

@ -11,9 +11,9 @@ RUN sudo ln -sf /usr/bin/opam-2.1 /usr/bin/opam
# Pin last known-good version for reproducible builds. # Pin last known-good version for reproducible builds.
# Remove this line (and the base image pin above) if you want to test with the # Remove this line (and the base image pin above) if you want to test with the
# latest versions. # latest versions.
RUN cd /home/opam/opam-repository && git fetch origin master && git reset --hard 7b89f6e5c24cf4076252e71abcbbe4d205705627 && opam update RUN cd /home/opam/opam-repository && git fetch origin master && git reset --hard 685eb4efcebfa671660e55d76dea017f00fed4d9 && opam update
RUN opam install -y mirage opam-monorepo RUN opam install -y mirage opam-monorepo ocaml-solo5
RUN mkdir /home/opam/qubes-mirage-firewall RUN mkdir /home/opam/qubes-mirage-firewall
ADD config.ml /home/opam/qubes-mirage-firewall/config.ml ADD config.ml /home/opam/qubes-mirage-firewall/config.ml
WORKDIR /home/opam/qubes-mirage-firewall WORKDIR /home/opam/qubes-mirage-firewall

View File

@ -5,5 +5,5 @@ docker build -t qubes-mirage-firewall .
echo Building Firewall... echo Building Firewall...
docker run --rm -i -v `pwd`:/home/opam/qubes-mirage-firewall qubes-mirage-firewall docker run --rm -i -v `pwd`:/home/opam/qubes-mirage-firewall qubes-mirage-firewall
echo "SHA2 of build: $(sha256sum ./dist/qubes-firewall.xen)" echo "SHA2 of build: $(sha256sum ./dist/qubes-firewall.xen)"
echo "SHA2 last known: 88fdd86993dfbd2e2c4a4d502c350bef091d7831405cf983aebe85f936799f2d" echo "SHA2 last known: f499b2379c62917ac32854be63f201e6b90466e645e54dea51e376baccdf26ab"
echo "(hashes should match for released versions)" echo "(hashes should match for released versions)"

View File

@ -24,11 +24,11 @@ let main =
package ~min:"2.3.0" ~sublibs:["mirage"] "arp"; package ~min:"2.3.0" ~sublibs:["mirage"] "arp";
package ~min:"3.0.0" "ethernet"; package ~min:"3.0.0" "ethernet";
package "shared-memory-ring" ~min:"3.0.0"; package "shared-memory-ring" ~min:"3.0.0";
package "netchannel" ~min:"1.11.0"; package ~min:"2.1.2" "netchannel";
package "mirage-net-xen"; package "mirage-net-xen";
package "ipaddr" ~min:"5.2.0"; package "ipaddr" ~min:"5.2.0";
package "mirage-qubes" ~min:"0.9.1"; package "mirage-qubes" ~min:"0.9.1";
package "mirage-nat" ~min:"3.0.0"; package ~min:"3.0.1" "mirage-nat";
package "mirage-logs"; package "mirage-logs";
package "mirage-xen" ~min:"8.0.0"; package "mirage-xen" ~min:"8.0.0";
package ~min:"6.4.0" "dns-client"; package ~min:"6.4.0" "dns-client";

8
dao.ml
View File

@ -65,11 +65,12 @@ let read_rules rules client_ip =
icmp_type = None; icmp_type = None;
number = 0;})] number = 0;})]
let vifs ~handle domid = let vifs client domid =
match String.to_int domid with match String.to_int domid with
| None -> Log.err (fun f -> f "Invalid domid %S" domid); Lwt.return [] | None -> Log.err (fun f -> f "Invalid domid %S" domid); Lwt.return []
| Some domid -> | Some domid ->
let path = Printf.sprintf "backend/vif/%d" domid in let path = Printf.sprintf "backend/vif/%d" domid in
Xen_os.Xs.immediate client (fun handle ->
directory ~handle path >>= directory ~handle path >>=
Lwt_list.filter_map_p (fun device_id -> Lwt_list.filter_map_p (fun device_id ->
match String.to_int device_id with match String.to_int device_id with
@ -101,7 +102,7 @@ let vifs ~handle domid =
ClientVif.pp vif (Printexc.to_string ex)); ClientVif.pp vif (Printexc.to_string ex));
Lwt.return None Lwt.return None
) )
) ))
let watch_clients fn = let watch_clients fn =
Xen_os.Xs.make () >>= fun xs -> Xen_os.Xs.make () >>= fun xs ->
@ -114,7 +115,8 @@ let watch_clients fn =
| Xs_protocol.Enoent _ -> Lwt.return [] | Xs_protocol.Enoent _ -> Lwt.return []
| ex -> Lwt.fail ex) | ex -> Lwt.fail ex)
end >>= fun items -> end >>= fun items ->
Lwt_list.map_p (vifs ~handle) items >>= fun items -> Xen_os.Xs.make () >>= fun xs ->
Lwt_list.map_p (vifs xs) items >>= fun items ->
fn (List.concat items |> VifMap.of_list); fn (List.concat items |> VifMap.of_list);
(* Wait for further updates *) (* Wait for further updates *)
Lwt.fail Xs_protocol.Eagain Lwt.fail Xs_protocol.Eagain

View File

@ -10,14 +10,6 @@ module IpMap = struct
with Not_found -> None with Not_found -> None
end end
module Int = struct
type t = int
let compare (a:t) (b:t) = compare a b
end
module IntSet = Set.Make(Int)
module IntMap = Map.Make(Int)
(** An Ethernet interface. *) (** An Ethernet interface. *)
class type interface = object class type interface = object
method my_mac : Macaddr.t method my_mac : Macaddr.t

View File

@ -36,21 +36,6 @@ let report_mem_usage stats =
) )
) )
let print_mem_usage =
let rec aux () =
let stats = Xen_os.Memory.quick_stat () in
let { Xen_os.Memory.free_words; heap_words; _ } = stats in
let mem_total = heap_words * wordsize_in_bytes in
let mem_free = free_words * wordsize_in_bytes in
Log.info (fun f -> f "Memory usage: free %a / %a (%.2f %%)"
Fmt.bi_byte_size mem_free
Fmt.bi_byte_size mem_total
(fraction_free stats *. 100.0));
Xen_os.Time.sleep_ns (Duration.of_f 600.0) >>= fun () ->
aux ()
in
aux ()
let init () = let init () =
Gc.full_major (); Gc.full_major ();
let stats = Xen_os.Memory.quick_stat () in let stats = Xen_os.Memory.quick_stat () in

View File

@ -5,11 +5,14 @@ module Transport (R : Mirage_random.S) (C : Mirage_clock.MCLOCK) (Time : Mirage_
type io_addr = Ipaddr.V4.t * int type io_addr = Ipaddr.V4.t * int
type stack = Router.t * (src_port:int -> dst:Ipaddr.V4.t -> dst_port:int -> Cstruct.t -> (unit, [ `Msg of string ]) result Lwt.t) * (Udp_packet.t * Cstruct.t) Lwt_mvar.t type stack = Router.t * (src_port:int -> dst:Ipaddr.V4.t -> dst_port:int -> Cstruct.t -> (unit, [ `Msg of string ]) result Lwt.t) * (Udp_packet.t * Cstruct.t) Lwt_mvar.t
module IM = Map.Make(Int)
type t = { type t = {
protocol : Dns.proto ; protocol : Dns.proto ;
nameserver : io_addr ; nameserver : io_addr ;
stack : stack ; stack : stack ;
timeout_ns : int64 ; timeout_ns : int64 ;
mutable requests : Cstruct.t Lwt_condition.t IM.t ;
} }
type context = t type context = t
@ -17,12 +20,26 @@ module Transport (R : Mirage_random.S) (C : Mirage_clock.MCLOCK) (Time : Mirage_
let rng = R.generate ?g:None let rng = R.generate ?g:None
let clock = C.elapsed_ns let clock = C.elapsed_ns
let rec read t =
let _, _, answer = t.stack in
Lwt_mvar.take answer >>= fun (_, data) ->
if Cstruct.length data > 2 then begin
match IM.find_opt (Cstruct.BE.get_uint16 data 0) t.requests with
| Some cond -> Lwt_condition.broadcast cond data
| None -> ()
end;
read t
let create ?nameservers ~timeout stack = let create ?nameservers ~timeout stack =
let protocol, nameserver = match nameservers with let protocol, nameserver = match nameservers with
| None | Some (_, []) -> invalid_arg "no nameserver found" | None | Some (_, []) -> invalid_arg "no nameserver found"
| Some (proto, ns :: _) -> proto, ns | Some (proto, ns :: _) -> proto, ns
in in
{ protocol ; nameserver ; stack ; timeout_ns = timeout } let t =
{ protocol ; nameserver ; stack ; timeout_ns = timeout ; requests = IM.empty }
in
Lwt.async (fun () -> read t);
t
let with_timeout timeout_ns f = let with_timeout timeout_ns f =
let timeout = Time.sleep_ns timeout_ns >|= fun () -> Error (`Msg "DNS request timeout") in let timeout = Time.sleep_ns timeout_ns >|= fun () -> Error (`Msg "DNS request timeout") in
@ -32,16 +49,19 @@ module Transport (R : Mirage_random.S) (C : Mirage_clock.MCLOCK) (Time : Mirage_
let send_recv (ctx : context) buf : (Cstruct.t, [> `Msg of string ]) result Lwt.t = let send_recv (ctx : context) buf : (Cstruct.t, [> `Msg of string ]) result Lwt.t =
let open Router in let open Router in
let open My_nat in
let dst, dst_port = ctx.nameserver in let dst, dst_port = ctx.nameserver in
let router, send_udp, answer = ctx.stack in let router, send_udp, _ = ctx.stack in
let src_port, evict = let src_port, evict =
My_nat.free_udp_port router.nat ~src:router.uplink#my_ip ~dst ~dst_port:53 My_nat.free_udp_port router.nat ~src:router.uplink#my_ip ~dst ~dst_port:53
in in
let id = Cstruct.BE.get_uint16 buf 0 in
with_timeout ctx.timeout_ns with_timeout ctx.timeout_ns
((send_udp ~src_port ~dst ~dst_port buf >|= Rresult.R.open_error_msg) >>= function (let cond = Lwt_condition.create () in
| Ok () -> (Lwt_mvar.take answer >|= fun (_, dns_response) -> Ok dns_response) ctx.requests <- IM.add id cond ctx.requests;
(send_udp ~src_port ~dst ~dst_port buf >|= Rresult.R.open_error_msg) >>= function
| Ok () -> Lwt_condition.wait cond >|= fun dns_response -> Ok dns_response
| Error _ as e -> Lwt.return e) >|= fun result -> | Error _ as e -> Lwt.return e) >|= fun result ->
ctx.requests <- IM.remove id ctx.requests;
evict (); evict ();
result result

View File

@ -1,8 +1,6 @@
(* Copyright (C) 2015, Thomas Leonard <thomas.leonard@unikernel.com> (* Copyright (C) 2015, Thomas Leonard <thomas.leonard@unikernel.com>
See the README file for details. *) See the README file for details. *)
open Lwt.Infix
let src = Logs.Src.create "my-nat" ~doc:"NAT shim" let src = Logs.Src.create "my-nat" ~doc:"NAT shim"
module Log = (val Logs.src_log src : Logs.LOG) module Log = (val Logs.src_log src : Logs.LOG)
@ -46,7 +44,10 @@ let pick_free_port t proto =
go 10 go 10
let free_udp_port t ~src ~dst ~dst_port = let free_udp_port t ~src ~dst ~dst_port =
let rec go () = let rec go retries =
if retries = 0 then
t.last_resort_port, Fun.id
else
let src_port = let src_port =
Option.value ~default:t.last_resort_port (pick_free_port t `Udp) Option.value ~default:t.last_resort_port (pick_free_port t `Udp)
in in
@ -59,9 +60,9 @@ let free_udp_port t ~src ~dst ~dst_port =
in in
src_port, remove src_port, remove
end else end else
go () go (retries - 1)
in in
go () go 10
let dns_port t port = S.mem port t.udp_dns || port = t.last_resort_port let dns_port t port = S.mem port t.udp_dns || port = t.last_resort_port

View File

@ -5,7 +5,6 @@
open Fw_utils open Fw_utils
[@@@ocaml.warning "-67"]
module Make (R: Mirage_random.S)(Clock : Mirage_clock.MCLOCK)(Time : Mirage_time.S) : sig module Make (R: Mirage_random.S)(Clock : Mirage_clock.MCLOCK)(Time : Mirage_time.S) : sig
type t type t