authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-02 20:45:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-02 20:45:16-07:00
log88693a56fc6a7129d4967957f387b2e404e32f4d
tree44c2693b969de1e6aca43baf7cfbd6a04e97a03d
parentb08f1d0e2a6e4df051a5bce9aeab5b31a1af4746

std.Io.net.HostName: implement DNS name expansion


1 files changed, 45 insertions(+), 53 deletions(-)

lib/std/Io/net/HostName.zig+45-53
...@@ -51,6 +51,7 @@ pub const LookupError = error{...@@ -51,6 +51,7 @@ pub const LookupError = error{
51 ResolvConfParseFailed,51 ResolvConfParseFailed,
52 InvalidDnsARecord,52 InvalidDnsARecord,
53 InvalidDnsAAAARecord,53 InvalidDnsAAAARecord,
54 InvalidDnsCnameRecord,
54 NameServerFailure,55 NameServerFailure,
55} || Io.Timestamp.Error || IpAddress.BindError || Io.File.OpenError || Io.File.Reader.Error || Io.Cancelable;56} || Io.Timestamp.Error || IpAddress.BindError || Io.File.OpenError || Io.File.Reader.Error || Io.Cancelable;
5657
...@@ -381,16 +382,8 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio...@@ -381,16 +382,8 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio
381 addresses_len += 1;382 addresses_len += 1;
382 },383 },
383 std.posix.RR.CNAME => {384 std.posix.RR.CNAME => {
384 _ = &canonical_name;385 _, canonical_name = expand(record.packet, record.data_off, options.canonical_name_buffer) catch
385 @panic("TODO");386 return error.InvalidDnsCnameRecord;
386 //var tmp: [256]u8 = undefined;
387 //// Returns len of compressed name. strlen to get canon name.
388 //_ = try posix.dn_expand(packet, record.data, &tmp);
389 //const canon_name = mem.sliceTo(&tmp, 0);
390 //if (isValidHostName(canon_name)) {
391 // ctx.canon.items.len = 0;
392 // try ctx.canon.appendSlice(gpa, canon_name);
393 //}
394 },387 },
395 else => continue,388 else => continue,
396 };389 };
...@@ -525,51 +518,50 @@ fn writeResolutionQuery(q: *[280]u8, op: u4, dname: []const u8, class: u8, ty: u...@@ -525,51 +518,50 @@ fn writeResolutionQuery(q: *[280]u8, op: u4, dname: []const u8, class: u8, ty: u
525 return n;518 return n;
526}519}
527520
528pub const ExpandDomainNameError = error{InvalidDnsPacket};521pub const ExpandError = error{InvalidDnsPacket} || InitError;
529522
530pub fn expandDomainName(523/// Decompresses a DNS name.
531 msg: []const u8,524///
532 comp_dn: []const u8,525/// Returns number of bytes consumed from `packet` starting at `i`,
533 exp_dn: []u8,526/// along with the expanded `HostName`.
534) ExpandDomainNameError!usize {527///
535 // This implementation is ported from musl libc.528/// Asserts `buffer` is has length at least `max_len`.
536 // A more idiomatic "ziggy" implementation would be welcome.529pub fn expand(noalias packet: []const u8, start_i: usize, noalias dest_buffer: []u8) ExpandError!struct { usize, HostName } {
537 var p = comp_dn.ptr;530 const dest = dest_buffer[0..max_len];
538 var len: usize = std.math.maxInt(usize);531
539 const end = msg.ptr + msg.len;532 var i = start_i;
540 if (p == end or exp_dn.len == 0) return error.InvalidDnsPacket;533 var dest_i: usize = 0;
541 var dest = exp_dn.ptr;534 var len: ?usize = null;
542 const dend = dest + @min(exp_dn.len, 254);535
543 // detect reference loop using an iteration counter536 // Detect reference loop using an iteration counter.
544 var i: usize = 0;537 for (0..packet.len / 2) |_| {
545 while (i < msg.len) : (i += 2) {538 if (i >= packet.len) return error.InvalidDnsPacket;
546 // loop invariants: p<end, dest<dend539
547 if ((p[0] & 0xc0) != 0) {540 const c = packet[i];
548 if (p + 1 == end) return error.InvalidDnsPacket;541 if ((c & 0xc0) != 0) {
549 const j = @as(usize, p[0] & 0x3f) << 8 | p[1];542 if (i + 1 >= packet.len) return error.InvalidDnsPacket;
550 if (len == std.math.maxInt(usize)) len = @intFromPtr(p) + 2 - @intFromPtr(comp_dn.ptr);543 const j: usize = (@as(usize, c & 0x3F) << 8) | packet[i + 1];
551 if (j >= msg.len) return error.InvalidDnsPacket;544 if (j >= packet.len) return error.InvalidDnsPacket;
552 p = msg.ptr + j;545 if (len == null) len = (i + 2) - start_i;
553 } else if (p[0] != 0) {546 i = j;
554 if (dest != exp_dn.ptr) {547 } else if (c != 0) {
555 dest[0] = '.';548 if (dest_i != 0) {
556 dest += 1;549 dest[dest_i] = '.';
557 }550 dest_i += 1;
558 var j = p[0];
559 p += 1;
560 if (j >= @intFromPtr(end) - @intFromPtr(p) or j >= @intFromPtr(dend) - @intFromPtr(dest)) {
561 return error.InvalidDnsPacket;
562 }
563 while (j != 0) {
564 j -= 1;
565 dest[0] = p[0];
566 dest += 1;
567 p += 1;
568 }551 }
552 const label_len: usize = c;
553 if (i + 1 + label_len > packet.len) return error.InvalidDnsPacket;
554 if (dest_i + label_len + 1 > dest.len) return error.InvalidDnsPacket;
555 @memcpy(dest[dest_i..][0..label_len], packet[i + 1 ..][0..label_len]);
556 dest_i += label_len;
557 i += 1 + label_len;
569 } else {558 } else {
570 dest[0] = 0;559 dest[dest_i] = 0;
571 if (len == std.math.maxInt(usize)) len = @intFromPtr(p) + 1 - @intFromPtr(comp_dn.ptr);560 dest_i += 1;
572 return len;561 return .{
562 len orelse i - start_i + 1,
563 try .init(dest[0..dest_i]),
564 };
573 }565 }
574 }566 }
575 return error.InvalidDnsPacket;567 return error.InvalidDnsPacket;