aboutsummaryrefslogtreecommitdiff
path: root/lib/std/os.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/os.zig')
-rw-r--r--lib/std/os.zig48
1 files changed, 48 insertions, 0 deletions
diff --git a/lib/std/os.zig b/lib/std/os.zig
index d858f40106..08183ae785 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -3076,3 +3076,51 @@ pub fn recvfrom(
}
}
}
+
+pub const DnExpandError = error{InvalidDnsPacket};
+
+pub fn dn_expand(
+ msg: []const u8,
+ comp_dn: []const u8,
+ exp_dn: []u8,
+) DnExpandError!usize {
+ var p = comp_dn.ptr;
+ var len: usize = std.math.maxInt(usize);
+ const end = msg.ptr + msg.len;
+ if (p == end or exp_dn.len == 0) return error.InvalidDnsPacket;
+ var dest = exp_dn.ptr;
+ const dend = dest + std.math.min(exp_dn.len, 254);
+ // detect reference loop using an iteration counter
+ var i: usize = 0;
+ while (i < msg.len) : (i += 2) {
+ // loop invariants: p<end, dest<dend
+ if ((p[0] & 0xc0) != 0) {
+ if (p + 1 == end) return error.InvalidDnsPacket;
+ var j = ((p[0] & usize(0x3f)) << 8) | p[1];
+ if (len == std.math.maxInt(usize)) len = @ptrToInt(p) + 2 - @ptrToInt(comp_dn.ptr);
+ if (j >= msg.len) return error.InvalidDnsPacket;
+ p = msg.ptr + j;
+ } else if (p[0] != 0) {
+ if (dest != exp_dn.ptr) {
+ dest.* = '.';
+ dest += 1;
+ }
+ var j = p[0];
+ p += 1;
+ if (j >= @ptrToInt(end) - @ptrToInt(p) or j >= @ptrToInt(dend) - @ptrToInt(dest)) {
+ return error.InvalidDnsPacket;
+ }
+ while (j != 0) {
+ j -= 1;
+ dest.* = p[0];
+ dest += 1;
+ p += 1;
+ }
+ } else {
+ dest.* = 0;
+ if (len == std.math.maxInt(usize)) len = @ptrToInt(p) + 1 - @ptrToInt(comp_dn.ptr);
+ return len;
+ }
+ }
+ return error.InvalidDnsPacket;
+}