mirror of
https://github.com/minetest/minetest.git
synced 2024-11-29 19:13:44 +01:00
Network: Fix serialization version checks (#15477)
This fixes some incorrect assumptions that the read and write version ranges are identical - whereas they're in fact not.
This commit is contained in:
parent
6c324cb871
commit
c175046d30
@ -1128,7 +1128,7 @@ void Client::sendInit(const std::string &playerName)
|
|||||||
{
|
{
|
||||||
NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()));
|
NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()));
|
||||||
|
|
||||||
pkt << (u8) SER_FMT_VER_HIGHEST_READ << (u16) 0;
|
pkt << SER_FMT_VER_HIGHEST_READ << (u16) 0 /* unused */;
|
||||||
pkt << CLIENT_PROTOCOL_VERSION_MIN << LATEST_PROTOCOL_VERSION;
|
pkt << CLIENT_PROTOCOL_VERSION_MIN << LATEST_PROTOCOL_VERSION;
|
||||||
pkt << playerName;
|
pkt << playerName;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
|
#include "serialization.h" // SER_FMT_VER_HIGHEST_*
|
||||||
#include "network/socket.h"
|
#include "network/socket.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
#if USE_CURSES
|
#if USE_CURSES
|
||||||
|
@ -307,11 +307,9 @@ static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
|
|||||||
|
|
||||||
void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int compression_level)
|
void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int compression_level)
|
||||||
{
|
{
|
||||||
if(!ser_ver_supported(version))
|
if (!ser_ver_supported_write(version))
|
||||||
throw VersionMismatchException("ERROR: MapBlock format not supported");
|
throw VersionMismatchException("ERROR: MapBlock format not supported");
|
||||||
|
|
||||||
FATAL_ERROR_IF(version < SER_FMT_VER_LOWEST_WRITE, "Serialization version error");
|
|
||||||
|
|
||||||
std::ostringstream os_raw(std::ios_base::binary);
|
std::ostringstream os_raw(std::ios_base::binary);
|
||||||
std::ostream &os = version >= 29 ? os_raw : os_compressed;
|
std::ostream &os = version >= 29 ? os_raw : os_compressed;
|
||||||
|
|
||||||
@ -423,7 +421,7 @@ void MapBlock::serializeNetworkSpecific(std::ostream &os)
|
|||||||
|
|
||||||
void MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk)
|
void MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk)
|
||||||
{
|
{
|
||||||
if(!ser_ver_supported(version))
|
if (!ser_ver_supported_read(version))
|
||||||
throw VersionMismatchException("ERROR: MapBlock format not supported");
|
throw VersionMismatchException("ERROR: MapBlock format not supported");
|
||||||
|
|
||||||
TRACESTREAM(<<"MapBlock::deSerialize "<<getPos()<<std::endl);
|
TRACESTREAM(<<"MapBlock::deSerialize "<<getPos()<<std::endl);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "content_mapnode.h" // For mapnode_translate_*_internal
|
#include "content_mapnode.h" // For mapnode_translate_*_internal
|
||||||
#include "serialization.h" // For ser_ver_supported
|
#include "serialization.h" // For ser_ver_supported_*
|
||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util/directiontables.h"
|
#include "util/directiontables.h"
|
||||||
@ -620,7 +620,7 @@ s8 MapNode::addLevel(const NodeDefManager *nodemgr, s16 add)
|
|||||||
|
|
||||||
u32 MapNode::serializedLength(u8 version)
|
u32 MapNode::serializedLength(u8 version)
|
||||||
{
|
{
|
||||||
if(!ser_ver_supported(version))
|
if (!ser_ver_supported_read(version))
|
||||||
throw VersionMismatchException("ERROR: MapNode format not supported");
|
throw VersionMismatchException("ERROR: MapNode format not supported");
|
||||||
|
|
||||||
if (version == 0)
|
if (version == 0)
|
||||||
@ -636,7 +636,7 @@ u32 MapNode::serializedLength(u8 version)
|
|||||||
}
|
}
|
||||||
void MapNode::serialize(u8 *dest, u8 version) const
|
void MapNode::serialize(u8 *dest, u8 version) const
|
||||||
{
|
{
|
||||||
if(!ser_ver_supported(version))
|
if (!ser_ver_supported_write(version))
|
||||||
throw VersionMismatchException("ERROR: MapNode format not supported");
|
throw VersionMismatchException("ERROR: MapNode format not supported");
|
||||||
|
|
||||||
// Can't do this anymore; we have 16-bit dynamically allocated node IDs
|
// Can't do this anymore; we have 16-bit dynamically allocated node IDs
|
||||||
@ -651,7 +651,7 @@ void MapNode::serialize(u8 *dest, u8 version) const
|
|||||||
}
|
}
|
||||||
void MapNode::deSerialize(u8 *source, u8 version)
|
void MapNode::deSerialize(u8 *source, u8 version)
|
||||||
{
|
{
|
||||||
if(!ser_ver_supported(version))
|
if (!ser_ver_supported_read(version))
|
||||||
throw VersionMismatchException("ERROR: MapNode format not supported");
|
throw VersionMismatchException("ERROR: MapNode format not supported");
|
||||||
|
|
||||||
if(version <= 21)
|
if(version <= 21)
|
||||||
@ -679,18 +679,12 @@ Buffer<u8> MapNode::serializeBulk(int version,
|
|||||||
const MapNode *nodes, u32 nodecount,
|
const MapNode *nodes, u32 nodecount,
|
||||||
u8 content_width, u8 params_width)
|
u8 content_width, u8 params_width)
|
||||||
{
|
{
|
||||||
if (!ser_ver_supported(version))
|
if (!ser_ver_supported_write(version))
|
||||||
throw VersionMismatchException("ERROR: MapNode format not supported");
|
throw VersionMismatchException("ERROR: MapNode format not supported");
|
||||||
|
|
||||||
sanity_check(content_width == 2);
|
sanity_check(content_width == 2);
|
||||||
sanity_check(params_width == 2);
|
sanity_check(params_width == 2);
|
||||||
|
|
||||||
// Can't do this anymore; we have 16-bit dynamically allocated node IDs
|
|
||||||
// in memory; conversion just won't work in this direction.
|
|
||||||
if (version < 24)
|
|
||||||
throw SerializationError("MapNode::serializeBulk: serialization to "
|
|
||||||
"version < 24 not possible");
|
|
||||||
|
|
||||||
Buffer<u8> databuf(nodecount * (content_width + params_width));
|
Buffer<u8> databuf(nodecount * (content_width + params_width));
|
||||||
|
|
||||||
// Writing to the buffer linearly is faster
|
// Writing to the buffer linearly is faster
|
||||||
@ -712,13 +706,13 @@ void MapNode::deSerializeBulk(std::istream &is, int version,
|
|||||||
MapNode *nodes, u32 nodecount,
|
MapNode *nodes, u32 nodecount,
|
||||||
u8 content_width, u8 params_width)
|
u8 content_width, u8 params_width)
|
||||||
{
|
{
|
||||||
if(!ser_ver_supported(version))
|
if (!ser_ver_supported_read(version))
|
||||||
throw VersionMismatchException("ERROR: MapNode format not supported");
|
throw VersionMismatchException("ERROR: MapNode format not supported");
|
||||||
|
|
||||||
if (version < 22
|
if (version < 22
|
||||||
|| (content_width != 1 && content_width != 2)
|
|| (content_width != 1 && content_width != 2)
|
||||||
|| params_width != 2)
|
|| params_width != 2)
|
||||||
FATAL_ERROR("Deserialize bulk node data error");
|
throw SerializationError("Deserialize bulk node data error");
|
||||||
|
|
||||||
// read data
|
// read data
|
||||||
const u32 len = nodecount * (content_width + params_width);
|
const u32 len = nodecount * (content_width + params_width);
|
||||||
|
@ -63,7 +63,7 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
|
|||||||
if (pkt->getSize() < 1)
|
if (pkt->getSize() < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u8 serialization_ver;
|
u8 serialization_ver; // negotiated value
|
||||||
u16 proto_ver;
|
u16 proto_ver;
|
||||||
u16 unused_compression_mode;
|
u16 unused_compression_mode;
|
||||||
u32 auth_mechs;
|
u32 auth_mechs;
|
||||||
@ -80,9 +80,9 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
|
|||||||
<< ", proto_ver=" << proto_ver
|
<< ", proto_ver=" << proto_ver
|
||||||
<< ". Doing auth with mech " << chosen_auth_mechanism << std::endl;
|
<< ". Doing auth with mech " << chosen_auth_mechanism << std::endl;
|
||||||
|
|
||||||
if (!ser_ver_supported(serialization_ver)) {
|
if (!ser_ver_supported_read(serialization_ver)) {
|
||||||
infostream << "Client: TOCLIENT_HELLO: Server sent "
|
infostream << "Client: TOCLIENT_HELLO: Server sent "
|
||||||
<< "unsupported ser_fmt_ver"<< std::endl;
|
<< "unsupported ser_fmt_ver=" << (int)serialization_ver << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "remoteplayer.h"
|
#include "remoteplayer.h"
|
||||||
#include "rollback_interface.h"
|
#include "rollback_interface.h"
|
||||||
#include "scripting_server.h"
|
#include "scripting_server.h"
|
||||||
|
#include "serialization.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "tool.h"
|
#include "tool.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
@ -83,34 +84,27 @@ void Server::handleCommand_Init(NetworkPacket* pkt)
|
|||||||
if (denyIfBanned(peer_id))
|
if (denyIfBanned(peer_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// First byte after command is maximum supported
|
u8 max_ser_ver; // SER_FMT_VER_HIGHEST_READ (of client)
|
||||||
// serialization version
|
|
||||||
u8 client_max;
|
|
||||||
u16 unused;
|
u16 unused;
|
||||||
u16 min_net_proto_version = 0;
|
u16 min_net_proto_version;
|
||||||
u16 max_net_proto_version;
|
u16 max_net_proto_version;
|
||||||
std::string playerName;
|
std::string playerName;
|
||||||
|
|
||||||
*pkt >> client_max >> unused >> min_net_proto_version
|
*pkt >> max_ser_ver >> unused
|
||||||
>> max_net_proto_version >> playerName;
|
>> min_net_proto_version >> max_net_proto_version
|
||||||
|
>> playerName;
|
||||||
|
|
||||||
u8 our_max = SER_FMT_VER_HIGHEST_READ;
|
|
||||||
// Use the highest version supported by both
|
// Use the highest version supported by both
|
||||||
u8 depl_serial_v = std::min(client_max, our_max);
|
const u8 serialization_ver = std::min(max_ser_ver, SER_FMT_VER_HIGHEST_WRITE);
|
||||||
// If it's lower than the lowest supported, give up.
|
|
||||||
#if SER_FMT_VER_LOWEST_READ > 0
|
|
||||||
if (depl_serial_v < SER_FMT_VER_LOWEST_READ)
|
|
||||||
depl_serial_v = SER_FMT_VER_INVALID;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (depl_serial_v == SER_FMT_VER_INVALID) {
|
if (!ser_ver_supported_write(serialization_ver)) {
|
||||||
actionstream << "Server: A mismatched client tried to connect from " <<
|
actionstream << "Server: A mismatched client tried to connect from " <<
|
||||||
addr_s << " ser_fmt_max=" << (int)client_max << std::endl;
|
addr_s << " ser_fmt_max=" << (int)serialization_ver << std::endl;
|
||||||
DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_VERSION);
|
DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_VERSION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
client->setPendingSerializationVersion(depl_serial_v);
|
client->setPendingSerializationVersion(serialization_ver);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read and check network protocol version
|
Read and check network protocol version
|
||||||
@ -263,8 +257,9 @@ void Server::handleCommand_Init(NetworkPacket* pkt)
|
|||||||
|
|
||||||
NetworkPacket resp_pkt(TOCLIENT_HELLO, 0, peer_id);
|
NetworkPacket resp_pkt(TOCLIENT_HELLO, 0, peer_id);
|
||||||
|
|
||||||
resp_pkt << depl_serial_v << u16(0) << net_proto_version
|
resp_pkt << serialization_ver << u16(0) /* unused */
|
||||||
<< auth_mechs << std::string_view();
|
<< net_proto_version
|
||||||
|
<< auth_mechs << std::string_view() /* unused */;
|
||||||
|
|
||||||
Send(&resp_pkt);
|
Send(&resp_pkt);
|
||||||
|
|
||||||
|
@ -50,23 +50,30 @@
|
|||||||
28: Added "private" flag to NodeMetadata
|
28: Added "private" flag to NodeMetadata
|
||||||
29: Switched compression to zstd, a bit of reorganization
|
29: Switched compression to zstd, a bit of reorganization
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// This represents an uninitialized or invalid format
|
// This represents an uninitialized or invalid format
|
||||||
#define SER_FMT_VER_INVALID 255
|
constexpr u8 SER_FMT_VER_INVALID = 255;
|
||||||
// Highest supported serialization version
|
// Highest supported serialization version
|
||||||
#define SER_FMT_VER_HIGHEST_READ 29
|
constexpr u8 SER_FMT_VER_HIGHEST_READ = 29;
|
||||||
// Saved on disk version
|
// Saved on disk version
|
||||||
#define SER_FMT_VER_HIGHEST_WRITE 29
|
constexpr u8 SER_FMT_VER_HIGHEST_WRITE = 29;
|
||||||
// Lowest supported serialization version
|
// Lowest supported serialization version
|
||||||
#define SER_FMT_VER_LOWEST_READ 0
|
constexpr u8 SER_FMT_VER_LOWEST_READ = 0;
|
||||||
// Lowest serialization version for writing
|
// Lowest serialization version for writing
|
||||||
// Can't do < 24 anymore; we have 16-bit dynamically allocated node IDs
|
// Can't do < 24 anymore; we have 16-bit dynamically allocated node IDs
|
||||||
// in memory; conversion just won't work in this direction.
|
// in memory; conversion just won't work in this direction.
|
||||||
#define SER_FMT_VER_LOWEST_WRITE 24
|
constexpr u8 SER_FMT_VER_LOWEST_WRITE = 24;
|
||||||
|
|
||||||
inline bool ser_ver_supported(s32 v) {
|
inline bool ser_ver_supported_read(s32 v)
|
||||||
|
{
|
||||||
return v >= SER_FMT_VER_LOWEST_READ && v <= SER_FMT_VER_HIGHEST_READ;
|
return v >= SER_FMT_VER_LOWEST_READ && v <= SER_FMT_VER_HIGHEST_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool ser_ver_supported_write(s32 v)
|
||||||
|
{
|
||||||
|
return v >= SER_FMT_VER_LOWEST_WRITE && v <= SER_FMT_VER_HIGHEST_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compression functions
|
Compression functions
|
||||||
*/
|
*/
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
#include "server/serveractiveobject.h"
|
#include "server/serveractiveobject.h"
|
||||||
|
#include "serialization.h" // SER_FMT_VER_INVALID
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "profiler.h"
|
#include "profiler.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "hud.h"
|
#include "hud.h"
|
||||||
#include "gamedef.h"
|
#include "gamedef.h"
|
||||||
#include "serialization.h" // For SER_FMT_VER_INVALID
|
|
||||||
#include "content/mods.h"
|
#include "content/mods.h"
|
||||||
#include "inventorymanager.h"
|
#include "inventorymanager.h"
|
||||||
#include "content/subgames.h"
|
#include "content/subgames.h"
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "network/connection.h"
|
#include "network/connection.h"
|
||||||
#include "network/serveropcodes.h"
|
#include "network/serveropcodes.h"
|
||||||
#include "remoteplayer.h"
|
#include "remoteplayer.h"
|
||||||
|
#include "serialization.h" // SER_FMT_VER_INVALID
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
#include "serverenvironment.h"
|
#include "serverenvironment.h"
|
||||||
@ -51,6 +52,8 @@ std::string ClientInterface::state2Name(ClientState state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
RemoteClient::RemoteClient() :
|
RemoteClient::RemoteClient() :
|
||||||
|
serialization_version(SER_FMT_VER_INVALID),
|
||||||
|
m_pending_serialization_version(SER_FMT_VER_INVALID),
|
||||||
m_max_simul_sends(g_settings->getU16("max_simultaneous_block_sends_per_client")),
|
m_max_simul_sends(g_settings->getU16("max_simultaneous_block_sends_per_client")),
|
||||||
m_min_time_from_building(
|
m_min_time_from_building(
|
||||||
g_settings->getFloat("full_block_send_enable_min_time_from_building")),
|
g_settings->getFloat("full_block_send_enable_min_time_from_building")),
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include "irr_v3d.h" // for irrlicht datatypes
|
#include "irr_v3d.h" // for irrlicht datatypes
|
||||||
|
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "serialization.h" // for SER_FMT_VER_INVALID
|
|
||||||
#include "network/networkpacket.h"
|
#include "network/networkpacket.h"
|
||||||
#include "network/networkprotocol.h"
|
#include "network/networkprotocol.h"
|
||||||
#include "network/address.h"
|
#include "network/address.h"
|
||||||
@ -219,7 +218,7 @@ public:
|
|||||||
// Also, the client must be moved to some other container.
|
// Also, the client must be moved to some other container.
|
||||||
session_t peer_id = PEER_ID_INEXISTENT;
|
session_t peer_id = PEER_ID_INEXISTENT;
|
||||||
// The serialization version to use with the client
|
// The serialization version to use with the client
|
||||||
u8 serialization_version = SER_FMT_VER_INVALID;
|
u8 serialization_version;
|
||||||
//
|
//
|
||||||
u16 net_proto_version = 0;
|
u16 net_proto_version = 0;
|
||||||
|
|
||||||
@ -333,7 +332,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Version is stored in here after INIT before INIT2
|
// Version is stored in here after INIT before INIT2
|
||||||
u8 m_pending_serialization_version = SER_FMT_VER_INVALID;
|
u8 m_pending_serialization_version;
|
||||||
|
|
||||||
/* current state of client */
|
/* current state of client */
|
||||||
ClientState m_state = CS_Created;
|
ClientState m_state = CS_Created;
|
||||||
|
Loading…
Reference in New Issue
Block a user