hare

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

commit e348f32284b0e1f55426c206e42c295c5bd2df11
parent d97383835e6a155527d07852ce6292fcc3abf355
Author: Conrad Hoffmann <ch@bitfehler.net>
Date:   Mon, 10 Jul 2023 15:44:25 +0200

net::dns: implement encoding of TXT records

Encoding of resource records is needed for clients to be able to send
proper dynamic update requests (RFC 2136). This commit implements this
for TXT records (and also unhandled record types, which means it never
got decoded and just has to be written back).

Signed-off-by: Conrad Hoffmann <ch@bitfehler.net>

Diffstat:
Mnet/dns/encode.ha | 33++++++++++++++++++++++++++++++++-
Mnet/dns/error.ha | 5++++-
2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/net/dns/encode.ha b/net/dns/encode.ha @@ -59,6 +59,15 @@ fn encode_u32(enc: *encoder, val: u32) (void | error) = { enc.offs += 4; }; +fn encode_raw(enc: *encoder, val: []u8) (void | error) = { + let end = enc.offs + len(val); + if (len(enc.buf) <= end) { + return errors::overflow; + }; + enc.buf[enc.offs..end] = val; + enc.offs += len(val); +}; + fn encode_labels(enc: *encoder, names: []str) (void | error) = { // TODO: Assert that the labels are all valid ASCII? for (let i = 0z; i < len(names); i += 1) { @@ -86,8 +95,30 @@ fn rrecord_encode(enc: *encoder, r: *rrecord) (void | error) = { encode_u16(enc, r.rtype)?; encode_u16(enc, r.class)?; encode_u32(enc, r.ttl)?; + let ln_enc = *enc; // save state for rdata len + encode_u16(enc, 0)?; // write dummy rdata len + encode_rdata(enc, r.rdata)?; // write rdata + let rdata_len = enc.offs - ln_enc.offs - 2; + encode_u16(&ln_enc, rdata_len: u16)?; // write rdata len to its place +}; - abort(); // TODO +fn encode_rdata(enc: *encoder, rdata: rdata) (void | error) = { + match (rdata) { + case let d: unknown_rdata => + return encode_raw(enc, d); + case let d: txt => + return encode_txt(enc, d); + case => + abort(); // TODO + }; +}; + +fn encode_txt(enc: *encoder, txt: txt) (void | error) = { + for (let i = 0z; i < len(txt); i += 1) { + if (len(txt[i]) > 255) return errors::invalid; + encode_u8(enc, len(txt[i]): u8)?; + encode_raw(enc, txt[i])?; + }; }; fn encode_op(op: *op) u16 = diff --git a/net/dns/error.ha b/net/dns/error.ha @@ -59,7 +59,8 @@ export 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::overflow | errors::timeout | net::error | io::error); + | errors::invalid | errors::overflow | errors::timeout + | net::error | io::error); export fn strerror(err: error) const str = { static let buf: [64]u8 = [0...]; @@ -92,6 +93,8 @@ export fn strerror(err: error) const str = { return "Signature out of time window"; case let ue: unknown_error => return fmt::bsprintf(buf, "Unknown DNS error {}", ue: u8); + case errors::invalid => + return "The message contains one or more field with invalid values"; case errors::overflow => return "The encoded message would exceed the buffer size"; case errors::timeout =>