Skip to content

Commit 79f19b8

Browse files
authoredJul 18, 2017
[CSM] Add flavour limits controlled by server (#5930)
* [CSM] Add flavour limits controlled by server Server send flavour limits to client permitting to disable or limit some Lua calls * Add limits for reading nodedefs and itemdefs * flavour: Add lookup node limits * Merge get_node_or_nil into get_node. Sending fake node doesn't make sense in CSM, just return nil if node is not available for any reason * Add node range customization when noderange flavour is enabled (default 8 nodes) * Limit nodes range & disable chat message sending by default * Bump protocol version
1 parent 7e3cdf7 commit 79f19b8

18 files changed

+136
-29
lines changed
 

‎builtin/settingtypes.txt

+13
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,19 @@ block_send_optimize_distance (block send optimize distance) int 4 2
960960
# so that the utility of noclip mode is reduced.
961961
server_side_occlusion_culling (Server side occlusion culling) bool true
962962

963+
# Restricts the access of certain client-side functions on servers
964+
# Combine these byteflags below to restrict more client-side features:
965+
# LOOKUP_NODES_LIMIT: 1 (limits get_node call client-side to csm_flavour_noderange_limit)
966+
# CHAT_MESSAGES: 2 (disable send_chat_message call client-side)
967+
# READ_ITEMDEFS: 4 (disable get_item_def call client-side)
968+
# READ_NODEDEFS: 8 (disable get_node_def call client-side)
969+
# type: int
970+
csm_flavour_limits (Client side modding flavour limits) int 3
971+
972+
# If the CSM flavour for node range is enabled, get_node is limited to
973+
# this many nodes from the player.
974+
csm_flavour_noderange_limit (Client side noderange flavour limit) int 8
975+
963976
[*Mapgen]
964977

965978
# Name of map generator to be used when creating a new world.

‎doc/client_lua_api.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -701,12 +701,10 @@ Call these functions only at load time!
701701
* Returns the time of day: `0` for midnight, `0.5` for midday
702702

703703
### Map
704-
* `minetest.get_node(pos)`
705-
* Returns the node at the given position as table in the format
706-
`{name="node_name", param1=0, param2=0}`, returns `{name="ignore", param1=0, param2=0}`
707-
for unloaded areas.
708704
* `minetest.get_node_or_nil(pos)`
709-
* Same as `get_node` but returns `nil` for unloaded areas.
705+
* Returns the node at the given position as table in the format
706+
`{name="node_name", param1=0, param2=0}`, returns `nil`
707+
for unloaded areas or flavour limited areas.
710708
* `minetest.find_node_near(pos, radius, nodenames, [search_center])`: returns pos or `nil`
711709
* `radius`: using a maximum metric
712710
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`

‎minetest.conf.example

+13
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,19 @@
11721172
# type: bool
11731173
# server_side_occlusion_culling = true
11741174

1175+
# Restricts the access of certain client-side functions on servers
1176+
# Combine these byteflags below to restrict more client-side features:
1177+
# LOOKUP_NODES_LIMIT: 1 (limits get_node call client-side to csm_flavour_noderange_limit)
1178+
# CHAT_MESSAGES: 2 (disable send_chat_message call client-side)
1179+
# READ_ITEMDEFS: 4 (disable get_item_def call client-side)
1180+
# READ_NODEDEFS: 8 (disable get_node_def call client-side)
1181+
# type: int
1182+
# csm_flavour_limits = 3
1183+
1184+
# If the CSM flavour for node range is enabled, get_node is limited to
1185+
# this many nodes from the player.
1186+
# csm_flavour_noderange_limit 8
1187+
11751188
## Mapgen
11761189

11771190
# Name of map generator to be used when creating a new world.

‎src/client.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -1361,8 +1361,22 @@ void Client::removeNode(v3s16 p)
13611361
}
13621362
}
13631363

1364+
/**
1365+
* Helper function for Client Side Modding
1366+
* Flavour is applied there, this should not be used for core engine
1367+
* @param p
1368+
* @param is_valid_position
1369+
* @return
1370+
*/
13641371
MapNode Client::getNode(v3s16 p, bool *is_valid_position)
13651372
{
1373+
if (checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_LOOKUP_NODES)) {
1374+
v3s16 ppos = floatToInt(m_env.getLocalPlayer()->getPosition(), BS);
1375+
if ((u32) ppos.getDistanceFrom(p) > m_csm_noderange_limit) {
1376+
*is_valid_position = false;
1377+
return MapNode();
1378+
}
1379+
}
13661380
return m_env.getMap().getNodeNoEx(p, is_valid_position);
13671381
}
13681382

‎src/client.h

+23
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
364364
void handleCommand_EyeOffset(NetworkPacket* pkt);
365365
void handleCommand_UpdatePlayerList(NetworkPacket* pkt);
366366
void handleCommand_SrpBytesSandB(NetworkPacket* pkt);
367+
void handleCommand_CSMFlavourLimits(NetworkPacket *pkt);
367368

368369
void ProcessData(NetworkPacket *pkt);
369370

@@ -396,6 +397,14 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
396397

397398
// Causes urgent mesh updates (unlike Map::add/removeNodeWithEvent)
398399
void removeNode(v3s16 p);
400+
401+
/**
402+
* Helper function for Client Side Modding
403+
* Flavour is applied there, this should not be used for core engine
404+
* @param p
405+
* @param is_valid_position
406+
* @return
407+
*/
399408
MapNode getNode(v3s16 p, bool *is_valid_position);
400409
void addNode(v3s16 p, MapNode n, bool remove_metadata = true);
401410

@@ -552,6 +561,16 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
552561
return m_address_name;
553562
}
554563

564+
inline bool checkCSMFlavourLimit(CSMFlavourLimit flag) const
565+
{
566+
return m_csm_flavour_limits & flag;
567+
}
568+
569+
u32 getCSMNodeRangeLimit() const
570+
{
571+
return m_csm_noderange_limit;
572+
}
573+
555574
private:
556575

557576
// Virtual methods from con::PeerHandler
@@ -705,6 +724,10 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
705724
GameUIFlags *m_game_ui_flags;
706725

707726
bool m_shutdown = false;
727+
728+
// CSM flavour limits byteflag
729+
u64 m_csm_flavour_limits = CSMFlavourLimit::CSM_FL_NONE;
730+
u32 m_csm_noderange_limit = 8;
708731
};
709732

710733
#endif // !CLIENT_HEADER

‎src/defaultsettings.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ void set_default_settings(Settings *settings)
294294
settings->setDefault("max_block_send_distance", "9");
295295
settings->setDefault("block_send_optimize_distance", "4");
296296
settings->setDefault("server_side_occlusion_culling", "true");
297+
settings->setDefault("csm_flavour_limits", "3");
298+
settings->setDefault("csm_flavour_noderange_limit", "8");
297299
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
298300
settings->setDefault("time_speed", "72");
299301
settings->setDefault("server_unload_unused_data_timeout", "29");

‎src/network/clientopcodes.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
6666
{ "TOCLIENT_INVENTORY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Inventory }, // 0x27
6767
null_command_handler,
6868
{ "TOCLIENT_TIME_OF_DAY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_TimeOfDay }, // 0x29
69-
null_command_handler,
69+
{ "TOCLIENT_CSM_FLAVOUR_LIMITS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CSMFlavourLimits }, // 0x2A
7070
null_command_handler,
7171
null_command_handler,
7272
null_command_handler,

‎src/network/clientpackethandler.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1376,3 +1376,8 @@ void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
13761376
resp_pkt << std::string(bytes_M, len_M);
13771377
Send(&resp_pkt);
13781378
}
1379+
1380+
void Client::handleCommand_CSMFlavourLimits(NetworkPacket *pkt)
1381+
{
1382+
*pkt >> m_csm_flavour_limits >> m_csm_noderange_limit;
1383+
}

‎src/network/networkprotocol.h

+16-3
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
1717
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1818
*/
1919

20-
#ifndef NETWORKPROTOCOL_HEADER
21-
#define NETWORKPROTOCOL_HEADER
20+
#pragma once
21+
2222
#include "util/string.h"
2323

2424
/*
@@ -168,6 +168,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
168168
* sender
169169
* type (RAW, NORMAL, ANNOUNCE, SYSTEM)
170170
* content
171+
Add TOCLIENT_CSM_FLAVOUR_LIMITS to define which CSM flavour should be limited
171172
*/
172173

173174
#define LATEST_PROTOCOL_VERSION 35
@@ -313,6 +314,11 @@ enum ToClientCommand
313314
f1000 time_speed
314315
*/
315316

317+
TOCLIENT_CSM_FLAVOUR_LIMITS = 0x2A,
318+
/*
319+
u32 CSMFlavourLimits byteflag
320+
*/
321+
316322
// (oops, there is some gap here)
317323

318324
TOCLIENT_CHAT_MESSAGE = 0x2F,
@@ -1003,5 +1009,12 @@ enum PlayerListModifer: u8
10031009
PLAYER_LIST_REMOVE,
10041010
};
10051011

1012+
enum CSMFlavourLimit : u64 {
1013+
CSM_FL_NONE = 0x00000000,
1014+
CSM_FL_LOOKUP_NODES = 0x00000001, // Limit node lookups
1015+
CSM_FL_CHAT_MESSAGES = 0x00000002, // Disable chat message sending from CSM
1016+
CSM_FL_READ_ITEMDEFS = 0x00000004, // Disable itemdef lookups
1017+
CSM_FL_READ_NODEDEFS = 0x00000008, // Disable nodedef lookups
1018+
CSM_FL_ALL = 0xFFFFFFFF,
1019+
};
10061020

1007-
#endif

‎src/network/serveropcodes.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
155155
{ "TOCLIENT_INVENTORY", 0, true }, // 0x27
156156
null_command_factory,
157157
{ "TOCLIENT_TIME_OF_DAY", 0, true }, // 0x29
158-
null_command_factory,
158+
{ "TOCLIENT_CSM_FLAVOUR_LIMITS", 0, true }, // 0x2A
159159
null_command_factory,
160160
null_command_factory,
161161
null_command_factory,

‎src/network/serverpackethandler.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,8 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
643643
float time_speed = g_settings->getFloat("time_speed");
644644
SendTimeOfDay(pkt->getPeerId(), time, time_speed);
645645

646+
SendCSMFlavourLimits(pkt->getPeerId());
647+
646648
// Warnings about protocol version can be issued here
647649
if (getClient(pkt->getPeerId())->net_proto_version < LATEST_PROTOCOL_VERSION) {
648650
SendChatMessage(pkt->getPeerId(), ChatMessage(CHATMESSAGE_TYPE_SYSTEM,

‎src/script/lua_api/l_client.cpp

+12-15
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ int ModApiClient::l_send_chat_message(lua_State *L)
9191
{
9292
if (!lua_isstring(L, 1))
9393
return 0;
94+
95+
// If server disabled this API, discard
96+
if (getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_CHAT_MESSAGES))
97+
return 0;
98+
9499
std::string message = luaL_checkstring(L, 1);
95100
getClient(L)->sendChatMessage(utf8_to_wide(message));
96101
return 0;
@@ -166,24 +171,11 @@ int ModApiClient::l_gettext(lua_State *L)
166171

167172
// get_node(pos)
168173
// pos = {x=num, y=num, z=num}
169-
int ModApiClient::l_get_node(lua_State *L)
170-
{
171-
// pos
172-
v3s16 pos = read_v3s16(L, 1);
173-
// Do it
174-
bool pos_ok;
175-
MapNode n = getClient(L)->getNode(pos, &pos_ok);
176-
// Return node
177-
pushnode(L, n, getClient(L)->ndef());
178-
return 1;
179-
}
180-
181-
// get_node_or_nil(pos)
182-
// pos = {x=num, y=num, z=num}
183174
int ModApiClient::l_get_node_or_nil(lua_State *L)
184175
{
185176
// pos
186177
v3s16 pos = read_v3s16(L, 1);
178+
187179
// Do it
188180
bool pos_ok;
189181
MapNode n = getClient(L)->getNode(pos, &pos_ok);
@@ -290,6 +282,9 @@ int ModApiClient::l_get_item_def(lua_State *L)
290282
IItemDefManager *idef = gdef->idef();
291283
assert(idef);
292284

285+
if (getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_READ_ITEMDEFS))
286+
return 0;
287+
293288
if (!lua_isstring(L, 1))
294289
return 0;
295290

@@ -315,6 +310,9 @@ int ModApiClient::l_get_node_def(lua_State *L)
315310
if (!lua_isstring(L, 1))
316311
return 0;
317312

313+
if (getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_READ_NODEDEFS))
314+
return 0;
315+
318316
const std::string &name = lua_tostring(L, 1);
319317
const ContentFeatures &cf = ndef->get(ndef->getId(name));
320318
if (cf.name != name) // Unknown node. | name = <whatever>, cf.name = ignore
@@ -363,7 +361,6 @@ void ModApiClient::Initialize(lua_State *L, int top)
363361
API_FCT(show_formspec);
364362
API_FCT(send_respawn);
365363
API_FCT(gettext);
366-
API_FCT(get_node);
367364
API_FCT(get_node_or_nil);
368365
API_FCT(get_wielded_item);
369366
API_FCT(disconnect);

‎src/script/lua_api/l_client.h

-3
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ class ModApiClient : public ModApiBase
6565
static int l_set_last_run_mod(lua_State *L);
6666

6767
// get_node(pos)
68-
static int l_get_node(lua_State *L);
69-
70-
// get_node_or_nil(pos)
7168
static int l_get_node_or_nil(lua_State *L);
7269

7370
// get_wielded_item()

‎src/script/lua_api/l_env.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2525
#include "lua_api/l_vmanip.h"
2626
#include "common/c_converter.h"
2727
#include "common/c_content.h"
28+
#include <algorithm>
2829
#include "scripting_server.h"
2930
#include "environment.h"
3031
#include "server.h"
@@ -726,6 +727,15 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
726727
}
727728

728729
int start_radius = (lua_toboolean(L, 4)) ? 0 : 1;
730+
731+
#ifndef SERVER
732+
// Client API limitations
733+
if (getClient(L) &&
734+
getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_LOOKUP_NODES)) {
735+
radius = std::max<int>(radius, getClient(L)->getCSMNodeRangeLimit());
736+
}
737+
#endif
738+
729739
for (int d = start_radius; d <= radius; d++) {
730740
std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
731741
for (std::vector<v3s16>::iterator i = list.begin();

‎src/server.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ Server::Server(
298298

299299
m_liquid_transform_every = g_settings->getFloat("liquid_update");
300300
m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
301+
m_csm_flavour_limits = g_settings->getU64("csm_flavour_limits");
302+
m_csm_noderange_limit = g_settings->getU32("csm_flavour_noderange_limit");
301303
}
302304

303305
Server::~Server()
@@ -2017,7 +2019,14 @@ void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, boo
20172019
m_clients.send(pkt.getPeerId(),
20182020
reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
20192021
&pkt, reliable);
2022+
}
20202023

2024+
void Server::SendCSMFlavourLimits(u16 peer_id)
2025+
{
2026+
NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
2027+
sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
2028+
pkt << m_csm_flavour_limits << m_csm_noderange_limit;
2029+
Send(&pkt);
20212030
}
20222031

20232032
s32 Server::playSound(const SimpleSoundSpec &spec,

‎src/server.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
466466

467467
u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas);
468468
void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true);
469+
void SendCSMFlavourLimits(u16 peer_id);
470+
469471
/*
470472
Something random
471473
*/
@@ -664,6 +666,10 @@ class Server : public con::PeerHandler, public MapEventReceiver,
664666

665667
std::unordered_map<std::string, ModMetadata *> m_mod_storages;
666668
float m_mod_storage_save_timer = 10.0f;
669+
670+
// CSM flavour limits byteflag
671+
u64 m_csm_flavour_limits = CSMFlavourLimit::CSM_FL_NONE;
672+
u32 m_csm_noderange_limit = 8;
667673
};
668674

669675
/*
@@ -674,4 +680,3 @@ class Server : public con::PeerHandler, public MapEventReceiver,
674680
void dedicated_server_loop(Server &server, bool &kill);
675681

676682
#endif
677-

‎src/settings.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,11 @@ s16 Settings::getS16(const std::string &name) const
398398
}
399399

400400

401+
u32 Settings::getU32(const std::string &name) const
402+
{
403+
return (u32) stoi(get(name));
404+
}
405+
401406
s32 Settings::getS32(const std::string &name) const
402407
{
403408
return stoi(get(name));

‎src/settings.h

+1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class Settings {
134134
bool getBool(const std::string &name) const;
135135
u16 getU16(const std::string &name) const;
136136
s16 getS16(const std::string &name) const;
137+
u32 getU32(const std::string &name) const;
137138
s32 getS32(const std::string &name) const;
138139
u64 getU64(const std::string &name) const;
139140
float getFloat(const std::string &name) const;

0 commit comments

Comments
 (0)
Please sign in to comment.