hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mnet/dns/encoding.ha | 7+++++--
Mnet/dns/error.ha | 5++++-
Anet/dns/query.ha | 36++++++++++++++++++++++++++++++++++++
Mnet/dns/types.ha | 24+++++++++++++++++-------
Mscripts/gen-stdlib | 1+
Mstdlib.mk | 2++
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)