commit 23ce1ecf3281f441faad71475ca05cb22e6f2cac
parent 4bf2bb19ccf91f3405ea408e84266a3a313717e5
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 21 Jun 2021 10:55:09 -0400
net::dns: add porcelain "query" function
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
6 files changed, 65 insertions(+), 10 deletions(-)
diff --git a/net/dns/encoding.ha b/net/dns/encoding.ha
@@ -28,7 +28,7 @@ export fn decode(buf: []u8) (*message | format) = {
for (let i = 0; len(names) != 0; i += 1) {
let ns = decode_name(&dec, names)!;
names = ns.0;
- append(q.qname, ns.1);
+ append(q.qname, strings::dup(ns.1));
};
append(msg.questions, q);
@@ -48,11 +48,14 @@ fn decode_rrecords(
for (let i = 0z; i < count; i += 1) {
let r = rrecord { ... };
let names = decode_rrecord(dec, &r)?;
+ let rdata = r.rdata;
+ r.rdata = [];
+ append(r.rdata, rdata...);
for (let i = 0; len(names) != 0; i += 1) {
let ns = decode_name(dec, names)!;
names = ns.0;
- append(r.name, ns.1);
+ append(r.name, strings::dup(ns.1));
};
append(*out, r);
diff --git a/net/dns/error.ha b/net/dns/error.ha
@@ -1,3 +1,4 @@
+use errors;
use fmt;
// The DNS message was poorly formatted.
@@ -23,7 +24,8 @@ export type unknown_error = !u8;
// All error types which might be returned from [[net::dns]] functions.
export type error = (format | server_failure | name_error
- | not_implemented | refused | unknown_error);
+ | not_implemented | refused | unknown_error
+ | errors::opaque);
export fn strerror(err: error) const str = {
static let buf: [64]u8 = [0...];
@@ -34,5 +36,6 @@ export fn strerror(err: error) const str = {
not_implemented => "The name server does not support the requested kind of query",
refused => "The name server refuses to perform the specified operation for policy reasons",
ue: unknown_error => fmt::bsprintf(buf, "Unknown DNS error {}", ue: u8),
+ err: errors::opaque => errors::strerror(err),
};
};
diff --git a/net/dns/query.ha b/net/dns/query.ha
@@ -0,0 +1,36 @@
+use net::ip;
+use net::udp;
+
+// Performs a DNS query using the provided list of DNS servers. The caller must
+// free the return value with [[message_free]].
+export fn query(query: *message, addr: ip::addr...) (*message | error) = {
+ assert(len(addr) == 1, "TODO: Query multiple servers");
+ let socket = udp::listen(ip::ANY_V4, 0)?;
+ defer udp::close(socket);
+
+ // TODO: Use TCP for messages >512 bytes
+ let sendbuf: [512]u8 = [0...];
+ let z = encode(sendbuf, query);
+ udp::sendto(socket, sendbuf[..z], addr[0], 53)?;
+
+ let recvbuf: [512]u8 = [0...];
+ for (true) {
+ // TODO: Add timeout
+ let src: ip::addr = ip::ANY_V4;
+ z = udp::recvfrom(socket, recvbuf, &src, null)?;
+ if (!ip::equal(src, addr[0])) {
+ continue;
+ };
+
+ let header = header { ... };
+ let dec = decoder_init(recvbuf[..z]);
+ decode_header(&dec, &header)?;
+ if (header.id != query.header.id) {
+ continue;
+ };
+
+ break;
+ };
+
+ return decode(recvbuf[..z])?;
+};
diff --git a/net/dns/types.ha b/net/dns/types.ha
@@ -129,25 +129,35 @@ export type message = struct {
additional: []rrecord,
};
+fn strings_free(in: []str) void = {
+ for (let i = 0z; i < len(in); i += 1) {
+ free(in[i]);
+ };
+ free(in);
+};
+
// Frees a [[message]] and the resources associated with it.
export fn message_free(msg: *message) void = {
for (let i = 0z; i < len(msg.questions); i += 1) {
- free(msg.questions[i].qname);
+ strings_free(msg.questions[i].qname);
};
free(msg.questions);
- for (let i = 0z; i < len(msg.questions); i += 1) {
- free(msg.answers[i].name);
+ for (let i = 0z; i < len(msg.answers); i += 1) {
+ strings_free(msg.answers[i].name);
+ free(msg.answers[i].rdata);
};
free(msg.answers);
- for (let i = 0z; i < len(msg.questions); i += 1) {
- free(msg.answers[i].name);
+ for (let i = 0z; i < len(msg.authority); i += 1) {
+ strings_free(msg.authority[i].name);
+ free(msg.authority[i].rdata);
};
free(msg.authority);
- for (let i = 0z; i < len(msg.questions); i += 1) {
- free(msg.answers[i].name);
+ for (let i = 0z; i < len(msg.additional); i += 1) {
+ strings_free(msg.additional[i].name);
+ free(msg.additional[i].rdata);
};
free(msg.additional);
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -554,6 +554,7 @@ net_dns() {
gen_srcs net::dns \
error.ha \
encoding.ha \
+ query.ha \
types.ha
gen_ssa net::dns ascii endian net net::udp net::ip fmt
}
diff --git a/stdlib.mk b/stdlib.mk
@@ -824,6 +824,7 @@ $(HARECACHE)/net/net.ssa: $(stdlib_net_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_
stdlib_net_dns_srcs= \
$(STDLIB)/net/dns/error.ha \
$(STDLIB)/net/dns/encoding.ha \
+ $(STDLIB)/net/dns/query.ha \
$(STDLIB)/net/dns/types.ha
$(HARECACHE)/net/dns/net_dns.ssa: $(stdlib_net_dns_srcs) $(stdlib_rt) $(stdlib_ascii) $(stdlib_endian) $(stdlib_net) $(stdlib_net_udp) $(stdlib_net_ip) $(stdlib_fmt)
@@ -1945,6 +1946,7 @@ $(TESTCACHE)/net/net.ssa: $(testlib_net_srcs) $(testlib_rt) $(testlib_io) $(test
testlib_net_dns_srcs= \
$(STDLIB)/net/dns/error.ha \
$(STDLIB)/net/dns/encoding.ha \
+ $(STDLIB)/net/dns/query.ha \
$(STDLIB)/net/dns/types.ha
$(TESTCACHE)/net/dns/net_dns.ssa: $(testlib_net_dns_srcs) $(testlib_rt) $(testlib_ascii) $(testlib_endian) $(testlib_net) $(testlib_net_udp) $(testlib_net_ip) $(testlib_fmt)