From a7dbd9b46da6a7b9993f8d226b06088a35fed99e Mon Sep 17 00:00:00 2001 From: Yang Song Date: Thu, 13 Mar 2025 23:36:10 +0800 Subject: [PATCH] [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. --- src/posix/platform/resolver.cpp | 163 +++++++++++++++++++++----------- src/posix/platform/resolver.hpp | 18 ++-- 2 files changed, 116 insertions(+), 65 deletions(-) diff --git a/src/posix/platform/resolver.cpp b/src/posix/platform/resolver.cpp index 0e16e6fab..6f417756c 100644 --- a/src/posix/platform/resolver.cpp +++ b/src/posix/platform/resolver.cpp @@ -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(&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(&serverAddr6), + sizeof(serverAddr6)) > 0, + error = OT_ERROR_NO_ROUTE); + } } LogInfo("Forwarded DNS query %p to %d server(s).", static_cast(aTxn), mUpstreamDnsServerCount); exit: if (error != OT_ERROR_NONE) { - LogCrit("Failed to forward DNS query %p to server: %d", static_cast(aTxn), error); + LogWarn("Failed to forward DNS query %p to server: %s", static_cast(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(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) diff --git a/src/posix/platform/resolver.hpp b/src/posix/platform/resolver.hpp index d1d0e2cfc..94830124d 100644 --- a/src/posix/platform/resolver.hpp +++ b/src/posix/platform/resolver.hpp @@ -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]; };