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

Code before:
        LogPrintLevel(BCLog::NET, BCLog::Level::Error, "send() to netlink socket: %s\n", NetworkErrorString(errno));
        return std::nullopt;
    }

    // Receive response.
    char response[4096];
    int64_t recv_result;
    do {
        recv_result = sock->Recv(response, sizeof(response), 0);
    } while (recv_result < 0 && (errno == EINTR || errno == EAGAIN));
    if (recv_result < 0) {
        LogPrintLevel(BCLog::NET, BCLog::Level::Error, "recv() from netlink socket: %s\n", NetworkErrorString(errno));
        return std::nullopt;
    }

    for (nlmsghdr* hdr = (nlmsghdr*)response; NLMSG_OK(hdr, recv_result); hdr = NLMSG_NEXT(hdr, recv_result)) {
        rtmsg* r = (rtmsg*)NLMSG_DATA(hdr);
        int remaining_len = RTM_PAYLOAD(hdr);

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

Review comment (suggestion):
In https://github.com/bitcoin/bitcoin/pull/32159/commits/57ce645f05d18d8ad10711c347a5989076f1f788 (_net: filter for default routes in netlink responses_)

Just info for other reviewers, I found this useful since I'm generally unfamiliar with how routing and gateways work:

As I understand, the destination prefix is a mask indicating what routes the gateway can be used for, a destination prefix of `0` (alternatively `0.0.0.0` or `::0`) indicates that the gateway can be used for all destinations, and RFC 1812 offers this right above the beginning of section [5.2.4.4](https://datatracker.ietf.org/doc/html/rfc1812#section-5.2.4.4):

> (5) Default Route: This is a route to all networks for which there are no explicit routes.  It is by definition the route whose prefix length is zero.

Code after:
    request.dst_hdr.nla_len = sizeof(nlattr) + dst_data_len;

    if (sock->Send(&request, request.hdr.nlmsg_len, 0) != static_cast<ssize_t>(request.hdr.nlmsg_len)) {
        LogPrintLevel(BCLog::NET, BCLog::Level::Error, "send() to netlink socket: %s\n", NetworkErrorString(errno));
        return std::nullopt;
    }

    // Receive response.
    char response[4096];
    ssize_t total_bytes_read{0};
    bool done{false};
    while (!done) {
        int64_t recv_result;
        do {
            recv_result = sock->Recv(response, sizeof(response), 0);
        } while (recv_result < 0 && (errno == EINTR || errno == EAGAIN));
        if (recv_result < 0) {
            LogPrintLevel(BCLog::NET, BCLog::Level::Error, "recv() from netlink socket: %s\n", NetworkErrorString(errno));
            return std::nullopt;
        }

        total_bytes_read += recv_result;
        if (total_bytes_read > NETLINK_MAX_RESPONSE_SIZE) {
            LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "Netlink response exceeded size limit (%zu bytes, family=%d)\n", NETLINK_MAX_RESPONSE_SIZE, family);
            return std::nullopt;
        }

        for (nlmsghdr* hdr = (nlmsghdr*)response; NLMSG_OK(hdr, recv_result); hdr = NLMSG_NEXT(hdr, recv_result)) {
            if (!(hdr->nlmsg_flags & NLM_F_MULTI)) {
                done = true;
            }

            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;