mirror of
https://github.com/espressif/openthread.git
synced 2026-08-25 19:59:51 +00:00
[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:
+107
-56
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user