@@ -1133,11 +1133,66 @@ module Dns = struct
1133
1133
1134
1134
let resolve_dnssd question =
1135
1135
let open Dns.Packet in
1136
- let query name ty =
1137
- Uwt_preemptive. detach
1138
- (fun () ->
1139
- Dnssd. query (Dns.Name. to_string name) ty
1140
- ) () in
1136
+ let query_one name ty =
1137
+ let query = Dnssd.LowLevel. query (Dns.Name. to_string name) ty in
1138
+ let socket = Dnssd.LowLevel. socket query in
1139
+ let t, u = Lwt. task () in
1140
+ match Uwt.Poll. start socket [ Uwt.Poll. Readable ]
1141
+ ~cb: (fun _poll events ->
1142
+ match events with
1143
+ | Error error ->
1144
+ Log. err (fun f -> f " Uwt.Poll callback failed with %s" (Uwt. strerror error))
1145
+ | Ok events ->
1146
+ List. iter (fun event ->
1147
+ if event = Uwt.Poll. Readable then Lwt. wakeup_later u ()
1148
+ ) events
1149
+ ) with
1150
+ | Error error ->
1151
+ Log. err (fun f -> f " Uwt.Poll.start failed with %s" (Uwt. strerror error));
1152
+ Lwt. return (Ok [] )
1153
+ | Ok poll ->
1154
+ t >> = fun () ->
1155
+ let result = Uwt.Poll. close poll in
1156
+ if not (Uwt.Int_result. is_ok result) then begin
1157
+ let error = Uwt.Int_result. to_error result in
1158
+ Log. err (fun f -> f " Uwt.Poll.close failed with %s" (Uwt. strerror error));
1159
+ Lwt. return (Ok [] )
1160
+ end else begin
1161
+ Uwt_preemptive. detach
1162
+ (fun () ->
1163
+ Dnssd.LowLevel. response query
1164
+ ) ()
1165
+ end in
1166
+
1167
+ let query requested_name ty =
1168
+ (* The DNSServiceRef API will return CNAMEs first, without resolving to
1169
+ A/AAAA/... This function recursively resolves the CNAMES while avoiding
1170
+ returning duplicate records. *)
1171
+ (* NB we only return NoSuchRecord if we find no records. This is because it
1172
+ is possible to query a CNAME which exists, but which points to a non-existent
1173
+ record. *)
1174
+ let open Dnssd in
1175
+ let rec loop acc name ty =
1176
+ query_one name ty
1177
+ >> = function
1178
+ (* When we're recursing, ignore the NoSuchRecord error *)
1179
+ | Error NoSuchRecord when name <> requested_name -> Lwt. return (Ok acc)
1180
+ | Error e -> Lwt. return (Error e)
1181
+ | Ok rrs ->
1182
+ let not_seen_before = List. filter (fun x -> not (List. mem x acc)) rrs in
1183
+ (* If there are any CNAMEs, resolve these too *)
1184
+ let cnames = List. rev @@ List. fold_left (fun acc rr ->
1185
+ match rr.Dns.Packet. rdata with
1186
+ | CNAME name -> name :: acc
1187
+ | _ -> acc
1188
+ ) [] not_seen_before in
1189
+ Lwt_list. fold_left_s
1190
+ (fun acc name -> match acc with
1191
+ | Error e -> Lwt. return (Error e)
1192
+ | Ok acc ->
1193
+ loop acc name ty
1194
+ ) (Ok (acc @ not_seen_before)) cnames in
1195
+ loop [] requested_name ty in
1141
1196
1142
1197
begin match question with
1143
1198
| { q_class = Q_IN ; q_name; _ } when q_name = localhost_local ->
0 commit comments