Skip to content

Commit d7c895a

Browse files
authored
EXT-1620: Use getaddrinfo instead of c-ares in DnsResolver (#27689) (#28175)
1 parent cb20601 commit d7c895a

File tree

5 files changed

+215
-35
lines changed

5 files changed

+215
-35
lines changed

ydb/core/driver_lib/run/kikimr_services_initializers.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,14 @@ void TBasicServicesInitializer::InitializeServices(NActors::TActorSystemSetup* s
557557
resolverOptions.MonCounters = GetServiceCounters(counters, "utils")->GetSubgroup("subsystem", "dns_resolver");
558558
resolverOptions.ForceTcp = nsConfig.GetForceTcp();
559559
resolverOptions.KeepSocket = nsConfig.GetKeepSocket();
560+
switch (nsConfig.GetDnsResolverType()) {
561+
case NKikimrConfig::TStaticNameserviceConfig::ARES:
562+
resolverOptions.Type = NDnsResolver::EDnsResolverType::Ares;
563+
break;
564+
case NKikimrConfig::TStaticNameserviceConfig::LIBC:
565+
resolverOptions.Type = NDnsResolver::EDnsResolverType::Libc;
566+
break;
567+
}
560568
IActor *resolver = NDnsResolver::CreateOnDemandDnsResolver(resolverOptions);
561569

562570
setup->LocalServices.emplace_back(

ydb/core/protos/config.proto

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ message TStaticNameserviceConfig {
148148
NS_EXTERNAL = 3; // may be paired with external discovery
149149
}
150150

151+
enum EDnsResolverType {
152+
ARES = 0;
153+
LIBC = 1;
154+
}
155+
151156
message TEndpoint {
152157
optional string Name = 1;
153158
optional string Address = 2;
@@ -177,6 +182,7 @@ message TStaticNameserviceConfig {
177182
optional ENameserviceType Type = 5;
178183
optional bool KeepSocket = 6 [default = true];
179184
optional bool ForceTcp = 7 [default = false];
185+
optional EDnsResolverType DnsResolverType = 8 [default = ARES];
180186
}
181187

182188
message TDynamicNameserviceConfig {

ydb/library/actors/dnsresolver/dnsresolver.cpp

Lines changed: 156 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,13 @@ namespace NDnsResolver {
130130
std::atomic<size_t> Activations{ 0 };
131131
};
132132

133-
class TSimpleDnsResolver
134-
: public TActor<TSimpleDnsResolver>
133+
class TAresDnsResolver
134+
: public TActor<TAresDnsResolver>
135135
, private TAresLibraryInitBase
136136
, private TCallbackQueueBase
137137
{
138138
public:
139-
TSimpleDnsResolver(TSimpleDnsResolverOptions options) noexcept
139+
TAresDnsResolver(TSimpleDnsResolverOptions options) noexcept
140140
: TActor(&TThis::StateWork)
141141
, Options(std::move(options))
142142
, WorkerThread(&TThis::WorkerThreadStart, this)
@@ -146,7 +146,7 @@ namespace NDnsResolver {
146146
WorkerThread.Start();
147147
}
148148

149-
~TSimpleDnsResolver() noexcept override {
149+
~TAresDnsResolver() noexcept override {
150150
if (!Stopped) {
151151
PushCallback([this] {
152152
// Mark as stopped first
@@ -384,7 +384,7 @@ namespace NDnsResolver {
384384

385385
private:
386386
static void* WorkerThreadStart(void* arg) noexcept {
387-
static_cast<TSimpleDnsResolver*>(arg)->WorkerThreadLoop();
387+
static_cast<TAresDnsResolver*>(arg)->WorkerThreadLoop();
388388
return nullptr;
389389
}
390390

@@ -483,9 +483,159 @@ namespace NDnsResolver {
483483
bool Stopped = false;
484484
};
485485

486+
487+
#if not defined(_win32_)
488+
class TLibcDnsResolver
489+
: public TActor<TLibcDnsResolver>
490+
, private TCallbackQueueBase
491+
{
492+
public:
493+
TLibcDnsResolver(TSimpleDnsResolverOptions options) noexcept
494+
: TActor(&TThis::StateWork)
495+
, WorkerThread(&TThis::WorkerThreadStart, this)
496+
, Options(options)
497+
{
498+
WorkerThread.Start();
499+
}
500+
501+
~TLibcDnsResolver() noexcept override {
502+
if (!Stopped) {
503+
PushCallback([this] {
504+
Stopped = true;
505+
});
506+
507+
WorkerThread.Join();
508+
}
509+
}
510+
511+
static constexpr EActivityType ActorActivityType() {
512+
return EActivityType::DNS_RESOLVER;
513+
}
514+
515+
private:
516+
STRICT_STFUNC(StateWork, {
517+
hFunc(TEvents::TEvPoison, Handle);
518+
hFunc(TEvDns::TEvGetHostByName, Handle);
519+
hFunc(TEvDns::TEvGetAddr, Handle);
520+
})
521+
522+
void Handle(TEvents::TEvPoison::TPtr&) {
523+
Y_ABORT_UNLESS(!Stopped);
524+
525+
PushCallback([this] {
526+
// Mark as stopped last
527+
Stopped = true;
528+
});
529+
530+
WorkerThread.Join();
531+
PassAway();
532+
}
533+
534+
private:
535+
std::unique_ptr<TEvDns::TEvGetHostByNameResult> GetHostByName(TString name, int family) {
536+
auto result = std::make_unique<TEvDns::TEvGetHostByNameResult>();
537+
538+
struct addrinfo hints, *res;
539+
memset(&hints, 0, sizeof(hints));
540+
hints.ai_family = family;
541+
hints.ai_socktype = Options.ForceTcp ? SOCK_STREAM : SOCK_DGRAM;
542+
543+
result->Status = getaddrinfo(name.c_str(), nullptr, &hints, &res);
544+
if (result->Status != 0) {
545+
result->ErrorText = gai_strerror(result->Status);
546+
return result;
547+
}
548+
Y_DEFER { freeaddrinfo(res); };
549+
550+
for (auto *node = res; node; node = node->ai_next) {
551+
switch (node->ai_family) {
552+
case AF_INET: {
553+
result->AddrsV4.emplace_back(((sockaddr_in*)node->ai_addr)->sin_addr);
554+
break;
555+
}
556+
case AF_INET6: {
557+
result->AddrsV6.emplace_back(((sockaddr_in6*)node->ai_addr)->sin6_addr);
558+
break;
559+
}
560+
default:
561+
Y_ABORT("unknown address family in getaddrinfo callback");
562+
}
563+
}
564+
565+
return result;
566+
}
567+
568+
std::unique_ptr<TEvDns::TEvGetAddrResult> GetAddr(TString name, int family) {
569+
auto result = std::make_unique<TEvDns::TEvGetAddrResult>();
570+
auto res = GetHostByName(name, family);
571+
572+
result->Status = res->Status;
573+
result->ErrorText = res->ErrorText;
574+
if (res->AddrsV4.empty() && res->AddrsV6.empty()) {
575+
result->Status = EAI_NODATA;
576+
result->ErrorText = gai_strerror(result->Status);
577+
return result;
578+
}
579+
if (res->AddrsV4.size() > 0) {
580+
result->Addr = res->AddrsV4[0];
581+
}
582+
if (res->AddrsV6.size() > 0) {
583+
result->Addr = res->AddrsV6[0];
584+
}
585+
return result;
586+
587+
}
588+
589+
private:
590+
void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
591+
auto* msg = ev->Get();
592+
PushCallback([this, as = TActivationContext::ActorSystem(), name = std::move(msg->Name), family = msg->Family, sender = ev->Sender, cookie = ev->Cookie] () mutable {
593+
auto result = GetHostByName(name, family);
594+
as->Send(new IEventHandle(sender, SelfId(), result.release(), 0, cookie));
595+
});
596+
}
597+
598+
void Handle(TEvDns::TEvGetAddr::TPtr& ev) {
599+
auto* msg = ev->Get();
600+
PushCallback([this, as = TActivationContext::ActorSystem(), name = std::move(msg->Name), family = msg->Family, sender = ev->Sender, cookie = ev->Cookie] () mutable {
601+
auto result = GetAddr(name, family);
602+
as->Send(new IEventHandle(sender, SelfId(), result.release(), 0, cookie));
603+
});
604+
}
605+
606+
private:
607+
static void* WorkerThreadStart(void* arg) noexcept {
608+
static_cast<TLibcDnsResolver*>(arg)->WorkerThreadLoop();
609+
return nullptr;
610+
}
611+
612+
void WorkerThreadLoop() noexcept {
613+
TThread::SetCurrentThreadName("DnsResolver");
614+
while (!Stopped) {
615+
RunCallbacks();
616+
}
617+
}
618+
private:
619+
TThread WorkerThread;
620+
bool Stopped = false;
621+
TSimpleDnsResolverOptions Options;
622+
};
623+
624+
IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options) {
625+
switch (options.Type) {
626+
case EDnsResolverType::Ares:
627+
return new TAresDnsResolver(std::move(options));
628+
case EDnsResolverType::Libc:
629+
return new TLibcDnsResolver(std::move(options));
630+
default:
631+
Y_ABORT_UNLESS(false, "Invalid dns resolver type: %" PRIu32, options.Type);
632+
}
633+
}
634+
#else
486635
IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options) {
487-
return new TSimpleDnsResolver(std::move(options));
636+
return new TAresDnsResolver(std::move(options));
488637
}
638+
#endif
489639

490640
} // namespace NDnsResolver
491641
} // namespace NActors

ydb/library/actors/dnsresolver/dnsresolver.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,14 @@ namespace NDnsResolver {
8282
};
8383
};
8484

85+
enum class EDnsResolverType {
86+
Ares,
87+
Libc,
88+
};
89+
8590
struct TSimpleDnsResolverOptions {
91+
// Type of dns resolver to use
92+
EDnsResolverType Type = EDnsResolverType::Ares;
8693
// Initial per-server timeout, grows exponentially with each retry
8794
TDuration Timeout = TDuration::Seconds(1);
8895
// Number of attempts per-server

ydb/library/actors/dnsresolver/dnsresolver_ut.cpp

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,42 +29,51 @@ Y_UNIT_TEST_SUITE(DnsResolver) {
2929
};
3030

3131
Y_UNIT_TEST(ResolveLocalHost) {
32-
TTestActorRuntimeBase runtime;
33-
runtime.Initialize();
34-
auto sender = runtime.AllocateEdgeActor();
35-
auto resolver = runtime.Register(CreateSimpleDnsResolver());
36-
runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)),
37-
0, true);
38-
auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
39-
UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
40-
size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
41-
UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
32+
for (auto type : { EDnsResolverType::Ares, EDnsResolverType::Libc }) {
33+
TSimpleDnsResolverOptions options { .Type = type };
34+
TTestActorRuntimeBase runtime;
35+
runtime.Initialize();
36+
auto sender = runtime.AllocateEdgeActor();
37+
auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
38+
runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)),
39+
0, true);
40+
auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
41+
UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
42+
size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
43+
UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
44+
}
4245
}
4346

4447
Y_UNIT_TEST(ResolveYandexRu) {
45-
TTestActorRuntimeBase runtime;
46-
runtime.Initialize();
47-
auto sender = runtime.AllocateEdgeActor();
48-
auto resolver = runtime.Register(CreateSimpleDnsResolver());
49-
runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("yandex.ru", AF_UNSPEC)),
50-
0, true);
51-
auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
52-
UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
53-
size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
54-
UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
48+
for (auto type : { EDnsResolverType::Ares, EDnsResolverType::Libc }) {
49+
TSimpleDnsResolverOptions options { .Type = type };
50+
TTestActorRuntimeBase runtime;
51+
runtime.Initialize();
52+
auto sender = runtime.AllocateEdgeActor();
53+
auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
54+
runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("yandex.ru", AF_UNSPEC)),
55+
0, true);
56+
auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
57+
UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
58+
size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
59+
UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
60+
}
5561
}
5662

5763
Y_UNIT_TEST(GetAddrYandexRu) {
58-
TTestActorRuntimeBase runtime;
59-
runtime.Initialize();
60-
auto sender = runtime.AllocateEdgeActor();
61-
auto resolver = runtime.Register(CreateSimpleDnsResolver());
64+
for (auto type : { EDnsResolverType::Ares, EDnsResolverType::Libc }) {
65+
TSimpleDnsResolverOptions options { .Type = type };
66+
TTestActorRuntimeBase runtime;
67+
runtime.Initialize();
68+
auto sender = runtime.AllocateEdgeActor();
69+
auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
6270

63-
runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetAddr("yandex.ru", AF_UNSPEC)),
64-
0, true);
65-
auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
66-
UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
67-
UNIT_ASSERT_C(ev->Get()->IsV4() || ev->Get()->IsV6(), "Expect v4 or v6 address");
71+
runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetAddr("yandex.ru", AF_UNSPEC)),
72+
0, true);
73+
auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
74+
UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
75+
UNIT_ASSERT_C(ev->Get()->IsV4() || ev->Get()->IsV6(), "Expect v4 or v6 address");
76+
}
6877
}
6978

7079
Y_UNIT_TEST(ResolveTimeout) {

0 commit comments

Comments
 (0)