Repository: bitcoin/bitcoin
File: src/common/netif.cpp (C++)

Code before:
            rtmsg* r = (rtmsg*)NLMSG_DATA(hdr);
            int remaining_len = RTM_PAYLOAD(hdr);

            processed_one = true;
            if (hdr->nlmsg_flags & NLM_F_MULTI) {
                multi_part = true;
            }

            if (hdr->nlmsg_type == NLMSG_DONE) {
                done = true;
                break;
            }

            if (hdr->nlmsg_type != RTM_NEWROUTE) {
                continue; // Skip non-route messages
            }

            // Only consider default routes (destination prefix length of 0).
            if (r->rtm_dst_len != 0) {
                continue;
            }

            // Iterate over the attributes.
            rtattr* rta_gateway = nullptr;
            int scope_id = 0;
            for (rtattr* attr = RTM_RTA(r); RTA_OK(attr, remaining_len); attr = RTA_NEXT(attr, remaining_len)) {
                if (attr->rta_type == RTA_GATEWAY) {
                    rta_gateway = attr;
                } else if (attr->rta_type == RTA_OIF && sizeof(int) == RTA_PAYLOAD(attr)) {
                    std::memcpy(&scope_id, RTA_DATA(attr), sizeof(scope_id));
                }
            }

            // Found gateway?
            if (rta_gateway != nullptr) {
                if (family == AF_INET && sizeof(in_addr) == RTA_PAYLOAD(rta_gateway)) {
                    in_addr gw;
                    std::memcpy(&gw, RTA_DATA(rta_gateway), sizeof(gw));
                    return CNetAddr(gw);
                } else if (family == AF_INET6 && sizeof(in6_addr) == RTA_PAYLOAD(rta_gateway)) {
                    in6_addr gw;
                    std::memcpy(&gw, RTA_DATA(rta_gateway), sizeof(gw));
                    return CNetAddr(gw, scope_id);
                }
            }
        }

        // If we processed at least one message and multi flag not set, or if
        // we received no valid messages, then we're done.
        if ((processed_one && !multi_part) || !processed_one) {
            done = true;

Review comment (suggestion):
For context on this, IPv6 allows "scoped addresses", e.g. I can send a packet to a non-globally unique address, like a link-local address that has two destinations on two different links, so in order to disambiguate scoped addresses  [RFC4007#section-6](https://datatracker.ietf.org/doc/html/rfc4007#section-6) recommends the use of unique zone indexes:

>  Because the same non-global address may be in use in more than one zone of the same scope (e.g., the use of link-local address fe80::1 in two separate physical links) and a node may have interfaces attached to different zones of the same scope (e.g., a router normally has multiple interfaces attached to different links), a node requires an internal means to identify to which zone a non-global address belongs.  This is accomplished by assigning, within the node, a distinct "zone index" to each zone of the same scope to which that node is attached, and by allowing all internal uses of an address to be qualified by a zone index.

And  [RFC4007#section-7](https://datatracker.ietf.org/doc/html/rfc4007#section-7) suggests that specifying an output interface index as the zone index is sufficient, but more specific than necessary to disambiguate: 
>  When an upper-layer protocol sends a packet to a non-global destination address, it must have a means of identifying the intended zone to the IPv6 layer for cases in which the node is attached to more than one zone of the destination address's scope.
> Although identification of an outgoing interface is sufficient to identify an intended zone (because each interface is attached to no more than one zone of each scope), in many cases that is more specific than desired.

The name used in the rtnetlink interface (`RTA_OIF`) suggest that the unique scope ID / zone ID used  is the output interface index (OIF), but I guess that's an implementation detail, the point is, it's a unique index that makes an IPv6 address globally unique from the POV of a given device.

Code after:
            }

            if (hdr->nlmsg_type == NLMSG_DONE) {
                done = true;
                break;
            }

            rtmsg* r = (rtmsg*)NLMSG_DATA(hdr);
            int remaining_len = RTM_PAYLOAD(hdr);

            if (hdr->nlmsg_type != RTM_NEWROUTE) {
                continue; // Skip non-route messages
            }

            // Only consider default routes (destination prefix length of 0).
            if (r->rtm_dst_len != 0) {
                continue;
            }

            // Iterate over the attributes.
            rtattr* rta_gateway = nullptr;
            int scope_id = 0;
            for (rtattr* attr = RTM_RTA(r); RTA_OK(attr, remaining_len); attr = RTA_NEXT(attr, remaining_len)) {
                if (attr->rta_type == RTA_GATEWAY) {
                    rta_gateway = attr;
                } else if (attr->rta_type == RTA_OIF && sizeof(int) == RTA_PAYLOAD(attr)) {
                    std::memcpy(&scope_id, RTA_DATA(attr), sizeof(scope_id));
                }
            }

            // Found gateway?
            if (rta_gateway != nullptr) {
                if (family == AF_INET && sizeof(in_addr) == RTA_PAYLOAD(rta_gateway)) {
                    in_addr gw;
                    std::memcpy(&gw, RTA_DATA(rta_gateway), sizeof(gw));
                    return CNetAddr(gw);
                } else if (family == AF_INET6 && sizeof(in6_addr) == RTA_PAYLOAD(rta_gateway)) {
                    in6_addr gw;
                    std::memcpy(&gw, RTA_DATA(rta_gateway), sizeof(gw));
                    return CNetAddr(gw, scope_id);
                }
            }
        }
    }

    return std::nullopt;
}

#elif defined(WIN32)

std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family)