2020-04-29 10:06:48 -04:00
|
|
|
open Lwt.Infix
|
|
|
|
|
2022-03-30 03:12:01 -04:00
|
|
|
module Transport (R : Mirage_random.S) (C : Mirage_clock.MCLOCK) (Time : Mirage_time.S) = struct
|
2020-04-29 10:06:48 -04:00
|
|
|
type +'a io = 'a Lwt.t
|
|
|
|
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
|
|
|
|
|
2022-11-11 06:07:06 -05:00
|
|
|
module IM = Map.Make(Int)
|
|
|
|
|
2020-04-29 10:06:48 -04:00
|
|
|
type t = {
|
2021-11-10 09:26:17 -05:00
|
|
|
protocol : Dns.proto ;
|
|
|
|
nameserver : io_addr ;
|
2020-04-29 10:06:48 -04:00
|
|
|
stack : stack ;
|
|
|
|
timeout_ns : int64 ;
|
2022-11-11 06:07:06 -05:00
|
|
|
mutable requests : Cstruct.t Lwt_condition.t IM.t ;
|
2020-04-29 10:06:48 -04:00
|
|
|
}
|
2021-11-10 12:16:55 -05:00
|
|
|
type context = t
|
2020-04-29 10:06:48 -04:00
|
|
|
|
2021-11-10 09:26:17 -05:00
|
|
|
let nameservers { protocol ; nameserver ; _ } = protocol, [ nameserver ]
|
2020-04-29 10:06:48 -04:00
|
|
|
let rng = R.generate ?g:None
|
|
|
|
let clock = C.elapsed_ns
|
|
|
|
|
2022-11-11 06:07:06 -05:00
|
|
|
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
|
|
|
|
|
2021-11-10 09:26:17 -05:00
|
|
|
let create ?nameservers ~timeout stack =
|
|
|
|
let protocol, nameserver = match nameservers with
|
|
|
|
| None | Some (_, []) -> invalid_arg "no nameserver found"
|
|
|
|
| Some (proto, ns :: _) -> proto, ns
|
|
|
|
in
|
2022-11-11 06:07:06 -05:00
|
|
|
let t =
|
|
|
|
{ protocol ; nameserver ; stack ; timeout_ns = timeout ; requests = IM.empty }
|
|
|
|
in
|
|
|
|
Lwt.async (fun () -> read t);
|
|
|
|
t
|
2020-04-29 10:06:48 -04:00
|
|
|
|
2021-11-10 12:16:55 -05:00
|
|
|
let with_timeout timeout_ns f =
|
2022-03-30 03:12:01 -04:00
|
|
|
let timeout = Time.sleep_ns timeout_ns >|= fun () -> Error (`Msg "DNS request timeout") in
|
2021-11-10 12:16:55 -05:00
|
|
|
Lwt.pick [ f ; timeout ]
|
2020-04-29 10:06:48 -04:00
|
|
|
|
2022-10-27 05:24:59 -04:00
|
|
|
let connect (t : t) = Lwt.return (Ok (t.protocol, t))
|
2020-04-29 10:06:48 -04:00
|
|
|
|
2021-11-10 12:16:55 -05:00
|
|
|
let send_recv (ctx : context) buf : (Cstruct.t, [> `Msg of string ]) result Lwt.t =
|
2020-04-29 10:06:48 -04:00
|
|
|
let open Router in
|
2021-11-10 12:16:55 -05:00
|
|
|
let dst, dst_port = ctx.nameserver in
|
2022-11-11 06:07:06 -05:00
|
|
|
let router, send_udp, _ = ctx.stack in
|
2022-10-08 04:50:29 -04:00
|
|
|
let src_port, evict =
|
|
|
|
My_nat.free_udp_port router.nat ~src:router.uplink#my_ip ~dst ~dst_port:53
|
|
|
|
in
|
2022-11-11 06:07:06 -05:00
|
|
|
let id = Cstruct.BE.get_uint16 buf 0 in
|
2021-11-10 12:16:55 -05:00
|
|
|
with_timeout ctx.timeout_ns
|
2022-11-11 06:07:06 -05:00
|
|
|
(let cond = Lwt_condition.create () in
|
|
|
|
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 ->
|
|
|
|
ctx.requests <- IM.remove id ctx.requests;
|
2022-10-08 04:50:29 -04:00
|
|
|
evict ();
|
2020-04-29 10:06:48 -04:00
|
|
|
result
|
|
|
|
|
|
|
|
let close _ = Lwt.return_unit
|
|
|
|
|
|
|
|
let bind = Lwt.bind
|
|
|
|
|
|
|
|
let lift = Lwt.return
|
|
|
|
end
|
|
|
|
|