Skip to content

Commit d159f5f

Browse files
committed
dns-client(eio): add tcp/tls nameserver support
1 parent 789a97f commit d159f5f

File tree

4 files changed

+64
-22
lines changed

4 files changed

+64
-22
lines changed

dns-client-eio.opam

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,20 @@ build: [
1515
depends: [
1616
"dune" {>="3.2"}
1717
"cstruct" {>= "6.0.0"}
18+
"duration" {>= "0.2.1"}
1819
"base-domains"
1920
"ipaddr" {>= "5.3.0"}
2021
"dns-client" {>= version}
21-
"mirage-clock" {>= "3.0.0"}
22+
"dns-client.resolvconf" {>= version}
23+
"happy-eyeballs" {>= "0.3.0"}
2224
"mtime" {>= "1.2.0"}
2325
"mirage-crypto-rng-eio" {>= "0.10.7"}
2426
"domain-name" {>= "0.4.0"}
25-
"mtime" {>= "1.2.0"}
2627
"fmt" {>= "0.8.8"}
27-
"eio_main" {>= "0.5"}
28+
"logs" {>= "0.7.0"}
29+
"eio" {>= "0.7.0"}
30+
"tls-eio" {>= "0.15.5"}
31+
"ca-certs" {>= "0.2.3"}
2832
]
2933
synopsis: "DNS client for eio"
3034
description: """

eio/client/dns_client_eio.ml

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ type 'a env = <
77
..
88
> as 'a
99

10-
type io_addr = Ipaddr.t * int
10+
type io_addr = [`Plaintext of Ipaddr.t * int | `Tls of Tls.Config.client * Ipaddr.t * int]
1111
type stack = {
1212
sw : Eio.Switch.t;
1313
mono_clock : Eio.Time.Mono.t;
@@ -40,7 +40,7 @@ module Transport : Dns_client.S
4040
and context =
4141
{ t : t
4242
; mutable requests : Cstruct.t Eio.Promise.u IM.t
43-
; mutable ns_connection: <Eio.Net.stream_socket; Eio.Flow.close>
43+
; mutable ns_connection: <Eio.Flow.two_way>
4444
; mutable buf : Cstruct.t
4545
}
4646

@@ -64,16 +64,35 @@ module Transport : Dns_client.S
6464
let ( let* ) = Result.bind
6565
let ( let+ ) r f = Result.map f r
6666

67+
let authenticator =
68+
let authenticator_ref = ref None in
69+
fun () ->
70+
match !authenticator_ref with
71+
| Some x -> x
72+
| None -> match Ca_certs.authenticator () with
73+
| Ok a -> authenticator_ref := Some a ; a
74+
| Error `Msg m -> invalid_arg ("failed to load trust anchors: " ^ m)
75+
6776
let decode_resolv_conf data =
6877
let* ips = Dns_resolvconf.parse data in
78+
let authenticator = authenticator () in
6979
match ips with
7080
| [] -> Error (`Msg "empty nameservers from resolv.conf")
71-
| ips -> Ok (List.map (function `Nameserver ip -> (ip, 53)) ips)
81+
| ips ->
82+
List.map
83+
(function `Nameserver ip ->
84+
let tls_config = Tls.Config.client ~authenticator ~ip () in
85+
[`Plaintext (ip, 53); `Tls (tls_config, ip, 853)]
86+
)
87+
ips
88+
|> List.flatten
89+
|> Result.ok
7290

73-
let default_resolvers =
74-
List.(map
75-
(fun ip -> (ip, 53))
76-
((::) (Ipaddr.of_string_exn "1.1.1.1", Dns_client.default_resolvers)))
91+
let default_resolvers () =
92+
let authenticator = authenticator () in
93+
let peer_name = Dns_client.default_resolver_hostname in
94+
let tls_config = Tls.Config.client ~authenticator ~peer_name () in
95+
List.map (fun ip -> `Tls (tls_config, ip, 853)) Dns_client.default_resolvers
7796

7897
let rng = Mirage_crypto_rng.generate ?g:None
7998
let clock = Mtime_clock.elapsed_ns
@@ -82,14 +101,14 @@ module Transport : Dns_client.S
82101
{ nameservers =
83102
(match nameservers with
84103
| Some (`Udp,_) -> invalid_arg "UDP is not supported"
85-
| Some (`Tcp, []) -> Static default_resolvers
104+
| Some (`Tcp, []) -> Static (default_resolvers ())
86105
| Some (`Tcp, ns) -> Static ns
87106
| None ->
88107
(let* data = read_file stack.resolv_conf in
89108
let+ ips = decode_resolv_conf data in
90109
(ips, Some (Digest.string data)))
91110
|> function
92-
| Error _ -> Resolv_conf { ips = default_resolvers; digest = None}
111+
| Error _ -> Resolv_conf { ips = default_resolvers (); digest = None}
93112
| Ok(ips, digest) -> Resolv_conf {ips; digest})
94113
; stack
95114
; timeout = Eio.Time.Timeout.v stack.mono_clock @@ Mtime.Span.of_uint64_ns timeout
@@ -112,7 +131,7 @@ module Transport : Dns_client.S
112131
resolv_conf.ips <- ips;
113132
| Error _ ->
114133
resolv_conf.digest <- None;
115-
resolv_conf.ips <- default_resolvers
134+
resolv_conf.ips <- default_resolvers ()
116135
in
117136
match t.nameservers with
118137
| Static _ -> ()
@@ -125,9 +144,16 @@ module Transport : Dns_client.S
125144
| Error _, None -> ()
126145
| Error _, Some _ ->
127146
resolv_conf.digest <- None;
128-
resolv_conf.ips <- default_resolvers)
147+
resolv_conf.ips <- default_resolvers ())
148+
149+
let find_ns t (ip, port) =
150+
List.find
151+
(function `Plaintext (ip', p)
152+
| `Tls (_, ip', p) -> Ipaddr.compare ip ip' = 0 && p = port
153+
)
154+
(nameserver_ips t)
129155

130-
let rec he_handle_actions t he actions =
156+
let rec he_handle_actions t he actions : #Eio.Flow.two_way option =
131157
let fiber_of_action = function
132158
| Happy_eyeballs.Connect (host, id, (ip, port)) ->
133159
fun () ->
@@ -144,6 +170,11 @@ module Transport : Dns_client.S
144170
let flow = Eio.Net.connect ~sw:t.stack.sw t.stack.net stream in
145171
Log.debug (fun m -> m "he_handle_actions: connected to nameserver (%a)"
146172
Fmt.(pair ~sep:comma Ipaddr.pp int) (ip, port));
173+
let flow =
174+
match find_ns t (ip, port) with
175+
| `Plaintext _ -> (flow :> Eio.Flow.two_way)
176+
| `Tls (config, _,_) -> (Tls_eio.client_of_flow config flow :> Eio.Flow.two_way)
177+
in
147178
Some flow)
148179
with Eio.Time.Timeout ->
149180
Log.debug (fun m -> m "he_handle_actions: connection to nameserver (%a) timed out"
@@ -163,6 +194,9 @@ module Transport : Dns_client.S
163194
in
164195
Eio.Fiber.any (List.map fiber_of_action actions)
165196

197+
let to_ip_port =
198+
List.map (function `Plaintext (ip, port) -> (ip, port) | `Tls (_, ip, port) -> (ip, port))
199+
166200
let rec connect t =
167201
Log.debug (fun m -> m "connect : establishing connection to nameservers");
168202
match t.ctx, t.ns_connection_condition with
@@ -174,15 +208,15 @@ module Transport : Dns_client.S
174208
let ns_connection_condition = Eio.Condition.create () in
175209
t.ns_connection_condition <- Some ns_connection_condition;
176210
maybe_update_nameservers t;
177-
let ns = nameserver_ips t in
211+
let ns = to_ip_port @@ nameserver_ips t in
178212
let he = Happy_eyeballs.create (clock ()) in
179213
let he, actions = Happy_eyeballs.connect_ip he (clock ()) ~id:1 ns in
180214
begin match he_handle_actions t he actions with
181-
| Some ns_connection ->
215+
| Some conn ->
182216
let context =
183217
{ t = t
184218
; requests = IM.empty
185-
; ns_connection
219+
; ns_connection = conn
186220
; buf = Cstruct.empty
187221
}
188222
in
@@ -195,7 +229,7 @@ module Transport : Dns_client.S
195229
let error_msg =
196230
Fmt.str "unable to connect to nameservers %a"
197231
Fmt.(list ~sep:(any ", ") (pair ~sep:(any ":") Ipaddr.pp int))
198-
(nameserver_ips t)
232+
(to_ip_port @@ nameserver_ips t)
199233
in
200234
Logs.debug (fun m -> m "connect : %s" error_msg);
201235
Error (`Msg error_msg)
@@ -249,7 +283,7 @@ module Transport : Dns_client.S
249283
Error (`Msg "Invalid DNS query packet (data length <= 4)")
250284

251285
let send_recv ctx packet =
252-
let* () = validate_query_packet packet in
286+
let* () = validate_query_packet packet in
253287
try
254288
let request_id = Cstruct.BE.get_uint16 packet 2 in
255289
Eio.Time.Timeout.run_exn ctx.t.timeout (fun () ->

eio/client/dns_client_eio.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type 'a env = <
88
> as 'a
99

1010
module Transport : Dns_client.S
11-
with type io_addr = Ipaddr.t * int
11+
with type io_addr = [`Plaintext of Ipaddr.t * int | `Tls of Tls.Config.client * Ipaddr.t * int]
1212
and type +'a io = 'a
1313

1414
include module type of Dns_client.Make(Transport)

eio/client/dune

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
mtime
1313
mtime.clock.os
1414
mirage-crypto-rng
15-
mirage-crypto-rng-eio))
15+
mirage-crypto-rng-eio
16+
domain-name
17+
ca-certs
18+
eio
19+
tls-eio))
1620

1721
(executable
1822
(name ohost)

0 commit comments

Comments
 (0)