silk.net.dns.query.

Send one DNS question to the servers of a configuration, with retries and TCP fallback, without doing any input or output.

When to use#

Use an Exchange to drive a query from your own sockets and timers, for example in an event loop. For a plain native program, silk.net.dns.client_native drives an Exchange with system sockets.

Details#

Make an exchange with Exchange.make, then loop:

  1. Call Exchange.poll with the time of a MonotonicClock.

  2. For Step.Send, send Exchange.packet to the server of the step: as one UDP datagram, or on a new TCP connection, where the packet already has its two-byte length.

  3. For Step.Wait, wait for a reply or until the time of the step, whichever is first. Give each UDP datagram from a server, and each whole TCP message, to Exchange.receive. Tell Exchange.transportFailed when a send fails or a TCP connection breaks.

  4. For Step.Done, call Exchange.finish for the result.

The exchange tries each server in turn, for attempts rounds. It waits timeout for each server in the first round, and doubles the wait in each later round, up to 8 times timeout. A reply with the TC bit is asked again over TCP from the same server. A server that answers SERVFAIL, NOTIMP or REFUSED is skipped at once. A FORMERR answer to a query with EDNS is asked again without EDNS. A late UDP answer from a server that was asked before is accepted.

Gotchas#

The exchange checks the identifier and the question of each reply, but it cannot see where a datagram came from. Use one connected UDP socket for each server, or check the source address yourself, and give only datagrams from a server of the configuration.

Import as Exchange with import silk.net.dns.query { Exchange }.

Public declarations: 7.

EDNS_PAYLOAD_SIZE#

silk
pub const EDNS_PAYLOAD_SIZE: u16

The UDP payload size that queries with EDNS announce: 1232 bytes, which avoids IP fragmentation on most networks.

Transport#

silk
pub enum Transport

How a packet goes to a server.

Udp#

silk
Udp

One UDP datagram.

Tcp#

silk
Tcp

A TCP connection. The packet starts with its length in two bytes.

Implementation Debug for Transport#

silk
impl Debug for Transport

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> ()
    ! WriterError
    ? &mut Writer

Writes the name of the variant, such as Udp.

Step#

silk
pub union Step

What the owner of an Exchange must do next.

Send#

silk
Send

Send Exchange.packet for transport to endpoint, then call Exchange.poll again.

Field server#

silk
pub server: usize

The position of the server in the configuration.

Field endpoint#

silk
pub endpoint: Endpoint

The address of the server.

Field transport#

silk
pub transport: Transport

How to send the packet.

Wait#

silk
Wait

Wait for a reply until until, then call Exchange.poll again.

Field until#

silk
pub until: Instant

The time on the MonotonicClock at which the current try ends.

Done#

silk
Done

The exchange has a result. Call Exchange.finish.

QueryError#

silk
pub union QueryError

A query that failed.

NoServers#

silk
NoServers

The configuration has no servers.

Timeout#

silk
Timeout

No server answered before the last try ended.

Rejected#

silk
Rejected

The last server that answered refused the query, with SERVFAIL, NOTIMP, REFUSED or FORMERR.

Field responseCode#

silk
pub responseCode: u16

The response code, such as RCODE_SERVER_FAILURE.

Field server#

silk
pub server: usize

The position of the server in the configuration.

BadResponse#

silk
BadResponse

The last server that answered over TCP sent a message that cannot be read, or that does not answer the question.

Field reason#

silk
pub reason: MessageReason

The problem in the message.

Field server#

silk
pub server: usize

The position of the server in the configuration.

Unreachable#

silk
Unreachable

A send to the last server failed, or its TCP connection broke, as Exchange.transportFailed reported.

Field server#

silk
pub server: usize

The position of the server in the configuration.

Implementation Copy for QueryError#

silk
impl Copy for QueryError

Implementation Debug for QueryError#

silk
impl Debug for QueryError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> ()
    ! WriterError
    ? &mut Writer

Writes the name of the variant and its fields, such as Rejected { ... }.

Reply#

