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