summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2016-08-19 11:26:05 -0400
committerMark Benvenuto <mark.benvenuto@mongodb.com>2016-08-19 11:43:31 -0400
commit78c06c7e342bb159bcf22c85502cb7db3a695ffd (patch)
tree2ac566e4a34dd2945db79e949cc5c94d8463e034 /src/mongo
parent1a3d60af4d27d72e15637bb43510fe1b592a6c43 (diff)
downloadmongo-78c06c7e342bb159bcf22c85502cb7db3a695ffd.tar.gz
SERVER-25393 Disallow mongos making connections to older versions
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/client/dbclient.cpp16
-rw-r--r--src/mongo/db/db.cpp8
-rw-r--r--src/mongo/db/dbdirectclient.cpp4
-rw-r--r--src/mongo/db/repl/replication_info.cpp4
-rw-r--r--src/mongo/db/s/set_shard_version_command.cpp4
-rw-r--r--src/mongo/db/wire_version.h38
-rw-r--r--src/mongo/dbtests/dbtests.cpp8
-rw-r--r--src/mongo/executor/network_interface_asio_auth.cpp11
-rw-r--r--src/mongo/executor/network_interface_asio_connect.cpp3
-rw-r--r--src/mongo/executor/network_interface_asio_test.cpp16
-rw-r--r--src/mongo/rpc/protocol.cpp73
-rw-r--r--src/mongo/rpc/protocol.h22
-rw-r--r--src/mongo/rpc/protocol_test.cpp74
-rw-r--r--src/mongo/s/client/sharding_network_connection_hook.cpp15
-rw-r--r--src/mongo/s/commands/cluster_is_master_cmd.cpp4
-rw-r--r--src/mongo/s/server.cpp8
16 files changed, 227 insertions, 81 deletions
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp
index 51f5fe04c94..87a8f39fd3b 100644
--- a/src/mongo/client/dbclient.cpp
+++ b/src/mongo/client/dbclient.cpp
@@ -802,12 +802,18 @@ Status DBClientConnection::connect(const HostAndPort& serverAddress, StringData
return swProtocolSet.getStatus();
}
- _setServerRPCProtocols(swProtocolSet.getValue());
+ auto validateStatus =
+ rpc::validateWireVersion(WireSpec::instance().outgoing, swProtocolSet.getValue().version);
+ if (!validateStatus.isOK()) {
+ warning() << "remote host has incompatible wire version: " << validateStatus;
- auto negotiatedProtocol =
- rpc::negotiate(getServerRPCProtocols(),
- rpc::computeProtocolSet(WireSpec::instance().minWireVersionOutgoing,
- WireSpec::instance().maxWireVersionOutgoing));
+ return validateStatus;
+ }
+
+ _setServerRPCProtocols(swProtocolSet.getValue().protocolSet);
+
+ auto negotiatedProtocol = rpc::negotiate(
+ getServerRPCProtocols(), rpc::computeProtocolSet(WireSpec::instance().outgoing));
if (!negotiatedProtocol.isOK()) {
return negotiatedProtocol.getStatus();
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index c10f85b94c4..57d0c52a840 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -468,11 +468,11 @@ static void repairDatabasesAndCheckVersion(OperationContext* txn) {
static void _initWireSpec() {
WireSpec& spec = WireSpec::instance();
// accept from any version
- spec.minWireVersionIncoming = RELEASE_2_4_AND_BEFORE;
- spec.maxWireVersionIncoming = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.incoming.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.incoming.maxWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
// connect to any version
- spec.minWireVersionOutgoing = RELEASE_2_4_AND_BEFORE;
- spec.maxWireVersionOutgoing = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.outgoing.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.outgoing.maxWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
}
diff --git a/src/mongo/db/dbdirectclient.cpp b/src/mongo/db/dbdirectclient.cpp
index 06c06991722..f4bf62ed644 100644
--- a/src/mongo/db/dbdirectclient.cpp
+++ b/src/mongo/db/dbdirectclient.cpp
@@ -89,12 +89,12 @@ std::string DBDirectClient::getServerAddress() const {
// Returned version should match the incoming connections restrictions.
int DBDirectClient::getMinWireVersion() {
- return WireSpec::instance().minWireVersionIncoming;
+ return WireSpec::instance().incoming.minWireVersion;
}
// Returned version should match the incoming connections restrictions.
int DBDirectClient::getMaxWireVersion() {
- return WireSpec::instance().maxWireVersionIncoming;
+ return WireSpec::instance().incoming.maxWireVersion;
}
ConnectionString::ConnectionType DBDirectClient::type() const {
diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp
index 90dd3fb451a..d27257a8eb0 100644
--- a/src/mongo/db/repl/replication_info.cpp
+++ b/src/mongo/db/repl/replication_info.cpp
@@ -286,8 +286,8 @@ public:
result.appendNumber("maxMessageSizeBytes", MaxMessageSizeBytes);
result.appendNumber("maxWriteBatchSize", BatchedCommandRequest::kMaxWriteBatchSize);
result.appendDate("localTime", jsTime());
- result.append("maxWireVersion", WireSpec::instance().maxWireVersionIncoming);
- result.append("minWireVersion", WireSpec::instance().minWireVersionIncoming);
+ result.append("maxWireVersion", WireSpec::instance().incoming.maxWireVersion);
+ result.append("minWireVersion", WireSpec::instance().incoming.minWireVersion);
result.append("readOnly", storageGlobalParams.readOnly);
const auto parameter = mapFindWithDefault(ServerParameterSet::getGlobal()->getMap(),
diff --git a/src/mongo/db/s/set_shard_version_command.cpp b/src/mongo/db/s/set_shard_version_command.cpp
index b19e72c9489..de56695a4cb 100644
--- a/src/mongo/db/s/set_shard_version_command.cpp
+++ b/src/mongo/db/s/set_shard_version_command.cpp
@@ -148,8 +148,8 @@ public:
// TODO: SERVER-21397 remove post v3.3.
// Send back wire version to let mongos know what protocol we can speak
- result.append("minWireVersion", WireSpec::instance().minWireVersionIncoming);
- result.append("maxWireVersion", WireSpec::instance().maxWireVersionIncoming);
+ result.append("minWireVersion", WireSpec::instance().incoming.minWireVersion);
+ result.append("maxWireVersion", WireSpec::instance().incoming.maxWireVersion);
return true;
}
diff --git a/src/mongo/db/wire_version.h b/src/mongo/db/wire_version.h
index 86f629e0ca7..de816c0ae1b 100644
--- a/src/mongo/db/wire_version.h
+++ b/src/mongo/db/wire_version.h
@@ -26,6 +26,10 @@
* it in the license file.
*/
+#pragma once
+
+#include "mongo/base/disallow_copying.h"
+
namespace mongo {
/**
@@ -63,6 +67,14 @@ enum WireVersion {
COMMANDS_ACCEPT_WRITE_CONCERN = 5,
};
+/**
+ * Struct to pass around information about wire version.
+ */
+struct WireVersionInfo {
+ int minWireVersion;
+ int maxWireVersion;
+};
+
struct WireSpec {
MONGO_DISALLOW_COPYING(WireSpec);
@@ -71,18 +83,20 @@ struct WireSpec {
return instance;
}
- // Minimum version that the server accepts on incoming requests. We should bump this whenever
- // we don't want to allow incoming connections from clients that are too old.
- int minWireVersionIncoming;
- // Latest version that the server accepts on incoming requests. This should always be at the
- // latest entry in WireVersion.
- int maxWireVersionIncoming;
-
- // Minimum version allowed on remote nodes when the server sends requests. We should bump this
- // whenever we don't want to connect to clients that are too old.
- int minWireVersionOutgoing;
- // Latest version allowed on remote nodes when the server sends requests.
- int maxWireVersionOutgoing;
+ // incoming.minWireVersion - Minimum version that the server accepts on incoming requests. We
+ // should bump this whenever we don't want to allow incoming connections from clients that are
+ // too old.
+
+ // incoming.maxWireVersion - Latest version that the server accepts on incoming requests. This
+ // should always be at the latest entry in WireVersion.
+ WireVersionInfo incoming;
+
+ // outgoing.minWireVersion - Minimum version allowed on remote nodes when the server sends
+ // requests. We should bump this whenever we don't want to connect to clients that are too old.
+
+ // outgoing.maxWireVersion - Latest version allowed on remote nodes when the server sends
+ // requests.
+ WireVersionInfo outgoing;
private:
WireSpec() = default;
diff --git a/src/mongo/dbtests/dbtests.cpp b/src/mongo/dbtests/dbtests.cpp
index d9221e0944e..96ad9253f08 100644
--- a/src/mongo/dbtests/dbtests.cpp
+++ b/src/mongo/dbtests/dbtests.cpp
@@ -58,11 +58,11 @@ namespace dbtests {
void initWireSpec() {
WireSpec& spec = WireSpec::instance();
// accept from any version
- spec.minWireVersionIncoming = RELEASE_2_4_AND_BEFORE;
- spec.maxWireVersionIncoming = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.incoming.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.incoming.maxWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
// connect to any version
- spec.minWireVersionOutgoing = RELEASE_2_4_AND_BEFORE;
- spec.maxWireVersionOutgoing = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.outgoing.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.outgoing.maxWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
}
Status createIndex(OperationContext* txn, StringData ns, const BSONObj& keys, bool unique) {
diff --git a/src/mongo/executor/network_interface_asio_auth.cpp b/src/mongo/executor/network_interface_asio_auth.cpp
index d2e341007e6..78c66318805 100644
--- a/src/mongo/executor/network_interface_asio_auth.cpp
+++ b/src/mongo/executor/network_interface_asio_auth.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/auth/internal_user_auth.h"
#include "mongo/db/commands.h"
#include "mongo/db/server_options.h"
+#include "mongo/db/wire_version.h"
#include "mongo/rpc/factory.h"
#include "mongo/rpc/get_status_from_command_result.h"
#include "mongo/rpc/legacy_request_builder.h"
@@ -109,7 +110,15 @@ void NetworkInterfaceASIO::_runIsMaster(AsyncOp* op) {
if (!protocolSet.isOK())
return _completeOperation(op, protocolSet.getStatus());
- op->connection().setServerProtocols(protocolSet.getValue());
+ auto validateStatus =
+ rpc::validateWireVersion(WireSpec::instance().outgoing, protocolSet.getValue().version);
+ if (!validateStatus.isOK()) {
+ warning() << "remote host has incompatible wire version: " << validateStatus;
+
+ return _completeOperation(op, validateStatus);
+ }
+
+ op->connection().setServerProtocols(protocolSet.getValue().protocolSet);
invariant(op->connection().clientProtocols() != rpc::supports::kNone);
// Set the operation protocol
diff --git a/src/mongo/executor/network_interface_asio_connect.cpp b/src/mongo/executor/network_interface_asio_connect.cpp
index ffd392e15c7..57a9f302b58 100644
--- a/src/mongo/executor/network_interface_asio_connect.cpp
+++ b/src/mongo/executor/network_interface_asio_connect.cpp
@@ -52,8 +52,7 @@ NetworkInterfaceASIO::AsyncConnection::AsyncConnection(std::unique_ptr<AsyncStre
rpc::ProtocolSet protocols)
: _stream(std::move(stream)),
_serverProtocols(protocols),
- _clientProtocols(rpc::computeProtocolSet(WireSpec::instance().minWireVersionOutgoing,
- WireSpec::instance().maxWireVersionOutgoing)) {}
+ _clientProtocols(rpc::computeProtocolSet(WireSpec::instance().outgoing)) {}
AsyncStreamInterface& NetworkInterfaceASIO::AsyncConnection::stream() {
return *_stream;
diff --git a/src/mongo/executor/network_interface_asio_test.cpp b/src/mongo/executor/network_interface_asio_test.cpp
index 0c1117a1693..a7d894a7deb 100644
--- a/src/mongo/executor/network_interface_asio_test.cpp
+++ b/src/mongo/executor/network_interface_asio_test.cpp
@@ -59,11 +59,11 @@ HostAndPort testHost{"localhost", 20000};
void initWireSpecMongoD() {
WireSpec& spec = WireSpec::instance();
// accept from any version
- spec.minWireVersionIncoming = RELEASE_2_4_AND_BEFORE;
- spec.maxWireVersionIncoming = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.incoming.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.incoming.maxWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
// connect to any version
- spec.minWireVersionOutgoing = RELEASE_2_4_AND_BEFORE;
- spec.maxWireVersionOutgoing = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.outgoing.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.outgoing.maxWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
}
// Utility function to use with mock streams
@@ -72,9 +72,9 @@ RemoteCommandResponse simulateIsMaster(RemoteCommandRequest request) {
ASSERT_EQ(request.dbname, "admin");
RemoteCommandResponse response;
- response.data = BSON("minWireVersion" << mongo::WireSpec::instance().minWireVersionIncoming
+ response.data = BSON("minWireVersion" << mongo::WireSpec::instance().incoming.minWireVersion
<< "maxWireVersion"
- << mongo::WireSpec::instance().maxWireVersionIncoming);
+ << mongo::WireSpec::instance().incoming.maxWireVersion);
return response;
}
@@ -671,9 +671,9 @@ TEST_F(NetworkInterfaceASIOConnectionHookTest, ValidateHostInvalid) {
rpc::Protocol::kOpQuery, [](RemoteCommandRequest request) -> RemoteCommandResponse {
RemoteCommandResponse response;
response.data =
- BSON("minWireVersion" << mongo::WireSpec::instance().minWireVersionIncoming
+ BSON("minWireVersion" << mongo::WireSpec::instance().incoming.minWireVersion
<< "maxWireVersion"
- << mongo::WireSpec::instance().maxWireVersionIncoming
+ << mongo::WireSpec::instance().incoming.maxWireVersion
<< "TESTKEY"
<< "TESTVALUE");
return response;
diff --git a/src/mongo/rpc/protocol.cpp b/src/mongo/rpc/protocol.cpp
index 32b9f5b4442..90e7ad58389 100644
--- a/src/mongo/rpc/protocol.cpp
+++ b/src/mongo/rpc/protocol.cpp
@@ -108,7 +108,8 @@ StatusWith<ProtocolSet> parseProtocolSet(StringData repr) {
<< "and 'all' (0x3) are supported.");
}
-StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMasterReply) {
+StatusWith<ProtocolSetAndWireVersionInfo> parseProtocolSetFromIsMasterReply(
+ const BSONObj& isMasterReply) {
long long maxWireVersion;
auto maxWireExtractStatus =
bsonExtractIntegerField(isMasterReply, "maxWireVersion", &maxWireVersion);
@@ -120,7 +121,7 @@ StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMaste
// MongoDB 2.4 and earlier do not have maxWireVersion/minWireVersion in their 'isMaster' replies
if ((maxWireExtractStatus == minWireExtractStatus) &&
(maxWireExtractStatus == ErrorCodes::NoSuchKey)) {
- return supports::kOpQueryOnly;
+ return {{supports::kOpQueryOnly, {0, 0}}};
} else if (!maxWireExtractStatus.isOK()) {
return maxWireExtractStatus;
} else if (!minWireExtractStatus.isOK()) {
@@ -140,29 +141,77 @@ StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMaste
isMongos = (msgField == "isdbgrid");
}
- return (!isMongos && supportsWireVersionForOpCommandInMongod(minWireVersion, maxWireVersion))
- ? supports::kAll
- : supports::kOpQueryOnly;
+ if (minWireVersion < 0 || maxWireVersion < 0 ||
+ minWireVersion >= std::numeric_limits<int>::max() ||
+ maxWireVersion >= std::numeric_limits<int>::max()) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Server min and max wire version have invalid values ("
+ << minWireVersion
+ << ","
+ << maxWireVersion
+ << ")");
+ }
+
+ WireVersionInfo version{static_cast<int>(minWireVersion), static_cast<int>(maxWireVersion)};
+
+ return {{(!isMongos && supportsWireVersionForOpCommandInMongod(version))
+ ? supports::kAll
+ : supports::kOpQueryOnly,
+ version}};
}
-bool supportsWireVersionForOpCommandInMongod(int minWireVersion, int maxWireVersion) {
+bool supportsWireVersionForOpCommandInMongod(const WireVersionInfo version) {
// FIND_COMMAND versions support OP_COMMAND (in mongod but not mongos).
- return (minWireVersion <= WireVersion::FIND_COMMAND) &&
- (maxWireVersion >= WireVersion::FIND_COMMAND);
+ return (version.minWireVersion <= WireVersion::FIND_COMMAND) &&
+ (version.maxWireVersion >= WireVersion::FIND_COMMAND);
}
-ProtocolSet computeProtocolSet(int minWireVersion, int maxWireVersion) {
+ProtocolSet computeProtocolSet(const WireVersionInfo version) {
ProtocolSet result = supports::kNone;
- if (minWireVersion <= maxWireVersion) {
- if (maxWireVersion >= WireVersion::FIND_COMMAND) {
+ if (version.minWireVersion <= version.maxWireVersion) {
+ if (version.maxWireVersion >= WireVersion::FIND_COMMAND) {
result |= supports::kOpCommandOnly;
}
- if (minWireVersion <= WireVersion::RELEASE_2_4_AND_BEFORE) {
+ if (version.minWireVersion <= WireVersion::RELEASE_2_4_AND_BEFORE) {
result |= supports::kOpQueryOnly;
}
}
return result;
}
+Status validateWireVersion(const WireVersionInfo client, const WireVersionInfo server) {
+ // Since this is defined in the code, it should always hold true since this is the versions that
+ // mongos/d wants to connect to.
+ invariant(client.minWireVersion <= client.maxWireVersion);
+
+ // Server may return bad data.
+ if (server.minWireVersion > server.maxWireVersion) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Server min and max wire version are incorrect ("
+ << server.minWireVersion
+ << ","
+ << server.maxWireVersion
+ << ")");
+ }
+
+ // Determine if the [min, max] tuples overlap.
+ // We assert the invariant that min < max above.
+ if (!(client.minWireVersion <= server.maxWireVersion &&
+ client.maxWireVersion >= server.minWireVersion)) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Server min and max wire version are incompatible ("
+ << server.minWireVersion
+ << ","
+ << server.maxWireVersion
+ << ") with client min wire version ("
+ << client.minWireVersion
+ << ","
+ << client.maxWireVersion
+ << ")");
+ }
+
+ return Status::OK();
+}
+
} // namespace rpc
} // namespace mongo
diff --git a/src/mongo/rpc/protocol.h b/src/mongo/rpc/protocol.h
index 45280849c29..6ac205ccc2f 100644
--- a/src/mongo/rpc/protocol.h
+++ b/src/mongo/rpc/protocol.h
@@ -33,6 +33,7 @@
#include <type_traits>
#include "mongo/base/status_with.h"
+#include "mongo/db/wire_version.h"
namespace mongo {
class BSONObj;
@@ -108,19 +109,34 @@ StatusWith<StringData> toString(ProtocolSet protocols);
StatusWith<ProtocolSet> parseProtocolSet(StringData repr);
/**
+ * Validates client and server wire version. The server is returned from isMaster, and the client is
+ * from WireSpec.instance().
+ */
+Status validateWireVersion(const WireVersionInfo client, const WireVersionInfo server);
+
+/**
+ * Struct to pass around information about protocol set and wire version.
+ */
+struct ProtocolSetAndWireVersionInfo {
+ ProtocolSet protocolSet;
+ WireVersionInfo version;
+};
+
+/**
* Determines the ProtocolSet of a remote server from an isMaster reply.
*/
-StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMasterReply);
+StatusWith<ProtocolSetAndWireVersionInfo> parseProtocolSetFromIsMasterReply(
+ const BSONObj& isMasterReply);
/**
* Returns true if wire version supports OP_COMMAND in mongod (not mongos).
*/
-bool supportsWireVersionForOpCommandInMongod(int minWireVersion, int maxWireVersion);
+bool supportsWireVersionForOpCommandInMongod(const WireVersionInfo version);
/**
* Computes supported protocols from wire versions.
*/
-ProtocolSet computeProtocolSet(int minWireVersion, int maxWireVersion);
+ProtocolSet computeProtocolSet(const WireVersionInfo version);
} // namespace rpc
} // namespace mongo
diff --git a/src/mongo/rpc/protocol_test.cpp b/src/mongo/rpc/protocol_test.cpp
index 7ee5abd09ac..a02d8de5159 100644
--- a/src/mongo/rpc/protocol_test.cpp
+++ b/src/mongo/rpc/protocol_test.cpp
@@ -76,7 +76,8 @@ TEST(Protocol, parseProtocolSetFromIsMasterReply) {
<< "minWireVersion"
<< static_cast<int>(WireVersion::RELEASE_2_4_AND_BEFORE));
- ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod32)), supports::kAll);
+ ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod32)).protocolSet,
+ supports::kAll);
}
{
// MongoDB 3.2 (mongos)
@@ -87,19 +88,84 @@ TEST(Protocol, parseProtocolSetFromIsMasterReply) {
<< "msg"
<< "isdbgrid");
- ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongos32)), supports::kOpQueryOnly);
+ ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongos32)).protocolSet,
+ supports::kOpQueryOnly);
}
{
// MongoDB 3.0 (mongod)
auto mongod30 = BSON(
"maxWireVersion" << static_cast<int>(WireVersion::RELEASE_2_7_7) << "minWireVersion"
<< static_cast<int>(WireVersion::RELEASE_2_4_AND_BEFORE));
- ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod30)), supports::kOpQueryOnly);
+ ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod30)).protocolSet,
+ supports::kOpQueryOnly);
}
{
auto mongod24 = BSONObj();
- ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod24)), supports::kOpQueryOnly);
+ ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod24)).protocolSet,
+ supports::kOpQueryOnly);
}
}
+#define VALIDATE_WIRE_VERSION(macro, clientMin, clientMax, serverMin, serverMax) \
+ do { \
+ auto msg = BSON("minWireVersion" << static_cast<int>(serverMin) << "maxWireVersion" \
+ << static_cast<int>(serverMax)); \
+ auto swReply = parseProtocolSetFromIsMasterReply(msg); \
+ ASSERT_OK(swReply.getStatus()); \
+ macro(validateWireVersion({clientMin, clientMax}, swReply.getValue().version)); \
+ } while (0);
+
+TEST(Protocol, validateWireVersion) {
+ // Base Test
+ VALIDATE_WIRE_VERSION(ASSERT_OK,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN);
+
+ // Allowed during upgrade
+ // MongoD 3.4 client -> MongoD 3.4 server
+ VALIDATE_WIRE_VERSION(ASSERT_OK,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN);
+
+ // MongoD 3.4 client -> MongoD 3.2 server
+ VALIDATE_WIRE_VERSION(ASSERT_OK,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::FIND_COMMAND);
+
+ // MongoD 3.2 client -> MongoD 3.4 server
+ VALIDATE_WIRE_VERSION(ASSERT_OK,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN);
+
+ // MongoS 3.4 client -> MongoD 3.4 server
+ VALIDATE_WIRE_VERSION(ASSERT_OK,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN);
+
+ // MongoS 3.2 client -> MongoD 3.4 server
+ VALIDATE_WIRE_VERSION(ASSERT_OK,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::FIND_COMMAND,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN);
+
+ // Disallowed
+ // MongoS 3.4 -> MongoDB 3.2 server
+ VALIDATE_WIRE_VERSION(ASSERT_NOT_OK,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN,
+ WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN,
+ WireVersion::RELEASE_2_4_AND_BEFORE,
+ WireVersion::FIND_COMMAND);
+}
+
} // namespace
diff --git a/src/mongo/s/client/sharding_network_connection_hook.cpp b/src/mongo/s/client/sharding_network_connection_hook.cpp
index a6b7a071250..e3544a4617b 100644
--- a/src/mongo/s/client/sharding_network_connection_hook.cpp
+++ b/src/mongo/s/client/sharding_network_connection_hook.cpp
@@ -77,20 +77,7 @@ Status ShardingNetworkConnectionHook::validateHostImpl(
if (!shard->isConfig()) {
return Status::OK();
}
- long long remoteMaxWireVersion;
- status = bsonExtractIntegerFieldWithDefault(isMasterReply.data,
- "maxWireVersion",
- RELEASE_2_4_AND_BEFORE,
- &remoteMaxWireVersion);
- if (!status.isOK()) {
- return status;
- }
- if (remoteMaxWireVersion < FIND_COMMAND) {
- // Prior to the introduction of the find command and the 3.1 release series, it was
- // not possible to distinguish a config server from a shard server from its ismaster
- // response. As such, we must assume that the system is properly configured.
- return Status::OK();
- }
+
return {ErrorCodes::InvalidOptions,
str::stream() << "Surprised to discover that " << remoteHost.toString()
<< " does not believe it is a config server"};
diff --git a/src/mongo/s/commands/cluster_is_master_cmd.cpp b/src/mongo/s/commands/cluster_is_master_cmd.cpp
index 399cf8fd4b3..fade2fdb73f 100644
--- a/src/mongo/s/commands/cluster_is_master_cmd.cpp
+++ b/src/mongo/s/commands/cluster_is_master_cmd.cpp
@@ -112,8 +112,8 @@ public:
// Mongos tries to keep exactly the same version range of the server for which
// it is compiled.
- result.append("maxWireVersion", WireSpec::instance().maxWireVersionIncoming);
- result.append("minWireVersion", WireSpec::instance().minWireVersionIncoming);
+ result.append("maxWireVersion", WireSpec::instance().incoming.maxWireVersion);
+ result.append("minWireVersion", WireSpec::instance().incoming.minWireVersion);
const auto parameter = mapFindWithDefault(ServerParameterSet::getGlobal()->getMap(),
"automationServiceDescriptor",
diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp
index 809164b6e04..613800a8547 100644
--- a/src/mongo/s/server.cpp
+++ b/src/mongo/s/server.cpp
@@ -213,11 +213,11 @@ static Status initializeSharding(OperationContext* txn) {
static void _initWireSpec() {
WireSpec& spec = WireSpec::instance();
// accept from any version
- spec.minWireVersionIncoming = RELEASE_2_4_AND_BEFORE;
- spec.maxWireVersionIncoming = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.incoming.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.incoming.maxWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
// connect to version supporting Write Concern only
- spec.minWireVersionOutgoing = COMMANDS_ACCEPT_WRITE_CONCERN;
- spec.maxWireVersionOutgoing = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.outgoing.minWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
+ spec.outgoing.maxWireVersion = COMMANDS_ACCEPT_WRITE_CONCERN;
}
static ExitCode runMongosServer() {