Dns
Dns Server
The DnsServer trait and DnsAction is the interface between the cross compiled part and the logic.
pub enum DnsAction {
SendPacket {
payload: [u8; 576],
len: usize,
},
Ignore,
}
pub trait DnsServer {
fn handle_message(
&mut self,
buffer: &[u8],
) -> DhcpAction;
}
Message Format
DNS messages are binary-encoded over UDP. The wire format consists of a fixed 12-byte header, followed by a variable number of question and answer records. All multi-byte integers are big-endian.
Everything that is gray in the following tables is not implemented and only encoded with a default value.
Header
Header Flags
Question
Each question record contains an encoded name, a 16-bit type field, and a 16-bit class field (always 1 for IN / Internet in this implementation).
Supported question types:
| Value | Type | Description |
|---|---|---|
| 1 | A | IPv4 address |
| 5 | CNAME | Canonical name alias |
| 15 | MX | Mail exchange |
| 16 | TXT | Arbitrary text |
| 28 | AAAA | IPv6 address |
Answer
Answer records extend the question format with a 32-bit TTL (time-to-live in seconds) and a 16-bit len of the data, followed by the record data.
Name
Domain names are encoded as a sequence of length-prefixed labels, terminated by a zero byte. For example, captive.apple.com encodes as [7]captive[5]apple[3]com[0]. DNS compression pointers (top two bits 0xC0) are also supported for parsing — they redirect the reader to an earlier offset in the packet.
Record
Record payloads are type-specific:
This is just a example for the IPv4 type. For other types view the code inside logic/src/dns.rs.
Poisoned Dns Server
The PoisonedDnsServer is a simple DNS server designed to support a captive portal. Rather than forwarding or resolving queries, it responds to every DNS query — regardless of the requested domain - with an A record pointing to SERVER_IP. This forces all DNS-dependent traffic on the network to resolve to the device running the portal.
Behaviour:
- Parses the incoming DNS query.
- Takes the name from the first question record.
- Responds with a single
Arecord mapping that name toSERVER_IPwith a TTL of0. - Echoes back the original identification, opcode, and
RDflag, and setsAAandRAtotrue. - Returns
DnsAction::Ignoreif the packet cannot be parsed or contains no questions.
The TTL of
0prevents clients from caching the poisoned response, which ensures they re-query on each connection attempt - useful if the portal IP changes or the device restarts.