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{
5151 ResolvConfParseFailed,
5252 InvalidDnsARecord,
5353 InvalidDnsAAAARecord,
54 InvalidDnsCnameRecord,
5455 NameServerFailure,
5556} || 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
381382 addresses_len += 1;
382383 },
383384 std.posix.RR.CNAME => {
384 _ = &canonical_name;
385 @panic("TODO");
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 //}
385 _, canonical_name = expand(record.packet, record.data_off, options.canonical_name_buffer) catch
386 return error.InvalidDnsCnameRecord;
394387 },
395388 else => continue,
396389 };
......@@ -525,51 +518,50 @@ fn writeResolutionQuery(q: *[280]u8, op: u4, dname: []const u8, class: u8, ty: u
525518 return n;
526519}
527520
528pub const ExpandDomainNameError = error{InvalidDnsPacket};
529
530pub fn expandDomainName(
531 msg: []const u8,
532 comp_dn: []const u8,
533 exp_dn: []u8,
534) ExpandDomainNameError!usize {
535 // This implementation is ported from musl libc.
536 // A more idiomatic "ziggy" implementation would be welcome.
537 var p = comp_dn.ptr;
538 var len: usize = std.math.maxInt(usize);
539 const end = msg.ptr + msg.len;
540 if (p == end or exp_dn.len == 0) return error.InvalidDnsPacket;
541 var dest = exp_dn.ptr;
542 const dend = dest + @min(exp_dn.len, 254);
543 // detect reference loop using an iteration counter
544 var i: usize = 0;
545 while (i < msg.len) : (i += 2) {
546 // loop invariants: p<end, dest<dend
547 if ((p[0] & 0xc0) != 0) {
548 if (p + 1 == end) return error.InvalidDnsPacket;
549 const j = @as(usize, p[0] & 0x3f) << 8 | p[1];
550 if (len == std.math.maxInt(usize)) len = @intFromPtr(p) + 2 - @intFromPtr(comp_dn.ptr);
551 if (j >= msg.len) return error.InvalidDnsPacket;
552 p = msg.ptr + j;
553 } else if (p[0] != 0) {
554 if (dest != exp_dn.ptr) {
555 dest[0] = '.';
556 dest += 1;
557 }
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;
521pub const ExpandError = error{InvalidDnsPacket} || InitError;
522
523/// Decompresses a DNS name.
524///
525/// Returns number of bytes consumed from `packet` starting at `i`,
526/// along with the expanded `HostName`.
527///
528/// Asserts `buffer` is has length at least `max_len`.
529pub fn expand(noalias packet: []const u8, start_i: usize, noalias dest_buffer: []u8) ExpandError!struct { usize, HostName } {
530 const dest = dest_buffer[0..max_len];
531
532 var i = start_i;
533 var dest_i: usize = 0;
534 var len: ?usize = null;
535
536 // Detect reference loop using an iteration counter.
537 for (0..packet.len / 2) |_| {
538 if (i >= packet.len) return error.InvalidDnsPacket;
539
540 const c = packet[i];
541 if ((c & 0xc0) != 0) {
542 if (i + 1 >= packet.len) return error.InvalidDnsPacket;
543 const j: usize = (@as(usize, c & 0x3F) << 8) | packet[i + 1];
544 if (j >= packet.len) return error.InvalidDnsPacket;
545 if (len == null) len = (i + 2) - start_i;
546 i = j;
547 } else if (c != 0) {
548 if (dest_i != 0) {
549 dest[dest_i] = '.';
550 dest_i += 1;
568551 }
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;
569558 } else {
570 dest[0] = 0;
571 if (len == std.math.maxInt(usize)) len = @intFromPtr(p) + 1 - @intFromPtr(comp_dn.ptr);
572 return len;
559 dest[dest_i] = 0;
560 dest_i += 1;
561 return .{
562 len orelse i - start_i + 1,
563 try .init(dest[0..dest_i]),
564 };
573565 }
574566 }
575567 return error.InvalidDnsPacket;