Decompresses a DNS name.
Returns number of bytes consumed from packet starting at i,
along with the expanded HostName.
Asserts buffer is has length at least max_len.
pub fn expand(noalias packet: []const u8, start_i: usize, noalias dest_buffer: []u8) ExpandError!struct
pub fn expand(noalias packet: []const u8, start_i: usize, noalias dest_buffer: []u8) ExpandError!struct { usize, HostName } {
const dest = dest_buffer[0..max_len];
var i = start_i;
var dest_i: usize = 0;
var len: ?usize = null;
// Detect reference loop using an iteration counter.
for (0..packet.len / 2) |_| {
if (i >= packet.len) return error.InvalidDnsPacket;
const c = packet[i];
if ((c & 0xc0) != 0) {
if (i + 1 >= packet.len) return error.InvalidDnsPacket;
const j: usize = (@as(usize, c & 0x3F) << 8) | packet[i + 1];
if (j >= packet.len) return error.InvalidDnsPacket;
if (len == null) len = (i + 2) - start_i;
i = j;
} else if (c != 0) {
if (dest_i != 0) {
dest[dest_i] = '.';
dest_i += 1;
}
const label_len: usize = c;
if (i + 1 + label_len > packet.len) return error.InvalidDnsPacket;
if (dest_i + label_len + 1 > dest.len) return error.InvalidDnsPacket;
@memcpy(dest[dest_i..][0..label_len], packet[i + 1 ..][0..label_len]);
dest_i += label_len;
i += 1 + label_len;
} else {
return .{
len orelse i - start_i + 1,
try .init(dest[0..dest_i]),
};
}
}
return error.InvalidDnsPacket;
}