net::dns+x86_64 +linux

net::dns implements low-level DNS message encoding and decoding, as well as a porcelain DNS resolver.

TODO:

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,
	// Number of questions
	qdcount: u16,
	// Number of answers
	ancount: u16,
	// Number of name servers
	nscount: u16,
	// Number of additional resources
	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 {
	// Is this a query or a response?
	qr: qr,
	// Operation code
	opcode: opcode,
	// Authoritative answer bit
	aa: bool,
	// Truncation bit
	tc: bool,
	// Recursion desired bit
	rd: bool,
	// Recursion available bit
	ra: bool,
	// Response code
	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, // RFC 2136 UPDATE
	YXRRSET = 7,
	NXRRSET = 8,
	NOTAUTH = 9,
	NOTZONE = 10,
	BADSIG = 16, // RFC 2845 TSIG
	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[link]

type a = ip::addr4;

An A record.

type aaaa[link]

type aaaa = ip::addr6;

An AAAA record.

type caa[link]

type caa = struct {
	flags: u8,
	tag: str,
	value: str,
};

A CAA record.

type class[link]

type class = enum u16 {
	IN = 1,
	CS = 2,
	CH = 3,
	HS = 4,
};

Class type (e.g. Internet).

type cname[link]

type cname = struct {
	name: []str,
};

A CNAME record.

type dnskey[link]

type dnskey = struct {
	flags: u16,
	protocol: u8,
	algorithm: u8,
	key: []u8,
};

A DNSKEY record.

type edns_opt[link]

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,
	// Number of questions
	qdcount: u16,
	// Number of answers
	ancount: u16,
	// Number of name servers
	nscount: u16,
	// Number of additional resources
	arcount: u16,
};

DNS message header.

type message[link]

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[link]

type mx = struct {
	priority: u16,
	name: []str,
};

An MX record.

type ns[link]

type ns = struct {
	name: []str,
};

An NS record.

type nsec[link]

type nsec = struct {
	next_domain: []str,
	type_bitmaps: []u8,
};

An NSEC record.

type op[link]

type op = struct {
	// Is this a query or a response?
	qr: qr,
	// Operation code
	opcode: opcode,
	// Authoritative answer bit
	aa: bool,
	// Truncation bit
	tc: bool,
	// Recursion desired bit
	rd: bool,
	// Recursion available bit
	ra: bool,
	// Response code
	rcode: rcode,
};

Operational information for this message.

type opcode[link]

type opcode = enum u8 {
	QUERY = 0,
	IQUERY = 1,
	STATUS = 2,
	UPDATE = 5,
};

Operation requested from resolver.

type opt[link]

type opt = struct {
	options: []edns_opt,
};

An OPT record (EDNS, RFC 6891).

type ptr[link]

type ptr = struct {
	name: []str,
};

A PTR record.

type qclass[link]

type qclass = enum u16 {
	IN = 1,
	CS = 2,
	CH = 3,
	HS = 4,
	NONE = 254, // *
	ANY = 255,
};

Query class (superset of class).

type qr[link]

type qr = enum u8 {
	QUERY = 0,
	RESPONSE = 1,
};

Bit indicating if a header precedes a query or response.

type qtype[link]

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[link]

type question = struct {
	qname: []str,
	qtype: qtype,
	qclass: qclass,
};

A question section item.

type rcode[link]

type rcode = enum u8 {
	NOERROR = 0,
	FORMERR = 1,
	SERVFAIL = 2,
	NXDOMAIN = 3,
	NOTIMP = 4,
	REFUSED = 5,
	YXDOMAIN = 6, // RFC 2136 UPDATE
	YXRRSET = 7,
	NXRRSET = 8,
	NOTAUTH = 9,
	NOTZONE = 10,
	BADSIG = 16, // RFC 2845 TSIG
	BADKEY = 17,
	BADTIME = 18,
};

Response code from resolver.

type rdata[link]

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[link]

type rrecord = struct {
	name: []str,
	rtype: rtype,
	class: class,
	ttl: u32,
	rdata: rdata,
};

A resource record item.

type rrsig[link]

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[link]

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[link]

type soa = struct {
	mname: []str,
	rname: []str,
	serial: u32,
	refresh: u32,
	retry: u32,
	expire: u32,
};

An SOA record.

type srv[link]

type srv = struct {
	priority: u16,
	weight: u16,
	port: u16,
	target: []str,
};

An SRV record.

type sshfp[link]

type sshfp = struct {
	algorithm: u8,
	fp_type: u8,
	fingerprint: []u8,
};

An SSHFP record.

type tsig[link]

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[link]

type txt = [][]u8;

A TXT record.

type unknown_rdata[link]

type unknown_rdata = []u8;

The raw rdata field for an rrecord with an unknown rtype.

Errors

type bad_key[link]

type bad_key = !void;

Key not recognized.

type bad_sig[link]

type bad_sig = !void;

TSIG signature validation failed.

type bad_time[link]

type bad_time = !void;

Signature out of time window.

type error[link]

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[link]

type format = !void;

The DNS message was poorly formatted.

type name_error[link]

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[link]

type name_exists = !void;

Dynamic update prerequisite unsatisfied: a domain name exists when it shouldn't.

type not_auth[link]

type not_auth = !void;

Server not authoritative for the zone or request not authorized.

type not_implemented[link]

type not_implemented = !void;

The name server does not support the requested kind of query.

type not_zone[link]

type not_zone = !void;

Name not contained in zone.

type refused[link]

type refused = !void;

The name server refuses to perform the specified operation for policy reasons.

type rrset_error[link]

type rrset_error = !void;

Dynamic update prerequisite unsatisfied: a resource record set doesn't exists when it should.

type rrset_exists[link]

type rrset_exists = !void;

Dynamic update prerequisite unsatisfied: a resource record set exists when it shouldn't.

type server_failure[link]

type server_failure = !void;

The name server was unable to process this query due to a problem with the name server.

type unknown_error[link]

type unknown_error = !u8;

Any other server-provided error condition not known to Hare.

Functions

fn decode[link]

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[link]

fn encode(buf: []u8, msg: *message) (size | error);

Encodes a DNS message, returning its size, or an error.

fn message_free[link]

fn message_free(msg: *message) void;

Frees a message and the resources associated with it.

fn parse_domain[link]

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[link]

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[link]

fn strerror(err: error) const str;

Converts an error into a human-friendly string. The result may be statically allocated.

fn unparse_domain[link]

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.