This commit is contained in:
Will Clark 2025-04-29 11:53:25 +02:00 committed by GitHub
commit 8534b1e0eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -36,6 +36,9 @@ namespace {
// will fail, so we skip that. // will fail, so we skip that.
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1400000) #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1400000)
// Good for responses containing ~ 10,000-15,000 routes.
static constexpr ssize_t NETLINK_MAX_RESPONSE_SIZE{1'048'576};
std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family) std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family)
{ {
// Create a netlink socket. // Create a netlink socket.
@ -84,6 +87,10 @@ std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family)
// Receive response. // Receive response.
char response[4096]; char response[4096];
ssize_t total_bytes_read{0};
bool done{false};
bool multi_part{false};
while (!done) {
int64_t recv_result; int64_t recv_result;
do { do {
recv_result = sock->Recv(response, sizeof(response), 0); recv_result = sock->Recv(response, sizeof(response), 0);
@ -93,10 +100,36 @@ std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family)
return std::nullopt; 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;
}
bool processed_one{false};
for (nlmsghdr* hdr = (nlmsghdr*)response; NLMSG_OK(hdr, recv_result); hdr = NLMSG_NEXT(hdr, recv_result)) { for (nlmsghdr* hdr = (nlmsghdr*)response; NLMSG_OK(hdr, recv_result); hdr = NLMSG_NEXT(hdr, recv_result)) {
rtmsg* r = (rtmsg*)NLMSG_DATA(hdr); rtmsg* r = (rtmsg*)NLMSG_DATA(hdr);
int remaining_len = RTM_PAYLOAD(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. // Iterate over the attributes.
rtattr* rta_gateway = nullptr; rtattr* rta_gateway = nullptr;
int scope_id = 0; int scope_id = 0;
@ -122,6 +155,13 @@ std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family)
} }
} }
// 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;
}
}
return std::nullopt; return std::nullopt;
} }