aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralexvru <alexvru@ydb.tech>2023-05-18 21:02:06 +0300
committeralexvru <alexvru@ydb.tech>2023-05-18 21:02:06 +0300
commitaa90d2406103b86e18d21d2ee7b2b22aa8229a77 (patch)
tree51aa3bc3cb50c8b4479c02b03eac2751564f521f
parentbdfcb0ca2201b52b66cc45d813d287f09a9f9ff3 (diff)
downloadydb-aa90d2406103b86e18d21d2ee7b2b22aa8229a77.tar.gz
Validate incoming peer hostname through direct DNS lookup
-rw-r--r--library/cpp/actors/interconnect/interconnect_common.h1
-rw-r--r--library/cpp/actors/interconnect/interconnect_handshake.cpp95
-rw-r--r--ydb/core/driver_lib/run/kikimr_services_initializers.cpp3
-rw-r--r--ydb/core/protos/config.proto1
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;