1 /*
2 * The ManaPlus Client
3 * Copyright (C) 2011-2019 The ManaPlus Developers
4 * Copyright (C) 2019-2021 Andrei Karas
5 *
6 * This file is part of The ManaPlus Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "net/packetlimiter.h"
23
24 #include "configuration.h"
25 #include "settings.h"
26
27 #include "utils/cast.h"
28 #include "utils/checkutils.h"
29 #include "utils/timer.h"
30
31 #include <fstream>
32 #include <sys/stat.h>
33
34 #include "debug.h"
35
36 struct PacketLimit final
37 {
38 A_DEFAULT_COPY(PacketLimit)
39
40 int lastTime;
41 int timeLimit;
42 int cnt;
43 int cntLimit;
44 };
45
46 PacketLimit mPacketLimits[CAST_SIZE(PacketType::PACKET_SIZE) + 1];
47
initPacketLimiter()48 void PacketLimiter::initPacketLimiter()
49 {
50 // here i setting packet limits. but current server is broken,
51 // and this limits may not help.
52
53 mPacketLimits[CAST_SIZE(
54 PacketType::PACKET_CHAT)].timeLimit = 10 + 5;
55 mPacketLimits[CAST_SIZE(
56 PacketType::PACKET_CHAT)].lastTime = 0;
57 mPacketLimits[CAST_SIZE(
58 PacketType::PACKET_CHAT)].cntLimit = 1;
59 mPacketLimits[CAST_SIZE(
60 PacketType::PACKET_CHAT)].cnt = 0;
61
62 // 10
63 mPacketLimits[CAST_SIZE(
64 PacketType::PACKET_PICKUP)].timeLimit = 10 + 5;
65 mPacketLimits[CAST_SIZE(
66 PacketType::PACKET_PICKUP)].lastTime = 0;
67 mPacketLimits[CAST_SIZE(
68 PacketType::PACKET_PICKUP)].cntLimit = 1;
69 mPacketLimits[CAST_SIZE(
70 PacketType::PACKET_PICKUP)].cnt = 0;
71
72 // 10 5
73 mPacketLimits[CAST_SIZE(
74 PacketType::PACKET_DROP)].timeLimit = 5;
75 mPacketLimits[CAST_SIZE(
76 PacketType::PACKET_DROP)].lastTime = 0;
77 mPacketLimits[CAST_SIZE(
78 PacketType::PACKET_DROP)].cntLimit = 1;
79 mPacketLimits[CAST_SIZE(
80 PacketType::PACKET_DROP)].cnt = 0;
81
82 // 100
83 mPacketLimits[CAST_SIZE(
84 PacketType::PACKET_NPC_NEXT)].timeLimit = 0;
85 mPacketLimits[CAST_SIZE(
86 PacketType::PACKET_NPC_NEXT)].lastTime = 0;
87 mPacketLimits[CAST_SIZE(
88 PacketType::PACKET_NPC_NEXT)].cntLimit = 1;
89 mPacketLimits[CAST_SIZE(
90 PacketType::PACKET_NPC_NEXT)].cnt = 0;
91
92 mPacketLimits[CAST_SIZE(
93 PacketType::PACKET_NPC_INPUT)].timeLimit = 100;
94 mPacketLimits[CAST_SIZE(
95 PacketType::PACKET_NPC_INPUT)].lastTime = 0;
96 mPacketLimits[CAST_SIZE(
97 PacketType::PACKET_NPC_INPUT)].cntLimit = 1;
98 mPacketLimits[CAST_SIZE(
99 PacketType::PACKET_NPC_INPUT)].cnt = 0;
100
101 // 50
102 mPacketLimits[CAST_SIZE(
103 PacketType::PACKET_NPC_TALK)].timeLimit = 60;
104 mPacketLimits[CAST_SIZE(
105 PacketType::PACKET_NPC_TALK)].lastTime = 0;
106 mPacketLimits[CAST_SIZE(
107 PacketType::PACKET_NPC_TALK)].cntLimit = 1;
108 mPacketLimits[CAST_SIZE(
109 PacketType::PACKET_NPC_TALK)].cnt = 0;
110
111 // 10
112 mPacketLimits[CAST_SIZE(
113 PacketType::PACKET_EMOTE)].timeLimit = 10 + 5;
114 mPacketLimits[CAST_SIZE(
115 PacketType::PACKET_EMOTE)].lastTime = 0;
116 mPacketLimits[CAST_SIZE(
117 PacketType::PACKET_EMOTE)].cntLimit = 1;
118 mPacketLimits[CAST_SIZE(
119 PacketType::PACKET_EMOTE)].cnt = 0;
120
121 // 100
122 mPacketLimits[CAST_SIZE(
123 PacketType::PACKET_SIT)].timeLimit = 100;
124 mPacketLimits[CAST_SIZE(
125 PacketType::PACKET_SIT)].lastTime = 0;
126 mPacketLimits[CAST_SIZE(
127 PacketType::PACKET_SIT)].cntLimit = 1;
128 mPacketLimits[CAST_SIZE(
129 PacketType::PACKET_SIT)].cnt = 0;
130
131 mPacketLimits[CAST_SIZE(
132 PacketType::PACKET_DIRECTION)].timeLimit = 50;
133 mPacketLimits[CAST_SIZE(
134 PacketType::PACKET_DIRECTION)].lastTime = 0;
135 mPacketLimits[CAST_SIZE(
136 PacketType::PACKET_DIRECTION)].cntLimit = 1;
137 mPacketLimits[CAST_SIZE(
138 PacketType::PACKET_DIRECTION)].cnt = 0;
139
140 // 2+
141 mPacketLimits[CAST_SIZE(
142 PacketType::PACKET_ATTACK)].timeLimit = 2 + 10;
143 mPacketLimits[CAST_SIZE(
144 PacketType::PACKET_ATTACK)].lastTime = 0;
145 mPacketLimits[CAST_SIZE(
146 PacketType::PACKET_ATTACK)].cntLimit = 1;
147 mPacketLimits[CAST_SIZE(
148 PacketType::PACKET_ATTACK)].cnt = 0;
149
150 mPacketLimits[CAST_SIZE(
151 PacketType::PACKET_STOPATTACK)].timeLimit = 2 + 10;
152 mPacketLimits[CAST_SIZE(
153 PacketType::PACKET_STOPATTACK)].lastTime = 0;
154 mPacketLimits[CAST_SIZE(
155 PacketType::PACKET_STOPATTACK)].cntLimit = 1;
156 mPacketLimits[CAST_SIZE(
157 PacketType::PACKET_STOPATTACK)].cnt = 0;
158
159 mPacketLimits[CAST_SIZE(
160 PacketType::PACKET_ONLINELIST)].timeLimit = 1800;
161 mPacketLimits[CAST_SIZE(
162 PacketType::PACKET_ONLINELIST)].lastTime = 0;
163 mPacketLimits[CAST_SIZE(
164 PacketType::PACKET_ONLINELIST)].cntLimit = 1;
165 mPacketLimits[CAST_SIZE(
166 PacketType::PACKET_ONLINELIST)].cnt = 0;
167
168 // 300ms + 50 fix
169 mPacketLimits[CAST_SIZE(
170 PacketType::PACKET_WHISPER)].timeLimit = 30 + 5;
171 mPacketLimits[CAST_SIZE(
172 PacketType::PACKET_WHISPER)].lastTime = 0;
173 mPacketLimits[CAST_SIZE(
174 PacketType::PACKET_WHISPER)].cntLimit = 1;
175 mPacketLimits[CAST_SIZE(
176 PacketType::PACKET_WHISPER)].cnt = 0;
177
178 if (!settings.serverConfigDir.empty())
179 {
180 const std::string packetLimitsName = settings.serverConfigDir
181 + "/packetlimiter.txt";
182
183 std::ifstream inPacketFile;
184 struct stat statbuf;
185
186 if ((stat(packetLimitsName.c_str(), &statbuf) != 0)
187 || !S_ISREG(statbuf.st_mode))
188 {
189 // wtiting new file
190 writePacketLimits(packetLimitsName);
191 }
192 else
193 { // reading existent file
194 inPacketFile.open(packetLimitsName.c_str(), std::ios::in);
195 char line[101];
196
197 if (!inPacketFile.is_open() || !inPacketFile.getline(line, 100))
198 {
199 inPacketFile.close();
200 return;
201 }
202
203 const int ver = atoi(line);
204
205 for (int f = 0;
206 f < CAST_S32(PacketType::PACKET_SIZE);
207 f ++)
208 {
209 if (!inPacketFile.getline(line, 100))
210 break;
211
212 if (!(ver == 1 &&
213 (static_cast<PacketTypeT>(f) == PacketType::PACKET_DROP ||
214 static_cast<PacketTypeT>(f)
215 == PacketType::PACKET_NPC_NEXT)))
216 {
217 mPacketLimits[f].timeLimit = atoi(line);
218 }
219 }
220 inPacketFile.close();
221 if (ver < 5)
222 writePacketLimits(packetLimitsName);
223 }
224 }
225 }
226
writePacketLimits(const std::string & packetLimitsName)227 void PacketLimiter::writePacketLimits(const std::string &packetLimitsName)
228 {
229 std::ofstream outPacketFile;
230 outPacketFile.open(packetLimitsName.c_str(), std::ios::out);
231 if (!outPacketFile.is_open())
232 {
233 reportAlways("Error opening file for writing: %s",
234 packetLimitsName.c_str())
235 outPacketFile.close();
236 return;
237 }
238 outPacketFile << "4" << std::endl;
239 for (int f = 0; f < CAST_S32(PacketType::PACKET_SIZE); f ++)
240 {
241 outPacketFile << toString(mPacketLimits[f].timeLimit)
242 << std::endl;
243 }
244
245 outPacketFile.close();
246 }
247
checkPackets(const PacketTypeT type)248 bool PacketLimiter::checkPackets(const PacketTypeT type)
249 {
250 if (type > PacketType::PACKET_SIZE)
251 return false;
252
253 if (!serverConfig.getValueBool("enableBuggyServers", true))
254 return true;
255
256 const PacketLimit &limit = mPacketLimits[CAST_SIZE(type)];
257 const int timeLimit = limit.timeLimit;
258
259 if (timeLimit == 0)
260 return true;
261
262 const int time = tick_time;
263 const int lastTime = limit.lastTime;
264 const int cnt = limit.cnt;
265 const int cntLimit = limit.cntLimit;
266
267 if (lastTime > tick_time)
268 {
269 // instance()->mPacketLimits[type].lastTime = time;
270 // instance()->mPacketLimits[type].cnt = 0;
271
272 return true;
273 }
274 else if (lastTime + timeLimit > time)
275 {
276 if (cnt >= cntLimit)
277 {
278 return false;
279 }
280 // instance()->mPacketLimits[type].cnt ++;
281 return true;
282 }
283 // instance()->mPacketLimits[type].lastTime = time;
284 // instance()->mPacketLimits[type].cnt = 1;
285 return true;
286 }
287
limitPackets(const PacketTypeT type)288 bool PacketLimiter::limitPackets(const PacketTypeT type)
289 {
290 if (CAST_S32(type) < 0 || type > PacketType::PACKET_SIZE)
291 return false;
292
293 if (!serverConfig.getValueBool("enableBuggyServers", true))
294 return true;
295
296 PacketLimit &pack = mPacketLimits[CAST_SIZE(type)];
297 const int timeLimit = pack.timeLimit;
298
299 if (timeLimit == 0)
300 return true;
301
302 const int time = tick_time;
303 const int lastTime = pack.lastTime;
304 const int cnt = pack.cnt;
305 const int cntLimit = pack.cntLimit;
306
307 if (lastTime > tick_time)
308 {
309 pack.lastTime = time;
310 pack.cnt = 0;
311 return true;
312 }
313 else if (lastTime + timeLimit > time)
314 {
315 if (cnt >= cntLimit)
316 {
317 return false;
318 }
319 pack.cnt ++;
320 return true;
321 }
322 pack.lastTime = time;
323 pack.cnt = 1;
324 return true;
325 }
326