[posix] update Posix::Resolver to support IPv6 addresses for servers. (#11325)

This commit enhances the DNS resolver (`resolver.cpp`) to support IPv6
addresses in upstream DNS server configurations, allowing for greater
flexibility and compatibility in IPv6-enabled environments.
This commit is contained in:
Yang Song
2025-03-13 08:36:10 -07:00
committed by GitHub
parent 7f2828657a
commit a7dbd9b46d
2 changed files with 116 additions and 65 deletions
+107 -56
View File
@@ -86,6 +86,8 @@ void Resolver::LoadDnsServerListFromConf(void)
{
std::string line;
std::ifstream fp;
otIp4Address ip4Address;
otIp6Address ip6Address;
VerifyOrExit(mIsResolvConfEnabled);
@@ -95,17 +97,26 @@ void Resolver::LoadDnsServerListFromConf(void)
while (fp.good() && std::getline(fp, line) && mUpstreamDnsServerCount < kMaxUpstreamServerCount)
{
if (line.find(kNameserverItem, 0) == 0)
{
in_addr_t addr;
const char *addressString = &line.c_str()[sizeof(kNameserverItem)];
if (inet_pton(AF_INET, &line.c_str()[sizeof(kNameserverItem)], &addr) == 1)
{
LogInfo("Got nameserver #%d: %s", mUpstreamDnsServerCount, &line.c_str()[sizeof(kNameserverItem)]);
mUpstreamDnsServerList[mUpstreamDnsServerCount] = addr;
mUpstreamDnsServerCount++;
}
// Skip the lines that don't start with "nameserver"
if (line.find(kNameserverItem, 0))
{
continue;
}
if (inet_pton(AF_INET, addressString, &ip4Address) == 1)
{
otIp4ToIp4MappedIp6Address(&ip4Address, &ip6Address);
}
else if (inet_pton(AF_INET6, addressString, &ip6Address) != 1)
{
continue;
}
LogInfo("Got nameserver #%u: %s", mUpstreamDnsServerCount, addressString);
mUpstreamDnsServerList[mUpstreamDnsServerCount] = ip6Address;
mUpstreamDnsServerCount++;
}
if (mUpstreamDnsServerCount == 0)
@@ -120,10 +131,12 @@ exit:
void Resolver::Query(otPlatDnsUpstreamQuery *aTxn, const otMessage *aQuery)
{
char packet[kMaxDnsMessageSize];
otError error = OT_ERROR_NONE;
uint16_t length = otMessageGetLength(aQuery);
sockaddr_in serverAddr;
char packet[kMaxDnsMessageSize];
otError error = OT_ERROR_NONE;
uint16_t length = otMessageGetLength(aQuery);
otIp4Address ip4Addr;
sockaddr_in serverAddr4;
sockaddr_in6 serverAddr6;
Transaction *txn = nullptr;
@@ -132,24 +145,44 @@ void Resolver::Query(otPlatDnsUpstreamQuery *aTxn, const otMessage *aQuery)
txn = AllocateTransaction(aTxn);
VerifyOrExit(txn != nullptr, error = OT_ERROR_NO_BUFS);
TryRefreshDnsServerList();
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(53);
for (int i = 0; i < mUpstreamDnsServerCount; i++)
for (uint32_t i = 0; i < mUpstreamDnsServerCount; i++)
{
serverAddr.sin_addr.s_addr = mUpstreamDnsServerList[i];
VerifyOrExit(
sendto(txn->mUdpFd, packet, length, MSG_DONTWAIT, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) > 0,
error = OT_ERROR_NO_ROUTE);
if (otIp4FromIp4MappedIp6Address(&mUpstreamDnsServerList[i], &ip4Addr) == OT_ERROR_NONE)
{
memcpy(&serverAddr4.sin_addr.s_addr, &ip4Addr, sizeof(otIp4Address));
serverAddr4.sin_family = AF_INET;
serverAddr4.sin_port = htons(53);
VerifyOrExit(sendto(txn->mUdpFd4, packet, length, MSG_DONTWAIT, reinterpret_cast<sockaddr *>(&serverAddr4),
sizeof(serverAddr4)) > 0,
error = OT_ERROR_NO_ROUTE);
}
else
{
memcpy(&serverAddr6.sin6_addr, &mUpstreamDnsServerList[i], sizeof(otIp6Address));
serverAddr6.sin6_family = AF_INET6;
serverAddr6.sin6_port = htons(53);
VerifyOrExit(sendto(txn->mUdpFd6, packet, length, MSG_DONTWAIT, reinterpret_cast<sockaddr *>(&serverAddr6),
sizeof(serverAddr6)) > 0,
error = OT_ERROR_NO_ROUTE);
}
}
LogInfo("Forwarded DNS query %p to %d server(s).", static_cast<void *>(aTxn), mUpstreamDnsServerCount);
exit:
if (error != OT_ERROR_NONE)
{
LogCrit("Failed to forward DNS query %p to server: %d", static_cast<void *>(aTxn), error);
LogWarn("Failed to forward DNS query %p to server: %s", static_cast<void *>(aTxn),
otThreadErrorToString(error));
if (txn != nullptr)
{
CloseTransaction(txn);
}
}
return;
}
@@ -168,21 +201,31 @@ void Resolver::Cancel(otPlatDnsUpstreamQuery *aTxn)
Resolver::Transaction *Resolver::AllocateTransaction(otPlatDnsUpstreamQuery *aThreadTxn)
{
int fdOrError = 0;
Transaction *ret = nullptr;
int fd4OrError = 0;
int fd6OrError = 0;
Transaction *ret = nullptr;
for (Transaction &txn : mUpstreamTransaction)
{
if (txn.mThreadTxn == nullptr)
{
fdOrError = CreateUdpSocket();
if (fdOrError < 0)
fd4OrError = CreateUdpSocket(AF_INET);
if (fd4OrError < 0)
{
LogInfo("Failed to create socket for upstream resolver: %d", fdOrError);
LogInfo("Failed to create socket for upstream resolver: %d", fd4OrError);
break;
}
fd6OrError = CreateUdpSocket(AF_INET6);
if (fd6OrError < 0)
{
LogInfo("Failed to create socket for upstream resolver: %d", fd6OrError);
break;
}
ret = &txn;
ret->mUdpFd = fdOrError;
ret->mUdpFd4 = fd4OrError;
ret->mUdpFd6 = fd6OrError;
ret->mThreadTxn = aThreadTxn;
break;
}
@@ -191,20 +234,20 @@ Resolver::Transaction *Resolver::AllocateTransaction(otPlatDnsUpstreamQuery *aTh
return ret;
}
void Resolver::ForwardResponse(Transaction *aTxn)
void Resolver::ForwardResponse(otPlatDnsUpstreamQuery *aThreadTxn, int aFd)
{
char response[kMaxDnsMessageSize];
ssize_t readSize;
otError error = OT_ERROR_NONE;
otMessage *message = nullptr;
VerifyOrExit((readSize = read(aTxn->mUdpFd, response, sizeof(response))) > 0);
VerifyOrExit((readSize = read(aFd, response, sizeof(response))) > 0);
message = otUdpNewMessage(gInstance, nullptr);
VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
SuccessOrExit(error = otMessageAppend(message, response, readSize));
otPlatDnsUpstreamQueryDone(gInstance, aTxn->mThreadTxn, message);
otPlatDnsUpstreamQueryDone(gInstance, aThreadTxn, message);
message = nullptr;
exit:
@@ -228,7 +271,7 @@ Resolver::Transaction *Resolver::GetTransaction(int aFd)
for (Transaction &txn : mUpstreamTransaction)
{
if (txn.mThreadTxn != nullptr && txn.mUdpFd == aFd)
if (txn.mThreadTxn != nullptr && (txn.mUdpFd4 == aFd || txn.mUdpFd6 == aFd))
{
ret = &txn;
break;
@@ -256,10 +299,15 @@ Resolver::Transaction *Resolver::GetTransaction(otPlatDnsUpstreamQuery *aThreadT
void Resolver::CloseTransaction(Transaction *aTxn)
{
if (aTxn->mUdpFd >= 0)
if (aTxn->mUdpFd4 >= 0)
{
close(aTxn->mUdpFd);
aTxn->mUdpFd = -1;
close(aTxn->mUdpFd4);
aTxn->mUdpFd4 = -1;
}
if (aTxn->mUdpFd6 >= 0)
{
close(aTxn->mUdpFd6);
aTxn->mUdpFd6 = -1;
}
aTxn->mThreadTxn = nullptr;
}
@@ -270,11 +318,18 @@ void Resolver::UpdateFdSet(otSysMainloopContext &aContext)
{
if (txn.mThreadTxn != nullptr)
{
FD_SET(txn.mUdpFd, &aContext.mReadFdSet);
FD_SET(txn.mUdpFd, &aContext.mErrorFdSet);
if (txn.mUdpFd > aContext.mMaxFd)
FD_SET(txn.mUdpFd4, &aContext.mReadFdSet);
FD_SET(txn.mUdpFd4, &aContext.mErrorFdSet);
FD_SET(txn.mUdpFd6, &aContext.mReadFdSet);
FD_SET(txn.mUdpFd6, &aContext.mErrorFdSet);
if (txn.mUdpFd6 > aContext.mMaxFd)
{
aContext.mMaxFd = txn.mUdpFd;
aContext.mMaxFd = txn.mUdpFd6;
}
if (txn.mUdpFd4 > aContext.mMaxFd)
{
aContext.mMaxFd = txn.mUdpFd4;
}
}
}
@@ -287,38 +342,34 @@ void Resolver::Process(const otSysMainloopContext &aContext)
if (txn.mThreadTxn != nullptr)
{
// Note: On Linux, we can only get the error via read, so they should share the same logic.
if (FD_ISSET(txn.mUdpFd, &aContext.mErrorFdSet) || FD_ISSET(txn.mUdpFd, &aContext.mReadFdSet))
if (FD_ISSET(txn.mUdpFd4, &aContext.mErrorFdSet) || FD_ISSET(txn.mUdpFd4, &aContext.mReadFdSet))
{
ForwardResponse(&txn);
ForwardResponse(txn.mThreadTxn, txn.mUdpFd4);
CloseTransaction(&txn);
}
else if (FD_ISSET(txn.mUdpFd6, &aContext.mErrorFdSet) || FD_ISSET(txn.mUdpFd6, &aContext.mReadFdSet))
{
ForwardResponse(txn.mThreadTxn, txn.mUdpFd6);
CloseTransaction(&txn);
}
}
}
}
void Resolver::SetUpstreamDnsServers(const otIp6Address *aUpstreamDnsServers, int aNumServers)
void Resolver::SetUpstreamDnsServers(const otIp6Address *aUpstreamDnsServers, uint32_t aNumServers)
{
mUpstreamDnsServerCount = 0;
mUpstreamDnsServerCount = OT_MIN(aNumServers, static_cast<uint32_t>(kMaxUpstreamServerCount));
memcpy(mUpstreamDnsServerList, aUpstreamDnsServers, mUpstreamDnsServerCount * sizeof(otIp6Address));
for (int i = 0; i < aNumServers && i < kMaxUpstreamServerCount; ++i)
{
otIp4Address ip4Address;
// TODO: support DNS servers with IPv6 addresses
if (otIp4FromIp4MappedIp6Address(&aUpstreamDnsServers[i], &ip4Address) == OT_ERROR_NONE)
{
mUpstreamDnsServerList[mUpstreamDnsServerCount] = ip4Address.mFields.m32;
mUpstreamDnsServerCount++;
}
}
LogInfo("Set upstream DNS server list, count: %d", mUpstreamDnsServerCount);
}
int Resolver::CreateUdpSocket(void)
int Resolver::CreateUdpSocket(sa_family_t aFamily)
{
int fd = -1;
VerifyOrExit(otSysGetInfraNetifName() != nullptr, LogDebg("No infra network interface available"));
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
fd = socket(aFamily, SOCK_DGRAM, IPPROTO_UDP);
VerifyOrExit(fd >= 0, LogDebg("Failed to create the UDP socket: %s", strerror(errno)));
#if OPENTHREAD_POSIX_CONFIG_UPSTREAM_DNS_BIND_TO_INFRA_NETIF
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, otSysGetInfraNetifName(), strlen(otSysGetInfraNetifName())) < 0)
+9 -9
View File
@@ -99,7 +99,7 @@ public:
* IPv6 address or an IPv4-mapped IPv6 address.
* @param[in] aNumServers The number of upstream DNS servers.
*/
void SetUpstreamDnsServers(const otIp6Address *aUpstreamDnsServers, int aNumServers);
void SetUpstreamDnsServers(const otIp6Address *aUpstreamDnsServers, uint32_t aNumServers);
private:
static constexpr uint64_t kDnsServerListNullCacheTimeoutMs = 1 * 60 * 1000; // 1 minute
@@ -108,25 +108,25 @@ private:
struct Transaction
{
otPlatDnsUpstreamQuery *mThreadTxn;
int mUdpFd;
int mUdpFd4;
int mUdpFd6;
};
static int CreateUdpSocket(void);
static int CreateUdpSocket(sa_family_t aFamily);
Transaction *GetTransaction(int aFd);
Transaction *GetTransaction(otPlatDnsUpstreamQuery *aThreadTxn);
Transaction *AllocateTransaction(otPlatDnsUpstreamQuery *aThreadTxn);
void ForwardResponse(Transaction *aTxn);
void ForwardResponse(otPlatDnsUpstreamQuery *aThreadTxn, int aFd);
void CloseTransaction(Transaction *aTxn);
void FinishTransaction(int aFd);
void TryRefreshDnsServerList(void);
void LoadDnsServerListFromConf(void);
bool mIsResolvConfEnabled = true;
int mUpstreamDnsServerCount = 0;
in_addr_t mUpstreamDnsServerList[kMaxUpstreamServerCount];
uint64_t mUpstreamDnsServerListFreshness = 0;
bool mIsResolvConfEnabled = true;
uint32_t mUpstreamDnsServerCount = 0;
otIp6Address mUpstreamDnsServerList[kMaxUpstreamServerCount];
uint64_t mUpstreamDnsServerListFreshness = 0;
Transaction mUpstreamTransaction[kMaxUpstreamTransactionCount];
};