silk
pub struct Reply

The answer to a query.

Field message#

silk
pub message: Message

The message that the server sent.

Field bytes#

silk
pub bytes: Bytes

The message as it was on the wire, without the TCP length.

Field server#

silk
pub server: usize

The position of the server in the configuration.

Field transport#

silk
pub transport: Transport

How the message came.

Receipt#

silk
pub enum Receipt

What Exchange.receive did with a message.

Answer#

silk
Answer

The message answers the query. Exchange.poll now returns Step.Done.

Retry#

silk
Retry

The message made the exchange retry: over TCP, without EDNS, or at the next server.

Ignored#

silk
Ignored

The message is not for this query, or came when no reply was expected from that server. It changed nothing.

Exchange#

silk
pub struct Exchange

One question sent to the servers of a configuration. See the module documentation for the protocol.

Implementation Exchange#

silk
impl Exchange

Associated function make#

silk
pub effect fn make(config: &ResolverConfig, question: Question, id: u16, first: usize) -> Exchange
    ! MessageError | OutOfMemoryError
    ? &mut Allocator

Returns an exchange that asks question with the identifier id.

Details#

The exchange uses the servers, timeout, attempts, edns and useTcp of config, and starts at server first, modulo the number of servers. To follow the rotate option, give a different first to each query. Take id from a Random provider, so that an attacker cannot guess it.

Errors#

  • MessageError if the query does not fit in a message, which happens only for a wrong class or type.

  • OutOfMemoryError if the Allocator cannot supply the packets.

Method endpoint#

silk
pub fn endpoint(self: &Self, server: usize) -> Endpoint

Returns the address of server server, its position in the configuration. server must be less than the number of servers.

Method id#

silk
pub fn id(self: &Self) -> u16

Returns the identifier of the query.

Method packet#

silk
pub fn packet(self: &Self, transport: Transport) -> &[u8]

Returns the packet to send for transport: one DNS message for UDP, or the message after its two-byte length for TCP.

Method poll#

silk
pub fn poll(self: &mut Self, now: &Instant) -> Step

Returns the next thing to do at the time now of a MonotonicClock.

Details#

Step.Send starts a try, and the next call returns Step.Wait with the end of that try. When now reaches the end, the exchange moves to the next server and returns Step.Send again. After the last try it returns Step.Done, and Exchange.finish gives QueryError.Timeout or the last problem a server reported.

Method receive#

silk
pub effect fn receive(
    self: &mut Self,
    server: usize,
    transport: Transport,
    bytes: &[u8],
  ) -> Receipt
    ! OutOfMemoryError
    ? &mut Allocator

Gives the exchange a message from server server: one UDP datagram, or one TCP message without its two-byte length.

Details#

A message with another identifier or question is ignored, as is a UDP message from a server that was not asked over UDP, or a TCP message when no TCP answer is expected from that server. A UDP message that cannot be read is ignored too, because anyone can send one. A TCP message that cannot be read makes the exchange move to the next server.

Errors#

  • OutOfMemoryError if the Allocator cannot supply the message or new packets.

Method transportFailed#

silk
pub fn transportFailed(self: &mut Self, server: usize, transport: Transport) -> ()

Tells the exchange that sending to server with transport failed, or that its TCP connection broke before a whole answer came.

Details#

If the current try uses that server and transport, the exchange moves to the next server at once. Otherwise nothing changes.

Method isDone#

silk
pub fn isDone(self: &Self) -> bool

Returns true once Exchange.poll returns Step.Done.

Method finish#

silk
pub fn finish(self: Self) -> Result<Reply, QueryError>

Returns the result: the reply, or why there is none.

Details#

A reply can have any response code other than SERVFAIL, NOTIMP, REFUSED and FORMERR, such as RCODE_NAME_ERROR for a name that does not exist. Check reply.message.header.responseCode.

Errors#

  • QueryError.Timeout if the exchange is not done, or no server answered in time.

  • The last problem that a server reported, if no server answered.

Category: Networking.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.

View the source of this page