Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 26 additions & 31 deletions lib/std/net.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1483,7 +1483,7 @@ fn linuxLookupNameFromDnsSearch(
) !void {
var rc: ResolvConf = undefined;
rc.init(gpa) catch return error.ResolveConfParseFailed;
defer rc.deinit();
defer rc.deinit(gpa);

// Count dots, suppress search when >=ndots or name ends in
// a dot, which is an explicit request for global scope.
Expand Down Expand Up @@ -1586,40 +1586,38 @@ fn linuxLookupNameFromDns(
}

const ResolvConf = struct {
gpa: Allocator,
attempts: u32,
ndots: u32,
timeout: u32,
search: ArrayList(u8),
/// TODO there are actually only allowed to be maximum 3 nameservers, no need
/// for an array list.
ns: ArrayList(LookupAddr),
ns_buffer: [3]LookupAddr,
ns_len: u2,

/// Returns `error.StreamTooLong` if a line is longer than 512 bytes.
/// TODO: https://github.com/ziglang/zig/issues/2765 and https://github.com/ziglang/zig/issues/2761
fn init(rc: *ResolvConf, gpa: Allocator) !void {
rc.* = .{
.gpa = gpa,
.ns = .empty,
.ns_buffer = undefined,
.ns_len = 0,
.search = .empty,
.ndots = 1,
.timeout = 5,
.attempts = 2,
};
errdefer rc.deinit();
errdefer rc.deinit(gpa);

const file = fs.openFileAbsoluteZ("/etc/resolv.conf", .{}) catch |err| switch (err) {
error.FileNotFound,
error.NotDir,
error.AccessDenied,
=> return linuxLookupNameFromNumericUnspec(gpa, &rc.ns, "127.0.0.1", 53),
=> return linuxLookupNameFromNumericUnspec(&rc.ns_buffer, &rc.ns_len, "127.0.0.1", 53),
else => |e| return e,
};
defer file.close();

var line_buf: [512]u8 = undefined;
var file_reader = file.reader(&line_buf);
return parse(rc, &file_reader.interface) catch |err| switch (err) {
return parse(rc, gpa, &file_reader.interface) catch |err| switch (err) {
error.ReadFailed => return file_reader.err.?,
else => |e| return e,
};
Expand All @@ -1628,8 +1626,7 @@ const ResolvConf = struct {
const Directive = enum { options, nameserver, domain, search };
const Option = enum { ndots, attempts, timeout };

fn parse(rc: *ResolvConf, reader: *Io.Reader) !void {
const gpa = rc.gpa;
fn parse(rc: *ResolvConf, gpa: Allocator, reader: *Io.Reader) !void {
while (reader.takeSentinel('\n')) |line_with_comment| {
const line = line: {
var split = mem.splitScalar(u8, line_with_comment, '#');
Expand All @@ -1655,7 +1652,7 @@ const ResolvConf = struct {
},
.nameserver => {
const ip_txt = line_it.next() orelse continue;
try linuxLookupNameFromNumericUnspec(gpa, &rc.ns, ip_txt, 53);
try linuxLookupNameFromNumericUnspec(&rc.ns_buffer, &rc.ns_len, ip_txt, 53);
},
.domain, .search => {
rc.search.items.len = 0;
Expand All @@ -1667,8 +1664,8 @@ const ResolvConf = struct {
else => |e| return e,
}

if (rc.ns.items.len == 0) {
return linuxLookupNameFromNumericUnspec(gpa, &rc.ns, "127.0.0.1", 53);
if (rc.ns_len == 0) {
return linuxLookupNameFromNumericUnspec(&rc.ns_buffer, &rc.ns_len, "127.0.0.1", 53);
}
}

Expand All @@ -1678,19 +1675,15 @@ const ResolvConf = struct {
answers: [][]u8,
answer_bufs: []const []u8,
) !void {
const gpa = rc.gpa;
const timeout = 1000 * rc.timeout;
const attempts = rc.attempts;

var sl: posix.socklen_t = @sizeOf(posix.sockaddr.in);
var family: posix.sa_family_t = posix.AF.INET;

var ns_list: ArrayList(Address) = .empty;
defer ns_list.deinit(gpa);

try ns_list.resize(gpa, rc.ns.items.len);
var ns_addr_buffer: [3]Address = undefined;

for (ns_list.items, rc.ns.items) |*ns, iplit| {
for (ns_addr_buffer[0..rc.ns_len], rc.ns_buffer[0..rc.ns_len]) |*ns, iplit| {
ns.* = iplit.addr;
assert(ns.getPort() == 53);
if (iplit.addr.any.family != posix.AF.INET) {
Expand Down Expand Up @@ -1724,7 +1717,7 @@ const ResolvConf = struct {
std.os.linux.IPV6.V6ONLY,
&mem.toBytes(@as(c_int, 0)),
);
for (ns_list.items) |*ns| {
for (ns_addr_buffer[0..rc.ns_len]) |*ns| {
if (ns.any.family != posix.AF.INET) continue;
mem.writeInt(u32, ns.in6.sa.addr[12..], ns.in.sa.addr, native_endian);
ns.in6.sa.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
Expand Down Expand Up @@ -1760,7 +1753,7 @@ const ResolvConf = struct {
var i: usize = 0;
while (i < queries.len) : (i += 1) {
if (answers[i].len == 0) {
for (ns_list.items) |*ns| {
for (ns_addr_buffer[0..rc.ns_len]) |*ns| {
_ = posix.sendto(fd, queries[i], posix.MSG.NOSIGNAL, &ns.any, sl) catch undefined;
}
}
Expand All @@ -1782,7 +1775,7 @@ const ResolvConf = struct {
if (rlen < 4) continue;

// Ignore replies from addresses we didn't send to
const ns = for (ns_list.items) |*ns| {
const ns = for (ns_addr_buffer[0..rc.ns_len]) |*ns| {
if (ns.eql(sa)) break ns;
} else continue;

Expand Down Expand Up @@ -1821,22 +1814,24 @@ const ResolvConf = struct {
}
}

fn deinit(rc: *ResolvConf) void {
const gpa = rc.gpa;
rc.ns.deinit(gpa);
fn deinit(rc: *ResolvConf, gpa: Allocator) void {
rc.search.deinit(gpa);
rc.* = undefined;
}
};

fn linuxLookupNameFromNumericUnspec(
gpa: Allocator,
addrs: *ArrayList(LookupAddr),
addrs: *[3]LookupAddr,
addrs_len: *u2,
name: []const u8,
port: u16,
) !void {
const addr = try Address.resolveIp(name, port);
try addrs.append(gpa, .{ .addr = addr });
// Ignore new nameserver entries past the third one
if (addrs_len.* == addrs.len) return;

const address = try Address.resolveIp(name, port);
addrs[addrs_len.*] = .{ .addr = address };
addrs_len.* += 1;
}

fn dnsParse(
Expand Down