net::dns
net::dns implements low-level DNS message encoding and decoding, as well as a porcelain DNS resolver.
TODO:
- DNS over TCP
- Porcelain resolver API (resolv.conf)
- Decoders for various record types
- Complete RFC 2535 support
- Look for other RFCs worth addressing
Index
Types
type a = ip::addr4;
type aaaa = ip::addr6;
type caa = struct {
flags: u8,
tag: str,
value: str,
};
type class = enum u16 {
IN = 1,
CS = 2,
CH = 3,
HS = 4,
};
type cname = struct {
name: []str,
};
type dnskey = struct {
flags: u16,
protocol: u8,
algorithm: u8,
key: []u8,
};
type edns_opt = struct {
code: u16,
data: []u8,
};
type header = struct {
id: u16,
op: op,
qdcount: u16,
ancount: u16,
nscount: u16,
arcount: u16,
};
type message = struct {
header: header,
questions: []question,
answers: []rrecord,
authority: []rrecord,
additional: []rrecord,
};
type mx = struct {
priority: u16,
name: []str,
};
type ns = struct {
name: []str,
};
type nsec = struct {
next_domain: []str,
type_bitmaps: []u8,
};
type op = struct {
qr: qr,
opcode: opcode,
aa: bool,
tc: bool,
rd: bool,
ra: bool,
rcode: rcode,
};
type opcode = enum u8 {
QUERY = 0,
IQUERY = 1,
STATUS = 2,
UPDATE = 5,
};
type opt = struct {
options: []edns_opt,
};
type ptr = struct {
name: []str,
};
type qclass = enum u16 {
IN = 1,
CS = 2,
CH = 3,
HS = 4,
NONE = 254, ANY = 255,
};
type qr = enum u8 {
QUERY = 0,
RESPONSE = 1,
};
type qtype = enum u16 {
A = 1,
NS = 2,
CNAME = 5,
SOA = 6,
PTR = 12,
MX = 15,
TXT = 16,
AAAA = 28,
SRV = 33,
OPT = 41,
SSHFP = 44,
RRSIG = 46,
NSEC = 47,
DNSKEY = 48,
AXFR = 252, ALL = 255, CAA = 257,
};
type question = struct {
qname: []str,
qtype: qtype,
qclass: qclass,
};
type rcode = enum u8 {
NOERROR = 0,
FORMERR = 1,
SERVFAIL = 2,
NXDOMAIN = 3,
NOTIMP = 4,
REFUSED = 5,
YXDOMAIN = 6, YXRRSET = 7,
NXRRSET = 8,
NOTAUTH = 9,
NOTZONE = 10,
BADSIG = 16, BADKEY = 17,
BADTIME = 18,
};
type rdata = (a | aaaa | caa | cname | dnskey | mx | ns | nsec | opt | ptr | rrsig | soa | srv | sshfp | tsig | txt | unknown_rdata);
type rrecord = struct {
name: []str,
rtype: rtype,
class: class,
ttl: u32,
rdata: rdata,
};
type rrsig = struct {
type_covered: u16,
algorithm: u8,
labels: u8,
orig_ttl: u32,
sig_expiration: u32,
sig_inception: u32,
key_tag: u16,
signer_name: []str,
signature: []u8,
};
type rtype = enum u16 {
A = 1,
NS = 2,
CNAME = 5,
SOA = 6,
PTR = 12,
MX = 15,
TXT = 16,
AAAA = 28,
SRV = 33,
OPT = 41,
SSHFP = 44,
RRSIG = 46,
NSEC = 47,
DNSKEY = 48,
TSIG = 250,
CAA = 257,
};
type soa = struct {
mname: []str,
rname: []str,
serial: u32,
refresh: u32,
retry: u32,
expire: u32,
};
type srv = struct {
priority: u16,
weight: u16,
port: u16,
target: []str,
};
type sshfp = struct {
algorithm: u8,
fp_type: u8,
fingerprint: []u8,
};
type tsig = struct {
algorithm: []str,
time_signed: u64,
fudge: u16,
mac_len: u16,
mac: []u8,
orig_id: u16,
error: u16,
other_len: u16,
other_data: []u8,
};
type txt = [][]u8;
type unknown_rdata = []u8;
Errors
type bad_key = !void;
type bad_sig = !void;
type bad_time = !void;
type error = !(format | server_failure | name_error | not_implemented | refused | name_exists | rrset_exists | rrset_error | not_auth | not_zone | bad_sig | bad_key | bad_time | unknown_error | errors::invalid | errors::overflow | errors::timeout | net::error | io::error);
type format = !void;
type name_error = !void;
type name_exists = !void;
type not_auth = !void;
type not_implemented = !void;
type not_zone = !void;
type refused = !void;
type rrset_error = !void;
type rrset_exists = !void;
type server_failure = !void;
type unknown_error = !u8;
Functions
fn decode(buf: []u8) (*message | format);
fn encode(buf: []u8, msg: *message) (size | error);
fn message_free(msg: *message) void;
fn parse_domain(in: str) []str;
fn query(query: *message, servers: ip::addr...) (*message | error);
fn strerror(err: error) const str;
fn unparse_domain(in: []str) str;
Types
type a
type a = ip::addr4;
An A record.
type aaaa
type aaaa = ip::addr6;
An AAAA record.
type caa
type caa = struct {
flags: u8,
tag: str,
value: str,
};
A CAA record.
type class
type class = enum u16 {
IN = 1,
CS = 2,
CH = 3,
HS = 4,
};
Class type (e.g. Internet).
type cname
type cname = struct {
name: []str,
};
A CNAME record.
type dnskey
type dnskey = struct {
flags: u16,
protocol: u8,
algorithm: u8,
key: []u8,
};
A DNSKEY record.
type edns_opt
type edns_opt = struct {
code: u16,
data: []u8,
};
An EDNS (RFC 6891) option, as contained in opt records.
type header = struct {
id: u16,
op: op,
qdcount: u16,
ancount: u16,
nscount: u16,
arcount: u16,
};
DNS message header.
type message
type message = struct {
header: header,
questions: []question,
answers: []rrecord,
authority: []rrecord,
additional: []rrecord,
};
A DNS message, Hare representation. See encode and decode for the DNS representation.
type mx
type mx = struct {
priority: u16,
name: []str,
};
An MX record.
type ns
type ns = struct {
name: []str,
};
An NS record.
type nsec
type nsec = struct {
next_domain: []str,
type_bitmaps: []u8,
};
An NSEC record.
type op
type op = struct {
qr: qr,
opcode: opcode,
aa: bool,
tc: bool,
rd: bool,
ra: bool,
rcode: rcode,
};
Operational information for this message.
type opcode
type opcode = enum u8 {
QUERY = 0,
IQUERY = 1,
STATUS = 2,
UPDATE = 5,
};
Operation requested from resolver.
type opt
type opt = struct {
options: []edns_opt,
};
An OPT record (EDNS, RFC 6891).
type ptr
type ptr = struct {
name: []str,
};
A PTR record.
type qclass
type qclass = enum u16 {
IN = 1,
CS = 2,
CH = 3,
HS = 4,
NONE = 254, ANY = 255,
};
Query class (superset of class).
type qr
type qr = enum u8 {
QUERY = 0,
RESPONSE = 1,
};
Bit indicating if a header precedes a query or response.
type qtype
type qtype = enum u16 {
A = 1,
NS = 2,
CNAME = 5,
SOA = 6,
PTR = 12,
MX = 15,
TXT = 16,
AAAA = 28,
SRV = 33,
OPT = 41,
SSHFP = 44,
RRSIG = 46,
NSEC = 47,
DNSKEY = 48,
AXFR = 252, ALL = 255, CAA = 257,
};
Question type (superset of rtype).
type question
type question = struct {
qname: []str,
qtype: qtype,
qclass: qclass,
};
A question section item.
type rcode
type rcode = enum u8 {
NOERROR = 0,
FORMERR = 1,
SERVFAIL = 2,
NXDOMAIN = 3,
NOTIMP = 4,
REFUSED = 5,
YXDOMAIN = 6, YXRRSET = 7,
NXRRSET = 8,
NOTAUTH = 9,
NOTZONE = 10,
BADSIG = 16, BADKEY = 17,
BADTIME = 18,
};
Response code from resolver.
type rdata
type rdata = (a | aaaa | caa | cname | dnskey | mx | ns | nsec | opt | ptr | rrsig | soa | srv | sshfp | tsig | txt | unknown_rdata);
Tagged union of supported rdata types.
type rrecord
type rrecord = struct {
name: []str,
rtype: rtype,
class: class,
ttl: u32,
rdata: rdata,
};
A resource record item.
type rrsig
type rrsig = struct {
type_covered: u16,
algorithm: u8,
labels: u8,
orig_ttl: u32,
sig_expiration: u32,
sig_inception: u32,
key_tag: u16,
signer_name: []str,
signature: []u8,
};
An RRSIG record.
type rtype
type rtype = enum u16 {
A = 1,
NS = 2,
CNAME = 5,
SOA = 6,
PTR = 12,
MX = 15,
TXT = 16,
AAAA = 28,
SRV = 33,
OPT = 41,
SSHFP = 44,
RRSIG = 46,
NSEC = 47,
DNSKEY = 48,
TSIG = 250,
CAA = 257,
};
Record type.
type soa
type soa = struct {
mname: []str,
rname: []str,
serial: u32,
refresh: u32,
retry: u32,
expire: u32,
};
An SOA record.
type srv
type srv = struct {
priority: u16,
weight: u16,
port: u16,
target: []str,
};
An SRV record.
type sshfp
type sshfp = struct {
algorithm: u8,
fp_type: u8,
fingerprint: []u8,
};
An SSHFP record.
type tsig
type tsig = struct {
algorithm: []str,
time_signed: u64,
fudge: u16,
mac_len: u16,
mac: []u8,
orig_id: u16,
error: u16,
other_len: u16,
other_data: []u8,
};
A TSIG record.
type txt
type txt = [][]u8;
A TXT record.
type unknown_rdata
type unknown_rdata = []u8;
The raw rdata field for an rrecord with an unknown rtype.
Errors
type bad_key
type bad_key = !void;
Key not recognized.
type bad_sig
type bad_sig = !void;
TSIG signature validation failed.
type bad_time
type bad_time = !void;
Signature out of time window.
type error
type error = !(format | server_failure | name_error | not_implemented | refused | name_exists | rrset_exists | rrset_error | not_auth | not_zone | bad_sig | bad_key | bad_time | unknown_error | errors::invalid | errors::overflow | errors::timeout | net::error | io::error);
All error types which might be returned from functions in this module.
type format = !void;
The DNS message was poorly formatted.
type name_error
type name_error = !void;
The domain name referenced in the query does not exist. Meaningful only for responses from an authoritative name server.
type name_exists
type name_exists = !void;
Dynamic update prerequisite unsatisfied: a domain name exists when it shouldn't.
type not_auth
type not_auth = !void;
Server not authoritative for the zone or request not authorized.
type not_implemented
type not_implemented = !void;
The name server does not support the requested kind of query.
type not_zone
type not_zone = !void;
Name not contained in zone.
type refused
type refused = !void;
The name server refuses to perform the specified operation for policy reasons.
type rrset_error
type rrset_error = !void;
Dynamic update prerequisite unsatisfied: a resource record set doesn't exists when it should.
type rrset_exists
type rrset_exists = !void;
Dynamic update prerequisite unsatisfied: a resource record set exists when it shouldn't.
type server_failure
type server_failure = !void;
The name server was unable to process this query due to a problem with the name server.
type unknown_error
type unknown_error = !u8;
Any other server-provided error condition not known to Hare.
Functions
fn decode
fn decode(buf: []u8) (*message | format);
Decodes a DNS message, heap allocating the resources necessary to represent it in Hare's type system. The caller must use message_free to free the return value.
fn encode
fn encode(buf: []u8, msg: *message) (size | error);
Encodes a DNS message, returning its size, or an error.
fn message_free
fn message_free(msg: *message) void;
Frees a message and the resources associated with it.
fn parse_domain
fn parse_domain(in: str) []str;
Converts a human-readable domain name (e.g. "example.org") into a DNS-ready name slice (e.g. ["example", "org"]). The slice returned must be freed by the caller, but the members of the slice themselves are borrowed from the input.
fn query
fn query(query: *message, servers: ip::addr...) (*message | error);
Performs a DNS query using the provided list of DNS servers. The caller must free the return value with message_free.
If no DNS servers are provided, the system default servers (if any) are used.
fn strerror
fn strerror(err: error) const str;
Converts an error into a human-friendly string. The result may be statically allocated.
fn unparse_domain
fn unparse_domain(in: []str) str;
Converts a DNS name slice (e.g. ["example", "org"]) into a human-readable domain name (e.g. "example.org"). The return value must be freed by the caller.