This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,196 @@
(* TODO ideally there'd be something like mirage-flow-lwt that didn't depend
on lwt and a ton of other things, and still provided [map]
and [connect] and so on. leaving this stuff here for now until a
better solution presents itself. *)
val default_resolver_hostname : [`host] Domain_name.t
val default_resolvers : Ipaddr.t list
(** [default_resolver] is a list of IPv6 and IPv4 address of the default
resolver. Currently it is the IP address of the UncensoredDNS.org
anycast service. *)
module type S = sig
type context
(** A context is a network connection initialized by {!connect} *)
type +'a io
(** [io] is the type of an effect. ['err] is a polymorphic variant. *)
type io_addr
(** An address for a given context type, usually this will consist of
IP address + a TCP/IP or UDP/IP port number, but for some context types
it can carry additional information for purposes of cryptographic
verification. *)
type stack
(** A stack with which to connect. *)
type t
(** The abstract state of a DNS client. *)
val create : ?nameservers:(Dns.proto * io_addr list) -> timeout:int64 ->
stack -> t
(** [create ~nameservers ~timeout stack] creates the state record of
the DNS client. We use [timeout] (ns) as a cumulative time budget for
connect and request timeouts. *)
val nameservers : t -> Dns.proto * io_addr list
(** The address of a nameservers that is supposed to work with
the underlying context, can be used if the user does not want to
bother with configuring their own.*)
val rng : int -> string
(** [rng t] is a random number generator. *)
val clock : unit -> int64
(** [clock t] is the monotonic clock. *)
val connect : t -> (Dns.proto * context, [> `Msg of string ]) result io
(** [connect t] is a new connection ([context]) to [t], or an error. *)
val send_recv : context -> string -> (string, [> `Msg of string ]) result io
(** [send_recv context buffer] sends [buffer] to the [context] upstream, and
then reads a buffer. *)
val close : context -> unit io
(** [close context] closes the [context], freeing up resources. *)
val bind : 'a io -> ('a -> 'b io) -> 'b io
(** a.k.a. [>>=] *)
val lift : 'a -> 'a io
end
module Make : functor (T : S) ->
sig
type t
(** The abstract type of a DNS client. *)
val transport : t -> T.t
(** [transport t] is the transport of [t]. *)
val create : ?cache_size:int ->
?edns:[ `None | `Auto | `Manual of Dns.Edns.t ] ->
?nameservers:(Dns.proto * T.io_addr list) -> ?timeout:int64 ->
T.stack -> t
(** [create ~cache_size ~edns ~nameservers ~timeout stack] creates the state
of the DNS client. We use [timeout] (ns, default 5s) as a time budget for
connect and request timeouts. To specify a timeout, use
[create ~timeout:(Duration.of_sec 3)]. Whether or not to use
{{:https://tools.ietf.org/html/rfc6891}EDNS} in queries is controlled
by [~edns] (defaults to [`None]): if [None], no EDNS will be present,
[`Auto] adds TCP Keepalive if protocol is TCP, [`Manual edns] adds the
EDNS data specified. *)
val nameservers : t -> Dns.proto * T.io_addr list
(** [nameservers state] returns the list of nameservers to be used. *)
val getaddrinfo : t -> 'response Dns.Rr_map.key ->
'a Domain_name.t ->
('response, [> `Msg of string ]) result T.io
(** [getaddrinfo state query_type name] is the
[query_type]-dependent response regarding [name], or
an [Error _] message. See {!Dns_client.query_state} for more information
about the result types. *)
val gethostbyname : t -> [ `host ] Domain_name.t ->
(Ipaddr.V4.t, [> `Msg of string ]) result T.io
(** [gethostbyname state hostname] is the IPv4 address of
[hostname] resolved via the [state] specified.
If the query fails, or if the [domain] does not have any IPv4 addresses,
an [Error _] message is returned. Any extraneous IPv4 addresses are
ignored. For an example of using this API, see [unix/ohost.ml] in the
distribution of this package. *)
val gethostbyname6 : t -> [ `host ] Domain_name.t ->
(Ipaddr.V6.t, [> `Msg of string ]) result T.io
(** [gethostbyname6 state hostname] is the IPv6 address of
[hostname] resolved via the [state] specified.
It is the IPv6 equivalent of {!gethostbyname}. *)
val get_resource_record : t -> 'response Dns.Rr_map.key -> 'a Domain_name.t ->
('response,
[> `Msg of string
| `No_data of [ `raw ] Domain_name.t * Dns.Soa.t
| `No_domain of [ `raw ] Domain_name.t * Dns.Soa.t ]) result T.io
(** [get_resource_record state query_type name] resolves
[query_type, name] via the [state] specified. The
behaviour is equivalent to {!getaddrinfo}, apart from the error return
value - [get_resource_record] distinguishes some errors, at the moment
[No_data] if the [name] exists, but not the [query_type], and
[No_domain] if the [name] does not exist. This allows clients to treat
these error conditions explicitly. *)
val get_raw_reply : t -> 'response Dns.Rr_map.key ->
'a Domain_name.t ->
(Dns.Packet.reply, [> `Partial | `Msg of string ]) result T.io
(** [get_raw_reply state query_type name] resolves [query_type, name] via the
[state] specified. The complete DNS reply is returned. CNAME records
are not followed. This allows DNSSec to process the entire reply. *)
end
module Pure : sig
(** The pure interface to the client part of uDns.
Various helper modules to do with side effects are available from
{!Dns_client_lwt}, {!Dns_client_unix} and so forth. *)
type 'key query_state constraint 'key = 'a Dns.Rr_map.key
(** [query_state] is parameterized over the query type, so the type of the
representation of the answer depends on what the name server was asked to
provide. See {!Dns.Rr_map.k} for a list of response types. The first
element (the [int32]) in most of the tuples is the Time-To-Live (TTL)
field returned from the server, which you can use to calculate when you
should request fresh information in case you are writing a long-running
application. *)
val make_query :
(int -> string) -> Dns.proto -> ?dnssec:bool ->
[ `None | `Auto | `Manual of Dns.Edns.t ] ->
'a Domain_name.t ->
'query_type Dns.Rr_map.key ->
string * 'query_type Dns.Rr_map.key query_state
(** [make_query rng protocol name query_type] is [query, query_state]
where [query] is the serialized DNS query to send to the name server,
and [query_state] is the information required to validate the response. *)
val parse_response : 'query_type Dns.Rr_map.key query_state -> string ->
(Dns.Packet.reply, [ `Partial | `Msg of string]) result
(** [parse_response query_state response] is the information contained in
[response] parsed using [query_state] when the query was successful, or
an [`Msg message] if the [response] did not match the [query_state]
(or if the query failed).
In a TCP usage context the [`Partial] means there are more bytes to be
read in order to parse correctly. This can happen due to short reads or if
the server (or something along the route) chunks its responses into
multiple individual packets. In that case you should concatenate
[response] and the next received data and call this function again.
In a UDP usage context the [`Partial] means information was lost, due to
an incomplete packet. *)
val handle_response : 'query_type Dns.Rr_map.key query_state -> string ->
( [ `Data of 'query_type
| `Partial
| `No_data of [`raw] Domain_name.t * Dns.Soa.t
| `No_domain of [`raw] Domain_name.t * Dns.Soa.t ],
[`Msg of string]) result
(** [handle_response query_state response] is the information contained in
[response] parsed using [query_state] when the query was successful, or
an [`Msg message] if the [response] did not match the [query_state]
(or if the query failed).
In a TCP usage context the [`Partial] means there are more bytes to be
read in order to parse correctly. This can happen due to short reads or if
the server (or something along the route) chunks its responses into
multiple individual packets. In that case you should concatenate
[response] and the next received data and call this function again.
In a UDP usage context the [`Partial] means information was lost, due to
an incomplete packet. *)
end