DoxigAlpha

linuxLookupName

Function parameters

Parameters

#
addrs:*ArrayList(LookupAddr)
canon:*ArrayList(u8)
opt_name:?[]const u8
family:posix.sa_family_t
flags:posix.AI
port:u16

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);
}