diff options
author | alexvru <alexvru@ydb.tech> | 2023-05-18 21:02:06 +0300 |
---|---|---|
committer | alexvru <alexvru@ydb.tech> | 2023-05-18 21:02:06 +0300 |
commit | aa90d2406103b86e18d21d2ee7b2b22aa8229a77 (patch) | |
tree | 51aa3bc3cb50c8b4479c02b03eac2751564f521f | |
parent | bdfcb0ca2201b52b66cc45d813d287f09a9f9ff3 (diff) | |
download | ydb-aa90d2406103b86e18d21d2ee7b2b22aa8229a77.tar.gz |
Validate incoming peer hostname through direct DNS lookup
4 files changed, 69 insertions, 31 deletions
diff --git a/library/cpp/actors/interconnect/interconnect_common.h b/library/cpp/actors/interconnect/interconnect_common.h index 74ccbe88e2..aa2cbe9a19 100644 --- a/library/cpp/actors/interconnect/interconnect_common.h +++ b/library/cpp/actors/interconnect/interconnect_common.h @@ -49,6 +49,7 @@ namespace NActors { ui32 PreallocatedBufferSize = 8 << 10; // 8 KB ui32 NumPreallocatedBuffers = 16; bool EnableExternalDataChannel = false; + bool ValidateIncomingPeerViaDirectLookup = false; ui32 GetSendBufferSize() const { ui32 res = 512 * 1024; // 512 kb is the default value for send buffer diff --git a/library/cpp/actors/interconnect/interconnect_handshake.cpp b/library/cpp/actors/interconnect/interconnect_handshake.cpp index 835b110a6d..9b2cf91a69 100644 --- a/library/cpp/actors/interconnect/interconnect_handshake.cpp +++ b/library/cpp/actors/interconnect/interconnect_handshake.cpp @@ -93,37 +93,7 @@ namespace NActors { {} void Connect(TString *peerAddr) { - // issue request to a nameservice to resolve peer node address - const auto mono = TActivationContext::Monotonic(); - Actor->Send(Actor->Common->NameserviceId, new TEvInterconnect::TEvResolveNode(Actor->PeerNodeId, - TActivationContext::Now() + (Actor->Deadline - mono))); - - // wait for the result - auto ev = Actor->WaitForSpecificEvent<TEvResolveError, TEvLocalNodeInfo, TEvInterconnect::TEvNodeAddress>( - "ResolveNode", mono + ResolveTimeout); - - // extract address from the result - std::vector<NInterconnect::TAddress> addresses; - if (!ev) { - Actor->Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve timed out", true); - } else if (auto *p = ev->CastAsLocal<TEvLocalNodeInfo>()) { - addresses = std::move(p->Addresses); - if (addresses.empty()) { - Actor->Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true); - } - } else if (auto *p = ev->CastAsLocal<TEvInterconnect::TEvNodeAddress>()) { - const auto& r = p->Record; - if (!r.HasAddress() || !r.HasPort()) { - Actor->Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true); - } - addresses.emplace_back(r.GetAddress(), static_cast<ui16>(r.GetPort())); - } else { - Y_VERIFY(ev->GetTypeRewrite() == ui32(ENetwork::ResolveError)); - Actor->Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: " + ev->Get<TEvResolveError>()->Explain - + ", Unresolved host# " + ev->Get<TEvResolveError>()->Host, true); - } - - for (const NInterconnect::TAddress& address : addresses) { + for (const NInterconnect::TAddress& address : Actor->ResolvePeer()) { // create the socket with matching address family int err = 0; Socket = NInterconnect::TStreamSocket::Make(address.GetFamily(), &err); @@ -837,6 +807,64 @@ namespace NActors { } } + std::vector<NInterconnect::TAddress> ResolvePeer() { + // issue request to a nameservice to resolve peer node address + const auto mono = TActivationContext::Monotonic(); + Send(Common->NameserviceId, new TEvInterconnect::TEvResolveNode(PeerNodeId, TActivationContext::Now() + (Deadline - mono))); + + // wait for the result + auto ev = WaitForSpecificEvent<TEvResolveError, TEvLocalNodeInfo, TEvInterconnect::TEvNodeAddress>( + "ValidateIncomingPeerViaDirectLookup", mono + ResolveTimeout); + + // extract address from the result + std::vector<NInterconnect::TAddress> addresses; + if (!ev) { + Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve timed out", true); + } else if (auto *p = ev->CastAsLocal<TEvLocalNodeInfo>()) { + addresses = std::move(p->Addresses); + if (addresses.empty()) { + Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true); + } + } else if (auto *p = ev->CastAsLocal<TEvInterconnect::TEvNodeAddress>()) { + const auto& r = p->Record; + if (!r.HasAddress() || !r.HasPort()) { + Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true); + } + addresses.emplace_back(r.GetAddress(), static_cast<ui16>(r.GetPort())); + } else { + Y_VERIFY(ev->GetTypeRewrite() == ui32(ENetwork::ResolveError)); + Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: " + ev->Get<TEvResolveError>()->Explain + + ", Unresolved host# " + ev->Get<TEvResolveError>()->Host, true); + } + + return addresses; + } + + void ValidateIncomingPeerViaDirectLookup() { + auto addresses = ResolvePeer(); + + for (const auto& address : addresses) { + if (address.GetAddress() == PeerAddr) { + return; + } + } + + auto makeList = [&] { + TStringStream s; + s << '['; + for (auto it = addresses.begin(); it != addresses.end(); ++it) { + if (it != addresses.begin()) { + s << ' '; + } + s << it->GetAddress(); + } + s << ']'; + return s.Str(); + }; + Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, TStringBuilder() << "Connecting node does not resolve to peer address" + << " PeerAddr# " << PeerAddr << " AddressList# " << makeList(), true); + } + void PerformIncomingHandshake() { LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH02", NLog::PRI_DEBUG, "starting incoming handshake"); @@ -864,6 +892,11 @@ namespace NActors { } UpdatePrefix(); + // validate incoming peer if needed + if (Common->Settings.ValidateIncomingPeerViaDirectLookup) { + ValidateIncomingPeerViaDirectLookup(); + } + // extract next packet NextPacketFromPeer = request.Header.NextPacket; diff --git a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp index 24c6a9018c..5379919c86 100644 --- a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp +++ b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp @@ -573,6 +573,9 @@ static TInterconnectSettings GetInterconnectSettings(const NKikimrConfig::TInter if (config.HasEnableExternalDataChannel()) { result.EnableExternalDataChannel = config.GetEnableExternalDataChannel(); } + if (config.HasValidateIncomingPeerViaDirectLookup()) { + result.ValidateIncomingPeerViaDirectLookup = config.GetValidateIncomingPeerViaDirectLookup(); + } return result; } diff --git a/ydb/core/protos/config.proto b/ydb/core/protos/config.proto index 16c9366041..b5fe889700 100644 --- a/ydb/core/protos/config.proto +++ b/ydb/core/protos/config.proto @@ -439,6 +439,7 @@ message TInterconnectConfig { optional uint32 PreallocatedBufferSize = 40; optional uint32 NumPreallocatedBuffers = 41; optional bool EnableExternalDataChannel = 42; + optional bool ValidateIncomingPeerViaDirectLookup = 44; // ballast is added to IC handshake frames to ensure correctness of jumbo frames transmission over network optional uint32 HandshakeBallastSize = 14; |