linuxLookupName
Function parameters
Parameters
Type definitions in this namespace
Types
Functions in this namespace
Functions
- tcpConnectToHost
- All memory allocated with `allocator` will be freed before this function returns.
- getAddressList
- Call `AddressList.deinit` on the result.
Error sets in this namespace
Error Sets
= switch (native_os) { .windows => builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false, .wasi => false, else => true, }
Values
- has_unix_sockets
- = switch (native_os) { .windows => builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false, .wasi => false, else => true, }
Source
Implementation
fn linuxLookupName(
gpa: Allocator,
addrs: *ArrayList(LookupAddr),
canon: *ArrayList(u8),
opt_name: ?[]const u8,
family: posix.sa_family_t,
flags: posix.AI,
port: u16,
) !void {
if (opt_name) |name| {
// reject empty name and check len so it fits into temp bufs
canon.items.len = 0;
try canon.appendSlice(gpa, name);
if (Address.parseExpectingFamily(name, family, port)) |addr| {
try addrs.append(gpa, .{ .addr = addr });
} else |name_err| if (flags.NUMERICHOST) {
return name_err;
} else {
try linuxLookupNameFromHosts(gpa, addrs, canon, name, family, port);
if (addrs.items.len == 0) {
// RFC 6761 Section 6.3.3
// Name resolution APIs and libraries SHOULD recognize localhost
// names as special and SHOULD always return the IP loopback address
// for address queries and negative responses for all other query
// types.
// Check for equal to "localhost(.)" or ends in ".localhost(.)"
const localhost = if (name[name.len - 1] == '.') "localhost." else "localhost";
if (mem.endsWith(u8, name, localhost) and (name.len == localhost.len or name[name.len - localhost.len] == '.')) {
try addrs.append(gpa, .{ .addr = .{ .in = Ip4Address.parse("127.0.0.1", port) catch unreachable } });
try addrs.append(gpa, .{ .addr = .{ .in6 = Ip6Address.parse("::1", port) catch unreachable } });
return;
}
try linuxLookupNameFromDnsSearch(gpa, addrs, canon, name, family, port);
}
}
} else {
try canon.resize(gpa, 0);
try addrs.ensureUnusedCapacity(gpa, 2);
linuxLookupNameFromNull(addrs, family, flags, port);
}
if (addrs.items.len == 0) return error.UnknownHostName;
// No further processing is needed if there are fewer than 2
// results or if there are only IPv4 results.
if (addrs.items.len == 1 or family == posix.AF.INET) return;
const all_ip4 = for (addrs.items) |addr| {
if (addr.addr.any.family != posix.AF.INET) break false;
} else true;
if (all_ip4) return;
// The following implements a subset of RFC 3484/6724 destination
// address selection by generating a single 31-bit sort key for
// each address. Rules 3, 4, and 7 are omitted for having
// excessive runtime and code size cost and dubious benefit.
// So far the label/precedence table cannot be customized.
// This implementation is ported from musl libc.
// A more idiomatic "ziggy" implementation would be welcome.
for (addrs.items, 0..) |*addr, i| {
var key: i32 = 0;
var sa6: posix.sockaddr.in6 = undefined;
@memset(@as([*]u8, @ptrCast(&sa6))[0..@sizeOf(posix.sockaddr.in6)], 0);
var da6 = posix.sockaddr.in6{
.family = posix.AF.INET6,
.scope_id = addr.addr.in6.sa.scope_id,
.port = 65535,
.flowinfo = 0,
.addr = [1]u8{0} ** 16,
};
var sa4: posix.sockaddr.in = undefined;
@memset(@as([*]u8, @ptrCast(&sa4))[0..@sizeOf(posix.sockaddr.in)], 0);
var da4 = posix.sockaddr.in{
.family = posix.AF.INET,
.port = 65535,
.addr = 0,
.zero = [1]u8{0} ** 8,
};
var sa: *align(4) posix.sockaddr = undefined;
var da: *align(4) posix.sockaddr = undefined;
var salen: posix.socklen_t = undefined;
var dalen: posix.socklen_t = undefined;
if (addr.addr.any.family == posix.AF.INET6) {
da6.addr = addr.addr.in6.sa.addr;
da = @ptrCast(&da6);
dalen = @sizeOf(posix.sockaddr.in6);
sa = @ptrCast(&sa6);
salen = @sizeOf(posix.sockaddr.in6);
} else {
sa6.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
da6.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
mem.writeInt(u32, da6.addr[12..], addr.addr.in.sa.addr, native_endian);
da4.addr = addr.addr.in.sa.addr;
da = @ptrCast(&da4);
dalen = @sizeOf(posix.sockaddr.in);
sa = @ptrCast(&sa4);
salen = @sizeOf(posix.sockaddr.in);
}
const dpolicy = policyOf(da6.addr);
const dscope: i32 = scopeOf(da6.addr);
const dlabel = dpolicy.label;
const dprec: i32 = dpolicy.prec;
const MAXADDRS = 3;
var prefixlen: i32 = 0;
const sock_flags = posix.SOCK.DGRAM | posix.SOCK.CLOEXEC;
if (posix.socket(addr.addr.any.family, sock_flags, posix.IPPROTO.UDP)) |fd| syscalls: {
defer Stream.close(.{ .handle = fd });
posix.connect(fd, da, dalen) catch break :syscalls;
key |= DAS_USABLE;
posix.getsockname(fd, sa, &salen) catch break :syscalls;
if (addr.addr.any.family == posix.AF.INET) {
mem.writeInt(u32, sa6.addr[12..16], sa4.addr, native_endian);
}
if (dscope == @as(i32, scopeOf(sa6.addr))) key |= DAS_MATCHINGSCOPE;
if (dlabel == labelOf(sa6.addr)) key |= DAS_MATCHINGLABEL;
prefixlen = prefixMatch(sa6.addr, da6.addr);
} else |_| {}
key |= dprec << DAS_PREC_SHIFT;
key |= (15 - dscope) << DAS_SCOPE_SHIFT;
key |= prefixlen << DAS_PREFIX_SHIFT;
key |= (MAXADDRS - @as(i32, @intCast(i))) << DAS_ORDER_SHIFT;
addr.sortkey = key;
}
mem.sort(LookupAddr, addrs.items, {}, addrCmpLessThan);
}